《编译原理课程设计》课程报告题目 C语言词法分析器和C-语言语法分析器
学生姓名
学生学号
指导教师
提交报告时间 2019 年 6 月 8 日
C语言词法分析器
1 实验目的及意义
1.熟悉C语言词法
2.掌握构造DFA的过程
3.掌握利用DFA实现C语言的词法分析器
4.理解编译器词法分析的工作原理
2 词法特点及正则表达式
2.1词法特点
2.1.1 保留字
AUTO, BREAK , CASE , CHAR , CONST , CONTINUE , DEFAULT , DO , DOUBLE , ELSE,
ENUM , EXTERN , FLOAT , FOR , GOTO,
IF , INT , LONG , REGISTER , RETURN,
SHORT , SIGNED , SIZEOF , STATIC , STRUCT ,
SWITCH , TYPEDEF , UNION , UNSIGNED , VOID,
VOLATILE , WHILE,
2.1.2 符号
+ - * / ++ -- += -= *= < <= > >= == != = ; , ( ) [ ] { } /* */ :
2.2 正则表达式
whitespace = (newline|blank|tab|comment)+
digit=0|..|9
nat=digit+
signedNat=(+|-)?nat
NUM=signedNat(“.”nat)?
letter = a|..|z|A|..|Z
ID = letter(letter|digit|“_”)+
CHAR = 'other+' STRING = “other+”
3 Token定义
3.2 tokenType类型代码
4 DFA设计
4.1 注释的DFA设计
注释的DFA如下所示,一共分为5个状态,在开始状态1时,如果输入的字符为/, 则进入状态2,此时有可能进入注释状态,如果在状态2时,输入的字符为*,则进入注释状态,状态将转到3,如果在状态3时,输入的字符为*,则有可能结束注释状态,此时状态将转到状态4,如果在状态4时输入的字符为/,则注释状态结束,状态转移到结束状态。
4.2 词法分析的DFA设计
词法分析的DFA如下所示,一共分为10个状态:START、INNUM、INNUM1、INNUM2、INID、INCOMPARE、INOPERATE、INSTRING、INCHAR、DONE。状态START表示开始状态,状态INNUM,INNUM1,INNUM2表示数字类型(NUM)Token的状态,状态INID 表示标示符(ID)类型Token的状态,状态INOPERATE表示算数运算符型Token的状态,状态INOCOMPARE表示比较运算符型Token的状态,INSTRING表示字符串(STRING)类型Token的状态,INCHAR表示字符(CHARACTER)类型Token的状态,状态DONE表示接收状态。
●在开始状态START时
?如果输入的字符为空白符,如空格换行等,则仍在START状态
?如果输入的字符为digit,则进入状态INNUM,即可能是数字类型(NUM)Token的状态
?如果输入的字符为letter,则进入状态INID,即可能是标识符类型Token的状态
?如果输入的字符为>、<、!、=,则进入状态INCOMPARE,即可能是比较运算符型Token的状态
?如果输入的字符为+、—、*、/,则进入状态INOPERATE,即可能是算数运算符类型Token的状态
?如果输入的字符为‘,则进入状态INCHAR,即可能是字符类型Token的状态
?如果输入的字符为“,则进入状态INSTRING,即可能是字符串类型Token的状态
?如果输入的字符为是除以上之外的,则进入状态DONE,这次输入的字符可能是单目运算符、错误等
●在状态INNUM时
?如果输入的字符为digit,则仍停留在INNUM状态
?如果输入的字符为”.”,则转到INNUM1状态
●在状态INNUM1时
?如果输入的字符为digit,则进入INNUM2状态
●在状态INNUM2时
●如果输入的为其他的字符,则转到DONE状态
?如果输入字符为digit,则停留在INNUM2状态
?如果输入的为其他字符,则转到DONE状态
●在状态INID时
?如果输入的字符为letter或“_”或digit,则仍停留在INID状态
?如果输入的为其他的字符,则转到DONE状态
●在状态INCOMPARE时
?如果输入的字符为=,则转到DONE状态
?如果输入的为其他的字符,则直接转到DONE状态
●在状态INOPERATE时
?如果输入的字符为=,转到DONE状态
?如果输入的为其他的字符,则直接转到DONE状态
●在状态INCOMPARE时
?如果输入的字符为=,则转到DONE状态
?如果输入的为其他的字符,则直接转到DONE状态
●在状态INCHAR时
?如果输入为单引号,则转到DONE状态
?如果输入的为其他字符,则停留在INCHAR状态
●在状态INSTRING时
?如果输入为双引号,则转到DONE状态
?如果输入的为其他字符,则停留在INSTRING状态
●在状态DONE时
接受状态,根据分析过程中获取的字符串确定Token的类型,并生成和保存相应的Token
5 代码结构分析
5.1主要结构
词法分析部分的代码在scan.c和scan.h文件中,全局变量以及公共函数代码在global.h以及util.h和util.c文件中。主函数中进行文件打开和关闭,并调用scan.c中的getToken()函数对源文件进行词法分析。
5.2 函数和成员变量的作用和含义
void printToken(TokenType,const char*); /*输出token */
char* copyString(char*); /* 字符串复制*/
TokenType getToken(void);/* 词法分析函数*/
static int getNextChar(void)/* 获取下一个字符*/
static void ungetNextChar(void)/* 退回一个字符*/
static TokenType reservedLookup (char* s) /* 查找对应的保留字*/
char tokenString[MAXTOKENLEN+1]; /* token字符串*/
int lineno =0;/* 当前行号*/
static char lineBuf[BUFLEN];/* 整行代码缓冲区*/
static int linepos =0;/* 当前行的位置*/
static int bufsize =0;/* 缓冲区大小*/
static int EOF_flag = FALSE;/* 文件结束标志*/
6 实验结果与分析
6.1 测试文件test.c
/*test.c*/
int main(void)
{
###
int a =0;
float b =20.1;
char c[]="abcdefg";
char d ='h';
if(a>=2)
{
b+=0.1
a++;
}
}
6.2 测试结果
6.3结果分析
test.c文件中包括注释,保留字,整数和小数,标识符,特殊符号,字符串以及错误输入。
本程序成功对test.c文件进行了词法分析,对注释进行了忽略,输出了相应的行号、类型、取值,对于错误的输入显示ERROR。
7 小结
通过编写C语言词法分析器,我对编译器的基本原理有了更深的认识,同时掌握了DFA 的设计与实现。
在最开始的编写过程中,我总是把词法和语法分析混淆,比如一些错误应该在语法分析中判断,我却写进了词法分析中,后来我逐步认识到词法分析的作用就是提取源代码中的Token。在DFA的实现过程中,我主要参考了书后tiny语言DFA的实现方法,将它扩展到C 语言。另外C语言词法比较复杂,因为时间关系我省略了一些,比如位运算符,转义字符等等,希望今后能完善。
C-语言语法分析器
1 实验目的及意义
用C语言编制Tiny/C-语言的语法分析程序,实现对词法分析程序所提供的Token
序列的语法检查和结构分析。
2 文法规则(EBNF)
program→declaration-list
declaration_list → declaration{ declaration }
declaration→var-declaration|fun-declaration
var_declaration →type-specifier ID; | type-specifier ID [NUM];
type - specifier → int | void
fun-declatation→type-specifier ID (params) | compound-stmt
params→param_list | void
param_list→param{, param}
param→ type-specifier ID{[ ]}
compound-stmt→{ local-declaration statement-list}
local-declarations → empty {var- declaration}
statement-list→{statement}
statement→expression-stmt | compound-stmt | selection-stmt | iteration-stmt | return-stmt expression-stmt→ [expression];
selection-stmt→if (expression) statement [else statement]
iteration-stmt→while (expression)statement
return-stmt→return [expression];
expression→ var = expression | simple-expression
relop → < = | < | > | > = | = = | ! =
var→ID | ID [expression]
simple-expression->additive-expression{ relop additive-expression }
additive-expression→term{addop term }
addop → + | -
term→factor{mulop factor }
mulop →* | /
factor→(expression) | var | call | NUM call→ID( args )
args→arg-list | empty
arg-list→ expression{, expression}
3 节点类型及定义
3.1节点类型
3.2节点定义
typedef struct treeNode
{
struct treeNode *child[4];
struct treeNode *sibling;
int lineno;
NodeKind nodekind;
union{ TokenType op;int val;const char* name;} attr;
ExpType type;
} TreeNode;
4 代码结构分析
TreeNode * p =t;
//程序以变量声明开始
while((token!=INT)&&(token!=VOID)&&(token!=ENDFILE)) {
syntaxError("开始不是类型声明");
token = getToken();
if(token==ENDFILE)
break;
}
while(token==INT||token==VOID)
{
TreeNode * q;
q = declaration();
if(q!=NULL)
{
if(t==NULL)
{
t=p=q;
}
else
{
p->sibling=q;
p=q;
}
}
}
match(ENDFILE);
return t;
}
{
t = newNode(Var_DeclK);
a = newNode(Arry_DeclK);
t->child[0]= p;//p是t子节点
t->child[1]= a;
match(LBRACKET);
s = newNode(ConstK);
s->attr.val = atoi(tokenString);
match(NUM);
a->child[0]=q;
a->child[1]=s;
match(RBRACKET);
match(SEMI);
}
else if(token==SEMI)
{
t = newNode(Var_DeclK);
t->child[0]= p;
t->child[1]= q;
match(SEMI);
}
else
{
syntaxError("");
}
}
else
{
syntaxError("");
}
return t;
}
else if(k!=NULL)
{
p = k;
}
if(p!=NULL)
{
t->child[0]= p;
if(token==ID)
{
q = newNode(IdK);
q->https://www.wendangku.net/doc/457492946.html, = copyString(tokenString);
t->child[1]= q;
match(ID);
}
else
{
syntaxError("");
}
if(token==LBRACKET&&(t->child[1]!=NULL))//@@@@@@@@@@@@
{
match(LBRACKET);
t->child[2]= newNode(IdK);
match(RBRACKET);
}
else
{
return t;
}
}
else
{
syntaxError("");
}
return t;
}
TreeNode * q2 = newNode(IdK);
q2->https://www.wendangku.net/doc/457492946.html, = copyString(tokenString);
p->child[1]= q2;
match(ID);
if(token==LBRACKET)
{
TreeNode * q3 = newNode(Var_DeclK);
p->child[3]= q3;
match(LBRACKET);
match(RBRACKET);
match(SEMI);
}
else if(token==SEMI)
{
match(SEMI);
}
else
{
match(SEMI);
}
}
else
{
syntaxError("");
}
if(p!=NULL)
{
if(t==NULL)
t = q = p;
else
{
q->sibling = p;
q = p;
}
}
}
return t;
}