在此文件上运行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'的$$没有声明的类型。
这是什么意思,我该如何解决?
答案 0 :(得分:41)
定义的union(%union)不打算直接使用。相反,你需要告诉Bison联盟的哪个成员被哪个表达式使用。
这是通过%type directive完成的。
代码的固定版本是:
%{
#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;}
;
%%
答案 1 :(得分:7)
作为进一步的想法,如果你想更明确地减少(如果你正在进行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,将lexeme洗牌到正确的标量有效载荷。
不是一个完整的解释,但你明白了。
希望这有助于您未来的Bison / Lex前端和......
祝你好运