C 词法分析中的“贪心法”

c语言底层读取字符的方法:

本文出自《c的陷阱与缺陷》 【美】 Andrew Koenig 著 人民邮电出版社

C语言的某些符号,例如/*、和=,只有一个字符长,称为单字符符号。而C语言中的其他符号,例如/“==,以及标识符,包括了多个字符,称为多字符符号。当C编译器读入一个字符后又跟了一个字符“,那么编译器就必须做出判断: 是将其作为两个分别的符号对待,还是合起来作为一个符号对待。 C语言对这个问题的解决方案可以归纳为一个很简单的规则;每一个符号应该包含尽可能多的字符。也就是说,编译器将程序分解成符号的方法是,从左到右一个字符一个字符地读入,如果该字符可能组成一个符号,那么再读入下一个字符,判断已经读入的两个字符组成的字符串是否可能是一个符号的组成部分;如果可能,继续读入下一个字符,重复上述判断,直到读入的字符组成的字符串已不在可能组成一个有意义的符号。这个处理策略有时被称为 “ 贪心法 ” ,或者,更口语化一点,称为“大嘴法”。Kemighan与Ritchie对这个方法的表述如下,“如果(编译器的)输入流截止至某个字符之前都已经被分解为一个个符号,那么下一个符号将包括从该字符之后可能组成一个符号的最长字符串。”

需要注意的是,除了字符串与字符常量,符号的中间不能嵌有空自(空格链制表符和换行符)。
例如,== 是单个符号,
= = 则是两个符号,
下面的表达式

a---b //(a--)-b = a-1-b 

与表达式:

a-- -b // (a--)-b = a-1-b

的含义相同,而与

a- --b // a-(b--) = a-b+1

的含义不同,同样地,如果/是为判断下一个符号而读入的第一个字符串,.而/之后紧接着*,那么无论上下文如何,这两个字符都将被当的一个符号/*,表示一段注释的开始。

根据代码中注释的意思,下面的语句的本身似乎是用x除以p所指向的值,把所得的商再赋给y:

y = x/*p

而实际上,/*被确部器理解为一段注释的开始、编译器将不断读入字符,直到*/出现为止,也就是说,该语句直接将 x 的值赋给了 y。根本不会顾及到后面出现的 p ,将上面的语句重写如下:

y = x / *p

或者更加清楚一点,写作:

y= x/*p)

这样得到的实际效果才是语句注释所表示的原意:
请如此类的 准二义性(ncar-ambiguity) 问题,在有的上下文环境中还有可能招致麻烦。侧如,老版本的C语言中允许使用=+来代表现在+=的含义,这种老版的C编译器会将:

a=-1;

理解为下面的语句

a =- 1

亦即

a =a-1      //a--

因此,如果程序员的原意是:简单的赋值

a= -1

那么所得结果将使其大吃一惊。

另一方面,尽管/*看上去像一段注释的开始,在下例中这种老版本的编译器会将

a=/*p

当作

a/= *p

这种老版本的编译器还会将复合赋值视为两个符号,因而可以毫无疑问地处理

a >> = 1

而一个严格的ANSIC编译器则会报错。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Modify_QmQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值