根据维基百科页面, MUMPS 没有保留字:
保留字:无。由于 MUMPS 通过上下文解释源代码,因此不需要保留字。您可以使用语言命令的名称作为变量。
Lexer 规则之类的Command_KILL
功能与保留字完全一样:它们旨在确保在"kill"
遇到输入时不会生成其他标记。所以令牌类型Command_KILL
总是会在 上产生"kill"
,即使它是一个标识符。如果需要,您可以保留命令词法分析器规则,但您也必须将它们视为 ID,因为您只是不知道仅"kill"
基于令牌所指的是什么。
在 ANTLR 中实现 MUMPS 意味着关注令牌使用和上下文而不是令牌类型。考虑这个语法:
grammar Example;
document : (expr (EOL|EOF))+;
expr : command=ID Space+ value (Space* COMMA Space* value)* #CallExpr
| command=ID Space+ name=ID Space* Equal Space* value #SetExpr
;
value : ID | INT;
INT : [0-9]+;
ID : [a-zA-Z][a-zA-Z0-9]*;
Space : ' ';
Equal : '=';
EOL : [\r\n]+;
COMMA : ',';
解析器规则expr
知道ID
令牌何时是基于整行布局的命令。
- 如果输入标记是
ID ID
,那么输入是 a CallExpr
:第一个ID
是命令名称,第二个ID
是常规标识符。
- 如果输入标记是
ID ID Equal ID
,那么输入是 a SetExpr
:第一个ID
是命令("set"
或者类似的东西),第二个ID
是目标标识符,第三个ID
是源标识符。
这是一个 Java 测试应用程序,后跟一个类似于您的问题中提到的测试用例。
import java.util.List;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
public class ExampleTest {
public static void main(String[] args) {
ANTLRInputStream input = new ANTLRInputStream(
"new new, set, kill\nset kill = new");
ExampleLexer lexer = new ExampleLexer(input);
ExampleParser parser = new ExampleParser(new CommonTokenStream(lexer));
parser.addParseListener(new ExampleBaseListener() {
@Override
public void exitCallExpr(ExampleParser.CallExprContext ctx) {
System.out.println("Call:");
System.out.printf("\tcommand = %s%n", ctx.command.getText());
List<ExampleParser.ValueContext> values = ctx.value();
if (values != null) {
for (int i = 0, count = values.size(); i < count; ++i) {
ExampleParser.ValueContext value = values.get(i);
System.out.printf("\targ[%d] = %s%n", i,
value.getText());
}
}
}
@Override
public void exitSetExpr(ExampleParser.SetExprContext ctx) {
System.out.println("Set:");
System.out.printf("\tcommand = %s%n", ctx.command.getText());
System.out.printf("\tname = %s%n", ctx.name.getText());
System.out.printf("\tvalue = %s%n", ctx.value().getText());
}
});
parser.document();
}
}
输入
new new, set, kill
set kill = new
输出
Call:
command = new
arg[0] = new
arg[1] = set
arg[2] = kill
Set:
command = set
name = kill
value = new
由调用代码决定命令在给定上下文中是否有效。由于 MUMPS 对命令和标识符的松散方法,解析器无法合理处理此问题。但这并不像听起来那么糟糕:您将知道哪些命令的功能类似于调用,哪些功能类似于集合,因此您将能够测试来自Listener
ANTLR 生成的输入。例如,在上面的代码中,很容易测试“set”是否是传递给exitSetExpr
.
一些 MUMPS 语法可能比这更难处理,但一般方法是相同的:让词法分析器像ID
s 一样处理命令和标识符,并使用解析器规则来确定 anID
是指命令还是基于整行的上下文。