简而言之:如何在ANTLR中实现动态变量?
我带着一个基本的ANTLR问题再次来找你
我有这个语法:
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();} ;
到目前为止,它所做的(或应该做的)是内置的“println”功能,可以完全按照您的想法进行操作,还有一个“defun”规则来定义变量。
当在字符串或整数上调用“defun”时,该值将被放入“内存”HashMap中,第一个参数是变量的名称,第二个参数是其值。
当在原子上调用println时,它应该显示原子的值。原子可以是字符串或整数。它从内存中获取其值并返回它。例如:
defun greeting "Hello world!"
println greeting
但是当我运行此代码时,我收到此错误:
line 3:8 no viable alternative at input 'greeting'
null
注意:当我这样做时会出现此输出:
println "greeting"
输出:
undefined variable "greeting"null
有谁知道为什么会这样?对不起,如果我不清楚,我不明白这一点。
答案 0 :(得分:1)
defun greeting "Hello world!" println greeting
但是当我运行此代码时,我收到此错误:
第3:8行输入'问候'时没有可行的选择
因为输入"greeting"
被标记为VAR
而VAR
不是atom
。因此输入defun greeting "Hello world!"
与defun
规则的2 nd 备选方式正确匹配:
defun
: 'defun' VAR INT // 1st alternative
| 'defun' VAR STRING_LITERAL // 2nd alternative
;
但输入println "greeting"
无法与println
规则匹配:
println
: 'println' atom
;
您必须意识到词法分析器不会根据解析器在特定时间尝试匹配的内容生成令牌。输入"greeting"
将始终标记为VAR
,而不是ID
规则。
您需要做的是从词法分析器中删除ID
规则,并在解析器规则中将ID
替换为VAR
。