Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

$1 of [...] has no declared type

Tags:

yacc

I am unfamiliar with Yacc and trying to get an example I found here to work. When I try to compile with yacc -d calc.yacc, I get the following errors.

calc.yacc:42.17-18: $1 of `stat' has no declared type

calc.yacc:96.22-23: $1 of `expr' has no declared type

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

I tried googling and from what I can tell, the solution has to do with %type, but I'm not sure what to add.

The code is below:

%{
    #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);
    }
like image 945
emilytrabert Avatar asked Aug 05 '13 01:08

emilytrabert


2 Answers

$1, $2, and so on refer to the terms on the right-hand side of a grammar rule. For example in

stat:    expr
             {
               printf("%d\n",$1);
             }
             |
             LETTER '=' expr {
               regs[$1] = $3;
             }

LETTER '=' expr is one of the rules and in the following parentheses $1 refers to LETTER. regs[$1] = $3; will be made into a C statement but in order to do that, yacc needs to know what type $1 has. If you add

%type <a> LETTER

after the first %type declaration (or simply list LETTER after expr) the first error will be taken care of. Same goes for DIGIT and base. Note that there is nothing that refers to the value of stat (naturally) so there is no need for a %type declaration for stat. Thus in

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

the first line implies that DIGIT has an unknown type, the second line refers to the same problem with number; finally the last line reminds you to declare the type for base. Here is the yacc code it is referring to:

 number:  DIGIT
             {
               $$ = $1;
               base = ($1==0) ? 8 : 10;
             }       |
             number DIGIT
             {
               $$ = base * $1 + $2;
             }
             ;

Finally, without getting into too many details, the statement

regs[$1]=$3; 

will be translated by yacc into something close to:

regs[YS[1].<type of LETTER>]=YS[3].<type of expr>;

where YS is a 'magic array' (actually yacc's stack); YS has the type of the declared %union. Thus you can see that to make this into legal C, yacc needs to know which member of the %union <type of LETTER> refers to. This is what the %type declaration is for.

like image 98
alexsh Avatar answered Oct 23 '22 10:10

alexsh


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

It is required to use %type directive to specify which members of union is used in which expressions.In order to use union member, a, we should use the aforementioned directive. See More here %type

like image 1
syq Avatar answered Oct 23 '22 10:10

syq