编译原理实验报告Word文档下载推荐.docx
《编译原理实验报告Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《编译原理实验报告Word文档下载推荐.docx(11页珍藏版)》请在冰豆网上搜索。
,||,!
==,
print,while,if,else,{,}false,true
各种单词对应的记号如下:
/**/不返回记号
"
while"
WHILE
if"
IF
else"
ELSE
print"
PRINT
false"
INTEGER
true"
INTEGER
[a-z]VARIABLE
[0-9]+INTEGER
-()<
=+*/%;
{}返回本身
="
GE
<
LE
=="
EQ
!
NE
"
AND
||"
OR
NOT
[\t\n]+不返回记号
3.实验基本思想
首先是对输入的程序扫描,进行词法分析,并返回记号。
在c语言头文件中定义了一个结构体,用来存放记号的类型和值(如果有的话)。
在语法分析中,规定了优先级和结合性。
根据输入语句的类型而进行不同的操作。
4.源代码
1.Lex词法分析代码:
%{
#include<
stdlib.h>
#include"
node.h"
myparser.h"
voidyyerror(char*);
%}
%%
/*"
([^\*]|(\*)*[^\*/])*(\*)*"
*/"
;
//注释
{returnWHILE;
}
{returnIF;
{returnELSE;
{returnPRINT;
{yylval.iValue=0;
returnINTEGER;
}
{yylval.iValue=1;
}
[a-z]{yylval.sIndex=*yytext-'
a'
;
returnVARIABLE;
[0-9]+{yylval.iValue=atoi(yytext);
[-()<
{}.]{return*yytext;
{returnGE;
{returnLE;
{returnEQ;
{returnNE;
{returnAND;
{returnOR;
{returnNOT;
[\t\n]+;
/*去除空格,回车*/
.printf("
unknowsymbol:
[%s]\n"
yytext);
intyywrap(void)
{
return1;
2.Yacc语法分析源代码:
%{
#include<
stdio.h>
stdarg.h>
#include"
/*属性操作类型*/
Node*opr(intname,intnum,...);
Node*set_index(intvalue);
Node*set_content(intvalue);
voidfreeNode(Node*p);
intexeNode(Node*p);
intyylexeNode(void);
voidyyerror(char*s);
intVar[26];
/*变量数组*/
%union{
intiValue;
/*变量值*/
charsIndex;
/*变量数组索引*/
Node*nPtr;
/*结点地址*/
%token<
iValue>
VARIABLE
sIndex>
INTEGER
%tokenWHILEIFPRINT
%nonassocIFX
%nonassocELSE
%leftANDORGELEEQNE'
'
'
%rightNOT
%left'
+'
-'
*'
/'
%'
%nonassocUMINUS//不具有结合性
%type<
nPtr>
stmtexprstmt_list
program:
function{exit(0);
}
;
function:
functionstmt{exeNode($2);
freeNode($2);
|/*NULL*/
stmt:
'
{$$=opr('
2,NULL,NULL);
|expr'
{$$=$1;
|PRINTexpr'
{$$=opr(PRINT,1,$2);
|VARIABLE'
='
expr'
{$$=opr('
2,set_index($1),$3);
|WHILE'
('
)'
stmt{$$=opr(WHILE,2,$3,$5);
|IF'
stmt%precIFX{$$=opr(IF,2,$3,$5);
stmtELSEstmt%precELSE{$$=opr(IF,3,$3,$5,$7);
|'
{'
stmt_list'
}'
{$$=$2;
stmt_list:
stmt{$$=$1;
|stmt_liststmt{$$=opr('
2,$2,$1);
expr:
INTEGER{$$=set_content($1);
|VARIABLE{$$=set_index($1);
expr{$$=opr('
2,$1,$3);
|exprGEexpr{$$=opr(GE,2,$1,$3);
|exprLEexpr{$$=opr(LE,2,$1,$3);
|exprNEexpr{$$=opr(NE,2,$1,$3);
|exprEQexpr{$$=opr(EQ,2,$1,$3);
|exprANDexpr{$$=opr(AND,2,$1,$3);
|exprORexpr{$$=opr(OR,2,$1,$3);
|NOTexpr{$$=opr(NOT,1,$2);
expr%precUMINUS{$$=opr(UMINUS,1,$2);
{$$=$2;
#defineSIZE_OF_NODE((char*)&
p->
content-(char*)p)
Node*set_content(intvalue)
Node*p;
size_tsizeNode;
/*分配结点空间*/
sizeNode=SIZE_OF_NODE+sizeof(int);
if((p=malloc(sizeNode))==NULL)
yyerror("
outofmemory"
);
/*复制内容*/
p->
type=TYPE_CONTENT;
content=value;
returnp;
Node*set_index(intvalue)
type=TYPE_INDEX;
index=value;
Node*opr(intname,intnum,...)
va_listvalist;
inti;
sizeNode=SIZE_OF_NODE+sizeof(OpNode)+(num-1)*sizeof(Node*);
type=TYPE_OP;
op.name=name;
op.num=num;
va_start(valist,num);
for(i=0;
i<
num;
i++)
op.node[i]=va_arg(valist,Node*);
va_end(valist);
voidfreeNode(Node*p)//释放节点空间
if(!
p)return;
if(p->
type==TYPE_OP)
{
for(i=0;
op.num;
freeNode(p->
op.node[i]);
free(p);
voidyyerror(char*s)
fprintf(stdout,"
%s\n"
s);
intmain(void)
yyparse();
return0;
3.自己定义的头文件node.h中代码:
typedefenum{TYPE_CONTENT,TYPE_INDEX,TYPE_OP}NodeEnum;
/*操作符*/
typedefstruct{
intname;
/*操作符名称*/
intnum;
/*操作元个数*/
structNodeTag*node[1];
/*操作元地址可扩展*/
}OpNode;
typedefstructNodeTag{
NodeEnumtype;
/*树结点类型*/
/*Union必须是最后一个成员*/
union{
intcontent;
/*内容*/
intindex;
/*索引*/
OpNodeop;
/*操作符对象*/
};
}Node;
externintVar[26];
5.运行结果
四则运算:
布尔运算:
If语句:
While:
6.心得体会
通过本次实验,我查阅了许多资料,对编译器的运行原理有了一定程度的掌握。
自己编写的编译器功能简单,通过和使用的各种编译器对比后发现我们现在使用的编译器的非常的复杂。
同时,为以后在编写代码的时候防止错误的发生和找错的时候奠定了一定基础,可以更快找出部分错误。
同时,和队友在一起讨论的过程中也收获了一些知识,增进了和队友的友情。