看板Programming
标 题Re: [问题] 如何学写COMPILER? [纯抛砖引玉]
发信站KKCITY (Fri Apr 27 14:10:53 2007)
转信站ptt!ctu-reader!ctu-peer!news.nctu!netnews.chu!Leo.mi.chu!zoonews.ee.nt
※ 引述《[email protected] (汀)》之铭言:
> 你好像已经忘记我更前面说「context-free LALR(1) parser」了:
BNF is context-free only
> 一个 grammer 能用 BNF 表示,
> 并不会代表它的 parser 好写,
> 因为 BNF 可以随你高兴写,
> 但写出来的 form 不见得适合 context-free LALR(1) parser 去 parse。
> 换句话说我只要随便举个 context-sensitve 的 BNF,
> context-free LALR(1) parser 就 parse 不出来,
> 这跟「不能用 machine 做 parse」是不一样的意思。
> > 3GL 是 50 年代 programming 技术, template 从 lisp(196x), forth 就有
> > OO 语言的历史比 C 还久, smalltalk(1969) 就有 dynamic typing
> > yacc 远比 template, OO 先进得多!
> 只不过是去 parse 一个 .y file,
> 然後照内订的机制去产生 .c 和 .h,
> 再摆上一堆 #line 进去辅助 debug 而已,
> 可惜这堆 #line 也拯救不了它产生出来的 code 难 debug 的特性,
> 相信你有用 debugger 跳进去看过的话应该就会有所感想。
如果所用的 yacc 可靠, 你也不该追进去看
只应该看人写的部份的 C, 好的 debugger 是支援 yacc 的
spirit 是 boost 之中特别容易让 compiler 挂点的东西之一,
光 boost 要编起来就很麻烦, 遇到 compile error 比 yacc 更头大
只因为是 C++ 就一定好 debug? error message 的数量就可说明
> 比较晚写出来并不代表它比较先进,
> 名词比较早出来并不代表它永远比较落後,
> 但是一样东西从出来到现在都没有改变,
> 却显然是落後的一种证明。
> 何况 parser generator 跟 language 谁早谁晚,
> 并不会代表早的一方比较先进,
> 今天用 C++ 的 boost::spirit library 写出的 parser,
> 显然就是比 yacc generator 出来的 parser 容易 debug,
> 因为 boost::spirit 用的技术比较先进 (无关它是否较晚被做出来),
看起来跟 yacc 很像, 却是 C++, 比较先进是说用 C++ 就先进?
xxx = a|b;
yyy = xxx|c;
因 C++ 语法限制所以还不能像 yacc 用 LR, spirit 是 LL only
从来没有比 yacc 先进的说法
> 而 yacc 使用的技术却一直停留在旧时代,
> 如此而已。
> > C++ 只是把这些 196x-197x 的东西换个用辞, 大家基本上停留在 3GL
> > 旧没有不好, 像 assembly 还不是要学会,
> 旧的东西本来就没有不好,
> 但是没有随着技术进步而更新实作内容就是不好 (白话就是不长进),
> 工程上 legacy system 本来就是一个很沈重的负担。
> assembly 永远不是旧的东西,
PPC, MIPS, x86 assembly 不够旧?
为了 binary 相容一个指另集最少活 20 年
CPU 效能看法也一直在变, 古代 ram 少, cisc>>risc, risc 不划算
民初 ram 多, risc>>cisc, 工作站用 RISC 成王道
近代 cache 少, ram 慢, cisc >> risc, x86 干掉 PPC,SPARC,MIPS
现代多核心 vliw>>cisc>>risc, 只是 compiler 难搞
何种 CPU instruction 叫先进?
> 每当一个新的 CPU 被设计出来,
> 新的 assembly language 也再次出现,
> > 商用 compiler 也还是在用 4GL, 含 yacc
> > 很多所谓的 "library" 是 4GL interpreter, 如 SQL
> > 写 compiler 用 4GL 很快很省事, bug 好不好抓跟程式架构有关,
> 这跟我看到的情形差很多,
> 商用的 compiler,
> 如 ACE Cosy、MetaWare 的 C/C++ Compiler Tool Suite、Target 的 CHESS,
> 还有 Altium TASKING 的 Viper,
> 它们的 front-end 都不是 4GL 做出来的。
microchip c18, m$ visual c 都是 bsd yacc
只要在档案中有很大的非人写成的 table, 都是 code gen 产生的
不一定是 yacc, 但是通常 compiler/interpreter 走两个极端:
1. 4GL, 最快速完成
2. 用 3GL 硬干, 执行最快速, 如 turbo pascal, 大多 interpreter
visual c 有 "grammar.y", c18 有 "yacc stack overflow"
在 compiler 执行档找 yacc 的收获会不少
> 照你上面讲的,
> 那还不是要去背 interface 跟 abstract 是什麽东西?
> 还不是要背 interface 跟 abstract 还有啥都没写差在哪?
> 事实上在 Java 也不是把 virtual 换成 interface,
> 而是把 C++ 某种 abstract base class 的特例制订成一个语言机制,
> interface 在 C++ 就是只含有 pure virtual function,
> 且没有任何 data members 的 abstract base class,
> 没有 constructor、有一个 pure virtual destructor (Java 无 destructor);
> 这只是把一个 C++ 没有明确描述的东西用明确的语言机制去描述,
> 但同时也是带给 programmer 一个限制,
> 我想你应该也注意到了,
> interface 不能有 data members,
> 但是 C++ 可以,
> 这就是所谓的限制。
> C++ 跟 Java 的取向不同,
> 赋予 programmers 自由和责任也大相迳庭,
> 要互相比较是很困难的。
照这样说, 那 yacc 跟 spirit 比 C++ 和 java 之间差更多
要互相比较是更困难罗, 为啥不能比较 C++ & java
> 所以我要强掉的:「C + 一堆 tricks」 == 「C++ + 很少 tricks 」
> 就是这个原因。
C++ 的 template 不算 tricks 的话, 比 template 更简单的 C 语法何来 tricks
C 的语法能作的变化更简单
> C++ 在 performance 上的问题没你想的夸张,
> 甚至是 memory 的占用上;
> 就算是使用纯 OOP 撰写程式也不会比 C 差到 10% 以上,
> 擅长使用 template + OO 的人可以降到 1.5 - 3% 左右,
template 为何会比 C 省 memory, 举个例吧
C 一定可以做出和 C++ 产生的 machine code 一样的东西, 最多就是 source 大点
obj C 的 dynamic typing 才是 C 一类 static typing 不能比的
> 而且 memory space 也不会因为使用 template 占用太多;
> 使用 template 来搭 OO 可以压低继承树增加 performance,
> 甚至是将 runtime 的 recursive call 改写成一连串相异函式的 tail-call,
> 懂得如何帮 template 瘦身的人更不会因为 template 而让程式特别吃记忆体,
> 这些都有书可以学。
> > C 连 calling convention 都标准化, 跨 compiler 的 linking 都可以,
> > C++ 原来 function name encoding 还算有标准, 现在不同家的 obj file 无法互通
> 事实上 C 那个不是标准化,
> 只是 x86 上有特别订一套而已,
> 你去别的 architectrue 上 try 也是死成一片,
MIPS, ARM, PPC, FR 都有标准, 但 C++ 各家 compiler 差太多, 怎麽定
一个 pointer to class method 就有 n 种作法
> 因为 gcc3 用 bison 做的 parser 实在有够烂,
bison is a version of yacc, bison != yacc
一堆 compiler 用 byacc
> 如果你真的熟悉 C++ 标准,
> 你应该知道有很多东西在旧的 compiler 放很松,
> 以 eMule 的 source code 来说最大的差异就是 typename 的检查,
> 如果 T<X>::type 的 T 是一个 class template,
> type 是 T<X> 里面的一个 typedef,
> 根据 C++ 标准,
> 你用 T<X>::type 宣告一个变数需要在前面冠上 typename,
> 但许多旧的 compiler 自行放宽了这个限制,
> 这个光 VC 6 (C++98 标准制订前发售) -> VC 7.1 就会遇上了,
> 大学时代我同学把我叫去帮他编,
> 我就解过一次,
> 其它软体在 GCC 上也遇到过这个问题。
> > C 从来没发生过旧 code 不能 compile, 或 obj file 不能 link
> 是吗?
> 我国 BBS 的 source code 就惨遭以下大地震屠杀:
> 我手上的环境是 GCC 4.3:
> /usr/include/varargs.h:35:2: #error "Change your code to use <stdarg.h> instead."
> 如果你说这只是 C standard 改了 library header 又没什麽,
> 那我把它改成 #include <stdarg.h> 好了 (其实这个例子什麽都不用 #include),
> 结果又出现:
> test2.c:3: error: ISO C requires a named argument before '...'
> 很遗憾,
> 这段纯 C 程式码在 15 - 20 年前可以正确无误的通过编译,
> 连一个警告讯息都不会有,
> 我从 K&R C 一路玩到 C99,
> legacy code 会遇上什麽问题都遇过了,
> 说 C 不会遇到 ARM -> C++98 -> C++03 -> C++0x 的问题,
> 那是绝对不可能的。
> 知道 GCC 为什麽会有 -fstrict-aliasing 这个 option 吗?
> 因为 C standard 後来有放松一些 aliasing 的判定方式,
> 让 compiler 能做出更多的 optimization,
> 以致於有些做过 pointer casting 的老旧 code (GCC 手册的范例是 union),
> 在 -O2 以上编译出来的程式码,
> 在「执行期」发生了与过去完全不同的意外行为。
如果用了非标准的 pointer access, 是写的人有问题
就如 ++i 的问题一样
较少人使用 (...) 的 function, 这是个很少出现的问题, 也很好改 search/replace
旧的 binary 和新的还是能相容
C++ 的问题如 pointer to class method != fucntion pointer,
callback 刚好是 function pointer 主要用途, 又常是 class method
造成很多 GUI 程式的 callback 大改, 又无法 binary 相容
include, export 等让书上的 hello world 都要改, 程度上很不同
> 照标准写哪怕换了 compiler 就会炸掉?
> 更何况那种东西搭一堆 #ifdef 就好了,
> 如果不是写 linux kernel (cross-compiling),
> 那还有 autoconf 可以搭上去用。
> 问题是很多人不懂标准,
> 而且标准也会随着时间修改,
> linux kernel 算还好的,
> 虽然没有直接重写成 C++,
OS 不能用 C++ 写, 因为会有 compiler/archiecture 相依性,
object 的 memory allocation, method calling 不同 compiler 都做不一样
dynamic linking 也完全没定义, 这种东西不能写 portable 的 OS kernel
古早的 OS 有用 PL/I 等高阶语言写, 都不好 port, 才会弄出万用的 C
> 但是至少 code 跟 implementation 有在改进,
> 所以我一直都没有把它当成 yacc 来骂。
--
┌─────◆KKCITY◆─────┐KKMAN团队 全新力作 ◎◎KKBOX◎◎
│ bbs.kkcity.com.tw │知名歌手通通都有 所有新歌想听就听
└──《From:59.120.53.7
》──┘※※ 内容丰富多元的线上音乐台 ※※
--
1F:推 abcdefghi:spirit是LL(k),这个 k 确实比 yacc 厉害 140.113.23.107 04/27 15:40
2F:推 ykjiang:偷瞄的效果真显着 :p 61.59.14.41 04/27 18:13