「プログラミング言語を作る」ソースコードバグ情報

このページは、拙著「プログラミング言語を作る」技術評論社 ISBN978-4-7741-3895-4 におけるプログラムソースのバグ情報です。


2022/07/24 エラーメッセージにおける>, >=, <, <=の表示がおかしい

util.cのget_operator_string()が返す文字列が間違っていて、エラーメッセージにおける>, >=, <, <=が間違った文字になっていました(すべて、>と<が逆転していた)。

本件はTwitterにてご報告いただきました。


2022/07/23 配列リテラルが頭カンマを許している

crowbar_bookの0.2〜0.4およびdiksam_bookの0.2〜0.4において、文法が、以下のように配列の先頭にカンマが来るソースを許していました。

a = [, 1, 2, 3];

しかし、実際にこういうソースを動かそうとするとコアを吐いて死にます。

expression_listが空を許さないようにして修正しました。

本件はTwitterにてご報告いただきました。


2022/07/23 埋め込みアクションでcatch_clauseに型指定がないというエラー

以前、blockの埋め込みアクションについて、型指定がないというエラーが起きていました。正誤表の以下の項目です。

http://kmaebashi.com/programmer/devlang/book/seigo.html#p206

私のところではなぜか動いていたのですが、今回再ビルドしたところ環境が新しくなったせいかエラーになるようになったようで、他の箇所(catch_clauseのところ)に同様の問題があることが発覚しました。


2022/07/03 crowbarの0.1〜0.3でcontinueが外側のループに漏れ出てしまう

crowbar_bookの0.1〜0.3では、execute_for_statement()等に以下のような実装がありました。

if (result.type == RETURN_STATEMENT_RESULT) {
    break;
} else if (result.type == BREAK_STATEMENT_RESULT) {
    result.type = NORMAL_STATEMENT_RESULT;
    break;
}

ループの中にreturnbreakがあった時の処理です。continueについて何も書いてありませんが、continueの場合ループ自体はそのまま継続するので、特に何も書かなくても一応は動きます。

ただ、ループが終わった後でresult.typeCONTINUE_STATEMENT_RESULTのままになってしまっているので、これが外側のループに漏れ出して、外側のループでもcontinueされてしまいます。以下のように、result.typeNORMAL_STATEMENT_RESULTに書き換えておかないといけません。

if (result.type == RETURN_STATEMENT_RESULT) {
    break;
} else if (result.type == BREAK_STATEMENT_RESULT) {
    result.type = NORMAL_STATEMENT_RESULT;
    break;
} else if (result.type == CONTINUE_STATEMENT_RESULT) {
    result.type = NORMAL_STATEMENT_RESULT;
}

0.4は、ラベルの機能を入れたおかげでcontinueに対する処理が入っており、このバグはありませんでした。

本件はTwitterにてご報告いただきました。


2013/12/08 crowbarのinterface.cにおける無駄なコード

crowbar_bookの0.2以降のinterface.cには、以下の関数があります。

static void
release_global_strings(CRB_Interpreter *interpreter) {
    while (interpreter->variable) {
        Variable *temp = interpreter->variable;
        interpreter->variable = temp->next;
    }
}

このプログラムは、ループしながらinterpreter->variableを書き換えていますが、 最終的にはinterpreter->>variableはNULLになるだけですので、 単純に「interpreter->variable = NULL;」と書くのと同値です。 そしてその処理は呼び出し側のCRB_dispose_interpreter()でも行っているので、 この関数自体が意味を持ちません。

どうも、こうなってしまった原因は、 crowbarのver.0.1の参照カウンタ使用版における以下の関数にあるようです。

static void
release_global_strings(CRB_Interpreter *interpreter) {
    while (interpreter->variable) {
        Variable *temp = interpreter->variable;
        interpreter->variable = temp->next;
        if (temp->value.type == CRB_STRING_VALUE) {
            crb_release_string(temp->value.u.string_value);
        }
    }
}

この時点では、連結リストで管理しているグローバル変数を順に確認し、 文字列だった場合は文字列の領域を開放する、という処理が必要でした。

ver.0.2以降はmark&sweep式のGCを導入しましたので、 interpreter->variableをNULLにしたうえでcrb_garbage_collect()を 呼び出せばこのような処理は不要です(そして実際にそのようにしています)。

ver.0.1を修正して0.2を作るとき、 コンパイルエラーになるところだけ削って無駄な関数を残してしまったようです。


2013/12/08 realloc()するスタック領域をネイティブ関数に渡している

これは、crowbar, Diksamの両方にある問題です。

ver.0.2以降のcrowbarおよびDiksamでは、 スタックをrealloc()で伸長しています。 そして、ネイティブ関数を呼び出す際、 スタック配列の要素へのポインタをネイティブ関数にそのまま渡してしまっているので、 さらにrealloc()によりスタックが拡張されたときには アドレスが変わってしまう可能性があります。

ネイティブ関数の中でスタックが伸びることがあるのかというと、 crowbar/Diksamともに、ネイティブ関数内からcrowbarまたはDiksamの 関数を呼び出す手段を提供しているので、 (頻度はともかく)問題が起きる可能性があります。

すみませんが、当方ではすぐには直せそうにありません。 具体的な修正方法については こちらの掲示板の議論も参考にしてください。


書籍情報のページに戻る | 著者のWebページトップはこちら

ご意見、ご質問、不具合連絡等は掲示板にお願いいたします。