如果
条件表达式 + IF 主体 + [ELSE 主体]
尽管
条件表达式+循环体
[表达]
任务
赋值变量+赋值变量
ikB
手术
运算符左值 + 运算符右值
数组元素
数组名+下标
呼叫K
函数调用
函数名+参数列表
参数K
CallK参数列表
[表达式](如果有多个表达式,则它们是兄弟节点)
未知节点
没有任何
4.3. 成员函数和变量的作用及意义:
Token():获取数组中存储的Token。 每次获取后,数组下标指向下一个void。
(int n): 打印n个空格 void (
s):错误报告功能,报告错误位置(行号)以及错误位置附近的Token void match(
ex):匹配目标Token类型ex。 如果匹配成功,则获得下一个Token(赋值),否则报void错误。
(*t): 打印生成的语法树* (
k): 根据节点类型创建新节点
以下是语法递归向下分析中各阶段的分析函数:
TreeNode * declaration_list(void);
TreeNode * declaration(void);
TreeNode * params(void);
TreeNode * param_list(TreeNode * k);
TreeNode * param(TreeNode * k);
TreeNode * compound_stmt(void);
TreeNode * local_declaration(void);
TreeNode * statement_list(void);
TreeNode * statement(void);
TreeNode * expression_stmt(void);
TreeNode * selection_stmt(void);
TreeNode * iteration_stmt(void);
TreeNode * return_stmt(void);
TreeNode * expression(void);
TreeNode * var(void);
TreeNode * simple_expression(TreeNode * k);
TreeNode * additive_expression(TreeNode * k);
TreeNode * term(TreeNode * k);
TreeNode * factor(TreeNode * k);
TreeNode * call(TreeNode * k);
TreeNode * args(void);
下表列出了使用基于上述C语法的递归向下分析方法来分析程序的过程。 待分析语法中列出了几种待分析语法。 分析函数就是程序针对这个语法编写的分析函数。 使用 来分析语法,分析是语法的分析过程和分析函数的编写思路,代码是分析函数的C语言实现;
4.4. 各个语法分析过程如下(具体代码实现见源码):
待分析语法→-list
解析函数
*解析(无效)
分析
说明用 C 语言编写的程序由一组声明序列组成。 parse(void)函数采用递归向下分析的方法,直接调用()函数,返回树节点
待分析语法 → { }
解析函数
* (空白)
分析
说明用 C 语言编写的程序由一组声明序列组成。 (void)函数使用递归向下分析的方法直接调用()函数并返回树节点
待分析语法→param{, param}
解析函数
*(*k)
分析
描述 参数列表由以逗号分隔的参数序列组成。 (*k)函数使用递归向下分析的方法直接调用param(*k)函数并返回树节点
待分析语法参数→ type- ID{[ ]}
解析函数 * param( * k)
分析可知,参数由int或void、标识符组成,末尾可能有方括号表示数组。 param(*k) 函数根据检测前面的 Token 是 int 还是 void 来创建一个新的 IntK 或 VoidK 节点作为其第一个子节点,然后创建一个 IdK 节点作为其第二个子节点,最后检测该集合是否为 a方括号,判断是否创建第三个子节点来表示数组类型
待分析语法-stmt→{ local- -list}
解析函数
* (空白)
分析
描述 复合语句由一组声明和括在花括号中的语句组成。 (void)函数使用递归向下分析的方法直接调用()函数和()函数,并使用返回的树节点作为其第一个子节点和第二个子节点
待分析语法 local-→empty {var- }
解析函数
* (空白)
分析
指示局部变量声明为空或由一系列变量声明组成。 (void)函数可以通过判断前面的Token是int还是void来知道局部变量声明是否为空。 如果没有,则创建一个新的变量定义节点()
待分析语法-列表→{}
分析函数*(无效)
分析描述由0到更多的语句列表组成。 (void)函数通过判断前面的Token类型是否是First集合来判断后面的Token类型是否是First集合。 如果是,则采用递归向下分析的方法直接调用()函数。
待分析语法-stmt→[];
解析函数
* (空白)
分析
描述 表达式语句有一个可选的表达式,后跟一个分号。 (void)函数判断前面的Token类型是否是分号。 如果没有,则直接调用()
待分析语法-stmt→while ()
解析函数
* (空白)
分析
(void)函数直接调用()函数和()函数分别获取其第一个和第二个子节点。
待分析语法-stmt→[];
解析函数
* (空白)
分析
(void)函数判断前面的Token类型是否是分号。 如果没有,则直接调用()获取其子节点。
5、准备2~3个测试用例来测试并解释程序的运行结果。
5.1. 测试例1(正例):
代码:
检测结果:
手工绘制的语法树如下(由于篇幅原因只绘制了第一个函数,实际上还有一个函数树没有绘制):
5.2. 测试例2(反例):
代码:
检测结果:
你可以在这里看到它! 会报错;
4. 总结
本次《编译原理》课程设计,我经历了从一开始不了解任务要求和内容的理论知识,然后编写代码完成基本功能,根据DFA修改和完善代码的过程以及自上而下的理论等等。
在写语法分析的时候,我已经对编译器语法分析的内容有了一定的了解,所以就直接研究了理论。 首先,我自己研究了递归向下分析方法。 看了书上的几段递归向下分析的伪代码,我对递归向下分析方法的原理有了初步的了解,也大致知道了根据语法如何分析,但还是很难入手如何分析写代码,所以我根据TINY语言的语法看了几遍书后面的TINY语言的递归向下分析语法分析程序,这样我就基本了解了C语言的语法分析。 如何编写程序。 由于C语言给出的语法带有左递归,所以我将带有左递归的语法重写为EBNF的形式,并相应地编写了代码。 由于在编写代码的过程中需要判断分析是否正确或者选择多种语法中的一种进行分析,所以有时必须检测所需的或者下一个Token的类型。 在这种情况下,您需要找到第一组。 在推导中如果有空就需要请求set,所以这就需要我了解First set和set。 我也是根据得到的First set和程序中的set进行判断,来确定程序的走向。 在写的过程中,还有一类问题,就是有一个共同的左因子,比如语法→var=| -,左边的因子是ID。 分析过程中,由于已经取出了ID Token,并生成了IdK节点,但目前状态无法确定它是哪个派生。 但IdK节点已经生成,无法回滚。 此外,还采用了自上而下的分析方法。 生成的IdK不能在程序之上使用。 您可以自行查阅资料。 学习决定了如何处理这种情况:将生成的IdK节点传递给下面的处理程序,因此*(*k)、*(*k)等函数被设计为带有节点类型参数的函数。 ,目的是将生成的节点传递给下面的分析函数。
通过这门编译原理课程的学习和实践,我受益匪浅。 首先,最基本的成果是完成课程设计任务,实现编译器的词法分析和语法分析阶段的功能。 词法分析主要可以过滤注释,分析语法分析阶段所需的token,满足语法阶段的所有要求。 能够识别词法分析阶段是否存在错误以及错误的类型和位置。 语法分析主要可以基于递归向下分析思想和C语法对词法分析得到的Token进行语法分析。 它可以构建语法树,并判断语法分析过程中是否存在错误,以及错误的位置和类型。
总之,这次课程实验让我受益匪浅,达到了我预期的效果。