知识点总结:
1.一个文法,由终结符号和非终结符号组成。文法的规则,或称为产生式,由一个产生式头的非终结符号和产生式体的终结/非 终结符号组成。文法中由一个非终结符号作为开始符号。
2.属性是指与一个程序关联的任何量值,被扩展到文法符号上,例如<num,12>表示一个num文法符号的属性值为12.
3.词法分析器读入字符,并输出一个词法单元的流。词法单元由终结符号和其属性值组成。
4.语法分析目的是从一个文法的开始符号推导出一个给定的终结符号串(通常,反复的将某个非终结符号替换成它的产生式体,这回形成一颗语法分析树,每个非叶子节点对应一个产生式,叶子结点则对应终结符号或者空)。
5.预测语法分析法,是通过观看流中的一个符号,无二义的确定该过程体中的控制流。(有自顶向下也有自底向上)
6.语法制导翻译通过在文法中增加规则和程序片段(语义动作)以计算属性值。
7.语法分析的结果是中间代码,抽象语法树的每个节点代表了程序构造,子节点给出了该构造有意义的子构造;三地址代码由三地址指令组成,每个指令只完成一个运算。
8。符号表用来存放关于标识符的信息。
关于附录A实现的简易java词法分析器+语法分析器,有以下几个值得回顾的要点:
a) 设计一个翻译器,是通过文法的结构来做大纲的,如:
文法: block -> '{' decls stmts '}'
我们可以为设计方法block(),decls(),stmts()。那么这句文法翻译过来的方法就是:
void block(){
match('{');
decls();
stmts();
match('}');
}
具体细节再作调整,实际上,这样写有一些问题,例如java中的变量声明可能和方法混在一起,并不按序排列。所以可能需要插入一个while循环。
b) 通常把终结符号作为一个类来设计,如:
文法:decl->id type
那么我们可以设计类id,和类type。追溯他们的父类,标识符应该是一个表达式,所以可以继承Expr。而类型,则更像是一个词法单元,正如num,因此可以继承Token,至于是否继承Word,那是看方便与否以及扩展性的。
c) 对于控制条件的跳转:
用label变量控制标签下标,再遇到分支结构时,以true入口false入口作为标签位控制
jump(int t,int f)->如果为t入口,则goto Lt,如果为f入口,则goto Lf,并在恰当的位置输出Lx
d) 符号表的设计:
以树图的形式设计符号表是非常好的想法,再每次进入block时,先以中间变量存入top,随之top被赋予新的对象env,在这个块中将以该符号表为主进行运算,出块时,top回到父节点。
e) 对数组的处理:
一个数组,应该是有两个表达式的,分别是数组的名称以及他的下标,在设计数组类型的时候就该考虑到这个问题。另外在翻译的时候,设计数组的问题,我们需要考虑左值右值是否是数组。
f) 错误的处理:
通常,需要记录行号,至于追溯到第几个字符,也是可以做到的。
g) 有问题的地方:
java中的输入流对换行不友好,回车符又不好控制。