第二章 一个简单的语法制导翻译器
将具有代表性的程序设计语言语句翻译为三地址码(一种中间表示形式),本章的重点是编译器的前端,特别是词法分析,语法分析和中间代码生产。
建立一个中缀算术表达式转换为后缀表达式的语法制导翻译器
{
int i; int j; float[100] a;float v;float x;
while(true){
do j = i+1;while(a[i]<v);
do j = j-1;while(a[j]>v);
if(i>=j) break;
x = a[i]; a[i] = a[j]; a[j] = x;
}
}
引言
编译器在分析阶段把一个源程序划分成各个组成部分,并生成源程序的内部表示形式。这种内部表示称为中间代码。然后编译器在合成阶段将这个中间代码翻译成目标程序。
分析阶段的工作是围绕着待编译语言的“语法”展开的,一个程序设计语言的语法(syntax)描述了该语言的程序的正确形式,而该语言的语义(semantics)则定义了程序的定义,即每个程序在运行时组做什么事情,接下来将给出一个广泛使用的表示方法来描述语法,这个方法就是上下文无关文法或BNF(Backus-Naur范式)。使用现有的语义表示方法来描述一个语言的语义的难度远远大于描述语言的语法的难度。因此,将结合非形式化描述和启发性的示例来描述语言的语义。
上下文无关法不仅可以描述一个语言的语法,还可以指导程序的翻译过程。接下来将介绍面向文法的编译技术,即语法制导翻译(syntax-directed translation)技术,或者说语法分析。
从中缀表达式到后缀表达式的语法制导翻译过程,后缀表达式是一种将运算符置于运算符置于运算分量之后的表示方法。
词法分析器使得翻译器可以处理由多个字符组成的构造,比如标识符。标识符由多个字符组成,但是在语法分析阶段被当做一个单元进行处理。这样的单元被称为词法单元(token)
中间代码生成,一种被称为抽象语法树(abstract synta tree),或者简称语法树(syntax tree),它表示了 源程序的层次化语法结构.
2.2 语法定义
用于描述程序设计语言语法的表示方法–‘上下文无关文法’或者简称“文法”。
文法自然地描述了大多数程序设计语言构造的层次化语法结构,例如if-else语句。
if (express) statement else statement
//用expr表示表达式,变量struct表示语句
struct->if(expr)stmt else stmt
其中箭头(->)可以读作“可以具有如下形式”,这样的规则称为产生式(production)像if和括号这样的词法元素称为终结符号(terminal),像expr和stmt这样的变量表示终结符号的序列,它们称为非终结符号。
2.2.1文法定义
一个上下文无关文法(context-free grammar)由四个元素组成
- 一个终结符号集合,它们有时候被称为“词法单元”。终结符号是该文法所定义的语言的基本符号的集合;
- 一个非终结符号合集,它们有时候也被称为“词法变量”。每个非终结符号表示一个终结符号串的集合
- 一个产生式集合,其中每个产生式包括一个称为产生式或者左部的非终结符号,一个箭头,和一个称为产生式体或右部的由终结符号及非终结符号组成的序列。产生式主要用来表示某个构造的某种书写形式。如果产生式头非终结符号组成的序列,那么该产生式体就代表了该构造的一种书写形式。
- 指定一个非终结符号为开始符号
词法单元和终结单元
在编译器中,词法分析器读入源程序中的字符序列,将它们组织成为具有词法含义的词素,生成并输出代表这些词素的词法单元序列。词法单元由两个部分组成:名字和属性。词法单元的名字是语法分析器在进行语法分析时使用的抽象符号,我们常常把这些词法单元名字称为终结符号,因为他们在描述程序设计语言的文法中是以终结符号的形式出现的。如果词法单元具有属性值,那么这个值就是一个指向符号表的指针,符号表中包含了该词法单元的附加信息,这些附加信息不是文法的组成部分,因此在我们的讨论语法分析时,通常将词法单元和终结符号当做同义词。
以非终结符号list为头部的三个产生式可以等价地组合为:
list->list + digit|list - digit|digit
2.2.2 推导
根据文法推导符号串时,首先从开始符号出发,不断将某个非终结符号替换为该非终结符号的某个产生式的体。可以从开始符号推导得到的所有符号终结符号串的集合称为该文法定义的语言(language)。
语法分析(parsing)的任务是:接受一个终结符号串作为输入,找出从文法的开始符号推导出这个串的方法。如果不能从文法的开始符号推导得到该终结符号串的方法。如果不能从文法的开始符号推导得到该终结符号串,则报告该符号串中包含的语法错误。
2.2.3 语法分析树
语法分析树用图形方式展现了从文法的开始符号推导出相应语言中的符号串的过程。
给定一个上下文无关法,该文法的一颗语法分析树(parse tree)是具有以下性质的树:
- 根节点的标号为文法的开始符号;
- 每个叶子结点的标号为一个终结符号或e;
- 每个内部结点的标号为一个非终结符号;
- 如果非终结符号A是某个内部结点的标号,并且它的子结点的标号从左到右分为为X1,X2…Xn
关于树形结构的术语
树形结构在编译系统中起着重要的作用。
- 一棵树由一个或者多个结点组成。结点可以带有标号(label)
- 树有且只有一个根(root)节点。每个非根节点都有唯一的父(parent)节点。根结点没有父节点。
- 如果节点N是结点M的父节点,那么M就是N的子结点(child)结点,一个结点的各个子结点彼此被称为兄弟(sibling)节点。它们之间是有序的,按照从左往右的方式排列
- 没有子结点的节点称为叶子(leaf)节点,其他节点,即有一个或者多个子结点的节点,称为内部节点(interior node);
- 节点N的后代(descendent)结点要么是结点N本身,要么是N的子结点。