ウィキペディアのページによると、MUMPS には予約語がありません。
予約語: なし。MUMPS はコンテキストによってソース コードを解釈するため、予約語は必要ありません。言語コマンドの名前を変数として使用できます。
Lexer ルールのようなCommand_KILL
機能は、予約語とまったく同じです。これらは、入力"kill"
が検出されたときに他のトークンが生成されないように設計されています。そのため、たとえそれが識別子であることを意図していたとしても、トークン タイプCommand_KILL
は常に で生成されます。"kill"
必要に応じてコマンド レクサー ルールを保持することもできますが"kill"
、トークンだけでは何が参照されているかわからないため、ID のように扱う必要があります。
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
入力は ですCallExpr
。最初ID
はコマンド名で、2 番目ID
は通常の識別子です。
- 入力トークンが
ID ID Equal ID
の場合、入力は aSetExpr
です。1 つ目ID
はコマンド ("set"
またはそのようなもの)、2 つ目ID
はターゲット識別子、3 つ目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 のように扱わせ、パーサー ルールを使用しID
て、 がコマンドまたは識別子に基づいて参照されているかどうかを判断します。行全体のコンテキスト。