编译器实现之旅——第六章 实现语法分析器
在上一章的旅程中,我们为实现语法分析器做了许多准备,我们讨论了如何表示语法,如何将记号流变为抽象语法树,如何消除左递归,如何得到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);
}
}
至此,语法分析器就已经全部实现完成了。伴随着语法分析器的实现,整个前端的旅程也就告一段落了。接下来,我们将进入更为精彩,更为广阔的后端世界一探究竟。请看下一章:《编译器后端概观》。

浙公网安备 33010602011771号