Yacc解析器语法错误。 int X;分别读作int X和;

时间:2011-03-31 23:23:32

标签: parsing grammar yacc bison bnf

问题描述

在我的yacc解析器语法中,我定义了以下规则和相应的操作(请参阅下面的 program.y )。解析 int X; 应该有 type => TOK_INT variable_list => TOK_VARIABLE ,然后这些与声明匹配以 statment ; 结尾。但是,请将其读作 int X ; 。也就是说,两个单独的陈述。谁能明白为什么?

program.y

program:
    function { exit(0); }
    ;

function:
    function line { printf("goal\n"); printtree_print($2); }
        |
        ;

line:
    statement ';' { printf("line\n"); printtree_print($1); }
    ;

statement:
    declaration { printf("declaration\n"); printtree_print($1); }
    | assignment { printf("assignment\n"); printtree_print($1); }
    ;

declaration: 
       type variable_list { printf("varlist\n"); printtree_print($2); $$ = $2;  }
       ;

type:
    TOK_INT { typeMode = typeInt; }
    ;

variable_list: 
         TOK_VARIABLE
         { $$ = node_mkVariable($1, typeMode); 

        printtree_print($$);
        }
         ; 

assignment:  
      TOK_VARIABLE TOK_ASSIGN expr
      { printf("assignment %s = expr\n", $1); 
        node_setInTable($1, $3); 
    $$ = node_getFromTable($1); }
      ;

expr:
    TOK_INTEGER { $$ = node_mkConstant($1); }
| TOK_VARIABLE { $$ = node_mkVariable($1, typeVariable); }
;

2 个答案:

答案 0 :(得分:3)

由于'expr'和'赋值'可能与问题没有密切关系,我从测试装置中省略了它们。由于您没有提供演示问题的最小可编译代码,因此我为您创建了它:

%{
#include <stdlib.h>
#include <stdio.h>
static void yyerror(const char *str);
static int yylex(void);
static void printtree_print(int);
static int node_mkVariable(int, int);
int typeMode;
enum { typeInt };
%}
%token TOK_INT
%token TOK_VARIABLE
%%
program:
    function
        { exit(0); }
    ;

function:
        /* Nothing */
    |   function line
        { printf("goal\n"); printtree_print($2); }
    ;

line:
    statement ';'
        { printf("line\n"); printtree_print($1); }
    ;

statement:
    declaration
        { printf("declaration\n"); printtree_print($1); }
    ;

declaration: 
    type variable_list
        { printf("varlist\n"); printtree_print($2); $$ = $2;  }
    ;

type:
    TOK_INT
         { typeMode = typeInt; }
    ;

variable_list: 
    TOK_VARIABLE
    {
        $$ = node_mkVariable($1, typeMode); 
        printtree_print($$);
    }
    ; 
%%
void printtree_print(int n)
{
    printf("PT_P: %d\n", n);
}
int yylex(void)
{
    static int counter = 0;
    static int tokens[] = { TOK_INT, TOK_VARIABLE, ';', 0 };
    enum { NUM_TOKENS = sizeof(tokens) / sizeof(tokens[0]) };
    if (counter < NUM_TOKENS)
    {
        printf("Token: %d\n", tokens[counter]);
        return(tokens[counter++]);
    }
    return 0;
}
int node_mkVariable(int var, int mode)
{
    return 23 + var + mode;
}
static void yyerror(const char *str)
{
    fprintf(stderr, "Error: %s\n", str);
    exit(1);
}
int main(void)
{
    while (yyparse() == 0)
        ;
    return 0;
}

当我编译它时,我得到输出:

Token: 258
Token: 259
PT_P: 23
varlist
PT_P: 23
declaration
PT_P: 23
Token: 59
line
PT_P: 23
goal
PT_P: 23
Token: 0

考虑到基础设施,这看起来是正确的,并且没有显示您观察到的行为的迹象。因此,您需要向我们展示足够多的额外代码来重现您的问题 - 以便证明它不是您没有提供的代码的人工制品,而是您语法的一个特征。

FWIW:这是使用系统提供的Yacc(实际上是Bison 2.3)在MacOS X 10.6.7上编译的 - 我在我的机器上获得了与其他2个Yacc变体基本相同的输出。海湾合作委员会是4.2.1(XCode 3)。

答案 1 :(得分:0)

你的lexer实际上可能有问题。 调试的一种方法是删除除直接涉及的所有子句之外的所有子句,然后逐个添加子句以查看哪一个引入了错误。