ウィキペディアのページによると、MUMPSには予約語がありません。
予約語:なし。MUMPSはソースコードをコンテキストごとに解釈するため、予約語は必要ありません。言語コマンドの名前を変数として使用できます。
レクサールールは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
、の場合、入力はSetExpr
次のようになります。最初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
て、がコマンドを参照するか、行全体のコンテキスト。