[语法分析]LR分析器与其它分析器的交互

    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]);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值