问题
I'm trying to learn to use ANTLR, but I cannot figure out what's wrong with my code in this case. I hope this will be really easy for anyone with some experience with it. This is the grammar (really short).
grammar SmallTest;
@header {
package parseTest;
import java.util.ArrayList;
}
prog returns [ArrayList<ArrayList<String>> all]
:(stat { if ($all == null)
$all = new ArrayList<ArrayList<String>>();
$all.add($stat.res);
} )+
;
stat returns [ArrayList<String> res]
:(element { if ($res == null)
$res = new ArrayList<String>();
$res.add($element.text);
} )+ NEWLINE
| NEWLINE
;
element: ('a'..'z'|'A'..'Z')+ ;
NEWLINE:'\r'? '\n' ;
The problem is that when I generate the Java code there are some empty if conditions, and the compiler displays an error because of that, I could edit that manually, but that would probably be much worse. I guess something is wrong in this.
Sorry for asking, this has to be really stupid, but my example is so similar to those in the site that I cannot imagine a way to atomize the differences any more.
Thank you very much.
回答1:
You should put the initialization of your lists inside the @init { ... }
block of the rules, which get executed before anything in the rule is matched.
Also, your element
rule should not be a parser rule, but a lexer rule instead (it should start with a capital!).
And the entry point of your parser, the prog
rule, should end with the EOF
token otherwise the parser might stop before all tokens are handled properly.
Finally, the @header { ... }
section only applies to the parser (it is a short-hand for @parser::header { ... }
), you need to add the package declaration to the lexer as well.
A working demo:
SmallTest.g
grammar SmallTest;
@header {
package parseTest;
import java.util.ArrayList;
}
@lexer::header {
package parseTest;
}
prog returns [ArrayList<ArrayList<String>> all]
@init {$all = new ArrayList<ArrayList<String>>();}
: (stat {$all.add($stat.res);})+ EOF
;
stat returns [ArrayList<String> res]
@init {$res = new ArrayList<String>();}
: (ELEMENT {$res.add($ELEMENT.text);})* NEWLINE
;
ELEMENT : ('a'..'z'|'A'..'Z')+ ;
NEWLINE : '\r'? '\n' ;
SPACE : ' ' {skip();};
Main.java
package parseTest;
import org.antlr.runtime.*;
public class Main {
public static void main(String[] args) throws Exception {
SmallTestLexer lexer = new SmallTestLexer(new ANTLRStringStream("a bb ccc\ndddd eeeee\n"));
SmallTestParser parser = new SmallTestParser(new CommonTokenStream(lexer));
System.out.println(parser.prog());
}
}
And to run it all, do:
java -cp antlr-3.3.jar org.antlr.Tool parseTest/SmallTest.g javac -cp .:antlr-3.3.jar parseTest/*.java java -cp .:antlr-3.3.jar parseTest.Main
which yields:
[[a, bb, ccc], [dddd, eeeee]]
回答2:
Try converting element
into a token
ELEMENT: ('a'..'z'|'A'..'Z')+ ;
来源:https://stackoverflow.com/questions/6526131/antlr-generating-empty-conditions