编译原理课程设计语法分析器.docx
《编译原理课程设计语法分析器.docx》由会员分享,可在线阅读,更多相关《编译原理课程设计语法分析器.docx(12页珍藏版)》请在冰豆网上搜索。
编译原理课程设计语法分析器
中国海洋大学
课程设计
课程名称:
编译原理课程设计
任课教师:
葛林
学生姓名:
甘言海
学生学号:
020*********
专业班级:
计算机信息保密20XX级
学院名称:
信息科学与工程学院
20XX年12月23日
一、概要设计
使用Lex和Yacc设计一个语法分析器,并在语法分析的同时生成分析树。
给产生式加上动作,动作为生成一棵语法分析树,输入为实验1所给语言写的源程序文件;输出为一个C语言源程序文件(即输入是所给语言的源程序文件,输出为语义相同的C语言源程序文件)。
二、详细设计
1.基本思路
为所给语言写出无二义性的文法,用正规式定义语言的一些基本元素,如变量名、关键字和常数。
将基本元素的识别放在词法分析里,语言的语句单元、程序结构等放在语法分析里完成。
2.基本原理
词法分析和语法分析合作完成对源语言程序的分析,词法分析返回语法分析所需要的词法单元,包括变量名、关键字、整数和浮点数。
语法分析负责源程序语法结构的检查和语法树的构造。
语法树的构造通过计算文法符号的综合属性自下而上一步步获得。
3.数据基础
为语法树定义数据结构,包括各文法符号属性值的数据结构定义,并为它们实现各自的构造函数。
4.工作流程
根据语法树打印出语义相同的C语言源程序需要众多函数的支持,它们分别负责各个语法结构(即文法符号的属性)的打印输出。
这些函数单独放在一个文件里,其中打印源程序的函数由主函数调用,然后由打印源程序的函数负责调用其它函数完成整个源程序的打印。
5.提示信息
对于能够正确通过词法分析和语法分析的源程序输出分析成功的提示信息,否则提示源程序存在语法错误。
三、实现方法
1.文法符号的定义(为各文法符号指定属性值类型)
1)文法符号类型
%union{
intival;
doublefval;
stringsval;
a_idid;
a_opop;
a_bopbop;
ttypetyp;
a_expcalexp;
a_bexprelexp;
a_stmsten;
a_stm_liststens;
a_progprog;
a_decdecl;
a_dec_listdecltable;
a_var_listvartable;
a_vardecvardeclare;
a_extensionexten;
}
2)终结符定义并指定属性值类型
%tokenID
%tokenINT
%tokenFLOAT
%tokenINTEGERREAL
%tokenSEMICOLONENDVARPERIODCOLONCOMMAASSIGNIFWHILELPARENRPARENPROGRAMBEGINERELSEDOTHEN
%tokenEQNEQLTGTLEGE
%leftMINUSPLUS
%leftTIMESDIVIDED
3)为非终结符指定属性值类型
%typeprogr
%typeEXTENSION
%typeDECLARE
%typeDECLARETABLE
%typeSENTENCEGIVESENTENCEIFSENTENCEWHILESENTENCE
%typeSENTENCETABLEGROUPSENTENCE
%typeCALCULATEEXPRESSTERMFACTOR
%typeRELATIONEXPRESS
%typeVARIETYTABLE
%typeVARIETYDECLARE
%typeVARIETY
%typeTYPE
2.类型定义
1)程序数据结构定义
structa_prog_{
stringname;
a_pospos;
a_extensionexten;
};
2)分程序数据结构定义
structa_extension_{
a_pospos;
a_vardecvardeclare;
a_stm_liststmlist;
};
3)变量声明部分数据结构定义
structa_vardec_{
a_pospos;
a_dec_listdectable;
};
4)变量声明表数据结构定义
structa_dec_list_{
a_dechead;
a_dec_listtail;
};
5)变量声明数据结构定义
structa_dec_{
ttypetype;
a_pospos;
a_var_listvarlist;
};
6)变量表数据结构定义
structa_var_list_{
a_idhead;
a_var_listtail;
};
7)语句表数据结构定义
structa_stm_list_{
a_stmhead;
a_stm_listtail;
};
8)语句数据结构定义
structa_stm_{
enum{A_assign,A_if,A_while,A_seq}kind;
a_pospos;
union{
structa_assign_stm_{
a_idvar;
a_expexp;
}assign;//赋值语句:
var=exp;
structa_if_stm_{
a_bexpb;
a_stms1;
a_stms2;
}iff;//if语句:
ifbthens1elses2;
structa_while_stm_{
a_bexpb;
a_stms;
}whilee;//while语句:
whilebdos;
a_stm_listseq;//顺序语句:
是若干顺序的语句的一个列表。
}stm;
};
9)算数表达式数据结构定义
structa_exp_{
enum{A_varExp,A_intExp,A_realExp,A_opExp}kind;
a_pospos;
union{
struct{
a_opop;
a_expleft;
a_expright;
}biopExp;//二元运算表达式:
leftopright
a_idvar;//变量表达式
intival;//整型数表达式
doublefval;//实型数表达式
}exp;
};
10)布尔表达式数据结构定义
structa_bexp_{
a_pospos;
struct{
a_bopbop;
a_expleft;
a_expright;
}bexp;
};
11)变量数据结构定义
structa_id_{
a_pospos;
stringval;
};
12)类型数据结构定义
typedefenum{T_int,T_real}ttype;
13)标识符数据结构定义
typedefchar*string;
14)二元算数运算符数据结构定义
typedefenum{A_plusOp,A_minusOp,A_timesOp,A_divideOp}a_op;
15)二元布尔运算符数据结构定义
typedefenum{A_eqOp,A_neqOp,A_ltOp,A_leOp,A_gtOp,A_geOp}a_bop;
16)各种指针类型定义
typedefstructa_exp_*a_exp;
typedefstructa_bexp_*a_bexp;
typedefstructa_id_*a_id;
typedefstructa_stm_*a_stm;
typedefstructa_stm_list_*a_stm_list;
typedefstructa_dec_*a_dec;
typedefstructa_vardec_*a_vardec;
typedefstructa_dec_list_*a_dec_list;
typedefstructa_var_list_*a_var_list;
typedefstructa_prog_*a_prog;
typedefstructa_extension_*a_extension;
17)各种数据结构嵌套定义,自顶向下,层次分明
3.词法分析器的设计
1)正规式
词法分析器的主要功能就是为语法分析提供词法记号,为此词法分析要能够识别所有合法的词法单元并在识别到一个词法单元后将它的属性值写入全局变量以便语法分析器能够使用这个属性值。
最后词法分析器要将这个词法单元所对应的终结符记号返回给语法分析器,使语法分析器知道现在已经得到了一个终结符号,然后采取相应的动作(移进终结符或者归约产生式)。
为了实现这些功能,词法分析器需要定义识别这些词法单元的正规式,正规定义如下:
delim[\t\n]
ws{delim}+
letter[A-Za-z]
digit[0-9]
id{letter}({letter}|{digit})*
constinteger{digit}+
constfloat{constinteger}?
\.{constinteger}
还有一些词法单元的识别因为较为简单,直接采用正规式的方式放在词法规则段中。
2)定义状态
此外为了能够识别注释并做相应的处理,需要设置一个状态,以表示现在词法分析是否处于注释的范围内,状态定义如下:
%sCOMMENT
当遇到注释开始标志时,词法分析器就进入注释状态,遇到注释结束标志再切换回正常状态。
3)标识符属性值
识别到标识符时,由于其属性是一个字符串,不能直接将变量yytext的值赋给全局变量yylval,因为yytext的值是一个指针变量,而我们无法知道这个指针所指向的内存区域在下一时刻会发生怎样的变化,因此无法确保在语法分析的最后还能正确地获取标识符的名字。
为此在遇到标识符时,我们需要自己开辟一块内存区域来存放标识符的名字,将此刻yytext所指内存区域的值复制一份到我们自己开辟的内存区域。
4)其他符号属性值
当词法分析遇到整数或浮点数时,需要将yytext所指字符串转换成整数或浮点数,简单的调用函数atoi()和atof()即可完成。
识别到其他词法单元只需要根据词法单元的类型进行简单的赋值即可。
4.语法分析器的设计
1)原理
由于语法分析是为了分析源程序的语法结构并建立语法树,因此只需为该语言书写一个有效的文法并在产生式后添加相应的语义动作,在语义动作里通过计算非终结符的综合属性来建立程序的语法树。
2)为该语言书写的文法(含语义动作)如下:
progr:
PROGRAMIDSEMICOLONEXTENSION{program=A_Prog(EM_tokPos,$2,$4);}
;
EXTENSION:
VARIETYDECLAREGROUPSENTENCEPERIOD{$$=A_Exten(EM_tokPos,$1,$2);}
;
VARIETYDECLARE:
VARDECLARETABLE{$$=A_VarDec(EM_tokPos,$2);}
;
DECLARETABLE:
DECLARESEMICOLON{$$=A_DecList($1,NULL);}
|DECLARESEMICOLONDECLARETABLE{$$=A_DecList($1,$3);}
;
DECLARE:
VARIETYTABLECOLONTYPE{$$=A_Dec(EM_tokPos,$1,$3);}
;
TYPE:
INTEGER
|REAL
;
VARIETYTABLE:
VARIETY{$$=A_VarList($1,NULL);}
|VARIETYCOMMAVARIETYTABLE{$$=A_VarList($1,$3);}
;
SENTENCETABLE:
SENTENCE{$$=A_StmList($1,NULL);}
|SENTENCESEMICOLONSENTENCETABLE{$$=A_StmList($1,$3);}
;
SENTENCE:
GIVESENTENCE
|IFSENTENCE
|WHILESENTENCE
|GROUPSENTENCE{$$=A_Seq(EM_tokPos,$1);}
;
GIVESENTENCE:
VARIETYASSIGNCALCULATEEXPRESS{$$=A_Assign(EM_tokPos,$1,$3);}
;
IFSENTENCE:
IFRELATIONEXPRESSTHENSENTENCEELSESENTENCE{$$=A_If(EM_tokPos,$2,$4,$6);}
;
WHILESENTENCE:
WHILERELATIONEXPRESSDOSENTENCE{$$=A_While(EM_tokPos,$2,$4);}
;
GROUPSENTENCE:
BEGINERSENTENCETABLEEND{$$=$2;}
CALCULATEEXPRESS:
TERM
|CALCULATEEXPRESSPLUSTERM{$$=A_OpExp(EM_tokPos,$2,$1,$3);}
|CALCULATEEXPRESSMINUSTERM{$$=A_OpExp(EM_tokPos,$2,$1,$3);}
;
TERM:
FACTOR
|TERMTIMESFACTOR{$$=A_OpExp(EM_tokPos,$2,$1,$3);}
|TERMDIVIDEDFACTOR{$$=A_OpExp(EM_tokPos,$2,$1,$3);}
;
FACTOR:
VARIETY{$$=A_VarExp(EM_tokPos,$1);}
|INT{$$=A_IntExp(EM_tokPos,$1);}
|FLOAT{$$=A_RealExp(EM_tokPos,$1);}
|LPARENCALCULATEEXPRESSRPAREN{$$=$2;}
;
RELATIONEXPRESS:
CALCULATEEXPRESSEQCALCULATEEXPRESS{$$=A_BExp(EM_tokPos,$2,$1,$3);}
|CALCULATEEXPRESSNEQCALCULATEEXPRESS{$$=A_BExp(EM_tokPos,$2,$1,$3);}
|CALCULATEEXPRESSGECALCULATEEXPRESS{$$=A_BExp(EM_tokPos,$2,$1,$3);}
|CALCULATEEXPRESSLECALCULATEEXPRESS{$$=A_BExp(EM_tokPos,$2,$1,$3);}
|CALCULATEEXPRESSGTCALCULATEEXPRESS{$$=A_BExp(EM_tokPos,$2,$1,$3);}
|CALCULATEEXPRESSLTCALCULATEEXPRESS{$$=A_BExp(EM_tokPos,$2,$1,$3);}
;
VARIETY:
ID{$$=A_Id(EM_tokPos,$1);}
3)注意的事项
文法的书写要注意避免冲突,但不能改变原语言的语法结构。
这里是对文法的结构做了微小的变化,将变量声明部分更改为VAR加一个变量声明表。
将变量声明表的结构调整为变量声明加分号或者是变量声明加分号再加一个变量声明表,这样在识别一个变量声明结构后又遇到一个分号时就一定会移进而不会发生移进—归约冲突。
5.输出函数部分
1)基本原理
这部分的功能主要是根据语法分析器构造的语法树输出语义相同的C语言源程序,因此主要是实现各个语法结构的打印输出。
由于各语法结构层层嵌套,语法树采用自下而上的方式构造,因此输出可以采用自顶向下的方式,通过函数的层层调用完成程序各个部分的输出,最后完成整个源程序的输出。
2)解决方式
输出采用自顶向下的方式,各个语法结构的输出函数只负责本语法结构的正确输出,而不会向上负责,但是会向下传递一下格式控制的信息,在这里指的是输出的语法结构距行首有多少空格,这主要是为了输出的美观整齐。
6.主函数部分
功能分析:
由主函数负责调用语法分析器,语法分析器调用词法分析器。
语法分析成功后由主函数显示分析成功的提示信息并调用输出函数,将语法分析建立的语法树的根节点传递给输出函数,完成同语义C语言源程序的输出。
四、实验结果
1.词法分析器与语法分析器编译后与数据定义文件和输出函数文件由gcc编译连接后生成可执行文件。
执行可执行文件,可顺利通过测试用例test1.p的分析,显示分析成功并打印出相应的C语言源程序。
测试用例test0.p是一个存在语法错误的源程序,测试时提示存在语法错误,对test0.p做简单修改后同样能够通过测试。
2.运行时屏幕截图