Search code examples
javaparsingcompiler-constructionjavacc

Issue parsing a custom grammar using JavaCC


I am writing a parser with JavaCC. This my current progress:

PARSER_BEGIN(Compiler)

public class Compiler {
    public static void main(String[] args) {
        try {
            (new Compiler(new java.io.BufferedReader(new java.io.FileReader(args[0])))).S();
            System.out.println("Syntax is correct");
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
}

PARSER_END(Compiler)

<DEFAULT, INBODY> SKIP:  { " " | "\t" | "\r" }
<DEFAULT> TOKEN: { "(" | ")" |  <ID: (["a"-"z","A"-"Z","0"-"9","-","_"])+ > | "\n" : INBODY }
<DEFAULT> TOKEN: { <#RAND: (" " | "\t" | "\r")* > | <END: <RAND> "\n" <RAND> ("\n" <RAND>)+ > }
<INBODY>  TOKEN: { <STRING: (~["\n", "\r"])*> : DEFAULT }

void S(): {}
{
    (Signature() "\n" Body() (["\n"] <EOF> | <END> [<EOF>]) )+
}

void Signature(): {}
{
    "(" <ID> <ID> ")"
}

void Body(): {}
{
    <STRING> ("\n" <STRING> )*
}

My goal is to parse a language looking like this:

(test1 pic1)
This line is a <STRING> token
After the last <STRING> one empty line is necessary

(test2 pic1)
String1
It is also allowed to have an arbitrary number (>=1) of empty lines




(test3 pic1)
String1
String2

(test4 pic1)
String1
String2
An arbitrary number (also zero) of empty lines follow till <EOF>

It almost works fine, but the problem I am now facing is the following:

At the end of the parsed text it is (like stated in the example above) allowed to have an arbitrary number (including zero) of empty lines till <EOF>. If I have no empty line before <EOF> it works as expected (it prints "Syntax is correct"). If I have at least two empty lines before <EOF> it also works as expected (it prints "Syntax is correct"). If there is exact only one empty line before <EOF> it should also print "Syntax is correct". But I get following exception stack trace instead:

ParseException: Encountered "<EOF>" at line 19, column 9.
Was expecting:
    <STRING> ...

        at Compiler.generateParseException(Compiler.java:284)
        at Compiler.jj_consume_token(Compiler.java:217)
        at Compiler.Body(Compiler.java:83)
        at Compiler.S(Compiler.java:18)
        at Compiler.main(Compiler.java:6)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at com.simontuffs.onejar.Boot.run(Boot.java:340)
        at com.simontuffs.onejar.Boot.main(Boot.java:166)

Does someone have an idea what the problem might be?

UPDATE:

Changing the line

(Signature() "\n" Body() (["\n"] <EOF> | <END> [<EOF>]) )+

to

(Signature() "\n" Body() (<EOF> | <END> [<EOF>]) )+

produces the same behavior. It seems that ["\n"] is (for some reason) completely ignored.


Solution

  • I found the core of the issue. Changing the line

    <STRING> ("\n" <STRING> )*
    

    to

    <STRING> (LOOKAHEAD(2) "\n" <STRING> )*
    

    solved the problem.

    It just needed a local LOOKAHEAD(2).