0

複雑な文法を書きました。文法は以下で見ることができます:

grammar i;

options {
output=AST;
}

@header {
package com.data;
}

operatorLogic   : 'AND' | 'OR';
value       : STRING;
query       : (select)*;
select      : 'SELECT'^ functions 'FROM table' filters?';';
operator    : '=' | '!=' | '<' | '>' | '<=' | '>=';
filters : 'WHERE'^ conditions;
conditions  : (members (operatorLogic members)*);
members : STRING operator value;
functions   : '*';
STRING  : ('a'..'z'|'A'..'Z')+;
WS      : (' '|'\t'|'\f'|'\n'|'\r')+ {skip();}; // handle white space between keywords

出力は AST を使用して行われます。上記はほんの一例です。しかし、私はいくつかの大きな文法を開発しており、これにアプローチする方法についてアドバイスが必要です.

たとえば、上記の文法に従って、次のように生成できます。

SELECT * from table;
SELECT * from table WHERE name = i AND name = j;

このクエリはさらに複雑になる可能性があります。Java コードに AST を実装したので、ツリーを取り戻すことができます。文法とロジックを分離したかったので、それらはまとまりがあります。したがって、AST が最適なアプローチでした。

ユーザーはクエリを文字列として入力し、私のコードは可能な限り最善の方法でクエリを処理する必要があります。ご覧のとおり、関数パーサーは現在 * であり、これはすべてを選択することを意味します。将来的には、これは他のものを含むように拡張される可能性があります。

私のコードはこれをどのように処理できますか? 最善のアプローチは何ですか?

私はこのようなことができます:

String input = "SELECT * from table;";
if(input.startsWith("SELECT")) {
    select();
}

ご覧のとおり、オプションのフィルターも処理する必要があるため、このアプローチはより複雑です。AND と OR である operatorLogic も実行する必要があります。

最善の方法は何ですか?オンラインで調べましたが、これを処理する方法の例が見つかりませんでした。

例を挙げることはできますか?

編集:

String input = "SELECT * FROM table;";
if(input.startsWith("SELECT")) {
   select();
}
else if(input.startsWith("SELECT *")) {
  findAll();
}
4

1 に答える 1

0

複数の開始ルール (「SELECT ...」、「UPDATE ...」など) を処理する最も簡単な方法は、単一のトップレベルの開始ルールで ANTLR 文法に作業を任せることです。あなたはすでにそれをほとんど持っているので、あなたが持っているものを更新するだけの問題です。

現在、文法は 1 つのコマンド タイプの入力 ("SELECT...") に制限されています。

query       : (select)*; //query only handles "select" because that's all there is.
select      : 'SELECT'^ functions 'FROM table' filters?';';

が開始ルールである場合、追加のトップレベル入力を受け入れるには、以上を受け入れるようqueryに定義する必要があります。queryselect

query       : (select | update)*; //query now handles any number of "select" or "update" rules, in any order.
select      : 'SELECT'^ functions 'FROM table' filters?';';
update      : 'UPDATE'^ ';';  //simple example of an update rule

これで、ルールは、、またはqueryなどの入力を処理できるようになりました。新しい最上位ルールが追加されたら、更新してその新しいルールをテストします。この方法では、Java コードで入力をテストする必要はありません。ルールを呼び出すだけで、残りはパーサーに処理させます。SELECT * FROM table;UPDATE;SELECT * FROM table; UPDATE;queryquery

入力から 1 つのタイプの入力のみを処理する場合は、次のqueryように定義します。

query       : select*  //read any number of selects, but no updates
            | update*  //read any number of updates, but no selects
            ;

ルールqueryは引き続きと を処理しますが、 のようなコマンドの組み合わせは処理SELECT * FROM table;しません。UPDATE;SELECT * FROM table; UPDATE;


query_returnを呼び出して AST ツリーを取得するqueryと、文字列ではなく、Java コードで処理できる意味のあるものが得られます。そのツリーは、パーサーが処理したすべての入力を表します。

次のように、ツリーの子をウォークスルーできます。

iParser.query_return r = parser.query();
CommonTree t = (CommonTree) r.getTree();

for (int i = 0, count = t.getChildCount(); i < count; ++i) {
    CommonTree child = (CommonTree) t.getChild(i);
    System.out.println("child type: " + child.getType());
    System.out.println("child text: " + child.getText());
    System.out.println("------");
}

AST ツリー全体をたどるのは、getChild(...)すべての親ノードを再帰的に呼び出すことです (上記の例では、最上位の子ノードのみを見ています)。


代替の処理*は、定義した他の代替と同じです。拡張したいルールで代替を定義するだけです。以上を受け入れる場合は、functions以上を受け入れるよう*に定義functionsします*。;)

次に例を示します。

functions: '*'      //"all"
         | STRING   //some id
         ;

これで、パーサーはSELECT * FROM table;とを受け入れることができSELECT foobar FROM table;ます。

Java コードでは、入力文字列を調べる必要がないことに注意してください。そのような誘惑に駆られたときはいつでも、代わりに文法を調べさせる方法を探してください。次に、Java コードは、AST ツリーの出力を調べて、必要なものを探します。

于 2012-11-28T15:41:29.040 に答える