1、实验4 用Yacc工具构造语法分析器 一、实验目的 掌握移进-归约技术语法分析技术,利用语法分析器生成工具Yacc/Bison实现语法分析器的构造。 二、实验内容 利用语法分析器生成工具Yacc/Bison编写一个语法分析程序,与词法分析器结合,能够根据语言的上下文无关文法,识别输入的单词序列是否文法的句子。 源语言的文法定义见教材附录 A.1,p394,要求实现完整的语言。 三、实验要求 1.个人完成,提交实验报告。 2.实验报告中给出采用测试源代码片断,及其对应的最右推导过程(形式可以自行考虑,如依次给出推导使用的产生式)。 例如,程序片断 四、实验思路 本次实
2、验是一次实现词法分析和语法分析的过程,词法分析的内容与第二次实验类似,对关键词,数字,标识符以及其他类型的字符进行识别,分别返回对应的数据类型,这个过程相对来说是比较简单的,由于有特定的词法分析过程的格式,很容易将代码编写出来。语法分析的过程则给出了文法以及相应的语义动作,代码的编写相对比较复杂。 首先,在D:\FlexBison的目录下建立一个文件夹,我命名为expmt3,将bison.exe和flex.exe放到expmt3目录下。然后编写mylex.l文件和myyacc.y文件,在dos下切换到expmt3目录下,先用命令flex mylex.l生成lex.yy.c文件,再用命令bis
3、on –d myyacc.y生成myyacc.tab.c文件和myyacc.tab.h文件,在这个目录中再新建一个example.c文件,用vc++打开这个文件,然后编译这个文件,再将前两步生成的lex.yy.c、myyacc.tab.c和myyacc.tab.h文件加入到工程中,再编译并连接生成可执行文件。最后测试程序的正确性要在expmt3的debug目录下创建一个测试文件test.txt,将测试片段放入其中,然后在dos界面运行程序,知道产生正确的结果,实验就完成了。
五、具体代码
Mylex.l
%option noyywrap
%{
#include
4、
#include
5、C);} "float" {printf("FLOAT "); return(BASIC);} "break" {printf("BREAK");return(BREAK);} "do" {printf("DO ");return(DO);} "while" {printf("WHILE ");return(WHILE);} "true" {printf("TRUE ");return(TRUE);} "index" {printf("INDEX "); return(INDEX);} "bool" {printf("BOOL "); ret
6、urn(BASIC);} "char" {printf("CHAR "); return(BASIC);} "real" {printf("real");return(REAL);} "false" {printf("FLASE "); return(FALSE);} [a-zA-Z_][a-zA-Z0-9_]* {printf("ID");return(ID);} [+-]?[0-9]+ {printf("NUM");return(NUM);} [+-]?[0-9]*[.][0-9]+ {printf("NUM");return(NUM);}
7、 "<" {printf("LT ");return('<');} "<=" {printf("LE ");return(LE);} "=" {printf("= ");return('=');} "==" {printf("EQ ");return(EQ);} "!=" {printf("NE ");return(NE);} ">" {printf("GT ");return('>');} ">=" {printf("GE ");return(GE);} "+" {printf("+ ");
8、return('+');} "-" {printf("- ");return('-');} "[" {printf("[ ");return('[');} "]" {printf("] ");return(']');} "{" {printf("{");return('{');} "}" {printf("}");return('}');} "(" {printf("(");return('(');} ")" {printf(")");return(')');} ";" {pri
9、ntf(";");return(';');}
"," {printf(",");return(',');}
"&&" {printf("&&");return(AND);}
"||" {printf("||");return(OR);}
%%
Myyacc.y
%{
#include
10、E FALSE BASIC ELSE INDEX GE LE NE EQ AND OR %% program : block { printf("program-->block\n"); } ; block : '{' decls stmts '}' { printf("block-->{decls stmts}\n"); } ; decls : | decls decl { printf("decls-->decls decl\n"); } ; decl : type ID ';' { printf("decl-->typ
11、e id;\n"); } ; type : type '[' NUM ']' { printf("type-->type[num]\n"); } | BASIC { printf("type-->basic\n"); } ; stmts : | stmts stmt { printf("stmts-->stmts stmt\n"); } ; stmt : matched_stmt { printf("stmt-->matched_stmt\n");} | open_stmt { printf("stmt-->op
12、en_stmt\n");} ; open_stmt: IF '(' booL ')' stmt { printf("open_stmt-->if(bool)stmt\n");} | IF '(' booL ')' matched_stmt ELSE open_stmt { printf("open_stmt-->if(bool) matched_stmt else open_stmt\n");} ; matched_stmt: IF '(' booL ')' matched_stmt ELSE matched_stmt { printf("matche
13、d_stmt-->if(bool) matched_stmt else matched_stmt\n");} | other { printf("matched_stmt-->other\n");} ; other: loc '=' booL ';' { printf("stmt-->loc=bool;\n"); } | WHILE '(' booL ')' stmt { printf("stmt-->while(bool)stmt\n"); } | DO stmt WHILE '(' booL ')' ';' { printf(
14、"stmt-->do stmt while(bool);\n"); } | BREAK ';' { printf("stmt-->break;\n"); } | block { printf("stmt-->block\n"); } ; loc : loc '[' booL ']' { printf("loc-->loc[bool]\n"); } | ID { printf("loc-->id\n"); } ; booL : booL OR join { printf("bool-->bool||join\n"); } |
15、 join { printf("bool-->join\n"); } ; join : join AND equality { printf("join-->join&&equality\n"); } | equality { printf("join-->equality\n"); } ; equality : equality EQ rel { printf("equality-->equality==rel\n"); } | equality NE rel { printf("equality-->equality!=rel\n
16、"); }
| rel { printf("equality-->rel\n"); }
;
rel : expr '<' expr { printf("rel-->expr
17、pr\n"); } ; expr : expr '+' term { printf("expr-->expr+term\n"); } | expr '-' term { printf("expr-->expr-term\n"); } | term { printf("expr-->term\n"); } ; term : term '*' unary { printf("term-->term*unary\n"); } | term '/' unary { printf("term-->term/unary\n"); }
18、 | unary { printf("term-->unary\n"); } ; unary : '!' unary { printf("unary-->!unary\n"); } | '-' unary { printf("unary-->-unary\n"); } | factor { printf("unary-->factor\n"); } ; factor : '(' booL ')' { printf("factor-->(bool)\n"); } | loc { printf("factor-->loc
19、\n"); } | NUM { printf("factor-->num\n"); } | REAL { printf("factor-->real\n"); } | TRUE { printf("factor-->true\n"); } | FALSE { printf("factor-->false\n"); } ; %% int yyerror(s) char *s; { fprintf(stderr,"syntactic error:%s\n",s); return 0; } 六、 实验结果
20、 七、 实验总结 实验中的注意事项: (1)一个由 Yacc 生成的解析器调用 yylex() 函数来获得标记。对于由 Lex 生成的 lexer 来说,要和 Yacc 结合使用,每当 Lex 中匹配一个模式时都必须返回一个标记。 因此 Lex 中匹配模式时的动作一般格式为: {pattern} { /* do smthg*/ return TOKEN_NAME; } 于是 Yacc 就会获得返回的标记。当 Yacc 编译一个带有 _d 标记的myyacc .y文件时,会生成一个头文件myyacc.tab.h,它对每个标记都有 #define 的定义。 如果 Lex 和 Yacc 一起使用的话,头文件必须在相应的 Lex 文件mylex.l中的 C 声明段中包括。 (2)在myyacc.y中要加入对函数int yylex()和函数int yyerror()的外部声明。 (3)对文件放置的位置也要很小心,不然很容易就造成错误 (4)这次的实验使我对语法分析的过程更加了解,更多的掌握了移进——规约技术语法分析,对理论知识起到了巩固的作用,加强了编译整个理论体系的认识,也对flex &bison的操作有了更深一步的了解。






