我对Yacc不熟悉并试图找到一个例子,我发现here可以工作。当我尝试使用yacc -d calc.yacc
进行编译时,出现以下错误。
calc.yacc:42.17-18:`stat'的$ 1没有声明的类型
calc.yacc:96.22-23:`expr'的$ 1没有声明的类型
calc.yacc:105.17-18:$ number的$ 1没有声明的类型
calc.yacc:106.20-21:$ number的$ 1没有声明的类型
calc.yacc:110.29-30:“number”的$ 2没有声明的类型
我尝试使用谷歌搜索,据我所知,解决方案与%类型有关,但我不确定要添加什么。
代码如下:
%{
#include <stdio.h>
int regs[26];
int base;
%}
%start list
%union { int a; }
%type <a> expr number
%token DIGIT LETTER
%left '|'
%left '&'
%left '+' '-'
%left '*' '/' '%'
%left UMINUS /*supplies precedence for unary minus */
%% /* beginning of rules section */
list: /*empty */
|
list stat '\n'
|
list error '\n'
{
yyerrok;
}
;
stat: expr
{
printf("%d\n",$1);
}
|
LETTER '=' expr
{
regs[$1] = $3;
}
;
expr: '(' expr ')'
{
$$ = $2;
}
|
expr '*' expr
{
$$ = $1 * $3;
}
|
expr '/' expr
{
$$ = $1 / $3;
}
|
expr '%' expr
{
$$ = $1 % $3;
}
|
expr '+' expr
{
$$ = $1 + $3;
}
|
expr '-' expr
{
$$ = $1 - $3;
}
|
expr '&' expr
{
$$ = $1 & $3;
}
|
expr '|' expr
{
$$ = $1 | $3;
}
|
'-' expr %prec UMINUS
{
$$ = -$2;
}
|
LETTER
{
$$ = regs[$1];
}
|
number
;
number: DIGIT
{
$$ = $1;
base = ($1==0) ? 8 : 10;
} |
number DIGIT
{
$$ = base * $1 + $2;
}
;
%%
main()
{
return(yyparse());
}
yyerror(s)
char *s;
{
fprintf(stderr, "%s\n",s);
}
yywrap()
{
return(1);
}
答案 0 :(得分:4)
$ 1,$ 2等等是指语法规则右侧的术语。例如在
中stat: expr
{
printf("%d\n",$1);
}
|
LETTER '=' expr {
regs[$1] = $3;
}
LETTER'='expr是规则之一,在下面的括号中,$ 1指的是LETTER。 regs[$1] = $3;
将被制作成C语句,但为了做到这一点,yacc需要知道$ 1的类型。如果你添加
%type <a> LETTER
在第一个%类型声明之后(或者只是在expr之后列出LETTER
),将会处理第一个错误。 DIGIT
和base
也是如此。请注意,没有任何内容可以引用stat(自然)的值,因此不需要stat的%类型声明。因此在
calc.yacc:105.17-18: $1 of `number' has no declared type
calc.yacc:106.20-21: $1 of `number' has no declared type
calc.yacc:110.29-30: $2 of `number' has no declared type
第一行表示DIGIT
具有未知类型,第二行表示与number
相同的问题;最后,最后一行提醒您声明base
的类型。这是它所指的yacc代码:
number: DIGIT
{
$$ = $1;
base = ($1==0) ? 8 : 10;
} |
number DIGIT
{
$$ = base * $1 + $2;
}
;
最后,没有涉及太多细节,声明
regs[$1]=$3;
将由yacc翻译成接近:
的内容regs[YS[1].<type of LETTER>]=YS[3].<type of expr>;
其中YS是'魔术数组'(实际上是yacc的堆栈); YS具有声明的%union的类型。因此,您可以看到,为了使其成为合法的C,yacc需要知道%union <type of LETTER>
的哪个成员引用。这是%type
声明的用途。
答案 1 :(得分:-1)
%{
#include<stdio.h>
int regs[26];
int base;
%}
%union { int a; }
%token DIGIT LETTER
%left '|'
%left '&'
%left '+' '-'
%left '*' '/' '%'
%left UMINUS /*supplies precedence for unary minus */
%type <a> stat expr number DIGIT LETTER
%% /* beginning of rules section */
list: list stat '\n'
|
list error '\n'
{
yyerrok;
}
| /*empty */
;
stat: expr
{
printf("%d\n",$1);
}
|
LETTER '=' expr
{
regs[$1] = $3;
}
;
expr: '(' expr ')'
{
$$ = $2;
}
|
expr '*' expr
{
$$ = $1 * $3;
}
|
expr '/' expr
{
$$ = $1 / $3;
}
|
expr '%' expr
{
$$ = $1 % $3;
}
|
expr '+' expr
{
$$ = $1 + $3;
}
|
expr '-' expr
{
$$ = $1 - $3;
}
|
expr '&' expr
{
$$ = $1 & $3;
}
|
expr '|' expr
{
$$ = $1 | $3;
}
|
'-' expr %prec UMINUS
{
$$ = -$2;
}
|
LETTER
{
$$ = regs[$1];
}
|
number
;
number: DIGIT
{
$$ = $1;
base = ($1==0) ? 8 : 10;
}
|
number DIGIT
{
$$ = base * $1 + $2;
}
;
%%
main()
{
return(yyparse());
}
yyerror(s)
char *s;
{
fprintf(stderr, "%s\n",s);
}
yywrap()
{
return(1);
}
需要使用%type 指令来指定在哪些表达式中使用union的成员。为了使用union成员a,我们应该使用上述指令。 点击此处%type