卒業決定しました

というわけで卒業決定しました。皆さんありがとうございます。

問題を起こすと卒業できなくなるので、主に @ymckamからセクハラで訴えられたら卒業できなくなります。

四年間の雑感は卒業式後に書く予定ですが、とりあえず4月からは琉球大学大学院理工学研究科情報工学専攻というところに進む予定です。あと2年間は確実に沖縄にいる予定なのでよろしくお願い致します。

www.amazon.jp

飲み会の予定は常に募集中です。よろしくお願い致します。

mac osでPerlのビルドでld関連で死ぬ時

趣味はPerlのビルドなので、plenv経由でPerl5.28.1を入れようとしたところ以下のようなエラーが発生しました。

./miniperl -Ilib make_ext.pl DynaLoader.o  MAKE="/Library/Developer/CommandLineTools/usr/bin/make" LIBPERL_A=libperl.a LINKTYPE=static CCCDLFLAGS=
Generating a Unix-style Makefile
Writing Makefile for DynaLoader
"../../miniperl" "-I../../lib" DynaLoader_pm.PL DynaLoader.pm
rm -f DynaLoader.xs
cp dl_dlopen.xs DynaLoader.xs
"../../miniperl" "-I../../lib" "../../lib/ExtUtils/xsubpp" -noprototypes -typemap '/Users/anatofuz/.plenv/build/1549952483.53003/perl-5.28.1/ext/DynaLoader/../../lib/ExtUtils/typemap'  DynaLoader.xs > DynaLoader.xsc
mv DynaLoader.xsc DynaLoader.c
cc -c   -fno-common -DPERL_DARWIN -mmacosx-version-min=10.14 -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include -DPERL_USE_SAFE_PUTENV -Wall -Werror=declaration-after-statement -Werror=pointer-arith -Wextra -Wc++-compat -Wwrite-strings -O3   -DVERSION=\"1.45\" -DXS_VERSION=\"1.45\"  "-I../.."  -DLIBC="" DynaLoader.c
rm -rf ../../DynaLoader.o
cp DynaLoader.o ../../DynaLoader.o
rm -f libperl.a
/usr/local/bin/ar rc libperl.a op.o     perl.o  gv.o toke.o perly.o pad.o regcomp.o dump.o util.o mg.o reentr.o mro_core.o keywords.o hv.o av.o run.o pp_hot.o sv.o pp.o scope.o pp_ctl.o pp_sys.o doop.o doio.o regexec.o utf8.o taint.o deb.o universal.o globals.o perlio.o perlapi.o numeric.o mathoms.o locale.o pp_pack.o pp_sort.o caretx.o dquote.o time64.o   DynaLoader.o
cc -o perl -mmacosx-version-min=10.14 -fstack-protector-strong -L/usr/local/lib  perlmain.o   libperl.a `cat ext.libs` -lpthread -ldl -lm -lutil -lc 
ld: warning: ignoring file libperl.a, file was built for archive which is not the architecture being linked (x86_64): libperl.a
Undefined symbols for architecture x86_64:
  "_PL_csighandlerp", referenced from:
      _main in perlmain.o
  "_PL_do_undump", referenced from:
      _main in perlmain.o
  "_PL_exit_flags", referenced from:
      _main in perlmain.o
  "_PL_perl_destruct_level", referenced from:
      _main in perlmain.o
  "_PL_sig_name", referenced from:
      _main in perlmain.o
  "_PL_sig_num", referenced from:
      _main in perlmain.o
  "_Perl_newXS", referenced from:
      _xs_init in perlmain.o
  "_Perl_rsignal", referenced from:
      _main in perlmain.o
  "_Perl_rsignal_state", referenced from:
      _main in perlmain.o
  "_Perl_sys_init3", referenced from:
      _main in perlmain.o
  "_Perl_sys_term", referenced from:
      _main in perlmain.o
  "_boot_DynaLoader", referenced from:
      _xs_init in perlmain.o
  "_perl_alloc", referenced from:
      _main in perlmain.o
  "_perl_construct", referenced from:
      _main in perlmain.o
  "_perl_destruct", referenced from:
      _main in perlmain.o
  "_perl_free", referenced from:
      _main in perlmain.o
  "_perl_parse", referenced from:
      _main in perlmain.o
  "_perl_run", referenced from:
      _main in perlmain.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [perl] Error 1
Installation failure: make at /Users/anatofuz/.plenv/plugins/perl-build/bin/perl-build line 10353.
ABORT

plenvやperl-buildのエラーではない(ldなのでコンパイルが走った後のエラーである)事から、Perl自体の問題ではあると思っていたので、Perlのバグのページなどを見ていました。

rt.cpan.org

(一応Mojave独自のエラーとしてはこれがあり、ヘッダーファイルをコピるdmgを実行することで回避出来るそうです)

ただbugsのページを確認していても、ld関連のバグ報告がなく、Perl入学式のslackで相談してみました。

僕以外のmojave環境では普通にビルドが通るらしく、これは...となっている時にこのエントリが発見されました。

naoyat.hatenablog.jp

見事にbinutilsをいれており、arが被り破滅していました。

ということで brew uninstall binutils して強制的に解決。

その結果見事にperl 5.28.1がビルド出来ました!!!

Perl入学式の皆さん有難うございました!!! 流石にこれは訓練されてないと気づかない...!

完全にMojaveだと疑っていましたがおま環問題でした。Appleの皆さんすいません :bow:

YAPC::Tokyo2019に参加して, 踏み出せたこと

1月25日, 26日とYAPC::Tokyoに参加しました. YAPC自体はKansaiが初参加で, Okinawaではスタッフをしていた.

今回のTokyoでは, 初めてスピーカーとして出させていただき, 当日スタッフもやらせてもらった. 更に前夜祭と本編のLTも出させていただいた.本当にYAPCを楽しむことが出来た.参加者, 運営の皆様ありがとうございます.

前夜祭

スタッフをやらせていただいていたので早めに会場について, ノベルティの荷物詰めなどをしていた. 初めて実際にお会いする方が多かったが, 会場の雰囲気は非常に楽しくて, 疲れはしたが準備をする事が出来た.

前夜祭の資料は大体の枠組みは行きの飛行機と前日に書いていた. 今回は大学の卒業研究などを通して勉強していたMoarVMとNQP(Perl6の実行環境とサブセットの話)で登壇した.

NQP自体はPerl6の内部で利用されているもので, 皆さんの興味がNQPに向くか非常に不安だった. 登壇が終わったあとにid:papixさんから, 「本編に出れる」と言われた時は嬉しかったし, Twitterを見た感じ皆さんに楽しんでいただいたようで非常に良かった.

前夜祭では他にはてなインターン振りにid:cohalzさんとお会い出来たのが良かった. 思えばあの時から, YAPC::Tokyoが前を向かせて貰ったのだと思う.

本編

本編はRoom1の会場の司会などを担当していた.Twitterの中の人もしようかなと思っていたが, 資料を準備したかったのと, 写真を綺麗に取る自信があまり無かったので, Twitterはお願いしていた.

司会は本当にやりやすくて, 自由に喋る事が出来た.司会自体はそんなに上手くなかったかもしれないが, YAPCのスタッフとして関わる事が出来ていたのは嬉しかった. Okinawaの時はコアスタッフだったのだが, 精神を崩していた時期もあり, 本調子で振る舞う事が出来なかった気がする. 今回のYAPCは, しっかり責務を果たせたかなと思った.

初めての登壇は不思議と緊張しなかった.あのRoom1, そしてYAPCの会場が非常に温かい雰囲気であり, 心地よく喋る事が出来た. このスライドに至る前に, ビルドを追求していくにつれてmetaconfigを発見したりと非常に面白かった.

5分前のベルでペース配分を焦ってしまったのが心残りではあるが, 自分としては大体したかったことが出来たと思う. あのスライドは本当に皆さんに興味を持っていただけるか自信がなく, 当日人がくるかどうかも心配していた. いざ時間になると, 本当に皆さん移動し忘れているのではないかと思うほど来ていただいて, トークを聞いてくださっていた. トークの内容も, 皆さんツイートしていただいたり, 途中で盛り上がっていただいたりと, 本当に自分自身も信じられないほどだった.

本当にこれは自分自身だけが面白いと感じているのではないかとずっと思っていた. Roppongi.pmにも呼んでいただいたので, 今考えると周囲の方々も面白いと思っていただいていたと思うのだけれど, あの内容は個人的には誰でも出来ると思ってしまっていて, そんなことを発表していいのかとちょっと思ったりもしていた.

そして登壇して, 席に戻って, タグを見たり, その後の懇親会や二次会, スライドを公開した上でのSNSなどで, 本当に意外なまでに皆さんに好評的な評価を頂いた. これは本当に自分も信じられなくて, その後miyagawaさんにまでNiceなどと言われて, 本当にこれが自分自身に起こっている事なのか信じられなかった. 僕だけが楽しいと思っていた事が, 皆さんにも楽しいと伝わったこと.本当に信じられない気持ちだった.

LTではgolangにPerl1.0を書き換えている話をした.これ自体は結構前から思いついていて, 実際に手を動かし始めたのはYAPCのLTに応募してからだった.

書いてみるとPerl1.0の内部構造がトレースのたびに理解出来るようになった気がして, 非常に楽しく夢中になれた. 当日までに動かすものを作りたかったが, なかなか厳しくて, ふわっとした話になってしまったのは反省している. ただ年内には出せるようにしたいので, 今後も開発していこうと思った. これも, ふわっとした話なので, そんなに評価されないかななどと思っていたが, Twitterを見ると様々な人に言及されていて嬉しかった.

懇親会ではいろいろな人とお会いする事が出来た.YAPCの参加回数が増えている為知り合いが増えてきたのもある気がする. 個人的には皆さんPerl1.0の話とか, Acmeモジュールの話やPerl6と言った好きな話題をする事が出来て, ありがたかった. id:utgwkkさんと初めてリアルで会えたのもいい体験だった.

不思議な感覚は他にもあった.id:ssabcireくんにTwitterで見ていて影響を受けたとか, 入学式の鹿さんに助けてもらったとか, id:kiryuanzuさんにエントリを見たとか言われた. 個人的にはそんなに頑張ってないし, やっているつもりも無かったのだが, そう言っていただけると嬉しかったし, 同時に何か不思議な気持ちになった.

その後は以前のエントリにも書いたが, id:papixさんに自信を持てと言われて, 運営の打ち上げの後に, 秋葉原で飲んでいた皆さんと合流した. id:mackee_wさんやid:xtetsujiさんが待っていただいたのが嬉しかった.

飲み会id:kiryuanzuさんと話しているうちに, 自分が本当に好きだったこと, 大切にしたい事が思い出せたように感じる. そこで, 思い出せた事は, YAPC::Kansaiの時のあの純粋な好奇心と, 自分が好きなことをする気持ちだった. YAPC::Okinawaやハッカーズチャンプルー, いつもの.pmなどで, 少しずつ取り戻しつつあった, 大切な感覚が取り戻せたと思っている. なんというか, 本当に肩の荷が下がり, 気持ちよくプログラミングや情報技術に迎える様になった.

今回のテーマは「報恩謝徳」だった.本当に今回のYAPC::Tokyoでは皆さんから恩をいただく事が出来た. 本当に, 楽しかった以外の感想がないほど楽しかったし, やっていくぞと, 本当に思うことが出来た. Perlコミュニティの皆さんにはいつも助けられてばかりだし, id:papixさんに至っては, 様々な意味でいつも励まされている. 沖縄でPerlを始めるきっかけとなったid:codehexさんとまたお会い出来たし, 本当に様々な人に支えられているんだなと感じた. この恩をいつか返せるように, そして新しくPerlYAPCに出会った方に, 僕がしていただけたことを逆に出来るように, 今後もやっていきたいと思った.

そういえばいつもYAPCに行くと元気になる気がする.やはりYAPCは人生を変えると思う.YAPC::Kansaiに行ってなければPerlを書いていなかったが, YAPC::Tokyoに行ってなければ, 今後Perlを書いてなかった気がする.

なんとなく同じ内容になってしまったが, まぁいいとして...

YAPC::Tokyo2019で感じたこと

(感想は別で書く予定で, これはYAPCを通じて考えたエモい話です)

最近(1年くらい)は好きなことに対して自信が持てなかった気がする. YAPC::Kansaiの時などは, 勉強したてのPerlAcmeモジュールが好きで, 書いているAcmeモジュールのロジックがコピペだろうと正直作っているだけで楽しかった. 最近の精神状態では, 意味を理解しないとロジックを書くべきではないとか思ってしまって多分書いてなかった気がする. Perlを書くこと.Acmeモジュールを使ったり読むこと.Perlの本を読んで勉強すること. その全てが純粋に楽しくて,その習得状況や書くコードの質などの差は確かにあるかもしれないが, それには本来優劣などは存在しない行為だと思う. 誰かと戦う為にジョークモジュールを作ることはないし, 何か強制的にコードを書く必要も本来はなかった. 純粋に楽しいからしていて,ただそれだけが活動のベースにあったのだと思う.

しかし最近は, 何をやっても.ことさら好きなはずのコンピュータのことでは, 人と比べることや, その意味を考えるようになってしまった. 「これを勉強してもxxxさんはすでに高校時代に実装していたんだよなぁ...」とか「こんな駄目なコードしか僕は書けないのに,xxxさんはこんなにもOSSを書いたりしている...」とかとかとか. 能力の差や技術力の差は確かに存在している.バズるサービスを開発する能力や, 綺麗なウェブページを作る能力, 難しい言語処理系のシステムを臆すること無くCで実装する事が出来る能力. それらを持っている人と, それらが今すぐに欲しくなってしまって, 自分の現状と比べて辛くなる事が多くなってしまった.

確かにPerlはずっと書いていたが, 最近書くPerlは楽しんで書くというよりは, 何かの為に書く事が多い気がしていた. 最初Perlを勉強した時にがむしゃらに書いていた, あのときの楽しさは無かった気がする.

YAPC::Tokyoのしばらく前, Roppongi.pmの前の時に, 何故か昔のPerlをビルドすることをしていた. 最初は唐突にPerlの初期バージョンに興味がわき, ぐぐったらコードがビルドできたのでおもちゃの様に遊んだ. 詳しくは覚えていないのだが, LTのネタに使えるかなと思ってやったかもしれない.

あの時.昔のPerlをビルドしている時は, 今考えるとKansaiのあの時に, Acmeモジュールを書こうと思って苦戦していた際の精神状況に似ていた気がした. そのコードややる事の意味などはどうでもよく,ただ個人的にやりたいからやっていた.面白そうだから.ただそれだけの純粋な理由だった.

思ったことはそう.僕は例えば何かのサービスを作らなければならないとか.早くしなければならないとか.そういう使命感みたいなのが動作すると途端に気力が無くなってしまうという性質なのかもしれないということだ. 最近webアプリを書く事が以前に比べて好きになれなかったのだが, 考えると, webの勉強をしなければならないという使命感が常につきまとい, その結果重くのしかかった気持ちに純粋な好奇心が負けてしまい, 死んでいたのだと思う.

好きなことは自由な時に自由にやりたい.それが仕事で出来るかはわからないが, 多分僕はそういう感じで技術とか変わっていくのが良い気がしていた.当然やらなければならないドリブンでせざるを得ないものもあるし, そういう時は多少辛くなると思っている.

しかし今思っているのは, そのやろうとしている事が本心で, 純粋な気持ちで面白いと思っているかどうかが重要だということだ. そしてその気持ちに優劣などはなくて, 好きなことは誰との比較も承認も必要なく, 好きと言い張って良いということだ. 好きなもので好きなことを好きようにやる.人生そううまくは行かないし, 業務の内容が好きかどうかなどは必ずすべてがそうではないと思う. だけれども, 自分自身の趣味の時間とか, やっていきたい気持ち自体は, 自分自身で認めていきたいと思った. やはり自分が本当に面白いと思っていることは, 人に喋っていて面白さが伝わるし, みんなに気持ちが伝わると思う. おそらく, 今まで僕が見てきたwebとかのすごい学生や人々は, その純粋な気持ちがたまたまwebに向いていただけで, 彼らは純粋な気持ちを持っている為に優劣などを考える事はなくて, 成長していけているのだと思う.

今は自分自身が何が面白いのか, 取り戻すのと掴むのに時間を要すると思っている. しかしその時間を焦る事をせず, 人々と比べずにやっていきたいと思った.

この考え方に追いついたのは, 個人的に自分だけが楽しいと思っていた昔のPerlをビルドする話をYAPCに採択していただいたこと.

当日のトークで, 自分が面白いと思った事に, 来ていただいた皆さんが同じ様に面白いと思って頂いた事.

id:papixさんに自信を持てと言われたこと, その後の飲み会で id:kiryuanzuさんと過去の話から様々なことを話せた事.

Twitterやブログで予想外に様々な人々から反響をいただいた事などがつながったからだと思う.全員のidを乗せるとすごい事になってしまうので書けないのですが, 北海道から沖縄, 海外や画面の向こうの人まで, 本当に皆さんありがとうございます.

YAPC::Tokyoでは3本も前に出させてもらった.どれも楽しかった.これはこの3本がすべて自分が面白いと思っていた事だからだと思う. 純粋な気持ちで面白いと思える事が, 僕は特にPerlに多いようだ.自分自身気づかなかったが, 好きなことを話している事はかなり楽しそうらしい. 今までのやらなければならないベースの考え方を脱却するのは人間なので難しいのだが, だけれども, 少しずつ純粋な気持ちを取り戻したいと思った.

完全にとりとめのないが, とりあえず今まとめとかないと駄目だと思ったのでまとめておいた.YAPCの感想はあとで書きます

継続を基本とするC言語CbCのご紹介

この記事は琉大情報工学科(知能情報コース) Advent Calendar 2018 の16日目の記事です.

どうせなのでCasl2のエミュレーターでも書くかという気になりましたが,今日はドラゴンボールを見てしまったのでエミュレーターは途中までとなりました.ご了承下さい.

さて今日は一部界隈でまことしやかに盛り上がっている謎の言語CbCことContinuation Based Cについての話です. ただしCbCは沼なので間違えている可能性があります.サイレント修正される可能性がありますがご了承下さい.

Continuation Based Cとは

Continuation Based C(以下CbC)とは継続を基本としたC言語の下位言語です. C言語での関数呼び出しやfor文などのループ文をコードから消滅させ, 状態遷移単位でコードを書くことが出来る言語です. 応用例としては世界最速のgrepやGearsOS, Perl6処理系のCbCMoarVMなどが存在します.

現在はgcc及びllvm/clang上に実装した2種類が存在します.

C言語を使ってプログラミングをする場合,メモリのアロケートやエラーハンドリングなどを記述していく必要があります. しかしこの処理は複雑かつエラーを発生させやすい為,通常の処理と分離して記述することが望ましいとされます. これらの処理をMetaComputationと呼びます. しかしC言語を使ったプログラミングである程度規模が大きいものを行おうとすると,これらの処理と通常の計算処理を分離して記述することは非常に難しいとされます.

CbCでは,関数の代わりにCodeSegmentとDataSegmentを基本単位として導入する事で,これらをやりやすくします.

CodeSegment

CbCでは関数の代わりにCodeSegmentを利用します.

CodeSegmentは関数よりも小さく,ステートメントよりも大きい単位となっています. CodeSegmentを利用したCbCではループ文を持ちません. これはCodeSegmentがコンパイラにおける基本ブロックと呼ばれる単位に該当する為です.

CodeSegmentはCの関数の代わりに __code と書くことで宣言出来ます. これは __code という型が有るわけではなく, CbCプログラマからはCodeSegmentである事を示す指示子の様な役割を果たします.

__code 自体はCbCコンパイラではvoid型として扱います.

CodeSegmentからCodeSegmentへはCのgoto文を利用して遷移します. この遷移はCの関数呼び出しとは異なり,callなどの命令を利用せずjmpを利用した軽量継続で行います. 実際にコード例を見てみましょう.

extern int printf(const char*,...);
  int main (){
     int data = 0;
     goto cg1(&data);
  }
  __code cg1(int *datap){
(*datap)++;
    goto cg2(datap);
}
__code cg2(int *datap){
    (*datap)++;
    printf("%d\n",*datap);
}

このコードはmain関数で設定した data = 0 をcg1と言うCodeSegmentに入力として渡します. この時点ではCの世界からCbCの世界に突入する段階ですので, cg1自体はcallで呼び出されます.

cg1では受け取ったdataのアドレスからdataをインクリメントし data = 1 にします. インクリメントの後 cg2 に軽量継続します. cg2では同様にdataをインクリメントし, printするという流れです.

#include <stdio.h>

__code fact(int n, int result,__code (*print)()) {
    if (n > 0) {
        result *= n;
        n--;
        goto fact(n,result,print);
    } else {
        goto (*print)(result);
    }
}

__code print_result(int result){
    printf("result is %d\n",result);
}

int main(int argc, char** argv){
    goto fact(20,0,print_result);
}

他には上記のような階上を求めるコードも書くことが可能です. fact(int n, int result,__code (*print)()) の引数として __code のCodeSegment自体を渡しています.

この様にCodeSegmentの引数にはCodeSegment自体もいれることが可能です. この引数の事をDataSegmentもしくはInterfaceと呼びます. なぜ引数ではなくDataSegmentと呼称するかについては後述します.

軽量継続とは

先程から何回か出ている軽量継続とは何でしょうか. 軽量継続ではなく,継続とはSchemaなどの処理系には実装されています.

Wikipediaによると

継続は、前の状態を引き継ぐこと。持続、保持。 計算機科学における継続(けいぞく、continuation)とは、プログラムの実行においてある時点において評価されていない残りのプログラム(the rest of the program)を意味するものであり、手続き(procedure)として表現される

https://ja.wikipedia.org/wiki/%E7%B6%99%E7%B6%9A

詳しくは http://practical-scheme.net/docs/cont-j.html

つまり,CbCではCレベルで次の処理の命令をよりSchemaなどの関数型言語のように記述することが出来るインターフェイスを提供します. この際にSchemaなどでは,現在の位置などを環境として保存する必要がありますが, CbCの場合そのあたりを保存しない為軽量な継続,つまり軽量継続と読んでいます.

うれしいところ

Cで軽量継続を使えると何が嬉しいのでしょうか. それはCの関数呼び出しがコストがかかる事がまず挙げられます.

Cの関数呼び出しでは, 呼び出し側は引数を積み上げ,戻り番地のセーブを行い, 呼び出される方は局所変数を保存したり,スタックやフレームポインタを押し上げるなどの処理が必要となります. これらを一切行わず,プログラムカウンタを変更するのみのjmp命令にCbCのgotoを利用したCodeSegmentは変換する事が可能です.

その為CodeSegmentを直接指定してgotoするなどの処理が書けるようになり,煩わしいfor文やcase-switch文をなくすことが可能です

Cでも末尾再帰と呼ばれる方法を利用すればこの方法が可能であり,実際CbCは内部的に末尾再帰アルゴリズムを用いて最適化しています.

その為, CodeSegmentのDataSegment部分を同じにする事で,全ての命令がjmp命令にコンパイルされます. jmp命令になるということは,CodeSegment間の引き渡しで引数がレジスタに乗ったまま移動されるということです.最高ですね.

つまりCodeSegmentの引数は入力のみではなく入出力としての意味を持つ為,引数ではなくData SegmentやInterfaceという呼び方をしています.

FizzBuzz

試しにFizzBuzzを書いてみます

#define __environment _CbC_environment
#define __return _CbC_return

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

__code fizzbuzz(int,int,char*,__code(),void*);
__code say2(int,int,char*,__code(),void*);
__code fizz(int,int,char*,__code(),void*);
__code buzz(int,int,char*,__code(),void*);

int main(void){
    int n = 100;
    fizzbuzz(1,n,"",__return,__environment);
    return 0;
}

__code fizzbuzz(int i,int n,char* ret_result,__code(*return1)(),void *return1env) {
    if ( i <= n ) {
        goto fizz(i,n,ret_result,return1,return1env);
    } else {
        goto return1(0,return1env);
    }
}


__code fizz(int i,int n,char* ret_result,__code(*return1)(),void *return1env) {
    if (i % 3 == 0){
        ret_result = "fizz";
    } else {
        ret_result = "";
    }
    goto buzz(i,n,ret_result,return1,return1env);
}

__code buzz(int i,int n,char* ret_result,__code(*result1)(),void *return1env) {
    char *result;
    result = (char *)malloc(15);
    if (i % 5 == 0){
        snprintf(result,9,"%s%s",ret_result,"buzz");
    } else {
        snprintf(result,8,"%s",ret_result);
    }
    goto say2(i,n,result,result1,return1env);
}

__code say2(int i,int n,char* ret_result,__code(*return1)(),void *return1env) {
    if ( ret_result[0] == '\0'){
        printf("%i : %i\n" ,i,i);
    } else {
        printf("%i:%s\n",i,ret_result);
    }
    goto fizzbuzz(i+1,n,"",return1,return1env);
}

CbCっぽく書くコツはDataSegmentをそろえる事です.

これを-Sをつけてアセンブラを見てみましょう.

cbclang -S fizzbuzz.cbc

 .section  __TEXT,__text,regular,pure_instructions
    .macosx_version_min 10, 14
    .globl    _main..ret0             ## -- Begin function main..ret0
    .p2align  4, 0x90
_main..ret0:                            ## @main..ret0
    .cfi_startproc
## %bb.0:                               ## %entry
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq (%rsi), %rax
    movl %edi, (%rax)
    movq 8(%rsi), %rax
    movq (%rax), %rbp
    movq 8(%rax), %rsi
    movq 16(%rax), %rsp
    jmpq *%rsi
    .cfi_endproc
                                        ## -- End function
    .globl    _main                   ## -- Begin function main
    .p2align  4, 0x90
_main:                                  ## @main
    .cfi_startproc
## %bb.0:                               ## %entry
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq %rsp, %rbp
    .cfi_def_cfa_register %rbp
    pushq    %r15
    pushq    %r14
    pushq    %r13
    pushq    %r12
    pushq    %rbx
    subq $264, %rsp              ## imm = 0x108
    .cfi_offset %rbx, -56
    .cfi_offset %r12, -48
    .cfi_offset %r13, -40
    .cfi_offset %r14, -32
    .cfi_offset %r15, -24
    leaq -208(%rbp), %rax
    leaq -252(%rbp), %rcx
    leaq _main..ret0(%rip), %rdx
    movq ___stack_chk_guard@GOTPCREL(%rip), %rsi
    movq (%rsi), %rsi
    movq %rsi, -48(%rbp)
    movl $0, -212(%rbp)
    movl $100, -216(%rbp)
    movl -216(%rbp), %esi
    movq %rdx, -224(%rbp)
    movq -224(%rbp), %rdx
    movq %rdx, -232(%rbp)
    movq -232(%rbp), %rdx
    movq %rcx, -248(%rbp)
    movq %rax, -240(%rbp)
    movq -240(%rbp), %rax
    movq %rax, %rcx
    movq %rbp, %rdi
    movq %rdi, (%rax)
    movq %rsp, %rdi
    movq %rdi, 16(%rax)
    leaq LBB1_8(%rip), %rax
    movq %rax, 8(%rcx)
    movl %esi, -268(%rbp)        ## 4-byte Spill
    movq %rdx, -280(%rbp)        ## 8-byte Spill
    #EH_SjLj_Setup LBB1_8
## %bb.6:                               ## %entry
    xorl %eax, %eax
    movl %eax, -284(%rbp)        ## 4-byte Spill
LBB1_7:                                 ## %entry
    movl -284(%rbp), %eax        ## 4-byte Reload
    movq -240(%rbp), %rcx
    movq %rcx, %rdx
    movq %rbp, %rsi
    movq %rsi, (%rcx)
    movq %rsp, %rsi
    movq %rsi, 16(%rcx)
    leaq LBB1_11(%rip), %rcx
    movq %rcx, 8(%rdx)
    movl %eax, -288(%rbp)        ## 4-byte Spill
    #EH_SjLj_Setup LBB1_11
## %bb.9:                               ## %entry
    xorl %eax, %eax
    movl %eax, -292(%rbp)        ## 4-byte Spill
LBB1_10:                                ## %entry
    movl -292(%rbp), %eax        ## 4-byte Reload
    cmpl $0, %eax
    je   LBB1_2
## %bb.1:                               ## %if.then
    movl -252(%rbp), %eax
    movl %eax, -212(%rbp)
    jmp  LBB1_3
LBB1_2:                                 ## %if.end
    leaq -248(%rbp), %rax
    movq %rax, -264(%rbp)
    movq -264(%rbp), %rax
    leaq L_.str(%rip), %rdx
    movl $1, %edi
    movl -268(%rbp), %esi        ## 4-byte Reload
    movq -280(%rbp), %rcx        ## 8-byte Reload
    movq %rax, %r8
    callq    _fizzbuzz
    subq $8, %rsp
    movl $0, -212(%rbp)
LBB1_3:                                 ## %return
    movl -212(%rbp), %eax
    movq ___stack_chk_guard@GOTPCREL(%rip), %rcx
    movq (%rcx), %rcx
    movq -48(%rbp), %rdx
    cmpq %rdx, %rcx
    movl %eax, -296(%rbp)        ## 4-byte Spill
    jne  LBB1_5
## %bb.4:                               ## %SP_return
    movl -296(%rbp), %eax        ## 4-byte Reload
    addq $264, %rsp              ## imm = 0x108
    popq %rbx
    popq %r12
    popq %r13
    popq %r14
    popq %r15
    popq %rbp
    retq
LBB1_5:                                 ## %CallStackCheckFailBlk
    callq    ___stack_chk_fail
LBB1_8:                                 ## Block address taken
                                        ## %entry
    movl $1, %eax
    movl %eax, -284(%rbp)        ## 4-byte Spill
    jmp  LBB1_7
LBB1_11:                                ## Block address taken
                                        ## %entry
    movl $1, %eax
    movl %eax, -292(%rbp)        ## 4-byte Spill
    jmp  LBB1_10
    .cfi_endproc
                                        ## -- End function
    .globl    _fizzbuzz               ## -- Begin function fizzbuzz
    .p2align  4, 0x90
_fizzbuzz:                              ## @fizzbuzz
    .cfi_startproc
## %bb.0:                               ## %entry
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq $48, %rsp
    cmpl %esi, %edi
    movl %esi, -4(%rbp)          ## 4-byte Spill
    movq %r8, -16(%rbp)          ## 8-byte Spill
    movq %rcx, -24(%rbp)         ## 8-byte Spill
    movq %rdx, -32(%rbp)         ## 8-byte Spill
    movl %edi, -36(%rbp)         ## 4-byte Spill
    jg   LBB2_2
## %bb.1:                               ## %if.then
    movl -36(%rbp), %edi         ## 4-byte Reload
    movl -4(%rbp), %esi          ## 4-byte Reload
    movq -32(%rbp), %rdx         ## 8-byte Reload
    movq -24(%rbp), %rcx         ## 8-byte Reload
    movq -16(%rbp), %r8          ## 8-byte Reload
    addq $48, %rsp
    popq %rbp
    jmp  _fizz                   ## TAILCALL
LBB2_2:                                 ## %if.else
    xorl %eax, %eax
    movb %al, %cl
    movl %eax, %edi
    movq -16(%rbp), %rsi         ## 8-byte Reload
    movb %cl, %al
    movq -24(%rbp), %rdx         ## 8-byte Reload
    callq    *%rdx
    addq $48, %rsp
    popq %rbp
    retq $8
    .cfi_endproc
                                        ## -- End function
    .globl    _fizz                   ## -- Begin function fizz
    .p2align  4, 0x90
_fizz:                                  ## @fizz
    .cfi_startproc
## %bb.0:                               ## %entry
    subq $56, %rsp
    .cfi_def_cfa_offset 64
    leaq L_.str.1(%rip), %rax
    movl $3, %edx
    movq %rax, 48(%rsp)          ## 8-byte Spill
    movl %edi, %eax
    movl %edx, 44(%rsp)          ## 4-byte Spill
    cltd
    movl 44(%rsp), %r9d          ## 4-byte Reload
    idivl    %r9d
    cmpl $0, %edx
    movq 48(%rsp), %r10          ## 8-byte Reload
    movl %esi, 40(%rsp)          ## 4-byte Spill
    movq %r8, 32(%rsp)           ## 8-byte Spill
    movq %rcx, 24(%rsp)          ## 8-byte Spill
    movl %edi, 20(%rsp)          ## 4-byte Spill
    movq %r10, 8(%rsp)           ## 8-byte Spill
    je   LBB3_2
## %bb.1:                               ## %if.else
    leaq L_.str(%rip), %rax
    movq %rax, 8(%rsp)           ## 8-byte Spill
    jmp  LBB3_2
LBB3_2:                                 ## %if.end
    movq 8(%rsp), %rax           ## 8-byte Reload
    movl 20(%rsp), %edi          ## 4-byte Reload
    movl 40(%rsp), %esi          ## 4-byte Reload
    movq %rax, %rdx
    movq 24(%rsp), %rcx          ## 8-byte Reload
    movq 32(%rsp), %r8           ## 8-byte Reload
    addq $56, %rsp
    jmp  _buzz                   ## TAILCALL
    .cfi_endproc
                                        ## -- End function
    .globl    _buzz                   ## -- Begin function buzz
    .p2align  4, 0x90
_buzz:                                  ## @buzz
    .cfi_startproc
## %bb.0:                               ## %entry
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq $64, %rsp
    movl $15, %eax
    movl %eax, %r9d
    movl %edi, -4(%rbp)          ## 4-byte Spill
    movq %r9, %rdi
    movl %esi, -8(%rbp)          ## 4-byte Spill
    movq %r8, -16(%rbp)          ## 8-byte Spill
    movq %rcx, -24(%rbp)         ## 8-byte Spill
    movq %rdx, -32(%rbp)         ## 8-byte Spill
    callq    _malloc
    movl $5, %esi
    movl -4(%rbp), %r10d         ## 4-byte Reload
    movq %rax, -40(%rbp)         ## 8-byte Spill
    movl %r10d, %eax
    cltd
    idivl    %esi
    cmpl $0, %edx
    jne  LBB4_2
## %bb.1:                               ## %if.then
    movl $9, %eax
    movl %eax, %esi
    xorl %edx, %edx
    movl $15, %eax
    movl %eax, %ecx
    leaq L_.str.2(%rip), %r8
    leaq L_.str.3(%rip), %rdi
    movq -40(%rbp), %r9          ## 8-byte Reload
    movq %rdi, -48(%rbp)         ## 8-byte Spill
    movq %r9, %rdi
    movq -32(%rbp), %r9          ## 8-byte Reload
    movq -48(%rbp), %r10         ## 8-byte Reload
    movq %r10, (%rsp)
    movb $0, %al
    callq    ___snprintf_chk
    movl %eax, -52(%rbp)         ## 4-byte Spill
    jmp  LBB4_3
LBB4_2:                                 ## %if.else
    movl $8, %eax
    movl %eax, %esi
    xorl %edx, %edx
    movl $15, %eax
    movl %eax, %ecx
    leaq L_.str.4(%rip), %r8
    movq -40(%rbp), %rdi         ## 8-byte Reload
    movq -32(%rbp), %r9          ## 8-byte Reload
    movb $0, %al
    callq    ___snprintf_chk
    movl %eax, -56(%rbp)         ## 4-byte Spill
LBB4_3:                                 ## %if.end
    movl -4(%rbp), %edi          ## 4-byte Reload
    movl -8(%rbp), %esi          ## 4-byte Reload
    movq -40(%rbp), %rdx         ## 8-byte Reload
    movq -24(%rbp), %rcx         ## 8-byte Reload
    movq -16(%rbp), %r8          ## 8-byte Reload
    addq $64, %rsp
    popq %rbp
    jmp  _say2                   ## TAILCALL
    .cfi_endproc
                                        ## -- End function
    .globl    _say2                   ## -- Begin function say2
    .p2align  4, 0x90
_say2:                                  ## @say2
    .cfi_startproc
## %bb.0:                               ## %entry
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq $64, %rsp
    movsbl   (%rdx), %eax
    cmpl $0, %eax
    movl %esi, -4(%rbp)          ## 4-byte Spill
    movq %r8, -16(%rbp)          ## 8-byte Spill
    movq %rcx, -24(%rbp)         ## 8-byte Spill
    movq %rdx, -32(%rbp)         ## 8-byte Spill
    movl %edi, -36(%rbp)         ## 4-byte Spill
    jne  LBB5_2
## %bb.1:                               ## %if.then
    leaq L_.str.5(%rip), %rdi
    movl -36(%rbp), %esi         ## 4-byte Reload
    movl -36(%rbp), %edx         ## 4-byte Reload
    movb $0, %al
    callq    _printf
    movl %eax, -40(%rbp)         ## 4-byte Spill
    jmp  LBB5_3
LBB5_2:                                 ## %if.else
    leaq L_.str.6(%rip), %rdi
    movl -36(%rbp), %esi         ## 4-byte Reload
    movq -32(%rbp), %rdx         ## 8-byte Reload
    movb $0, %al
    callq    _printf
    movl %eax, -44(%rbp)         ## 4-byte Spill
LBB5_3:                                 ## %if.end
    movl -36(%rbp), %eax         ## 4-byte Reload
    incl %eax
    leaq L_.str(%rip), %rdx
    movl %eax, %edi
    movl -4(%rbp), %esi          ## 4-byte Reload
    movq -24(%rbp), %rcx         ## 8-byte Reload
    movq -16(%rbp), %r8          ## 8-byte Reload
    addq $64, %rsp
    popq %rbp
    jmp  _fizzbuzz               ## TAILCALL
    .cfi_endproc
                                        ## -- End function
    .section  __TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
    .space    1

L_.str.1:                               ## @.str.1
    .asciz    "fizz"

L_.str.2:                               ## @.str.2
    .asciz    "%s%s"

L_.str.3:                               ## @.str.3
    .asciz    "buzz"

L_.str.4:                               ## @.str.4
    .asciz    "%s"

L_.str.5:                               ## @.str.5
    .asciz    "%i : %i\n"

L_.str.6:                               ## @.str.6
    .asciz    "%i:%s\n"


.subsections_via_symbols

実際にCodeSegment同士はjmpで,mallocなどの関数呼び出しのみcallになっている事がわかります

~/w/c/S/cbc-sandbox » grep jmp fizzbuzz.s
    jmpq    *%rsi
    jmp LBB1_3
    jmp LBB1_7
    jmp LBB1_10
    jmp _fizz                   ## TAILCALL
    jmp LBB3_2
    jmp _buzz                   ## TAILCALL
    jmp LBB4_3
    jmp _say2                   ## TAILCALL
    jmp LBB5_3
    jmp _fizzbuzz               ## TAILCALL
~/w/c/S/cbc-sandbox » grep call fizzbuzz.s
    callq   _fizzbuzz
    callq   ___stack_chk_fail
    callq   *%rdx
    callq   _malloc
    callq   ___snprintf_chk
    callq   ___snprintf_chk
    callq   _printf
    callq   _printf

試すには

試すには gccはこちら

clangはこちらを見ていただくと出来ます.

なおclangが容量をすごく取りますが,現状Mac os Mojaveではclangしかビルド出来ません...助けてくれ...

Perl入学式第2回目をPerl6で解いてみる(Part1)

皆さんこんにちは.最近はようやく寒くなってきた沖縄からid:anatofuzです.

そういえばYAPC::Tokyoのチケットはまだ売っている様です.皆さん行きましょう.

yapcjapan.org

今日は雰囲気でPerl6でPerl入学式第2回の構文基礎を書いていこうと思います

Perl6とは

Perl6とはPerlっぽい別言語です. Python2とPython3の関係ではないので注意しましょう.

とは言え,最初にエイヤッとした言語デザイナーがLarryWallでもありますし, 幾つかのSyntaxはPerlに似ています.

Hello,World!

print "Hello, World!\n"; このように書いたものを, hello.plとして保存します printは, 端末に文字を出力します \nは改行を表します 最後に;を忘れずに!

Perl6ではprintもありますが,よく使うのはsayです.

say "Hello,World!";

ちなみに他にこういうやり方もあります

"Hello,World!\n".print;

これはMuクラスに生えているprintメソッドを利用した場合です. https://docs.perl6.org/routine/print

perl5までのprintはIOクラスのメソッドとなっています

print "Hello,World!\n";

もちろんsayもメソッドとして生えているので出来ます

"Hello,World!".say;

おまじない

!/usr/bin/env perl

use strict; use warnings; おまじないとして, 冒頭の3行を書くようにしよう use strict -> 厳密な書式を定めたり, 未定義の変数を警告するといった効果があります use warnings -> 望ましくない記述を警告してくれる効果があります 以下, この資料のサンプルコードではこれを「お約束」として省略します 書かれているものとして扱ってください

Perl6ではstrictやwarningsの様なものは標準で入っています. この代わりのおまじないと言えば,シェバングと次の1行が該当するでしょうか.

#!/usr/bin/env perl6
use v6;

このv6とはPerl5で仮にこのPerl6プログラムを実行した際にエラーを出してくれるというものです. Perl6的には特に害が無いです. https://docs.perl6.org/language/101-basics#v6

例えば次の様なスクリプトを書いたとしましょう.

use v6;
print "hoge\n";

2行目に関してはPerl5でもprintがあるので,実行することが可能ですが, 仮に他の処理があると予期せぬ処理をPerl5がしそうです. 現在のPerl6では普通のスクリプトの拡張子をp6, クラス定義などのモジュールになるファイルの拡張子をpm6とすることを推奨していますが,Perl5と同じplが拡張子として使われている場合もあります. このプログラムは use v6; をしているので, Perl6で実行すると次のようなエラーを出します.

~/.sandbox » perl hoge.p6
Perl v6.0.0 required--this is only v5.26.2, stopped at hoge.p6 line 1.
BEGIN failed--compilation aborted at hoge.p6 line 1.

という訳で1行読み込んで終わりました.安全性のために書いておくのがオススメです.

復習問題

Hello, Perl Entrance!という文字列を出力するhello_perl.plを書いて下さい

say "Hello, Perl Entrance!";

構文チェック

perl6では perl -c hoge.p6 とするといい感じになります.

~/.sandbox » perl6 -c hoge.p6
Syntax OK

スカラ変数

Perl6はPerl5と似ており,スカラ,配列,ハッシュの3タイプに変数が分類されます.

Perl6のドキュメントによると次の様に書かれています https://docs.perl6.org/type/Scalar

A Scalar is an internal indirection which is for most purposes invisible during ordinary use of Perl 6. It is the default container type associated with the $ sigil. A literal Scalar may be placed around a literal value by enclosing the value in $(…). This notation will appear in the output of a .perl method in certain places where it is important to note the presence of Scalars.

When a value is assigned to a $-sigiled variable, the variable will actually bind to a Scalar, which in turn will bind to the value. When a Scalar is assigned to a $-sigiled variable, the value bound to by that Scalar will be bound to the Scalar which that variable was bound to (a new one will be created if necessary.)

In addition, Scalars delegate all method calls to the value which they contain. As such, Scalars are for the most part invisible. There is, however, one important place where Scalars have a visible impact: a Scalar will shield its content from flattening by most Perl 6 core list operations.

A $-sigiled variable may be bound directly to a value with no intermediate Scalar using the binding operator :=. You can tell if this has been done by examining the output of the introspective pseudo-method .VAR:

雰囲気で理解すると,Perl6におけるスカラ型は $ で宣言した変数名と,実際の値をバインドしてくれる中間的なクラスであり,$ で宣言すると自動的に全てスカラになるということの様です.

また := を利用することで,間にスカラクラスを挟まず,ダイレクトに値を束縛することが可能です.

とは言え,基本的にはPerl5と同じ扱いですが,実際に型として利用されるのはバインドされている変数ということの様です.

これは公式ドキュメントによると次の様に見ることが可能です.

my $a = 1;
$a.^name.say;     # OUTPUT: «Int␤»
$a.VAR.^name.say; # OUTPUT: «Scalar␤»
my $b := 1;
$b.^name.say;     # OUTPUT: «Int␤»
$b.VAR.^name.say; # OUTPUT: «Int␤»

.^name で変数の型が確認できます. $a では1をスカラクラス経由でバインドしており,基底にScalarがあることがわかります.

一方 $b は1を束縛している為,アイテム化されておらず,$b そのものがIntであることがわかります.

Perl6では $ があるかないかでScalarクラスであるかどうかが変わります.

.say for (1, 2, 3);           # OUTPUT: «1␤2␤3␤», not itemized
.say for $(1, 2, 3);          # OUTPUT: «(1 2 3)␤», itemized
say (1, 2, 3).VAR ~~ Scalar;  # OUTPUT: «False␤»
say $(1, 2, 3).VAR ~~ Scalar; # OUTPUT: «True␤»

上の例を見ると $ があるかないかで変わっていることがわかりますね. この $(1,2,3) はアイテム化されているといい, $(1,2,3) でひとまとめです.

その為 $(1,2,3) は実はこうなります.

> my @hoge = $(1,2,3);
[(1 2 3)]
> say @hoge
[(1 2 3)]
> @hoge[0]
(1 2 3)
> @hoge[0][0]
1

アイテム化されている為,実は $(1,2,3) はスカラであり,その中の要素はリストなので配列のようにアクセスするというPerl5っぽい挙動を示します.

コメント

Perl6のコメントはPerl5と同じく# です

# こうするとコメント

またPerl6ではMulti-line commentも追加されました

"#`" とカッコでくくると,その間がコメントとなります.

if #`( why would I ever write an inline comment here? ) True {
    say "something stupid";
}

この例では #`の後に ( が来ているので,この中が全部コメントとなり 最終的にはif True { という感じに解釈されます.

$perl6 hoge.p6
something stupid

これは結構便利ですね!!

疲れたので続きは次回...