最近、次のような式の文法を作成する必要がありました。
rule1 & rule2 & rule3 => produces binary tree
(AndNode (AndNode RuleNode(rule1) RuleNode(rule2)) RuleNode(rule3))
rule1 | (rule2 & rule3) => produces binary tree
(OrNode RuleNode(rule1) (AndNode RuleNode(rule2) RuleNode(rule3)))
RuleNode、AndNode、および OrNode は、後で式全体が評価されるときに使用されるクラスです。rule1、rule2 などは単に私のドメインの概念であり、パーサーまたはレクサー ルールとは何の関係もありません。
文法は次のとおりです。
RULE : ('a'..'z'|'A'..'Z')('a'..'z'|'A'..'Z'|'0'..'9')*;
QUOTE : '\'';
PARAM : QUOTE ( ~('\'') )* QUOTE;
LPAREN : '(';
RPAREN : ')';
DELIMITER : ',';
AND : '&';
OR : '|';
WS : (' ' | '\t')+ {$channel = HIDDEN;};
params : LPAREN! PARAM (DELIMITER! PARAM)* RPAREN!;
rule : RULE<RuleNode>^ params?;
expr : andexpr;
andexpr : orexpr (AND<AndNode>^ orexpr)*;
orexpr : atom (OR<OrNode>^ atom)*;
atom : rule | LPAREN! expr RPAREN!;
parse : expr;
AND 演算子をデフォルトのものにする必要があるまでは、すべて問題なく機能していたので、次のような例を書くことができました。
rule1 rule2 rule3
rule1 | (rule2 rule3)
私は別の方法で anexpr ルールを指定しようとしました:
1)
andexpr : orexpr+ -> (^(AND<AndNode> orexpr))+;
結果 - バイナリ ツリーではなく、AndNode をルートとしても持たないツリーを生成します。
(nil RuleNode(rule1) RuleNode(rule2) RuleNode(rule3))
2)
ANTLR ツリー構築(演算子セクション)の最初の例に基づいて、次のことも試しました。
andexpr : (a=orexpr->$a) (b=orexpr -> ^(AND<AndNode> $andexpr $b))*;
結果 - 1) と同じフラット ツリー
2) からカスタム ノードを削除した場合:
andexpr : (a=orexpr->$a) (b=orexpr -> ^(AND $andexpr $b))*;
次に、パーサーはバイナリ ツリーを生成します。
(AND (AND RuleNode(rule1) RuleNode(rule2)) RuleNode(rule3))
残念ながら、AND は私のカスタム AndNode ではありません。AndNode の構築と関係があると思われます - 元の例では「&」が必要で、コンストラクターは
AndNode(Token token) { this.token = token; }
しかし、オプションの「&」を使用した文法の場合、新しいものを実装する必要がありました
AndNode(int type) { }
トークンをパラメーターとして受け入れなくなりました。
この場合のルールを書くのを手伝ってください。そうすれば、バイナリ ツリーとカスタム ノードの両方が得られます。私は立ち往生しています。