龙年读龙书——如何学习编译原理(一)
我想成为二进制高手!
虽然不确定这个学了对二进制有没有用,但学校也有这个课,就开始看了。
第一章
编译器(complier):将源语言翻译成目标语言,并可以报告错误的一个程序。
从源程序形成可执行文件,需要经过预处理器(preprocessor),再通过编译器产生汇编语言程序,由汇编器(assmbler)处理,生成可重定位的机器代码,连接器(linker)解决内存地址问题,再由加载器(loader)统一执行。
编译器结构和步骤:
两个部分:分析(analysis)和综合(synthesis),也分别称为编译器的前端(front end)和后端(back end)。
步骤:
- 词法分析(lexical analysis)或扫描(scanning),形成有意义词素(lexeme)。词法分析产生词法单元(token)作为输出:<token-name,attribute-value>。类似于一个 <属性 ,存储位置> (?瞎理解的)的东西。
- 语法分析(syntax analysis)或解析(parsing),常用语法树(syntax tree)。类似于表达式求值这种,当然肯定复杂很多。
- 语义分析(semantic analysis),检查源程序是否符合源语言的规定,一个重要部分是类型检查(type checking),支持一些自动类型转换(coercion)。
- 中间代码生成,三地址代码(three-address
code),用类似于汇编的指令组成,形如
or , 是某种运算。 - 代码优化和代码生成。
- 符号表管理。符号表记录源程序中的各种变量名和属性相关信息,支持编译器查询/修改/存储每个名字的记录。
- 最后统一为一个趟(pass)。
然后是一些杂项,包括历史,应用,体系架构啥的。
程序语言设计基础
静态(static)和动态(dynamic):取决于一个问题是否可以在编译时刻(complie time)决定,还是在运行时刻(run time)决定。
作用域(scope):一个 变量
环境(environment)与状态(state):环境是一个从名字到存储位置(变量,C 语言中的 “左值”)的映射,状态是一个位置到值的映射(C 语言中,即把左值映射为右值)。
参数传递机制:
实在参数:调用过程中使用的参数。
形式参数:过程定义中使用的参数。
- 值调用(call-by-value):对参数求值或拷贝变量。需要注意的是,很多指针是值调用,也可以更改变量的值,比如传递数组名。
- 引用调用(call-by-reference):传递实在参数的地址。类似于传指针,会修改参数的值。但是如果是表达式,调用前会先求值并存储到一个新位置上,此时修改不会影响数据。
- 名调用,今天不再采取,忽略(
别名(alias):就是两个形式参数指向同一个位置,修改一样的东西。
第二章
上下文无关文法(context-free grammar):
- 终结符号(terminal),就是前面的词法单元。
- 非终结符号(nonterminal),“语法变量“,表示一个终结符号串的集合。
- 产生式(production),包括一个产生式头部或左部的非终结符号,箭头,一个产生式体或右部的由上面两个符号组成的序列,表示产生式头代表的一种构造的书写形式。形如
,其中 是一个非终结符号, 是串,表示 可以由 中的某种方式构造。 - 开始符号(starts symbol),指定的一个非终结符号。
推导:从开始符号串出发,不断将某个非终结符号替换为其某个产生式的体。
语言(language):一个文法可以推导出的所有终结符号串的集合。
语法分析(parsing):接受一个终结符号串,找出推导方法。如果不能,报告语法错误。
语法分析树(parse
tree):将推导过程表示成树形结构。构造方式为,如果使用产生式
二义性(ambiguous):一个文法有多个语法分析树可以生成同一个终结符号串。
运算符的结合(associate):左结合是运算分量两侧都有运算符时,属于左边的运算符,右结合则属于右边。简单理解就是
运算符的优先级:很熟悉的东西,不多说了(
后面一些内容在之后的章节会有具体讲述,所以 gugugu