/* Power by Keamou@CS@CITS@NKU */
1 用自然语言结合代码实例描述你的C语言编译器所支持语言特性的语法和语义。
答:
赋值(=)语句
语法结构是:
变量名 = 表达式
语义是:
将表达式计算所得的值赋给变量。
产生式为:
stmt → id = expr
if 分支语句
语法结构是:
if(判定条件语句)动作程序段
else动作程序段二
语义是:
a) 判断条件不成立?跳到c)
b) 执行动作程序段一,跳到d)
c) 执行动作程序段二
d)
产生式为:
stmt → if expr then stmt
| if expr then stmt else stmt
while 循环语句
语法结构是:
while(循环判定语句)循环体
语义是:
a) 循环判定语句不成立?跳到c)
b) 执行循环体,跳到a)
c)
产生式为:
stmt → while ( expr ) stmt
for循环语句
语法结构是:
for (循环初始化语句; 循环判定条件; 循环增量语句)
循环体(可以任意的语句——简单语句、条件分支、循环、复合语句…)
语义是:
a) 执行循环初始化语句
b) 循环判定条件不成立?跳到e)
c) 执行循环体
d) 执行循环增量语句,跳到b)
e)
产生式为:
stmt → for( expr1 , expr2 ,expr3 )stmt
函数
语法结构是:
函数名(参数){ 代码段 }
语义是:
遇到函数 函数名(参数) 时调用函数的代码段
产生式为:
func → ( type ) term ( params ) { stmt }
变量声明
语法结构是:
变量类型 变量名列表;
语义是:
在内存开辟相应的空间以存储变量信息
产生式为:
expr → type idlist
type → int | char | double | float
idlist → id | id , idlist
2 为每个语言特性编写等价的汇编语言框架,上机验证其正确性。
答:
赋值(=)语句
value = tmp 的汇编代码:
MOV AX,tmp
MOV value,AX
if 分支语句
if(a>3)b++; else b--; 的汇编代码:
MOV AX,3
CMP a,AX
JLE tmpN
MOV AX,b
MOV BX,1
ADD AX,BX
MOV b,AX
JMP tmpM
tmpN:
MOV AX,b
MOV BX,1
SUB AX,BX
MOV b,AX
tmpM:
while 循环语句
while(a>3)b++;的汇编代码是:
tmpN:
MOV AX,3
CMP a,AX
JLE tmpM
MOV AX,b
MOV BX,1
ADD AX
MOV b,AX
JMP tmpN
tmpM:
for循环语句
for(int i=0;i<3;i++)b++;的汇编代码:
MOV AX,0
MOV i,AX
tmpN:
MOV AX,3
CMP i,AX
JLE tmpM
JMP tmpO
tmpP:
MOV AX,i
MOV BX,1
ADD AX,BX
MOV i,AX
JMP tmpN
tmpO:
MOV AX,b
MOV BX,1
ADD AX,BX
MOV b,AX
JMP tmpP
tmpM:
函数
先是通过压栈传参,后函数声明:
Funct:
Stmt转化的汇编代码段
Funct ENDS
函数调用:
CALL Funct
变量声明
汇编代码为:
变量名 DB变量大小 DUP(?)
3 考虑如何让你的编译器支持输入输出的语言特性。建议:可借助MASM32包对msvcrt动态链接库的支持,实现对printf等库函数的直接调用。详细可参考MASM32包中/tools/makecimp/vcrtdemo目录中使用msvcrt的例子。
答:
在翻译产生的汇编代码前加上一段引用声明:
include /masm32/include/msvcrt.inc
includelib /masm32/lib/msvcrt.lib
【注】此代码中的路径表示masm32的安装目录在当前目录下。
当遇到printf()函数时,翻译成相应的汇编代码:
invoke crt_printf, SADD("<打印语句> <参数> <打印语句>"),参数列表
例如:翻译printf(“my %d masm/n”,mytime);得汇编代码如下
invoke crt_printf, SADD(“my %d masm”, 13,10),OFFSET mytime
4 尝试编写简单的目标代码生成程序。下面是一个简单的C程序的语法树。设计程序,对语法树进行遍历,访问到某个语言结构(树的节点、子树)时将其转换为汇编语言代码。
答:
根据语法树,设计翻译模式,写成Yacc代码如下:
lines : lines prog '/n' { printf("%s/n", $2); }
| lines '/n'
|
;
prog : mainfunction
;
mainfunction
: 'm''a''i''n' params {printf("DATA SEGMENT/ntmp%d DB ?/n",tmp);} '{' stmts '}' {printf("CODE ENDS/nEND START/n");}
;
params : '(' type ')'
;
stmts : stmt{printf("CODE SEGMENT/n ASSUME DS:DATA,CS:CODE,ES:DATA/nSTART:/n");}stmts
| stmt
;
stmt : 'f''o''r''(' expr ';' {printf("JUDGE%d/n",tmp);}expr ';' {printf("EXPR%d:/n",tmp);}
expr {printf("JMP JUDGE%d:/n",tmp);}
')'{printf("STMT%d:/n",tmp);} stmt {printf("JMP EXPR%d/nOUT%d:/n",tmp,tmp);}
| expr ';'
| type vars ';' {printf("DATA ENDS/n");}
;
type : 'i''n''t'' ' {getsize(sizeof(int));}
| 'v''o''i''d'
;
vars : var ',' vars {printf("%s DB %d DUP(?)/n",$1,typesize);}
| var {printf("%s DB %d DUP(?)/n",$1,typesize);}
;
var : 'a' { strcpy($$, "a"); }
| (为节省空间,其他字母省略)
| 'i' { strcpy($$, "i"); }
| (为节省空间,其他字母省略)
;
expr : var '<' '=' expr { gettmp($$); getcode($$,$1,$4,"<=");}
| var '+' expr { gettmp($$); getcode($$,$1,$3,"+");}
| var '=' expr { gettmp($$); getcode($$,$1,$3,"=");}
| var
| digit
;
digit : con { strcpy($$, $1); }
| con digit { strcpy($$, $1); strcat($$, $2);}
|
;
con : '0' { strcpy($$, "0"); }
| '1' { strcpy($$, "1"); }
| '2' { strcpy($$, "2"); }
| '3' { strcpy($$, "3"); }
| '4' { strcpy($$, "4"); }
| '5' { strcpy($$, "5"); }
| '6' { strcpy($$, "6"); }
| '7' { strcpy($$, "7"); }
| '8' { strcpy($$, "8"); }
| '9' { strcpy($$, "9"); }
;
上述文法实现题目中要求的遍历语法树,其中还包括识别多位十进制整数的实现。
具体代码请看附件代码包。
Yacc程序编译通过后放在VC6.0下再编译执行得如下结果: