TINY部分源码分析报告.docx
《TINY部分源码分析报告.docx》由会员分享,可在线阅读,更多相关《TINY部分源码分析报告.docx(25页珍藏版)》请在冰豆网上搜索。
TINY部分源码分析报告
TINY源码分析
一、文件概述
MAIN.C:
主函数
GLOBALS.H:
全局定义的文件
SCAN.C/SCAN.H:
词法分析
PARSE.C/PARSE.H:
语法分析
UTIL.C/UTIL.H:
构造树
SYMTAB.C/SYMTAB.H:
符号表
CGEN.C/CGEN.H:
生成"汇编代码"
CODE.C/CODE.H:
这个只是用来把分析过程输出到屏幕的.
二、各个文件的分析
1.MAIN.C:
主要有三个FILE*句柄:
source--源代码文件。
listing--显示分析过程的文件,这里重定向到stdout。
code--目标汇编代码文件。
从该文件中可知程序运行的流程:
检查参数正确否(tiny.exefilename)->构造语法树(调用parse函数)->根据语法树生成代码(调用codeGen函数,该函数又调用cGen函数。
2.GLOBALS.H:
定义了关键字个数8个。
定义了关键字,运算符等内容的枚举值。
定义了语句类型的枚举值,这个决定树的结点。
定义了变量类型(也就三种,void,integer,boolean)。
定义了树的节点--这个最重要了!
!
其结构如下所示:
typedefstructtreeNode
{
structtreeNode*child[MAXCHILDREN];
structtreeNode*sibling;
intlineno;
NodeKindnodekind;
union{StmtKindstmt;ExpKindexp;}kind;
union{TokenTypeop;
intval;
char*name;}attr;
ExpTypetype;/*fortypecheckingofexps*/
}TreeNode;
3.UTIL.C/UTIL.H
主要函数
TreeNode*newStmtNode(StmtKindkind)
此函数创建一个有关语法树的声明节点
TreeNode*newExpNode(ExpKindkind)
此函数创建一个有关语法树的表述节点
char*copyString(char*s)
此函数分配和创建一个新的已存在树的复制
voidprintTree(TreeNode*tree)
输出一个语法树
这两个文件主要是关于语法树的创建和输出
4.SCAN.c/SCAN.H
主要有这么几个函数:
staticintgetNextChar(void);
staticvoidungetNextChar(void);
staticTokenTypereservedLookup(char*s);
TokenTypegetToken(void);
reservedLookup函数是查找关键字的,在符号表中找。
这里还定义了一个保存关键字的结构:
staticstruct
{char*str;
TokenTypetok;
}reservedWords[MAXRESERVED]
=
{{"if",IF},{"then",THEN},{"else",ELSE},{"end",END},
{"repeat",REPEAT},{"until",UNTIL},{"read",READ},
{"write",WRITE}};
最重要的是getToken(void)函数。
这个相当于lex的功能,进行词法分析。
也就是一个DFA,switch后面跟了一堆的case。
其中getNextChar(void)函数的思路,以下列出:
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++];}else{EOF_flag=TRUE;returnEOF;}}elsereturnlineBuf[linepos++];}4.PARSE.C/PARSE.H有这么几个函数:TreeNode*parse(void)staticTreeNode*stmt_sequence(void);staticTreeNode*statement(void);staticTreeNode*if_stmt(void);staticTreeNode*repeat_stmt(void);staticTreeNode*assign_stmt(void);staticTreeNode*read_stmt(void);staticTreeNode*write_stmt(void);staticTreeNode*exp(void);staticTreeNode*simple_exp(void);staticTreeNode*term(void);staticTreeNode*factor(void);最重要的是parse这个函数,就是用来构造整个程序的语法树的。下面的一堆私有函数构造相应语法的语法树,然后parse最后把它们这些子树整合成一个大树。5.SYMTAB.C/SYMTAB.H这个是符号表操作的,也就是词法分析的时候查找表,看该token是不是关键字。如果不是,就当作表识符添加进去。在语法分析的时候也要用到,看变量有没有声明的时候用的。三、实验心得:通过这次实验,仔细地去查看和分析了TINY编译器的部分源码。了解到了编译器的运行:检查参数正确否(tiny.exefilename)->构造语法树(调用parse函数)->根据语法树生成代码(调用codeGen函数),同时熟悉了编译器是如何使用prase函数进行语法树的构建以及语法树生成代码的转化,最主要的是进一步清晰了解到编译器的构造和运行原理,加深了对课本知识的运用和拓展,感觉收获很大!Main.c/****************************************************//*File:main.c*//*MainprogramforTINYcompiler*//*CompilerConstruction:PrinciplesandPractice*//*KennethC.Louden*//****************************************************/#include"globals.h"/*setNO_PARSEtoTRUEtogetascanner-onlycompiler,NO_PARSE为true时创建一个只扫描的编译器*/#defineNO_PARSEFALSE/*setNO_ANALYZEtoTRUEtogetaparser-onlycompiler,NO_ANALYZE为true时创建一个只分析和扫描的编译器*/#defineNO_ANALYZEFALSE/*setNO_CODEtoTRUEtogetacompilerthatdoesnot*generatecodeNO_CODE为true时创建一个执行语义分析,但不生成代码的编译器*/#defineNO_CODEFALSE#include"util.h"#ifNO_PARSE#include"scan.h"//如果NO_PARSE为true,调用头文件scan.h#else#include"parse.h"//否则调用头文件prase.h#if!NO_ANALYZE#include"analyze.h"//如果NO_ANALYZE为true,调用头文件analyze.h#if!NO_CODE#include"cgen.h"//如果NO_CODE为true,调用头文件cgen.h#endif#endif#endif//结束预处理语句符号/*allocateglobalvariables分配全局变量*/intlineno=0;FILE*source;//指针指向源代码文件地址FILE*listing;//指针指向显示分析过程的文件的地址FILE*code;//指针指向目标汇编代码文件的地址/*allocateandsettracingflags分配和设置跟踪标志*/intEchoSource=FALSE;intTraceScan=FALSE;intTraceParse=FALSE;intTraceAnalyze=FALSE;intTraceCode=FALSE;intError=FALSE;//跟踪标志全部初始化为falsemain(intargc,char*argv[]){TreeNode*syntaxTree;charpgm[120];/*sourcecodefilename*/if(argc!=2){fprintf(stderr,"usage:%s\n",argv[0]);exit(1);//如果argv不为2,打印显示信息并退出}strcpy(pgm,argv[1]);//复制argv[1]地址以null为退出字符的存储器区块到另一个存储器区块品pgm内if(strchr(pgm,'.')==NULL)strcat(pgm,".tny");//把.tyn文件所指字符串添加到pgm结尾处并添加'\0'。source=fopen(pgm,"r");//以只读的方式打开pgm文件,并将指向pgm文件的指针返回给sourceif(source==NULL){fprintf(stderr,"File%snotfound\n",pgm);exit(1);//如果源代码文件为空,打印显示信息并退出}listing=stdout;/*sendlistingtoscreen清单发送到屏幕*/fprintf(listing,"\nTINYCOMPILATION:%s\n",pgm);//答应显示语句#ifNO_PARSEwhile(getToken()!=ENDFILE);//如果输入流没有结束就继续进行循环,直至结束#elsesyntaxTree=parse();//调用prase()函数构造语法树if(TraceParse){fprintf(listing,"\nSyntaxtree:\n");printTree(syntaxTree);//如果语法分析追踪标志为TRUE且没有语法错误,则将生成的语法树输出到屏幕}#if!NO_ANALYZEif(!Error){if(TraceAnalyze)fprintf(listing,"\nBuildingSymbolTable...\n");buildSymtab(syntaxTree);//输出含符号表信息的语法树if(TraceAnalyze)fprintf(listing,"\nCheckingTypes...\n");typeCheck(syntaxTree);//输出含类型检查的语法树if(TraceAnalyze)fprintf(listing,"\nTypeCheckingFinished\n");//打印结束信息}#if!NO_CODEif(!Error){char*codefile;intfnlen=strcspn(pgm,".");codefile=(char*)calloc(fnlen+4,sizeof(char));strncpy(codefile,pgm,fnlen);strcat(codefile,".tm");//将源文件名,去掉扩展名,添加扩展名.tmcode=fopen(codefile,"w");//以只写的方式打开目标汇编代码文件,并返回地址给codez指针if(code==NULL){printf("Unabletoopen%s\n",codefile);exit(1);//如果code指针为空,打印显示信息并退出}codeGen(syntaxTree,codefile);//目标代码生成fclose(code);}#endif#endif#endif//结束之前对应的条件编译fclose(source);//关闭源代码文件return0;}GLOBALS.H/****************************************************//*File:globals.h*//*GlobaltypesandvarsforTINYcompiler*//*mustcomebeforeotherincludefiles*//*CompilerConstruction:PrinciplesandPractice*//*KennethC.Louden*//****************************************************/#ifndef_GLOBALS_H_#define_GLOBALS_H_//宏定义#include#include#include#include//头文件引用#ifndefFALSE#defineFALSE0//定义FALSE为0#endif#ifndefTRUE#defineTRUE1//定义TRUE为1#endif/*MAXRESERVED=thenumberofreservedwords*/#defineMAXRESERVED8//定义了关键字个数8个typedefenum/*book-keepingtokens*/{ENDFILE,ERROR,/*reservedwords*/IF,THEN,ELSE,END,REPEAT,UNTIL,READ,WRITE,/*multicharactertokens*/ID,NUM,/*specialsymbols*/ASSIGN,EQ,LT,PLUS,MINUS,TIMES,OVER,LPAREN,RPAREN,SEMI}TokenType;//定义了关键字,运算符等内容的枚举值externFILE*source;/*sourcecodetextfile源代码地址*/externFILE*listing;/*listingoutputtextfile显示分析过程的文件的地址*/externFILE*code;/*codetextfileforTMsimulator目标汇编代码文件的地址*/externintlineno;/*sourcelinenumberforlisting*//**************************************************//***********Syntaxtreeforparsing************//**************************************************/typedefenum{StmtK,ExpK}NodeKind;//定义了语句类型的枚举值,这个决定树的节点typedefenum{IfK,RepeatK,AssignK,ReadK,WriteK}StmtKind;typedefenum{OpK,ConstK,IdK}ExpKind;/*ExpTypeisusedfortypechecking*/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;/*fortypecheckingofexps*/}TreeNode;/**************************************************//***********Flagsfortracing************//**************************************************//*EchoSource=TRUEcausesthesourceprogramto*beechoedtothelistingfilewithlinenumbers*duringparsing*/externintEchoSource;/*TraceScan=TRUEcausestokeninformationtobe*printedtothelistingfileaseachtokenis*recognizedbythescanner*/externintTraceScan;/*TraceParse=TRUEcausesthesyntaxtreetobe*printedtothelistingfileinlinearizedform*(usingindentsforchildren)*/externintTraceParse;/*TraceAnalyze=TRUEcausessymboltableinserts*andlookupstobereportedtothelistingfile*/externintTraceAnalyze;/*TraceCode=TRUEcausescommentstobewritten*totheTMcodefileascodeisgenerated*/externintTraceCode;/*Error=TRUEpreventsfurtherpassesifanerroroccurs*/externintError;#endifSCAN.C/*词法扫描程序*/#include"globals.h"#include"util.h"#include"scan.h"/*定义的状态*/typedefenum{START,/*初始状态*/INASSIGN,/*进入到赋值状态*/INCOMMENT,/*进入到注释状态*/INNUM,/*进入到数字状态*/INID,/*进入到标志符状态*/DONE/*状态结束*/}StateType;/*每当语法分析程序需要一个单词时,就调用该子程序,得到(类别码,单词的值)*//*语义标识符和保留字*/chartokenString[MAXTOKENLEN+1];/*BUFLEN=源代码的输入缓冲长度*/#defineBUFLEN256staticcharlineBuf[BUFLEN];/*当前行*/staticintlinepos=0;/*在linebuf中的当前位置*/staticintbufsize=0;/*缓冲区的字符串当前大小*/staticintEOF_flag=FALSE;/*如果读入下一个字符出错,设置EOF_flag为假。*//*从linebuffer中读取下一个非空白字符,如果读完,则读入新行。*/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++];}else{EOF_flag=TRUE;returnEOF;}}elsereturnlineBuf[linepos++];}/*如果读入下一个字符出错,在linebuf中回退一个字符。*/staticvoidungetNextChar(void){if(!EOF_flag)linepos--;}/*保留字的查找表*/staticstruct{char*str;TokenTypetok;}reservedWords[MAXRESERVED]={{"if",IF},{"then",THEN},{"else",ELSE},{"end",END},{"repeat",REPEAT},{"until",UNTIL},{"rea
lineno++;
if(fgets(lineBuf,BUFLEN-1,source))
if(EchoSource)fprintf(listing,"%4d:
%s",lineno,lineBuf);
bufsize=strlen(lineBuf);
linepos=0;
returnlineBuf[linepos++];
}
else
EOF_flag=TRUE;
returnEOF;
elsereturnlineBuf[linepos++];
4.PARSE.C/PARSE.H
有这么几个函数:
TreeNode*parse(void)
staticTreeNode*stmt_sequence(void);
staticTreeNode*statement(void);
staticTreeNode*if_stmt(void);
staticTreeNode*repeat_stmt(void);
staticTreeNode*assign_stmt(void);
staticTreeNode*read_stmt(void);
staticTreeNode*write_stmt(void);
staticTreeNode*exp(void);
staticTreeNode*simple_exp(void);
staticTreeNode*term(void);
staticTreeNode*factor(void);
最重要的是parse这个函数,就是用来构造整个程序的语法树的。
下面的一堆私有函数构造相应语法的语法树,然后parse最后把它们这些子树整合成一个大树。
5.SYMTAB.C/SYMTAB.H
这个是符号表操作的,也就是词法分析的时候查找表,看该token是不是关键字。
如果不是,就当作表识符添加进去。
在语法分析的时候也要用到,看变量有没有声明的时候用的。
三、实验心得:
通过这次实验,仔细地去查看和分析了TINY编译器的部分源码。
了解到了编译器的运行:
检查参数正确否(tiny.exefilename)->构造语法树(调用parse函数)->根据语法树生成代码(调用codeGen函数),同时熟悉了编译器是如何使用prase函数进行语法树的构建以及语法树生成代码的转化,最主要的是进一步清晰了解到编译器的构造和运行原理,加深了对课本知识的运用和拓展,感觉收获很大!
Main.c
/****************************************************/
/*File:
main.c*/
/*MainprogramforTINYcompiler*/
/*CompilerConstruction:
PrinciplesandPractice*/
/*KennethC.Louden*/
#include"globals.h"
/*setNO_PARSEtoTRUEtogetascanner-onlycompiler,NO_PARSE为true时创建一个只扫描的编译器*/
#defineNO_PARSEFALSE
/*setNO_ANALYZEtoTRUEtogetaparser-onlycompiler,NO_ANALYZE为true时创建一个只分析和扫描的编译器*/
#defineNO_ANALYZEFALSE
/*setNO_CODEtoTRUEtogetacompilerthatdoesnot
*generatecodeNO_CODE为true时创建一个执行语义分析,但不生成代码的编译器
*/
#defineNO_CODEFALSE
#include"util.h"
#ifNO_PARSE
#include"scan.h"//如果NO_PARSE为true,调用头文件scan.h
#else
#include"parse.h"//否则调用头文件prase.h
#if!
NO_ANALYZE
#include"analyze.h"//如果NO_ANALYZE为true,调用头文件analyze.h
NO_CODE
#include"cgen.h"//如果NO_CODE为true,调用头文件cgen.h
#endif
#endif//结束预处理语句符号
/*allocateglobalvariables分配全局变量*/
intlineno=0;
FILE*source;//指针指向源代码文件地址
FILE*listing;//指针指向显示分析过程的文件的地址
FILE*code;//指针指向目标汇编代码文件的地址
/*allocateandsettracingflags分配和设置跟踪标志*/
intEchoSource=FALSE;
intTraceScan=FALSE;
intTraceParse=FALSE;
intTraceAnalyze=FALSE;
intTraceCode=FALSE;
intError=FALSE;//跟踪标志全部初始化为false
main(intargc,char*argv[])
{TreeNode*syntaxTree;
charpgm[120];/*sourcecodefilename*/
if(argc!
=2)
{fprintf(stderr,"usage:
%s\n",argv[0]);
exit
(1);//如果argv不为2,打印显示信息并退出
strcpy(pgm,argv[1]);//复制argv[1]地址以null为退出字符的存储器区块到另一个存储器区块品pgm内
if(strchr(pgm,'.')==NULL)
strcat(pgm,".tny");//把.tyn文件所指字符串添加到pgm结尾处并添加'\0'。
source=fopen(pgm,"r");//以只读的方式打开pgm文件,并将指向pgm文件的指针返回给source
if(source==NULL)
{fprintf(stderr,"File%snotfound\n",pgm);
(1);//如果源代码文件为空,打印显示信息并退出
listing=stdout;/*sendlistingtoscreen清单发送到屏幕*/
fprintf(listing,"\nTINYCOMPILATION:
%s\n",pgm);//答应显示语句
while(getToken()!
=ENDFILE);//如果输入流没有结束就继续进行循环,直至结束
syntaxTree=parse();//调用prase()函数构造语法树
if(TraceParse){
fprintf(listing,"\nSyntaxtree:
\n");
printTree(syntaxTree);//如果语法分析追踪标志为TRUE且没有语法错误,则将生成的语法树输出到屏幕
Error)
{if(TraceAnalyze)fprintf(listing,"\nBuildingSymbolTable...\n");
buildSymtab(syntaxTree);//输出含符号表信息的语法树
if(TraceAnalyze)fprintf(listing,"\nCheckingTypes...\n");
typeCheck(syntaxTree);//输出含类型检查的语法树
if(TraceAnalyze)fprintf(listing,"\nTypeCheckingFinished\n");//打印结束信息
{char*codefile;
intfnlen=strcspn(pgm,".");
codefile=(char*)calloc(fnlen+4,sizeof(char));
strncpy(codefile,pgm,fnlen);
strcat(codefile,".tm");//将源文件名,去掉扩展名,添加扩展名.tm
code=fopen(codefile,"w");//以只写的方式打开目标汇编代码文件,并返回地址给codez指针
if(code==NULL)
{printf("Unabletoopen%s\n",codefile);
(1);//如果code指针为空,打印显示信息并退出
codeGen(syntaxTree,codefile);//目标代码生成
fclose(code);
#endif//结束之前对应的条件编译
fclose(source);//关闭源代码文件
return0;
GLOBALS.H
globals.h*/
/*GlobaltypesandvarsforTINYcompiler*/
/*mustcomebeforeotherincludefiles*/
#ifndef_GLOBALS_H_
#define_GLOBALS_H_//宏定义
#include
#include//头文件引用
#ifndefFALSE
#defineFALSE0//定义FALSE为0
#ifndefTRUE
#defineTRUE1//定义TRUE为1
/*MAXRESERVED=thenumberofreservedwords*/
#defineMAXRESERVED8//定义了关键字个数8个
typedefenum
/*book-keepingtokens*/
{ENDFILE,ERROR,
/*reservedwords*/
IF,THEN,ELSE,END,REPEAT,UNTIL,READ,WRITE,
/*multicharactertokens*/
ID,NUM,
/*specialsymbols*/
ASSIGN,EQ,LT,PLUS,MINUS,TIMES,OVER,LPAREN,RPAREN,SEMI
}TokenType;//定义了关键字,运算符等内容的枚举值
externFILE*source;/*sourcecodetextfile源代码地址*/
externFILE*listing;/*listingoutputtextfile显示分析过程的文件的地址*/
externFILE*code;/*codetextfileforTMsimulator目标汇编代码文件的地址*/
externintlineno;/*sourcelinenumberforlisting*/
/**************************************************/
/***********Syntaxtreeforparsing************/
typedefenum{StmtK,ExpK}NodeKind;//定义了语句类型的枚举值,这个决定树的节点
typedefenum{IfK,RepeatK,AssignK,ReadK,WriteK}StmtKind;
typedefenum{OpK,ConstK,IdK}ExpKind;
/*ExpTypeisusedfortypechecking*/
typedefenum{Void,Integer,Boolean}ExpType;//定义了变量类型
#defineMAXCHILDREN3//定义了最大子节点
typedefstructtreeNode//定义了树的节点
{structtreeNode*child[MAXCHILDREN];
/***********Flagsfortracing************/
/*EchoSource=TRUEcausesthesourceprogramto
*beechoedtothelistingfilewithlinenumbers
*duringparsing
externintEchoSource;
/*TraceScan=TRUEcausestokeninformationtobe
*printedtothelistingfileaseachtokenis
*recognizedbythescanner
externintTraceScan;
/*TraceParse=TRUEcausesthesyntaxtreetobe
*printedtothelistingfileinlinearizedform
*(usingindentsforchildren)
externintTraceParse;
/*TraceAnalyze=TRUEcausessymboltableinserts
*andlookupstobereportedtothelistingfile
externintTraceAnalyze;
/*TraceCode=TRUEcausescommentstobewritten
*totheTMcodefileascodeisgenerated
externintTraceCode;
/*Error=TRUEpreventsfurtherpassesifanerroroccurs*/
externintError;
SCAN.C
/*词法扫描程序*/
#include"scan.h"
/*定义的状态*/
START,/*初始状态*/
INASSIGN,/*进入到赋值状态*/
INCOMMENT,/*进入到注释状态*/
INNUM,/*进入到数字状态*/
INID,/*进入到标志符状态*/
DONE/*状态结束*/
}StateType;
/*每当语法分析程序需要一个单词时,就调用该子程序,得到(类别码,单词的值)*/
/*语义标识符和保留字*/
chartokenString[MAXTOKENLEN+1];
/*BUFLEN=源代码的输入缓冲长度*/
#defineBUFLEN256
staticcharlineBuf[BUFLEN];/*当前行*/
staticintlinepos=0;/*在linebuf中的当前位置*/
staticintbufsize=0;/*缓冲区的字符串当前大小*/
staticintEOF_flag=FALSE;/*如果读入下一个字符出错,设置EOF_flag为假。
/*从linebuffer中读取下一个非空白字符,如果读完,则读入新行。
{if(!
(linepos{lineno++;if(fgets(lineBuf,BUFLEN-1,source)){if(EchoSource)fprintf(listing,"%4d:%s",lineno,lineBuf);bufsize=strlen(lineBuf);linepos=0;returnlineBuf[linepos++];}else{EOF_flag=TRUE;returnEOF;}}elsereturnlineBuf[linepos++];}/*如果读入下一个字符出错,在linebuf中回退一个字符。*/staticvoidungetNextChar(void){if(!EOF_flag)linepos--;}/*保留字的查找表*/staticstruct{char*str;TokenTypetok;}reservedWords[MAXRESERVED]={{"if",IF},{"then",THEN},{"else",ELSE},{"end",END},{"repeat",REPEAT},{"until",UNTIL},{"rea
{lineno++;
{if(EchoSource)fprintf(listing,"%4d:
{EOF_flag=TRUE;
/*如果读入下一个字符出错,在linebuf中回退一个字符。
staticvoidungetNextChar(void)
EOF_flag)linepos--;}
/*保留字的查找表*/
={{"if",IF},{"then",THEN},{"else",ELSE},{"end",END},
{"repeat",REPEAT},{"until",UNTIL},{"rea
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1