思い出した様に2WaySqlParser
大切な何かが弾けた途端に、カオスを受け入れる事が出来た。
つまり、こういう事。
grammar TwoWaySql; options { output = AST; ASTLabelType = CommonTree; //superClass = Parser; } @header { import java.util.LinkedList; } @lexer::header { } @lexer::members { boolean inComment = false; boolean inLineComment = false; } twowaySQL returns[TwoWayQuery query] @init { $query = new TwoWayQuery(); } @after { $query.freeze(); } : nodelist EOF { $query.setChildren($nodelist.list); $query.update($nodelist.tree); } ; nodelist returns[LinkedList<QueryNode> list] @init{ $list = new LinkedList<QueryNode>(); } : (comment {$list.add($comment.node);} | inbind {$list.add($inbind.node);} | txt {$list.add($txt.node);} )+ ; charactors : (IDENT| SYMBOLS | QUOTED | SYM_BIND | SYM_C | SYM_LP | SYM_RP)+ ; txt returns[TxtNode node] @init { $node = new TxtNode(); } @after { $node.freeze(); } : charactors { $node.update($charactors.tree); } ; // $<comment comment returns[QueryNode node]: begincomment {$node = $begincomment.node;} | ifcomment {$node = $ifcomment.node;} | bindcomment {$node = $bindcomment.node;} | blockcomment {$node = $blockcomment.node;} | linecomment {$node = $linecomment.node;} ; blockcomment returns[TxtNode node] @init { $node = new TxtNode(); } @after { $node.freeze(); } : C_ST charactors C_ED { $node.update($C_ST);$node.update($C_ED); } ; linecomment returns[TxtNode node] @init { $node = new TxtNode(); } @after { $node.freeze(); } : C_LN_ST charactors C_LN_ED { $node.update($C_LN_ST);$node.update($C_LN_ED); } ; ifcomment returns[IfNode node] @init { $node = new IfNode(); } @after { $node.freeze(); } : (C_ST IF expression C_ED { $node.setExpression($expression.node); } nodelist { $node.setChildren($nodelist.list);} (elseifnode { $node.addElseIf($elseifnode.node); })* (elsenode { $node.setElse($elsenode.list); })? endcomment ) { $node.update($C_ST); $node.update($endcomment.tree); } ; elseifnode returns[IfNode node] @init { $node = new IfNode(); } @after { $node.freeze(); } : elseifcomment nodelist { $node.update($elseifcomment.tree); $node.setExpression($elseifcomment.node); $node.setChildren($nodelist.list); $node.update($nodelist.tree); } ; elseifcomment returns[ExpressionNode node] : (elseifblockcomment {$node = $elseifblockcomment.node;} | elseiflinecomment {$node = $elseiflinecomment.node;} ) ; elseifblockcomment returns[ExpressionNode node] : C_ST ELSEIF expression C_ED { $node = $expression.node; } ; elseiflinecomment returns[ExpressionNode node] : C_LN_ST ELSEIF expression C_LN_ED { $node = $expression.node; } ; elsenode returns[LinkedList<QueryNode> list] : elsecomment nodelist { $list = $nodelist.list; } ; elsecomment : (C_ST ELSE C_ED | C_LN_ST ELSE C_LN_ED) ; expression returns[ExpressionNode node] @init { $node = new ExpressionNode(); } @after { $node.freeze(); } : charactors {$node.update($charactors.tree);} ; begincomment returns[BeginNode node] @init { $node = new BeginNode(); } @after { $node.freeze(); } : ( (C_ST BEGIN C_ED {$node.update($C_ST);} | C_LN_ST BEGIN C_LN_ED {$node.update($C_LN_ST);} ) nodelist endcomment ) { $node.setChildren($nodelist.list); $node.update($endcomment.tree); } ; endcomment : C_ST END C_ED | C_LN_ST END C_LN_ED ; bindcomment returns[BindNode node] @init { $node = new BindNode(); } @after { $node.freeze(); } : (C_ST SYM_BIND expression C_ED txt) { $node.update($C_ST); $node.setExpression($expression.node); $node.setSkipped($txt.node); $node.update($txt.tree); } ; inbind returns[InBindNode node] @init { $node = new InBindNode(); TxtNode skip = new TxtNode(); } @after { $node.freeze(); } : IN C_ST SYM_BIND expression C_ED SYM_LP inbindchars (SYM_C inbindchars)* SYM_RP { $node.update($IN); $node.setExpression($expression.node); skip.update($SYM_LP); skip.update($SYM_RP); $node.setSkipped(skip); $node.update($SYM_RP); } ; inbindchars : (IDENT| SYMBOLS | SYM_C | QUOTED)+ ; // $> // $<Symbols SYMBOLS : '*' | '/' | '-' | '#'; SYM_LP : '('; SYM_RP : ')'; SYM_C : ','; SYM_BIND: '?'; // $> QUOTED : SYM_Q ~(SYM_Q)+ SYM_Q; fragment SYM_Q : '\u0027' | '"'; // $<Comments C_ST : {!inComment}? '/*' { inComment = true; }; C_ED : {inComment}? '*/' { inComment = false; }; C_LN_ST : {!inComment}? ('--'|'#') { inLineComment = true; inComment = true; }; C_LN_ED : {inLineComment}? ( LN_R? LN_N | EOF ) { inLineComment = false; inComment = false; }; // $> // $<Keywords BEGIN : ('b'|'B')('e'|'E')('g'|'G')('i'|'I')('n'|'N'); IF : ('i'|'I')('f'|'F'); ELSE : ('e'|'E')('l'|'L')('s'|'S')('e'|'E'); ELSEIF : ELSE IF; END : ('e'|'E')('n'|'N')('d'|'D'); IN : {!inComment}? ('i'|'I')('n'|'N'); // $> IDENT : CHAR+; fragment WS : '\t' | ' '; fragment LN_R : '\r'; fragment LN_N : '\n'; fragment CHAR : ~(SYMBOLS | SYM_Q | SYM_BIND | SYM_LP | SYM_RP | SYM_C | LN_R | LN_N | WS); // $<Hidden LT : {!inLineComment}? (LN_R | LN_N)+ { $channel = HIDDEN; }; WHITE_SPACES : (WS)+ { $channel = HIDDEN; }; // $>
折角頑張ってRewriteRuleを書いてたけど、全部捨てちゃった。
いや、tree grammarの意味がサッパリ分からなくなってしまってだね。
エラー処理する為に、最初のgrammarもjava依存になるんだったら、
もうファイル一個で済ませた方が、何だかんだ言って、良くね?
とか、思ったが、正直間違った気がしないでも無い。
この状態から、テストコードを書きながら、
エラーリカバリの為のコードを準備しるます。
トークン読み飛ばしたり、
エラートークン突っ込んだりするサンプルコード見ても、
何やってるのかさっぱり分からないと言うか、しっくり来ないからだす。
思い通りのツリーオブジェクトが作れている感じなので、
結局、ここまでは、腕力できてしまいますた、サテサテ…。
黒魔術を受け入れると、数学ワカンネ俺でもASTモドキ構築出来るANTLRとANTLR Worksは、ガチで凄いと思います。