1、.编译原理课程设计报告 实验1:用Lex设计词法分析器1实验目的:学会用lex设计一个词法分析器。实验内容:使用lex为下述文法语言写一个词法分析器。实验要求:输入为用该语言所写的源程序文件;输出为记号序列,每个记号显示为二元组(记号名,记号属性值)的形式。输出可以在屏幕上,也可以输出到文件中。不要求建立符号表。在cygwin下用flex和gcc工具将实验调试通过,并能通过例子parser0中testcases目录下的test1.p测试例的测试。实验参考:exam1.l和exam2.l。语言文法: PROGRAM ; BEGIN END. VAR ;: | : ; INTEGER | REAL
2、 | , | ; | | | := IF THEN ELSE WHILE DO BEGIN END | + | - | * | / | | () | | | | . | . | | =| A | B | | X | Y | Z | a | b | | x | y | z0|1|2|9程序代码:%#include #define LT1#defineLE2#define GT3#defineGE4#defineEQ5#define NE6#define PROGRAM 7#define END13#define VAR9#define IF10#define THEN 11#define ELS
3、E 12#define WHILE18#defineDO19#define ID 20#define NUMBER 21#define RELOP 22#define NEWLINE 23#define ERRORCHAR 24%delim t nwsdelim+letter A-Za-zdigit 0-9id_|letter(letter|digit)*numberdigit+(.digit+)?(E+-?digit+)?int1 digit|digitint1*/%s COMMENT%/*BEGIN COMMENT;ECHO;*/BEGIN INITIAL;ECHO;.|nECHO; /*
4、 ECHO是一个宏,相当于 fprintf(yyout, %s, yytext)*/ws ;whilereturn (WHILE);do return (DO);PROGRAM return (PROGRAM);end return (END);VAR return (VAR);if return (IF);then return (THEN);else return (ELSE);id return (ID);number return (NUMBER); return (RELOP);= return (RELOP);= return (RELOP); return (RELOP); re
5、turn (RELOP);= return (RELOP);+ return (RELOP);- return (RELOP);* return (RELOP);/ return (RELOP);:= return (RELOP); return (RELOP);. return (RELOP);, return (RELOP);.return ERRORCHAR;%int yywrap () return 1;void writeout(int c) switch(c) case ERRORCHAR: fprintf(yyout, (ERRORCHAR, %s) , yytext);brea
6、k; case RELOP: fprintf(yyout, (RELOP, %s) , yytext);break; case WHILE: fprintf(yyout, (WHILE, %s) , yytext);break; case DO: fprintf(yyout, (DO, %s) , yytext);break; case NUMBER: fprintf(yyout, (NUM, %s) , yytext);break; case ID: fprintf(yyout, (ID, %s) , yytext);break; case NEWLINE: fprintf(yyout, n
7、);break; case PROGRAM: fprintf(yyout, (PROGRAM, %s) , yytext);break; case END: fprintf(yyout, (END, %s) , yytext);break; case VAR: fprintf(yyout, (VAR, %s) , yytext);break; case IF: fprintf(yyout, (IF, %s) , yytext);break; case THEN: fprintf(yyout, (THEN, %s) , yytext);break; case ELSE: fprintf(yyou
8、t, (ELSE, %s) , yytext);break; default:break; return;int main (int argc, char * argv)int c,j=0;if (argc=2) if (yyin = fopen(argv1, r) = NULL) printf(Cant open file %sn, argv1); return 1; if (argc=3) yyout=fopen(argv2, w); while (c = yylex()writeout(c);j+;if (j%5 = 0) writeout(NEWLINE);if(argc=2) fcl
9、ose(yyin); if (argc=3) fclose(yyout);return 0;测试文件为Test1.p:PROGRAM test;VAR i, j, k: INTEGER; f0: REAL;BEGIN i := 1; j := 1; k := 0; f0 := 3.2; WHILE k=100 DO BEGIN IF j S or S | S and S | not S | (S) | true | false,其中优先级or and not,or 和 and 左结合,not 右结合。用非二义文法实现作为选作内容,非二义文法请参照表达式非二义文法自己写出来。在cygwin下用f
10、lex,bison和gcc工具将实验调试通过,并写出测试例测试正确性。实验参考:calculator0-3这四个例子。程序代码:Cal.y文件:%int yylex(); #define YYSTYPE double /* 将Yacc栈定义为double类型 printf(nThe value of the expression is %lf.n, $1);*/%token NUM LPAREN RPAREN ENTER %left OR%left AND%right NOT%left PLUS MINUS%left TIMES DIVIDE%right UMINUS% /* 这样写prog可
11、以让分析器每次读入一行进行分析,下一行重新分析expr */prog : prog exprp | exprp ;exprp : expr ENTER printf(1 表示 true;0 表示 false %lf.n, $1);shuchu($1); ;expr : expr PLUS expr$ = $1 + $3;| expr MINUS expr $ = $1 - $3;| expr TIMES expr $ = $1 * $3;| expr DIVIDE expr $ = $1 / $3;| LPAREN expr RPAREN $ = $2;| MINUS expr $ = -$2
12、;| NUM $ = $1; | expr OR expr $=panduan($1*$1+$3*$3); | expr AND expr $=panduan($1*$3); | NOT expr $=panduan2($2);%int main()yyparse();return 0;Cal.l文件:%#include cal.tab.h#include int yywrap(void) return 1;#define LT1#defineLE2#define GT3#defineGE4#defineEQ5#define NE6#define PROGRAM7#define END13#d
13、efine VAR9#define IF10#define THEN 11#define ELSE 12#define WHILE18#defineDO19#define ID 20#define RELOP 22#define NEWLINE 23#define ERRORCHAR 24%ws t+digit 0-9inumdigit+fnum digit*.digit+letterA-Za-zid_|letter(letter|digit)*%inum sscanf(yytext, %lf, &yylval); return NUM;fnumsscanf(yytext, %lf, &yyl
14、val); return NUM;+return PLUS;*return TIMES;-return MINUS;/return DIVIDE;(return LPAREN;)return RPAREN;or return OR;and return AND;not return NOT;return LT;return GT;=return GE;= return EQ;!= return NQ;:= return FZ;ws;nreturn ENTER;. printf(nLEX:ERROR! c=%sn, yytext);/*BEGIN COMMENT;ECHO;*/BEGIN INI
15、TIAL;ECHO;whilereturn (WHILE);do return (DO);PROGRAM return (PROGRAM);end return (END);VAR return (VAR);if return (IF);then return (THEN);else return (ELSE);id return (ID);%int panduan(double a)if(a!=0) a=1;return a;int panduan2(double a)if(a=0) a=1;else if(a!=0) a=0;return a;int shuchu(double a)if(
16、a=0)printf(false);else if (a!=0)printf(true);return 1;运行程序:实验4:用Yacc设计语法分析器1实验目的:学习如何使用Yacc设计一个语法分析器,并与用lex写的词法分析器链接起来。实验内容:使用yacc为课程设计实验1所给的语言写一个语法分析器(你可以重新设计该语言的文法,但不能改变语言)。其中,词法分析使用课程设计实验2中已完成的词法分析器(即,你需要将本实验的语法分析器和实验2的词法分析器链接起来)。实验要求:输入为实验1所给语言写的源程序文件;输出为屏幕显示语法分析是否成功。在语法分析中不能出现任何的冲突(移进-归约或归约-归约冲
17、突),或者虽然有冲突,但是你能够说清楚冲突是如何解决的。在cygwin下用flex,bison和gcc工具将实验调试通过,并且你写的语法分析器至少应该能通过例子parser0中testcases目录下的test0.p和test1.p两个测试例的测试。实验参考:可以在例子parser0的基础上进行修改;如果你尚不能将实验2的词法分析器和本实验的语法分析器链接起来,可以暂时使用parser0给出的词法分析器(前提是你的语法分析器中终结符名的定义与parser0的相同)。程序代码:Cal.y%int yylex(); #define YYSTYPE double /* 将Yacc栈定义为double类型 printf(nThe value of the expression is %lf.n, $1);*/%token NUM LPAREN RPAREN ENTER %left OR%left AND%right NOT%left PLUS MINUS%left TIMES DIVIDE END%right UMINUS BEGIN VAR %nonassoc PROGRAM%union int inum; double fnum; char * id;% /* 这样写prog可以让分析器每次读入一行进行分析,下一行重新分析expr prog : prog exprp | expr