Re: LEX/YACC - grammar problems and printing error messages

johnl@iecc.cambridge.ma.us (John R. Levine)
Thu, 28 May 1992 18:38:40 GMT

          From comp.compilers

Related articles
LEX/YACC - grammar problems and printing error messages nett@technix.mn.org (1992-05-28)
Re: LEX/YACC - grammar problems and printing error messages johnl@iecc.cambridge.ma.us (1992-05-28)
Re: LEX/YACC - grammar problems and printing error messages craig@comp.lancs.ac.uk (1992-05-29)
LEX/YACC - grammar problems and printing error messages thiemann@informatik.uni-tuebingen.de (1992-06-02)
| List of all articles for this month |

Newsgroups: comp.unix.programmer,comp.compilers
From: johnl@iecc.cambridge.ma.us (John R. Levine)
Keywords: lex, errors
Organization: I.E.C.C.
References: 92-05-148
Date: Thu, 28 May 1992 18:38:40 GMT

In article 92-05-148 you write:
>[how can I get the entire line where an error occurs into an error message?]


Yacc promises to complain as soon as it sees a token you can't parse so it's
mostly a matter of having the current line available when the error occurs.


Basically, you have to buffer the line yourself. In AT&T lex one
possibility is to rewrite the input() macro to do line buffering, but
here's a sketch of how to do it in a portable way that should work with
flex, the version of lex that all sensible people use. This should extend
in a straightforward way to multi-line records so long as the lexer can
tell where the record boundaries are.


---begin untested lex code---


%{
char linebuf[500]; /* line buffer for tokens */
int curoffs; /* start of current token */
int clear_on_next = 0;
%}


%%


/* clear buffer after end of line */
\n { add_linebuf(); clear_on_next = 1; return(EOL); }


/* real token */
foo { add_linebuf(); return(FOO); }


/* ignored white space still needs to go in the buffer */
[ \t]+ { add_linebuf(); }


%%


/* initialize the line buffer */
clr_linebuf()
{
linebuf[0] = '\0';
curoffs = 0;
clear_on_next = 0;
}


/* add the current token to the current line */
add_linebuf()
{
if(clear_on_next)
clr_linebuf();


curoffs = strlen(linebuf); /* start of current */
strcpy(linebuf+curoffs, yytext); /* append current */
/* strcpy is faster than strcat */
}


/* report an error */
yyerror(char *errmsg)
{
int curend = linebuf+strlen(linebuf); /* current buf end */
char *p;


/* get the rest of the line if not at end */
if(!clear_on_next) {
for(p = curend; ; ) {
int c = input();


*p++ = c;
if(c == '\n')
break;
}
*p = 0;
/* now give it back so lex can scan it later */
while(p > curend)
unput(*--p);
}


/* linebuf[] now has the whole line, with the current token */
/* at curoffs */


/* print error message and current line */
printf("%s\n%s", errmsg, linebuf);


/* print an X under the most recent token */
printf("%*sX\n", curoffs , ""); /* curoffs spaces, then X */
}
--end untested lex code---


Here's a slightly easier approach which pre-reads the next line after
every newline, but doesn't keep track of the location of the current
token.


--begin more untested lex code---
%%


\n.* { strcpy(linebuf, yytext+1); /* save the next line */
yyless(1); /* give back all but the \n to rescan */
}
--begin more untested lex code---


Regards,
John Levine, johnl@iecc.cambridge.ma.us, {spdcc|ima|world}!iecc!johnl


--


Post a followup to this message

Return to the comp.compilers page.
Search the comp.compilers archives again.