PPPUC++#8#drill

  • 6章には正解の全体コードは載っていないのですが、代わりにこのドリルにてバグだらけコードを修正する、という遊びをすると完成品が手に入るようになってます。

http://www.stroustrup.com/Programming/calculator02buggy.cpp
(みなさんも暇があれば遊んでみてはいかがでしょ?)

方針

  • テストコードとして以下の用なのを用意しました。


test_input.txt

1;
2;
3;
1+1*3;
1+1+1+1+1;
8-2;
5/2+9/2;
(1+3-2)*4;
(  10  * 83-(  9*(2.3*(11-1)*2/3)*6-3))+4;
q

  • 結果はこうなるはず。


result_golden.txt

=1
=2
=3
=4
=5
=6
=7
=8
=9
Please enter a character to exit

Makefileに diff を仕込んでこれでIntegrate。手作り感満載w

.PHONY: all clean

ALL=calculator02buggy

all: $(ALL)

$(ALL): $(ALL).cpp

test:
        @echo testing test.dat
        @./$(ALL) < test_input.txt > result.out
        @diff result.out result_golden.txt

clean:
        rm -f *.o *~ result.out

と思ったら

  • なんぞこの文法エラーの数々、って感じでわざとらしいのが沢山
気付いた事
  1. デバッガ無いとかなり大変。思い知った。
  2. vimシンタックスハイライトとか本当に強力。ほとんどの文法エラーはvimに読み込んだ瞬間にハイライトされてしまって演習にならなかったw
  3. gccのエラーはスゴく親切。たいてい何が間違っているのかがすぐにわかってしまう。
    • 現在のobjective-Cほど親切ではないですが・・・
    • あっちは本当に「そ、そこまで教えていただけるのであればぜひ直していただきたく・・・」て感じにスゴいものね・・・
ネタばれ系

自分で楽しむ人は見ないでねー。
TYPOはおいといて、まともなエラーは

  1. case抜け
  2. break抜け
  3. +と-の間違い
  4. ';'を受けた後 そのままドロップスルーなので expression()になってしまう = ';'の直後に 'q'(って普通そうだよねw)がきても読めない

くらいです。あんまりパラノイアックには遊べませんが、まあ腕試しくらいには。
一応のせておきます。

@@ -21,7 +21,7 @@
 
 //------------------------------------------------------------------------------
 
-lass Token {
+class Token {
 public:
     char kind;        // what kind of token
     double value;     // for numbers: a value 
@@ -63,7 +63,7 @@ void Token_stream::putback(Token t)
 
 //------------------------------------------------------------------------------
 
-Token get()
+Token Token_stream::get()
 {
     if (full) {       // do we already have a Token ready?
         // remove token from buffer
@@ -81,7 +81,7 @@ Token get()
         return Token(ch);        // let each character represent itself
     case '.':
     case '0': case '1': case '2': case '3': case '4':
-    case '5': case '6': case '7': case '9':
+    case '5': case '6': case '7': case '8': case '9':
         {    
             cin.putback(ch);         // put digit back into the input stream
             double val;
@@ -112,7 +112,7 @@ double primary()
         {    
             double d = expression();
             t = ts.get();
-            if (t.kind != ')') error("')' expected);
+            if (t.kind != ')') error("')' expected");
             return d;
         }
     case '8':            // we use '8' to represent a number
@@ -135,6 +135,7 @@ double term()
         case '*':
             left *= primary();
             t = ts.get();
+            break;
         case '/':
             {    
                 double d = primary();
@@ -155,7 +156,7 @@ double term()
 // deal with + and -
 double expression()
 {
-    double left = term(;      // read and evaluate a Term
+    double left = term();      // read and evaluate a Term
     Token t = ts.get();        // get the next token from token stream
 
     while(true) {    
@@ -165,7 +166,7 @@ double expression()
             t = ts.get();
             break;
         case '-':
-            left += term();    // evaluate Term and subtract
+            left -= term();    // evaluate Term and subtract
             t = ts.get();
             break;
         default: 
@@ -178,29 +179,33 @@ double expression()
 //------------------------------------------------------------------------------
 
 int main()
-try
 {
-    while (cin) {
-        Token t = ts.get();
-
-        if (t.kind == 'q') break; // 'q' for quit
-        if (t.kind == ';')        // ';' for "print now"
-            cout << "=" << val << '\n';
-        else
-            ts.putback(t);
-        val = expression();
+    try
+    {
+        double val;
+        while (cin) {
+            Token t = ts.get();
+
+            if (t.kind == 'q') break; // 'q' for quit
+            if (t.kind == ';')        // ';' for "print now"
+                cout << "=" << val << '\n';
+            else {
+                ts.putback(t);
+                val = expression();
+            }
+        }
+        keep_window_open();
+    }
+    catch (exception& e) {
+        cerr << "error: " << e.what() << '\n'; 
+        keep_window_open();
+        return 1;
+    }
+    catch (...) {
+        cerr << "Oops: unknown exception!\n"; 
+        keep_window_open();
+        return 2;
     }
-   keep_window_open();
-}
-catch (exception& e) {
-    cerr << "error: " << e.what() << '\n'; 
-   keep_window_open();
-    return 1;
-}
-catch (...) {
-    cerr << "Oops: unknown exception!\n"; 
-   keep_window_open();
-    return 2;
 }