开发者

Problem in making the grammar accept different range of numeric values

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:

  1. 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 as set value1 8, its working fine. Why?

  2. When I give the input as: set value2 832 I am getting the exception: line 1:12 missing EOF at '3'. If I remove either integer1 or integer2 from the grammar, the other one is working fine. Why so? Why they are not working together.

  3. I want integer1 to reject 0 and accept 10000. What changes should I do in the grammar?

  4. I removed integer2 and modified integer1.

    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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜