Action表中还有一小部分没有填完,就是LR分析器委托其他分析器识别非终结符的那一部分。其中包括在变量定义时委托VariableAnalyser识别变量,在识别循环条件或赋值语句等状态中委托OperationAnalyser识别运算式,以及在识别正反花括号内部的基本块时委托一个新的LRAnalyser去识别它。这些Action也可以用宏来实现,大家应该已经轻车熟路,这里就不多说了,直接看代码吧
#define switchAnalyser(current, encounter, analyser) \ static void linkName(current, encounter)(struct LRAnalyser* self, \ struct Token* t) \ { \ struct SyntaxAnalyser* delegateAnalyser = (analyser); \ analyserStack->push(analyserStack, delegateAnalyser); \ delegateAnalyser->consumeToken(delegateAnalyser, t); \ } /***************************************************************/ switchAnalyser(Declaration_1, IDENT, newVariableAnalyser()) #define switchAnalyserFirstAssignment(current, analyser) \ switchAnalyser(current, PLUS, analyser) \ switchAnalyser(current, MINUS, analyser) \ switchAnalyser(current, NOT, analyser) \ switchAnalyser(current, INTEGER, analyser) \ switchAnalyser(current, REAL, analyser) \ switchAnalyser(current, IDENT, analyser) \ switchAnalyser(current, LPARENT, analyser) /*********/ switchAnalyserFirstAssignment(LRState0, newOperationAnalyser()) switchAnalyserFirstAssignment(IfElseBranch_2, newOperationAnalyser()) switchAnalyserFirstAssignment(WhileLoop_2, newOperationAnalyser()) switchAnalyserFirstAssignment(IfElseBranch_4, newOperationAnalyser()) switchAnalyserFirstAssignment(WhileLoop_4, newOperationAnalyser()) switchAnalyserFirstAssignment(ElseBlock_1, newOperationAnalyser()) switchAnalyserFirstAssignment(Sentence_IOAssignmentEoS_1, newOperationAnalyser()) switchAnalyserFirstAssignment(BasicBlock_SentenceBasicBlock_1, newOperationAnalyser()) switchAnalyserFirstAssignment(Initialization_AssignAssignment_1, newOperationAnalyser()) #define switchAnalyserFirstSentence(current, analyser) \ switchAnalyser(current, IF, analyser) \ switchAnalyser(current, WHILE, analyser) \ switchAnalyser(current, READ, analyser) \ switchAnalyser(current, WRITE, analyser) \ switchAnalyser(current, BREAK, analyser) \ switchAnalyser(current, INTEGER_TYPE, analyser) \ switchAnalyser(current, REAL_TYPE, analyser) \ switchAnalyser(current, EOS, analyser) \ switchAnalyser(current, LBRACE, analyser) \ switchAnalyserFirstAssignment(current, analyser) /// switchAnalyserFirstSentence(Sentence_LBraceBasicBlockRBrace_1, newLRAnalyser()) switchAnalyser(Sentence_LBraceBasicBlockRBrace_1, RBRACE, newLRAnalyser()) #undef switchAnalyserFirstSentence #undef switchAnalyserFirstAssignment #undef switchAnalyser
在状态Sentence_LBraceBasicBlockRBrace_1下,除了遇见First(Sentence),还可能遇见<RBRACE>,因为一个语句块可能是空的,这时仍然委托一个LR分析器来分析它。其实这里也可以换一种思路实现,就是增加一条产生式
Sentence -> <LBRACE> <RBRACE>
这样在状态Sentence_LBraceBasicBlockRBrace_1遇到<RBRACE>时,将它规约为一个空语句就可以了。
委托分析器的返回与comsumeNonTerminal函数
当一个委托分析器返回一个非终结符给LR分析器时,LR分析器必须做一次Goto状态转移。然而现在有个小问题:非终结符并没有像Token那样有一个type成员,还记得reduce宏函数的的实现吗?规约之后查询Goto表的那一列其实是通过传递给宏的参数leftPart来确定的,也就是说这个是静态绑定的。
为了实现consumeNonTerminal成员函数,除了为非终结符也添加上一个类型成员以外,当然还是有其它方案的。在设计LRState状态时,我们留下过一个“后门”,Goto表的列数比实际需要多1,现在就可以利用这个后门来确定接受非终结符之后的Goto目标状态。这很大程度上跟Jerry语言的LR分析器比较简单有关:每个委托分析器状态只可能委托给一种分析器。也就是说,在某个特定的状态下,如果调用consumeNonTerminal成员函数,那么传入的非终结符类型是确定的,如状态IfElseBranch_2如果接受一个非终结符,那么它一定是Assignment,而状态Declaration_1接受的一定是Variable,等等;对应的,这时状态IfElseBranch_2一定会Goto到状态IfElseBranch_3,而状态Declaration_1一定会Goto状态VariableRegister_VariableInitialization_1。因此,可以将这些特殊的Goto目标存放在多出的那一列中。
#define extraGoto(source, target) \ jerryLRStates[source].gotoes[NR_GOTO_TABLE_COLUMN] = jerryLRStates + target extraGoto(LRState0, Sentence_AssignmentEoS_1); extraGoto(IfElseBranch_4, Sentence_AssignmentEoS_1); extraGoto(ElseBlock_1, Sentence_AssignmentEoS_1); extraGoto(WhileLoop_4, Sentence_AssignmentEoS_1); extraGoto(BasicBlock_SentenceBasicBlock_1, Sentence_AssignmentEoS_1); extraGoto(Sentence_LBraceBasicBlockRBrace_1, Sentence_LBraceBasicBlockRBrace_2); extraGoto(IfElseBranch_2, IfElseBranch_3); extraGoto(WhileLoop_2, WhileLoop_3); extraGoto(Sentence_IOAssignmentEoS_1, Sentence_IOAssignmentEoS_2); extraGoto(Initialization_AssignAssignment_1, Initialization_AssignAssignment_2); extraGoto(Declaration_1, VariableRegister_VariableInitialization_1); #undef extraGoto
而对应的,consumeNonTerminal成员函数的实现是
void consumeNonTerminal_LRAnalyser(void* self, struct AbstractSyntaxNode* nonTerminal) { struct LRAnalyser* lra = (struct LRAnalyser*)self; struct LRState* currentState = (struct LRState*) (lra->stateStack->peek(lra->stateStack)); lra->symbolStack->push(lra->symbolStack, nonTerminal); lra->stateStack->push(lra->stateStack, currentState->gotoes[NR_GOTO_TABLE_COLUMN]); }