一、实验目的

编写一个简单的LL(1)语法分析器

二、实验题目

三、分析与设计

四、源代码

#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <conio.h>
#define digit 1 // 1数字
#define op 2 // +-*/()#
#define Hh 3 // 3Hh
#define AF 4 // 4A-F
#define letter 5 // 5其它字母
using namespace std;
//栈结构
typedef struct node {char data;struct node* next;
};
node* temp, * top;
char cmpchar;
string line;
// 定义分析表结构
int table[5][8] = {{0, 0, 0, 0, 1, 0, 1, 0},{1, 1, 0, 0, 0, 1, 0, 1},{0, 0, 0, 0, 1, 0, 1, 0},{1 ,1, 1, 1, 0, 1, 0, 1},{0, 0, 0, 0, 1, 0, 1, 0}
};char q; // 指向输入符号串中当前的字符
char word[20]; // 存储当前识别的单词
int state; // 表示所处的状态
int i; // 单词的下标char read(string line, int k);
void push(char c);
void pop();
int i2d(char cmpchar); // EATBF
int j2d(char current); // +-*/()i#
void dopush(int t);
bool check_terminal(char ch); // 判断是否是终结符
int isDigitOrChar(char ch);
string change_i(string words); // 将含有十进制或十六进制数的表达式转换为用i代替的表达式int main() {//读取文件 ifstream fin("test.txt");if (!fin.is_open()) {cout << "open file error." << endl;_getch();return -1;}while (getline(fin, line)) {puts("--------------------------------------------");string temp = line;//改写为i的式子 line = change_i(line);if (line == "-1") {cout << temp << " is not a valid express." << endl;continue;}cout << "Output string is: " << line << endl;int i, j, t;// 初始化push('#');push('E'); int cur = 0;char current;while (cur < line.size()) {current = read(line, cur);cmpchar = top->data;pop();printf("Top: %c --- Cur: %c", cmpchar, current);// 栈顶是终结符或#,但输入串中不是终结符或#时,判定为出错if (check_terminal(cmpchar) && cmpchar != current) {cur--; // 便于判定为非法break;}//栈顶和当前元素一致,匹配成功 if (current == cmpchar) {if (current == '#') break;printf("   match success of %c\n\n", current);cur++;continue;}cout << endl;i = i2d(cmpchar);j = j2d(current);//有产生式 if (table[i][j] == 1) {t = 10 * i + j;dopush(t);}else {cur--; // 便于判定为非法break;}}//输出结论 if (cur + 1 == line.size()) {cout << endl;cout << temp << endl;cout << "Your input is valid!" << endl;}else {cout << endl;cout << temp << endl;cout << "Sorry, your input is invalid!" << endl;}}return 0;
}char read(string line, int k) {return line[k];
}// 压栈
void push(char c) {temp = (node*)malloc(sizeof(node));temp->data = c;temp->next = top;top = temp;
}// 弹栈
void pop() {cmpchar = top->data;if (top->next != NULL)top = top->next;
}// 将i字符数字化
int i2d(char cmpchar) {int i = 0;switch (cmpchar) {case 'E': i = 0; break;case 'A': i = 1; break;case 'T': i = 2; break;case 'B': i = 3; break;case 'F': i = 4;}return i;
}// 将j字符数字化
int j2d(char current) {int j = 0;switch (current) {case '+': j = 0; break;case '-': j = 1; break;case '*': j = 2; break;case '/': j = 3; break;case '(': j = 4; break;case ')': j = 5; break;case 'i': j = 6; break;case '#': j = 7;}return j;
}
//将对应产生式入栈
void dopush(int t) {switch (t) {case 4: push('A'); push('T'); break;case 6: push('A'); push('T'); break;case 10: push('A'); push('T'); push('+'); break;case 11: push('A'); push('T'); push('-'); break;case 15: break;case 17: break;case 24: push('B'); push('F'); break;case 26: push('B'); push('F'); break;case 30: break;case 31: break;case 32: push('B'); push('F'); push('*'); break;case 33: push('B'); push('F'); push('/'); break;case 35: break;case 37: break;case 44: push(')'); push('E'); push('('); break;case 46: push('i'); break;}
}int isDigitOrChar(char ch) {if (ch >= 48 && ch <= 57) // 数字return digit;else if (ch == 72 || ch == 104) // H or hreturn Hh;else if ((ch >= 65 && ch <= 70) || (ch >= 97 && ch <= 102)) // 字母A,B,C,D,E,Freturn AF;else if ((ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122)) // 除A~F外的其它字母return letter;else if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')' || ch == '#')return op;
}// 将含有十进制或十六进制数的表达式转换为用i代替的表达式
string change_i(string words) {memset(word, 0, sizeof word);state = 0;i = 0;cout << "Input string is: " << words << endl;string result = "";int cnt = 0;q = words[cnt++];while (cnt <= words.size()) {// 先判断状态,再判断字符switch (state) {case 0: // 0状态switch (isDigitOrChar(q)) {case digit: // 数字word[i++] = q;state = 2; // 转移到2状态break;case Hh: // H or hcase AF: // 字母A,B,C,D,E,F or a,b,c,d,e,fcase letter: // 字母word[i++] = q;state = 1;break;case op: // 操作符result += q;state = 0;break;default: // 其它(非法字符 )word[i++] = q;state = 5;}break;case 1: // 1状态switch (isDigitOrChar(q)) {case Hh: // 当前状态遇到字母、数字往下读入case AF:case digit:case letter:word[i++] = q;state = 1;break;case op: // 读入完毕,识别为标识符word[i] = '\0';printf("%s is an identifier.\n", word);//result += "i";memset(word, 0, sizeof word);i = 0;state = 0;break;default:word[i++] = q;state = 5;}break;case 2: // 2状态switch (isDigitOrChar(q)) {case digit: // 若为数字,不改变状态往下读入word[i++] = q;state = 2;break;case Hh: // 若为Hh,转移至状态3word[i++] = q;state = 3;break;case AF: // 若为AF,则有可能是16进制,转移至状态4word[i++] = q;state = 4;break;case op: // 成功识别为整数word[i] = '\0';printf("%s is an Integer.\n", word);result += "i";result += q;//cout << result << endl;memset(word, 0, sizeof word);i = 0;state = 0;break;default:word[i++] = q;state = 5;}break;case 3: // 3状态switch (isDigitOrChar(q)) {case op: // 识别为16进制数word[i] = '\0';printf("%s is a Hex digit.\n", word);result += "i";result += q;//cout << result << endl;memset(word, 0, sizeof word);i = 0;state = 0;break;default:word[i++] = q;state = 5;}break;case 4: // 4状态switch (isDigitOrChar(q)) {case digit: // 若为数字或A~F,仍为状态4,往下读入case AF:word[i++] = q;state = 4;break;case Hh:word[i++] = q;state = 3;break;case op: // 如果16进制没有以h或H结尾,转移至错误状态state = 5;cnt--;break;default:word[i++] = q;state = 5;}break;case 5: // 出错状态if (isDigitOrChar(q) == op) { // 若为空格,则识别为非标识符word[i] = '\0';printf("%s is not an identifier.\n", word);memset(word, 0, sizeof word);i = 0;state = 0;result = "-1";return result;}else { // 出错序列还未读取完毕,往下读入word[i++] = q;q = words[cnt++];continue;}break;}q = words[cnt++]; // 指针下移(指向输入符号串中的下一个字符)}return result;
}// 判断是否是终结符
bool check_terminal(char ch) {if (isDigitOrChar(ch) == op || ch == 'i') return true;else return false;
}

五、实验结果(运行截屏)


六、实验总结

(1)重点与难点
因为理论部分的知识没有掌握透彻,所有对我而言,判断什么时候进行匹配,什么时候匹配失败,什么时候匹配成功的逻辑思考较难。
因为老师给的测试用例图片看上去很复杂,有些畏难心态,一直空着输出的语句没写,后来仔细分析了一下逻辑,发现还挺好写的。

(2)存在的不足
分析表已经在代码中确定了,没有实现自动实现分析表

(3)未来改进方案
可以尝试写出自动分析表实现的代码,使之适应范围更广

(4)结论(开发体验、收获、感想等)
本次实验用到了数据结构中栈的知识点,通过实验,对这部分的基础知识进行了进一步的巩固。LL(1)的语法分析在理论课中是一个难点和重点,通过本次实验,我基本上理解了该语法的逻辑,巩固并加深了对这部分知识的理解与记忆。算法中,讲字符数字化,并将两个数字合并为一个二位数然后再进行状态判断的做法,十分独特且具有启发意义,在一定程度上,简化了代码的复杂性,简化了代码的逻辑难度,很值得学习。

七、测试用例

7+9*2#
80+5eH+(6+1)*2+4h#
95eah+3*(5+10)+35h#
9*6+(5+2)*5+80bh#
59h+((3+9ah)*3+4#
6+(5+2))*5+80bh#

LL(1)语法分析器相关推荐

  1. 递归下降文法C语言实验报告,递归下降语法分析器实验报告.doc

    递归下降语法分析器实验报告 编译原理实验报告 题目: 递归下降语法分析器 学 院 计算机科学与技术 专 业 xxxxxxxxxxxxxxxx 学 号 xxxxxxxxxxxx 姓 名 宁剑 指导教师 ...

  2. PHP语法分析器:RE2C BISON 总结

    在这之前,我曾经尝试过一个项目,就是将我们的PHP代码自动生成so扩展, 编译到PHP中,我叫它 phptoc. 但是由于各种原因,暂停了此项目. 写这篇文章一是因为这方面资料太少,二是把自己的收获总 ...

  3. 编译原理 - 实验三 - 递归下降语法分析器的调试及扩展

    一. 语法分析介绍 语法分析是编译过程的核心部分,它的主要任务是按照程序语言的语法规则,从由词法分析输出的源程序符号串中识别出各类语法成分,同时进行语法检查,为语义分析和代码生成做准备.执行语法分析任 ...

  4. java实现语法分析器_语法分析 | 语法分析的任务

    在之前,我们有对编译器做过一定的介绍,我们认为编译器是具有一定流水线结构的软件系统.它可以分为前端,中端和后端这样的不同的阶段. 编译器前端 对于我们正在研究的前端,我们已经通过词法分析的学习掌握了从 ...

  5. Java中语法分析器_语法分析器(java语法分析器)

    亲这是一款采用递归下降语法分析器,是一种适合手写语法编译器的方法,且非常简单.递归下降法对语言所用的文法有一些限制,但递归下降是现阶段主流的语法分析方法,因为它可以由开发人员高度控制,在提供错误信息方 ...

  6. 《编译原理》实验报告——基于YACC的TINY语法分析器的构建

    一.实验要求 运用YACC,针对TINY语言,构造一个语法分析器.给出实验方案,实施并描述结果. 二.实验方案 (1)设计基于LEX的TINY词法分析器 (2)设计基于YACC的TINY语法分析器 ( ...

  7. 《编译原理》实验预习报告——基于YACC的TINY语法分析器的构建

    一.实验目的 运用YACC,针对给定的文法,构造一个语法分析器.给出实验方案,实施并描述结果. 二.实验预习提示 1.表达:针对5.5节中的calculator文法,设计输入和输出 2.观察:观察pa ...

  8. 《编译原理》实验报告——递归下降语法分析器的构建

    一.实验要求 运用递归下降法,针对给定的上下文无关文法,给出实验方案.预估实验中可能出现的问题. 二.实验方案 1.构造LL(1),通过设计.编制.调试递归下降语法分析程序,对输入的符号串进行分析匹配 ...

  9. java实现语法分析器_200 行 JS 代码,带你实现代码编译器

    一.前言 对于前端同学来说,编译器可能适合神奇的魔盒 ,表面普通,但常常给我们惊喜. 编译器,顾名思义,用来编译,编译什么呢?当然是编译代码咯 . 其实我们也经常接触到编译器的使用场景: React ...

  10. c语言语法分析源程序,深入浅出编译原理-5-一个简单语法分析器的C语言实现

    引言 前面已经介绍了编译器的预处理,词法分析,词法分析器的实现,也在其中说到了语法分析的任务和过程. 语法分析的输入是词法单元序列,然后根据语言的文法表示(展开式),利用有限状态机理论,生成抽象语法树 ...

最新文章

  1. 算法-------求众数
  2. proteus仿真micropython_[MicroPython]TurniBit开发板DIY自动窗帘模拟系统
  3. mysql 5.7 学习
  4. Verilog MIPS32 CPU(一)-- PC寄存器
  5. 「递归」第2集 | 变得了魔术,解得了高数,这届鹅厂程序员有点酷
  6. 操作系统基础:存储管理知识笔记(一)
  7. 深度学习pytorch--多层感知机(三)
  8. uva 10285——Longest Run on a Snowboard
  9. linux下web压力测试工具ab使用及详解
  10. linux on win原理,linux on win10 上手体验
  11. 2016.3.16(Java图形用户界面)
  12. 1036 跟奥巴马一起编程 (15 分)—PAT (Basic Level) Practice (中文)
  13. 基于linux在线预览
  14. GNS3 将虚拟机加入组网
  15. EditPlus 快捷键大全
  16. vscode缓存清理
  17. 字符串相乘(给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。)
  18. Java项目:图书管理系统(java+JSP+layui+bootstrap+Servlet+Mysql)
  19. windows 2012新建额外域控没有netlogon和SYSVOL共享的解决办法
  20. 前端入门教程(四)head内常用标签与body内常用标签

热门文章

  1. java+uiautomator 打包运行
  2. 关于EOF和读文件的一些事
  3. 玉湖冷链黄铮洪出任广东省物流标准化技术委员会副主任
  4. “ 试题管理系统”需求分析报告
  5. SCI论文写作的学习与总结
  6. mysql字符集mysqldump_Mysqldump 字符集问题
  7. OpenStack ironic裸金属部署(裸金属作为独立服务)
  8. 2020东软面试题小计(校招Java篇)
  9. win10批量修改文件扩展名
  10. 检查excel指定列中是否有错别字存在