C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[7]: 電卓 ((1+2)3)カッコの入れ子


(過去ログ 57 を表示中)

[トピック内 20 記事 (1 - 20 表示)]  << 0 >>

■32500 / inTopicNo.1)  電卓 ((1+2)3)カッコの入れ子
  
□投稿者/ しろ☆ (1回)-(2009/02/08(Sun) 12:23:26)

分類:[VB.NET/VB2005 以降] 

2009/02/08(Sun) 12:26:07 編集(投稿者)

はじめまして。

VB2005で電卓を作っています。
今カッコの計算の処理で躓いています。
(1+2)のような入れ子ではないカッコの計算は出来ました。
入れ子の時にはどうしたらいいのかわからないのです。
電卓アプリのお祭りも拝見しましたが
みなさんすごいです。

ご存知の方がいらしたらよろしくお願いします。

引用返信 編集キー/
■32502 / inTopicNo.2)  Re[1]: 電卓 ((1+2)3)カッコの入れ子
□投稿者/ επιστημη (1676回)-(2009/02/08(Sun) 13:00:32)
επιστημη さんの Web サイト
2009/02/08(Sun) 13:48:41 編集(投稿者)

ご参考 つ http://blogs.wankuma.com/episteme/archive/2007/07/04/83639.aspx
VBに翻訳したってください > だれぞ

ここでは再帰下降パーサで逆ポーランド記法に変換してますが、
記法変換じゃなくてまぢ計算しちゃえばええです。

わからんなら勉強してください。聞きかじりでほいほいやれるもんじゃありません実際。
数式という文法を解釈し処理すんだからこれはまさにインタプリタなのよ。

引用返信 編集キー/
■32523 / inTopicNo.3)  Re[1]: 電卓 ((1+2)3)カッコの入れ子
□投稿者/ Azulean (289回)-(2009/02/08(Sun) 17:03:27)
演算子の優先順位とか色々とめんどくさいので、言うほど簡単にはできません。

> 電卓アプリのお祭りも拝見しましたが
> みなさんすごいです。
電卓アプリ祭り関連で必要そうなキーワードを集めて、調べて、学んだ上で、自分のプログラムではどういったアプローチが必要か考えてみるというのも作戦だと思いますが、何を知りたいのでしょうか?
引用返信 編集キー/
■32525 / inTopicNo.4)  Re[2]: 電卓 ((1+2)3)カッコの入れ子
□投稿者/ やじゅ (927回)-(2009/02/08(Sun) 17:26:34)
やじゅ さんの Web サイト
数式の解析と計算処理をまとめてやろうとしないで
大きく2段階で分けて考えるといいんじゃないでしょうか

1.数式の解析→逆ポーランド記法に返還
http://www.gg.e-mansion.com/~kkatoh/program/novel2/novel207.html
http://www.gg.e-mansion.com/~kkatoh/program/novel2/novel208.html

2.逆ポーランド記法から計算処理
http://www.sm.rim.or.jp/~shishido/pol.html
引用返信 編集キー/
■32526 / inTopicNo.5)  Re[3]: 電卓 ((1+2)3)カッコの入れ子
□投稿者/ επιστημη (1684回)-(2009/02/08(Sun) 17:35:38)
επιστημη さんの Web サイト
> 数式の解析と計算処理をまとめてやろうとしないで
> 大きく2段階で分けて考えるといいんじゃないでしょうか

いや、それは無駄ってもんでしょう。
逆ポーランドに出力する代わりにスタック使って計算するが吉。

一旦逆ポで吐いちゃうと、そいつをまたアタマから舐めてどーのこーの...でしょ?

引用返信 編集キー/
■32528 / inTopicNo.6)  Re[4]: 電卓 ((1+2)3)カッコの入れ子
□投稿者/ アクア (77回)-(2009/02/08(Sun) 17:58:35)
アクア さんの Web サイト
アクアと申しますどうぞ宜しくお願いします。

> 電卓アプリのお祭りも拝見しましたが
たぶん、私のBlogのエントリもご覧になられたご様子なので、出来ればお手伝いしたいと思うのですが、その前にお聞きしたい事があります。

タイトルにある
((1+2)3)ってどういう事なのでしょうか

((1+2)*3)って事でいいのですか?

計算式がどの様に作られているのかお教え頂けないでしょうか?

#もしかして、質問の解釈を間違えているのかなぁ…
引用返信 編集キー/
■32529 / inTopicNo.7)  Re[4]: 電卓 ((1+2)3)カッコの入れ子
□投稿者/ も (69回)-(2009/02/08(Sun) 18:07:06)
No32526 (επιστημη さん) に返信
>>数式の解析と計算処理をまとめてやろうとしないで
>>大きく2段階で分けて考えるといいんじゃないでしょうか
>
> いや、それは無駄ってもんでしょう。
> 逆ポーランドに出力する代わりにスタック使って計算するが吉。
>
> 一旦逆ポで吐いちゃうと、そいつをまたアタマから舐めてどーのこーの...でしょ?
スタック使って計算ってことは逆ポーランド記法で数式を組み立てるって事かと
# 数式用のスタックと計算用のスタック(と必要ならアキュムレータようの一時記憶)が必要だった気がする
引用返信 編集キー/
■32530 / inTopicNo.8)  Re[5]: 電卓 ((1+2)3)カッコの入れ子
□投稿者/ επιστημη (1685回)-(2009/02/08(Sun) 18:52:25)
επιστημη さんの Web サイト
2009/02/08(Sun) 19:05:35 編集(投稿者)
> スタック使って計算ってことは逆ポーランド記法で数式を組み立てるって事かと

組み立てなくてもいい。その場で評価するなら。

> # 数式用のスタックと計算用のスタック(と必要ならアキュムレータようの一時記憶)が必要だった気がする

その場評価なら必要なし。論より証拠でやってみた。

http://blogs.wankuma.com/episteme/archive/2007/07/04/83639.aspx
↑こいつを忠実にVBで再現。

Module Module1

  Dim ch As Char ' 今読んでる文字
  Dim stk As New System.Collections.Generic.Stack(Of Double) ' スタック
  Dim dic As New System.Collections.Generic.Dictionary(Of Char, Double) ' 変数/値の辞書
  Dim line As String ' 入力文字列

  ' スタックをダンプせよ
  Sub dump()
    For Each value As Double In stk
      Console.Write(" {0}", value)
    Next
    Console.WriteLine()
  End Sub

  ' 空白をスキップして読め
  Sub readch()
    Do
      If line.Length = 0 Then Return
      ch = line(0)
      line = line.Remove(0, 1)
    Loop While ch = " "c
  End Sub

  ' factor とは ( と ) で囲まれた expression 
  '        もしくは 文字
  Sub factor()
    If ch = "("c Then
      readch()
      expression()
      If ch = ")"c Then
        readch()
      Else
        Console.WriteLine("?")
      End If
    ElseIf ch >= "a"c AndAlso ch <= "z"c Then
      stk.Push(dic(ch))
      dump()
      readch()
    Else
      Console.WriteLine("?")
    End If
  End Sub

  ' term とは factor * factor
  '      もしくは factor / factor
  Sub term()
    factor()
    Do
      If ch = "*"c Then
        Console.Write(ch)
        readch()
        factor()
        Dim x As Double = stk.Pop()
        Dim y As Double = stk.Pop()
        stk.Push(x * y)
        dump()
      ElseIf ch = "/"c Then
        Console.Write(ch)
        readch()
        factor()
        Dim x As Double = stk.Pop()
        Dim y As Double = stk.Pop()
        stk.Push(y / x)
        dump()
      Else
        Exit Do
      End If
    Loop
  End Sub

  ' expression とは term + term
  '            もしくは term - term
  Sub expression()
    term()
    Do
      If ch = "+"c Then
        Console.Write(ch)
        readch()
        term()
        Dim x As Double = stk.Pop()
        Dim y As Double = stk.Pop()
        stk.Push(x + y)
        dump()
      ElseIf ch = "-"c Then
        Console.Write(ch)
        readch()
        term()
        Dim x As Double = stk.Pop()
        Dim y As Double = stk.Pop()
        stk.Push(y - x)
        dump()
      Else
        Exit Do
      End If
    Loop
  End Sub

  Sub Main()
    dic.Add("a"c, 1)
    dic.Add("b"c, 2)
    dic.Add("c"c, 3)
    dic.Add("d"c, 4)
    line = "(a+b)*(c+d)" ' 数値を直接入れるのは字句解析がめんどっちーのでパス
    readch()
    expression()
    Console.WriteLine("result = {0}", stk.Pop())
  End Sub

End Module

# VBおんちなんできっついわぁ...

引用返信 編集キー/
■32531 / inTopicNo.9)  Re[6]: 電卓 ((1+2)3)カッコの入れ子
□投稿者/ も (70回)-(2009/02/08(Sun) 19:40:58)
No32530 (επιστημη さん) に返信
> 2009/02/08(Sun) 19:05:35 編集(投稿者)
>
> > スタック使って計算ってことは逆ポーランド記法で数式を組み立てるって事かと
>
> 組み立てなくてもいい。その場で評価するなら。
>
>># 数式用のスタックと計算用のスタック(と必要ならアキュムレータようの一時記憶)が必要だった気がする
>
> その場評価なら必要なし。論より証拠でやってみた。
>
# バッサリ
> # VBおんちなんできっついわぁ...
ぐおおお・・・vbcないからコンパイルすら出来ないなんて・・・

実地試験できませんが,"(0+1)+2*(3+(4*5+6)*7)/8+10" なんて場合は,
逆ポーランド記法を組み立てる途中にスタックのポップ/プッシュが多発して,
評価と組み立てを同時にできなかったと思ったけど,そうでもないのかな.
引用返信 編集キー/
■32532 / inTopicNo.10)  Re[7]: 電卓 ((1+2)3)カッコの入れ子
□投稿者/ επιστημη (1686回)-(2009/02/08(Sun) 20:26:17)
επιστημη さんの Web サイト
> 実地試験できませんが,"(0+1)+2*(3+(4*5+6)*7)/8+10" なんて場合は,
> 逆ポーランド記法を組み立てる途中にスタックのポップ/プッシュが多発して,
> 評価と組み立てを同時にできなかったと思ったけど,そうでもないのかな.

えーと、当然再帰にハマるわけですが、少なくともカッコの入れ子の深さまでは
関数呼び出しの連続になるでしょう。すなわちcall-stackを消費します。
とはいえ数百段くらいはどってことないハズよん。

引用返信 編集キー/
■32533 / inTopicNo.11)  Re[7]: 電卓 ((1+2)3)カッコの入れ子
□投稿者/ しろ☆ (2回)-(2009/02/08(Sun) 20:52:39)
みなさま
こんなにたくさんお返事ありがとうございます。
私宛ではない書き込みもありますが私の質問にお時間を割いてくださって感謝しています。


επιστημη様
参考になるリンクやお話をたくさんありがとうございます。

>数式という文法を解釈し処理すんだからこれはまさにインタプリタなのよ。

そうですよね。精進します。


Azulean様
お返事ありがとうございます。
秋に四則演算のみをする単純な電卓を最初に作り、次はコードを見やすくまとめ、
次は「=」が押されるまでいくつでも計算できるように改良…と言うように少しずつ勉強しています。
今入れ子ではないカッコの時はIndexOfでカッコを探し計算していますが入れ子になった時このままで
出来るのか、もっと良い方法があるのではないかと思い
電卓アプリのお祭りにはカッコを実装した方が少なかった事もあり質問させていただきました。


やじゅ様
お返事ありがとうございます。
アドバイスとリンク先も良く読み参考にさせていただきます。


アクア様
お返事ありがとうございます。
電卓の勉強をはじめた頃からBlogのエントリもずっと拝見しています。
どうかよろしくお願いします。
タイトルの式の意味は((1+2)*3)です。
((1+2)3)と*を省略して入力しても計算できるようにしたいのです。
分かりにくい説明で申し訳ありません。

カッコつきの計算部分のコードを添付します。

'()カッコを探す
Private Function MyTankoSiki2() As Integer
Dim kotae As Integer, shiki As String = ans.Text
Dim shiki1, shiki2 As String
Dim pt1, pt2 As Integer

Do
'( を探す
pt1 = shiki.IndexOf("(")
If pt1 = -1 Then
Exit Do
End If

') を探す
pt2 = shiki.IndexOf(")")

'A+(B)+C
shiki1 = shiki.Substring(0, pt1) 'Aを取り出す
shiki2 = shiki.Substring(pt2 + 1) 'Cを取り出す
shiki = shiki.Substring(pt1 + 1, pt2 - pt1 - 1) 'Bを取り出す
kotae = MyTankoSiki(shiki) '()内を計算
shiki = shiki1 & kotae.ToString & shiki2
Loop
'計算する
kotae = MyTankoSiki(shiki)
Return kotae
End Function


も様
お返事ありがとうございます。
私にはまだまだ難しいですがおふたりのお話が理解できるようにがんばります。


引用返信 編集キー/
■32534 / inTopicNo.12)  Re[8]: 電卓 ((1+2)3)カッコの入れ子
□投稿者/ επιστημη (1687回)-(2009/02/08(Sun) 21:14:15)
επιστημη さんの Web サイト
> 今入れ子ではないカッコの時はIndexOfでカッコを探し計算していますが
> 入れ子になった時このままで出来るのか

再帰つかってやれなくもないすね。

exp = "((1 + 2) * (3 + 4)) / 7"
最も外側の()に囲まれる部分を x0 に置き換えます
exp = "x0 / 7", x0 = "(1 + 2) * (3 + 4)"
x0 について同じことをします
exp = "x0 / 7", x0 = "x1 * x2", x1 = "1 + 2", x2 = "3 + 4"
カッコがなくなったら計算します
exp = "x0 / 7", x0 = "x1 * x2", x1 = "3", x2 = "7"
x1, x2 が確定したので元に戻します
exp = "x0 / 7", x0 = "3 * 7"
カッコがなくなったら計算します
exp = "x0 / 7", x0 = "21"
x0 が確定したので元に戻します
exp = "21 / 7"
カッコがなくなったら計算します
exp = "3"

おしまい。
例示した再帰下降パーサも同じことやってると思っていいですね。

引用返信 編集キー/
■32535 / inTopicNo.13)  Re[9]: 電卓 ((1+2)3)カッコの入れ子
□投稿者/ dogatana (34回)-(2009/02/08(Sun) 22:21:02)
2009/02/08(Sun) 22:22:42 編集(投稿者)
2009/02/08(Sun) 22:22:12 編集(投稿者)

No32534 (επιστημη さん) に返信
>>今入れ子ではないカッコの時はIndexOfでカッコを探し計算していますが
>>入れ子になった時このままで出来るのか
>
> 再帰つかってやれなくもないすね。
>
> 例示した再帰下降パーサも同じことやってると思っていいですね。

電卓ならεπιστημη さんの書かれているトップダウンパーサの再帰下降パーサで、expressionから順にパースと同時に計算するのが一番簡単ではないかと。
LL(1)文法で手書き向きですが、言語まで組み立てるとなると、先読みで一意に決まる構文の定義が面倒だったと思います。Pascalが代表的。

ボトムアップだと演算子優先順位パーサで、カッコも演算子とみなして演算子の優先順位の定義とスタック使って計算するか、コンパイラ・コンパイラ前提でLRパーサを使うかですが、VB向けのコンパイラ・コンパイラってあるのかしらん。

ちゃんとやるなら、コンパイラに関する本で勉強するのが早いと思いますね。


引用返信 編集キー/
■32536 / inTopicNo.14)  Re[10]: 電卓 ((1+2)3)カッコの入れ子
□投稿者/ επιστημη (1688回)-(2009/02/08(Sun) 22:26:20)
επιστημη さんの Web サイト
2009/02/08(Sun) 22:28:37 編集(投稿者)

> VB向けのコンパイラ・コンパイラってあるのかしらん。

yacc.NET と lex.NET ほしいよねー♪
Visual Studio に同梱されててもいいとおもうなり。

# 実行時オプションで C#, VB. C++/CLI, IL が選べるの♪
# Javaのがあるんだから、ちょちょいといぢればC#版は作れんじゃ...

引用返信 編集キー/
■32537 / inTopicNo.15)  Re[11]: 電卓 ((1+2)3)カッコの入れ子
□投稿者/ dogatana (35回)-(2009/02/08(Sun) 22:40:15)
2009/02/08(Sun) 22:42:04 編集(投稿者)
2009/02/08(Sun) 22:41:04 編集(投稿者)

No32536 (επιστημη さん) に返信

> yacc.NET と lex.NET ほしいよねー♪
> Visual Studio に同梱されててもいいとおもうなり。

字句解析ならなんとか(lexなくても)手書きでいけるでしょうけど、構文解析となると大変。
移植ならなんとかいけいますかね。

> # 実行時オプションで C#, VB. C++/CLI, IL が選べるの♪
> # Javaのがあるんだから、ちょちょいといぢればC#版は作れんじゃ...

でも「実行時オプションで選べる」構成って可能なんでしょうかねぇ。
yaccもソース掃き出しですが、.NET用だと各言語共通で使えるような共通言語で出せるとかでないときついかも。
各言語用だと、それぞれの言語の特性というか作法に従う必要があるでしょうし。
(.NETわかってないので、はずしてますかね。。)

言い出しっぺということで、いっそεπιστημη さんが書いてしまうってのは? :p


引用返信 編集キー/
■32540 / inTopicNo.16)  Re[12]: 電卓 ((1+2)3)カッコの入れ子
□投稿者/ επιστημη (1689回)-(2009/02/08(Sun) 23:04:46)
επιστημη さんの Web サイト
> でも「実行時オプションで選べる」構成って可能なんでしょうかねぇ。
> yaccもソース掃き出しですが、.NET用だと各言語共通で使えるような共通言語で出せるとかでないときついかも。

アクション部を別建てにできればなんとかならんかなー

> 言い出しっぺということで、いっそεπιστημη さんが書いてしまうってのは? :p

(∩゚д゚)アーアーきこえなーい

引用返信 編集キー/
■32556 / inTopicNo.17)  Re[11]: 電卓 ((1+2)3)カッコの入れ子
□投稿者/ aetos (97回)-(2009/02/09(Mon) 14:51:10)
aetos さんの Web サイト
No32536 (επιστημη さん) に返信
> 2009/02/08(Sun) 22:28:37 編集(投稿者)
>
>>VB向けのコンパイラ・コンパイラってあるのかしらん。
>
> yacc.NET と lex.NET ほしいよねー♪
> Visual Studio に同梱されててもいいとおもうなり。

ふむぅ?
http://msdn.microsoft.com/ja-jp/library/bb166360.aspx
引用返信 編集キー/
■32557 / inTopicNo.18)  Re[12]: 電卓 ((1+2)3)カッコの入れ子
□投稿者/ επιστημη (1692回)-(2009/02/09(Mon) 15:15:24)
επιστημη さんの Web サイト
2009/02/09(Mon) 17:14:17 編集(投稿者)

> http://msdn.microsoft.com/ja-jp/library/bb166360.aspx

あったんかい...あー、Visual Studio SDK なのか。
インスコしてみよかしらドチドチ

[追記] ぶっこんでみました。> MPLEX, MPPG
なんやこのマニュアル、ぺらぺらやんかー(ぷんすか
動き出すまでにはまだ当分かかりそうです orz

引用返信 編集キー/
■32596 / inTopicNo.19)  Re[6]: 電卓 ((1+2)3)カッコの入れ子
□投稿者/ επιστημη (1696回)-(2009/02/10(Tue) 15:04:54)
επιστημη さんの Web サイト
>> スタック使って計算ってことは逆ポーランド記法で数式を組み立てるって事かと
> 
> 組み立てなくてもいい。その場で評価するなら。
> 
>># 数式用のスタックと計算用のスタック(と必要ならアキュムレータようの一時記憶)が必要だった気がする
> 
> その場評価なら必要なし。論より証拠でやってみた。

てかスタックすら要らなくね? 演算子とその左辺/右辺が確定した時点で評価できっから。
ダメで元々でやってみた。

Module 数式の構文解析と評価

    Dim 変数値 As New System.Collections.Generic.Dictionary(Of Char, Double)
    Dim 入力文字 As Char
    Dim 入力文字列 As String

    Sub 一文字読む()
        Do
            If 入力文字列.Length = 0 Then Return
            入力文字 = 入力文字列(0)
            入力文字列 = 入力文字列.Remove(0, 1)
        Loop While 入力文字 = " "c
    End Sub

    ' 因子(factor) とは ( 式 )
    '             もしくは 変数
    Function 因子() As Double
        Dim 結果 As Double
        If 入力文字 = "("c Then
            一文字読む()
            結果 = 式()
            If 入力文字 = ")"c Then
                一文字読む()
            Else
                Console.WriteLine("?")
            End If
        ElseIf 入力文字 >= "a"c AndAlso 入力文字 <= "z"c Then
            結果 = 変数値(入力文字)
            一文字読む()
        Else
            Console.WriteLine("?")
        End If
        Return 結果
    End Function

    ' 項(term) とは 因子
    '          もしくは 因子 * 因子
    '          もしくは 因子 / 因子
    Function 項() As Double
        Dim 結果 As Double
        結果 = 因子()
        Do
            If 入力文字 = "*"c Then
                一文字読む()
                結果 = 結果 * 因子()
            ElseIf 入力文字 = "/"c Then
                一文字読む()
                結果 = 結果 / 因子()
            Else
                Exit Do
            End If
        Loop
        Return 結果
    End Function

    ' 式(expression) とは 項
    '                もしくは 項 + 項
    '                もしくは 項 - 項
    Function 式() As Double
        Dim 結果 As Double
        結果 = 項()
        Do
            If 入力文字 = "+"c Then
                一文字読む()
                結果 = 結果 + 項()
            ElseIf 入力文字 = "-"c Then
                一文字読む()
                結果 = 結果 - 項()
            Else
                Exit Do
            End If
        Loop
        Return 結果
    End Function

    Sub Main()
        変数値.Add("a"c, 1)
        変数値.Add("b"c, 2)
        変数値.Add("c"c, 3)
        変数値.Add("d"c, 4)
        ' 数値を直接入れるのは字句解析がめんどっちーのでパス
        入力文字列 = "((a+b)*(c+d))/c"
        一文字読む()
        Dim 結果 As Double = 式()
        Console.WriteLine("結果 = {0}", 結果)
    End Sub

End Module

引用返信 編集キー/
■32622 / inTopicNo.20)  Re[7]: 電卓 ((1+2)3)カッコの入れ子
 
□投稿者/ しろ☆ (3回)-(2009/02/10(Tue) 22:28:27)
επιστημη様
dogatana様
aetos様

引き続きありがとうございます。
勉強を始めて日の浅い私には難しい部分もありますが
大変参考になるトピックになりました。
分からなかった部分は少しずつ調べ理解して行きたいと思います。

お返事をくださったみなさま
こんなにたくさんお返事をいただけて
お時間を割いていただいて本当にありがとうございます。

みなさまのおかげで完成できそうです。

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -