LL(1)语法分析器
一、实验目的
编写一个简单的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)语法分析器相关推荐
- 递归下降文法C语言实验报告,递归下降语法分析器实验报告.doc
递归下降语法分析器实验报告 编译原理实验报告 题目: 递归下降语法分析器 学 院 计算机科学与技术 专 业 xxxxxxxxxxxxxxxx 学 号 xxxxxxxxxxxx 姓 名 宁剑 指导教师 ...
- PHP语法分析器:RE2C BISON 总结
在这之前,我曾经尝试过一个项目,就是将我们的PHP代码自动生成so扩展, 编译到PHP中,我叫它 phptoc. 但是由于各种原因,暂停了此项目. 写这篇文章一是因为这方面资料太少,二是把自己的收获总 ...
- 编译原理 - 实验三 - 递归下降语法分析器的调试及扩展
一. 语法分析介绍 语法分析是编译过程的核心部分,它的主要任务是按照程序语言的语法规则,从由词法分析输出的源程序符号串中识别出各类语法成分,同时进行语法检查,为语义分析和代码生成做准备.执行语法分析任 ...
- java实现语法分析器_语法分析 | 语法分析的任务
在之前,我们有对编译器做过一定的介绍,我们认为编译器是具有一定流水线结构的软件系统.它可以分为前端,中端和后端这样的不同的阶段. 编译器前端 对于我们正在研究的前端,我们已经通过词法分析的学习掌握了从 ...
- Java中语法分析器_语法分析器(java语法分析器)
亲这是一款采用递归下降语法分析器,是一种适合手写语法编译器的方法,且非常简单.递归下降法对语言所用的文法有一些限制,但递归下降是现阶段主流的语法分析方法,因为它可以由开发人员高度控制,在提供错误信息方 ...
- 《编译原理》实验报告——基于YACC的TINY语法分析器的构建
一.实验要求 运用YACC,针对TINY语言,构造一个语法分析器.给出实验方案,实施并描述结果. 二.实验方案 (1)设计基于LEX的TINY词法分析器 (2)设计基于YACC的TINY语法分析器 ( ...
- 《编译原理》实验预习报告——基于YACC的TINY语法分析器的构建
一.实验目的 运用YACC,针对给定的文法,构造一个语法分析器.给出实验方案,实施并描述结果. 二.实验预习提示 1.表达:针对5.5节中的calculator文法,设计输入和输出 2.观察:观察pa ...
- 《编译原理》实验报告——递归下降语法分析器的构建
一.实验要求 运用递归下降法,针对给定的上下文无关文法,给出实验方案.预估实验中可能出现的问题. 二.实验方案 1.构造LL(1),通过设计.编制.调试递归下降语法分析程序,对输入的符号串进行分析匹配 ...
- java实现语法分析器_200 行 JS 代码,带你实现代码编译器
一.前言 对于前端同学来说,编译器可能适合神奇的魔盒 ,表面普通,但常常给我们惊喜. 编译器,顾名思义,用来编译,编译什么呢?当然是编译代码咯 . 其实我们也经常接触到编译器的使用场景: React ...
- c语言语法分析源程序,深入浅出编译原理-5-一个简单语法分析器的C语言实现
引言 前面已经介绍了编译器的预处理,词法分析,词法分析器的实现,也在其中说到了语法分析的任务和过程. 语法分析的输入是词法单元序列,然后根据语言的文法表示(展开式),利用有限状态机理论,生成抽象语法树 ...
最新文章
- 算法-------求众数
- proteus仿真micropython_[MicroPython]TurniBit开发板DIY自动窗帘模拟系统
- mysql 5.7 学习
- Verilog MIPS32 CPU(一)-- PC寄存器
- 「递归」第2集 | 变得了魔术,解得了高数,这届鹅厂程序员有点酷
- 操作系统基础:存储管理知识笔记(一)
- 深度学习pytorch--多层感知机(三)
- uva 10285——Longest Run on a Snowboard
- linux下web压力测试工具ab使用及详解
- linux on win原理,linux on win10 上手体验
- 2016.3.16(Java图形用户界面)
- 1036 跟奥巴马一起编程 (15 分)—PAT (Basic Level) Practice (中文)
- 基于linux在线预览
- GNS3 将虚拟机加入组网
- EditPlus 快捷键大全
- vscode缓存清理
- 字符串相乘(给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。)
- Java项目:图书管理系统(java+JSP+layui+bootstrap+Servlet+Mysql)
- windows 2012新建额外域控没有netlogon和SYSVOL共享的解决办法
- 前端入门教程(四)head内常用标签与body内常用标签