1:Micro编译器结构
(1)词法分析器:读取源程序,产生记号表示流,供语法分析器调用
(2)语法分析器:一直处理记号,知道遇到了需要语义处理的语法结构,直接调用语义例程
(3)语义例程:调用适当的支持例程生成代码
(4)符号表:有语义例程使用(接口描述)
2:Micro词法分析器
词法记号集:token(枚举类型)
Typedef
BEGIN,
}token;
Extern
词法分析器的主要识别循环过程:
#include
#include
//识别操作符,注释,分隔符,标识符,整数常量的词法分析器循环
int
while((in_char { //遇到空格就直接进行下一个token的读取 if(isspace(in_char)) continue; //如果以字母开头,表示的是标识符
else {
//如果读取的字符是数字,字母,或者下划线,则继续读取,直到获取最长的符合序列
for(c //将额外字符压回输入流
ungetc(c, //返回此标识符
return } //如果以数字开头,表示的是整数常量
else {
//如果读取的字符是数字,则继续读取,知道获取最长的符合序列
while(isdigit(c //将额外的字符压回输入流
ungetc(c, //返回此整数常量
return }
else
return
else
return
else
return
else
return
else
return
else { //查找赋值操作":="
c
if(c
return else {
ungetc(c, lexical_error(in_char); } }
else { //查找注释符"--"
c
if(c {
while((in_char } //否则为减号 else {
ungetc(c,
return } } else //不是以字母或者数字开头,则为无效字符,出错 lexical_error(in_char); }
|
保留字的识别方式:
(1)词法分析器中有一张保留字表,每当一个标识符被识别时,检查保留字表,如果在此表中,则被解释成保留字;
(2)保留字作为编译器符号表中的初始部分,含有特殊属性reserved,词法分析器识别一个标识符后,在符号中找到该标识符,如果有特殊属性,则识别为保留字。
(3)要检查保留字需要额外的缓存来存放每一个被检查了的标识符,所以,另外定义例程来实现这个功能:check_reserved()和buffer_char()
代码修改如下:
#include
#include
//识别操作符,注释,分隔符,标识符,整数常量的词法分析器循环
int clear_buffer(); if(feof(stdin))
return
while((in_char { //遇到空格就直接进行下一个token的读取 if(isspace(in_char)) continue; //如果以字母开头,表示的是标识符
else {
//缓存每个字符 buffer_char(in_char); //如果读取的字符是数字,字母,或者下划线,则继续读取,直到获取最长的符合序列
for(c buffer_cahr(c); //将额外字符压回输入流
ungetc(c, //返回标识符并检测其是否为保留字
return } //如果以数字开头,表示的是整数常量
else {
//缓存每个字符 buffer_char(in_char); //如果读取的字符是数字,则继续读取,知道获取最长的符合序列
while(isdigit(c buffer_char(c); //将额外的字符压回输入流
ungetc(c, //返回此整数常量
return }
else
return
else
return
else
return
else
return
else
return
else { //查找赋值操作":="
c
if(c
return else {
ungetc(c, lexical_error(in_char); } }
else { //查找注释符"--"
c
if(c {
while((in_char } //否则为减号 else {
ungetc(c,
return } } else //不是以字母或者数字开头,则为无效字符,出错 lexical_error(in_char); } |
3:Micro语法
使用CFG(Context-Free
产生式:A
A:左部(Left-Hand
B
产生式代表了一个规则,左部文法符号可以由其右部文法符号代替,如:
<program>
CFG中有两种文法符号:
(1)非终结符:
通常由'<'和'>'限定或者出现在产生式的左边来被识别,它们实际上是占位符,必须根据以它作为左部的产生式来替换或者重写
(2)终结符:
从来不被重写,代表语言的词法记号(token)
CFG的全部目的:指定哪些终结符序列式合法的。
CFG的检测方式:有一个开始符号(start)或目标符号(goal)的非终结符开始,随后应用产生式重写非非终结符,知道仅剩下终结符,任何可由此产生的终结符序列都被认为是合法的。
扩展的BNF可以定义:
(1)可选项:"["和"]"括起来
(2)可选的项列表:"{"和"}"括起来
但是上述功能也可以通过BNF来实现,所以,扩展的BNF实际上跟BNF是一致的。
下面定义扩展的CFG:
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.<primary>
11.<primary>
12.<add
13.<add
14.<system |
使用上述的CFG推导一个程序:begin
<program>
begin
begin
begin
begin
begin
begin
begin
begin
begin
begin
begin
begin
begin
begin |
CFG不包含优先级,如果要包含优先级,可定义如下:
<expression>
<factor>
<primary>
<primary>
<primary> |
4:递归下降语法分析
递归下降:
递归语法分析例程,当处理一个程序的时候,它下降遍历所识别的分析树。
基本思想:
每个非终结符都有一个相关的语法分析过程(parsing
对应于Micro文法产生式所编写的语法分析例程:
void { program(); match(SCANEOF); }
void { match(BEGIN); statement_list(); match(END); }
void { statement(); while(true) { switch(next_token()) {
case
case
case statement(); default:
return } } }
void {
token switch(tok) {
case match(ID); match(ASSIGNOP); expression_r(); match(SEMICOLON); break;
case match(READ); match(LPAREN); id_list(); match(RPAREN); match(SEMICOLON); break;
case match(WRITE); match(LPAREN); expr_list(); match(RPAREN); match(SEMICOLON); break; default: syntax_error(tok); break; } }
void { match(ID);
while(next_token() { match(COMMA); match(ID); } }
void { primary();
for(t { add_op(); primary(); } }
void { expression_r();
while(next_token { match(COMMA); expression_r(); } }
void {
token
if(add_op match(tok); else syntax_error(tok); }
void {
token swith(tok) {
case match(LPAREN); expression_r(); match(RPAREN); break;
case match(ID); break;
case match(INTLITERAL); break; default: syntax_error(); break; } } |
5:翻译Micro
5.1:目标语言(三地址机器代码)
5.2:临时变量(Temp&X)
5.3:动作符号(见代码)
5.4:语义信息(见代码)
5.5:Micro动作符号(见代码)
文法符号的语义记录:
#define
typedef
typedef {
enum }op_rec;
enum
typedef {
enum union {
string
int }; }expr_rec; |
带有符号动作的Micro文法:
<program>
<statement
<statement>
<statement>
<statement>
<id
<expr
<expression>
<primary>
<primary>
<primary>
<add
<add
<ident>
<system |
符号表例程的规范及相应于Micro动作符号的语义例程所必须的辅助例程:
//判断s是否在符号表中
extern //将s无条件地加入符号表
extern //辅助例程check_id():把一个变量加入符号表 //并生成一条预留存储空间的汇编命令语句来声明变量
void {
if(! { enter(s); //创建一条完整的指令
generate("Declare", } } //函数get_temp()分配临时变量
char { //目前为止最大的临时分配空间
static
static max_temp++;
sprintf(tempname, check_id(tempname);
return }
|
Micro的动作例程:
void { }
void {
generate("Halt", }
void {
generate("Store", }
op_rec {
op_rec
if(current_token
o.operator else
o.operator
return }
expr_rec {
expr_rec
erec.kind
strcpy(erec.name,
generate(extract(op),
return }
void {
generate("Read", }
expr_rec {
expr_rec check_id(token_buffer);
t.kind
strcpy(t.name,
return }
expr_rec {
expr_rec
t.kind
(void)sscanf(token_buffer,
return }
void {
generate("Write", }
|
修改语法分析过程以包含语义处理的例子:
未包含语义处理之前:
void { primary();
for(t { add_op(); primary(); } } |
包含了语义处理之后:
void {
expr_rec
op_rec primary(&left_operand);
while(naex_token() { add_op(&op); primary(&right_operand);
left_operand }
*result } |
递归下降语法分析和翻译示例:begin
上述过程中语法分析器动作有:
1:调用语法分析例程(如:system_goal(),statement_list()等)找出输入中的一个字符串来匹配文法中的非终结符
2:调用match()来匹配文法终结符和一个输入词法记号(如:match(BEGIN),match(ID)等)
3:调用语义动作例程(如:start(),process_id()等)
分析步骤记录:
_______________________________________________________________________________
(1)Call
(2)Call
(3)Semantic
(4)Math(BEGIN)
(5)Call
(6)Call
(7)Call
(8)match(ID)
(9)Semantic
(10)match(ASSIGNOP)
(11)Call
(12)Call
(13)Call
(14)match(ID)
(15)Semantic
(16)Call
(17)match(MINUSOP)
(18)Semantic
(19)Call
(20)match(INTLITERAL)
(21)Semantic
(22)Semantic
(23)Call
(24)mathc(PLUSOP)
(25)Semantic
(26)Call
(27)Call
(28)match(ID)
(29)Semantic
(30)Semantic
(31)Semantic
(32)match(SEMICOLON)
(33)match(END)
(34)match(SCANEOF)
(35)Semantic |