编译原理课程设计C语言编译器.docx
《编译原理课程设计C语言编译器.docx》由会员分享,可在线阅读,更多相关《编译原理课程设计C语言编译器.docx(58页珍藏版)》请在冰点文库上搜索。
![编译原理课程设计C语言编译器.docx](https://file1.bingdoc.com/fileroot1/2023-4/30/b2e2c61e-ce6b-4feb-bd0c-d4e3730bcf5d/b2e2c61e-ce6b-4feb-bd0c-d4e3730bcf5d1.gif)
编译原理课程设计C语言编译器
编译原理课程设计报告
课题名称:
C-语言编译器设计
提交文档学生姓名:
李杰
提交文档学生学号:
0743041240
同组成员名单:
无
指导教师姓名:
金军
指导教师评阅成绩:
指导教师评阅意见:
.
.
提交报告时间:
2010年6月10日
1.课程设计目标
实验建立C-编译器。
只含有scanner和parser部分。
2.分析与设计
(1)实现方法:
编程语言为C语言。
编程方法:
scanner部分根据DFA图用switch-case结构实现状态转换;parser部分用递归下降分析方法实现。
(2)扫描器:
C-惯用的词法
1、语言的关键字:
elseifintreturnvoidwhile
2、专用符号:
+-*/<<=>>===!
==;,()[]{}/**/
3、其他标记是ID和NUM,通过下列正则表达式定义:
ID=letterletter*NUM=digitdigit*letter=a|..|z|A|..|Zdigit=0|..|9
4、空格由空白、换行符和制表符组成。
空格通常被忽略,除了它必须分开ID、NUM关键字。
5.注释用通常的C语言符号/*...*/围起来。
注释可以放在任何空白出现的位置(即注释不能放在标记内)上,且可以超过一行。
注释不能嵌套
各单词的状态转换图(DFA图如下)词法结构见文件"globals.h"中。
(3)分析器:
分析树结构见文件"globals.h"中。
C-的BNF语法如下:
(4)代码设计说明:
程序结构:
语法分析函数parse通过调用词法分析函数getToken实现语法分析。
文件和函数的设计说明:
文件main.c包含相应头文件,及main函数的实现;文件golbals.h包含符号表和分析数的数据结构及在其它文件中使用的变量;文件util.h和util.c实现与词法分析和语法分析输出相关的函数printToken和printTree,以及分析树节点初始化相关的函数newStmtNode,newExpNode(Expkind)和copyString;文件scan.h和scan.c实现词法分析,主要函数为getToken;文件parse.h和parse.c实现语法分析,函数为与文法规则对应的函数。
关键数据结构
3.程序代码实现
文件main.c代码如下:
//实验建立C-编译器。
只含有scanner和parser部分。
#include"globals.h"
#include"util.h"
#include"scan.h"
#include"parse.h"
//全局变量和标志
intlineno=0;
;
;
;
intEchoSource=TRUE;
intTraceScan=TRUE;
intTraceParse=TRUE;
intError=FALSE;
intmain(intargc,char*argv[])
{
TreeNode*syntaxTree;
charpgm[120];//代码文件名
if(argc!
=2)
{
fprintf(stderr,"usage:
%sC:
\source.c\n",argv[0]);
return-1;
}
strcpy(pgm,argv[1]);
if(strchr(pgm,'.')==NULL)
{strcat(pgm,".tny");}
source=fopen(pgm,"r");
if(source==NULL)
{
fprintf(stderr,"notfound\n",pgm);
return-1;
}
listing=stdout;
fprintf(listing,"\nC-COMPILATION:
%s\n",pgm);
//while(getToken()!
=ENDFILE);
EchoSource=FALSE;
TraceScan=FALSE;
syntaxTree=parse();
if(TraceParse)
{fprintf(listing,"\nSyntaxtree\n:
");
printTree(syntaxTree);
}
fclose(source);
return0;
}
文件globals.h代码如下:
#ifndef_GLOBALS_H_
#define_GLOBALS_H_
#include
#include
#include
#include
#ifndefFALSE
#defineFALSE0
#endif
#ifndefTRUE
#defineTRUE1
#endif
#defineMAXRESERVED6
typedefenum
{
END,
IF,ELSE,INT,RETURN,VOID,WHILE,//关键字
ID,NUM,
ASSIGN,EQ,LT,PLUS,MINUS,TIMES,OVER,LPAREN,RPAREN,SEMI,BT,LQ,BQ,
UEQ,DOU,LZGH,RZGH,LDGH,RDGH,//特殊字符
}TokenType;
externFILE*source;
externFILE*listing;
externFILE*code;
externintlineno;
//语法分析树
typedefenum{Stmtk,Expk}Nodekind;
typedefenum{IfK,ElseK,IntK,ReturnK,VoidK,WhileK,AssignK,HanK,HanshutiK}Stmtkind;
typedefenum{Opk,Constk,Idk,Vark}Expkind;
typedefenum{Void,Integer,Boolean}ExpType;
#defineMAXCHILDREN3
typedefstructtreeNode
{
structtreeNode*child[MAXCHILDREN];
structtreeNode*sibling;
intlineno;
Nodekindnodekind;
union{Stmtkindstmt;Expkindexp;}kind;
union{TokenTypeop;
intval;
char*name;}attr;
ExpTypetype;
}TreeNode;
externintEchoSource;
externintTraceScan;
externintTraceParse;
externintError;
#endif
文件util.h代码如下:
#ifndef_UTIL_H_
#define_UTIL_H_
voidprintToken(TokenType,constchar*);
//为分析树
TreeNode*newStmtNode(Stmtkind);
TreeNode*newExpNode(Expkind);
char*copyString(char*);
voidprintTree(TreeNode*);
#endif
文件util.c代码如下:
#include"globals.h"
#include"util.h"
voidprintToken(TokenTypetoken,constchar*tokenString)
{switch(token)
{caseIF:
caseINT:
caseELSE:
caseRETURN:
caseVOID:
caseWHILE:
fprintf(listing,
"reservedword:
%s\n",tokenString);
break;
caseASSIGN:
fprintf(listing,"=\n");break;
caseLT:
fprintf(listing,"<\n");break;
caseEQ:
fprintf(listing,"==\n");break;
caseLPAREN:
fprintf(listing,"(\n");break;
caseRPAREN:
fprintf(listing,")\n");break;
caseSEMI:
fprintf(listing,";\n");break;
casePLUS:
fprintf(listing,"+\n");break;
caseMINUS:
fprintf(listing,"-\n");break;
caseTIMES:
fprintf(listing,"*\n");break;
caseOVER:
fprintf(listing,"/\n");break;
caseBT:
fprintf(listing,">\n");break;
caseLQ:
fprintf(listing,"<=\n");break;
caseBQ:
fprintf(listing,">=\n");break;
caseUEQ:
fprintf(listing,"!
=\n");break;
caseDOU:
fprintf(listing,",\n");break;
caseLZGH:
fprintf(listing,"[\n");break;
caseRZGH:
fprintf(listing,"]\n");break;
caseLDGH:
fprintf(listing,"{\n");break;
caseRDGH:
fprintf(listing,"}\n");break;
caseENDFILE:
fprintf(listing,"EOF\n");break;
caseNUM:
fprintf(listing,
"NUM,val=%s\n",tokenString);
break;
caseID:
fprintf(listing,
"ID,name=%s\n",tokenString);
break;
caseERROR:
fprintf(listing,
"ERROR:
%s\n",tokenString);
break;
default:
/*shouldneverhappen*/
fprintf(listing,"Unknowntoken:
%d\n",token);
}
}
TreeNode*newStmtNode(Stmtkindkind)
{
TreeNode*p=(TreeNode*)malloc(sizeof(TreeNode));
intk;
if(p==NULL)
{fprintf(listing,"outofmemoryerroratline%d\n",lineno);}
else
{
for(k=0;k{p->child[k]=NULL;}
p->sibling=NULL;
p->nodekind=Stmtk;
p->kind.stmt=kind;
p->lineno=lineno;
}
returnp;
}
TreeNode*newExpNode(Expkindkind)
{
TreeNode*p=(TreeNode*)malloc(sizeof(TreeNode));
intk;
if(p==NULL)
{fprintf(listing,"outofmemoryerroratline%d\n",lineno);}
else
{
for(k=0;k{p->child[k]=NULL;}
p->sibling=NULL;
p->nodekind=Expk;
p->kind.exp=kind;
p->lineno=lineno;
p->type=Void;
}
returnp;
}
char*copyString(char*s)
{
inti;
char*p;
if(s==NULL)
{returnNULL;}
i=strlen(s)+1;
p=malloc(i);
if(p==NULL)
{fprintf(listing,"outofmemoryerroratline%d\n",lineno);}
else{strcpy(p,s);}
returnp;
}
staticindentno=0;
#defineINDENTindentno+=2
#defineUNINDENTindentno-=2
staticvoidprintSpace(void)
{
intk;
for(k=0;k{fprintf(listing,"");}
}
voidprintTree(TreeNode*t)
{inti;
INDENT;
while(t!
=NULL)
{
printSpace();
if(t->nodekind==Stmtk)
{
switch(t->kind.stmt)
{
caseIfK:
fprintf(listing,"If\n");
break;
caseIntK:
fprintf(listing,"Int\n");
break;
caseVoidK:
fprintf(listing,"Void\n");
break;
caseReturnK:
fprintf(listing,"Return\n");
break;
caseWhileK:
fprintf(listing,"While\n");
break;
caseAssignK:
fprintf(listing,"Assignto:
%s\n",t->attr.name);
break;
caseHanK:
fprintf(listing,"Hanshu\n");
break;
caseHanshutiK:
fprintf(listing,"Hanshuti\n");
break;
default:
fprintf(listing,"Unknownstmtkind\n");
break;
}
}
elseif(t->nodekind==Expk)
{switch(t->kind.exp)
{
caseOpk:
fprintf(listing,"Op:
");
printToken(t->attr.op,"\0");
break;
caseConstk:
fprintf(listing,"Const:
%d\n",t->attr.val);
break;
caseIdk:
fprintf(listing,"Id:
%s\n",t->attr.name);
break;
caseVark:
fprintf(listing,"Vark:
%d\n",t->attr.val);
break;
default:
fprintf(listing,"Unknownexpkind\n");
break;
}
}
else{fprintf(listing,"Unknownexpkind\n");}
for(i=0;i{printTree(t->child[i]);}
t=t->sibling;
}
UNINDENT;
}
文件scan.h代码如下:
#ifndef_SCAN_H_
#define_SCAN_H_
#defineMAXTOKENLEN40
externchartokenString[MAXTOKENLEN+1];
TokenTypegetToken(void);
#endif
文件scan.c代码如下:
#include"globals.h"
#include"util.h"
#include"scan.h"
//DFA中的状态
typedefenum
{START,INID,INNUM,DONE,INASSIGN,INCOMMENT,ZHU,ZZHU}StateType;
chartokenString[MAXTOKENLEN+1];
#defineBUFLEN256//代码文件的行数
staticcharlineBuf[BUFLEN];//保存当前行
staticintlinepos=0;//lineBuf中的当前位置
staticintbufsize=0;//buffer串的大小
staticintEOF_Flag=FALSE;
//获取字符从lineBuf[BUFLEN]中
staticintgetNextChar(void)
{
if(!
(linepos{
lineno++;//新一行
if(fgets(lineBuf,BUFLEN-1,source))//取新一行
{if(EchoSource)fprintf(listing,"%4d:
%s",lineno,lineBuf);
bufsize=strlen(lineBuf);
linepos=0;
returnlineBuf[linepos++];//先返回lineBuf[linepos],后linepos加1.
}
else
{EOF_Flag=TRUE;
returnEOF;
}
}
elsereturnlineBuf[linepos++];
}
//没有取得字符。
staticvoidungetNextChar(void)
{
if(!
EOF_Flag)linepos--;
}
//关键字的查找表
staticstruct
{char*str;
TokenTypetok;
}reservedWords[MAXRESERVED]
={{"if",IF},{"else",ELSE},{"void",VOID},{"return",RETURN},{"int",INT},{"while",WHILE}};
//关键字的查找
staticTokenTypereserveLookup(char*s)
{
inti;
for(i=0;i{
if(!
strcmp(s,reservedWords[i].str))
{
returnreservedWords[i].tok;
}
}
returnID;
}
TokenTypegetToken(void)
{
//token串存放的索引
inttokenStringIndex=0;
//存放返回的token
TokenTypecurrentToken;
//现在的状态
StateTypestate=START;
//token串的标记
intsave;
intf1=0;//标志取>:
1、<:
2、=:
3和!
:
4
intd=getNextChar();
if(d==EOF)
{currentToken=ENDFILE;
returncurrentToken;
}
else
{
ungetNextChar();
}
while(state!
=DONE)
{intc=getNextChar();
save=TRUE;
switch(state)
{
caseSTART:
if(isdigit(c))
state=INNUM;
elseif(isalpha(c))
state=INID;
elseif(c=='>')
{f1=1;
state=INASSIGN;
}
elseif(c=='<')
{f1=2;
state=INASSIGN;
}
elseif(c=='=')
{f1=3;
state=INASSIGN;
}
elseif(c=='!
')
{f1=4;
state=INASSIGN;
}
elseif((c=='')||(c=='\t')||(c=='\n'))
save=FALSE;
elseif(c=='/')
{save=FALSE;
state=ZHU;
}
else
{
state=DONE;
switch(c)
{
caseEOF:
save=FALSE;
currentToken=ENDFILE;
break;
case'+':
currentToken=PLUS;
break;
case'-':
currentToken=MINUS;
break;
case'*':
currentToken=TIMES;
break;
case'(':
currentToken=LPAREN;
break;
case')':
currentToken=RPAREN;
break;
case'[':
currentToken=LZGH;
break;
case']':
currentToken=RZGH;
break;
case'{':
currentToken=LDGH;
break;
case'}':
currentToken=RDGH;
break;
case';':
currentToken=SEMI;
break;
case',':
currentToken=DOU;
break;
de