lexical analysis:
根据输入,输出Tokens,即<Token Class, Lexeme>二元组。如<Identifier, "abc">, <key word, "if">, <Number, "1234"> etc.
look ahead sometimes
parse tree
叶子节点:终结符
内节点:非终结符
对上下文无关文法的展开(derivation):最左展开(left-most derivation),最右展开(right-most derivation)
正确的上下文无关文法应该能消除最左和最右展开的歧义,即无论哪种展开,都能返回一致的解析树。
消除歧义:
1. 重写文法
2. 将*/等高优先级操作符置于+-之前。
错误处理
1. panic mode
放弃当前token,直到找到下一个能够匹配的(略过当前statement/expression, etc)
e.g., (1+ +2) +3
1+之后期待另一个int,略过第二个+。直到2。
2. Error productions(错误产生式)
修改产生式:E--> int | E+E | (E) | error int | (error)
error int表示放弃当前token,直到遇到int为止。
注意修改产生式会使语法复杂化。
3. Automatic local or global correction
如短语层次的恢复:将一个逗号替换为分号,删除一个多余的分号或者插入一个遗漏的分号,等。
抽象语法树
精简的parse tree。
自顶向下(TOP-DOWN)构建语法树:
递归下降(Recursive Descent)
按照产生式,从上至下,逐条测试(若发现不匹配会有回溯)
E-->T
bool E1(){ return T();}
E-->T+E
bool E2(){ return T() && term(PLUS) && E();}
E->T | T+E
bool E(){
TOKEN *save=next;
return (next=save, E1())
|| (next=save, E2());
}
问题:
对于S--> Sa的产生式:
bool S1(){ return S() && term(a);}
bool S(){ return S1();}
产生式的最左端为非终结符,这种情况下,递归下降会产生死循环。
重写产生式,将左递归写为右递归。
将形如下列的左递归产生式:
S-->Sa1 | .... | San | b1 | ... | bm
重写为:
S-->b1S' | ... | bmS'
S'-->a1S' | ... | anS' | ε
(消除左递归)