Lex与Yacc学习(九)之Yacc语法

Yacc语法

本文讨论yacc语法的格式并描述可用的各种特征和选项

yacc语法结构

yacc语法包括三部分:定义段、规则段和用户子例程段

...定义段...

%%

...规则段...

%%

...用户子例程段...

各部分由以两个百分号开头的行分开,尽管某一个部分可以为空,但是前两部分是必须的,第三部分和前面的百分号可以省略。

符号

yacc 语法由符号组成,即语法的“词”。符号是一串不以数字开头的字母、数字、句点和下划线。符号error专用于错误恢复,另外,yacc对任何符号都不会附加“先验”的意义。

由词法分析程序产生的符号叫做终结符号或者标记。定义在规则左侧的叫做非终结符号或者非终结。标记也可能是字面上引用的字符,通常遵循约定:标记大写,非终结符号小写。

定义段

定义段包括文字块,逐字拷贝到生成的C文件开头部分的C代码,通常包括声明和#include行。可能有%union  %start   %token   %type   %left  %right  和 %nonassoc声明。

也可以包含普通的C语言风格的注释,所有这些都是可选的,在简单的语法分析程序中,定义段可能完全是空的。

规则段

规则段由语法规则和包括C代码的动作组成。

用户子例程段

yacc 将用户子例程段的内容完全拷贝到C文件中,通常这部分包括从动作调用的例程。

动作

动作是yacc与在语法中规则相符时执行的C代码,动作一定是C复合语句。

通过使用后面跟有数字的美元符号,动作可以查阅在规则中与符号有关的值,冒号后面跟的第一个符号是数字1,例如:

date:month  '/'  day   '/'  year

                                          { printf ("date %d-%d-%d  found",$1,$3,$5);}

而名字,$$是指冒号左边符号的值,符号值可以有不同的C类型。

歧义和冲突

由于语法有歧义或者包含冲突,yacc对于语法规范的翻译可能会失败。一些情况下,语法确实有歧义,也就是说对于一个单独的输入字符串有两种可能的分析而且yacc处理不了。

另外一些情况,语法并无歧义,但yacc使用的语法分析技术不足以分析这个语法。

移进/归约冲突

当一个输入字符串有两种可能的分析时,而且其中一个分析完成一个规则(归约选项),而另一个却没有(移进选项)时,移进/归约冲突便发生了。

例如:

%%

e:                   ‘X’

                       |   e  '+'   e

                       ;

对于输入字符串“X+X+X” ,有两种可能的分析: “(X+X)+X”或者“X+(X+X)”,采用归约选项使得语法分析程序使用第一个分析,而采用移进选项则使用另一个。

归约/归约冲突

当同样的标记可以完成两个不同的规则时,就会发生归约/归约冲突。

例如:

%%

prog:    proga | progb

proga:       'X' ;

progb:       'Y' ;

一个“X”可能是proga,也可能是progb。

大多数归约/归约冲突没这么明显,但是几乎在任何情况下它们在语法中都表现为错误。

特殊字符

由于yacc处理符号标记而不是文本,它的输入字符集比起lex来说就简单的多,下面列出了yacc所使用的特殊符号的列表:

%

具有两个%标记的行将yacc语法分成了几部分;

定义段的所有声明都是以%开始,包括%{ %}    %union  %start   %token   %type   %left  %right  和 %nonassoc声明。

\

反斜线符号是废弃的百分号同义词,在动作中,C语言字符串中有其通常作用。

$

在动作中,美元符号引入一个值引用,举例来说,$3表示规则右端第3个符号的值。

文字标记由一个单引号结束,例如 ‘z‘ 。

<>

在一个动作的值引用中,可以不考虑尖括号包围起来的默认类型。

"

有些yacc版本在文字标记中将单引号和双引号同等对待,这样使用根本不方便。

{}

动作中C代码在大括号中。

;

除了后面紧接着是以竖线开头的规则外,规则部分每个都是以分号结束。

|

当连续两个规则具有相同的左端,第二个规则可用一个 | 代替符号和冒号。

:

在每一条规则里,左端的每个符号后面都跟着一个冒号。

_

符号可以包括和字母、数字以及句点在一起的下划线。

.

符号可以包括与字母、数字、下划线一起的句点。

=

早期版本使用,现已不推荐。

时间: 2024-10-11 03:15:43

Lex与Yacc学习(九)之Yacc语法的相关文章

JSP的学习(3)——语法知识二之page指令

本篇接上一篇<JSP的学习(2)——语法知识一>,继续来学习JSP的语法.本文主要从JSP指令中的page指令,对其各个属性进行详细的学习: JSP指令: JSP指令是为JSP引擎而设计的,JSP指令不产生任何可见输出,只是告诉在转换成Servlet的过程中如何处理JSP页面中的其余部分.在JSP 2.0 规范中共定义了三个指令: 1)   page指令 2)   include指令 3)   taglib指令 taglib指令是导入标签库的指令,以后会介绍到. JSP指令格式: <%@

学习笔记之06-点语法

前言 在Java中,我们可以通过"对象名.成员变量名"来访问对象的公共成员变量,这个就称为"点语法".比如: 1.在Student类的第2行定义了一个公共的成员变量age 1 public class Student { 2 public int age; 3 } 2.然后在第5行通过点语法直接给stu的成员变量age赋值 1 public class Test { 2 3 public static void main(String[] args) { 4 Stu

Esper学习之七:EPL语法(三)

1.Aggregation 和SQL一样,EPL也有Aggregation,即聚合函数.语法如下: [plain] view plaincopy aggregate_function([all|distinct] expression) aggregate_function就是聚合函数的名字,比如avg,sum等.expression通常是事件流的某个属性,也可以是不同事件流的多个属性,或者是属性和常量.函数之间的运算.举例如下. [plain] view plaincopy // 查询最新5秒

Oracle学习(九):创建和管理表

1.知识点:可以对照下面的录屏进行阅读 SQL> --创建表 SQL> create table test1 2 (tid number, 3 tname varchar2(20), 4 hidatedate date default sysdate); SQL> --使用as和子查询快速建表 SQL> --创建表:包含员工号 姓名 月薪 年薪 部门名称 SQL> create table empincome 2 as 3 select empno,ename,sal,sal

lua学习笔记之基本语法

Lua学习笔记之基本语法 1.  赋值语句 赋值是改变一个变量的值和改变表域的最基本的方法. a = "hello".."world" t.n = t.n+1 lua可以对多个变量同时赋值,变量列表和值列表的各个元素用逗号分开,赋值语句右边的值会一次赋给左边的变量. a,b = 10,2*x    <-->a = 10;b = 2*x 遇到赋值语句lua会先计算右边所有的值然后再执行赋值操纵,所以我们可以这样进行交换变量的值: x,y = y,x    

01-Python学习笔记-基础语法

Python标识符 -d           在解析时显示调试信息 -O           生成优化代码 ( .pyo 文件 ) -S           启动时不引入查找Python路径的位置 -v            输出Python版本号 -X           从 1.6版本之后基于内建的异常(仅仅用于字符串)已过时. -c cmd     执行 Python 脚本,并将运行结果作为 cmd 字符串. file           在给定的python文件执行python脚本. P

lua学习笔记(1)-基本语法

==============变量类型nilnumber(实数)    1 2 3.14 7.65e8string            "hello world" "\n"boolean(true false)    true falsefunction*userdata and threadstable(1)默认key初始化t = {a, "hello", b, "world"} (2)自定义key初始化t = {n1 =

ios学习路线_OC基础语法

OC是面向对象的语言,同java,python等等一样. OC中的变量类命名同其他对象语言基本类似,写法遵循驼峰法则 一般命名用到的是下划线,字母,开头字符非数字,网上很多有说也可以$符号,其实命名中基本不会用到这个 OC里面的关键字也不多,如图: OC中分基本数据类型和指针类型(即指对象类型) 那么一些基本类型的范围值和写法,这里不一一说,网上太多了,随便百度下 下面废话也不多说,直接给个网上的ppt说明吧 其实写过面向对象语言的朋友,基本上这块so easy 这里可以下载oc的基础部分 io

基于ZF中的.htaccess文件学习Apache的Rewrite语法

首先我们看一下这个.htaccess文件: RewriteEngine On RewriteCond %{REQUEST_FILENAME} -s [OR] RewriteCond %{REQUEST_FILENAME} -l [OR] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^.*$ - [NC,L] RewriteRule ^.*$ index.php [NC,L] 这里面涉及到了3个指令: 1.RewriteEngine  最简单,控制

学习python3 MySQL数据库语法遇到的问题:&quot;Can&#39;t connect to MySQL server on &#39;localhost&#39;

运行学习教程里面的mysql数据库按照里面要的步骤安装pyMySQL,学习里面的内容,会出现一些疑问,我也遇到了,发现这是一个认识上错误,实例如下: 根据基础教程运行下面代码,会报错: #!/usr/bin/python3 import pymysql # 打开数据库连接 db = pymysql.connect("localhost","test","test","DB" ) # 使用 cursor() 方法创建一个游标对象