编译器与解释器的设计流程
编译器前端部分
词法分析 (字符流->记号流)
词法分析也称作扫描,是编译器的第一个步骤,词法分析器读入组成源程序的字符流,并且将它们组织成为有意义的词素的序列,对于每一个词素,词法分析器产生如下形式的词法单元作为输出。实际上就是从字符流到单词流的过程。
语法分析(语法树)
也称作解析,语法分析器使用由词法分析器生成的各个词法单元的第一个分量来创建树形的中间表示。该中间表示给出了词法分析产生的词法单元流的语法结构。一个常用的表示方法是语法树,树中的每个内部结点表示一个运算,而该结点的子结点表示该运算的分量。
语义分析
语义分析器使用语法树和符号表中的信息来检查源程序是否和语言定义的语义一致。它同时也收集类型信息,并把这些信息存放在语法树或符号表中,以便在随后的中间代码生成过程中使用。语义分析的一个重要部分是类型检查,编译器检查每个运算符是否具有匹配的运算分量,比如数组下标必须是整数,若用一个浮点数来做下标,编译器就会报错。程序设计语言可能允许某些类型转换,这被称作自动类型转换。
中间代码生成
在把一个源程序翻译成目标代码的过程中,一个编译器可能构造出一个或多个中间表示。这些中间表示可以有多种形式。其中语法树是一种中间表示形式。在源程序的语法分析和语义分析完成之后,很多编译器生成一个明确的低级的或类机器语言的中间表示,我们可以把这个表示看作是某个抽象机器的程序。该中间表示应该具有两个重要的性质:易于生成,且能够被轻松地翻译为目标机器上的语言。
编译器后端部分
代码优化
目标代码生成
解释器前端部分
词法分析
语法分析
语义分析
中间代码生成
执行
Tiny语言
TINY语言的介绍
- TINY的程序结构是一个由分号分隔开的语句序列。
- 既无过程也无声明。
- 所有的变量都是整型变量,通过对其赋值可较轻易地声明变量。
- 只有两个控制语句: if语句和repeat语句,这两个控制语句本身也可包含语句序列。If语句有一个可选的else部分且必须由关键字end结束。
- read语句和write语句完成输入/输出。
- TINY的表达式只有布尔表达式和整型算术表达式。布尔表达式由对两个算术表达式的比较组成,该比较使用<与=比较算符。算术表达式可以包括整型常数、变量、参数以及4个整型算符+、-、*、/,此外还有一般的数学属性。
Tiny 语言的文法
!(/home/ngkimbing/git/Tiny/BNF中Tiny的文法)
Lex & Yacc
Lex
首先,lex和yacc是开源工具,帮助开发者实现语法,词法分析。如果作为一个开发者去使用它们,就需要阅读它们的说明书,直到你会用,一句话,就是个工具而已。当然,如果你对编译原理很清楚,可以更好地理解它,甚至可以分析它们的源代码哦。
Lex和yacc都是贝尔实验室在20世纪70年代发明的。
lex 代表 lexical analyzar(词法分析器)
yacc 代表 yet another compiler compiler(编译器代码生成器)
一个简单的Lex程序
test.l
/* 第一段 */
%{
int chars = 0;
int words = 0;
int lines = 0;
%}
/* 第二段 */
mywords [a-zA-Z]+
mylines \n
mychars .
%%
{
mywords} {
words++; chars += strlen(yytext); }
{
mylines} {
chars++; lines++; }