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]);
}
本文介绍了一个LR分析器如何通过委托机制使用其他分析器来识别非终结符的过程。包括使用宏定义来简化委托分析器的配置,以及如何处理非终结符的返回与状态转移。
1万+

被折叠的 条评论
为什么被折叠?



