在编译原理中,语义分析是编译过程的一个关键阶段,它负责检查源代码的逻辑含义,确保程序符合目标语言的语义规则。实验三的主题是“语法分析并进行语义分析”,主要目的是实现一个简单的编译器,能够识别并处理特定的文法结构,同时进行类型检查和符号表管理。
文法定义了以下构造:
- `stmt_seq`:表示语句序列,可以是单一语句或多个语句的组合。
- `statement`:包括声明语句(`decl_stmt`)和赋值语句(`assign_stmt`)。
- `decl_stmt`:定义变量类型和变量列表,类型可以是整型(`int`)或浮点型(`float`)。
- `assign_stmt`:包含一个标识符(`id`)和一个表达式(`exp`),用于赋值。
- `exp`:表达式可以由加法、减法、乘法或除法操作符连接的项(`term`)组成。
- `term`:项可以是因子(`factor`)之间通过乘法或除法操作符连接。
- `factor`:因子可以是标识符、数字或括号内的表达式。
样例程序中展示了如何使用C语言来实现这些功能。程序定义了一系列枚举类型,如`tokentype`(记号类型)、`nodekind`(节点类型)、`stmtkind`(语句类型)、`expkind`(表达式类型)和`exptype`(表达式类型)。`treenode`结构体用于表示语法树的节点,包含了子节点、兄弟节点、节点类型、数据类型、表达式类型等信息。`bucket`结构体则用于符号表的实现,存储变量名和对应的数据类型。
程序的主要功能包括:
1. `decl()`:处理变量声明,将变量名和类型添加到符号表。
2. `factor()`, `term()`, `exp()`: 分别处理因子、项和表达式的解析。
3. `assign_stmt()`: 处理赋值语句,进行类型检查。
4. `stmt_seq()`: 处理语句序列。
5. `pretraverse()`: 遍历语法树,方便查看和调试。
6. `hash()`: 计算字符串的哈希值,用于符号表的快速查找。
7. `st_insert()`: 将新的变量名和数据类型插入符号表。
8. `st_lookup()`: 在符号表中查找变量名。
9. `buildsymtab()`: 构建符号表,基于语法树的节点信息。
10. `setnodetype()`: 进行类型检查,并根据检查结果设置节点类型。
在`main()`函数中,首先调用`stmt_seq()`进行语法分析构建语法树,接着调用`buildsymtab()`建立符号表,最后调用`pretraverse()`遍历语法树进行调试输出,并使用`setnodetype()`进行类型检查。
这个实验不仅要求理解编译原理的基本概念,还涉及到实际的编程实现,包括文法分析、符号表管理和类型检查等关键步骤,有助于提升对编译器工作原理的理解。