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

11,526

$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.

Share:
11,526
emilytrabert
Author by

emilytrabert

Updated on June 09, 2022

Comments

  • emilytrabert
    emilytrabert almost 2 years

    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);
        }
    
  • torek
    torek over 10 years
    Incidentally, all the errors would also go away if you removed the %union and %type directives. The default type for the stack is int, and without a %union yacc assumes all tokens and nonterminals have the same type (YYSTYPE if I recall correctly, default int anyway). Use %union and %type to set different types for different tokens/nonterminals.
  • Artjom B.
    Artjom B. about 6 years
    Welcome to Stack Overflow! While this code block may answer the question, it would be best if you could provide a little explanation for why it does so. Please edit your answer to include such a description.