1

I am following the classic Kernighan & Pike The Unix Programming Environment; specifically the chapter that covers yacc. In the first example, a basic calculator named hoc1 is prepared with yacc.

Following the book I prepare the following code:

%{
#define YYSTYPE double
%}
%token NUMBER
%left '+' '-'
%left '*' '/'
%%
list:
    | list '\n'
    | list expr '\n'    { printf("\t%.8g\n", $2); }
    ;
expr:     NUMBER        { $$ = $1; }
    | expr '+' expr     { $$ = $1 + $3; }
    | expr '-' expr     { $$ = $1 - $3; }
    | expr '*' expr     { $$ = $1 * $3; }
    | expr '/' expr     { $$ = $1 / $3; }
    | '(' expr ')'      { $$ = $2; }
    ;
%%

#include <stdio.h>
#include <ctype.h>
char    *progname;
int lineno = 1;

int main(int argc, char *argv[]) {

    progname = argv[0];
    yyparse();
    
}


int yylex(void) {

    int c;
    
    /* Left trim all spaces/tabs */
    while((c=getchar()) == ' ' || c == '\t');
    
    /* Return 0 if EOF */
    if(c== EOF) {
        return 0;
    }
    
    /* Return NUMBER if number */
    if(c=='.' || isdigit(c)) {
        ungetc(c,stdin);
        scanf("%lf", &yylval);
        return NUMBER;
    }
    
    /* Count lines */
    if(c=='\n') {
        lineno++;
    }
    
    return c;       
    
}

void yyerror(char *s) {
    
    warning(s, (char *)0);

}

void warning(char *s, char *t) {

    fprintf(stderr, "%s: %s", progname, s);
    if(t) {
        fprintf(stderr, " %s", t);
    }
    fprintf(stderr, " near line %d\n", lineno);

}

But I get the following error while compiling the program:

~/tutorials/unix_programming_environment/hoc1 % yacc hoc1.y

~/tutorials/unix_programming_environment/hoc1 % cc y.tab.c -o hoc1

hoc1.y:64:2: warning: implicit declaration of function 'warning' is invalid in C99 [-Wimplicit-function-declaration]
        warning(s, (char *)0);
        ^
hoc1.y:68:6: error: conflicting types for 'warning'
void warning(char *s, char *t) {
     ^
hoc1.y:64:2: note: previous implicit declaration is here
        warning(s, (char *)0);
        ^
1 warning and 1 error generated.

I do not understand neither the warning or the error.

Edit: using yacc in FreeBSD 12.1

M.E.
  • 4,955
  • 4
  • 49
  • 128
  • 1
    @zwol: Why do you think the problem is a bug in `yacc` rather than that they have not declared `warning` before using it? – Eric Postpischil Jul 05 '20 at 00:04
  • Remember that the book was published in 1984, long before there was a standard C. There wasn't reliably a `void` type then either. There was no `` either. – Jonathan Leffler Jul 05 '20 at 01:05
  • @EricPostpischil Oops. I didn't notice the scrollbar so I thought the bad code was coming from the parser skeleton. – zwol Jul 05 '20 at 02:06
  • Actually the book uses the K&R style (which I have never used). So I tried to adapt the example to ANSI C89. – M.E. Jul 05 '20 at 11:49

1 Answers1

2

Move the definition of the yyerror function after the definition of the warning function or put this line before the yyerror function:

void warning(char *, char *);

This compiler message:

hoc1.y:64:2: warning: implicit declaration of function 'warning' is invalid in C99 [-Wimplicit-function-declaration]

tells you that the function warning is being used before any declaration of it is seen. This results in an implicit declaration due to the history of the C language.

This compiler message:

hoc1.y:68:6: error: conflicting types for 'warning'

tells you that the actual definition of warning has a different type than that of the implicit declaration from above.

This solution to this is to declare warning before using it, which you can do either by putting the definition (which is a declaration) before the use or by putting a separate declaration before the use.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312