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

前言

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

语法

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

statement -> NAME = expression

expression -> 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 PLOW

cart_animal -> HORSE | GOAT
work_animal -> HORSE | OX

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

cart_animal -> HORSE | GOAT
work_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$ ./cal
print 2+3

test lex print

test lex NUMBER

test yacc NUMBER

test lex +
test lex NUMBER

test yacc expression + NUMBER

test yacc PRINT expression
result is 5mini2:cal nosources$ 
可见,“print 2+3” 这条语句,先接受到print,然后接受2,并且识别成NUMBER,然后接受+,然后接受3,识别成NUMBER,这时候,可以规约expression + NUMBER,之后又可以规约 PRINT expression,最终得到“result is 5”



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值