0

OK、私はここに質問する前にすべてを試しましたが、これは私を夢中にさせています.

カスタム NoSQL データベースでドキュメントをクエリするための単純な言語を作成しています。サンプル クエリは次のようになります。

VALUE("price: " SUM($price) " Average: " AVG($price)).MATCH($price > 5 OR $price < 100 OR $cost > 30)

これは、SQL と MONGODB の集計クエリの中間にあるものです (VALUE のパラメーターは文字列と集計を連結し、一致する場合はブール値の一致があります)。

問題は、これを解析すると、行 1:69 無関係な入力 ' ' が得られ、COMPARATOR を期待し、その後に行 1:69 実行可能な代替手段が入力 ' ' に続かないことです。これは行 80 ~ 82 および行 95 ~ 97 についても同じです。

ご覧のとおり、問題はコンパレーター ('<'、'>' など) の周辺にあります。私は自分の文法で競合やあいまいさを探していましたが、運がありませんでした (確かに、最近 ANTLR を始めたばかりです)。

これが私の文法です:

// Define a grammar called Capsa
grammar Capsa;

eval : VARIABLE | function;

function : functionValue;

functionValue : 'VALUE(' (STRING ' ')* functionNumber (' '(STRING|functionNumber))* ')' (match)?;

match : '.MATCH(' booleanexpression ')';

functionNumber: FUNCTIONNUMBERTYPE'(' value ')';
FUNCTIONNUMBERTYPE: 'SUM'|'AVG'|'MAX'|'MIN'|'FIRST'|'LAST' ;

value
  : VARIABLE          #Var
  | REALNUMBER        #Literal
  | STRING            #Literal
  | calcexpression    #Calc
  | booleanValue      #Literal;

/*
** Boolean stuff
*/
AND : '&&' | ' AND ';
OR : '||' | ' OR ';
NOT : '!' | ' NOT ';

booleanexpression : '(' booleanexpression ')'   #BooleanParentExpression
  | booleanexpression AND booleanexpression     #AndExpression
  | booleanexpression OR booleanexpression      #OrExpression
  | NOT booleanexpression                       #NotExpression
  | (value COMPARATOR value)                    #Comparison
  | booleanValue                                #ComparisonLogic;

booleanValue
  : 'true'
  | 'false';
/*
** Comparators
*/
fragment GT : '>';
fragment GTE : '>=';
fragment LT : '<';
fragment LTE : '<=';
fragment EQ : '=';
fragment EX : ':' | '==';
COMPARATOR : GT | GTE | LT | LTE | EQ | EX;
/*
** End Comparators
*/

/*
** End Boolean stuff
*/

/*
** Calc
*/
calcexpression
  : '(' calcexpression ')'                    #CalcParentExpression
  | calcexpression ('*'|'/') calcexpression   #MultOrDiv
  | calcexpression ('+'|'-') calcexpression   #AddOrSub
  | VARIABLE                                  #CalcID
  | REALNUMBER                                #CalcNumber;

/*
** End Calc
*/

fragment ID : [a-zA-Z_][a-zA-Z0-9_]+ ;
VARIABLE : '$'ID;
STRING : '"' (ESC | ~["\\])* '"' ;
fragment CONSTANT : STRING | REALNUMBER;

fragment ESC : '\\' (["\\/bfnrt] | UNICODE) ;
fragment UNICODE : 'u' HEX HEX HEX HEX ;
fragment HEX : [0-9a-fA-F] ;
fragment INT : [0-9]+ ; // no leading zeros
fragment EXP : [Ee] [+\-]? INT ; // \- since - means "range" inside [...]

REALNUMBER
: '-'? INT '.' INT EXP? // 1.35, 1.35E-9, 0.3, -4.5
| '-'? INT EXP // 1e10 -3e4
| '-'? INT // -3, 45
;

WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines

これまでに見つけた唯一の解決策は、次の行を変更することです。

  | (value COMPARATOR value)                    #Comparison

為に:

  | (value ' '* COMPARATOR ' '* value)                    #Comparison

しかし、私にとっては解決策というよりもハックのように見えます...

私は何が欠けていますか?私はそれがかなりばかげたことになると確信しています...しかし、私はこれに運がなくて一日を過ごしました...

ボーナストラック:

(これはそれほど重要ではありません) また、ブールクエリ (5+3 > 6 または $variable+10 < 100 など) で calc 式を許可しようとしていますが、この場合、コンパレータ ('> '、'<'、...)、演算子 ('+'、'-'、...) が存在する場合。

4

1 に答える 1

1

空白を省略しているのに、なぜ' '文法規則で一致するのfunctionValueですか?

この部分を削除すると、計算式の正しい解析を含む完全に機能する文法が得られます(指定された例で)。

ルールは次のとおりです。

functionValue : 'VALUE(' (STRING)* functionNumber ((STRING|functionNumber))* ')' (match)?;

ANTLR4 を楽しんでください。これは非常に優れたツールです。

PS: パーサー文法とレクサー文法を分割することを考えてみてください。読みやすい 2 つのファイルが得られます。

それらのヘッダーは

CapsaParser.g4

parser grammar CapsaParser;
options { tokenVocab = CapsaLexer; }

CapsaLexer.g4

lexer grammar CapsaLexer;
于 2013-10-07T13:27:46.273 に答える