【问题标题】:Shift Reduce Conflict减少冲突
【发布时间】:2017-04-24 03:32:32
【问题描述】:

我在修复语法中的 shift reduce 冲突时遇到了问题。我尝试添加 -v 来读取问题的输出,它引导我进入状态 0,并提到我的 INT 和 FLOAT 被规则 9 减少为 variable_definitions。我看不到冲突,我很难找到解决方案。

%{
#include <stdio.h>
#include <stdlib.h>
%}

%token INT FLOAT
%token ADDOP MULOP INCOP
%token WHILE IF ELSE RETURN
%token NUM ID
%token INCLUDE
%token STREAMIN ENDL STREAMOUT
%token CIN COUT
%token NOT
%token FLT_LITERAL INT_LITERAL STR_LITERAL


%right ASSIGNOP
%left AND OR
%left RELOP

%%
program:    variable_definitions
      | function_definitions
      ;
function_definitions: function_head block
      | function_definitions function_head block
      ;
identifier_list: ID
      | ID '[' INT_LITERAL ']'
      | identifier_list ',' ID
      | identifier_list ',' ID '[' INT_LITERAL ']'  
      ;
variable_definitions: 
      | variable_definitions type identifier_list ';'
      ;
type:         INT
      | FLOAT
      ;
function_head: type ID arguments
      ;
arguments: '('parameter_list')'
      ;
parameter_list:
      |parameters
      ;
parameters:   type ID
      | type ID '['']'
      | parameters ',' type ID
      | parameters ',' type ID '['']'
      ;
block:        '{'variable_definitions statements'}'
      ;
statements:   
      | statements statement
      ;
statement:    expression ';'
      | compound_statement
      | RETURN expression ';'  
      | IF '('bool_expression')' statement ELSE statement
      | WHILE '('bool_expression')' statement 
      | input_statement ';'
      | output_statement ';'
      ;
input_statement: CIN
      | input_statement STREAMIN variable
      ;
output_statement: COUT
      | output_statement STREAMOUT expression
      | output_statement STREAMOUT STR_LITERAL
      | output_statement STREAMOUT ENDL
      ;
compound_statement: '{'statements'}'
      ;
variable:     ID
      | ID '['expression']'
      ;
expression_list: 
      | expressions
      ;
expressions:  expression
      | expressions ',' expression
      ;
expression:   variable ASSIGNOP expression
      | variable INCOP expression
      | simple_expression
      ;
simple_expression: term
      | ADDOP term
      | simple_expression ADDOP term
      ;
term:         factor
      | term MULOP factor
      ;
factor:       ID
      | ID '('expression_list')'
      | literal
      | '('expression')'
      | ID '['expression']'
      ;
literal:      INT_LITERAL
      | FLT_LITERAL
      ;
bool_expression: bool_term
      | bool_expression OR bool_term
      ;
bool_term:    bool_factor
      | bool_term AND bool_factor
      ;
bool_factor:  NOT bool_factor
      | '('bool_expression')'
      | simple_expression RELOP simple_expression
      ;
%%

【问题讨论】:

    标签: bison flex-lexer yacc lex


    【解决方案1】:

    您对program 的定义是,它要么是变量定义列表,要么是函数定义列表(program: variable_definitions | function_definitions;)。这对我来说似乎有点奇怪。如果我想同时定义一个函数和一个变量怎么办?我必须编写两个程序并以某种方式将它们链接在一起吗?

    这不是问题的原因,但修复它也可能会解决问题。直接原因是function_definitions 是一个或多个函数定义,而variable_definitions 是零个或多个变量定义。换句话说,function_definitions 递归的基本情况是一个函数定义,而variable_definitions 的基本情况是空序列。因此,变量定义列表以空序列开头。

    但是函数定义和变量定义都以type 开头。因此,如果程序的第一个标记是int,它可能是返回类型为int 的函数定义或类型为int 的变量定义的开始。在前一种情况下,解析器应移动int 以生成function_definitions 基本情况:;在后一种情况下,它应该立即减少一个空的variable_definitions 基本情况。

    如果您真的希望程序既可以是函数定义也可以是变量定义,但不能两者兼而有之。您需要通过将基本情况从空更改为type identifier_list ';',使variable_definitions 具有与function_definitions 相同的形式。然后您可以向program 添加一个空产生式,以便解析器能够识别空输入。

    但正如我在开头所说的,您可能希望程序是一系列定义,每个定义都可以是变量或函数:

    program: %empty
           | program type identifier_list ';'
           | program function_head block
    

    顺便说一句,您误读了-v 生成的输出文件。它显示了状态 0 的以下操作:

    INT    shift, and go to state 1
    FLOAT  shift, and go to state 2
    
    INT       [reduce using rule 9 (variable_definitions)]
    FLOAT     [reduce using rule 9 (variable_definitions)]
    

    在这里,INTFLOAT 是可能的前瞻。所以INT [reduce using rule 9 (variable_definitions)] 行的解释是“如果前瞻是INT,立即减少使用生产9”。生产 9 产生空序列,因此减少将解析器堆栈顶部的零标记减少为 variable_definitions。缩减不使用前瞻令牌,所以缩减后前瞻令牌仍然是INT

    但是,解析器实际上并没有这样做,因为它对INT 有不同的操作,即转换它并进入状态1。如第一行开始INT 所示。方括号[...] 表示未执行此操作,因为它是一个冲突,并且冲突的解决是一些其他操作。因此,对该行更准确的解释是“如果不是针对 INT 的先前操作,则前瞻 INT 将使用规则 9 导致减少。”

    【讨论】:

    • 这是一个非常有用的答案,你真的帮助我理解了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多