1、为语法树定义数据结构,包括各文法符号属性值的数据结构定义,并为它们实现各自的构造函数。4. 工作流程根据语法树打印出语义相同的C语言源程序需要众多函数的支持,它们分别负责各个语法结构(即文法符号的属性)的打印输出。这些函数单独放在一个文件里,其中打印源程序的函数由主函数调用,然后由打印源程序的函数负责调用其它函数完成整个源程序的打印。5. 提示信息对于能够正确通过词法分析和语法分析的源程序输出分析成功的提示信息,否则提示源程序存在语法错误。三、 实现方法1. 文法符号的定义(为各文法符号指定属性值类型)1) 文法符号类型%union intival;doublefval;stringsval;
2、a_id id;a_op op;a_bop bop;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) 终结符定义并指定属性值类型%token IDival INTfval FLOATtyp INTEGER REAL%token SEMICOLON END VAR PERIOD COLON COMMA ASSIGN IF WHIL
3、E LPAREN RPAREN PROGRAM BEGINER ELSE DO THEN bop EQ NEQ LT GT LE GE%left MINUS PLUS TIMES DIVIDED3) 为非终结符指定属性值类型%type progrexten EXTENSIONdecl DECLAREdecltable DECLARETABLE%type SENTENCE GIVESENTENCE IFSENTENCE WHILESENTENCEstens SENTENCETABLE GROUPSENTENCEcalexp CALCULATEEXPRESS TERM FACTORrelexp R
4、ELATIONEXPRESSvartable VARIETYTABLEvardeclare VARIETYDECLAREid VARIETY TYPE2. 类型定义1) 程序数据结构定义structa_prog_ string name;a_pospos;2) 分程序数据结构定义structa_extension_ a_stm_liststmlist; ;3) 变量声明部分数据结构定义structa_vardec_ a_dec_listdectable;4) 变量声明表数据结构定义structa_dec_list_ a_dec head;a_dec_list tail;5) 变量声明数据结构定
5、义structa_dec_ ttype type;a_var_listvarlist;6) 变量表数据结构定义structa_var_list_ a_id head;a_var_list tail;7) 语句表数据结构定义structa_stm_list_ a_stm head;a_stm_list tail;8) 语句数据结构定义structa_stm_ enum A_assign, A_if, A_while, A_seq kind;union structa_assign_stm_ a_idvar;a_expexp; assign;/赋值语句:var = exp;structa_if_s
6、tm_ a_bexp b;a_stm s1;a_stm s2; iff;/ if语句:if b then s1 else s2;structa_while_stm_ a_stm s; whilee;/ while语句:while b do s;a_stm_listseq;/顺序语句:是若干顺序的语句的一个列表。 stm;9) 算数表达式数据结构定义structa_exp_ enum A_varExp, A_intExp, A_realExp, A_opExp kind;struct a_exp left;a_exp right; biopExp; /二元运算表达式:leftop right /
7、变量表达式 /整型数表达式 double fval;/实型数表达式exp;10) 布尔表达式数据结构定义structa_bexp_ bexp;11) 变量数据结构定义structa_id_ stringval;12) 类型数据结构定义typedefenumT_int, T_real ttype;13) 标识符数据结构定义typedef char *string;14) 二元算数运算符数据结构定义typedefenum A_plusOp, A_minusOp, A_timesOp, A_divideOp a_op;15) 二元布尔运算符数据结构定义typedefenum A_eqOp, A_ne
8、qOp, 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_l
9、ist;typedefstructa_var_list_ * a_var_list;typedefstructa_prog_ * a_prog;typedefstructa_extension_ * a_extension;17) 各种数据结构嵌套定义,自顶向下,层次分明3. 词法分析器的设计1) 正规式词法分析器的主要功能就是为语法分析提供词法记号,为此词法分析要能够识别所有合法的词法单元并在识别到一个词法单元后将它的属性值写入全局变量以便语法分析器能够使用这个属性值。最后词法分析器要将这个词法单元所对应的终结符记号返回给语法分析器,使语法分析器知道现在已经得到了一个终结符号,然后采取相应的
10、动作(移进终结符或者归约产生式)。为了实现这些功能,词法分析器需要定义识别这些词法单元的正规式,正规定义如下:delim t nws delim+letter A-Za-zdigit 0-9id letter(letter|digit)*constinteger digit+constfloat constinteger?.constinteger还有一些词法单元的识别因为较为简单,直接采用正规式的方式放在词法规则段中。2) 定义状态此外为了能够识别注释并做相应的处理,需要设置一个状态,以表示现在词法分析是否处于注释的范围内,状态定义如下:%s COMMENT当遇到注释开始标志时,词法分析器就
11、进入注释状态,遇到注释结束标志再切换回正常状态。3) 标识符属性值识别到标识符时,由于其属性是一个字符串,不能直接将变量yytext的值赋给全局变量yylval,因为yytext的值是一个指针变量,而我们无法知道这个指针所指向的内存区域在下一时刻会发生怎样的变化,因此无法确保在语法分析的最后还能正确地获取标识符的名字。为此在遇到标识符时,我们需要自己开辟一块内存区域来存放标识符的名字,将此刻yytext所指内存区域的值复制一份到我们自己开辟的内存区域。4) 其他符号属性值当词法分析遇到整数或浮点数时,需要将yytext所指字符串转换成整数或浮点数,简单的调用函数atoi()和atof()即可完
12、成。识别到其他词法单元只需要根据词法单元的类型进行简单的赋值即可。4. 语法分析器的设计1) 原理由于语法分析是为了分析源程序的语法结构并建立语法树,因此只需为该语言书写一个有效的文法并在产生式后添加相应的语义动作,在语义动作里通过计算非终结符的综合属性来建立程序的语法树。2) 为该语言书写的文法(含语义动作)如下:progr : PROGRAM ID SEMICOLON EXTENSION program = A_Prog(EM_tokPos,$2,$4); ;EXTENSION : VARIETYDECLARE GROUPSENTENCE PERIOD $=A_Exten(EM_tokPo
13、s,$1,$2);VARIETYDECLARE : VAR DECLARETABLE $=A_VarDec(EM_tokPos,$2);DECLARETABLE : DECLARE SEMICOLON $=A_DecList($1,NULL);|DECLARE SEMICOLON DECLARETABLE $=A_DecList($1,$3);DECLARE : VARIETYTABLE COLON TYPE $=A_Dec(EM_tokPos,$1,$3);TYPE :INTEGER |REALVARIETYTABLE :VARIETY $=A_VarList($1,NULL);|VARIE
14、TY COMMA VARIETYTABLE $=A_VarList($1,$3);SENTENCETABLE :SENTENCE $=A_StmList($1,NULL);|SENTENCE SEMICOLON SENTENCETABLE $=A_StmList($1,$3);SENTENCE : GIVESENTENCE | IFSENTENCE | WHILESENTENCE | GROUPSENTENCE $=A_Seq(EM_tokPos,$1);GIVESENTENCE : VARIETY ASSIGN CALCULATEEXPRESS $=A_Assign(EM_tokPos,$1
15、,$3);IFSENTENCE : IF RELATIONEXPRESS THEN SENTENCE ELSE SENTENCE $=A_If(EM_tokPos,$2,$4,$6);WHILESENTENCE : WHILE RELATIONEXPRESS DO SENTENCE $=A_While(EM_tokPos,$2,$4);GROUPSENTENCE : BEGINER SENTENCETABLE END $=$2;CALCULATEEXPRESS : TERM | CALCULATEEXPRESS PLUS TERM $=A_OpExp(EM_tokPos,$2,$1,$3);|
16、 CALCULATEEXPRESS MINUS TERM $=A_OpExp(EM_tokPos,$2,$1,$3);TERM : FACTOR | TERM TIMES FACTOR $=A_OpExp(EM_tokPos,$2,$1,$3); | TERM DIVIDED FACTOR $=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); | LPAREN CALCU
17、LATEEXPRESS RPAREN $=$2;RELATIONEXPRESS : CALCULATEEXPRESS EQ CALCULATEEXPRESS $=A_BExp(EM_tokPos,$2,$1,$3);| CALCULATEEXPRESS NEQ CALCULATEEXPRESS $=A_BExp(EM_tokPos,$2,$1,$3);| CALCULATEEXPRESS GE CALCULATEEXPRESS $=A_BExp(EM_tokPos,$2,$1,$3);| CALCULATEEXPRESS LE CALCULATEEXPRESS $=A_BExp(EM_tokP
18、os,$2,$1,$3);| CALCULATEEXPRESS GT CALCULATEEXPRESS $=A_BExp(EM_tokPos,$2,$1,$3);| CALCULATEEXPRESS LT CALCULATEEXPRESS $=A_BExp(EM_tokPos,$2,$1,$3);VARIETY : ID $=A_Id(EM_tokPos,$1);3) 注意的事项文法的书写要注意避免冲突,但不能改变原语言的语法结构。这里是对文法的结构做了微小的变化,将变量声明部分更改为VAR加一个变量声明表。将变量声明表的结构调整为变量声明加分号或者是变量声明加分号再加一个变量声明表,这样在识
19、别一个变量声明结构后又遇到一个分号时就一定会移进而不会发生移进归约冲突。5. 输出函数部分1) 基本原理这部分的功能主要是根据语法分析器构造的语法树输出语义相同的C语言源程序,因此主要是实现各个语法结构的打印输出。由于各语法结构层层嵌套,语法树采用自下而上的方式构造,因此输出可以采用自顶向下的方式,通过函数的层层调用完成程序各个部分的输出,最后完成整个源程序的输出。2) 解决方式输出采用自顶向下的方式,各个语法结构的输出函数只负责本语法结构的正确输出,而不会向上负责,但是会向下传递一下格式控制的信息,在这里指的是输出的语法结构距行首有多少空格,这主要是为了输出的美观整齐。6. 主函数部分功能分析:由主函数负责调用语法分析器,语法分析器调用词法分析器。语法分析成功后由主函数显示分析成功的提示信息并调用输出函数,将语法分析建立的语法树的根节点传递给输出函数,完成同语义C语言源程序的输出。四、 实验结果1. 词法分析器与语法分析器编译后与数据定义文件和输出函数文件由gcc编译连接后生成可执行文件。执行可执行文件,可顺利通过测试用例test1.p的分析,显示分析成功并打印出相应的C语言源程序。测试用例test0.p是一个存在语法错误的源程序,测试时提示存在语法错误,对test0.p做简单修改后同样能够通过测试。2. 运行时屏幕截图
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1