1
votes

I'm trying to create my own errors, but apparently, envoking yyerror() is not enough to tell parser that there is an error. I made a little example to describe my problem better. So here is a parser that must check if a statement is two numbers with comma between them. And numbers can not start with 0.

input for yacc:

%token DIGIT            

%{      
#include <stdio.h> 
#include <stdlib.h>
void yyerror(char *s);    
%}

%%
    list:    |
        list stat ';' {printf("The statement is correct!\n\n");} |
        list error ';' {printf("The statement is incorrect!\n\n");}

    stat:   number ',' number

    number: DIGIT {if ($1==0) yyerror("number starts with 0");} | 
        number DIGIT {$$ = $1*10+$2;}
%%
extern int linenum;
void yyerror(char *s) {
    fprintf(stderr, " line %d: %s\n", linenum, s);
}

for lex:

%{
#include <stdio.h>
#include "y.tab.h"
int linenum = 1;
%} 

%% 

[0-9]               {
                 yylval = yytext[0] - '0';
                 return DIGIT;
                }

[ \t\r]+            ;
\n                  ++linenum;
.               return(yytext[0]);

Input for the parser:

34, 43;
32,fs;
03, 23;

And here is the output:

The statement is correct!

 line 2: syntax error
The statement is incorrect!

 line 3: number starts with 0
The statement is correct!

Even though the error on the 3rd line is found, parsing still continues. How can I fix it?

Upd: the problem was solved by using YYERROR;

3

3 Answers

0
votes

If you want it to stop after detecting one error (why?), just return from the production concerned.

By default it will perform error recovery.

0
votes

The parse is continuing because you have a rule with error in it, which is an error recovery rule that tells the parser how to recover from an error and continue. If you don't want to continue after an error, remove the error recovery rule. Then yyparse will immediately return (non-zero) after an error.

-1
votes

Seems to me yyerror() just prints the error message, but does not set an error state in the parser. Possibly you can modify syntax a bit?

lex:

0          {
             yylval = 0;
             return ZERO;
           }
[1-9]      {
             yylval = yytext[0] - '0';
             return DIGITNOZERO;
           }

yacc:

number: DIGITNOZERO | 
        number DIGITNOZERO  {$$ = $1*10+$2;} | 
        number ZERO {$$ = $1*10;}