7:54 2006-3-16
试验报告:
主程序,cmplie.exe 源文件 cmplie.c
辅助程序 creatTree.exe viewTree.exe
pro.txt 是输入的“程序”文件,即要被编译的文件
pro.txt----------->(cmplie.exe)------->te.txt 和 四元式(在屏幕上)
te.txt-------->(creatTree.exe)--------->tree.xml
tree.xml------->(viewTree.exe)--------->可视化语法树
语法规则:
program->def_list
def_list->def_list defintion|defintion
defintion->type var_init kinds
var_use->id [simple_exp]*
type->int | bool
kinds-> = num ;| ( type var_use) { sentence_list } | ;
sentence_list->sentence_list sentence | sentence
sentence->expper | simple_exp;
expper->var_use = simple_exp;| phylum| call ;| if_stmt | while_stmt | return_stmt
phylum->{ sentence_list }
call->id (id_list)
e->else sentence_list | empty
if_stmt->if ( relop_exp ) sentence e
while_stmt->while ( relop_exp ) sentence
renturn_stmt->return simple_exp ;
id_list->var_use [,var_use]* | empty
simple_exp-> trem [addop term]*
term->term mulop factor | factor
factor->( simple_exp ) | var_use | num
relop_exp->simple_exp [relop simple_exp]+
mulop->* | \
addop -> + | -
relop->== | < | <= | > | >= | != | & | ! | |
类似c语言的规则,
系统主要构成:
预处理程序(删除注释)+词法分析程序+LL2(语法分析)+基于自顶向下的语义分析+输出中间代码
核心算法:
模块化解释:
预处理程序:
代码:
void clear()
{
FILE *fout,*fin;
char t;
fout=fopen("pro.txt","r");
fin=fopen("te.txt","w");
t=fgetc(fout);
while(!feof(fout)) 去处类似 // 之类的注释
{
if(t!='/') fprintf(fin,"%c",t);
else
{
t=fgetc(fout);
if(t!='/')
{
fprintf(fin,"%c",t);
continue;
}
else
{
while(t!='\n') t=fgetc(fout);
}
fprintf(fin,"%c",t);
}
t=fgetc(fout);
}
fprintf(fin,"$");
fclose(fout);
fclose(fin);
}
词法分析程序:
代码:
采用token_first 和 token_second 两个结构体来保留两个字符,
int accept() 为了满足LL2分析设计的具有提前读取的词法分析程序
{
char *p;
每次从文件读到token_second中,token_first的内容是token_second前一次的
例如:文件里有 a b c d 四个词
在同一状态下:
状态 token_first token_second
1 NULL a
2 a b
3 b c
4 c d
5 d NULL
可以看出,token_second 总是走在 token_first 前
p=token_second.content;
将上一次token_second 赋值给 token_first
strcpy(token_first.content,token_second.content);
token_first.lines=token_second.lines;
token_first.type=token_second.type;
token_first.value=token_second.value;
*p='\0';
if( ch1 == '$')
return 1;
charNoEmpty();
token_second.lines=lines;
token_second.value=0;
if((ch1 >= 'a' && ch1 <= 'z') || (ch1 >= 'A' && ch1 <= 'Z')) 字符串处理
{
do{
*p=ch1;
p++;
ch1=fgetc(input);
}while(((ch1 >= 'a' && ch1 <= 'z') || (ch1 >= 'A' && ch1 <= 'Z') || (ch1 >= '0' && ch1 <= '9') )) ;
*p='\0';
token_second.type=typeDef(token_second.content); 判断是 保留字 还是 标志符
return 1;
}
if(ch1 >= '0' && ch1 <= '9') 数字串处理
{
do{
*p=ch1;
p++;
ch1=fgetc(input);
}while(ch1 >= '0' && ch1 <= '9') ;
*p='\0';
token_second.type=SYM_num;
token_second.value=changNum(token_second.content);
return 1;
}
switch(ch1) 界符 运算符的处理
{
case '>': *p=ch1;
p++;
ch1=fgetc(input);
if(ch1 == '=')
{
*p=ch1;
p++;
*p='\0';
ch1=fgetc(input);
token_second.type=SYM_MoreOrEqual;
}
else
{
*p='\0';
token_second.type=SYM_More;
}
break;
case '<': *p=ch1;
p++;
ch1=fgetc(input);
if(ch1 == '=')
{
*p=ch1;
p++;
*p='\0';
ch1=fgetc(input);
token_second.type=SYM_LessOrEqual;
}
else
{
*p='\0';
token_second.type=SYM_Less;
}
break;
case '=': *p=ch1;
p++;
ch1=fgetc(input);
if(ch1 == '=')
{
*p=ch1;
p++;
*p='\0';
ch1=fgetc(input);
token_second.type=SYM_Equal;
}
else
{
*p='\0';
token_second.type=SYM_Evaluate;
}
break;
case '!': *p=ch1;
p++;
ch1=fgetc(input);
if(ch1 == '=')
{
*p=ch1;
p++;
*p='\0';
ch1=fgetc(input);
token_second.type=SYM_NotEqual;
}
else
{
*p='\0';
token_second.type=SYM_Not;
}
break;
case '{':token_second.type=SYM_BigLeftBracket;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
case '}':token_second.type=SYM_BigRightBracket;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
case ';':token_second.type=SYM_Semicolon;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
case ',':token_second.type=SYM_Comma;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
case '+':token_second.type=SYM_Plus;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
case '-':token_second.type=SYM_Sub;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
case '*':token_second.type=SYM_Mul;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
case '/':token_second.type=SYM_Div;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
case '(':token_second.type=SYM_LeftBracket;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
case ')':token_second.type=SYM_RightBracket;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
case '&':token_second.type=SYM_And;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
case '|':token_second.type=SYM_Or;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
case '[':token_second.type=SYM_NormalLeftBracket;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
case ']':token_second.type=SYM_NormalRightBracket;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
case '$':break;
default: error(1);break;
}
return 1;
}
语法分析:
代码:
代码太长了,语法分析采用的是LL1和局部LL2的分析方法,自顶向下的递归调用方法编程.
语法规则一:
factor->( simple_exp ) | var_use | num
代码一:
struct op factor()
{
struct op temp1,temp;
switch(token_first.type)
{
case SYM_LeftBracket:
accept();
temp1=simple_exp();
{
temp.place=temp1.place;
}
if( token_first.type != SYM_RightBracket)
error(1);
accept();
break;
case SYM_id: {
temp.place=serch(token_first.content);
}
accept();
break;
case SYM_num: {
temp.place=fill_num(token_first.value);
}
accept();
break;
default: error(1);break;
}
return temp;
}
由于语义处理同语法处理,同时进行,所以factor函数由语法角度看来不太明确,修改上述代码,可得纯语法分析代码:
void factor()
{
switch(token_first.type)
{
case SYM_LeftBracket:
accept();
simple_exp();
if( token_first.type != SYM_RightBracket)
error(1);
accept();
break;
case SYM_id: accept();
break;
case SYM_num: accept();
break;
default: error(1);break;
}
}
对比明确的语法规则:factor->( simple_exp ) | var_use | num
代码开篇分了三种情况,满足那一种条件,调用哪个函数;
语法规则二:
expper->var_use = simple_exp;| phylum| call ;| if_stmt | while_stmt | return_stmt
特意调出这个在LL1文法中冲突的地方,由语法规则可知:var_use 和 call 的首字符中都有 id ,所以比较它们的
第二个字符,代码中直接调用token_second来进行判断
.......
case SYM_id:
if(token_second.type == SYM_Evaluate || token_second.type == SYM_NormalLeftBracket)
{
.......
}
else
{
.......
}
break;
.......
由代码可以看出,在首字符都是ID的情况下,接下来判断token_second
语义分析:
语义分析从动作行为上说,分为这几类:
填表,查表,生成四元式,分配变量和四元式的等,每个行为举一个例子,
表有几种:
符号表 (均有基本类型构成) 操作:serch,fill,fill_num
int num;
char name[10];
int type; //类型(0表示num,1,int,2,bool,1,单个变量,2,数组,5,函数)
int shuzu[3]; //维数,维长
int place;
四元式表 操作:getpos,emit
int lop; struct pl
struct pl e1; int p;
struct pl e2; int offset;
struct pl e;
serch:
struct pl serch(char *str) 查找×str表示的字符串在符号表的位置
{
struct pl temp;
int i=top-1;
while(i>=0)
{
if(!strcmp(table[i].name,str))
{
temp.p=i;
temp.offset=0;
return temp;
}
i--;
}
temp.p=-1;
return temp;
}
fill:
struct pl fill(char *str) 将*str填入到符号表里,返回符号表的序号
{
struct pl temp;
strcpy(table[top].name,str);
top++;
temp.p=top-1;
temp.offset=0;
return temp;
}
fill_num:
struct pl fill_num(int num)
{
struct pl temp;
table[top].num=num;
top++;
temp.p=top-1;
temp.offset=0;
return temp;
}
getpos:
int getpos()
{
return pos;
}
emit:
int emit(int a,struct pl b,struct pl c,struct pl d) 纯粹的赋值
{
mid[pos].lop=a;
mid[pos].e1=b;
mid[pos].e2=c;
mid[pos].e=d;
pos++;
return pos-1;
}
newTemp:
struct pl newTemp(int type) 生成新的临时变量
{
struct pl temp;
end++;
temp.p=end-1;
temp.offset=0;
return temp;
}
fenpei:
void fenpei()
{
int i,j;
i=pos*4;
for(j=0; j < top; j++)
{
switch(table[j].type)
{
case 0:;
case 1:table[j].place=i;i++;break;
case 2:table[j].place=i;i+=2;break;
case 12:table[j].place=i;
if(table[j].shuzu[0] == 1)
i+=table[j].shuzu[1];
else
i+=table[j].shuzu[1]*table[j].shuzu[2];
break;
case 5:table[j].place=i;i+=2;break;
}
}
for(j=80; j < end; j++)
{
switch(table[j].type)
{
case 0:
case 1:table[j].place=i;i++;break;
case 2:table[j].place=i;i+=2;break;
case 12:table[j].place=i;
if(table[j].shuzu[0] == 1)
i+=table[j].shuzu[1];
else
i+=table[j].shuzu[1]*table[j].shuzu[2];
break;
}
}
}
所有的公共子函数看完了,下面是几个具体的语法分析夹杂语义分析的实例:
1。先看数组变量的定义和引用
定义:
struct op var_init(struct op temp2) //传入参数表示类型
{
struct op temp1;
int i=1;
{//语义
temp1.place=fill(token_first.content);
table[temp1.place.p].type=temp2.code;
}
accept();
if(token_first.type == SYM_NormalLeftBracket)
{
table[temp1.place.p].type*=10;
table[temp1.place.p].type+=2;
} 前面是普通的变量定义,后面while循环里面是关于数组的定义,
涉及数组维数和每维的长度
while(token_first.type == SYM_NormalLeftBracket)
{
accept();
if( token_first.type != SYM_num)
error(1);
table[temp1.place.p].shuzu[1]++;
i+=table[temp1.place.p].shuzu[1];
table[temp1.place.p].shuzu[i]=token_first.value;
accept();
if( token_first.type != SYM_NormalRightBracket)
error(1);
accept();
}
return temp1;
}
引用:
struct op var_use()
{
int i=1;
struct op temp1;
{//语义
temp1.place=serch(token_first.content);
}
accept();
while(token_first.type == SYM_NormalLeftBracket)
{
i++;
accept();
if( token_first.type != SYM_num)
error(1);
temp1.place.offset=temp1.place.offset * table[temp1.place.p].shuzu[i+1];
temp1.place.offset+=token_first.value;
accept();
if( token_first.type != SYM_NormalRightBracket)
error(1);
accept();
}
return temp1;
}
2。if 语句的翻译
struct op if_stmt()
{
struct op temp,temp1,temp2;
struct pl pltemp;
int m1,m2,m3;
if(token_first.type == SYM_if)
{
accept();
if( token_first.type != SYM_LeftBracket)
error(1);
accept();
temp1=relop_exp();
{//语义 产生两个跳转函数,分别跳到条件成立和不成立的两个地方去
m1=emit(SYM_Jz,temp1.place,zero,zero);
m2=emit(SYM_Jmp,zero,zero,zero);
}
if( token_first.type != SYM_RightBracket)
error(1);
accept();
{//语义 重新给条件成立的跳转函数的四元式赋值
pltemp.p=getpos();
pltemp.offset=0;
mid[m1].e=pltemp;
}
sentence_list();
{//语义 跳过else 的范围
m3=emit(SYM_Jmp,zero,zero,zero);
}
{//语义 给条件不成立的跳转函数的四元式赋值
pltemp.p=getpos();
pltemp.offset=0;
mid[m2].e=pltemp;
}
temp2=e();
{//语义 给调处else的范围四元式赋值
pltemp.p=getpos();
pltemp.offset=0;
mid[m3].e=pltemp;
}
}
else
{
error(1);
}
return temp;
}
/************************************/
struct op e()
{
struct op temp;
if( token_first.type == SYM_else)
{
accept();
if( token_first.type == SYM_BigLeftBracket)
{
accept();
sentence_list();
if( token_first.type != SYM_BigRightBracket)
error(1);
accept();
}
else
{
error(1);
}
}
return temp;
}
3.while语句的翻译
struct op while_stmt()
{
struct op temp,temp1;
struct pl pltemp;
int m1,m2;
if(token_first.type == SYM_while)
{
accept();
if(token_first.type != SYM_LeftBracket)
error(1);
accept();
{
m1=getpos(); 取得while开始的循环部分
}
temp1=relop_exp();
{//语义
m2=getpos();
pltemp.p=m2+2;
pltemp.offset=0;
emit(SYM_Jz,temp1.place,zero,pltemp); 产生跳转语句,分别对待条件
m2=emit(SYM_Jmp,zero,zero,zero);
}
if(token_first.type != SYM_RightBracket)
error(1);
accept();
sentence();
{
pltemp.p=m1;
pltemp.offset=0;
emit(SYM_Jmp,zero,zero,pltemp); 为了执行下个循环,跳转到while开始部分
}
{
pltemp.p=getpos();
pltemp.offset=0;
mid[m2].e=pltemp; 给条件为假是,调出while的四元式赋值
}
}
else
{
error(1);
}
return temp;
}
语义分析在每个函数中都存在着,通过上面几个特殊的例子,可以更好的了解语义分析和语法分析。
系统实例:
int a[5];
int b=20;
int e=90;
bool c=1;
bool d=1;
int main() //jkjkjkdflk
{
a[3]=b+2;
b=b+2;
while( b > 9)
{
if(e>b)
{
c=0;
}
else
{
b=0;
}
}
}
生成::::::::::::::::::::::
地址 (四元式代码)
操作码 量(1) (2) (3) 均是地址表示 解释
0 18 168 0 167 [167]=[168] b=20
4 18 170 0 169 [169]=[170] e=90
8 18 173 0 171 [171]=[173] c=1
12 18 176 0 174 [174]=[176] d=1
16 18 167 0 183 [183]=[167] [183]=b
20 18 183 0 184 [184]=b
24 18 178 0 185 [185]=2
28 11 184 185 184 [184]=b+2
32 18 184 0 165 [165]=b+2 a[3]=b+2
36 18 167 0 186
40 18 186 0 187
44 18 179 0 188
48 11 187 188 187
52 18 187 0 167 b=b+2
56 18 167 0 189 [189]=b
60 18 189 0 190 [190]=b
64 18 190 0 191 [191]=b
68 18 180 0 192 [192]=[180]=9
72 18 192 0 193 [193]=9
76 22 191 193 191 比较大小
80 33 191 0 88 转移
84 32 0 0 152 两个方向,88(进入),152(跳过while)
88 18 169 0 194
92 18 194 0 195
96 18 195 0 196
100 18 167 0 197
104 18 197 0 198
108 22 196 198 196 if函数判断
112 33 196 0 120 成立(120)
116 32 0 0 136 否定(136)
120 18 181 0 199
124 18 199 0 200
128 18 200 0 171
132 32 0 0 148
136 18 182 0 201
140 18 201 0 202
144 18 202 0 167
148 32 0 0 56 while的最后跳转
符号表:
个数 内容 地址
0 0 152
1 0 153
2 0 154
3 0 155
4 0 156
5 0 157
6 0 158
7 0 159
8 0 160
9 0 161
10 a 12 162
11 b 1 167
12 20 168
13 e 1 169
14 90 170
15 c 2 171
16 1 173
17 d 2 174
18 1 176
19 main 1 177
20 2 178
21 2 179
22 9 180
23 0 181
24 0 182
临时变量表:
个数 内容 地址
80 0 183
81 0 184
82 0 185
83 0 186
84 0 187
85 0 188
86 0 189
87 0 190
88 0 191
89 0 192
90 0 193
91 0 194
92 0 195
93 0 196
94 0 197
95 0 198
96 0 199
97 0 200
98 0 201
99 0 202
操作码表:
#define SYM_int 1
#define SYM_bool 2
#define SYM_if 3
#define SYM_else 4
#define SYM_while 5
#define SYM_do 6
#define SYM_return 7
#define SYM_BigLeftBracket 8
#define SYM_BigRightBracket 9
#define SYM_Semicolon 10
#define SYM_Plus 11
#define SYM_Sub 12
#define SYM_Mul 13
#define SYM_Div 14
#define SYM_LeftBracket 15
#define SYM_RightBracket 16
#define SYM_Comma 17
#define SYM_Evaluate 18
#define SYM_Equal 19
#define SYM_Less 20
#define SYM_LessOrEqual 21
#define SYM_More 22
#define SYM_MoreOrEqual 23
#define SYM_NotEqual 24
#define SYM_Not 25
#define SYM_And 26
#define SYM_Or 27
#define SYM_num 28
#define SYM_id 29
#define SYM_NormalLeftBracket 30
#define SYM_NormalRightBracket 31
#define SYM_Jmp 32
#define SYM_Jz 33
#define SYM_Return 34
#define SYM_Call 35
总结:
距离要求差语义分析错误,和bool函数的运算。
发表于 @ 2006年05月22日 23:45:00 | 评论( loading... ) | 举报| 收藏