LL(1)语法分析设计原理与实现——以赋值语句为例

这篇具有很好参考价值的文章主要介绍了LL(1)语法分析设计原理与实现——以赋值语句为例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、实验目的

语法分析的设计方法和实现原理;LL(1)分析表的构造;LL(1)分析过程;LL(1)分析器 的构造;

二、实验内容

实现 LL(1)分析中控制程序(表驱动程序);完成以下描述赋值语句的 LL(1) 文法的 LL(1)分析过程。

G[S]:S→V=E

E→TE′

E′→ATE′|ε

T→FT′

T′→MFT′|ε

F→ (E)|i

A→+|-

M→*|/

V→i

[设计说明] 终结符号 i 为用户定义的简单变量,即标识符的定义。

[设计要求]

(1)输入串应是词法分析的输出二元式序列,即某算术表达式“专题 1”的 输出结果。输出为输入串是否为该文法定义的算术表达式的判断结果;

(2)LL(1)分析过程 应能发现输入串出错;

(3)设计两个测试用例(尽可能完备,正确和出错),并给出测试结 果;

(4)考虑根据 LL(1)文法编写程序构造 LL(1)分析表,包括 FIRST 集合和 FOLLOW 集 合,并添加到你的 LL(1)分析程序中。

输出结果:

词法分析输入文件:

赋值语句的语法分析程序设计与实现,数据结构,算法,c++,编辑器

词法分析输出:

赋值语句的语法分析程序设计与实现,数据结构,算法,c++,编辑器

LL1文法分析结果:

先根据已知文法构造分析表:

赋值语句的语法分析程序设计与实现,数据结构,算法,c++,编辑器

读取文件进行LL1文法分析:

赋值语句的语法分析程序设计与实现,数据结构,算法,c++,编辑器

以下为实现该文法分析的全部代码,文件读取部分也可改为自行输入字符串,对主函数的like字符型数组进行更改即可。文章来源地址https://www.toymoban.com/news/detail-767785.html

#define  _CRT_SECURE_NO_WARNINGS  1
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
#include <cassert>
#include<fstream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<stack>
using namespace std;
#define max_size 100

char LL_1[100][100]= {
  "S->V=E",
  "E->Te",
  "e->ATe|N", //E'用小e表示
  "T->Ft",    //T'用小t表示   
  "t->MFt|N",
  "F->(E)|i",
  "A->+|-",
  "M->*|/",
  "V->i"
};//文法数组

int num_ll = 9;//这里表示文法条数
//记录文法分析表格

char LL1[50][50][100];
char frist[100][100];//记录frist集数据
char follow[100][100];//记录follow集数据

char H[200]; //记录非终结符合
char L[200]; //记录终结符号
stack<char>cmp;//分析栈
char shizi[500], like[500];//从文件中读取字符串

int location_H(char c);//判断当前字符是否属于非终结符号
int location_L(char c);//判断当前字符是否属于终结符号
void add_HL(char ll[100][100]);//添加非终结符号与终结符号
int check(char l[100], char c);//在字符串中查找字符
void find_frist(char ll[100][100]);//第一遍寻找frist集的函数
void find_the_frist(int ll_index, char ll[100][100], int n_frist);//用作递归
void find_follow(char ll[100][100]);//用作寻找follow集
void make_table(char ll[100][100]);//用作构建表格
void print_table();//输出结果的函数
int findH(char a);//查找非终结符号
int findL(char b);//查找终结符号
int error(int i, int cnt, int len, char p[], char str[]);//出错处理
void analyze(char str[1000], int len);//LL1分析函数
void openthefile();//读取词法分析输出的函数

void LL_1table(char ll[100][100]) {
  add_HL(ll);
  find_frist(ll);
  find_follow(ll);
  make_table(ll);
  print_table();//输出结果函数
}

int check(char l[100], char c) {
  int temp = 0;
  for(int i = 0; i < strlen(l); i++) {
    if (c == l[i]) {
      temp = 1;
      break;
    }
  }
  return temp;
}
void add_HL(char ll[100][100]) {
  int H_index = 0;
  int L_index = 0;
  int temp = 0;
  int temp1 = 0;
  for (int i = 0; i < num_ll; i++) {//添加非终结符号
    H[H_index] = ll[i][0];
    H_index++;
  }
  for (int i = 0; i < num_ll; i++) {
    for (int j = 3; j < strlen(ll[i]); j++) {
      //由于文法开始前三个字符必定不为终结符号,所以从三号索引开始
      temp = 0;
      for (int k = 0; k < strlen(H); k++) {
        if (ll[i][j] == H[k] || ll[i][j] == '|' || ll[i][j] == 'N') {
          temp = 1;
          break;
        }
      }
      if (temp == 0) {
        temp1 = 0;
        for (int k = 0; k < strlen(L); k++) {
          //判断该非终结符号是否已经存在
          if (ll[i][j] == L[k]) {
            temp1 = 1;
            break;
          }
        }
        if (temp1 == 0) {
          L[L_index] = ll[i][j];//添加终结符号
          L_index++;
        }
      }
    }
  }
  L[strlen(L)] = '#';
}
int location_H(char c) {
  int location = -1;
  for (int i = 0; i < num_ll; i++) {
    if (c == H[i]) {
      location = i;
      break;
    }
  }
  return location;
}
int location_L(char c) {
  int location = -1;
  for (int i = 0; i < num_ll; i++) {
    if (c == L[i]) {
      location = i;
      break;
    }
  }
  return location;
}
void print_table() {
  cout << "------------------20231048 马云霄-----------------------" << endl;
  cout << "该文法的非终结符号集为:" << H << endl;
  cout << "该文法的终结符号集为:" << L << endl;
  cout << "-------------------------------------------------------" << endl;
  cout << "              frist集            follow集" << endl;
  for (int i = 0; i < num_ll; i++) {
    cout << "   符号 " << H[i] << " :      " << frist[i]<<"               " <<follow[i]<< endl;
  }
  cout << "-------------------------------------------------------" << endl;
  cout << "当前LL(1)分析表格为:" << endl;
  cout << "        ";
  for (int i = 0; i < strlen(L); i++) {
    cout << L[i] << "       ";
  }
  cout << endl;
  for (int i = 0; i < num_ll; i++) {
    cout << H[i] << ": ";
    for (int j = 0; j < strlen(L); j++) {
      if (strlen(LL1[i][j]) == 0) {
        strcpy(LL1[i][j], "null");
      }
      cout.width(8);
      cout.unsetf(ios::right);
      cout.fill(' ');
      cout <<LL1[i][j];
    }
    cout << endl;
  }
  cout << "-------------------------------------------------------" << endl;
}
void find_frist(char ll[100][100]) {
  int temp;
  int n_frist;//当前添加frist集元素位置
  int if_the_frist_word;//判断当前符号是否为第一个符号
  int location;//下次递归寻找的非终结符号的位置
  for (int i = 0; i < num_ll; i++) {
    n_frist = 0;
    if_the_frist_word = 0;
    for (int j = 3; j < strlen(ll[i]); j++) {
      if (if_the_frist_word == 0) {//判断当前符号是否为第一个符号
        temp = 0;//表示当前字符为非终结符号
        location = 0;
        for (int k = 0; k < strlen(H); k++) {
          if (H[k] == ll[i][j]) {
            location = k;
            temp = 1;
            break;
          }
        }
        if (temp == 0) {//如果当前字符为终结符号
          n_frist = strlen(frist[i]);
          frist[i][n_frist] = ll[i][j];
        }
        else {
          find_the_frist(location, ll, i);
        }
      }
      if_the_frist_word = 1;
      if (ll[i][j] == '|') {
        if_the_frist_word = 0;//或符号的下一个符号要进行识别
      }
    }
  }
}
void find_the_frist(int ll_index,char ll[100][100],int n_frist) {
  int if_the_frist_word = 0;
  int location;//表示当前找寻的非终结符号的位置
  int temp;
  int location_frist;
  for (int j = 3; j < strlen(ll[ll_index]); j++) {
    if (if_the_frist_word == 0) {//判断当前符号是否为第一个符号
      temp = 0;//表示当前字符为非终结符号
      location = 0;
      for (int k = 0; k < strlen(H); k++) {
        if (H[k] == ll[ll_index][j]) {
          temp = 1;
          location = k;
          break;
        }
      }
      if (temp == 0) {//如果当前字符为终结符号
        location_frist = strlen(frist[n_frist]);
        frist[n_frist][location_frist] = ll[ll_index][j];
      }
      else {
        find_the_frist(location, ll, n_frist);//递归寻找
      }
    }
    if_the_frist_word = 1;
    if (ll[ll_index][j] == '|') {
      if_the_frist_word = 0;//或符号的下一个符号要进行识别
    }
  }
}
void find_follow(char ll[100][100]) {
  follow[0][0] = '#';//为开始符号添加终结符
  int f_location;
  int ff_location;
  for (int i = 0; i < num_ll; i++) {
    for (int j = 3; j < strlen(ll[i])-1; j++) {
      if (location_H(ll[i][j]) != -1) {
        if (location_H(ll[i][j + 1]) == -1&&ll[i][j+1]!='|') {
          //如果后面字符为终结符,直接将其加入follow集
          if (check(follow[location_H(ll[i][j])], ll[i][j + 1]) == 0) {
            //判断当前字符是否已经存在
            f_location = strlen(follow[location_H(ll[i][j])]);
            follow[location_H(ll[i][j])][f_location] = ll[i][j + 1];
          }
        }
        else {
          //如果不是,则将其后面的非终结符号的frist集加入当前follow集
          f_location = strlen(frist[location_H(ll[i][j+1])]);
          for (int k = 0; k < f_location; k++) {
            if (frist[location_H(ll[i][j + 1])][k] != 'N') {
              //判断当前字符是否为空
              if (check(follow[location_H(ll[i][j])], frist[location_H(ll[i][j + 1])][k]) == 0) {
                ff_location = strlen(follow[location_H(ll[i][j])]);
                follow[location_H(ll[i][j])][ff_location] = frist[location_H(ll[i][j + 1])][k];
              }
            }
          }
        }
      }
    }
  }
  for (int i = 0; i < num_ll; i++) {
    for (int j = 3; j < strlen(ll[i]) - 1; j++) {
      if (location_H(ll[i][j]) != -1) {
        if (ll[i][j + 1] == '|') {
          //如果该非终结符号后续没有符号
          f_location = strlen(follow[location_H(ll[i][0])]);
          for (int k = 0; k < f_location; k++) {
              //判断当前字符是否为空
            if (check(follow[location_H(ll[i][j])], follow[location_H(ll[i][0])][k]) == 0) {
              ff_location = strlen(follow[location_H(ll[i][j])]);
              follow[location_H(ll[i][j])][ff_location] = follow[location_H(ll[i][0])][k];
            }
          }
        }
        else if (location_H(ll[i][j + 1]) != -1) {
          //如果后续为非终结符号
          if (check(frist[location_H(ll[i][j + 1])], 'N') == 1) {
            //该非终结符号可以推导出空
            f_location = strlen(follow[location_H(ll[i][0])]);
            for (int k = 0; k < f_location; k++) {
              //判断当前字符是否为空
              if (check(follow[location_H(ll[i][j])], follow[location_H(ll[i][0])][k]) == 0) {
                ff_location = strlen(follow[location_H(ll[i][j])]);
                follow[location_H(ll[i][j])][ff_location] = follow[location_H(ll[i][0])][k];
                //该符号的follow集加上推原符号的follow集的内容
              }
            }
          }
        }
      }
    }
    if (location_H(ll[i][strlen(ll[i]) - 1]) != -1) {
      //如果该符号为该文法的最后一个符号且为非终结符号
      f_location = strlen(follow[location_H(ll[i][0])]);
      for (int k = 0; k < f_location; k++) {
        //判断当前字符是否为空
        if (check(follow[location_H(ll[i][strlen(ll[i]) - 1])], follow[location_H(ll[i][0])][k]) == 0) {
          ff_location = strlen(follow[location_H(ll[i][strlen(ll[i]) - 1])]);
          follow[location_H(ll[i][strlen(ll[i]) - 1])][ff_location] = follow[location_H(ll[i][0])][k];
        }
      }
    }
  }
}
void make_table(char ll[100][100]) {
  int temp = 0;
  int w = 2;
  for (int i = 0; i < num_ll; i++) {
    if (check(ll[i], '|') == 0) {
      //当前检索文法中不含或
      for (int j = 0; j < strlen(frist[i]); j++) {//遍历当前frist集
        if (frist[i][j] == 'N') {
          continue;
        }
        for (int k = 1; k < strlen(ll[i]); k++) {
          LL1[i][location_L(frist[i][j])][k - 1] = ll[i][k];
        }
      }
    }
    else {
      //当前文法中含或,则需要判断填入哪条文法
      for (int j=0; j < strlen(frist[i]); j++) {
        if (frist[i][j] == 'N') {
          continue;
        }
        temp = 0;
        for (int k = 3; k < strlen(ll[i]); k++) {
          //遍历当前文法,由于前三个符号不使用,这里从3开始遍历
          if (temp == 0) {
            if (location_H(ll[i][k]) != -1) {
              //判断当前符号为终结符号还是非终结符号
              if (check(frist[location_H(ll[i][k])], frist[i][j]) == 1) {
                //如果当前符号为frist集取自其文法中该符号的frist集
                LL1[i][location_L(frist[i][j])][0] = '-';
                LL1[i][location_L(frist[i][j])][1] = '>';
                w = 2;//标记当前表格对应位置字符串长度
                for (int r = k; r < strlen(ll[i]); r++) {
                  //将对应文法放入当前表格
                  LL1[i][location_L(frist[i][j])][w] = ll[i][r];
                  w++;
                  if (ll[i][r + 1] == '|')
                    break;
                }
              }
            }
              else if (ll[i][k] != 'N' && ll[i][k] == frist[i][j]) {
                //当前符号为终结符号且不为空
                LL1[i][location_L(frist[i][j])][0] = '-';
                LL1[i][location_L(frist[i][j])][1] = '>';
                w = 2;
                for (int r = k; r < strlen(ll[i]); r++) {
                  LL1[i][location_L(frist[i][j])][w] = ll[i][r];
                  w++;
                  if (ll[i][r + 1] == '|')
                    break;
                }
              }
            }
          temp = 1;
          if (ll[i][k] == '|') {
            //只判断或符号后面的符号即可
            temp = 0;
          }
        }
      }
    }
  }
  for (int i = 0; i < num_ll; i++) {
    if (check(frist[i], 'N') == 1) {
      for (int j = 0; j < strlen(follow[i]); j++) {
        LL1[i][location_L(follow[i][j])][0] = '-';
        LL1[i][location_L(follow[i][j])][1] = '>';
        LL1[i][location_L(follow[i][j])][2] = '$';
      }
    }
  }
}

int findH(char a)
{
  for (int i = 0; i < strlen(H); i++)//找到对应行
  {
    if (a == H[i])
    {
      return i;
    }
  }
  return -1;
}
int findL(char b)
{
  for (int i = 0; i < strlen(L); i++)//找到对应列
  {
    if (b == L[i])
    {
      return i;
    }
  }
  return -1;
}
int error(int i, int cnt, int len, char p[], char str[])
{
  printf("%d\t\t%s\t\t", cnt, p);
  for (int q = i; q < len; q++)
  {
    cout << str[q];
  }
  printf("\t\t报错\n");
  return len;
}
void analyze(char str[1000], int len)
{
  int cnt = 1;//输出Step专用
  int i = 0;
  int temp = 1;
  char p[2000] = "#S";//输出stack专用
  int pindex = 2;
  printf("Step\t\tStack\t\tString\t\tRule\n");
  while (i < len)
  {
    int x, y;
    char ch = cmp.top();//读取栈顶元素
    if (check(H,ch)==1)
    {
      cmp.pop();
      x = findH(ch);//当前文法识别字符位置
      y = findL(str[i]);//当前字符位置
      if (x != -1 && y != -1)
      {
        int len2 = strlen(LL1[x][y]);
        if (strcmp(LL1[x][y], "null") == 0)
        {
          i = error(i, cnt, len, p, str);
          continue;
        }
        printf("%d\t\t%s\t\t", cnt, p);
        if (p[pindex - 1] != '#' && pindex>0&&temp!=0 )
        {
          p[pindex] = '\0';
          pindex--;
        }
        temp = 1;
        if (LL1[x][y][2] != '$')
        {
          for (int q = len2 - 1; q > 1; q--)
          {
            p[pindex] = LL1[x][y][q];
            cmp.push(LL1[x][y][q]);
            pindex++;
          }
        }
        if(pindex>0 && LL1[x][y][2] == '$')
        {
          p[pindex] = '\0';
          pindex--;
          temp = 0;
        }
        for (int q = i; q < len; q++)
        {
          cout << str[q];
        }
        printf("\t\t%c%s\n", ch, LL1[x][y]);
      }
      else
      {
        i = error(i, cnt, len, p, str);
        continue;
        ///未找到,报错
      }

    }
    else
    {
      if (ch == str[i])
      {
        cmp.pop();
        printf("%d\t\t%s\t\t", cnt, p);
        if (ch == '#' && str[i] == '#')
        {
          printf("#\t\t接受\n");
          return;
        }
        for (int q = i; q < len; q++)
        {
          cout << str[q];
        }
        printf("\t\t%c匹配\n", ch);
        p[pindex] = '\0';
        pindex--; 
        i++;
      }
      else
      {
        i = error(i, cnt, len, p, str);
        continue;
        ///报错
      }
    }
    cnt++;
  }
}
void openthefile() {
  cout << "读取文件可知输入语句:" << endl;
  FILE* fp;
  char buf[1000];
  if ((fp = fopen("E:\\desktop\\result.txt", "r")) != NULL) {
    while (fgets(buf, 1000, fp) != NULL)
    {
      int len = strlen(buf);
      printf("%s \n", buf);
      int flag = 0;

      for (int i = 0; i < len; i++) {
        if (buf[i] == '(' && flag == 0) {
          flag = 1;//识别符号
          for (int j = i + 1; j < len; j++) {
            if (buf[j] == ',') {
              shizi[strlen(shizi)]= buf[j + 1];
              if ((buf[j + 1] >= 'a' && buf[j + 1] <= 'z') ||
                (buf[j + 1] >= 'A' && buf[j + 1] <= 'Z')) {
                like[strlen(like)] += 'i';
              }
              else like[strlen(like)] = buf[j + 1];
              i = j + 1;
              break;
            }
          }
        }
        else if (flag == 1 && buf[i] == ')') {
          flag = 0;
        }
      }
    }
  }
  shizi[strlen(shizi)] = '#';
  like[strlen(like)] = '#';
  fclose(fp);
  cout << "-------------------------------------------------------" << endl;
  cout << "输入的语句为:" << shizi << endl;
  cout << "将其转化为:" << like << endl;
  cout << "-------------------------------------------------------" << endl;
}
int main()
{
  LL_1table(LL_1);
  openthefile();
  int len = strlen(like);
  cmp.push('#');
  cmp.push('S');
  analyze(like, len);
  return 0;
}

到了这里,关于LL(1)语法分析设计原理与实现——以赋值语句为例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Verilog语法(三)——赋值语句

    在 Verilog 中,阻塞赋值、非阻塞赋值和连续赋值是用于赋值操作的不同语法。它们之间的区别主要在于赋值时机和对后续代码执行的影响。 阻塞赋值使用等号 = 进行赋值,它的作用是在当前时钟周期内立即更新目标变量的值,然后继续执行下一条语句。因为它会阻塞后续语句

    2024年02月06日
    浏览(58)
  • Verilog语法——6.测试文件使用for和random语句进行赋值

    参考资料 【明德扬_verilog零基础入门语法HDL仿真快速掌握-手把手教你写FPGA/ASIC代码设计流程中的应用】 题目要求: 涉及到for语句的赋值语句: 小贴士 verilog不支持c/c++中的自增语句i++,因此只能写成i=i+1 for语句应该用在initial begin(…) end中,此处只展示关键代码 6.2.1 random语句

    2024年01月17日
    浏览(43)
  • 【编译原理】 实验三 LL(1)分析法(LL1分析表的自动生成)

    由于代码较长,csdn对文章总长度有字数限制,想只看完整代码的请移步另一篇博客。 https://blog.csdn.net/qq_46640863/article/details/125705891 理论与习题讲解移步视频 https://www.bilibili.com/video/BV1zu4y1C7SL 1.实现LL(1)分析算法 2.输入:教材中的算术表达式文法;待分析的语句(如i+i*i) 3.输

    2024年02月06日
    浏览(46)
  • 编译原理实验三:预测分析法语法分析器的设计

    ​ 根据文法编制预测分析法语法分析程序,以便对输入的符号串进行语法分析。通过编写预测分析法语法分析程序掌握预测分析法的基本原理、FIRST和FOLLOW集的计算、预测分析表的构造方法以及语法分析法主控程序的设计。 对于给定的上下文无关文法,编程完成以下功能:

    2024年02月05日
    浏览(55)
  • 编译原理——语法分析器(C/C++代码实现)

    编写一个简单的LL(1)语法分析器。(注意:此实验是简化版的LL(1)文法,已给出预测分析表,不需要求FIRST和FOLLOW集,直接根据预测分析表编写程序即可) 根据编译原理理论课中学习的算术表达式文法,以及该文法LL(1)分析表,用C语言编写接受算术表达式为输入的语法

    2023年04月26日
    浏览(40)
  • 编译原理——SLR(1)语法分析器(C/C++代码实现)

    设计、编制、实现并调试SLR(1)语法分析器,加深对语法分析的理解。 根据编译原理理论课中学习的算术表达式文法以及该文法的LR分析表,用C语言编写接受算术表达式为输入的语法分析器,以控制台(或文本文件,也可以结合词法分析器完成)为输入,控制台(或文件)

    2024年02月11日
    浏览(42)
  • LVGL源码分析(1):lv_ll链表的实现

    在LVGL中难免需要用到链表:group中的对象需要用链表来存储,这样可以切换对象的焦点;再比如LVGL内部的定时器,多个定时器也是用链表进行存储的。这篇文章就来分析一下LVGL中链表的源码。 对于链表来说,肯定有一个头指针和一个尾指针,在LVGL中,链表的数据结构如下:

    2024年02月13日
    浏览(53)
  • [编译原理]DO-WHILE循环语句的翻译程序设计(LR(1)方法、输出四元式)C++实现

    初始条件: ​ 理论:完成编译原理,数据结构、高级编程语言、汇编语言等相关课程的学习,基于计算机专业知识进行课程设计。 ​ 实践:计算机实验室提供计算机及软件环境。如果自己有计算机及环境也可以在其上进行设计任务。 要求完成的主要任务: (包括课程设计工

    2024年02月03日
    浏览(54)
  • 【编译原理实验】 -- 词法分析程序设计原理与实现(C语言实现)

    目录 目标任务 设计要求 一、程序功能描述 二、正则文法 三、程序结构描述 四、代码  五、程序测试  测试用例1 测试结果1 测试用例2 测试结果2 以下为正则文法所描述的 C 语言子集单词符号的示例,请补充单词符号:++,--, , , += , -= ,*=, /= ,(逻辑与),||(逻辑或),

    2024年02月02日
    浏览(127)
  • 编译原理——语法分析

    原文链接请访问https://code-child.cn lm表示的是最左 例子 例子 比如求x的first集合,那么就是求的x—字符串,所有字符串首字母构成的集合 计算需要反复 算法 预测分析表 预测分析中的错误检测 预测分析中的错误恢复 例子: M表示预测分析表,A表示栈顶的非终结符,a表示当前

    2024年02月06日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包