编译 Yacc 代码

Compiling Yacc code

下面是我解析C源代码的yacc代码。我对此有点陌生,这是一个已经存在的代码。

{

%{
  #include <stdio.h>
  #include <string.h>
  #include "Expression.c"

%}


%token Identifier
%token Number
%token '=' '+' '-' '*' '/' ',' ';' '(' ')' '{' '}' '[' ']' '<' '>'
%token INT
%token CHAR
%token FLOAT
%token LONG
%token DOUBLE
%token RETURN
%token IF
%token ELSE
%token EQ       /* == */
%token BADTOKEN

%%

program
 : function 
     { $$ = ; }
 | program function 
    { $$ = binaryNode("",,);}
 | error '}'    

function: 
 typename Identifier '(' formal.arguments ')' function.body
    { $$ = attachAllChildren(,,,); }

typename
 : INT 
    { $$ = leafNode("INT");}
 | CHAR 
    { $$ = leafNode("CHAR"); }
 | DOUBLE 
    { $$ = leafNode("DOUBLE"); }
 | LONG 
    { $$ = leafNode("LONG"); }
 | FLOAT
    { $$ = leafNode("FLOAT"); }

formal.arguments
 :  /* empty */
    { $$ = NULL; }
 | formal.argument.list
    { $$ = ; }

formal.argument.list
 : formal.argument
    { $$ = ; }
 | formal.argument.list ',' formal.argument
    { $$ = binaryNode(",", , ); }

formal.argument
 : typename Identifier
    { $$ = attachChild(, ); }

function.body
 : '{' '}'
    { $$ = NULL; }
 | '{' statements '}'
    { $$ = ; }

statements
 : statement
    { $$ = ; }
 | statements statement
    { $$ = attachChild(,);}

statement
 : declaration
    { $$ = ; }
 | RETURN expression ';'        /* return statement */
    { $$ = unaryNode("RETURN", ); }
 | if.statement
    { $$ =; }
 | term '=' expression ';'      /* assignment */
    { $$ = binaryNode("=", , ); }
 | expression ';'
    { $$ = ; }

 | '{' statements '}'
    { $$ = ; }

 | ';'              /* null statement */
    { $$ = NULL; }

declaration
 : typename Identifier ';'
    { $$ = attachChild(,); }

 | typename Identifier '[' Number ']' ';'   /* array */
    { $$ = attachSiblings(, , ); }

if.statement
 : IF '(' expression ')' statement
    { $$ = ternaryNode("IF",,, NULL); }

 | IF '(' expression ')' statement ELSE statement
    { $$ = ternaryNode("IF", , , ); }

expression
 : additive.expression
    { $$ = ; }
 | expression EQ additive.expression
    { $$ = binaryNode("=",, ); }
 | expression '>' additive.expression
    { $$ = binaryNode(">", , ); }
 | expression '<' additive.expression
    { $$ = binaryNode("<", , ); }

additive.expression
 : term
    { $$ = ; }
 | additive.expression '+' term
    { $$ = binaryNode("+", , );}
 | additive.expression '-' term
    { $$ = binaryNode("-", , );}

term
 : Identifier
    { $$ = leafNode();}
 | Number
    { $$ = leafNode();}
 | Identifier '(' opt.actual.arguments ')'  /* function call */
    { $$ = attachChild(,);}
 | Identifier '[' expression ']'        /* array access */
    { $$ = attachChild(,); }
 | '(' expression ')'
    { $$ = ;}


 opt.actual.arguments
  : /* empty */
    { $$ = NULL;}
  | actual.arguments
    { $$=; }


 actual.arguments
   : expression
    { $$ = ; }

   | actual.arguments ',' expression
    { $$ = binaryNode(",",, ); }

 %%

 yyerror(msg)
 char* msg;
 {
   #if !defined(YYBISON)
   extern int yynerrs;

   ++yynerrs;
   #endif
   fprintf(stderr, "Error: %s\n",msg);
  }             

 main()
 {
    extern int yynerrs;
    yyparse();
    fprintf(stderr, "%d errors.\n", yynerrs);
    return 0;
  }
 }

在编译上述代码时,我收到一条警告,指出代码中存在 1 个 shift/reduce 冲突。我该如何解决?

使用 yacc 的 -v 选项,它将生成一个 y.output 文件,告诉您冲突在哪里以及它是如何触发的。请注意,冲突不是错误——您仍然可以从 yacc 获得有效的解析器——但该解析器可能无法准确识别您的语法定义的语言。

在你的情况下,你会得到类似的东西:

State 81 conflicts: 1 shift/reduce
        :
State 81

   28 if.statement: IF '(' expression ')' statement .
   29             | IF '(' expression ')' statement . ELSE statement

    ELSE  shift, and go to state 83

    ELSE      [reduce using rule 28 (if.statement)]
    $default  reduce using rule 28 (if.statement)

这告诉你你有经典的 dangling else ambiguity,所以你可以忽略冲突,因为生成的解析器将通过将 else 绑定到最接近的 if 来解决歧义,这可能就是你想要。