[Porcelli] ( https://github.com/porcelli/plsql-parser )から提供された PLSQL パーサーを変更しました。このパーサーを使用して PlSql ファイルを解析しています。FOR ループ ステートメントの解析で問題に直面しています。
for i in 1..l_line_tbl.count
LOOP
l_line_tbl(i).schedule_ship_date := l_max_ship_date;
l_line_tbl(i).ship_set_id := x_ship_set_id;
END LOOP;
上記のステートメントは解析されず、EarlyExitException がスローされます。
ここで、このステートメントを変更して 1 と二重ドット (..) の間にスペースを入れると、ステートメントが解析されます。最初のケースの処理方法がわかりません。
for i in 1 ..l_line_tbl.count
LOOP
l_line_tbl(i).schedule_ship_date := l_max_ship_date;
l_line_tbl(i).ship_set_id := x_ship_set_id;
END LOOP;
パーサー文法:
loop_statement
@init { int mode = 0; }
: label_name?
(while_key condition {mode = 1;} | for_key cursor_loop_param {mode = 2;})?
loop_key
seq_of_statements
end_key loop_key label_name?
-> {mode == 1}? ^(WHILE_LOOP[$while_key.start] label_name*
^(LOGIC_EXPR condition) seq_of_statements)
-> {mode == 2}? ^(FOR_LOOP[$for_key.start] label_name* cursor_loop_param seq_of_statements)
-> ^(loop_key label_name* seq_of_statements)
;
// $<Loop - Specific Clause
cursor_loop_param
@init { int mode = 0; }
: (index_name in_key reverse_key? lower_bound DOUBLE_PERIOD)=>
index_name in_key reverse_key? lower_bound DOUBLE_PERIOD upper_bound
-> ^(INDEXED_FOR index_name reverse_key? ^(SIMPLE_BOUND lower_bound upper_bound))
| record_name in_key ( cursor_name expression_list? {mode = 1;} | LEFT_PAREN
select_statement RIGHT_PAREN)
->{mode == 1}? ^(CURSOR_BASED_FOR record_name cursor_name expression_list?)
-> ^(SELECT_BASED_FOR record_name select_statement)
;
// $>
レクサー文法:
FOR_NOTATION
: UNSIGNED_INTEGER
{state.type = UNSIGNED_INTEGER; emit(); advanceInput();}
'..'
{state.type = DOUBLE_PERIOD; emit(); advanceInput();}
UNSIGNED_INTEGER
{state.type = UNSIGNED_INTEGER; emit(); advanceInput(); $channel=HIDDEN;}
;
fragment
UNSIGNED_INTEGER
: ('0'..'9')+
;