编译器实现之旅——第六章 实现语法分析器

在上一章的旅程中,我们为实现语法分析器做了许多准备,我们讨论了如何表示语法,如何将记号流变为抽象语法树,如何消除左递归,如何得到First集合等问题。现在,就让我们来实现语法分析器吧。

1. CMM语言的语法及其做出选择的方案

这里,我们直接给出CMM语言的语法及其做出选择的方案,并已经消除了左递归。消除左递归的方法以及得到First集合的方法已经在上一章讨论过,这里就不再讨论了。

CMM语言的语法及其做出选择的方案如下:

1. Program ::= Decl { Decl }

如果下一个记号不是END,则选择"{ Decl }"。

2. Decl ::= VarDecl
          | FuncDecl

首先,下一个记号必须是int或void;下第二个记号必须是单词。

如果下第三个记号是"["或";",则选择VarDecl;如果下第三个记号是"(",则选择FuncDecl;如果都不是,则出现了语法错误。

3. VarDecl ::= Type ID [ '[' Number ']' ] ';'

显然,当解析至"... [ '[' Number ']' ] ';'"时,如果下一个记号是"[",则选择"[ '[' Number ']' ]"。

4. Type ::= int
          | void

下一个记号是什么就选择什么。

5. FuncDecl ::= Type ID '(' ParamList ')' '{' LocalDecl StmtList '}'

不需要做出选择。

6. ParamList ::= [ Param { ',' Param } ]

如果下一个记号是int或void,则选择Param。

7. Param ::= Type ID [ '[' ']' ]

与第3条的情况类似。

(对于这条语法,细心地读者可能会发现:诸如"void xxx"这样的写法也是符合语法的。这是语法写错了吗?我们将在语义分析器的相关章节看到答案)

8. LocalDecl ::= { VarDecl }

如果下一个记号是int或void,则选择"{ VarDecl }"。

9. StmtList ::= { Stmt }

如果下一个记号是";"、单词、"("、数字、"{"、"if"、"while"或"return",则选择"{ Stmt }"。

10. Stmt ::= ExprStmt
           | IfStmt
           | WhileStmt
           | ReturnStmt

如果下一个记号是";"、单词、"("或数字,则选择"ExprStmt";如果下一个记号是"if",则选择"IfStmt";如果下一个记号是"while",则选择"WhileStmt";如果下一个记号是"return",则选择"ReturnStmt";如果都不是,则出现了语法错误。

11. ExprStmt ::= [ Expr ] ';'

如果下一个记号是单词、"("或数字,则选择"[ Expr ]"。

12. IfStmt ::= if '(' Expr ')' '{' StmtList '}' [ else '{' StmtList '}' ]

不需要做出选择。

13. WhileStmt ::= while '(' Expr ')' '{' StmtList '}'

不需要做出选择。

14. ReturnStmt ::= return [ Expr ] ';'

与第11条的情况一致。

15. Expr ::= Var '=' Expr
           | SimpleExpr

如果下一个记号是"("或数字,则选择"SimpleExpr";如果下一个记号是单词,则继续往后看;如果都不是,则出现了语法错误。

如果下第二个记号是"(",则选择"SimpleExpr";否则,继续往后看。

此时,就比较复杂了。我们需要往后解析一次Var,然后再看解析后的下一个记号。如果这个记号是"=",则选择"Var '=' Expr";否则,还是选择"SimpleExpr"。

16. Var ::= ID [ '[' Expr ']' ]

与第3条的情况类似。

17. SimpleExpr ::= AddExpr [ RelOp AddExpr ]

与第18条的情况一致。

18. RelOp ::= '<'
            | '<='
            | '>'
            | '>='
            | '=='
            | '!='

下一个记号是什么就选择什么。

19. AddExpr ::= Term { AddOp Term }

与第20条的情况一致。

20. AddOp ::= '+'
            | '-'

下一个记号是什么就选择什么。

21. Term ::= Factor { MulOp Factor }

与第22条的情况一致。

22. MulOp ::= '*'
            | '/'

下一个记号是什么就选择什么。

23. Factor ::= '(' Expr ')'
             | Number
             | Call
             | Var

如果下一个记号是"(",则选择"'(' Expr ')'";如果下一个记号是数字,则选择"Number";如果下一个记号是单词,则继续往后看;如果都不是,则出现了语法错误。

如果下第二个记号是"(",则选择"Call";否则,选择"Var"。

24. Call ::= ID '(' [ ArgList ] ')'

与第11条的情况一致。

25. ArgList ::= Expr { ',' Expr }

与第3条的情况类似。

有了这些语法规则和选择方案,我们就可以开始实现语法分析器了。实现语法分析器的代码实际上非常简单,我们只需要将每一条语法规则都分别翻译为一个函数即可。并且,这样的翻译规则具有很强的规律性,所以接下来,我们会挑选几个典型的翻译案例,来看看我们具体需要怎么做。最后,我们也将完整的给出对应于这25条语法规则的25个函数。

2. 语法分析器的类定义

首先,让我们来看看语法分析器的类定义。请看:

class __SyntaxAnalyzer
{
    // Friend
    friend class Core;


public:

    // Constructor
    explicit __SyntaxAnalyzer(const vector<__Token> &tokenList = {});


private:

    // Attribute
    vector<__Token> __tokenList;


    // Invalid __Token
    static void __invalidToken(const __Token *tokenPtr);


    // Match __Token
    static void __matchToken(__TokenType tokenType, __Token *&tokenPtr);


    // ENBF: Parse
    static void __Parse(__AST *&root, __Token *&tokenPtr);


    // ENBF: Program
    static void __Program(__AST *&root, __Token *&tokenPtr);


    // ENBF: Decl
    static void __Decl(__AST *&root, __Token *&tokenPtr);


    // ENBF: VarDecl
    static void __VarDecl(__AST *&root, __Token *&tokenPtr);


    // ENBF: Type
    static void __Type(__AST *&root, __Token *&tokenPtr);


    // ENBF: FuncDecl
    static void __FuncDecl(__AST *&root, __Token *&tokenPtr);


    // ENBF: ParamList
    static void __ParamList(__AST *&root, __Token *&tokenPtr);


    // ENBF: Param
    static void __Param(__AST *&root, __Token *&tokenPtr);


    // ENBF: LocalDecl
    static void __LocalDecl(__AST *&root, __Token *&tokenPtr);


    // ENBF: StmtList
    static void __StmtList(__AST *&root, __Token *&tokenPtr);


    // ENBF: Stmt
    static void __Stmt(__AST *&root, __Token *&tokenPtr);


    // ENBF: ExprStmt
    static void __ExprStmt(__AST *&root, __Token *&tokenPtr);


    // ENBF: IfStmt
    static void __IfStmt(__AST *&root, __Token *&tokenPtr);


    // ENBF: WhileStmt
    static void __WhileStmt(__AST *&root, __Token *&tokenPtr);


    // ENBF: ReturnStmt
    static void __ReturnStmt(__AST *&root, __Token *&tokenPtr);


    // ENBF: Expr
    static void __Expr(__AST *&root, __Token *&tokenPtr);


    // ENBF: Var
    static void __Var(__AST *&root, __Token *&tokenPtr);


    // ENBF: SimpleExpr
    static void __SimpleExpr(__AST *&root, __Token *&tokenPtr);


    // ENBF: RelOp
    static void __RelOp(__AST *&root, __Token *&tokenPtr);


    // ENBF: AddExpr
    static void __AddExpr(__AST *&root, __Token *&tokenPtr);


    // ENBF: AddOp
    static void __AddOp(__AST *&root, __Token *&tokenPtr);


    // ENBF: Term
    static void __Term(__AST *&root, __Token *&tokenPtr);


    // ENBF: MulOp
    static void __MulOp(__AST *&root, __Token *&tokenPtr);


    // ENBF: Factor
    static void __Factor(__AST *&root, __Token *&tokenPtr);


    // ENBF: Call
    static void __Call(__AST *&root, __Token *&tokenPtr);


    // ENBF: ArgList
    static void __ArgList(__AST *&root, __Token *&tokenPtr);


    // Syntax Analysis
    __AST *__syntaxAnalysis();
};

可见,语法分析器中定义了__tokenList,用于保存由词法分析器得到的记号流;且语法分析器的目标是得到__root,即抽象语法树的树根;语法分析器中还定义了25个分别对应于上文中25条语法规则的函数;一个总解析函数__Parse;以及一个工具函数__matchToken。我们在下文中将会见到这些函数的实现。

3. 各个周边函数的实现

接下来,我们来看看语法分析器的各个周边函数的实现:

__SyntaxAnalyzer::__SyntaxAnalyzer(const vector<__Token> &tokenList):
    __tokenList(tokenList) {}


void __SyntaxAnalyzer::__invalidToken(const __Token *tokenPtr)
{
    throw runtime_error((format("Invalid token: %s in line %d") %
        tokenPtr->__tokenStr                                    %
        tokenPtr->__lineNo
    ).str());
}


__AST *__SyntaxAnalyzer::__syntaxAnalysis()
{
    __AST *root = nullptr;

    auto tokenPtr = __tokenList.data();

    __Parse(root, tokenPtr);

    return root;
}

__invalidToken函数是一个报错函数,其用于在语法分析器发现语法错误时报错并退出;__syntaxAnalysis函数通过调用__Parse函数,得到了我们想要的__root。

其他周边函数的实现都很简单,这里就不讨论了。

4. 第10条语法的翻译

首先,让我们来看看第10条语法是什么:

10. Stmt ::= ExprStmt
           | IfStmt
           | WhileStmt
           | ReturnStmt

不难看出,第10条语法仅仅定义了一系列的选择,而非一个具体的结构。所以,对于这样的语法,我们就只需要做出选择,然后将生成语法树的任务委托给选择出的函数即可。请看:

void __SyntaxAnalyzer::__Stmt(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            Stmt ::= ExprStmt
                   | IfStmt
                   | WhileStmt
                   | ReturnStmt


        __AST:

            __ExprStmt | __IfStmt | __WhileStmt | __ReturnStmt
    */

    if (tokenPtr->__tokenType == __TokenType::__Semicolon        ||
        tokenPtr->__tokenType == __TokenType::__Id               ||
        tokenPtr->__tokenType == __TokenType::__LeftRoundBracket ||
        tokenPtr->__tokenType == __TokenType::__Number)
    {
        __ExprStmt(root, tokenPtr);
    }
    else if (tokenPtr->__tokenType == __TokenType::__If)
    {
        __IfStmt(root, tokenPtr);
    }
    else if (tokenPtr->__tokenType == __TokenType::__While)
    {
        __WhileStmt(root, tokenPtr);
    }
    else if (tokenPtr->__tokenType == __TokenType::__Return)
    {
        __ReturnStmt(root, tokenPtr);
    }
    else
    {
        __invalidToken(tokenPtr);
    }
}

5. 第12条语法的翻译

首先,让我们来看看第12条语法是什么:

12. IfStmt ::= if '(' Expr ')' '{' StmtList '}' [ else '{' StmtList '}' ]

显然,这条语法定义了if语句的组成,其特点在于带有一个可选部分。对于这样明确定义出了一个抽象语法树节点结构的语法,我们应将其实现为一个双层的抽象语法树节点。请看:

void __SyntaxAnalyzer::__IfStmt(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            IfStmt ::= if '(' Expr ')' '{' StmtList '}' [ else '{' StmtList '}' ]


        __AST:

            __TokenType::__IfStmt
                |
                |---- __Expr
                |
                |---- __StmtList
                |
                |---- [__StmtList]
    */

    root = new __AST(__TokenType::__IfStmt, "IfStmt", {nullptr, nullptr});

    __matchToken(__TokenType::__If, tokenPtr);
    __matchToken(__TokenType::__LeftRoundBracket, tokenPtr);

    __Expr(root->__subList[0], tokenPtr);

    __matchToken(__TokenType::__RightRoundBracket, tokenPtr);
    __matchToken(__TokenType::__LeftCurlyBracket, tokenPtr);

    __StmtList(root->__subList[1], tokenPtr);

    __matchToken(__TokenType::__RightCurlyBracket, tokenPtr);

    if (tokenPtr->__tokenType == __TokenType::__Else)
    {
        __matchToken(__TokenType::__Else, tokenPtr);
        __matchToken(__TokenType::__LeftCurlyBracket, tokenPtr);

        root->__subList.push_back(nullptr);

        __StmtList(root->__subList[2], tokenPtr);

        __matchToken(__TokenType::__RightCurlyBracket, tokenPtr);
    }
}

首先,__matchToken函数是什么?原来,这是一个用于检查并越过一个记号的工具函数,其实现如下:

void __SyntaxAnalyzer::__matchToken(__TokenType tarTokenType, __Token *&tokenPtr)
{
    if (tokenPtr->__tokenType == tarTokenType)
    {
        tokenPtr++;
    }
    else
    {
        __invalidToken(tokenPtr);
    }
}

__matchToken函数的实现十分简单:其检查当前记号是否与给定的目标记号一致,如果一致,则越过当前记号;否则,就报错退出。这个函数的实现虽然十分简单,但在语法分析器中却十分常用。确切的说,任何一个记号都需要经由这个函数检查并越过。在第15条语法的实现中,我们正是通过多次调用这个函数,检查并越过了许多对于抽象语法树而言不需要的记号,如"if"、"("等。

说完了__matchToken函数,我们再来看看这条语法的实现。首先,我们创建了一个带有两个子节点的根节点,以存放If语句。为什么一上来就确定带有两个子节点呢?不难发现,If语句真正的有效部分是一个"Expr"以及后面的一个或两个"Stmt",而"Expr"和第一个"Stmt"是必须出现的,故我们可以确定:If语句至少需要两个子节点。接下来,我们按部就班的调用各种函数,跳过不需要的记号,并构造各个子节点。当语法解析推进到"[ else Stmt ]"部分时,我们通过一个if语句实现了可选这一语义。也就是说,如果当前的记号是一个else,我们就将子节点的数量从2个扩充至3个,并将else部分构造在第三个子节点上。

6. 第4条语法的翻译

首先,让我们来看看第4条语法是什么:

4. Type ::= int
          | void

这是一条非常简单的,所见即所得的语法。我们的实现也非常简单:

void __SyntaxAnalyzer::__Type(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            Type ::= int
                   | void


        __AST:

            __TokenType::__Int | __TokenType::__Void
    */

    if (tokenPtr->__tokenType == __TokenType::__Int || tokenPtr->__tokenType == __TokenType::__Void)
    {
        root = new __AST(tokenPtr);

        __matchToken(tokenPtr->__tokenType, tokenPtr);
    }
    else
    {
        __invalidToken(tokenPtr);
    }
}

可见,对于这类所见即所得的语法,我们直接在原地创建一个没有子节点的抽象语法树节点即可。

7. 第6条语法的翻译

首先,让我们来看看第6条语法是什么:

6. ParamList ::= [ Param { ',' Param } ]

这条语法的特点在于带有一个可重复的部分。如上文所说,当我们遇到一个可选的语法组分时,我们引入一个if语句来实现;不难想到,当我们遇到一个可重复的语法组分时,我们就要请出while语句了。请看:

void __SyntaxAnalyzer::__ParamList(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            ParamList ::= [ Param { ',' Param } ]


        __AST:

            __TokenType::__ParamList
                |
                |---- __Param
                |
                |---- [__Param]
                .
                .
                .
    */

    if (tokenPtr->__tokenType == __TokenType::__Int || tokenPtr->__tokenType == __TokenType::__Void)
    {
        root = new __AST(__TokenType::__ParamList, "ParamList", {nullptr});

        __Param(root->__subList[0], tokenPtr);

        while (tokenPtr->__tokenType == __TokenType::__Comma)
        {
            __matchToken(__TokenType::__Comma, tokenPtr);

            root->__subList.push_back(nullptr);

            __Param(root->__subList.back(), tokenPtr);
        }
    }
}

首先,语法规定:"Param"必须至少出现一次。这使得我们可以在创建根节点的时候就引入一个子节点,并随后构造这个子节点。接下来,我们通过while语句不断的查看下一个记号是不是逗号,如果是,我们就扩充一次子节点,并将最新的这个"Param"构造在最新的子节点上。

8. 第15条语法的翻译

首先,让我们来看看第15条语法是什么:

15. Expr ::= Var '=' Expr
           | SimpleExpr

这条语法看似平淡无奇,但其做出选择的方案却十分复杂,正如上文所示:

如果下一个记号是"("或数字,则选择"SimpleExpr";如果下一个记号是单词,则继续往后看;如果都不是,则出现了语法错误。

如果下第二个记号是"(",则选择"SimpleExpr";否则,继续往后看。

此时,就比较复杂了。我们需要往后解析一次Var,然后再看解析后的下一个记号。如果这个记号是"=",则选择"Var '=' Expr";否则,还是选择"SimpleExpr"。

怎么样实现"往后解析一次Var,然后再看解析后的下一个记号"这个动作呢?为了实现这一动作,我们就需要使用"备份-伪解析"方案了(幸运的是,这个方案在CMM的语法分析器实现中就只会用到这一次)。请看:

void __SyntaxAnalyzer::__Expr(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            Expr ::= Var '=' Expr
                   | SimpleExpr


        __AST:

            __TokenType::__Expr
                |
                |---- __Var
                |
                |---- __Expr

            ----------------------

            __TokenType::__Expr
                |
                |---- __SimpleExpr
    */

    root = new __AST(__TokenType::__Expr, "Expr", {nullptr});

    if (tokenPtr->__tokenType == __TokenType::__LeftRoundBracket || tokenPtr->__tokenType == __TokenType::__Number)
    {
        __SimpleExpr(root->__subList[0], tokenPtr);

        return;
    }
    else if (tokenPtr->__tokenType != __TokenType::__Id)
    {
        __invalidToken(tokenPtr);
    }

    if (tokenPtr[1].__tokenType == __TokenType::__LeftRoundBracket)
    {
        __SimpleExpr(root->__subList[0], tokenPtr);
    }
    else
    {
        auto tokenPtrBak = tokenPtr;

        __Var(root->__subList[0], tokenPtr);

        bool isAssignBool = tokenPtr->__tokenType == __TokenType::__Assign;

        delete root->__subList[0];

        tokenPtr = tokenPtrBak;

        if (isAssignBool)
        {
            root->__subList.push_back(nullptr);

            __Var(root->__subList[0], tokenPtr);

            __matchToken(__TokenType::__Assign, tokenPtr);

            __Expr(root->__subList[1], tokenPtr);
        }
        else
        {
            __SimpleExpr(root->__subList[0], tokenPtr);
        }
    }
}

让我们重点关注如何实现这个"备份-伪解析"方案。当语法分析器前进至"tokenPtr[1].__tokenType"处,且仍未得到正确决策时,我们就需要进行一次"伪解析"了。由于调用__Var函数会使得tokenPtr向后推进,故我们就需要通过一个tokenPtrBak变量暂存当前的tokenPtr,然后再调用__Var函数进行"伪解析"。调用__Var函数之后,tokenPtr就来到了"然后再看解析后的下一个记号"这个位置了,所以,我们马上就看看下一个记号是不是等号。看完了以后,我们就通过先前备份的tokenPtrBak变量,将tokenPtr恢复至原样。现在,我们终于可以做出正确的决策了。

9. 完整的实现

从语法规则翻译至函数实现的各个典型案例,在上文中已经逐个介绍完了,这里,我们给出全部25个函数的完整实现。请看:

void __SyntaxAnalyzer::__Parse(__AST *&root, __Token *&tokenPtr)
{
    __Program(root, tokenPtr);
}


void __SyntaxAnalyzer::__Program(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            Program ::= Decl { Decl }


        __AST:

            __TokenType::__Program
                |
                |---- __Decl
                |
                |---- [__Decl]
                .
                .
                .
    */

    root = new __AST(__TokenType::__Program, "Program", {nullptr});

    __Decl(root->__subList[0], tokenPtr);

    while (tokenPtr->__tokenType != __TokenType::__END)
    {
        root->__subList.push_back(nullptr);

        __Decl(root->__subList.back(), tokenPtr);
    }
}


void __SyntaxAnalyzer::__Decl(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            Decl ::= VarDecl
                   | FuncDecl


        __AST:

            __VarDecl | __FuncDecl
    */

    if (tokenPtr->__tokenType != __TokenType::__Int && tokenPtr->__tokenType != __TokenType::__Void)
    {
        __invalidToken(tokenPtr);
    }

    if (tokenPtr[1].__tokenType != __TokenType::__Id)
    {
        __invalidToken(tokenPtr + 1);
    }

    if (tokenPtr[2].__tokenType == __TokenType::__LeftSquareBracket || tokenPtr[2].__tokenType == __TokenType::__Semicolon)
    {
        __VarDecl(root, tokenPtr);
    }
    else if (tokenPtr[2].__tokenType == __TokenType::__LeftRoundBracket)
    {
        __FuncDecl(root, tokenPtr);
    }
    else
    {
        __invalidToken(tokenPtr + 2);
    }
}


void __SyntaxAnalyzer::__VarDecl(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            VarDecl ::= Type ID [ '[' Number ']' ] ';'


        __AST:

            __TokenType::__VarDecl
                |
                |---- __Type
                |
                |---- __TokenType::__Id
                |
                |---- [__TokenType::__Number]
    */

    root = new __AST(__TokenType::__VarDecl, "VarDecl", {nullptr, nullptr});

    __Type(root->__subList[0], tokenPtr);

    if (tokenPtr->__tokenType == __TokenType::__Id)
    {
        root->__subList[1] = new __AST(tokenPtr);

        __matchToken(__TokenType::__Id, tokenPtr);
    }
    else
    {
        __invalidToken(tokenPtr);
    }

    if (tokenPtr->__tokenType == __TokenType::__LeftSquareBracket)
    {
        __matchToken(__TokenType::__LeftSquareBracket, tokenPtr);

        root->__subList.push_back(new __AST(tokenPtr));

        __matchToken(__TokenType::__Number, tokenPtr);
        __matchToken(__TokenType::__RightSquareBracket, tokenPtr);
    }

    __matchToken(__TokenType::__Semicolon, tokenPtr);
}


void __SyntaxAnalyzer::__Type(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            Type ::= int
                   | void


        __AST:

            __TokenType::__Int | __TokenType::__Void
    */

    if (tokenPtr->__tokenType == __TokenType::__Int || tokenPtr->__tokenType == __TokenType::__Void)
    {
        root = new __AST(tokenPtr);

        __matchToken(tokenPtr->__tokenType, tokenPtr);
    }
    else
    {
        __invalidToken(tokenPtr);
    }
}


void __SyntaxAnalyzer::__FuncDecl(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            FuncDecl ::= Type ID '(' ParamList ')' '{' LocalDecl StmtList '}'


        __AST:

            __TokenType::__FuncDecl
                |
                |---- __Type
                |
                |---- __TokenType::__Id
                |
                |---- __ParamList | nullptr
                |
                |---- __LocalDecl
                |
                |---- __StmtList
    */

    root = new __AST(__TokenType::__FuncDecl, "FuncDecl", {nullptr, nullptr, nullptr, nullptr, nullptr});

    __Type(root->__subList[0], tokenPtr);

    if (tokenPtr->__tokenType == __TokenType::__Id)
    {
        root->__subList[1] = new __AST(tokenPtr);

        __matchToken(__TokenType::__Id, tokenPtr);
    }
    else
    {
        __invalidToken(tokenPtr);
    }

    __matchToken(__TokenType::__LeftRoundBracket, tokenPtr);

    __ParamList(root->__subList[2], tokenPtr);

    __matchToken(__TokenType::__RightRoundBracket, tokenPtr);
    __matchToken(__TokenType::__LeftCurlyBracket, tokenPtr);

    __LocalDecl(root->__subList[3], tokenPtr);
    __StmtList(root->__subList[4], tokenPtr);

    __matchToken(__TokenType::__RightCurlyBracket, tokenPtr);
}


void __SyntaxAnalyzer::__ParamList(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            ParamList ::= [ Param { ',' Param } ]


        __AST:

            __TokenType::__ParamList
                |
                |---- __Param
                |
                |---- [__Param]
                .
                .
                .
    */

    if (tokenPtr->__tokenType == __TokenType::__Int || tokenPtr->__tokenType == __TokenType::__Void)
    {
        root = new __AST(__TokenType::__ParamList, "ParamList", {nullptr});

        __Param(root->__subList[0], tokenPtr);

        while (tokenPtr->__tokenType == __TokenType::__Comma)
        {
            __matchToken(__TokenType::__Comma, tokenPtr);

            root->__subList.push_back(nullptr);

            __Param(root->__subList.back(), tokenPtr);
        }
    }
}


void __SyntaxAnalyzer::__Param(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            Param ::= Type ID [ '[' ']' ]


        __AST:

            __TokenType::__Param
                |
                |---- __Type
                |
                |---- __TokenType::__Id
    */

    root = new __AST(__TokenType::__Param, "Param", {nullptr, nullptr});

    __Type(root->__subList[0], tokenPtr);

    if (tokenPtr->__tokenType == __TokenType::__Id)
    {
        root->__subList[1] = new __AST(tokenPtr);

        __matchToken(__TokenType::__Id, tokenPtr);
    }
    else
    {
        __invalidToken(tokenPtr);
    }

    if (tokenPtr->__tokenType == __TokenType::__LeftSquareBracket)
    {
        __matchToken(__TokenType::__LeftSquareBracket, tokenPtr);
        __matchToken(__TokenType::__RightSquareBracket, tokenPtr);
    }
}


void __SyntaxAnalyzer::__LocalDecl(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            LocalDecl ::= { VarDecl }


        __AST:

            __TokenType::__LocalDecl
                |
                |---- [__VarDecl]
                .
                .
                .
    */

    root = new __AST(__TokenType::__LocalDecl, "LocalDecl");

    while (tokenPtr->__tokenType == __TokenType::__Int || tokenPtr->__tokenType == __TokenType::__Void)
    {
        root->__subList.push_back(nullptr);

        __VarDecl(root->__subList.back(), tokenPtr);
    }
}


void __SyntaxAnalyzer::__StmtList(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            StmtList ::= { Stmt }


        __AST:

            __TokenType::__StmtList
                |
                |---- [__Stmt]
                .
                .
                .
    */

    root = new __AST(__TokenType::__StmtList, "StmtList");

    while (tokenPtr->__tokenType == __TokenType::__Semicolon     ||
        tokenPtr->__tokenType == __TokenType::__Id               ||
        tokenPtr->__tokenType == __TokenType::__LeftRoundBracket ||
        tokenPtr->__tokenType == __TokenType::__Number           ||
        tokenPtr->__tokenType == __TokenType::__LeftCurlyBracket ||
        tokenPtr->__tokenType == __TokenType::__If               ||
        tokenPtr->__tokenType == __TokenType::__While            ||
        tokenPtr->__tokenType == __TokenType::__Return)
    {
        root->__subList.push_back(nullptr);

        __Stmt(root->__subList.back(), tokenPtr);
    }
}


void __SyntaxAnalyzer::__Stmt(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            Stmt ::= ExprStmt
                   | IfStmt
                   | WhileStmt
                   | ReturnStmt


        __AST:

            __ExprStmt | __IfStmt | __WhileStmt | __ReturnStmt
    */

    if (tokenPtr->__tokenType == __TokenType::__Semicolon        ||
        tokenPtr->__tokenType == __TokenType::__Id               ||
        tokenPtr->__tokenType == __TokenType::__LeftRoundBracket ||
        tokenPtr->__tokenType == __TokenType::__Number)
    {
        __ExprStmt(root, tokenPtr);
    }
    else if (tokenPtr->__tokenType == __TokenType::__If)
    {
        __IfStmt(root, tokenPtr);
    }
    else if (tokenPtr->__tokenType == __TokenType::__While)
    {
        __WhileStmt(root, tokenPtr);
    }
    else if (tokenPtr->__tokenType == __TokenType::__Return)
    {
        __ReturnStmt(root, tokenPtr);
    }
    else
    {
        __invalidToken(tokenPtr);
    }
}


void __SyntaxAnalyzer::__ExprStmt(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            ExprStmt ::= [ Expr ] ';'


        __AST:

            __Expr | nullptr
    */

    if (tokenPtr->__tokenType == __TokenType::__Id               ||
        tokenPtr->__tokenType == __TokenType::__LeftRoundBracket ||
        tokenPtr->__tokenType == __TokenType::__Number)
    {
        __Expr(root, tokenPtr);
    }

    __matchToken(__TokenType::__Semicolon, tokenPtr);
}


void __SyntaxAnalyzer::__IfStmt(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            IfStmt ::= if '(' Expr ')' '{' StmtList '}' [ else '{' StmtList '}' ]


        __AST:

            __TokenType::__IfStmt
                |
                |---- __Expr
                |
                |---- __StmtList
                |
                |---- [__StmtList]
    */

    root = new __AST(__TokenType::__IfStmt, "IfStmt", {nullptr, nullptr});

    __matchToken(__TokenType::__If, tokenPtr);
    __matchToken(__TokenType::__LeftRoundBracket, tokenPtr);

    __Expr(root->__subList[0], tokenPtr);

    __matchToken(__TokenType::__RightRoundBracket, tokenPtr);
    __matchToken(__TokenType::__LeftCurlyBracket, tokenPtr);

    __StmtList(root->__subList[1], tokenPtr);

    __matchToken(__TokenType::__RightCurlyBracket, tokenPtr);

    if (tokenPtr->__tokenType == __TokenType::__Else)
    {
        __matchToken(__TokenType::__Else, tokenPtr);
        __matchToken(__TokenType::__LeftCurlyBracket, tokenPtr);

        root->__subList.push_back(nullptr);

        __StmtList(root->__subList[2], tokenPtr);

        __matchToken(__TokenType::__RightCurlyBracket, tokenPtr);
    }
}


void __SyntaxAnalyzer::__WhileStmt(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            WhileStmt ::= while '(' Expr ')' '{' StmtList '}'


        __AST:

            __TokenType::__WhileStmt
                |
                |---- __Expr
                |
                |---- __StmtList
    */

    root = new __AST(__TokenType::__WhileStmt, "WhileStmt", {nullptr, nullptr});

    __matchToken(__TokenType::__While, tokenPtr);
    __matchToken(__TokenType::__LeftRoundBracket, tokenPtr);

    __Expr(root->__subList[0], tokenPtr);

    __matchToken(__TokenType::__RightRoundBracket, tokenPtr);
    __matchToken(__TokenType::__LeftCurlyBracket, tokenPtr);

    __StmtList(root->__subList[1], tokenPtr);

    __matchToken(__TokenType::__RightCurlyBracket, tokenPtr);
}


void __SyntaxAnalyzer::__ReturnStmt(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            ReturnStmt ::= return [ Expr ] ';'


        __AST:

            __TokenType::__ReturnStmt
                |
                |---- [__Expr]
    */

    root = new __AST(__TokenType::__ReturnStmt, "ReturnStmt");

    __matchToken(__TokenType::__Return, tokenPtr);

    if (tokenPtr->__tokenType == __TokenType::__Id               ||
        tokenPtr->__tokenType == __TokenType::__LeftRoundBracket ||
        tokenPtr->__tokenType == __TokenType::__Number)
    {
        root->__subList.push_back(nullptr);

        __Expr(root->__subList.back(), tokenPtr);
    }

    __matchToken(__TokenType::__Semicolon, tokenPtr);
}


void __SyntaxAnalyzer::__Expr(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            Expr ::= Var '=' Expr
                   | SimpleExpr


        __AST:

            __TokenType::__Expr
                |
                |---- __Var
                |
                |---- __Expr

            ----------------------

            __TokenType::__Expr
                |
                |---- __SimpleExpr
    */

    root = new __AST(__TokenType::__Expr, "Expr", {nullptr});

    if (tokenPtr->__tokenType == __TokenType::__LeftRoundBracket || tokenPtr->__tokenType == __TokenType::__Number)
    {
        __SimpleExpr(root->__subList[0], tokenPtr);

        return;
    }
    else if (tokenPtr->__tokenType != __TokenType::__Id)
    {
        __invalidToken(tokenPtr);
    }

    if (tokenPtr[1].__tokenType == __TokenType::__LeftRoundBracket)
    {
        __SimpleExpr(root->__subList[0], tokenPtr);
    }
    else
    {
        auto tokenPtrBak = tokenPtr;

        __Var(root->__subList[0], tokenPtr);

        bool isAssignBool = tokenPtr->__tokenType == __TokenType::__Assign;

        delete root->__subList[0];

        tokenPtr = tokenPtrBak;

        if (isAssignBool)
        {
            root->__subList.push_back(nullptr);

            __Var(root->__subList[0], tokenPtr);

            __matchToken(__TokenType::__Assign, tokenPtr);

            __Expr(root->__subList[1], tokenPtr);
        }
        else
        {
            __SimpleExpr(root->__subList[0], tokenPtr);
        }
    }
}


void __SyntaxAnalyzer::__Var(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            Var ::= ID [ '[' Expr ']' ]


        __AST:

            __TokenType::__Var
                |
                |---- __TokenType::__Id
                |
                |---- [__Expr]
    */

    root = new __AST(__TokenType::__Var, "Var", {nullptr});

    if (tokenPtr->__tokenType == __TokenType::__Id)
    {
        root->__subList[0] = new __AST(tokenPtr);

        __matchToken(__TokenType::__Id, tokenPtr);
    }
    else
    {
        __invalidToken(tokenPtr);
    }

    if (tokenPtr->__tokenType == __TokenType::__LeftSquareBracket)
    {
        __matchToken(__TokenType::__LeftSquareBracket, tokenPtr);

        root->__subList.push_back(nullptr);

        __Expr(root->__subList[1], tokenPtr);

        __matchToken(__TokenType::__RightSquareBracket, tokenPtr);
    }
}


void __SyntaxAnalyzer::__SimpleExpr(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            SimpleExpr ::= AddExpr [ RelOp AddExpr ]


        __AST:

            __TokenType::__SimpleExpr
                |
                |---- __AddExpr
                |
                |---- [__RelOp]
                |
                |---- [__AddExpr]
    */

    root = new __AST(__TokenType::__SimpleExpr, "SimpleExpr", {nullptr});

    __AddExpr(root->__subList[0], tokenPtr);

    if (tokenPtr->__tokenType == __TokenType::__Less         ||
        tokenPtr->__tokenType == __TokenType::__LessEqual    ||
        tokenPtr->__tokenType == __TokenType::__Greater      ||
        tokenPtr->__tokenType == __TokenType::__GreaterEqual ||
        tokenPtr->__tokenType == __TokenType::__Equal        ||
        tokenPtr->__tokenType == __TokenType::__NotEqual)
    {
        root->__subList.push_back(nullptr);

        __RelOp(root->__subList[1], tokenPtr);

        root->__subList.push_back(nullptr);

        __AddExpr(root->__subList[2], tokenPtr);
    }
}


void __SyntaxAnalyzer::__RelOp(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            RelOp ::= <
                    | <=
                    | >
                    | >=
                    | ==
                    | !=


        __AST:

            __TokenType::__Less         |
            __TokenType::__LessEqual    |
            __TokenType::__Greater      |
            __TokenType::__GreaterEqual |
            __TokenType::__Equal        |
            __TokenType::__NotEqual
    */

    if (tokenPtr->__tokenType == __TokenType::__Less         ||
        tokenPtr->__tokenType == __TokenType::__LessEqual    ||
        tokenPtr->__tokenType == __TokenType::__Greater      ||
        tokenPtr->__tokenType == __TokenType::__GreaterEqual ||
        tokenPtr->__tokenType == __TokenType::__Equal        ||
        tokenPtr->__tokenType == __TokenType::__NotEqual)
    {
        root = new __AST(tokenPtr);

        __matchToken(tokenPtr->__tokenType, tokenPtr);
    }
    else
    {
        __invalidToken(tokenPtr);
    }
}


void __SyntaxAnalyzer::__AddExpr(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            AddExpr ::= Term { AddOp Term }


        __AST:

            __TokenType::__AddExpr
                |
                |---- __Term
                |
                |---- [__AddOp]
                |
                |---- [__Term]
                .
                .
                .
    */

    root = new __AST(__TokenType::__AddExpr, "AddExpr", {nullptr});

    __Term(root->__subList[0], tokenPtr);

    while (tokenPtr->__tokenType == __TokenType::__Plus || tokenPtr->__tokenType == __TokenType::__Minus)
    {
        root->__subList.push_back(nullptr);

        __AddOp(root->__subList.back(), tokenPtr);

        root->__subList.push_back(nullptr);

        __Term(root->__subList.back(), tokenPtr);
    }
}


void __SyntaxAnalyzer::__AddOp(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            AddOp ::= +
                    | -


        __AST:

            __TokenType::__Plus | __TokenType::__Minus
    */

    if (tokenPtr->__tokenType == __TokenType::__Plus || tokenPtr->__tokenType == __TokenType::__Minus)
    {
        root = new __AST(tokenPtr);

        __matchToken(tokenPtr->__tokenType, tokenPtr);
    }
    else
    {
        __invalidToken(tokenPtr);
    }
}


void __SyntaxAnalyzer::__Term(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            Term ::= Factor { MulOp Factor }


        __AST:

            __TokenType::__Term
                |
                |---- __Factor
                |
                |---- [__MulOp]
                |
                |---- [__Factor]
                .
                .
                .
    */

    root = new __AST(__TokenType::__Term, "Term", {nullptr});

    __Factor(root->__subList[0], tokenPtr);

    while (tokenPtr->__tokenType == __TokenType::__Multiply || tokenPtr->__tokenType == __TokenType::__Divide)
    {
        root->__subList.push_back(nullptr);

        __MulOp(root->__subList.back(), tokenPtr);

        root->__subList.push_back(nullptr);

        __Factor(root->__subList.back(), tokenPtr);
    }
}


void __SyntaxAnalyzer::__MulOp(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            MulOp ::= *
                    | /


        __AST:

            __TokenType::__Multiply | __TokenType::__Divide
    */

    if (tokenPtr->__tokenType == __TokenType::__Multiply || tokenPtr->__tokenType == __TokenType::__Divide)
    {
        root = new __AST(tokenPtr);

        __matchToken(tokenPtr->__tokenType, tokenPtr);
    }
    else
    {
        __invalidToken(tokenPtr);
    }
}


void __SyntaxAnalyzer::__Factor(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            Factor ::= '(' Expr ')'
                     | Number
                     | Call
                     | Var


        __AST:

            __Expr | __TokenType::__Number | __Call | __Var
    */

    if (tokenPtr->__tokenType == __TokenType::__LeftRoundBracket)
    {
        __matchToken(__TokenType::__LeftRoundBracket, tokenPtr);

        __Expr(root, tokenPtr);

        __matchToken(__TokenType::__RightRoundBracket, tokenPtr);
    }
    else if (tokenPtr->__tokenType == __TokenType::__Number)
    {
        root = new __AST(tokenPtr);

        __matchToken(tokenPtr->__tokenType, tokenPtr);
    }
    else if (tokenPtr->__tokenType == __TokenType::__Id)
    {
        if (tokenPtr[1].__tokenType == __TokenType::__LeftRoundBracket)
        {
            __Call(root, tokenPtr);
        }
        else
        {
            __Var(root, tokenPtr);
        }
    }
    else
    {
        __invalidToken(tokenPtr);
    }
}


void __SyntaxAnalyzer::__Call(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            Call ::= ID '(' [ ArgList ] ')'


        __AST:

            __TokenType::__Call
                |
                |---- __TokenType::__Id
                |
                |---- [__ArgList]
    */

    root = new __AST(__TokenType::__Call, "Call", {nullptr});

    if (tokenPtr->__tokenType == __TokenType::__Id)
    {
        root->__subList[0] = new __AST(tokenPtr);

        __matchToken(__TokenType::__Id, tokenPtr);
    }
    else
    {
        __invalidToken(tokenPtr);
    }

    __matchToken(__TokenType::__LeftRoundBracket, tokenPtr);

    if (tokenPtr->__tokenType == __TokenType::__Id               ||
        tokenPtr->__tokenType == __TokenType::__LeftRoundBracket ||
        tokenPtr->__tokenType == __TokenType::__Number)
    {
        root->__subList.push_back(nullptr);

        __ArgList(root->__subList[1], tokenPtr);
    }

    __matchToken(__TokenType::__RightRoundBracket, tokenPtr);
}


void __SyntaxAnalyzer::__ArgList(__AST *&root, __Token *&tokenPtr)
{
    /*
        EBNF:

            ArgList ::= Expr { ',' Expr }


        __AST:

            __TokenType::__ArgList
                |
                |---- __Expr
                |
                |---- [__Expr]
                .
                .
                .
    */

    root = new __AST(__TokenType::__ArgList, "ArgList", {nullptr});

    __Expr(root->__subList[0], tokenPtr);

    while (tokenPtr->__tokenType == __TokenType::__Comma)
    {
        __matchToken(__TokenType::__Comma, tokenPtr);

        root->__subList.push_back(nullptr);

        __Expr(root->__subList.back(), tokenPtr);
    }
}

至此,语法分析器就已经全部实现完成了。伴随着语法分析器的实现,整个前端的旅程也就告一段落了。接下来,我们将进入更为精彩,更为广阔的后端世界一探究竟。请看下一章:《编译器后端概观》。

posted @ 2021-02-19 16:29  樱雨楼  阅读(543)  评论(0编辑  收藏  举报