5.構文解析とコード生成 |
|||||||||||
[例題のプログラミング言語の文法]
(1)構文解析の処理 文種別ごとに, 式部分を分離し,逆ポーランド変換を行い,文ごとの解釈を行います。 文の中には,IfブロックやWhileブロックのように, 離れた部分にジャンプしたり, 後から前の部分を参照するような処理が必要となります。 またこれらのブロック中に,同様のブロックを挿入できます。 すなわち,制御構造をネストさせることができます。 これらを処理するためのスタックを用意します。 public struct BlockData // ブロックコントロールデータ { public string Type; public int BP; public int IfP; public int ThenP; } public BlockData [] IfStack=new BlockData[200]; public int IfStackP=0; public BlockData [] DoStack=new BlockData[200]; public int DoStackP=0; public int[] numBreak=new int[200]; // Break処理用テーブル public int[,] BreakP=new int[200,200]; トレース用ルーチン private void debugSA(int i) { listBox2.Items.Clear();string S=""; for(int k=0;k<numPolish;k++) { string X=Polish[k].operation+ "\t" + Polish[k].str; S="\n"+X; listBox2.Items.Add(X); } DialogResult result = MessageBox.Show(S,"構文解析途中経過2",MessageBoxButtons.OKCancel); if(result==DialogResult.Cancel) checkBox1.Checked=false; } (2)中間コードの展開形式 デバッグでソースプログラムの文番号を表示可能とするために, StNo 文番号 (文の中間コード群) の形式で出力します。 代入文では,逆ポーランド記法そのものを中間コード群とします。 その他の文は,以下のとおりとします。 (a) if文 (論理式の逆ポーランド記法) IfP: L1 push (elseでL1を設定) then (then以降のオブジェクト) ThenP: L2 push (elseでThenP設定,endifでL2を設定) goto L1: (Else以降のオブジェクト) L2: または,ThenPがないとき,すなわちelseがなかったとき (論理式の逆ポーランド記法) IfP: L2 push (endifでL2を設定) then (then以降のオブジェクト) L2: なお,「then」という命令は, スタック上の2つデータをポップし,後からポップした値が偽であれば, 先にポップした値をプログラムカウンタの値にする(ジャンプする)命令と とします。 「goto」という命令は,ポップした値を プログラムカウンタの値にする(ジャンプする)命令とします。 (b) while文 Bp: (論理式の逆ポーランド記法) IfP: L1 push (wendでL1を設定) then (while以降のオブジェクト) ThenP: Bp push goto L1: (wendでL1をbreakに設定) (c) repeat文 Bp: (repeat以降のオブジェクト) (論理式の逆ポーランド記法) ThenP: Bp push then L1: (untilでL1をbreakに設定) (d) for文 (初期化式の逆ポーランド記法) L1 push goto Bp: (増分式の逆ポーランド記法) L1: (判定式の逆ポーランド記法) L2 push (nextでL2を設定) then (for以降のオブジェクト) Bp push goto Bp L2: (nextでL2をbreakに設定) (e) function文(関数名テーブルに登録) *Pstart* *Parm 引数名1 *Parm 引数名2 |