3

I am writing a parser for prolog, the following is part of source. "arg_term" is very similar to "term", but it can not match ',' expression, because I need to count the number of arguments. "arg_item" will need match ',' expression, so I create two similar rules. I tried use semantic predicates, but Antlr 4 reported compiling error. Now it seems not to support semantic predicates in a direct left-recursive rule. The implementation looks clumsy. Can anyone provide a better solution?

I am not very familiar with Antlr and compiller implementation. In prolog, users can define their own operators and related precendence. How to cope with such cases? Now I just ignore their precedence and put them in the end of the "term" rule.

arguments returns [ int argc ]  //return argument number
    : 
    arg {$argc = 1; } (',' arg {$argc = $argc + 1;} )*  
    ;

arg :
    arg_term
    | '(' arg_item  ')'
    | '{' arg_item '}' 
    ;

arg_item:
     ':-' term
      | term ':-' term
      | term
        ;

arg_term :
    simple_term
    |'(' arg_term ')'
    | ('+'|'-') arg_term    //here '+, -' denotes number's sign.
    | arg_term ('**'|'^'|'isa'|'has')  arg_term        
    | arg_term ('//' | 'mod' | 'rem'  | '<<' | '>>' |'*' |'/')  arg_term     
    | arg_term ('+'|'-'|'#')  arg_term           
    | arg_term ':' arg_term                       
    | arg_term (OP_XFY_700|'<'|'>'|'=')  arg_term
    | '\\+' arg_term        
    | arg_term '->' arg_term 
    | arg_term ';' arg_term 
    | OP_FX_1150 arg_term
    | arg_term user_op arg_term 
    ;

term
    : 
    simple_term
    |'(' term ')'
    | ('+'|'-') term    
    | term ('**'|'^'|'isa'|'has')  term        
    | term ('//' | 'mod' | 'rem'  | '<<' | '>>' |'*' |'/')  term     
    | term ('+'|'-'|'#')  term           
    | term ':' term                      
    | term (OP_XFY_700|'<'|'>'|'=')  term
    | '\\+' term        
    | term ',' term     
    | term '->' term 
    | term ';' term 
    | OP_FX_1150 term
    | term user_op term 
    ;
frankli22586
  • 710
  • 6
  • 19

1 Answers1

0

1) Semantic predicates in ANTLR4 have changes since v3 (see here).

2) To clean up your arg_term and term productions, try something similar to this grammar snippet:

grammar Prolog;

...

argTerm: term (',' term)*;

term :
    simpleTerm
    |'(' term ')'
    | ('+'|'-') term
    | term ('**'|'^'|'isa'|'has')  term        
    | term ('//' | 'mod' | 'rem'  | '<<' | '>>' |'*' |'/') term     
    | term ('+'|'-'|'#') term           
    | term ':' term                       
    | term (OP_XFY_700|'<'|'>'|'=')  term
    | '\\+' term        
    | term '->' term 
    | term ';' term 
    | OP_FX_1150 term
    | term user_op term 
    ;

...

3) Rather than embedding that Java code in your grammar, use the ANTLR4 generated ParseTreeVisitor.

You can generate a PrologBaseVisitor by using the -visitor argument from the command line:

org.antlr.v4.Tool -visitor Prolog.g4

This is an example of an implementation extending the generated PrologBaseVisitor which would count your arguments:

public class ProglogArgCountVis extends PrologBaseVisitor<Integer> {

    // By default, all productions will return 0.
    @Override
    protected Integer defaultResult() {
         return 0;
    }

    // Return the size of ctx.term(), which is a list of 
    // TermContexts... see generated parser code.
    @Override
    public Integer visitArgTermContext(ArgTermContext ctx) {
         return ctx.term().size();
    }

}

Using this visitor would look something like this:

PrologParser p;

....

Integer argCount = new PrologArgCountVis().visit(p.argTerm());

User defined precedence would be interesting to implement. I think the best way to handle this situation would be to define another PrologBaseVisitor, have it check the precedence of every operator it visits and evaluate accordingly.

Community
  • 1
  • 1
hendryau
  • 426
  • 3
  • 14