C编译器剖析_3.1 语法分析_C语言的表达式(1)

3.1  C语言的表达式

    从第3章开始,我们进入UCC编译器的语法分析阶段。相关的代码主要在ucl\decl.c、ucl\expr.c和ucl\stmt.c,分别对应声明Declaration、表达式Expression和语句Statement。在第一章时,我们已经通过一个简单的例子ucc\examples\sc对这些概念有了一个直观的体会,在这一章中,我们需要结合IT大佬们制定的C标准文法来进行语法分析。基本的分析方法和第1章的例子类似,只是所涉及到的文法更加复杂,所构建的语法树也更加庞大。《K&R》的附录”A.13Grammar”一节给出了完整的C89标准文法,可把这一节不到6页的C文法打印出来,对照着UCC的源代码来看。在本章中,我们要完成的任务很明确,就是把C源代码转换成更加适合编译器处理的语法树。我们需要先熟悉一下语法树上最基本的结点,如图3.1.1所示。


图3.1.1   struct astNode

    图中第34行的结构体struct astNode就是语法树中一个最基本的结点,第30行的kind用于记录结点的类别,其取值范围由第6至第23行的枚举常量来确定,第8至14行的NK_Function等枚举常量主要用于标识语法树中与“声明Declaration”相关的结点,而第16行的NK_Expression就用于标识“表达式Expression”结点,第18至22行的NK_IfStatement等主要用于与“语句Statement”相关的结点。第31行的next域用于构成链表。第32行的coord主要用于记录与语法树结点对应的C源代码的位置。结构体struct astNode相当于是所有语法树结点的父类,如果要描述表达式对应的结点,我们需要引入能记录更多信息的结构体struct  astExpression,如图3.1.2所示。


图3.1.2   struct astExpression

      图3.1.2第44行的ty用于记录表达式对应的类型,我们在2.4节中初步介绍过C语言的类型系统。第45行的op是operator的缩写,用于记录表达式的运算符,而第52行的kids则用于记录表达式的运算数。第46行的isarray用于标记当前结点是否为数组,本来第44行的ty域就已记录了结点的类型信息,但是因为数组名在C语言中会被当作“指向数组第0个元素的指针”,此时在ty域中记录的类型已转变为指针类型,所以需要isarray来标记这个结点原本是个数组。第48行的lvalue则是left value的缩写,代表对应的表达式是否为左值。而第49行的bitfld用来标记当前结点是否为结构体对象的位域成员,对位域成员的访问比较特殊,需要进行移位操作。有了这个基础后,我们就可以来看一下ucl\expr.c中对表达式Expression的语法分析了,如图3.1.3所示。


图3.1.3 ParseExpression()

     图3.1.3第514至516行注释中的产生式告诉我们,C语言的表达式Expression由若干个被逗号隔开的赋值表达式AssignmentExpression构成。我们以下面”a,b,c”这个简单的表达式来说明一下由函数ParseExpression()所构成的语法树,如图3.1.4所示。


图3.1.4   表达式“a,b,c”对应的语法树

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值