- 论坛徽章:
- 2
|
回复 437# Ager
先说"人生攻击"那帖,我记错了,不是你发的。。。
提到这个是想说:一开始开到你的回帖,我直觉上感到里面有什么不对。然后从"产生代码不相同->代码不等价"开始,推出"相同表达式也不等价",发现原来这逻辑这么荒唐。然后就这么写了,顺手又发了。
发过之后又读了读,感觉攻击性太强,所以就在后面解释了一通。
至于发生在哪一步。先说一般化的情况,编译器不一定是一个密不可分的整体。
有一种可能的设计是:
1. 一部分是将源代码转换到中间代码
2. 另一部分再从中间代码转换到目标代码
中间代码可能与源代码相差很大,也有可能就是源代码的一个子集。而且中间代码不一定只有一步。
甚至可以从另一个角度来看这件事:对最终用户来说编译器是L->T语言,但编译器本身可能是L->L0->L1->...->T。
每一层得到的输入是上一层转换后的输出,已经看不到原样了,察觉不到区别了。
举一些差别不大的例子。
- -- 不需要分号,但需要对齐
- let x = 12
- y = 26
- in x + y
- -- 转换成这样,不需要对齐(虽然写的是对齐了的),但需要分号
- let { x = 12
- ; y = 26 }
- in x + y
- -- 对齐不是强制的,甚至还可以在一行
- let { x = 12 ; y = 26 } in x + y
- -- 这是列表
- [1,2,2,6]
- -- 被转换成通过(:)以及[]构造
- 1:2:2:6:[]
- -- 这是字符串
- "1226"
- -- 被转换成Char的列表
- '1':'2':'2':'6':[]
复制代码 这些转换都是语言spec里面写了的。
Haskell has adopted many of the convenient syntactic structures that have become popular in functional programming.
In this Report, the meaning of such syntactic sugar is given by translation into simpler constructs.
If these translations are applied exhaustively, the result is a program written in a small subset of Haskell that we call the Haskell kernel.
http://www.haskell.org/onlinereport/intro.html#sect1.2
上面两种转换的定义在:
2.7 Layout: http://www.haskell.org/onlinereport/lexemes.html#sect2.7
3.7 Lists: http://www.haskell.org/onlinereport/exps.html#sect3.7
被转换后的代码依然是合法的,是转换前的一个子集,写起来更困难。
而转换后差别很大的例子,Haskell kernel到GHC(Haskell的一个编译器) core就是。已经不是合法的Haskell代码了。我也手写不出来。。。
无论差别有多大,下层的都看不到上层的区别。
Haskell kernel->GHC core这个stage不知道Haskell源代码是怎么写的,是[1,2]还是1:2:[]。它只看得到后者。
GHC core -> asm这个stage也不知道core是由怎样的kernel转换来的。
所以[1,2]与1:2:[]是等价的。如果产生的最终代码不一样,肯定是其他原因造成的,不会是[1,2]与1:2:[]的写法不同造成的。
这种将core写进spec的语言不算少。
但其他许多语言虽然没做到这一步,也还是在局部有点这种意思的,它们把这个叫做语法糖。写起来舒适,但效果不变。
回到C。spec只说了p[x]是根据*(p+x)定义,没说后者一定是中间格式,没有将那个转换写进spec。
不过这样的转换并不是很困难的事情,没理由让两者产生不一样的代码。
我基本上不写*(p+x)的,大都写p[x]。而p[x]你列出的两种转换方式我都见过。就是说,这不一定是因为*(p+x)的原因,而是p[x]本身就有可能翻译为不同的代码。
|
|