Rodrigo Zea
Rodrigo Zea

Reputation: 73

ANTLR grammar not picking the right option

So, I'm trying to assign a method value to a var in a test program, I'm using a Decaf grammar.

The grammar:

// Define decaf grammar
grammar Decaf;

// Reglas LEXER
// Definiciones base para letras y digitos
fragment LETTER: ('a'..'z'|'A'..'Z'|'_');
fragment DIGIT: '0'..'9';
// Las otras reglas de lexer de Decaf 
ID: LETTER (LETTER|DIGIT)*;
NUM: DIGIT(DIGIT)*;
CHAR: '\'' ( ~['\r\n\\] | '\\' ['\\] ) '\'';
WS : [ \t\r\n\f]+  -> channel(HIDDEN);

COMMENT
    : '/*' .*? '*/' -> channel(2)
    ;

LINE_COMMENT
    : '//' ~[\r\n]* -> channel(2)
    ;

// -----------------------------------------------------------------------------------------------------------------------------------------

// Reglas PARSER
program:'class' 'Program' '{' (declaration)* '}';
declaration
    : structDeclaration
    | varDeclaration
    | methodDeclaration
    ;
varDeclaration
    : varType ID ';' 
    | varType ID '[' NUM ']' ';' 
    ;
structDeclaration:'struct' ID '{' (varDeclaration)* '}' (';')?;
varType 
    : 'int' 
    | 'char' 
    | 'boolean' 
    | 'struct' ID 
    | structDeclaration 
    | 'void' 
    ;
methodDeclaration: methodType ID '(' (parameter (',' parameter)*)* ')' block;
methodType
    : 'int'
    | 'char'
    | 'boolean' 
    | 'void'
    ;
parameter
    : parameterType ID
    | parameterType ID '[' ']' 
    | 'void'
    ;
parameterType
    : 'int' 
    | 'char' 
    | 'boolean'
    ;
block: '{' (varDeclaration)* (statement)* '}';
statement
    : 'if' '(' expression ')' block ( 'else' block )? #stat_if
    | 'while' '('expression')' block #stat_else
    | 'return' expressionOom ';' #stat_return
    | methodCall ';' #stat_mcall
    | block #stat_block
    | location '=' expression #stat_assignment
    | (expression)? ';' #stat_line
    ;
expressionOom: expression |;
location: (ID|ID '[' expression ']') ('.' location)?;
expression 
    : location #expr_loc
    | methodCall #expr_mcall
    | literal #expr_literal
    | '-' expression #expr_minus // Unary Minus Operation
    | '!' expression #expr_not // Unary NOT Operation
    | '('expression')' #expr_parenthesis
    | expression arith_op_fifth expression #expr_arith5 // * / % << >>
    | expression arith_op_fourth expression #expr_arith4 // + -
    | expression arith_op_third expression #expr_arith3 // == != < <= > >=
    | expression arith_op_second expression #expr_arith2 // &&
    | expression arith_op_first expression #expr_arith1 // ||
    ;

methodCall: ID '(' arg1 ')';
// Puede ir algo que coincida con arg2 o nada, en caso de una llamada a metodo sin parametro
arg1: arg2 |;
// Expression y luego se utiliza * para permitir 0 o más parametros adicionales
arg2: (arg)(',' arg)*;
arg: expression; 

// Operaciones
// Divididas por nivel de precedencia
// Especificación de precedencia: https://anoopsarkar.github.io/compilers-class/decafspec.html
rel_op : '<' | '>' | '<=' | '>=' ;
eq_op : '==' | '!=' ;
arith_op_fifth: '*' | '/' | '%' | '<<' | '>>';
arith_op_fourth: '+' | '-';
arith_op_third: rel_op | eq_op;
arith_op_second: '&&';
arith_op_first: '||';

literal : int_literal | char_literal | bool_literal ;
int_literal : NUM ;
char_literal : '\'' CHAR '\'' ;
bool_literal : 'true' | 'false' ;

And the test program is as follows:

class Program
{

int factorial(int b)
{
    int n;
    n = 1;
    return n+2;
}

void main(void)
{
    int a;
    int b;
    b=0;
    a=factorial(b);
    factorial(b);
    return;
}

}

The parse tree for this program looks as following, at least for the part I'm interested which is a=factorial(b):

Tree

This tree is wrong, since it should look like location = expression -> methodCall

The following tree is how it looks on a friend's implementation, and it should sort of look like this if the grammar was correctly implemented:

TreeC

This is correctly implemented, or the result I need, since I want the tree to look like location = expression -> methodCall and not location = expression -> location. If I remove the parameter from a=factorial(b) and leave it as a=factorial(), it will be read correctly as a methodCall, so I'm not sure what I'm missing.

So my question is, I'm not sure where I'm messing up in the grammar, I guess it's either on location or expression, but I'm not sure how to adjust it to behave the way I want it to. I sort of just got the rules literally from the specification we were provided.

Upvotes: 1

Views: 41

Answers (1)

Bart Kiers
Bart Kiers

Reputation: 170158

In an ANTLR rule, alternatives are matches from top to bottom. So in your expression rule:

expression
    : location #expr_loc
    | methodCall #expr_mcall
    ...
    ;

the generated parser will try to match a location before it tries to match a methodCall. Try swapping those two around:

expression
    : methodCall #expr_mcall
    | location #expr_loc
    ...
    ;

Upvotes: 2

Related Questions