50

在此文件上运行 Bison:

%{
    #include <iostream>
    int yylex();
    void yyerror(const char*);
%}


%union
{
    char    name[100];
    int     val;
}

%token NUM ID
%right '='
%left '+' '-'
%left '*'

%%

exp :   NUM     {$$.val = $1.val;}
    | ID        {$$.val = vars[$1.name];}
    | exp '+' exp   {$$.val = $1.val + $3.val;}
    | ID '=' exp    {$$.val = vars[$1.name] = $3.val;}
;

%%

导致以下警告:

警告:'exp' 的 $$ 没有声明的类型。

这是什么意思,我该如何解决?

4

2 回答 2

48

定义的联合 (%union) 不打算直接使用。相反,您需要告诉 Bison 哪个成员被哪个表达式使用。

这是通过%type 指令完成的。

代码的固定版本是:

%{
    #include <iostream>
    int yylex();
    void yyerror(const char*);
%}


%union
{
    char    name[100];
    int     val;
}

%token NUM ID
%right '='
%left '+' '-'
%left '*'

%type<val> exp NUM
%type<name> ID

%%

exp :   NUM     {$$ = $1;}
    | ID        {$$ = vars[$1];}
    | exp '+' exp   {$$ = $1 + $3;}
    | ID '=' exp    {$$ = vars[$1] = $3;}
;

%%
于 2009-06-18T19:08:34.710 回答
8

作为进一步的想法,如果你想更明确地减少你的减少(如果你正在做 AST 注释,这可能很方便),那么你可以让你的堆栈值指针,然后自己处理类型值。很像标量类型:

struct myScalar {
    union {
        int num;
        char *id;
        char *float_lexeme;
    }payload;

    enum {
        TYPE_NUM,
        TYPE_IDENTIFIER,
        TYPE_FLOAT_CHAR
    } type;
    char *orig_lexeme;
};

并有一个 typedef 和scalar_val *val堆栈。

当您转向更复杂的编译器前端时,它可以帮助您像这样构建您的 AST,这样当您遍历树时,您可以获得更好的元数据,并且您还可以通过前语义类型的翻译来增加翻译。然后归结为您的叶子产品,例如 ID,将词位洗牌到正确的标量有效负载中。

不是一个完整的解释,但你明白了。

希望这对您未来的 Bison/Lex 前端和...有所帮助

祝你好运

于 2009-06-18T19:41:30.467 回答