编译器是怎么工作的?使用yacc 和lex 写一个计算器
前天开始学yacc 和lex编译器,找了一通文档,发现没有好的文档,都是一上来就给初学者来个下马威讲高深的玩意,
所以我决定写一篇从初学者的观点来看编译器的文章。
让我们从计算器开始
-----------------------------
一听说要学习编译器,马上有同学想到C++,就会痛苦不堪,那一大坨** ,还要编译它?
没关系,我们不编译C++,我们只作和它功能相似的计算器。我们要写一个解释器,能计算诸如:
1+2+3+4+5
的表达式的就可以知道编译器作了哪些事。
分析这个表达式 1+2+3+4+5,先不说计算机, 人是怎么手工计算的?你当然会算:
1+2 = 3
3+3 = 6
6+4 = 10
10+5 = 15
恩,把两个数相加的结果加到另外一个数上就可以了,整个计算过程加上括号:
((((1+2) +3 ) +4 ) +5 )
考虑上边的计算过程,如果我们的程序也能像人一样,处理以上过程,不就可以处理这些计算了吗?
我的语法,我说了算
----------------
观察
1+2 = 3
3+3 = 6
6+4 = 10
10+5 = 15
这几组表达式,我们待计算的东西是什么?对, 是一个数 + 另外一个数,我们加出来的还是一个数,即:
数 + 数 = 数 /* number + number = number */
这是一个我们定义的加法模式,只要符合这个等式左边模式的,都可以被我们以上的表达式所处理了
如给已经接受了这种规则的状态,起个新名字为expression,
则我们可以定义我们能够处理(或接受)的输入为:
expression :
number + number
考虑(1+2) +3
因此,我们可以接受的加法计算器表达式变成了以下两种
expression:
number + number
或 expression + number
如果我们用 | 表示“或”的话,上边的表述则可以变成下边的:
expression:
number + number
| expression + number
以后的((((...)))都可以被我们后一条的语法所解析和接受
我们的计算规则: number + number = number 如果代入上式
就变成了:
expression:
number
| expression + number
上边的式子的意思是:
一个表达式可是一个数
一个表达式也可以是另外一个表达式加上一个数。
让我们来人肉编译一下这两条规则
15 OK,应用 第一条规则,15是我们定义的计算器可以接受的
(1+2)+3
先应用第1条规则
变成
(expression + 2) + 3
再应用第二条规则
变成 expression + 3
没错,这也是我们的计算器可以接受的
鸡生蛋生鸡生蛋生鸡生蛋生鸡生蛋生鸡生蛋生鸡生蛋生鸡。。。这就是递递递递递递递递递递递递递归了