lex与yacc程序配合编写语法分析程序

来源:互联网 发布:加好友软件qq2016 编辑:程序博客网 时间:2024/05/16 06:47

前言

凡是lex识别正则表达式的地方,yacc都可以识别完整的语法,lex将输入流分成块(标记),然后yacc去的这些块并将他们逻辑性的归组到一起

语法

yacc采用你指定的语法,并为这些语法中的表达式创建分析程序,语法是是一系列规则,用来识别输入符号

statement -> NAME = expressionexpression -> NUMBER + NUMBER | NUMBER - NUMBER

->左侧缩写为LHS(left -hand side),右侧缩写为RHS(right-hand side),LHS必须为非终结符,输入中的和被词法分析程序返回的为终结符或标记

使用树状结构来表示所分析的句子,例如输入“fred = 12 + 13”


递归规则

规则可以直接或者间接的引用本身

expression -> NUMBER| expression + NUMBER| expression - NUMBER

现在这个规则可以匹配"fred = 12 + 13 - 11 +7"这样的句子了

移进/规约分析

yacc的语法程序总是在寻找哪一个规则和当前能看到的标记匹配,每次读取一个标记,如果没有匹配到规则,就压入内部堆栈,并且换到一个反映刚刚读取的标记的新的状态,这个动作叫做移进,如果匹配到了一条规则,就会把右侧符号弹出堆栈,将左侧符号压入堆栈,并且切换到一种反映新符号的新状态,这个动作叫做规约,通过不断移进规约,语法程序就可以分析输入了

yacc不能分析的语法

  • 歧义语法:同样的输入,符合多个分析树
  • 需要向前(输入流的后面)看多个标记才能确定是否匹配到规则
phrase -> cart_animal AND CART| work_animal AND PLOWcart_animal -> HORSE | GOATwork_animal -> HORSE | OX

对于上面的文法,并没有歧义,输入如果是“HORSE AND CART”,当看到HORSE的时候,并不知道是cart_animal 还是work_animal,因为要知道后面AND 和后面的CART的时候,才可以确定是cart_animal,所以这个不行,改成下面的就可以,因为只向前看了一个标记,这个yacc是支持的
phrase -> cart_animal CART| work_animal PLOWcart_animal -> HORSE | GOATwork_animal -> HORSE | OX
当输入“HORSE CART”,读取HORSE的时候并不知道是cart_animal 还是work_animal,但是下一个是CART,所以规约成cart_animal CART,再规约到phrase

加减法程序

cal.y
%{#include <stdio.h>%}%token PRINT NUMBER%%statement: PRINT expression{printf("\ntest yacc PRINT expression\n");printf("result is %d", $2);}|expression {printf("\ntest yacc expression\n");printf("%d is the result", $1);};expression: expression '+' NUMBER {printf("\ntest yacc expression + NUMBER\n");$$ = $1 + $3;}|NUMBER {printf("\ntest yacc NUMBER\n");$$ = $1;} 


cal.l
%{#include "y.tab.h"extern int yylval;%}%%print {printf("\ntest lex print\n"); return PRINT;}[0-9]+ {printf("\ntest lex NUMBER\n");yylval = atoi(yytext);  return NUMBER;}[ \t] ;\n return 0;. {printf("\ntest lex %s", yytext); return yytext[0];} %%

mini2:cal nosources$ yacc -d cal.y && lex cal.l && cc -o cal y.tab.c lex.yy.c -ly -ll
mini2:cal nosources$ ./calprint 2+3test lex printtest lex NUMBERtest yacc NUMBERtest lex +test lex NUMBERtest yacc expression + NUMBERtest yacc PRINT expressionresult is 5mini2:cal nosources$ 
可见,“print 2+3” 这条语句,先接受到print,然后接受2,并且识别成NUMBER,然后接受+,然后接受3,识别成NUMBER,这时候,可以规约expression + NUMBER,之后又可以规约 PRINT expression,最终得到“result is 5”



0 0