Search code examples
compiler-constructionprogramming-languagesyacc

How to print the line that error occurs in Yacc?


Now I have the following code:

int yyerror( char *s ) 
{ 
    numberOfErrors ++;
    fprintf( stderr, "%s in line %d \n", s, yylineno ); 
}

This code prints the error reason and line number like syntax error in line 9 But what I am trying to do is, to print the line that error occurs as well. For example, if line 9 is: printf("Hello World"; (There is a typo. Missing ")") it should print

syntax error in line 9: printf("Hello World";

Is there a way to do this? Thanks.


Solution

  • Not easily.

    The input is read by the scanner, not the parser. Furthermore, the scanner is not really synchronised with the parser: it is usually working on identifying a token not yet analysed by the parser. So even if the scanner had a variable containing the "current line", that line would often be the line after the one containing the tokens being looked at by the parser. It could even be some subsequent line, if the scanner skipped over a long comment.

    Normally, the scanner does not actually have a buffer containing the current line, because it doesn't need it. It needs only the token it is currently scanning. Scanners usually read the input in fixed-length blocks, not lines, because it is more efficient, so there is no guarantee that all of the current line is contained in the current block.

    If you're using flex, you can change its input method so that it reads line-by-line. But that's not enough, because as mentioned above, the scanner's current line is often not the line we're interested in.

    It's worth noting here that the fact that the scanner is usually reading ahead affects the use of yylineno in parser error messages. In many cases, this will lead to the error report identifying the line after the error, or even later. This can be solved more easily, however, since bison provides the possibility of keeping a location object with every token. Unfortunately, flex scanners do not automatically fill in the location object, but a few lines of code are sufficient to do so. See this answer for a code sample.

    If the input is a regular file, it's pretty easy to reread the file to find a specific line. That won't work if the input is a pipe, for example, but it might be a good start.