Hatena::ブログ(Diary)

hogeなlog

プロフィール

hogelog

hogelog

小室 直(こむろ すなお)。電気通信大学2003年入学。2010年修士卒業。プログラミングとかしてます。

カレンダー
1984 | 01 |
2006 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 |
2010 | 01 | 06 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 05 | 08 | 09 | 10 | 12 |
2012 | 01 | 04 | 06 |

October 27(Sat), 2007

[] PHPで書いたいいかげんなPHP-REPL

とかくPHPの色々が全然わからんので(たとえば「あれ、Arrayってどう書くんだ」とか言うレベル)、対話環境がいる。Perlからphp -r hogehogeを呼び出すラッパだけだとあまりにもあまりだったので、PHPで書いた。ほんの少しだけ手を入れて、関数とかも定義しやすいように。ブラケットブレースを数えてるだけだったり。

% ./phpterm.php
php> $x = 342;
php> print "$x\n";
342
php> function hoge(){
  print "hoge\n";
  }
php> hoge();
hoge
php> function loop(){
  for($i=0;$i<3;++$i){
    print "$i\n";
    }
  }
php> loop();
0
1
2
php>

無いよりマシ、かなあ。つーかこんな感じのもん、誰かちゃんと作ってると思うのだけど。以下コード。

#!/usr/bin/php
<?php
  $prompt = "php> ";
  function isLine($line)
  {
    return preg_match("/[^{]+;\s*$/", $line);
  }
  function brakDepth($line)
  {
    $openNum = preg_match_all("/{/", $line, $out);
    $closeNum = preg_match_all("/}/", $line, $out);
    return $openNum - $closeNum;
  }
  function blockEnd($line)
  {
    return brakDepth($line)==0 and preg_match("/.+}\s*$/", $line)==1;
  }
  while($line = readline($prompt)){
    if(!isLine($line)){
      while(!blockEnd($line)){
        $depth = brakDepth($line);
        for($i=brakDepth($line), $indentsp="";$i>0;--$i){
          $indentsp .= "  ";
        }
        $line .= readline($indentsp);
      }
    }
    eval($line);
    readline_add_history($line);
  }
?>
トラックバック - http://d.hatena.ne.jp/hogelog/20071027

October 26(Fri), 2007

[][] PHPのおべんきょー用対話環境ほしい。

PHPよくわからんで、対話環境とか欲しーなあ思ったけど見あたらんかった。なのででっちあげた。こんな動作。

% phpterm.pl
php> $x = "hoge";
php> $y = $x . "\n";
php> echo $y;
hoge
php> 

ただ毎回php -r inputやってるだけ。超てきとう、どころじゃないぐらいてきとう。

php> echo "hoge\n";
hoge
php> echo "fuga\n";
hoge
fuga
php> list
echo "hoge\n";
echo "fuga\n";

php> clear
php> list

php> 

こんなことなるし。入力されてるプログラムを出力するコマンドlist、プログラムをリセットするコマンドclearとかだけ適当に仕込む。ソースはPerlで以下。Term::ReadLineべんりだった。

#!/usr/bin/perl -w

use strict;
use Term::ReadLine;

my $term = new Term::ReadLine 'PHP Terminal Modoki';
my $prompt = "php> ";
my $OUT = $term->OUT || \*STDOUT;

my @phpcmd = ("php","-r");
my $phpsrc = "";

my %funtable;

$funtable{"clear"} =  sub{$phpsrc = "";};
$funtable{"list"} =  sub{print $OUT "$phpsrc\n";};
$funtable{"help"} = sub{print"$_" for keys %funtable;};

while(defined(my $line = $term->readline($prompt))){
  chomp $line;
  if(exists($funtable{$line})){
    $funtable{$line}();
  }
  elsif($line =~ /\S/){
    $phpsrc .= $line . "\n";
    (system @phpcmd, $phpsrc) == 0 or exit 1;
  }
  $term->addhistory($line) if $line =~ /\S/;
}

つーかPHPで書いたほがマトモなん書けそう。って、そのPHPがわからんからREPL欲しいんだった。

トラックバック - http://d.hatena.ne.jp/hogelog/20071026

October 25(Thu), 2007

[] アルバイト

知り合いの人にアルバイトに誘われた。感覚でOKした。てっきりミスドの厨房でドーナッツ揚げ機から揚がってきたドーナッツの油を切ってベルトコンベアに乗せる作業と淡々と続けて、気付けば三年たったところで突然の解雇。再就職しようにも面接で「この三年間は何をしていたのですか?」「ドーナツをベルトコンベアにのせる仕事を」「その経験はこの会社での仕事でどう生かせますか?」「トングさばきなら、わりと自信あります」「そうですか。では次の方どうぞー」とかそんなことをするのかと思ってたけど、今日見学に行った感じだとどうも違うらしい。ミスドには全自動ドーナツメーカーは導入されてないようだ。なんてこった。21世紀にもなるというのに。首の後ろにプラグを指すだけでバーチャル世界にダイブできるようになるのはいつの時代だ。

そんなわけは無いんですけど。そんなわけってのが何を指しているのかと言えば、この上の段落の文章ほぼ全部です。アルバイトはじめましたってのだけホントです。全自動なミスドがあるのかどうかはよくわかりません。というわけで、電卓で円周率を計算した結果をExcelの升目に埋める人生はじめます。

いやなんつうか普通にバイト先に悪いんじゃね、と今気付いた。もっと生産的だと思います。ミスドで言うと懸賞応募に来たハガキがちゃんと条件満たしてるかチェックしたりするくらい、素晴しい仕事をするのだと思います。

ところで電気通信大学情報工学科計算機室(通称JED)にocamlが入ってないのはほげほげなので入れてほしい。ホームディレクトリがパンクしそうです。Vine Linuxにもパッケージあるわけだし。とかいう要望はどこに寄せればいいんだろう。JEDのサイトに載ってる管理者アドレスでいいのか。パンクしそうですっていうかした。COINS、Gauche、SML/NJ、GCL、OCaml、D(DMD)、あとなんだっけなあ、とかいう具合に色々ぶちこみまくってるせいですが。

腹減ってきたので寝ます。

[] ls依存症

インタプリタの対話環境でもついls。

OCaml

# ls
  (あ、間違った)^CInterrupted.

SML/NJ

- ls
=(ぎゃー)^C
Interrupt

Gauche

gosh> ls
*** ERROR: unbound variable: ls
Stack Trace:

Perl(perlsh)

main[91]$ ls
ls
main[92]$

Ruby(irb)

irb(main):001:0> ls
NameError: undefined local variable or method `ls' for main:Object
        from (irb):1
        from :0

Python

>>> ls
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: name 'ls' is not defined

GCL

>ls

Error: The variable LS is unbound.
Fast links are on: do (si::use-fast-links nil) for debugging
Error signalled by EVAL.
Broken at EVAL.  Type :H for Help.
>>

perlshは優しい子。

[][] 数値計算の授業を受けてて。

OCamlのコードとか考えてた。書けた。

# let newtonMethod f fa cond x0 =                                       
    let rec iter xn = if (cond f fa xn) then xn else (iter (xn -. (f xn) /. (fa xn))) in
  iter x0;;                                                             
val newtonMethod :
  (float -> float) ->
  (float -> float) ->
  ((float -> float) -> (float -> float) -> float -> bool) -> float -> float =
  <fun>
# (newtonMethod (fun x -> x*.x+.2.0*.x+.1.0) (fun x -> 2.0*.x+.2.0) (fun f fa xn -> xn-.(f xn)/.(fa xn) < 0.00001) 3.0);
- : float = 1.
トラックバック - http://d.hatena.ne.jp/hogelog/20071025

October 23(Tue), 2007

[][] OCaml熱さいかい(三日坊主になりませんように)

大学の図書館でThe Little Schemerを探したら貸し出し中だったので、なんかおもしれー本ねーかなーと探していたらThe Little MLerなる本を見つけた。おもしろそうなので借りた。読んだ。おもしろい。ちんたら読んでるので前の方しかまだ読んでないけど、パターンマッチパターンマッチパターンマッチ。

そんなわけで、よしMLで遊ぼうと思った。で、StandardMLとOCamlのどっちにしようかなと迷ったけれども、http://www.mpi-sws.mpg.de/~rossberg/sml-vs-ocaml.html を見て、OCamlはなんでもletで束縛するのが好みで、逆にSMLは~1.0、andalso、orelseみたいなのが嫌かもと思ったのでOCamlに。

The Little MLerに出てくるプログラム片はこんなの。

# fact 5;;
- : int = 120
# type shish_kebab = Skewer
  | Onion of shish_kebab
  | Lamb of shish_kebab
  | Tomato of shish_kebab;;
type shish_kebab =
    Skewer
  | Onion of shish_kebab
  | Lamb of shish_kebab
  | Tomato of shish_kebab
# Skewer;;
- : shish_kebab = Skewer
# Lamb(Skewer);;
- : shish_kebab = Lamb Skewer
# let rec only_onions = function Skewer -> true | Onion(x) -> only_onions(x)
  | Lamb(x) -> false | Tomato(x) -> false;;
val only_onions : shish_kebab -> bool = <fun>
# only_onions(Lamb(Skewer));;
- : bool = false
# only_onions(Onion(Lamb(Onion(Skewer))));;
- : bool = false
# only_onions(Onion(Onion(Onion(Skewer))));;
- : bool = true

本に載ってるのはSMLのコードですけど。

パターンマッチ使っていつぞ書いたfactとか書くとこうか。

# let rec fact = function 0 -> 1 | n -> n*(fact (n-1));;
val fact : int -> int = <fun>
# fact 10;;
- : int = 3628800

リファレンス。http://caml.inria.fr/pub/docs/manual-ocaml/index.html

日本語もあった。http://ocaml.jp/archive/ocaml-manual-3.06-ja/

SICPっぽくすると

末尾再帰で。こうか。途中の(0,a)とかはたぶんtupleとかいうやつ。

# let fact x =
    let rec f = function (0,a) -> a | (x,a) -> f(x-1,a*x) in
  f(x,1);;
val fact : int -> int = <fun>
# fact 10;;
- : int = 3628800

リストを逆順に並べるとか。

# let rec my_reverse = function [] -> [] | hd::tl -> (my_reverse tl) @ [hd];;
val my_reverse : 'a list -> 'a list = <fun>
# my_reverse [1;2;3;4;];;
- : int list = [4; 3; 2; 1]
# let my_reverse ls =
    let rec rev = function ([],rls) -> rls | (hd::tl,rls) -> rev(tl, [hd]@rls) in
  rev (ls,[]);;
val my_reverse : 'a list -> 'a list = <fun>
# my_reverse [1;2;3;4];;
- : int list = [4; 3; 2; 1]

ふむ。パタンマッチいいなこれは確かに。hd::tlはcar::cdrと書くとLisperに優しいですね。

October 22(Mon), 2007

[] Google Scholarおもしれー

論文サーチエンジンなんだけど、この子楽しい。この子が楽しいっつうか論文が楽しいのかもしれんけど。

[] Windows時計がわり

俺はどーも時計が好きじゃないので、Windowsの右下に表示されてる時計も消してます。だけどまあそれじゃ不便なので適当にこんなプログラム。プログラム名はc.exeとかにしておいて、システムディレクトリの中に放りこんどきます。そうすれば「Win+R, c, Enter」で現在時刻を確認できるように。Linuxだと「alias c='date'」ってやってるだけ。

#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
  char timestr[100];
  SYSTEMTIME ltime;
  GetLocalTime(&ltime);
  snprintf(timestr, sizeof(timestr), "%04d/%02d/%02d %02d:%02d:%02d",
      ltime.wYear, ltime.wMonth, ltime.wDay,
      ltime.wHour, ltime.wMinute, ltime.wSecond);
  MessageBox(NULL, timestr, "いま何時。", MB_OK);
  return 0;
}

久々にWindowsをブートしたけど、Firefoxがすげーキビキビ動く。GUIはやっぱりLinuxよりもWindowsのがつえーなあ。Macは知らぬ。

October 20(Sat), 2007

[] Parrotさわってみる

「Parrotってなあに?」ていうような人は、とりあえずささださんの手によるParrot 入門 - The Parrot Primer とか読むといいんじゃないかなと思います。

「動的言語向けに設計されてるレジスタベースな汎用VMだよー」とかそんな感じだと思いますきっと。

まずインストール

http://svn.perl.org/snapshots/parrot/ からparrot-latest.tar.gzをダウンロード。

% tar zxf parrot-latest.tar.gz
% sudo mv parrot /usr/local

とりあえず/usr/local/parrotあたりに入れておくことにしてみました。

% cd /usr/local/parrot
% perl Configure.pl
...(なんか色々やってる)
% make
...(なんか色々)
% make test
...(たくさん)

Failed Test               Stat Wstat Total Fail  Failed  List of Failed
-------------------------------------------------------------------------------
t/codingstd/cppcomments.t    0    11     1    2 200.00%  1
t/op/gc.t                    1   256    22    1   4.55%  4
 (8 subtests UNEXPECTEDLY SUCCEEDED), 12 tests and 616 subtests skipped.
Failed 2/351 test scripts, 99.43% okay. 2/7884 subtests failed, 99.97% okay.
make: *** [test] エラー 255

うーん。なんか成功してないテストもあるみたい。だけど、だいたいできてるみたいなので不安ですがとりあえず飛ばして次行きましょう。よくわかんないし。

% cd ~/bin
% ln -s /usr/local/parrot/parrot parrot
% parrot
parrot -[abcCEfgGhjprStvVwy.] [-d [FLAGS]] [-D [FLAGS]][-O [level]] [-o FILE] <file>

とりあえずparrotにリンクはっとく。これでとりあえず、parrotの環境構築できたつもり。

てきとうにPASMでなんか書いてみる。

PASMっていうのはParrotのアセンブリ言語のようなもの。

とりあえずハロワ。

% cat >hello.pasm
print "Hello, World!\n"
end
% parrot hello.pasm
Hello, World!
% parrot -o hello.pbc hello.pasm # バイトコードにコンパイル
% parrot hello.pbc # コンパイルしたバイトコードを実行
Hello, World!
%

Parrot VMはJVMとかのスタックベースなVMと違って、レジスタベース。実際のCPUの命令セットに少し似ている、かも。

% cat >reg.pasm
set I1, 100
set N1, 2.2
set S1, "hoge"
print I1
print N1
print S1
print "\n"
end
% parrot reg.pasm
1002.200000hoge

ParrotのレジスタにはIレジスタ、Nレジスタ、Sレジスタ、Pレジスタの4種類があって、たぶんそれぞれ32個ある。

なんか腰が痛いので今日はここまで。ほぼなんもしてねーじゃん。

[] 下書き機能

むかし、はてなダイアリーって下書き機能あった気がするんだけど。気のせいだっけか。

トラックバック - http://d.hatena.ne.jp/hogelog/20071020

October 15(Mon), 2007

[] ものすごい勢いで何もしない日々

自然日記も書かないってもんですね。

昔本屋でよく見かけた「三日でできる実践簡単ホームページ術!」みたいな本とかには「更新しないホームページは直ぐ飽きられる!小まめな更新これ掟ネ!」とか書いてあった気がする。しかし今時のウェブサーフィンはRSSリーダやアンテナ使ってナンボ。彼等ウェブサーファーは更新したときだけ見にくる。つーこた、質の悪い更新を頻繁にするよりかは、高品質の更新をときどきする程度で良いのではないだろうかとか思ったわけです。

漫画で言うと、週間連載だけどつまんないキャラメルリンゴより、月刊連載でおもしろいエンジェル伝説のが世間からの評価は高いみたいな話です。

そしてこの日記の質なんて元々低いのでそんなこと考える必要無いのです。というか高いとか低いってなにそれとかまあいいや。

なんか最近プログラム書いてないわーとか思って、最近ニコニコ動画で流行ってる(流行ってるのか?)「一曲かかってる間にプログラム書きます」的なもん作ってみようかと思い、D言語でBrainf*ckの処理系書こうとして全然おさまらなくてうへー、とかなったりしてた。

違った。それは先月のことだ。じゃあ今月はなにをやってたんだ俺は。

大学の実験でVerilog使って回路書いたりしてるけど、わりと面白いなあと思う。思うけれども自前でFPGA買ってきてほげほげするほどでもないかなあ。

ちなみに

ものすごい勢いでどうでもいい情報ですが、俺が「何もしない日々」とか言ってるときはたいていウェブ上の二次創作ものの文章を読み漁っています。たぶん割と悪食で、クロス、最低系、オリジナル主人公憑依系、介入だとかなんでも読む。改行の量が頭おかしかったり、フォーマットが気持ち悪いことなってる文章もFirebugでいじって読む。それでいて読んだ次の日くらいにはほぼ忘れてるので、ああ何もしてないなあと思う次第。

トラックバック - http://d.hatena.ne.jp/hogelog/20071015

October 07(Sun), 2007

[] VMってすごいんだなあ!と言いたかったのだけれども。

ソースプログラムを適当にASTっぽくしたあと、それを解釈実行するように書いたBrainfuckのインタプリタと、VMっぽく書いたのを比較して「VMはやいカッコイイ!」と言うつもりで、ごにょごにょプログラム書いてた。適当に書き終えた。

% gcc bfi_ast.c -o bfi_ast
% gcc bfi_vm.c -o bfi_vm
% time (repeat 10 ./bfi_ast quine2.b>/dev/null)
1.164 user 0.032 system 1.197 total
% time (repeat 10 ./bfi_vm quine2.b >/dev/null )
2.688 user 0.012 system 2.708 total

……おや。

うーん。書き方がいいかげん過ぎた。っていうかそもそもどっちもASTでもVMでもねーかんじ。あとBFじゃ構造が単純だからTree言っても読むの速いから、VMとやらの効率調べるにも限界があるような。もうちょとまともな構造持った言語の処理系で試さにゃ。適当にプログラム書いてわかったつもりになるのやめて、ちゃんと調べなきゃ駄目か。

なんか最近BF処理系しか書いてない。

VMぽいコード改良

なんか考えてみればアレだなあ、とか思ってた部分を変えたらだいぶ速くなった。そもそもまともなコード書ける人じゃないと、「ほげほげな手法」と「ふがふがな手法」の速度比較とか、なかなかできないということがわかった。

% gcc bfi_vm.c -o bfi_vm
% time (repeat 10 ./bfi_vm quine2.b >/dev/null)
2.052 user 0.028 system 2.084 total

October 06(Sat), 2007

[][] Brainf*ckはEOFの扱いがびみょーだよなあと思ってた。

バイナリデータのechoとかもできないし。どうもWikipediaにのってるくらい有名なびみょーどころだったみたい。

http://en.wikipedia.org/wiki/Brainfuck#End-of-file_behavior

16-bit、32-bitのセルを持つBFね。効率的にはどうなんだか、今度試してみよう。

EOFも考えたecho.bf

こう書くかな。でもメモリ領域がbyteの配列だとバイナリを入力とした時の出力が入力と一致しない。

,+[-.,+]

速度比較やってみた。

% time (repeat 10 ./bfi_uchar quine2.b >/dev/null)
2.076 user 0.028 system 2.109 total
% time (repeat 10 ./bfi_int quine2.b >/dev/null)
1.744 user 0.032 system 1.784 total
% time (repeat 10 ./bfi_uchar echo.bf </usr/include/X11/Xlib.h >hoge)
0.308 user 0.040 system 0.353 total
% time (repeat 10 ./bfi_int echo.bf </usr/include/X11/Xlib.h >hoge)
0.276 user 0.044 system 0.318 total

intのが良さげかな。

quine2.bはScheme:Brainfuckから拾ってきたもの。処理系のコードは適当に書いたこんなの(リンク先のはbfi_intのもの)。bfi_ucharとbfi_intの違いはメモリ領域が前者unsigned charの配列、後者intの配列というだけ。

トラックバック - http://d.hatena.ne.jp/hogelog/20071006

October 03(Wed), 2007

[][] zshでjava補完速くする

わりといっちゃってるシェルとして有名なzsh先生、javaコマンド打ったりするときも便利です。

Java初学者の人が

% javac HelloWorld.java
% java HelloWorld.class
Exception in thread "main" java.lang.NoClassDefFoundError: HelloWorld/class

とかやっちゃって困ってる場面はよく目にします。でもzshなら大丈夫。

% java H(TAB入力)

% java HelloWorld

と補完してくれます。さらには

% java -classpath /usr/java/apache-ant-1.7.0/lib/ant.jar (TAB入力)

とすることで

% java -classpath /usr/java/apache-ant-1.7.0/lib/ant.jar org.apache.tools.

まで補完、もう一度TABを押すと大量の候補リストを表示してくれたりします。なんだかやりすぎ感がして楽しいですね。

しかし俺の環境で、最近やたらとこの補完が遅くなってておかしいなあと思ってました。でzshのjavaコマンドの補完定義ファイル_javaと、その中で呼ばれてる_java_class読んで気付いたんですけど、こいつら環境変数CLASSPATHの中全部探って補完してくれるんですね。だからCLASSPATHが多ければその分時間がかかります。CLASSPATHが少なければOKというわけでもない。CLASSPATHにディレクトリが追加されてると、再帰的に下のディレクトリまで読みにいきます。

それで俺は.zshrcの書き方とかものすごくいいかげんなもんで、CLASSPATHが同じパスをいくつも含んでたり、変な位置を追加してたりしたもんだから、補完にものすごく時間がかかっていたわけです。適当に削ったらとても速くなってなんとも快適に。ただまあ、例えばルートディレクトリで

% java (TAB入力)

とかするとしばらく固まったりするわけですけど。C-cで止めれます。

トラックバック - http://d.hatena.ne.jp/hogelog/20071003

October 01(Mon), 2007

[][] Dで書いてなかったかなと

情報工学実験がガイダンスだけで空きコマできたのと、あーまた学期始まったなあと少し気分が昂ぶったのでBFインタプリタでも書いて落ち着くことにする。

一番時間がかかったのは、switchブロックのなかで一つbreakを書き忘れてたところがあったこと。そんなひとはもうswitch使っちゃいけないんじゃないだろうか。

import std.stdio;
import std.string;
abstract class Exp{
  abstract void eval();
}
class BasicExp : Exp{
  private:
  void delegate() exp;
  public:
  this(void delegate() e)
  {
    exp = e;
  }
  void eval()
  {
    exp();
  }
}
class BlockExp : Exp{
  private:
  Exp[] block;
  public:
  void addExp(Exp exp)
  {
    block ~= exp;
  }
  void eval()
  {
    foreach(Exp exp; block){
      exp.eval();
    }
  }
}
class WhileExp : Exp{
  private:
  Exp exp;
  public:
  this(Exp e)
  {
    exp = e;
  }
  void eval()
  {
    while(mem[pt]!=0){
      exp.eval();
    }
  }
}
Exp readBlock(FILE* input)
{
  BlockExp block = new BlockExp;
  while(true){
    int c = fgetc(input);
    switch(c){
      case '+':
        block.addExp(incExp);
        break;
      case '-':
        block.addExp(decExp);
        break;
      case '>':
        block.addExp(nextExp);
        break;
      case '<':
        block.addExp(prevExp);
        break;
      case ',':
        block.addExp(getExp);
        break;
      case '.':
        block.addExp(putExp);
        break;
      case '[':
        block.addExp(new WhileExp(readBlock(input)));
        break;
      case ']':
      case EOF:
        return block;
      default:
        break;
    }
  }
  throw new Exception("Parse Error: readBlock");
}
byte mem[30000];
int pt = 0;
Exp incExp, decExp, nextExp, prevExp, getExp, putExp;
int main(char[][] args)
{
  incExp = new BasicExp({++mem[pt];});
  decExp = new BasicExp({--mem[pt];});
  nextExp = new BasicExp({++pt;});
  prevExp = new BasicExp({--pt;});
  getExp = new BasicExp({mem[pt] = cast(byte)getchar();});
  putExp = new BasicExp({putchar(mem[pt]);});

  if(args.length!=2){
    writefln("%s input", args[0]);
    return 1;
  }
  FILE* input = fopen(toStringz(args[1]), toStringz("r"));
  if(input is null){
    writefln("cannot open %s", args[1]);
    return 1;
  }
  try{
    Exp mainBlock = readBlock(input);
    mainBlock.eval();
  }
  catch(Exception e){
    fwritefln(stderr, e);
  }
  return 0;
}
最近のコメント