第6章 練習問題4

  • 投稿日:
  • by
  • カテゴリ:

 第6章と第7章は、簡易電卓を作ってみるという内容である。最初に紹介した書評で酷評されている部分である。その部分を少し引用する。

この本では、まずBNF記法で数式の文法を定義したあと、教科書的な再帰下降構文解析による数式のパーサーを書いて計算を行っている。SICPでも冒頭でここまで無茶な課題はなかったはずだ。
もちろん、面白い課題であり、全プログラマーがプログラミング学習の比較的早い段階で一度は練習のために実装してみるべき課題ではあるが、いかにもタイミングが早すぎる。

 BNF記法そのものがわかりにくい記法であり、この評はその通りだと思う。ただ、私は、大学の授業でBNF記法を(演習付きで)勉強し、PL/Iという今では古語に近いプログラミング言語で数式のパーサーを書いた経験があるので、面白く読むことができた。特に、C++のクラス定義のありがたさが、よくわかる題材であった。

 練習問題4を引用する。

 Joe 17、Barbara 22のように、最初に名前とスコアの組み合わせを入力させるプログラムを作成する。文字列と値を保持するName_valueクラスを定義する。vector<Name_value>を使用し、名前をスコアvectorに追加する。名前がそれぞれ一意であることを確認し、重複する名前が入力された場合はエラーメッセージを出して終了する。名前とスコアの組は1行に1つづつ出力する。

 私の回答は、下記の通り。

#include "../../std_lib_facilities.h"

int main()

try {
    class Name_value {
    public:
        string name;
        int score;
    };

    vector<Name_value> list;

    while (true) {
        Name_value input;

        cout << "人名とスコアを入力してください。データの終わりはNoName 0です\n";
        cin >> input.name >> input.score;

        if (!cin) {
            cerr << "入力に間違いがありました\n";
            return 1;
        }

        if ((input.name == "NoName") && (input.score == 0)) {
            if (list.size() == 0)
                cout << "データが入力されていません\n";
            else
                cout << "各人のスコアは:\n";

            for (int i = 0; i < list.size(); ++i) {
                cout << list[i].name << ":" << list[i].score << "\n";
            }
            return 0;
        }

        for (int i = 0; i < list.size(); ++i) {
            if (list[i].name == input.name) {
                cout << "人名が重複しています\n";
                return 1;
            }
        }
        list.push_back(input);
    }
}
catch(runtime_error& e) {
    cerr << "runtime error: " << e.what() << "\n";
    return 1;
}

 

 前の章でエラーを勉強したので、今回からtry、catchの組み合わせでコーディングすることにした。
 回答例http://www.stroustrup.com/Programming/Solutions/Ch6/e6-4.cppと比べると、回答例の方がはるかにシンプルである。このあたりは、練習問題で、どこまでエラー処理をするかというところで異なる。
 私は、エラーメッセージをcerrへ吐き出して、return 1で終わるというコードを書いているが、includeしている定義でerror関数を呼べばいいので、ここは簡略化されるので、次回からは、そうしよう。