Download presentation
Presentation is loading. Please wait.
1
C++ 構文解析 構文解析器の状態保存と復元
長谷川啓
2
例1 void f() { int (n); // 宣言 ... int (n+n); // 式 }
3
例1 int の導出 (n+n); int (n); int simple-type-specifier
decl-specifier simple-type-specifier の次の字句が ‘(‘ であった場合に, 残りが init-declarator-list なのか ‘(‘ expression-list ‘)’ なのか不明 decl-specifier-seq
4
宣言を優先させる yacc/bison のレポートファイル
State X1 R11 type_specifier: simple_type_specifier . R12 postfix_expression: simple_type_specifier . '(' expression_list ')' R | simple_type_specifier . '(' ')' '(' shift, and go to state Y1 '(' [reduce using rule R11 (type_specifier)] $default reduce using rule R11 (type_specifier) このままの動作だと simple-type-specifier の後の ‘(‘ で R11の規則が使われることはない.
5
宣言を優先させる (続き) 以下のコードを yyparse の適切な場所に入れる.
if ( yystate == X1 && yychar == ‘(‘ ) { yyn = R11 + 1; goto yyreduce; } 勿論このままだと、函数スタイルのキャストは構文エラーを引き起こす。
6
構文解析器の状態を保存する さらに以下のように修正する if (yystate == X1 && yychar == ‘(‘ ) {
if (!retry[X1] ) { // 1 回目なら save(yystate, ...); // 構文解析器の状態を保存 yyn = R11 + 1; // 宣言だとして構文解析をする goto yyreduce; }
7
構文解析器の状態を復元する 以下のコードを yyerror が呼び出される前の位置に挿入する if (構文解析器の状態が保存されている) {
restore(&yystate, ...); // 構文解析器の状態を復元する ++retry[yystate]; // リトライカウンタをインクリメント goto yynewstate; }
8
1回目の構文エラーを起こすまでの字句も保存する
int get_token() { int ret = ... ... if (構文解析器の状態が保存されている) { // retry するときのために字句をため込んでおく // 字句に属性を付加しているのならば、それも保存する } return ret;
9
例2 struct T { ... }; int a; ... T t1(); // 戻り値の型が T の函数の宣言
T t2(a); // 型 T の変数の定義. a で初期化.
10
函数の宣言は優先されているが... yacc/bison のレポートファイル
State X2 R21 declarator: direct_declarator . R22 direct_declarator: direct_declarator . '(' parameter_declaration_clause ')' ... '(' shift, and go to state Y2 '(' [reduce using rule R21 (declarator)] $default reduce using rule R21 (declarator) このままの動作だと declarator の後の ‘(‘ で R21 の規則が使われることはない. つまり例2 の変数の定義は構文エラーになる
11
構文解析器の状態を保存する 以下のコード yyparse の適切な場所に追加する:
if (yystate == X2 && yychar == ‘(‘ ) { if (!retry[X2] ) // 1 回目なら save(yystate, ...); // 構文解析器の状態を保存 else { yyn = R21 + 1; goto yyreduce; }
12
例3 double f(); void g(int a) { int(f())+a; }
13
int(f())+a; int の次の ‘(‘ まで読み込んだ時点で例1の X1 になる
f の次の ‘(‘ まで読み込んだ時点で例2の X2 になる + を読み込んだ時点で X2 で保存した状態を捨てて X1 で保存した状態を復元するべき f を記号表に登録するのはマズいから
14
最後に保存した状態を捨てる 以下のコードを yyparse の適切な場所に追加する: if (yystate == X2) {
switch (yychar ) { case ’(’: case ’[’: ... break; // 宣言として構文解析してエラーにならないもの default: if (最後に保存した状態はX2 のもの) { 最後に保存した状態を捨てる goto yyerrlab; }
Similar presentations
© 2024 slidesplayer.net Inc.
All rights reserved.