我正在尝试创建一个接受两个整数范围的语法:
从1
到10000
的整数1
和,0
到25999
这是我写的:
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);
我面临以下问题:
当我将输入设为:set value1 3
时,我得到一个例外:line 1:11 required (...)+ loop did not match anything at input '3'
。另一方面,如果我将输入作为set value1 8
,则其工作正常。为什么呢?
当我将输入设为:set value2 832
时,我收到了异常:line 1:12 missing EOF at '3'
。
如果我从语法中删除integer1
或integer2
,另一个工作正常。为什么这样?为什么他们不合作。
我希望integer1
拒绝0
并接受10000
。我应该在语法上做些什么改变?
我删除了integer2
并修改了integer1
。
integer1 @init {int N= 0;}: ((DIGIT { N++; } )+ { N <=4 }?) | '10000';
但如果我将输入设为set value1 10
,则需要三个零。除了'10000'之外,它还没有准备接受任何以'1'开头的东西。
提前致谢:)
PS:我使用的是antlr-3.24
答案 0 :(得分:2)
你的语法看起来有点奇怪:在组合语法的词法分析器部分中处理整数值的标记化要容易得多,然后在解析器规则中检查谓词是否值与边界一致。此外,在不同的通道上放置空格要容易得多,这样您就不必使用SEPARATOR
标记丢弃解析器规则。
一个小小的演示:
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;};
这是一个小类来测试它:
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();
}
}
以上是上述课程的一些测试:
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
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