パソコン活用研究5番街(Visual
Basic、Excel(VBA)、BASIC プログラミング研究)
VB.NETで計算機を作る(乗算・除算)
(準備中)
前回(「VB.Netで計算機を作る(足し算引き算)」)では、再帰下降パースによる足し算引き算の実装をして
みましたが、今回は乗算(掛け算)・除算(割り算)と括弧( )を使えるようにしてみます。
Cによる完成形のプログラムは「プログラミング言語を作る」のP57〜P70にあります。
本に掲載されているプログラムは、再帰下降パーサによる完成されたプログラムで、
字句解析ー>構文解析ー>演算まで2段抜かしでやってしまうようなプログラムです。
このページでは、各プロセスの動きを1段づつ確認したいので、本にあるような洗練されたものとはかなり違う
無骨なプログラムを作っていきます。各プロセスのアルゴリズム、動作の確認を主眼においているので、
正しくない式が入力された時のチェック(異常系のチェック)は甘くしてます。なので正常系の場合のみちゃんと動作します。
If t.type = type.lparen Then v = expression() t = get_token() If t.type = type.rparen Then Return v Else Console.WriteLine("rparen is missing") End If
Cunget_token 今読んでいるtokenの番号をひとつ戻します。
2*(1+-3)の演算をしてみた時の動作をトレースしてみます。
Bで( )の処理に入ります。
DとFのプロセスが少し複雑な動きです。
B以降がやや複雑なので動作を説明します。( )の再帰的な処理と、unget_tokenでtokenを式に戻す
あたりがなかなかわかりにくい個所です。
unget_tokenでtokenを式に戻す動作については、実際は今読んでいるtoken番号をひとつ減らすという
操作で行っています。
Aでは、関数termのなかのv2=primary_expresiionのところまで進んでいます。
B primary_expressionの中で、左括弧"("が登場すると、expressionを再帰的に呼び出します。
C 再帰的に呼び出されたexpressionの中で、1+-3 の処理に入ります。
D termの中で、"+"が出てきたときは、unget_tokenして"+"は式の中に戻します。
whileループを抜けて、値1をexpressionにリターンします。
expressionの中であらためて"+"を取り出します。
E expressionの中でv2取得のプロセスに入り、expression -> term ->primary
expression -> get_token
-> primary_expressionで-3を取得 -> termのv1に-3を取得
F termの演算子チェックで右括弧")"に出会う -> unret_tokenで")"を式に戻し、whileループを抜けtermは
expressionに-3をリターン。
expressionは 1+-3を計算し、演算結果として-2を得る -> whileループの中でget_tokenで")"を得る。
->unget_tokenで")"を式に戻しwhileループを抜ける ->
Bで呼び出された ( )の結果として-2をリターン
-> ( )の処理を終える。
primary_expressionはBでexpressionを呼び出した次のコードの実行に移る。->
get_tokenで")"を取得したので、-2を
リターン -> termに戻りtermののv2=-2が取得される。
G termでv1*v2の計算が行われ、結果として-4が得られる。 ->whileループのget_tokenで"line_end"を取得
->whileループを抜け、-4をexpressionにリターン
@〜Gの動作フローを図示してえみます。各関数が自分の受け持った処理だけを行い、他の処理は他の関数
に丸投げしていますが、非常に巧妙に動作していることがわかると思います。
( )が複数重なってもちゃんと処理できます。
ちなみに演算用の変数v1,v2はdouble型ですので演算結果は小数点が出てきても大丈夫です。
2*(5/(1+2))+2 を演算させてみた結果
(途中はいくらか省略しています)
ソースコード(変更、追加のあった個所のみ) Function expression() As Double Dim v1, v2 As Double Dim t As token v1 = term() Console.WriteLine("expression v1:{0}", v1) While (1) t = get_token() Console.WriteLine("expression {0}: {1} : {2} ", t.str, t.type, t.v) If (t.type <> type.add_op And t.type <> type.sub_op) Then unget_token() : Exit While v2 = term() Console.WriteLine("expression v2:{0}", v2) If t.type = type.add_op Then v1 = v1 + v2 If t.type = type.sub_op Then v1 = v1 - v2 Console.WriteLine("expression calculated v1:{0}", v1) End While Return v1 End Function Function term() As Double Dim v1, v2 As Double Dim t As token v1 = primary_expression() Console.WriteLine("term v1:{0}", v1) While (1) t = get_token() Console.WriteLine("term {0}: {1} : {2} ", t.str, t.type, t.v) If (t.type <> type.mul_op And t.type <> type.div_op) Then unget_token() : Exit While v2 = primary_expression() Console.WriteLine("term v2:{0}", v2) If t.type = type.mul_op Then v1 = v1 * v2 If t.type = type.div_op Then v1 = v1 / v2 Console.WriteLine("term calculated v1:{0}", v1) End While Return v1 End Function Function primary_expression() As Double Dim t As token Dim v As Double t = get_token() Console.WriteLine("primary_expression {0}: {1} : {2} ", t.str, t.type, t.v) If t.type = type.number Then Return t.v If t.type = type.lparen Then v = expression() t = get_token() If t.type = type.rparen Then Return v Else Console.WriteLine("rparen is missing") End If End Function Function get_token() As token Static Dim i As Integer = 0 REM t = tok(i) If unget = 1 Then i = i - 1 : unget = 0 Console.WriteLine("get_token {0}: {1} : {2} :{3} ", i, tok(i).str, tok(i).type, tok(i).v) REM Console.WriteLine("get_token {0}: {1} : {2} :{3} ", num_token, t.str, t.type, t.v) i = i + 1 Return tok(i - 1) End Function Sub unget_token() unget = 1 End Sub
TopPage > Visual BasIc&Excel活用研究目次