I am trying to create a grammar that accepts two ranges of integer:
intege开发者_如何学Pythonr1 from 1
to 10000
and, integer2 from 0
to 25999
Here is what I have written:
grammar first;
tokens {
SET = 'set';
VALUE1 = 'value1';
VALUE2 = 'value2';
SEPARATOR = ' ';
}
expr : SET SEPARATOR attribute EOF;
attribute : VALUE1 SEPARATOR integer1
| VALUE2 SEPARATOR integer2;
DIGIT : '0'..'9';
integer1 @init {int N= 0;}: ((DIGIT { N++; } )+ { N <=4 }?);
integer2 : integer1
| ('1' (DIGIT DIGIT DIGIT DIGIT))
| ('2' ('0' | '1' | '2' | '3' | '4' | '5') DIGIT DIGIT DIGIT);
I am facing the following problems:
When I give the input as:
set value1 3
I am getting an exception:line 1:11 required (...)+ loop did not match anything at input '3'
. On the other hand if I am giving the input asset value1 8
, its working fine. Why?When I give the input as:
set value2 832
I am getting the exception:line 1:12 missing EOF at '3'
. If I remove eitherinteger1
orinteger2
from the grammar, the other one is working fine. Why so? Why they are not working together.I want
integer1
to reject0
and accept10000
. What changes should I do in the grammar?I removed
integer2
and modifiedinteger1
.integer1 @init {int N= 0;}: ((DIGIT { N++; } )+ { N <=4 }?) | '10000';
But if I give the input as set value1 10
, it is expecting three more zeros. It is not ready to accept anything which starts with '1', except for '10000'.
Thanks in advance :)
PS: I am using antlr-3.24
Your grammar looks a bit odd: it's far easier to handle the tokenizing of an integer value inside the lexer-part of your combined grammar and then check through a predicate in your parser rules if the value falls withing the bounds. Also, it's much easier to put white spaces on a different channel so that you don't have to litter your parser rules with SEPARATOR
tokens.
A little demo:
grammar K;
@parser::members {
private boolean inbounds(Token t, int min, int max) {
int n = Integer.parseInt(t.getText());
return n >= min && n <= max;
}
}
parse
: expr
;
expr
: Set Value1 integer1 {System.out.println("Value1 :: " + $integer1.text);}
| Set Value2 integer2 {System.out.println("Value2 :: " + $integer2.text);}
;
integer1
: Int {inbounds($Int, 1, 10000)}?
;
integer2
: Int {inbounds($Int, 0, 25999)}?
;
Value1 : 'value1';
Value2 : 'value2';
Set : 'set';
Int : '0'..'9'+;
Space : (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;};
and here's a small class to test it:
import org.antlr.runtime.*;
public class Main {
public static void main(String[] args) throws Exception {
String source = args[0];
ANTLRStringStream in = new ANTLRStringStream(source);
KLexer lexer = new KLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
KParser parser = new KParser(tokens);
parser.expr();
}
}
and here's a few test runs of the class above:
Valid
java -cp .:antlr-3.2.jar Main "set value1 667"
Value1 :: 667
java -cp .:antlr-3.2.jar Main "set value1 10000"
Value1 :: 10000
java -cp .:antlr-3.2.jar Main "set value2 10001"
Value2 :: 10001
Invalid
java -cp .:antlr-3.2.jar Main "set value1 10001"
line 0:-1 rule integer1 failed predicate: {Integer.parseInt($Int.text) >= 1 && Integer.parseInt($Int.text) <= 10000}?
Value1 :: null
java -cp .:antlr-3.2.jar Main "set value2 30000"
line 0:-1 rule integer2 failed predicate: {Integer.parseInt($Int.text) >= 0 && Integer.parseInt($Int.text) <= 25999}?
Value2 :: null
java -cp .:antlr-3.2.jar Main "set value1 0"
line 0:-1 rule integer1 failed predicate: {Integer.parseInt($Int.text) >= 1 && Integer.parseInt($Int.text) <= 10000}?
Value1 :: null
精彩评论