GNU Bison 根据上下文无关文法生成解析器。其兼容 Yacc 的表示法定义 token、非终结符、语义值和动作;按照约定,生成的解析器从扫描器获取 token。有关特定骨架和语言的接口,请参阅 GNU Bison 手册。
文法部分、值与动作 #
文法包含声明、产生式和可选的尾部代码,它们由 %% 分隔。声明定义 token、值类型、优先级、解析器设置和所需代码。产生式定义非终结符和动作。
%define api.value.type {int}
%token NUMBER
%left '+' '-'
%%
expression:
NUMBER { $$ = $1; }
| expression '+' expression { $$ = $1 + $3; }
;
%%产生式归约时会执行动作。$$ 表示结果的语义值,$1、$2 等表示右侧值。当符号携带不同值类型时,应使用带 %union 的 %type 和带类型的 %token 声明,或使用适当的 %define api.value.type 配置。确保析构函数和所有权规则覆盖错误恢复期间丢弃的值。
名称与解析器接口 #
C 解析器默认使用 yyparse、yylex 和 yyerror。%define api.prefix {project_} 为生成的外部名称设置独特前缀,因此多个生成的解析器可以链接到同一个程序中。使用匹配的前缀和头文件契约配置扫描器。
默认的 pull 解析器会自行调用词法分析器。%define api.push-pull push 为提供 token 的调用方生成 push 接口;both 同时提供 pull 和 push 接口。%define api.pure full 从可重入接口中移除解析器全局状态,但并发设计还需要可重入扫描器和显式的上下文传递。使用 %parse-param 和 %lex-param 在解析器及词法分析器调用之间传递该上下文。
位置、优先级与冲突 #
当诊断需要源代码范围时,启用 %locations。动作可以通过 @$ 和 @1 访问左侧和右侧的位置。词法分析器必须为所有输入一致填充位置字段,包括被忽略的空白。
%left、%right、%nonassoc、%precedence 和 %prec 根据声明的优先级和结合性解决选定的移进/归约冲突。除此之外,Bison 对移进/归约冲突默认优先移进,对归约/归约冲突使用较早的规则;这些默认行为都不能确立预期的语言语义。应调查每个冲突,在可用时使用 -Wcounterexamples 获取示例,并且仅将 %expect 保留为经过审查的、明确声明的冲突计数。
错误恢复 #
Bison 保留 error token 用于恢复产生式。发生语法错误时,statement: error ';' 这样的产生式可以丢弃输入,直到遇到同步 token,从而允许后续语句继续解析。只有当动作有意结束恢复时才使用 yyerrok;只有当已知前瞻 token 不合适时才使用 yyclearin。
恢复过程必须释放被丢弃的语义值、持续推进,并避免将级联错误报告为独立根因。应将恢复点放在稳定的文法边界——语句、声明或闭合分隔符——而不是在表达式内部接受任意 token。
评论
在 GitHub 上阅读或评论(发表评论需要登录)