help-bison
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Using %printer


From: Tim Van Holder
Subject: Re: Using %printer
Date: Fri, 15 Sep 2006 15:40:38 +0200
User-agent: Thunderbird 1.5.0.5 (Windows/20060719)

Akim Demaille wrote:
>>>> "Frans" == Frans Englich <address@hidden> writes:
>  > Opening the source and printing it is surely a good idea and a very nice 
>  > complement to regular reporting, but I still think that improving regular 
>  > reporting is significant.
> 
> I was not proposing to reopen the file for edition, but to get the
> full context and use caret-error-reporting:
> 
> % icc foo.c
> foo.c(1): error: more than one storage class may not be specified
>   register volatile const auto static extern int foo = 0;
>                           ^
> 
> foo.c(1): error: more than one storage class may not be specified
>   register volatile const auto static extern int foo = 0;
>                                ^
> 
> foo.c(1): error: more than one storage class may not be specified
>   register volatile const auto static extern int foo = 0;
>                                       ^
> 
> foo.c(1): error: a global-scope declaration may not have this storage class
>   register volatile const auto static extern int foo = 0;
>   ^
> 
> compilation aborted for foo.c (code 2)

I don't see how _bison_ can do this with any accuracy - after all it
only gets a token stream, with no guarantee of any correlation to a
usable file (in fact it could be getting tokens based on a terminal or
network traffic, so reopening the input file to get the context may not
even be possible at all).  If preserving "friendly" input for error
processing is needed, it pretty much HAS to be done in the lexer.

What's more, it's quite easy to handle in flex, using states.

Something like

  {
    if (context.line == 0) { // Fresh file - set up the initial state
      context.line = context.column = 1;
      BEGIN(INITIAL);
      yy_push_state(BUFFER_LINE);
    }
  }

<BUFFER_LINE>^[^\r\n]*/{EOL}? { // Get & save entire line
  // Possibly trim trailing whitespace here
  context.current_line = yytext;
  yy_pop_state();
  // Mark this as the start of a new line (for ^ matching)
  yy_set_bol(true);
}


<*>{

  {EOL} {
    context.column = 1;
    ++context.line;
    yy_push_state(BUFFER_LINE);
  }

}

should do the trick (noting that I use C++ actions, with 'context' being
a structure passed via %lex-param, and 'context.current_line' being a
std::string).

Then error reporting can look something like this:

void
yyerror(parser_context_t& context, const char* message)
{
  ++context.parse_errors;
  if (yyleng = 0)
    error(context.line, context.column, _("%s at empty token"),
    message);
  else
    error(context.line, context.column - yyleng,
          _("%s at token `%s'"), message,
          ((yytext[0] == '\n') ? _("[end-of-line]") : yytext));
  maybe_show_context_line(context);
}

void
maybe_show_context_line(parser_context_t& context)
{
  if (!context.current_line.empty()) {
  string context_line = context.current_line;
    try {
      context_line.insert(context.column - 1,          _("<<<"));
      context_line.insert(context.column - 1 - yyleng, _(">>>"));
    }
    catch (...) { context_line = context.current_line; }
    errinfo(context.line, 0, _("Context: %s\n"), context_line.c_str());
  }
}

So if bison has a parse error on an identifier, I would get

foo:13.9: error: syntax error, unexpected identifier, expecting
relational operator at token `xyzzy'
foo:13: Context:  if (foo >>>xyzzy<<<) {

So friendly token content, courtesy of yytext (I suppose this won't work
with GLR tho, as other tokens could have been consumed by the time the
error is reported), as well as the full context line, courtesy of
flex-based caching.





reply via email to

[Prev in Thread] Current Thread [Next in Thread]