具体的代码讲解和演示过程请参看视频:
用java开发编译器
从这节开始,我们看看解析器如何对逻辑控制语句,例如if else, for, while , do…while, goto 等语句进行相应的语法解析。
if else 语句的语法解析
我们先看看 if else 的语法定义:
IF_STATEMENT -> IF LP TEST RP STATEMENT
IF_ELSE_STATEMENT -> IF_STATEMENT
IF_ELSE_STATEMENT ->IF_ELSE_STATEMENT ELSE STATEMENT
STATEMENT -> IF_ELSE_STATEMENT
TEST -> EXPR
DECL -> VAR_DECL EQUAL INITIALIZER
INITIALIZER -> EXPR
如果C编译器遇到下面的语句:
if (i < 0)
i = 1;
else if (i == 0)
i = 2;
else
i = 3;
最开始的 if (i < 0) 则对应表达式:
IF_STATEMENT -> IF LP TEST RP STATEMENT
括号中间的 i < 0, 对应于语法中的TEST, 如果if 后面跟着else 关键字的话,像上面的例子, 那么代码:
if (i < 0)
i = 1;
else
这部分对应语法表达式:
IF_ELSE_STATEMENT ->IF_ELSE_STATEMENT ELSE STATEMENT
中的 IF_ELSE_STATEMENT ELSE 这部分, 剩下的部分:
if (i ==0)
i = 2;
else
i = 3;
则对应 STATEMENT , 其实这部分先是对应:
IF_ELSE_STATEMENT ->IF_ELSE_STATEMENT ELSE STATEMENT
然后再由:
STATEMENT -> IF_ELSE_STATEMENT
回归到STATEMENT.
下面我们看一个具体的分析实例:
void f() {
int a = 0;
int i = 0;
if (i < 1)
a = 1;
else if (i < 2)
a = 2;
else
a = 3;
}
对应语句:
int a = 0;
int i = 0;
解析过程前面章节已经详细描述,这里不再分析,我们看看if 部分语句的分析:
1: 读入关键字if, 返回标签IF
2: 读入左括号,返回标签LP
3: 读入变量i, 返回对应标签NAME,根据表达式:
UNARY -> NAME
BINARY -> UNARY
进行递归
4:读入符号 <, 得到标签 RELOP
5: 读入数字1, 返回标签NUMBER
6: 根据下面表达式进行连续递归:
UNARY -> .NUMBER
BINARY -> .UNARY
BINARY -> .BINARY RELOP BINARY
NO_COMMA_EXPR -> .BINARY
EXPR -> .NO_COMMA_EXPR
TEST -> .EXPR
也就是说括号内的表达式 i < 0, 被推导为 TEST -> EXPR
7: 读入右括号LP, 如果变量i,返回标签NAME, 接着进行下面的表达式递归:
UNARY -> .NAME
BINARY -> .UNARY
NO_COMMA_EXPR -> .BINARY
8: 读入等号,得到标签 EQUAL, 继续读入数值1,然后根据下面表达式进行递归:
UNARY -> .NUMBER
BINARY -> .UNARY
NO_COMMA_EXPR -> .BINARY
9: 此时满足表达式:
NO_COMMA_EXPR -> .NO_COMMA_EXPR EQUAL NO_COMMA_EXPR
因此根据该表达式再次递归。
然后再根据表达式:
EXPR -> .NO_COMMA_EXPR
进行递归。
10:读入分号,得到标签SEMI, 此时EXPR SEMI 正好构成表达式:
STATEMENT -> .EXPR SEMI
的右半部分,因此可以进行对应reduce操作。
11: 此时解析堆栈上的所有符号就能满足表达式:
IF_STATEMENT -> .IF LP TEST RP STATEMENT
因此,当前解析的内容都对应非终结符IF_STATEMENT. 继续根据表达式:
IF_ELSE_STATEMENT -> .IF_STATEMENT
再递归一次。
12: 接下来的else 后面部分,其解析过程跟前面解析if相关语句的流程是一样的。先把关键字else读入,得到标签ELSE. 后面又是if else 的重复,所以解析过程跟前面步骤是一样的。
13: 读入最后一个else, 然后读入变量名i, 根据以下表达式进行递归:
UNARY -> .NAME
BINARY -> .UNARY
NO_COMMA_EXPR -> .BINARY
14: 读入等号得到标签EQUAL, 读入数值3,根据下面表达式进行递归:
UNARY -> .NUMBER
BINARY -> .UNARY
NO_COMMA_EXPR -> .BINARY
15: 此时表达式:
NO_COMMA_EXPR -> .NO_COMMA_EXPR EQUAL NO_COMMA_EXPR
的右边可以满足,于是就可以进行对应的递归操作。
然后再次依赖表达式:
EXPR -> .NO_COMMA_EXPR
再进行一次递归。
16:读入接下来的分号,得到标签SEMI,然后又可以根据下面表达式进行递归:
STATEMENT -> .EXPR SEMI
17:得到STATEMENT后,IF_ELSE_STATEMENT 的语法表达式右边部分又得到满足:
IF_ELSE_STATEMENT -> .IF_ELSE_STATEMENT ELSE STATEMENT
这样的话,整个if … else if … else …. 这段代码就全被上面的语法表达式给吸收了。
18: 最后再跟进表达式:
STATEMENT -> .IF_ELSE_STATEMENT
进行递归,这也说明,if else 相关语法是对应于STATEMENT这个非终结符的。
后续的解析流程跟前面分析的一样,最后解析器会进入到接收状态,这表明我们给的的语法能够正确的解析if else if 这种条件转移控制代码。