有两个匹配字符串的规则,但是如果两个规则可以解析这个字符串,我需要使用第一个!
具体我是在为C ++编写类似语言的野牛解析器,问题是当我使用像
这样的指针声明时ClassName* a;
野牛将其解析为乘法运算符,而不是减速! 我需要将声明节点的优先级设置为高于乘法(表达式)。
答案 0 :(得分:3)
在yacc风格的LALR(1)中处理此问题的常用方法是让词法分析器通过在当前符号表中查找并为类型名称返回不同的标记来确定标识符何时是类型名称。所以你最终会得到如下规则:
declaration: decl_specs declarator_list ;
decl_specs: TYPE_NAME | ....
declarator: ID | TYPE_NAME | '*' declarator ...
expression: ID | expression '*' expression | ...
由于您不能使用已声明为类型名称的名称作为表达式中的值,因此这对于解析C非常有效。
当尝试解析C ++时,这不能很好地工作,因为你有明确的命名空间操作(使用::
),因为你可以拥有看起来像函数调用的声明。一般来说,在C ++中,你需要超过1个前瞻标记来解决其中的一些问题,因此LALR(1)解析器不能很好地工作。
使用bison,您可以使用%glr-parser
选项生成GLR解析器而不是LALR解析器。 GLR解析器本质上是无限的前瞻(在发生冲突时尝试所有可能性),这可能导致多个解析。您需要在规则上放置%dprec
修饰符以解决有利于一个解析器或其他解析的歧义,或%merge
指令以保持两个解析。
答案 1 :(得分:1)
根据我对你的问题的理解,你愿意放弃有没有明显副作用的陈述的可能性,比如没有作业的算术运算。您的解决方案是将语句规则重新定义为仅包含一些表达式(即调用和赋值)。
我假设你的语法看起来像这样(在伪野牛中):
statement:
expression ';'
| declaration
expression:
token
| expression '+' expression
| expression '-' expression
| expression '*' expression
| expression '/' expression
| expression '=' expression
| expression '(' param_list ')' // function call
除了使expression ';'
成为有效语句之外,您应该将表达式规则拆分为一个可以形成有效语句的集合,并且该集合将排除算术运算。
statement:
top_level_expression ';'
| declaration
top_level_expression:
expression '=' expression
| expression '(' param_list ')' // function call
expression:
token
| top_level_expression
| expression '+' expression
| expression '-' expression
| expression '*' expression
| expression '/' expression