yacc 规则
语法文件的规则部分包含一条或者多条语法规则。 每条规则均描述结构并为其命名。
语法规则具有下述格式:
A : BODY;其中A是非终端名称,并且BODY是可以选择后跟优先顺序规则的 0 或更多名称,文字和语义操作的序列。 只有名称和文字是构成语法所必需的。 语义操作和优先顺序规则为可选的。 冒号和分号是必需的 yacc 标点。
语义操作允许您关联每次在输入进程中识别规则时要执行的操作。 操作可为任意 C 语句,照那样执行输入或者输出、调用子程序或者改变外部变量。 操作也可引用解析器的操作;例如:移位和减少。
优先顺序规则由%prec 关键字并更改与特定语法规则关联的优先顺序级别。 保留符号%prec 可以立即出现在语法规则的主体之后,并且可以后跟标记名称或文字。 构造使得语法规则的优先顺序成为标记名称或者文字的优先顺序。
重复非终止名称
如果多个语法规则具有相同的非终端名称,请使用|(管道符号) 以避免重写左侧。 此外,使用;(分号) 仅在所有由管道符号连接的规则的末尾。 例如,下面的语法规则:
A : B C D ;
A : E F ;
A : G ;可通过如下使用管道符号提供给 yacc 命令:
A : B C D
| E F
| G
;在语法文件中使用递归
递归是使用函数定义自己的过程。 在语言定义中,这些规则通常采用下面的格式:
rule : EndCase
| rule EndCase因此,最简单的案例rule是EndCase,但rule还可以包含多次出现的 EndCase。 第二行中使用的条目rule在定义中rule是递归。 解析器通过输入循环直至排列减为最后的 EndCase。
当在规则中使用递归时,通常将对规则名称的调用作为规则中最左边的项(如上述示例中所示)。 如果对规则名称的调用出现在行的后面部分(如以下示例),解析器可能耗尽内部堆栈空间并停止。
rule : EndCase
| EndCase rule以下示例定义了line作为字符串的一个或多个组合,后跟换行符 (\n):
lines : line
| lines line
;
line : string '\n'
;空字符串
要指示与空字符串匹配的非终端符号,请使用;(分号) 本身在规则的主体中。 定义符号empty与此匹配的empty字符串,请使用类似于以下规则的规则:
empty : ;
| x;或
empty :
| x
;结束输入标记
当词法分析器到达输入流的末尾时,它向解析器发送输入末尾标记。 此标记是名为 endmarker的特殊标记,其标记值为 0。 当解析器接收到输入结束标记时,它会检查是否已将所有输入分配给已定义的语法规则,以及已处理的输入是否构成完整的单元 (如 yacc 语法文件中所定义)。 如果输入是完整的单元,那么解析器将停止。 如果输入不是完整的单元,解析器则发错误信号并停止。
词法分析器必须在合适的时间发送输入末尾标记,如在文件的末尾或者记录的末尾。