yacc语法学习-part1

YACC的使用方法
1、用户手动写出文法说明文件(.y或者.grm文件)

2、Yacc编译器将此文法说明文件.y转换成用C编写的语法分析器文件.tab.c,使用命令bison -d yacc.y(开发环境:Ubuntu16.04),

3、用C编译器(gcc或者g++)将.tab.c编译为可执行文件,可执行文件默认为a.exe。使用命令g++ -c yacc.tab.c(开发环境:Ubuntu16.04),

4、a.exe即为可执行的语法分析器。可以直接运行查看结果。

具体操作可参考博客:参考博客点击这里

yacc说明文件的书写:

结构

 第一部分:定义段
 
 %%
 第二部分:规则段
 
 %%
 第三部分:辅助函数段

其中,第三部分可以省略,格式如下:

第一部分:定义段
 %%
第二部分:规则段

第一部分:定义段
定义段可以分为两部分:

第一部分以符号%{和%}包裹,里面为以C语法写的一些定义和声明:例如,包含的头文件,宏定义,全局变量定义,函数声明等。

第二部分主要是对文法的终结符和非终结符做一些相关声明。这些声明主要有如下一些:%token,%left,%right,%nonassoc,%union,%type,%start。下面分别说明它们的用法。

  • %token
    定义文法中使用了哪些终结符,终结符一般全大写。
  • %left,%right,%nonassoc
    定义文法中使用的终结符,定义形式与%token类似。
    但是他们定义的终结符具有某种优先级和结合性:%left表示左结合,%right表示右结合,%nonassoc表示不可结合(它定义的终结符不能连续出现:例如<,如果文法中不允许出现形如a<b<c的句子,则<就是不可结合的)
    优先级关系是以他们定义出现的顺序决定的,先定义的优先级低,最后定义的优先级最高,同时定义的优先级相同
  • %start:
    指定文法的开始符号(非终结符),定义形式为: %start startsym ,其中startsym为文法的开始符号。不使用%start定义文法开始符号,则默认在第二部分定义的第一条产生式规则的左部非终结符为开始符号。
  • %union和%type:
    用来处理文法中各符号所带的属性。
    记号是由记号名和记号的属性值两部分组成的,文法中的终结符和非终结符都属于记号,都有各自的属性值。
    Yacc通过维护一个栈,保存文法符号的“属性值”,这个栈与移进-归约分析中的文法符号栈是对应的:即,如果移进归约分析栈中某个位置存放文法符号X,则对应的Yacc“属性值”栈中就存放X的属性值。Yacc将这个属性值栈的栈内元素的类型定义为YYSTYPE(这是一个宏),默认状态下,YYSTYPE定义为int类型,你可以在文法说明文件第一部分定义段中重新定义YYSTYPE为其他类型,例如,用#defineYYSTYPE double 将其定义为double类型。如果你想让属性值栈可以存放多种类型的属性值,可以将属性值栈元素的类型定义为一种union类型,此时,你可以用%union来定义它。

第二部分:规则段
规则段实际上定义了文法的非终结符及产生式集合,以及当归约整个产生式时应执行的操作。例如:

 expr : expr PLUS term         {$$ = $1 + $3;}
       | term                  {$$ = $1;}
		;

归约expr PLUSterm为expr时,将会做如下操作:从属性值栈中取出产生式右部expr的属性值($1)和term的属性值($3),将两者的和存入属性值栈中对应产生式左部的expr的属性值中

第三部分:辅助函数:
用C语言语法来写,一般指在规则段中用到或者在语法分析器的其他部分用到的函数。这一部分一般会被直接拷贝到yacc编译器产生的c源文件中。除了规则段用到的函数外,辅助函数段一般包括如下例程:yylex(),yyerror(),main()。

  • int yylex()是词法分析程序,它返回记号。语法分析驱动程序yyparse()将会调用yylex()获取记号。如果不使用lex生成这个函数,则必须在辅助函数段用C语言写这个程序。记号由记号名和属性值构成,记号名一般作为yylex的返回值
  • main()是主程序,主程序的主要作用是调用yyparse()函数,yyparse()是yacc生成的语法分析驱动函数,语法分析成功结束时,yyparse返回0,而发现错误时,则返回1,并且调用yyerror()函数输出错误信息。
  • yyerror()是错误报告例程。

YACC中.y文件如何注释
用C语法写的部分,可以用C语言的两类注释;如

//注释部分
/*或者这样注释*/

非C语法写的部分,可以用如下方式注释:

 /* 这里写注释,但是要注意“/*”前面要有先导空格,不能顶着行首来写*/

先学这么多,之后如果还有补充还会更新哒~

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值