7

我不熟悉 Yacc,并试图找到一个我在这里找到的例子来工作。当我尝试使用 编译时yacc -d calc.yacc,出现以下错误。

calc.yacc:42.17-18: $1 of `stat' 没有声明类型

calc.yacc:96.22-23: $1 of `expr' 没有声明类型

calc.yacc:105.17-18: $1 of `number' 没有声明类型

calc.yacc:106.20-21: $1 of `number' 没有声明类型

calc.yacc:110.29-30: $2 of `number' 没有声明类型

我尝试使用谷歌搜索,据我所知,解决方案与 %type 有关,但我不确定要添加什么。

代码如下:

%{
    #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);
    }
4

2 回答 2

8

$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

在第一个 %type 声明之后(或者只是LETTER在 expr 之后列出),第一个错误将被处理。DIGIT和 也是如此base。请注意,没有任何内容(自然)引用 stat 的值,因此不需要 %type 声明 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声明的目的。

于 2013-08-05T02:28:29.190 回答
-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 成员,我们应该使用上述指令。在这里查看更多%type

于 2018-04-01T07:58:13.267 回答