1、 编译器是一种翻译程序,它用于将源语言(即用某种程序设计语言写成的)程序翻译为目标语言(即用二进制数表示的伪机器代码写成的)程序。后者在windows操作系统平台下,其文件的扩展名通常为.obj。该文件通常还要经过进一步的连接,生成可执行文件(机器代码写成的程序,文件扩展名为.exe)。通常有两种方式进行这种翻译,一种是编译,另一种是解释。后者并不生成可执行文件,只是翻译一条语句、执行一条语句。这两种方式相编译比解释运行的速度要快得多。
2、 编译过程的5个阶段:词法分析;语法分析;语义分析与中间代码产生;优化;目标代码生成。
3、 在这五个阶段中,词法分析的任务是识别源程序中的单词是否有误,编译程序中实现这种功能的部分一般称为词法分析器。在编译器中,词法分析器通常仅作为语法分析程序的一个子程序以便在它需要单词符号时调用。在这一编译阶段中发现的源程序错误,称为词法错误。
4、 语法分析阶段的目的是识别出源程序的语法结构(即语句或句子)是否错误,所以有时又常为句子分析。编译程序中负责这一功能的程序称为语法分析器或语法分析程序。在这一阶段中发现的错误称为语法错误。
5、 C语言的(源)程序必须经过编译才能生成目标代码,再经过链接才能运行。PASCAL语言、FORTRAN语言的源程序也要经过这样的过程。通常将C、PASCAL、FORTRAN这样的语言统称为高级语言。而将最终的可执行程序称为机器语言程序。
6、 在编译C语言程序的过程中,发现源程序中的一个标识符过长,超过了编译程序允许的范围,这个错误应在词法分析阶段发现,这种错误通常被称作词法错误。
语法:描述一个程序语言的正确性
语义:描述一个程序的含义
上下文无关文法是用来描述语法的一种办法,而描述语义的难度太大。
上下文无关文法中的一些概念:
终结符号
可以理解为关键字或者一些最小单元的字符,比如while if 0 1 3 之类
非终结符号
是终结符号的集合,是自己命名的一个东西比如 digit -> 0 | 1|2|3…|8|9,这里digit称为非终结符号
产生式
产生式由两部分组成,左边是非终结符号,右边是非终结符号和终结符号的集合
比如:digit -> 0 | 1|2|3…|8|9,这一行本身就是产生式
开始符号
一段文法的第一行称为开始符号
文法的二义性
list -> list + digit | list - digit
list -> digit
digit -> 0|1|2|3|4|5|6|7|8|9
上面定义了一个文法,然后一个demo:9 - 5 + 3
用语法树来解析,过程如下:
1.先列出来目标内容
9 - 5 + 3
2.然后把他们都看成某个非终结符号
digit digit digit
9 - 5 + 3
3.再往上找关系
list
digit digit digit
9 - 5 + 3
可以发现,list - digit可以组成list。
list
/ \
list digit
digit | digit
9 - 5 + 3
4.继续
list
/ \
list + digit
/ \ |
list - digit |
digit | |
9 - 5 + 3
这样就根据一个文法定义,一个语句,生成了唯一的语法书,那么这个语句就没有二义性。
你可以试试,先将 5 + 3 -> list + digit,这就变成了list了,然后 9 - list,也就是 digit - list 或者是 list - list ,你就会发现文法中并没有这样的定义,也就是不存在这样的语法,这样也就造成了以上的内容只有一种解析结果。
如果从叶子节点开始计算,计算顺序就是 (9 - 5) + 3 是正确的
如果有二义性,那么有可能出现不同的计算顺序,导致结果出错,所以文法的定义没有二义性很重要
运算符的结合性
结合性有左结合和右结合。
左结合:
当一个数字左右两边都有运算符的时候,要根据运算符的结合性来决定数字是属于哪一边的
比如+是左结合
1+2+3 -> (1+2)+3 因为2左右两边都有+号,+号是左结合的,所以2是属于左边的运算符。
用文法定义的时候:
result -> result + digit | result
digit -> [0-9]
用语法树来表示
result
result digit
result digit |
digit | |
1 + 2 + 3
再看右结合
a = b = c
b的左右两边有运算符 =
=运算符是右结合的,所以b 是优先属于右边的操作符
a = (b = c)
文法定义:
result -> char = result | char
char-> [a-z]
用语法树表示:
result
char result
| char result
| | char
a = b = c
运算符的优先级
比如 * / 和 +- 就是两个级别的运算符,设计文法的时候可以将两个独立的分开比如如下的文法
expr -> expr + term | expr - term | term //expr是加减表达式
term-> term* factor | term/ factor | factor //term是乘除表达式
factor -> digit | expr
digit -> [0-9]
例子
1 + 2 * 3 //我们应该优先计算 2 * 3,直接在本子上画个语法树就出来了,我只能说,真的很巧妙!
任意优先级层次的语法
factor理解为一个因子,不可以被任何运算符分开,因为它就是数字本身了
高优先级的运算符可以把低优先级的运算符分开
比如 1 + 2 * 3
可以看成 1 + x 但是 * 比+的优先级更高,它可以把x分开