2
votes

I wanted to know what is the right way to apply the parsing rules for multiple lines using ANTLR. I am using the below rule which works fine for single line statements. I wanted to just repeat this over next lines:

    grammar Condition;


/* Parser Rules */

condition : (expr+)? EOF;
expr
    : expr And expr         # andExpr
    | expr Or expr          # orExpr
    | LPar expr RPar        # parExpr
    | prop MIN Numerical expr       # eqExpr
    | prop some expr        # someExpr
    | prop only expr        # onlyExpr
    | prop value dataValue      # valueExpr
    | id                    # idExpr
    | not id                    # idExpr
    ;

id : Identifier;
prop:Identifier;
dataValue:Identifier;

/* Lexical Tokens */

And : 'AND';
Or : 'OR';
LPar : '(';
RPar : ')';
Equals : '=';
some : 'some';
only : 'only';
MIN : 'MIN';
value:'value';
not:'not';
NEWLINE: ('\n') { skip(); };

Numerical : [1-9] [0-9]*;
Data
    : [true]
    | [false]
    | [A]
    | [B]
    | [C]
    | [D]
    ;

// Using generic identifier tokens so that better warnings can be given in later passes.
Identifier : [a-zA-Z_] [a-zA-Z0-9_]*;

// Skip parsing of whitespace but save on hidden channel to enable retrieval of original string.
WhiteSpace : [ \t\r\n]+ -> channel(HIDDEN);

// Invalid character rule is used so that the lexer pass never fails.
InvalidChar : .;

The above grammar gives correct results while testing, but when I try to use visitor it consume each token, it throws the below error :

line 2:0 extraneous input 'SafetyGoal' expecting {, 'AND', 'OR'}

Any suggestions?

EDIT Below is the code I am using to read the input file and call the visitor code:

Stream<String> stream = Files.lines( Paths.get("C:\\test\\RulesTest.txt"), StandardCharsets.UTF_8);
stream.forEach(s -> contentBuilder.append(s).append("\n"));
String input=contentBuilder.toString();
InputStream inStream = new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8));
org.antlr.v4.runtime.ANTLRInputStream in=new org.antlr.v4.runtime.ANTLRInputStream(inStream);
System.out.println("These are the lines:"+contentBuilder);
ConditionLexer lexer=new ConditionLexer(in);
org.antlr.v4.runtime.CommonTokenStream tokens= new org.antlr.v4.runtime.CommonTokenStream(lexer);
ConditionParser parser=new ConditionParser(tokens);
ParseTree tree=parser.expr();
MyVisitor vis=new MyVisitor();
vis.visit(tree);

The MyVisitor basically contains the same code as generated by the ANTLR, where I am storing the results as it parses.

2
What is the input?Bart Kiers
Input contains basically two lines, as of testing which are of the form as below(FSR AND testedBy some (testResult value true)) and next line SafetyGoal AND (fulfills some (not NR) OR fulfilledBy some NR)visraj
The rule you're invoking is condition, right? Btw: These are (probably) unrelated to your problem, but: A better way to write (expr+)? would be expr*. You're handling newlines twice (once in the NEWLINE and once in the WhiteSpace rule, so the NEWLINE rule is redundant. Oh and [true] matches a t, r, u or e, not the string "true".sepp2k
Your input parses without errors for me if I run grun Condition condition after compiling your grammar without any changes. So please post an MCVE.sepp2k

2 Answers

1
votes

Your Data rule is wrong: [true] matches a single character (t, r, u or e). Do this instead:

Data
    : 'true'
    | 'false'
    | [A]
    | [B]
    | [C]
    | [D]
    ;

And testResult value true is not matched by your alternative prop value dataValue because dataValue looks like this:

dataValue : Identifier;

where it should look like this (I'm guessing):

dataValue : Identifier | Data;

When I change your grammar as indicated above and parse the input:

(FSR AND testedBy some (testResult value true)) 
SafetyGoal AND (fulfills some (not NR) OR fulfilledBy some NR)

I get the following parse tree:

enter image description here

1
votes
ParseTree tree=parser.expr();

You're invoking the expr rule, which only matches a single expression. Your condition rule is the one that matches multiple expressions, so you should invoke that one instead.