$1 of [...] has no declared type
Asked Answered
P

2

8

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);
    }
Potoroo answered 5/8, 2013 at 1:15 Comment(0)
E
10

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

Enwomb answered 5/8, 2013 at 2:28 Comment(1)
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.Sharice
C
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);
}

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

Craftsman answered 1/4, 2018 at 7:58 Comment(1)
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.Radiocarbon

© 2022 - 2024 — McMap. All rights reserved.