juimdpp
juimdpp

Reputation: 47

JAVACC: how to skip \n always except when preceded by a semicolon

I am currently making a sql parser and I wish to print a prompt for each new input.

< STATE >
TOKEN:
{
    < ENTER : "\n" > : DEFAULT
| < ELSE: ~[] > : DEFAULT
}

<DEFAULT>
TOKEN:
{ <DESC: "desc">
|....
} 

[...]

  (

 q = query()
 < SEMICOLON >
 {
     token_source.SwitchTo(STATE) ; 
    if(getToken(1).image == "\n")
    {
      printMessage(q);
      getNextToken();
      System.out.print("INPUT > ");
    }
    else
      printMessage(q);
  token_source.SwitchTo(DEFAULT);
      if(getToken(0).image == ";") getNextToken();
 }
)+

The problem happens when I enter something like this: "desc a;desc a;", in other words, when two queries are not separated by a space. I believe this is because as soon as the state is changed to STATE, the "desc" is no longer taken as "desc" but rather as "d". I have thought of trying to save the remaining to-parse input before changing the state, but I don't know how to implement that. I would really appreciate any help!!

Upvotes: 0

Views: 275

Answers (1)

Theodore Norvell
Theodore Norvell

Reputation: 16221

Don't switch lexical states from the parser. It's almost never a good idea.

If you want to ignore newlines that don't follow semicolons and not ignore newlines that don't follow semicolons, you could do something like this:

// Skip white space, but stay in the same state so a newline follows white space
// that follows a semicolon, it will be treated as a token.
< * >  SKIP: {  " " | "\t" | "\f" } 

// Skip newlines that don't follow semicolons
< DEFAULT >  SKIP: {  "\n" | "\r" }

// Other newlines result in ENTER tokens
< AFTER_SEMICOLON > TOKEN: {
    < ENTER : "\n" | "\r" > : DEFAULT }

<*> TOKEN : {
    < SEMI_COLON : ";" > : AFTER_SEMICOLON
|
    < DESC : "desc" >  : DEFAULT
|
     <ID : (["a"-"z","A"-"Z"])+ >  : DEFAULT
     //etc etc
|
     <UNEXPECTED_CHARACTER : ~[] > : DEFAULT
}

void many_lines() :
{}
{
       { System.out.print( ">" ) ; }
       ( 
           one_line()
           many_lines()
       |
           <EOF>
       )

}

void one_line() :
{}
{
  expr() <SEMI_COLON> 
  (
     <ENTER>
  |
   one_line() 
  )
}

void expr() :
{}
{
    <DESC> <ID>
}

This has lousy error recovery, but it's a start.

Upvotes: 1

Related Questions