编译器开发:C语言循环控制语句的解析

76 篇文章 10 订阅
55 篇文章 6 订阅

若要深入理解本节内容,请参看视频讲解及相关代码演示:
用java开发编译器

任何编程语言,最常用的就是循环语句了,无论何种编程语言,都必须包含循环控制语句,在C语言中,for, while, do..while 这三种循环语句的使用,占据了源程序代码的绝大部分,因此,要开发C编译器,对这三种循环语句的语法解析是必不可少的,我们先看看他们的语法定义:

STATEMENT -> WHILE LP TEST RP STATEMENT 
STATEMENT -> FOR LP OPT_EXPR  TEST SEMI END_OPT_EXPR RP STATEMENT
OPT_EXPR -> EXPR SEMI
OPT_EXPR -> SEMI
END_OPT_EXPR -> EXPR
STATEMENT -> DO STATEMENT WHILE LP TEST RP SEMI

第一句语法对应的是while 循环, 例如:

while (i < 10) {
...
}

其中i < 10 对应语法中的TEST, {…}这部分对应语法中的statement

第二句语法:
STATEMENT -> FOR LP OPT_EXPR TEST SEMI END_OPT_EXPR RP STATEMENT
对应的是for 循环,注意OPT_EXPR 可以是一个表达式,也可以是一个分号,这样该语法就能对应下面的循环代码:

for (i = 0; i < 10; i++) {...}
或
for(; i< 10; i++) {...}

最后一句语法对应的是do…while 循环,适用于下面情况:

do {
...
} while (i < 10);

下面我们分别依据几个实例来讲解解析器对循环语句的解析过程,大家一定要通过观看视频才好深入理解本节的算法内涵。先看对for循环的解析:

void f() {
int a = 0;
int i = 0;
  for (i = 0; i < 10; i++) {
     a = a + 1;
  }
}

1: 解析器通过以下若干个语法表达式来解析 void f() , 这些内容在前面章节已经讲解过。

读入 void ,得到标签TYPE
通过表达式:
TYPE_SPECIFIER -> .TYPE
TYPE_OR_CLASS -> .TYPE_SPECIFIER
SPECIFIERS -> .TYPE_OR_CLASS
OPT_SPECIFIERS -> .SPECIFIERS
然后读入函数名f, 返回标签NAME,然后通过表达式:
FUNCT_DECL -> .NEW_NAME LP RP
把开头的函数的定义进行解析。

2:读入左括号,获得对应标签LC,进入STATEMENT部分的解析。

3: 解析器将通过下面步骤对变量声明语句: int a = 0; int i = 0; 进行解析,解析步骤在前面章节已经讲解过:

   读入关键字int, 得到标签type.
   根据以下表达式进行推导:
   TYPE_SPECIFIER -> .TYPE
   TYPE_OR_CLASS -> .TYPE_SPECIFIER
   SPECIFIERS -> .TYPE_OR_CLASS
   读入变量名a, 返回标签NAME,通过以下表达式进行推导:
   NEW_NAME -> .NAME
   VAR_DECL -> .NEW_NAME
   读入符号 =, 返回标签 EQUAL,读入数字0,返回标签NUMBER,继续根据相
   关表达式进行语法推导:
   UNARY -> .NUMBER
   BINARY -> .UNARY
   NO_COMMA_EXPR -> .BINARY
   EXPR -> .NO_COMMA_EXPR
   INITIALIZER -> .EXPR
   DECL -> .VAR_DECL EQUAL INITIALIZER
   DECL_LIST -> .DECL
   读入分号,得到标签SEMI,继续根据表达式进行推导:
   DEF -> .SPECIFIERS DECL_LIST SEMI
   DEF_LIST -> .DEF
   LOCAL_DEFS -> .DEF_LIST
   STATEMENT -> .LOCAL_DEFS
   STMT_LIST -> .STATEMENT

上面步骤重复2次,从而对int a= 0; int i = 0; 进行解析

4: 读入关键字for, 读入左括号(, 读入变量名i, 得到标签NAME, 根据以下语法表达式进行递归:

    UNARY -> .NAME
    BINARY -> .UNARY
    NO_COMMA_EXPR -> .BINARY

读入i 后面的等号和数字0,根据下面的表达式进行递归:

  UNARY -> .NUMBER
  NO_COMMA_EXPR -> .BINARY
  NO_COMMA_EXPR -> .NO_COMMA_EXPR EQUAL NO_COMMA_EXPR
  EXPR -> .NO_COMMA_EXPR

读入分号,得到标签SEMI, 根据表达式递归:

   OPT_EXPR -> .EXPR SEMI

这样,i = 0 就被解释为 OPT_EXPR.

5: 继续读入变量名i ,得到标签NAME, 根据下面表达式进行递归:

   UNARY -> .NAME
   BINARY -> .UNARY
   读入符号< 得到标签 RELOP 读入小于号后面的数字10,返回标签NUMBER,
   继续通过下面表达式进行递归:
   UNARY -> .NUMBER
   BINARY -> .UNARY
   BINARY -> .BINARY RELOP BINARY
   NO_COMMA_EXPR -> .BINARY
   EXPR -> .NO_COMMA_EXPR
   TEST -> .EXPR

这意味着,解析器将表达式 i < 10 解释为 TEST.

6: 继续读入后面的分号,得到标签SEMI, 读入变量i, 得到标签NAME,根据下面表达式进行递归:

   UNARY -> .NAME
   读取后面的符号++, 返回标签INCOP,继续根据下面表达式递归:
   BINARY -> .UNARY
   NO_COMMA_EXPR -> .BINARY
   EXPR -> .NO_COMMA_EXPR
   END_OPT_EXPR -> .EXPR

也就是说 i++ 这个表达式被解析器解读为END_OPT_EXPR.

7: 读入右括号),和左大括号,解析器开始 进入for 下面的STATEMENT部分的解析。由于在for循环体中,只有一句语句 a = a + 1, 因此接下来将对这句赋值语句进行解析。

8: 读入变量名 a, 得到对应标签NAME, 然后根据下面表达式进行递归:

  UNARY -> .NAME
  BINARY -> .UNARY
  NO_COMMA_EXPR -> .BINARY
  读入符号=,返回标签EQUAL, 读入等号后面的变量a,得到标签NAME,继续根据
  以下表达式进行解析:
  UNARY -> .NAME
  BINARY -> .UNARY
  读入符号+, 得到标签PLUS,读入数字1,得到标签NUMBER,继续根据表达式
  进行推导:
  UNARY -> .NUMBER
  BINARY -> .UNARY
  BINARY -> .BINARY PLUS BINARY
  NO_COMMA_EXPR -> .BINARY
  EXPR -> .NO_COMMA_EXPR
  读入分号,得到标签SEMI,继续根据表达式进行推导:
  STATEMENT -> .EXPR SEMI
  STMT_LIST -> .STATEMENT

到这里,解析器把语句a = a + 1; 先解读成EXPR, 然后继续把该表达式推导成STMT_LIST

9: 读入右大括号 }, 然后根据表达式进行递归:

 COMPOUND_STMT -> .LC STMT_LIST RC
 STATEMENT -> .COMPOUND_STMT

也就是说,解析器把for 语句后面的{…} 这部分解析成STATEMENT.

10: 根据表达式进行递归:

STATEMENT -> .FOR LP OPT_EXPR TEST SEMI END_OPT_EXPR RP STATEMEN

这时,整个for(…){…} 的代码部分被解析器解析成STATEMENT. 从而整个for循环语句能被解析器全部吸收

11: 接下来的推导跟以前一样,最后会推导到全局非终结符,进而解析器能够解析当前输入的代码。

对while, do…while 语句的解析请参看视频:

用java开发编译器

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值