用Yacc实现语法分析器-4-编译原理
用Yacc实现语法分析器
一、实验目的
掌握语法分析器的构造原理,掌握Yacc的编程方法。
二、实验内容
用Yacc编写一个语法分析程序,使之与词法分析器结合,能够根据语言的上下文无关文法,识别输入的单词序列是否文法的句子。
program → block
block → { stmts }
stmts → stmt stmts | e
stmt → id= expr ;
| if ( bool ) stmt
| if ( bool) stmt else stmt
| while (bool) stmt
| do stmt while (bool ) ;
| break ;
| block
bool → expr < expr
| expr <= expr
| expr > expr
| expr >= expr
| expr
expr → expr + term
| expr - term
| term
term → term * factor
| term / factor
| factor
factor → ( expr ) | id| num
三、实验步骤及结果
实验环境:unix
实验结果:按归约的先后顺序显示每次归约时所使用的产生式。
部分代码:
用于产生flex输入的代码
Test.l:[a-zA-Z_][a-zA-Z_0-9]* {return ID;} [0-9]+\.[0-9]+ {return REAL;} [0-9]+ {return NUM;} "||" {return OR;} "&&" {return AND;} "|" {return '|';} "&" {return '&';} "<=" {return LE;} "<" { return '<';} ">=" {return GE;} ">" {return '>';} "!=" {return NE;} "=" { return '=';} "==" {return EQ;} "\+" {return '+';} "\-" {return '-';} "\*" {return '*';} "\/" {return '/';} "(" {return '(';} ")" {return ')';} ";" {return ';';} "{" {return '{';} "}" {return '}';} "[" {return '['; } "]" {return ']';} Test.y:rel : expr '<' expr { printf("rel-->expr<expr\n"); } | expr LE expr { printf("rel-->expr<=expr\n"); } | expr GE expr { printf("rel-->expr>=expr\n"); } | expr '>' expr { printf("rel-->expr>expr\n"); } | expr { printf("rel-->expr\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"); } | unary { printf("term-->unary\n"); } ; unary : '!' unary { printf("unary-->!unary\n"); } | '-' unary %prec UMINUS{ printf("unary-->-unary\n"); } | factor { printf("unary-->factor\n"); } ; factor : '(' bool ')' { printf("factor-->(bool)\n"); } | loc { printf("factor-->loc\n"); } | NUM { printf("factor-->num\n"); } | REAL { printf("factor-->real\n"); } | TRUE { printf("factor-->true\n"); } | FALSE { printf("factor-->false\n"); }
Flex生成代码:
Test.l:[a-zA-Z_][a-zA-Z_0-9]* {return ID;} [0-9]+\.[0-9]+ {return REAL;} [0-9]+ {return NUM;} "||" {return OR;} "&&" {return AND;} "|" {return '|';} "&" {return '&';} "<=" {return LE;} "<" { return '<';} ">=" {return GE;} ">" {return '>';} "!=" {return NE;} "=" { return '=';} "==" {return EQ;} "\+" {return '+';} "\-" {return '-';} "\*" {return '*';} "\/" {return '/';} "(" {return '(';} ")" {return ')';} ";" {return ';';} "{" {return '{';} "}" {return '}';} "[" {return '['; } "]" {return ']';} Test.y:rel : expr '<' expr { printf("rel-->expr<expr\n"); } | expr LE expr { printf("rel-->expr<=expr\n"); } | expr GE expr { printf("rel-->expr>=expr\n"); } | expr '>' expr { printf("rel-->expr>expr\n"); } | expr { printf("rel-->expr\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"); } | unary { printf("term-->unary\n"); } ; unary : '!' unary { printf("unary-->!unary\n"); } | '-' unary %prec UMINUS{ printf("unary-->-unary\n"); } | factor { printf("unary-->factor\n"); } ; factor : '(' bool ')' { printf("factor-->(bool)\n"); } | loc { printf("factor-->loc\n"); } | NUM { printf("factor-->num\n"); } | REAL { printf("factor-->real\n"); } | TRUE { printf("factor-->true\n"); } | FALSE { printf("factor-->false\n"); }
Yacc生成部分代码:
#line 1334 "y.tab.c" yyvsp -= yylen; yyssp -= yylen; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; /*------------------------------------. | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if YYERROR_VERBOSE yyn = yypact[yystate]; if (YYPACT_NINF < yyn && yyn < YYLAST) { YYSIZE_T yysize = 0; int yytype = YYTRANSLATE (yychar); const char* yyprefix; char *yymsg; int yyx; /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yycount = 0; yyprefix = ", expecting "; for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) { yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]); yycount += 1; if (yycount == 5) { yysize = 0; break; } } yysize += (sizeof ("syntax error, unexpected ") + yystrlen (yytname[yytype])); yymsg = (char *) YYSTACK_ALLOC (yysize); if (yymsg != 0) { char *yyp = yystpcpy (yymsg, "syntax error, unexpected "); yyp = yystpcpy (yyp, yytname[yytype]); if (yycount < 5) { yyprefix = ", expecting "; for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) { yyp = yystpcpy (yyp, yyprefix); yyp = yystpcpy (yyp, yytname[yyx]); yyprefix = " or "; } } yyerror (yymsg); YYSTACK_FREE (yymsg); } else yyerror ("syntax error; also virtual memory exhausted"); } else
例如,程序片断
{
i = 2;
while (i <=100)
{
sum = sum + i;
i = i + 2;
}
}
(注:原本是在windwos环境下编程,最后到unix环境下,发现速度快了,灵活性高了,同时方便了很多。(flex,bison))
test.l
%option noyywrap %{ #include<stdlib.h> #include<ctype.h> #include<stdio.h> %} %% "if" {return IF;} "while" {return WHILE;} "do" {return DO;} "break" {return BREAK;} "int"|"float"|"bool"|"char" {return BASIC;} "true" {return TRUE;} "false" {return FALSE;} "else" {return ELSE;} [a-zA-Z_][a-zA-Z_0-9]* {return ID;} [0-9]+\.[0-9]+ {return REAL;} [0-9]+ {return NUM;} "||" {return OR;} "&&" {return AND;} "|" {return '|';} "&" {return '&';} "<=" {return LE;} "<" { return '<';} ">=" {return GE;} ">" {return '>';} "!=" {return NE;} "=" { return '=';} "==" {return EQ;} "\+" {return '+';} "\-" {return '-';} "\*" {return '*';} "\/" {return '/';} "(" {return '(';} ")" {return ')';} ";" {return ';';} "{" {return '{';} "}" {return '}';} "[" {return '['; } "]" {return ']';} "//".* {} [ \n\t] {} %%
test.y
%{ #include<ctype.h> #include<stdio.h> %} %left '+' '-' %left '*' '/' %nonassoc UMINUS %token NUM AND BASIC BREAK DO ELSE EQ FALSE GE %token ID IF INDEX LE MINUS NE OR REAL TRUE WHILE KET %token RIGHT_BRA %% program : block { printf("program-->block\n"); } ; block : '{' decls stmts '}' { printf("block-->{decls stmts}\n"); } ; decls : decls decl { printf("decls-->decls decl\n"); } | /*empty*/ ; decl : type ID ';' { printf("decl-->type id;\n"); } ; type : type '[' NUM ']' { printf("type-->type[num]\n"); } | BASIC { printf("type-->basic\n"); } ; stmts : stmts stmt { printf("stmts-->stmts stmt\n"); } | /*empty*/ ; stmt : DO stmt WHILE '(' bool ')' ';' { printf("stmt-->do stmt while(bool);\n"); } | IF '(' bool ')' stmt { printf("stmt--if(bool)stmt\n"); } | IF '(' bool ')' stmt ELSE stmt { printf("stmt-->if(bool)stmt else stmt\n"); } | WHILE '(' bool ')' stmt { printf("stmt-->while(bool)stmt\n"); } | BREAK ';' { printf("stmt-->break;\n"); } | block { printf("stmt-->block\n"); } | loc '=' bool ';' { printf("stmt-->loc=bool;\n"); } ; loc : loc '[' bool ']' { printf("loc-->loc[bool]\n"); } | ID { printf("loc-->id\n"); } ; bool : bool OR join { printf("bool-->bool||join\n"); } | 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"); } | rel { printf("equality-->rel\n"); } ; rel : expr '<' expr { printf("rel-->expr<expr\n"); } | expr LE expr { printf("rel-->expr<=expr\n"); } | expr GE expr { printf("rel-->expr>=expr\n"); } | expr '>' expr { printf("rel-->expr>expr\n"); } | expr { printf("rel-->expr\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"); } | unary { printf("term-->unary\n"); } ; unary : '!' unary { printf("unary-->!unary\n"); } | '-' unary %prec UMINUS{ printf("unary-->-unary\n"); } | factor { printf("unary-->factor\n"); } ; factor : '(' bool ')' { printf("factor-->(bool)\n"); } | loc { printf("factor-->loc\n"); } | NUM { printf("factor-->num\n"); } | REAL { printf("factor-->real\n"); } | TRUE { printf("factor-->true\n"); } | FALSE { printf("factor-->false\n"); } ; %% #include "lex.yy.c" int main() { extern FILE *yyin; yyin=fopen("b.txt","r"); yyparse(); return 0; } yyerror(char *s) { printf("%s error!\n",s); }
b.txt
{ i = 2; while (i <=100) { sum = sum + i; i = i + 2; } }
在unix可以生成a.out就能直接用。
《Lex与Yacc》中文第二版(带源码)_yacc_flex_两份文档:http://pan.baidu.com/share/link?shareid=167248&uk=1678594189
实验4 secomd time 晋级版():http://pan.baidu.com/share/link?shareid=167252&uk=1678594189