「やさしいLispの作り方」サポートページ

 この度は拙著「やさしいLispの作り方」をお買い求めいただきありがとうございました。
出版後にタイプミスが見つかりましたので、ご連絡いたします。ご迷惑をおかけして申し訳ありません。

2016年2月21日 C言語ソースがタブとスペースが混在していて見難いことからすべてスペースに変換したもの
に修正し、再度アップロードしました。内容に変更はありません。

現在、見つかっている間違いは以下の通りです。

第2講S式の正体
誤 例えば(+ 1 2)というS式をこの構造体配列に格納すると次の図のようになります。
正 例えば(1 2 3)というS式をこの構造体配列に格納すると次の図のようになります。

図と説明物が食い違っていました。

第3講急がば回れ
誤 typedef enum toktype {LPAREN,RPAREN,QUOTE,DOT,NUMBER,SYMBOL,OTHER}
正 typedef enum toktype {LPAREN,RPAREN,QUOTE,DOT,NUMBER,SYMBOL,OTHER} toktype;
toktype;が欠落していました。
2016年2月4日に修正後の原稿をKindleに送付し入れ替わっています。下記の点は現在修正されています。

第8講成長
oddp関数を追加するコードは次のようにしてください。

defsubr("oddp",f_oddp);

当初ここを defsubr("oddp",(int)f_oddp); としていました。これですとMacのGCCで動作しないことが判明しました。
関数ポインタの型指定を正確にし、キャストをしなくてもいいように改訂しました。
C言語ソースコードは改訂済みです。これによりWindows、Ubuntu、MacのGCCで動作することが確認できました。
書籍の本体の中で示されているコードは以前のままになっており(int)のキャストがついたままとなっていますので、ご注意ください。

出会い
誤 「僕がC言語にハマってることシズカさんがをクラスメートから聞きつけたみたいだ。」
正 「僕がC言語にハマってることをシズカさんがクラスメートから聞きつけたみたいだ。」

第4講 S式の読み取り(read)

誤 ほとんと数アトムと同じです。
正 ほとんど数アトムと同じです。

第3講 急がば回れ
誤 type 種類を示すもので次のようになっています。
正 type トークンの種類です。

第1講 Lispを動かしてみる
誤 「Fortranのに次に古い言語で」
正 「Fortranの次に古い言語で」

第2講セルの正体
誤 「C言語ですとポインタというものがあります。、」
正 「C言語ですとポインタというものがあります。」

第2講セルの正体
構造体の説明の*subrの箇所
誤 「ある部分は関数ポインタです。」
正 「この部分は関数ポインタです。」

第4講 S式の読み取り(read)
誤 「readとreadlistを読みなつつ」
正 「readとreadlistを読みつつ」

第7講 ゴミ集め
セリフ部分
誤 「僕: どいう場合なのか、想像がつきません。」
正 「僕: どういう場合なのか、想像がつきません。」

マークの説明中
途中で(g y)とい関数の計算
途中で(g y)という関数の計算

補講(eval)
ifのコードの説明の直後
誤 ほかにも(setq a 1)なんてももそうですね。
正 ほかにも(setq a 1)なんてものもそうですね。

第6講 いよいよ頭脳に着手(eval)
アトムのときのコードに無駄がありました。
if(atomp(addr)){
        if(numberp(addr))
            return(addr);
    	if(symbolp(addr)){
            res = findsym(addr);
            if(res == 0)
            	error(CANT_FIND_ERR, "eval", addr);
            else
            	switch(GET_TAG(res)){
                	case NUM:	return(res);
                	case SYM:	return(res);
                    case LIS:	return(res);
                	case SUBR:	return(res);
                    case FSUBR:	return(res);
                    case FUNC:  return(res);
                }	
        }
    }

わざわざswitch文で分ける必要はありませんでした。
以下のコードで十分です。
if(atomp(addr)){
        if(numberp(addr))
            return(addr);
    	if(symbolp(addr)){
            res = findsym(addr);
            if(res == 0)
            	error(CANT_FIND_ERR, "eval", addr);
            else
                return(res);
        }
    }
第5講 おうむ返し(print)

main関数をvoid型にしていてコンパイルできているのですが、int型にする方が望ましいです。
returnで数値を返すようにすれば-Wallで警告が出ません。
int main(void){
    printf("MonoLis Ver0.01\n");
    initcell();
    initsubr();
    int ret = setjmp(buf);
    
    repl:	
    if(ret == 0)
    	while(1){
			printf("> "); fflush(stdout); fflush(stdin);
            print(eval(read ()));
            printf("\n"); fflush(stdout);
        }
    else
    	if(ret == 1){
        	ret = 0;
            goto repl;
        }
        else
    		return 0;
}

第2講 セルの正体

initcell関数で配列領域をオーバーランしていました。
void initcell(void){
	int addr;
    
    for(addr=0; addr <= HEAPSIZE; addr++){
    	heap[addr].flag = FRE;
        heap[addr].cdr = addr+1;
    }

void initcell(void){
	int addr;
    
    for(addr=0; addr < HEAPSIZE; addr++){
    	heap[addr].flag = FRE;
        heap[addr].cdr = addr+1;
    }

全ソースコード

2016年1月30日、 アップロードされている全ソースコードを修正しました。
-Wallでウォーニングをかけていなかったため、タイプミスがありました。
原型をとどめる程度に修正をしています。