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〈bufsize))
{
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;//跟踪标志全部初始化为false
main(intargc,char*argv[])
{TreeNode*syntaxTree;
charpgm[120];/*sourcecodefilename*/
if(argc!
=2)
{fprintf(stderr,"usage:
%sexit
(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);
exit
(1);//如果源代码文件为空,打印显示信息并退出
}
listing=stdout;/*sendlistingtoscreen清单发送到屏幕*/
fprintf(listing,"\nTINYCOMPILATION:
%s\n”,pgm);//答应显示语句
#ifNO_PARSE
while(getToken()!
=ENDFILE);//如果输入流没有结束就继续进行循环,直至结束
#else
syntaxTree=parse();//调用prase()函数构造语法树
if(TraceParse){
fprintf(listing,"\nSyntaxtree:
\n”);
printTree(syntaxTree);//如果语法分析追踪标志为TRUE且没有语法错误,则将生成的语法树输出到屏幕
}
#if!
NO_ANALYZE
if(!
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_CODE
if(!
Error)
{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);
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〈stdio。
h〉
#include〈stdlib.h〉
#includeh〉
#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;
#endif
SCAN。
C
/*词法扫描程序*/
#include”globals。
h”
#include"util.h”
#include"scan.h”
/*定义的状态*/
typedefenum
{
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中读取下一个非空白字符,如果读完,则读入新行.*/
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},{"read”,READ},
{”write",WR