2

フォームの可能なデザインの言語の ためにCOS別名MUMPSの構文強調表示を実装する必要があります

new (new,set,kill)
set kill=new

ここで、「new」と「set」はコマンドであり、変数でもあります

grammar cos;

Command_KILL            :( ('k'|'K') | ( ('k'|'K')('i'|'I')('l'|'L')('l'|'L') ) ); 
Command_NEW             :( ('n'|'N') | ( ('n'|'N')('e'|'E')('w'|'W') ) ); 
Command_SET             :( ('s'|'S') | ( ('s'|'S')('e'|'E')('t'|'T') ) );


INT : [0-9]+;
ID : [a-zA-Z][a-zA-Z0-9]*;
Space: ' ';
Equal: '=';

newCommand
    :   Command_NEW Space ID
    ;
setCommand
    :   Command_SET Space ID Space*  Equal Space* INT
    ; 

コマンドとしての名前のようなID(NEW、SETなど)の場合、問題があります

4

1 に答える 1

5

ウィキペディアのページによると、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 構文は、これよりも処理が難しい場合がありますが、一般的なアプローチは同じです。レクサーにコマンドと識別子をIDs のように扱わせ、パーサー ルールを使用しIDて、 がコマンドまたは識別子に基づいて参照されているかどうかを判断します。行全体のコンテキスト。

于 2012-12-23T21:35:06.120 に答える