0
votes

My grammar looks like this (simplified to show the issue):

parse
    : block EOF
    ;

block
    : TYPE1 OPAR STRING CPAR type1_statement_block      
    | TYPE2 OPAR STRING CPAR type2_statement_block          
    ;

type1_statement_block
    : OBRACE function1+ CBRACE                  
    ;

function1
    : FUNCTIONNAME1 OPAR (parameter (',' parameter)*)? CPAR     
    ;

FUNCTIONNAME1 : 'COMMAND1';

type2_statement_block
    : OBRACE function2+ CBRACE                  
    ;

function2
    : FUNCTIONNAME2 OPAR (parameter (',' parameter)*)? CPAR     
    ;

FUNCTIONNAME2 : 'COMMAND1' | 'COMMAND2'

parameter
    : INT                               
    ;

OPAR : '(';
CPAR : ')';
OBRACE : '{';
CBRACE : '}';
TYPE1 : 'TYPE1';
TYPE2 : 'TYPE2';

INT
     : [0-9]+
     ;

STRING
 : '"' (~["\r\n] | '""')* '"'
 ;

SPACE
 : [ \t\r\n] -> skip
 ;

ErrChar
  : .
  ;

Parsing the following strings works fine:

TYPE1 ("abc") { COMMAND1(0) }
TYPE2 ("abc") { COMMAND2(0) }

However parsing the following string results in an error

TYPE2 ("abc") { COMMAND1(0) }

I get "mismatched input 'COMMAND1' expecting FUNCTIONNAME2"

How can I get this scenario to work? I.e. that both code block can contain the same function name?

1

1 Answers

0
votes

The basic issue is the lexer will always assign 'COMMAND1' to the token FUNCTIONNAME1, since that rule appears first and all other lexical requirements relative to the rule FUNCTIONNAME2 are equal. You could merge the FUNCTIONNAME1/2 rules, but that leads into the second issue with the grammar.

As written, the grammar is attempting to impose a semantic distinction between 'Type1' and 'Type2' statements that are otherwise syntactically identical. The better practice is to use the grammar to do syntactic analysis and defer semantic analysis for tree walks. The separation of concerns will make both easier.

block
    : ( cmd OPAR STRING CPAR statement_block )+
    ;

statement_block
    : OBRACE function+ CBRACE
    ;

function
    : FUNCTIONNAME OPAR (parameter (',' parameter)*)? CPAR     
    ;

cmd : 'TYPE1' | 'TYPE2' ;
FUNCTIONNAME : 'COMMAND1' | 'COMMAND2' ;