我正在使用Bison编写解析器,但似乎无法使语法正确。
以下是冲突一使用的一些规则:
program : function END_OF_FILE {return 0;}
formal_parameters : OPEN_PAREN formal_parameter list_E_fparameter CLOSE_PAREN | OPEN_PAREN CLOSE_PAREN
formal_parameter : expression_parameter | function_parameter
function : return_options IDENTIFIER formal_parameters block
function_parameter : return_options IDENTIFIER formal_parameters
expression_parameter : VAR identifier_list IDENTIFIER | identifier_list IDENTIFIER
variable_creation : identifier_list COLON type SEMI_COLON
labels : LABELS identifier_list SEMI_COLON
list_E_identifiers : list_E_identifiers COMMA IDENTIFIER |
identifier_list : IDENTIFIER list_E_identifiers
return_options : VOID | IDENTIFIER
状态12冲突:1减少/减少
state 12
56 identifier_list: IDENTIFIER . list_E_identifiers
60 return_options: IDENTIFIER .
102 list_E_identifiers: . list_E_identifiers COMMA IDENTIFIER
103 | .
COMMA reduce using rule 103 (list_E_identifiers)
IDENTIFIER reduce using rule 60 (return_options)
IDENTIFIER [reduce using rule 103 (list_E_identifiers)]
$default reduce using rule 60 (return_options)
list_E_identifiers go to state 23
状态64冲突:1次/减少
state 64
8 body: OPEN_BRACE list_E_statement . CLOSE_BRACE
17 statement: . opt_declaration unlabeled_statement
18 | . compound
31 compound: . OPEN_BRACE list_NE_unlstatement CLOSE_BRACE
73 opt_declaration: . IDENTIFIER COLON
74 | .
94 list_E_statement: list_E_statement . statement
CLOSE_BRACE shift, and go to state 68
IDENTIFIER shift, and go to state 69
OPEN_BRACE shift, and go to state 70
IDENTIFIER [reduce using rule 74 (opt_declaration)]
$default reduce using rule 74 (opt_declaration)
statement go to state 71
compound go to state 72
opt_declaration go to state 73
任何人都可以帮助我吗?我看过http://www.gnu.org/software/bison/manual/html_node/Understanding.html,但无法理解这意味着什么。
如果有帮助,我可以发布完整的语法。
谢谢!
答案 0 :(得分:0)
第二个冲突是“可选”元素的经典问题。编写可选标签的规则非常诱人,但optional_label
无法生成任何内容的事实迫使解析器在有足够信息之前尝试做出决定。
LR解析器必须在吸收任何进一步的令牌之前“减少”(识别)非终端。他们可以在下一个 k 标记中查找(LR(1)解析器的下一个标记,这是bison生成的),但是他们暂时不能使用该标记然后返回并执行减少。
因此,当解析器位于下一个标记(即标识符)应该启动语句的位置时,它可能正在查看以标识符开头的语句,或者它可能正在查看以标签开头的标签标识符。它可以通过查看标识符后面的冒号(如果有的话)来区分,但它看不到远远的结果。
现在,如果不是因为需要减少空optional_declaration
或包含标签的那个,那么就不会有问题。如果你写过这样的话:
statement: basic_statement | compound
basic_statement: unlabeled_statement | declaration unlabeled_statement
declaration: IDENTIFIER COLON
然后解析器在看到标识符时不必做出决定。它只需要在生产结束时作出决定;当有两种可能的制作完成时,它完全能够向前推进。但是当你强制它识别可选的标签时,它必须知道标签是否不在那里以减少(识别)空的生产。
对于第一次冲突,我们可以从输出中看到,有一些上下文符号为IDENTIFIER
的上下文,您可以有return_options
或identifier_list
。由于这两个产品都可以生成单个IDENTIFIER
,因此解析器不会知道要减少哪一个。
使用实际语法,很容易找到return_options IDENTIFIER
和identifier_list IDENTIFIER
都可能的上下文:
formal_parameter : expression_parameter | function_parameter
expression_parameter: identifier_list IDENTIFIER
function_parameter : return_options IDENTIFIER …
那个语法不含糊。如果IDENTIFIER IDENTIFIER
是function_parameter
的开头,则必须后跟(;如果是expression_parameter
,则必须后跟< kbd>,或)。但那是第二个下一个标记,这意味着你需要一个LR(2)解析器。
因此,我将提供有关处理LR(2)语法的通常建议。无论k的值如何,都可以将LR(k)语法重写为LR(1)语法,但结果通常是臃肿和丑陋的。因此,如果您正在使用野牛并且您愿意接受行动评估可能会稍微延迟的可能性,那么您最简单的解决方案就是要求Bison生成GLR解析器。通常,只需将%glr-parser
添加到选项部分即可。
值得注意的是,你的语法似乎是C和类似Pascal的语法之间的混淆。在C中,参数中的第一个标记始终是一个类型;函数的返回类型或以下标识符的类型。在Pascal中,参数中的最后一个标记是类型。但是在你的语法中,有时第一个标记是类型,有时它是最后一个标记。从某种意义上说,正是这种不一致导致了语法的尴尬。
(Pascal有更多标点符号:类型总是以冒号开头,函数参数前面有单词function
。这些额外的标记不需要使语法工作,但它可以是他们认为它们使语法更容易被人类阅读。)