yacc学习笔记(一)基础语法

yacc的功能:

sql解析中的语法分析工具,和flex配合使用。

yacc不能分析什么:

1、不能处理歧义语法,在歧义语法中,同样的输入符合多个分析树
2、不能处理需要向前看多于一个标记才能确定它是否已经匹配一条规则的语法。

yacc与lex的通信:

词法分析程序将标记返回给语法分析程序时,如果标记有相关的值,词法分析程序在返回之前都必须在yylval中存储值。
yylval默认为int型,在更复杂的语法分析程序中,yacc将yylval定义为一个union类型,放置在y.tab.h中。

yacc语法分析程序结构:

定义段:处理yacc生成的语法分析程序的控制信息,建立语法分析程序的执行环境
规则段:包含语法分析程序的规则;
代码段:被逐字拷贝到生成的C程序中的C代码

定义段常见内容:
1、标记的描述
例:/* ordinary key words in alphabetical order */
%token ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER
注意:可以将单个被引起来的字符作为标记而不用声明它们,所以不需要声明“=”、“+”或“-”
2、%type声明
用%type 声明非终结符的类型,每个声明都有如下格式:
%type name,name…
"type"名字必须由“%union"定义,每个name都是一个非终结符的名字
3、%union声明
%union声明标识符号值的所有可能C类型,声明采用这种格式:
%union {
…域声明…
}
域声明被逐字拷贝到输出文件中YYSTYPE类型的C联合类型声明中
在没有%union声明时,yacc将YYSTYPE定义为int,所以所有的符号值都是整数
例:

%union
{
	core_YYSTYPE		core_yystype;
	/* these fields must match core_YYSTYPE: */
	int					ival;
	char				*str;
	const char			*keyword;

	char				chr;
	bool				boolean;
	JoinType			jtype;
	DropBehavior		dbehavior;
	OnCommitAction		oncommit;
	List				*list;
	Node				*node;
	......
}

4、结合规则(associativity)声明:%left 左结合性声明,%right 右结合性声明,%nonassoc 声明没有结合规则
例:
%left ‘+’ ‘-’
%left ‘*’ ‘/’

yacc与lex程序结构都包括定义段、规则段、代码段三段,但规则段语法有以下不同:
1、和lex不同,yacc不关心行边界,你会发现大量的空白会使程序更容量阅读
2、分析程序增加了一条新规则:语句可以是纯表达式,也可以是一个赋值

规则段

起始符号:第一条规则左侧的符号通常是起始符号,但可以在定义部分使用%start声明覆盖它

%prec: 声明所用标记的优先级,常与声明段的%nonassoc配合使用,例:

%left '-' '+'
%left '*' '/'
%nonassoc UMINUS
%%
expression: expression '+' expression {$$=$1+$3;}
        | expression '-' expression {$$=$1-$3;}
        | expression '*' expression {$$=$1*$3;}
        | expression '/' expression
                {       if($3==0.0)
                                yyerror("divide by zero");
                        else
                                $$=$1/$3;
                }
        | '-' expression  %prec UMINUS    {$$=-$2;} //%prec告诉yacc为这条规则使用UMINUS的优先级
%%

lex+yacc实现简单计算器程序:
词法分析程序ch1-1.l:

%{
#include "y.tab.h"
extern int yylval;
%}

%%
[0-9]+          {yylval=atoi(yytext); return NUMBER;}
[ \t] ;
\n              return 0;
.               return yytext[0];
%%

int yywrap()
{
        return 1;
}

语法分析程序ch1-1.y

扫描二维码关注公众号,回复: 10080834 查看本文章
%{
#include <stdio.h>
%}

%token NAME NUMBER

%%
statement: NAME '=' expression
        | expression  {printf("=%d\n",$1);}
        ;

expression: expression '+' NUMBER {$$=$1+$3;}
        | expression '-' NUMBER {$$=$1-$3;}
        | NUMBER                {$$=$1;}
        ;
%%
extern FILE *yyin;

int main(){
        do{
                yyparse();
        }while(!feof(yyin));
}

void yyerror(char *s){
        fprintf(stderr,"%s\n",s);
}
~  

编译及运行:
lex ch1-1.l //生成lex.yy.c
yacc -d ch1-1.y //生成y.tab.c和y.tab.h
cc -o test y.tab.c lex.yy.c //生成可执行文件
./test //测试

发布了8 篇原创文章 · 获赞 2 · 访问量 213

猜你喜欢

转载自blog.csdn.net/sxqinjh/article/details/104596059