至于《编译原理》,相信很多人都学习过。
就和《计算机组成原理》、《汇编语言》一样学的时候云里雾里,学完之后九霄云外。
这些知识属于难学少用,所以很容易忘记。
以前也学过 2 遍左右的编译原理,知道个大概,但是终究没有深入学习。
个人重学的理由
最新在写 lombok-ex 一个类似于 lombok 的小工具。
想把 AOP 再提升一个档次,虽然磕磕绊绊也写了一些,但是对于编译原理不深入,终究还是写的不顺畅。
至于《编译原理》,相信很多人都学习过。
就和《计算机组成原理》、《汇编语言》一样学的时候云里雾里,学完之后九霄云外。
这些知识属于难学少用,所以很容易忘记。
以前也学过 2 遍左右的编译原理,知道个大概,但是终究没有深入学习。
最新在写 lombok-ex 一个类似于 lombok 的小工具。
想把 AOP 再提升一个档次,虽然磕磕绊绊也写了一些,但是对于编译原理不深入,终究还是写的不顺畅。
本书描述了将编程语言转换成可执行代码的技巧、数据结构以及运算法则。现代编译器是由很多阶段组成的,每一阶段对不同的语言进行操作。依据这样的结构,本的每章中都包含有一个相应的阶段。
为了说明编译语言的过程,本书将以一个简单但很重要的Java子集Mini Java为例。希望读者自己能够完成每一章中相应的阶段,那么在学习完第一部分后,就实现一个编译器。Mini Java很容易进行扩展以支持类扩展以及高级指令函数,第二部分中的习题就做了这样的工作,第二部分的其他章节还介绍了程序优化的高级术。附录A介绍了Mini Java语言。
编译器模块之间的接口几乎和模块内部的运算法则同等重要。为了具体描述这些接口,我们将把它们用真正的程序语言编写出来。本书使用了一种简单的、面向对象Java语言,Java是稳定的,它不能绕过类型系统从而违反抽象的原则; Java具有垃圾回收机制,在很大程度上简化了动态空间的处理。所有的这些属性对于实编译器都是很有好处的(几乎适用于编写任何软件)。
重新写一个 java 时间有限,只能先实现一个核心功能。
所以需要对 java 多一些特性的简化。
文本主要收集一些网上资料,做下简单的整理。
Goal = MainClass, { ClassDeclaration }, EOF;
MainClass = "class", Identifier, "{", "public", "static", "void", "main", "(", "String", "[", "]", Identifier, ")", "{", Statement, "}", "}";
ClassDeclaration = "class", Identifier, [ "extends", Identifier ], "{", { VarDeclaration }, { MethodDeclaration } "}";
VarDeclaration = Type, Identifier, ";";
MethodDeclaration = "public", Type, Identifier, "(", [ Type, Identifier, { ",", Type, Identifier }, ], ")", "{", { VarDeclaration }, { Statement }, "return", Expression, ";", "}";
Type = "int", "[", "]"
| "boolean"
| "int"
| Identifier
;
Statement = "{", { Statement }, "}"
| "if", "(", Expression, ")", Statement, "else", Statement
| "while", "(", Expression, ")", Statement
| "System.out.println", "(" , Expression, ")", ";"
| Identifier, "=", Expression, ";"
| Identifier, "[", Expression, "]", "=", Expression, ";"
;
Expression = Expression , ( "&&" | "<" | "+" | "-" | "*" ) , Expression
| Expression, "[", Expression, "]"
| Expression, ".", "length"
| Expression, ".", Identifier, "(", [ Expression { ",", Expression } ], ")"
| IntegerLiteral
| "true"
| "false"
| Identifier
| "this"
| "new", "int", "[", Expression, "]"
| "new", Identifier ,"(" ,")"
| "!", Expression
| "(", Expression, ")"
;
Identifier is one or more letters, digits, and underscores, starting with a letter
IntegerLiteral is one or more decimal digits
EOF is a distinguished token returned by the scanner at end-of-file
为了把程序从一种语言翻译成另一种语言,编译器必须首先把程序分解并搞清相应的结构和含义,然后再用不同的方式把它们组合起来。编译器的前端负责分析,后端负责组合。
分析包含3类:
词法分析:将输入分解成单独的字或记号;
语法分析:分析程序中短语的结构;
语义分析:分析程序的含义。
词法分析器接收字符流,生成一系列的名字、关键字和标点符号,并舍弃了记号之间的空白符和注释。
那些随机出现的空白符和注释将分析过程复杂化了,这也是将词法分析单独分离出去的主要原因。
词法分析并不是很复杂,但是需要使用形式化的方法和工具来实现,类似的方法对于学习分析是很有好处的,类似的工具还可以应用在编译器外的其他地方。
前儿章讨论过了用符号代替正则表达式的简化机制,这种机制在使用时是很方便的:
digits=[0-9] +
sum=(digits“+") *digits
有些文法使用了像递归下降这样的简单算法来简化分析。
实际上,就是把每个文法产生式转换成一个递归函数的子句。
如文法3.11所示。
S→if E then S else S L→end
S→beginS L L→;SL
S→print E
E→num=num
LL(k)预测法的弱点是它必须预测下一个将被使用的产生式,并且需要向前查看一个字符、LR(k)是一个更有效的分析法,它可以在看见与整个产生式相关的所有输人记号以后再做出决定(多于k个记号)。
LR(k)分别代表由左自右的分析、最右推导、向前查看k个记号。最右推导的使用看起来有些奇怪,怎样用最右推导进行由左向右的分析呢?
图3.18说明了在文法3.1程序中的LR分析过程,用一个新的产生式 S'→S$ 进行扩充。
a := 7
b := C + (d := 5+6, d)