c-repl - C言語のREPL

http://neugierig.org/software/c-repl/

便利そう。ただ、実際の開発で使うためにはオブジェクトファイルをロードできないとだめかも!?
gdcgccベースのD言語コンパイラなのでD言語にも対応できるかも?

$ cd ~/src; darcs get http://neugierig.org/software/darcs/c-repl

でインストール。

childがC言語、他はRubyスクリプトで書かれている。

$ ./repl
> .h math.h
.h math.h
> .l m
.l m
> printf("%g\n", sin(1.0))
printf("%g\n", sin(1.0))
0.841471

オブジェクトファイル対応化。環境変数によるヘッダファイル・オブジェクトファイル・ライブラリ指定

というわけでさっそく*.oも読み込めるようにhack。3行加えるだけ。

ついでにヘッダファイルやライブラリやオブジェクトファイルを毎回指定するなんてやってられないので環境変数で指定できるようにした。3行変更。

Rubyの部分はきれいに書かれているので改良は容易だった。

--- repl	2007/10/03 22:46:48	1.1
+++ repl	2007/10/03 23:33:50
@@ -63,8 +63,9 @@
     @cur_so_id = 1
     @runner = Runner.new
     @externs = []
-    @headers = []
-    @libraries = []
+    @headers = (ENV['REPL_HEADERS']||"").split
+    @libraries = (ENV['REPL_LIBS']||"").split
+    @objs = (ENV['REPL_OBJS']||"").split
     @commands = {
       'd' => ['toggle debug mode.',
               proc { @debug = !@debug; puts "debug is #{@debug?'on':'off'}" }],
@@ -94,11 +95,11 @@
       writer.close
       STDIN.reopen(reader)
       reader.close
-      cmd = "gcc -xc -g -shared -o #{name}.so"
+      cmd = "gcc -xc -g -I. -c - -o tmp.o && gcc -L. -g -shared -o #{name}.so tmp.o "
       # add in all libraries
       cmd += ' ' + @libraries.map{|l| "-l#{l}"}.join(' ')
-      # tell it to read input through stdin
-      cmd += ' -'
+      # add in all objects
+      cmd += ' ' + @objs.map{|o| "#{o}"}.join(' ')
       puts cmd if @debug
       exec(cmd)
     end

さて、実行結果は。

~/src/c-repl% cat hoge.c
int add(int x, int y) {
    return x+y;
}
~/src/c-repl% cat hoge.h
int add(int x, int y);
~/src/c-repl% REPL_LIBS=m REPL_OBJS=hoge.o REPL_HEADERS="math.h hoge.h" ./repl
> printf("%g\n", sin(1.0))
0.841471
> printf("%d\n", add(1,2))
3

作者へフィードバック

せっかくdarcsを使っているのだから作者にパッチ送付。

darcs record
darcs send -o mypatch

最後にmypatchを添付して作者にメール。

インストール

インストールするためには名前を変えておいたほうがいい。このへんいい加減。他のディレクトリで実行することを考慮していないのは明らかなので、実際のプログラムをhackするのに使われているかどうか怪しい。

まず、カレントのchildを実行するようハードコードされているので修正。

--- repl	2007/10/03 23:53:19	1.2
+++ repl	2007/10/03 23:53:23
@@ -20,7 +20,7 @@
       response_pipe[0].close
       STDIN.reopen(command_pipe[0])
       command_pipe[0].close
-      exec('./child', response_pipe[1].fileno.to_s)
+      exec('c-repl-child', response_pipe[1].fileno.to_s)
     end
     command_pipe[0].close
     command_pipe[1].sync = true

インストールの例。俺の場合~/binにPATHが通っていてRUBYLIBに~/rubyを指定してあるのでこんな感じ。

$ mv child c-repl-child
$ cp repl ~/bin; cp c-repl-child ~/bin; cp codesnippet.rb gdbmi.rb ~/ruby