leaf
leaf

Reputation: 95

ANTLR Variable Troubles

In short: how do I implement dynamic variables in ANTLR?
I come to you again with a basic ANTLR question.
I have this grammar:

grammar Amethyst;

options {
    language = Java;
}

@header {
    package org.omer.amethyst.generated;
    import java.util.HashMap;
}

@lexer::header {
    package org.omer.amethyst.generated;
}

@members {
    HashMap memory = new HashMap();
}

begin: expr;

expr: (defun | println)*
;

println:
    'println' atom {System.out.println($atom.value);}
;

defun:
    'defun' VAR INT {memory.put($VAR.text, Integer.parseInt($INT.text));}
    | 'defun' VAR STRING_LITERAL {memory.put($VAR.text, $STRING_LITERAL.text);}
;

atom returns [Object value]:
    INT {$value = Integer.parseInt($INT.text);}

    |   ID
    {
    Object v = memory.get($ID.text);
    if (v != null) $value = v;
    else System.err.println("undefined variable " + $ID.text);
    }

| STRING_LITERAL
  {
    String v = (String) memory.get($STRING_LITERAL.text);
    if (v != null) $value = String.valueOf(v);
    else System.err.println("undefined variable " + $STRING_LITERAL.text);
  }
;

INT: '0'..'9'+ ;
STRING_LITERAL: '"' .* '"';

VAR: ('a'..'z'|'A'..'Z')('a'..'z'|'A'..'Z'|'0'..'9')* ;
ID: ('a'..'z'|'A'..'Z'|'0'..'9')+ ;
LETTER: ('a..z'|'A'..'Z')+ ;
WS: (' '|'\t'|'\n'|'\r')+ {skip();} ;

What it does (or should do), so far, is have a built-in "println" function to do exactly what you think it does, and a "defun" rule to define variables.
When "defun" is called on either a string or integer, the value is put into the "memory" HashMap with the first parameter being the variable's name and the second being its value.
When println is called on an atom, it should display the atom's value. The atom can be either a string or integer. It gets its value from memory and returns it. So for example:

defun greeting "Hello world!"

println greeting

But when I run this code, I get this error:

line 3:8 no viable alternative at input 'greeting'
null

NOTE: This output comes when I do:

println "greeting"

Output:

undefined variable "greeting"null

Does anyone know why this is so? Sorry if I'm not being clear, I don't understand most of this.

Upvotes: 1

Views: 621

Answers (1)

Bart Kiers
Bart Kiers

Reputation: 170148

defun greeting "Hello world!"

println greeting

But when I run this code, I get this error:

line 3:8 no viable alternative at input 'greeting'

Because the input "greeting" is being tokenized as a VAR and a VAR is no atom. So the input defun greeting "Hello world!" is properly matched by the 2nd alternative of the defun rule:

defun
 : 'defun' VAR INT               // 1st alternative
 | 'defun' VAR STRING_LITERAL    // 2nd alternative
 ;

but the input println "greeting" cannot be matched by the println rule:

println
 : 'println' atom
 ;

You must realize that the lexer does not produce tokens based on what the parser tries to match at a particular time. The input "greeting" will always be tokenized as a VAR, never as an ID rule.

What you need to do is remove the ID rule from the lexer, and replace ID with VAR inside your parser rules.

Upvotes: 1

Related Questions