2012年12月6日木曜日

Ada勉強メモ 3

ADA-言語とプログラミング方法論』p.3「Ada 入門」から読みます。

1.1 背景
  • Adaは米国国防総省(DoD)が、1976年頃から開発を始めた。
  • FORTRANやCOBOLのように特定の用途向けではなく、Adaは汎用言語。
  • Adaは世界最初のプログラマの名前。

1.2 プログラミング言語Ada
  • Adaはコンパイル言語である。
  • オブジェクトプログラム(機械語プログラム)は、通常「プログラムライブラリ」に格納される。
    • プログラムライブラリって、Cで言うところのライブラリと同じかな?
  • プログラムライブラリには、完結したプログラム、副プログラム、パッケージが格納される。
  • Adaの識別子は文字から始まり、文字、アンダースコア、数字の羅列。ただしアンダースコアの連続はダメ
今日はここまで。
Adaの歴史と基本的な約束事が分かりました。
次回はいよいよAdaのプログラムを書いていきます。

2012年12月3日月曜日

【Eclipse】プラグインをデバッグする

Eclipseのプラグインでデバッグメッセージを出力する良い方法が見つかったのでメモ。

問題


  • Eclipseに自作プラグインを入れてEclipseを通常起動させても、標準出力・標準エラー出力が表示されない。
    つまり System.out.println を用いてデバッグメッセージを表示しようと思っても、画面に表示されない。
  • java.util.logging.Loggerを使おうと思っても、やっぱり標準出力が表示できないので無意味。
    もし標準出力が出るようになっても、ロギングレベルの設定方法が分からない。(まさか常にsetLevel(Level.ALL)するわけにも行かないですし)

やりたいこと

デバッグしたいなあ、と思ったときに、プラグインを再コンパイルせずに、デバッグメッセージをターミナルへ表示したい


解決策

Eclipseをデバッグモードで起動する方法を覚える

詳しくはRunning Eclipseを読みましょう。要点をまとめます。

Eclipseは
$ eclipse -debug
でデバッグモードで起動できます。Macならこんな感じ。
$ /Applications/eclipse/Eclipse.app/Contents/MacOS/eclipse -debug

さらに、 -consolelog オプションを付けると、標準出力がコンソールへ接続されます。

プラグインのデバッグメッセージの表示のON/OFFをフラグ化


フラグ化することで、プラグインの再コンパイルなしにデバッグメッセージのON/OFFを制御できるようになります。

こんなクラスを作ります。
/**
 * .options読み込みクラス
 * @author uchan
 *
 */
public class DebugOptions {

    public static final boolean verbose;

    static {
        verbose = Boolean.parseBoolean(Platform.getDebugOption(
                "com.github.uchan_nos.c_helper/verbose"));
    }
}

プログラム中では
if (DebugOptions.verbose) {
    logger.fine("debug message");
}
という風に使います。

あとはこんな感じの設定ファイルを作ります。

~/eclipse.options
# Output verbose messages
com.github.uchan_nos.c_helper/verbose=true

そして、Eclipseの -debug オプションの引数として指定します。

$ eclipse -debug ~/eclipse.options

起動ログに

Debug options:
    file:/Users/uchan/eclipse.options loaded
という表示があれば成功です。

2012年11月30日金曜日

Ada勉強メモ 2

Ada 教科書・ウェブページ紹介に載せた教科書

ADA-言語とプログラミング方法論

を読んでいきます。まずは目次から。

本書は4部から構成されています。目次をさらっと眺めます。

第I部 小規模プログラミング
  1. Ada入門
  2. Integerデータ型
  3. Booleanデータ型
  4. 基本的な制御構造
  5. 組織的プログラミング
  6. Characterデータ型
  7. 離散型
  8. さらに制御構造について
  9. Floatデータ型
  10. 配列と文字列
  11. レコード
  12. 副プログラム
第II部 大規模プログラミング
  1. パッケージ
  2. 例外
  3. 入出力
  4. プログラムの設計と構築
第III部 高度なデータ型
  1. アクセス型と動的データ構造
  2. 判別子を持つ型
  3. 数値型
  4. データ型一般について
第IV部 高度なプログラム構造
  1. 演算子宣言と多重定義
  2. 汎用体プログラム単位
  3. タスク
  4. ポータビリティとマシン依存プログラミング
  5. ケーススタディ:大規模情報システムの設計

僕はC言語畑の人ですが、聞いたことがない言葉が幾つかありますね。
  • 組織的プログラミング
  • 離散型
  • レコード
  • 副プログラム
  • アクセス型
  • 判別子
  • 汎用体プログラム単位
ざっと読んでみました。

「組織的プログラミング」の章は、大きなプログラムを作るときに必要になるテスト技法、段階的詳細化について解説していました。
テストにはホワイトボックステスト、ブラックボックステストがあります。
段階的詳細化というのは、解きたい問題を段階的に分割していく手法のことのようです。

「離散型」は、整数型や列挙型など、全順序が定義された離散的な値を扱う型の一般的な名前のようです。離散型ではないものの中には、実数型や構造型などが含まれます。(構造型ってなんだろう)

「レコード」は、C言語でいう構造体のことです。レコードは様々な型の複数の要素を持ちます。

今日の勉強はここまでです。ではまた。

2012年11月26日月曜日

【Git】タグを付け替える

Gitでのタグの付け方を勉強してました。
あるコミットに対してタグを付けたけど、やっぱり付け替えるやり方を見つけたのでメモ。

appling // gitタグの付け替えから引用します。
まずは既存のタグを削除
$ git tag -d <TAG>
$ git push origin :refs/tags/<TAG>
新たにタグを作成して公開
$ git tag <TAG>
$ git push --tags origin

この中で git push origin :refs/tags/<TAG> が良く分からなかったので、git help pushで調べてみました。
まずpushの構文は
 git push <repository> <refspec>
でした(かなり簡略化してあります)。

<refspec>には <src>:<dst> を指定できます。
<src>を空にした場合、<dst>を削除するという意味になるようです。
:<dst>を省略すると、<src>と同じrefが更新されるようです。

したがって、 git push origin :refs/tags/<TAG> はリモートの refs/tags/<TAG> を削除する命令ということですね。

そして、 push 時に --tags を指定すると、明示的に指定したrefに加え、 refs/tags 以下にあるすべての ref がアップロードされるようです。
したがって、 git push --tags origin は、<repository>=origin に、ローカルにあるすべてのタグをアップロードする命令ですね。

2012年11月18日日曜日

Ada 教科書・ウェブページ紹介

Adaを勉強するにあたり、参考となる教科書やウェブページを紹介します。

ADA-言語とプログラミング方法論
僕が教科書として使おうと思っている書籍です。
分厚くて、かなりたくさんの情報が載っている雰囲気です。
最初のAda規格に対応する古い本ですが、最新規格についての教科書が入手できませんでしたので、この本で勉強していくことにしました。

Ada Programming
WikibooksにあるAdaプログラミングの教科書です。
英語ですが、Ada 2005(現状の最新規格)までの範囲で解説がなされています。

Ada@WCIMH
Adaの勉強メモ的なウェブページです。
AdaからWIN32APIを呼び出すのは面白そうです。

2012年11月13日火曜日

研究の貢献を意識する

卒論や修論を書くときに常に考えておかねばならない,研究のテーマや貢献.
以下の質問項目にきちんと答えられれば,それなりにきちんと意識できていると思います.

まずこの2つ.
  • その研究は,どのような問題を解決しようとしていますか.
  • その問題が解決されたら,誰がどのくらい喜びますか.

上2つが固まってきたら,あと3つ
  • どういう方法でその問題を解決しようとしていますか.
  • その方法が本当に良いものかを確認するために,どのような実験を行いますか.
  • なぜその実験で,良いものかを確認できるのですか.


研究のテーマや貢献をしっかり意識できれば,論文の構成も浮かんでくるし,
どんな関連研究を調べればいいかも分かってくる.
何より,価値のある研究をすることができる!

2012年11月5日月曜日

Ada勉強メモ 1

ひょんなことからプログラミング言語 Ada を学ぶことになったので、
これからちょこちょこ勉強メモを書いていこうかと思います。

Adaってすげーんだぜ!

Adaっていうと
  • 古いんじゃないの?
  • もう使ってる人いないんじゃないの?
  • 何に使えるのさ
という意見があるかもしれません。僕もそんなイメージでした(というかAdaをほとんど知らなかった)。

最近ちょっとAdaを勉強したところによれば
  • 古くないよ!2005年にも新規格がISOに承認されたよ!
  • 航空分野なんかで使われているよ!
  • 航空機、航空管制などに使われているみたい。業界にはまったく詳しくないので本当のことは分かりません。
という感じ。いいね!

開発環境

勉強するには開発環境を入れましょう。
Adaはフリーのコンパイラがありますので、無料で勉強できます。
Mac OS Xでしたら、HomebrewにGNATがありますのでそれを入れてください。

$ brew install gnat

こうすると、gnatmakeやgpsなどのプログラムがインストールされます。
  • gnatmake: Adaプログラムのコンパイル過程を制御するプログラムっぽい
  • gps: Ada用の統合開発環境
僕の環境だと、インストール自体はできたのですが /usr/local/bin にリンクが生成されないっぽいのでこんな起動スクリプトを書きました。

#!/bin/sh
export PATH=/usr/local/Cellar/gnat/2012/bin:$PATH
gps

$ gps

で開発環境が起動します(X11アプリ)。

今回はここまで〜

2012年10月29日月曜日

vim on Mac: 全角記号(□とか○)がずれないようにする

MacのTerminal.appでvimを使っていると、□や○などが半角の幅で表示されてしまいます。

対策が分かりましたのでメモしておきます。

OS X Mountain Lionでは対処が簡単で、Terminal.appの環境設定画面の「詳細」タブで
「Unicode 東アジア A(曖昧)の文字幅を W(広)にする」
にチェックを入れるだけです。

結果はこの通り。

Mac OS X Lion 以前ではこの項目がないそうです。手元にLion以前がありませんので確認していませんが、SIMBLプラグインTerminalEastAsianAmbiguousClearerを導入すればいいみたいですね。

2012年10月22日月曜日

【Git】削除したことをindexに登録する

Gitを使っていて面白い挙動に出会ったのでメモ。

シチュエーションとしてはこんな感じ。

  1. ファイル"foo"を少し編集して、OSのコマンドで"bar"にリネームした。
  2. git add bar
  3. git rm foo


1の直後は、fooが削除されたことになっているが、もちろんfooが削除されたことはインデックスには登録されていない。すなわちコミット対象ではない。
# Changes not staged for commit:

# deleted:    foo

そして、当然barはトラックされていない。
# Untracked files:
# bar

2の直後は、barが新規に追加されたことになっている。インデックスにaddされたので、barはコミット対象である。
# Changes to be committed:
# new file:   bar

3の直後は、fooがbarにリネームされたことになっている!(ここが面白いと思ったところ)
# Changes to be committed:
# renamed:    foo -> bar


以前先輩と実験したときも、Gitのリネーム判断は結構面白い挙動をするなあという印象だった。本当に名前を変えたのか、削除して新規作成したのかにかかわらず、ファイルの内容の類似度でリネームかどうかを判断しているらしい。

2012年9月30日日曜日

XENO TACTIC MISSION 6 ノーダメージクリア

みなさんは XENO TACTIC というゲームをご存知でしょうか。
XENO TACTIC は無料のタワーディフェンスゲームです。

タワーディフェンスゲームというのは大雑把に言えば、敵に攻撃を与えるユニットなどをマップに配置し、敵を倒すゲームです。
自分で攻撃を与えるシューティングゲームではなく、攻撃ユニットを如何に配置するかを考えるゲームです。

XENO TACTIC はその中でも、自由配置型、つまりあらかじめ敵が動くコースは決まっておらず、攻撃ユニット自体を壁として使い、コースを設計するタイプです。普通のタワーディフェンスゲームと同じように、敵を倒すと資金を得られ、その資金で配置したユニットのレベルを上げることができます。

XENO TACTIC はMission 1から6まであり、5まではノーダメージクリアもできますが、Mission 6がクセモノです。何がクセモノかというと、チートを使って資金を増やし、はじめから最大強化した武器をありったけ配置してもノーダメージクリアどころか、単なるクリアさえ、ジャグリングというテクニックを使わない限りほぼ不可能でしょう。

ジャグリングというのは、マップに作ったコース上で敵を行ったり来たりさせるという技です。どんな長いコースを作っても、そこを敵が通り抜けるまでに体力が減り切らない場合は敵1体につき1ダメージを食らいます。Mission 6の50レベルのボス、90レベル位から後の敵は、最大強化した武器で長い迷路を組んでも倒しきる事ができません。
したがってジャグリングを用い、敵を何往復もさせるうちに攻撃を加えるようにします。

迷路がながければ長いほどいいかというとそうでもありません。途中途中で出てくるヘリコプター型の敵は組んだコースに関係なく上空を飛び去りますので、画面の端から端に移動する時間しか攻撃の猶予がありません。ということで、ヘリコプターに対して攻撃力の高い武器を画面中央に敷き詰めるということが必要になります。
そうすると必然的に迷路が短くなってしまうわけです。

さて、そんなわけで資金増量チート+ジャグリングを用いて Mission 6 ノーダメージクリアができましたので、スクリーンショットを貼って自慢したいと思います(笑)

100レベルに突入しました!
左と上から飛んでくるヘリコプターをDCAが攻撃しています。

残りは2体(98レベルのボス)
数十分間ジャグリングを繰り返します。

ノーダメージクリア!

2012年9月21日金曜日

ChromeにJava APIドキュメント検索モードを追加する

Google Chrome には検索エンジンを簡単に指定する仕組みがあるのでそれを使います。
どんな機能かは Google Chrome から好きな検索エンジンで検索する方法 - EC studio 技術ブログ に詳しく書かれています。

Chromeのバージョンが違うと画面が違うので、設定に困ったら公式サイトへ。 検索エンジンの管理

さて、この検索エンジンの設定を使って、Java SE 6のAPIドキュメントを
javase List
のようなキーワードで検索できるようにしてみます。

(実はつい先日までは普通にGoogleで検索するだけで十分だったのですが、どうやらAPIドキュメントの場所が変わってしまったらしく、まともに検索できなくなりました。)

設定は以下のようにします。


  • Java SE 6
    • 検索エンジンの名前。任意の名前。
  • javase
    • 検索エンジンを切り替えるためのキーワード。重複しない任意の名前。
  • http://www.google.co.jp/search?q=%s&sitesearch=http%3A%2F%2Fdocs.oracle.com%2Fjavase%2Fjp%2F6%2Fapi%2F
    • 検索式。「%s」が検索ワードに置き換わる。

ChromeのURL欄に「javase<スペース>」と入力すると今設定した検索エンジン(検索エンジンというか、site指定したGoogle検索)に切り替わりますので、探したいクラスやメソッド名などを入力して検索しましょう。

2012年9月4日火曜日

【Python】One-liner でフィボナッチ数列を返すジェネレータを作る

今日学校で議論していたのがこの話題。
Python にはジェネレータというものがあります。そこで、フィボナッチ数列を1つずつ返すジェネレータを作りたいという話になりました。

まずジェネレータを簡単に紹介します。
(i * 2 for i in range(0, 10))
とすると、これは 0, 2, ..., 18 を返すジェネレータになります。
ジェネレータはfor文で便利に扱えます。
g = (i * 2 for i in range(0, 10))
for x in g:
        print x
とすると、出力は
0
2
4
6
8
10
12
14
16
18
となります。

さて、ジェネレータを関数形式で書くことも可能です。
フィボナッチ数列を1つずつ返すジェネレータは次のように書けます。
def fib():
        a, b = 0, 1
        while True:
                yield a
                a, b = b, a + b

g = fib()
for i, f in enumerate(g):
        if i == 10:
                break
        print f
enumerateというのは、シーケンスの全要素に対し、各要素の位置をくっつけたタプルを返してくれる関数です。ここでは第10項までのフィボナッチ数列を求めるために使っています。

これ、 One-liner (一行プログラム)で書けたら素敵ですよね。という話になったのです。そのための構文があってもいいもんだなあ、と。
例えばこんな構文があったらどうかという結論になりました。
gen init ret next
genはキーワード、initは初期値、retは現在の値から yield するための値を取り出す関数、nextは現在の値から次の値を求める関数です。
フィボナッチ数列だったら次のように書けます。もちろん、今の Python にはこんな構文無いのでエラーですが。
g = gen (0, 1) (lambda (a, b) : a) (lambda (a, b) : (b, a + b))
for i, x in enumerate(g):
        if i == 10:
                break
        print x
これを実行すると次のような出力になることが期待されます。
0
0
1
1
2
3
5
8
13
21
34

素敵ですね。
ということで、無いなら作ってみました。
def gen(init, ret, next):
        while True:
                yield ret(init)
                init = next(init)

g = gen((0, 1), lambda (a, b) : a, lambda (a, b) : (b, a + b))
for i, x in enumerate(g):
        if i == 10:
                break
        print x
gen関数の定義は、gen構文が無いために仕方なく作った関数なので、そこを指摘して「One-liner じゃないじゃん!」と突っ込むのはやめてください。
ミソはgen関数を用いてジェネレータを生成しているところ。
while True:とかyieldとか書かなくても、結構複雑なジェネレータを1行で書くことができました。

おまけ:One-liner で素数ジェネレータ
https://gist.github.com/3618684

2012年8月24日金曜日

【eclim】Eclipse を vim から操作する

Eclipse の EGit からは --no-ff オプションを付けてマージできない(Eclipse Community Forums: EGit > EGit and no-fast-forward merges)ということが判明したので、CUI で git をすることになりました。
どうせ CUI でやるならファイルの編集操作も vim でやりたいなということで、前々から気になっていた eclim を使うことに。

インストールは
Installing / Upgrading - eclim (eclipse + vim)
vimでjavaの開発を行う その1 - def __mopemope__(self, *args, **kwargs):
などを参考にしました。

実際に使うにあたって幾つか豆知識を得ましたのでメモしておきます。

  • eclimd が OutOfMemory で落ちる
    • Java VM のメモリを増やそう
    • ~/.eclimrc に以下の設定を追加すればよい
      -Xmx256M
      -XX:PermSize=64m
      -XX:MaxPermSize=128m
  • デフォルトのワークスペースを指定したい
    • ~/workspace をデフォルトで開きたい
    • ~/.eclimrc に以下を追加
      osgi.instance.area.default=@user.home/workspace
  • eclim の補完を Eclipse のような挙動にしたい
    • これは Vim 自体の設定ですが、初期設定だと複数の変換候補がある場合であっても最初の変換候補が入力されてしまいます。インクリメンタルに補完候補を絞り込みたい!(System.out. で補完候補を出し、 p を入力すると p で始まるメソッドだけになってほしい)
    • Make Vim completion popup menu work just like in an IDE を参考にしました
    • .vimrc に以下を追記。詳しくは :help completeopt を参照
      set completeopt=longest,menuone,preview

これで結構快適になりました!

2012年8月17日金曜日

eclipse: visibleWhen

Eclipse のプラグイン開発の話題です

Eclipse 4.2 Juno で右クリックメニューにメニューを追加するには org.eclipse.ui.menus 拡張ポイントを使います。
locationURI に popup:org.eclipse.ui.popup.any を指定することで、右クリックにメニューを追加できます。
その他の locationURI の例は org.eclipse.ui.commandsはナカナカいけるのね を見てください。どうやら、基本的には頑張って locationURI を自分で探すようですね。(誰か完全な locationURI のリストでも作らないかな)

このままだとどこで右クリックしてもメニューが表示されてしまいます。何か条件が満たされたときだけ表示するには visibleWhen を指定すればいいようです。
僕は visibleWhen for command to appear in context menu あたりを参考にしました。

以下はプロジェクトエクスプローラ(もしかしたら他のファイル選択系ビューでも有効かもしれないけど実験していません)でファイル(IFile)かプロジェクトフォルダ(IProject)が選択された状態で右クリックしたときだけ "Import Command" メニューを表示するための記述例です。

   <extension
         point="org.eclipse.ui.menus">
      <menuContribution
            allPopups="false"
            locationURI="popup:org.eclipse.ui.popup.any">
         <command
               commandId="com.github.uchan_nos.directory_importer.importCommand"
               label="Import Command"
               style="push">
            <visibleWhen
                  checkEnabled="false">
               <with
                     variable="selection">
                  <iterate
                        ifEmpty="false"
                        operator="or">
                     <or>
                        <instanceof
                              value="org.eclipse.core.resources.IFile">
                        </instanceof>
                        <instanceof
                              value="org.eclipse.core.resources.IProject">
                        </instanceof>
                     </or>
                  </iterate>
               </with>
            </visibleWhen>
         </command>
      </menuContribution>
   </extension>

2012年8月11日土曜日

C-Helper がインデント乱れとmalloc/sizeof警告に対応しました

サイボウズ・ラボユースで製作中の C-Helper が、インデントの乱れや malloc / sizeof に関して警告できるようになりました。
さらにそれらの警告を Eclipse の Problem view に表示することで、プラグインっぽさが増しました。
どうでしょう。このUIならプログラミングの授業などで使ってもらえるでしょうか。

2012年8月1日水曜日

TeX: caption に url を書く

TeXで図を貼り付け、説明文(caption)にURLを書きたいという場面は沢山あると思います。そのときにurlパッケージを使いたいのですが、\caption{} の中に単純に \url{http://hoge.com/foo.html} を記入するだけではエラーになってしまいます。
エラー内容は僕には意味不明ですが、以下の様なエラーメッセージが出ます。

! Undefined control sequence.
\\->\let \reserved@e 
                     \relax \let \reserved@f \relax \@ifstar {\let \reserved...

ミソは \protect を使うことです。以下のように。

\begin{figure}[htbp]
  \begin{center}
    \includegraphics{hoge.jpg}
  \end{center}
  \caption{図の説明 引用元 \protect\url{http://hoge.com/foo.html} }
  \label{fig:hoge}
\end{figure}

\urlの前に\protectをつけます。
\protectコマンドを僕は知らなかったわけですが、TeX Q and A [エラー編]によれば、マクロ展開を抑止するためのコマンドらしいですね。

2012年7月31日火曜日

MacTex に新しいスタイルファイルを組み込む

MacTeX に .sty ファイルをインストールするにはどうすればいいかのメモ。

.sty ファイルを TeX に組み込むには、基本的に texmf ディレクトリを探し、その中の対応するサブディレクトリに放り込めばよい。
といっても、後から手動で追加するファイルをシステムのディレクトリに入れるのは少し気持ち悪いので、 MacTeX ではどこが個人ディレクトリになるのかを調査した。

によれば、 MacTeX では
  • ~/Library/texmf/tex
  • ~/Library/texmf/tex/latex
の2つを標準で検索してくれるらしい。(~/Library はホームディレクトリの中の Library ディレクトリである。例えば僕の場合は /Users/uchan/Library となる)
なければ自分で作ればいいので心配無用だ。
Finder だともしかしたら Library ディレクトリが見えないかもしれないが、そんな場合は Finder のメニューから「移動」>「フォルダへ移動」の画面で「/Users/hoge/Library」と入力すれば Library ディレクトリに移動できる。

試しに FOSE2012 のスタイルファイルを FOSE 2012 論文募集 のページの「フォーマット」「latex」のリンクから取ってきてインストールしてみた。
ファイル名は fose2012_latex_sty.zip であり、展開すると次のようなファイルが含まれたディレクトリ fose2012_latex_sty が生成される
  • example.pdf
  • example.tex
  • fose2005logo.eps
  • fose2012.cls
  • fose2012.sty
上3ファイルは .cls ファイルと .sty ファイルがきちんとインストールされたかどうかを試すためのスタイルファイル使用サンプルである。
下2ファイルは肝心要のクラスファイルとスタイルファイルでる。

展開して生成された fose2012_latex_sty ディレクトリを目的の場所に移動する。
~/Library/texmf/tex/latex/fose2012_latex_sty
となるように移動(またはコピー)すれば完成である。mktexlsrの実行などは必要ない。

2012年7月21日土曜日

プログラム開発にはCUIでの経験が生きる カレントディレクトリ的な意味で

画像表示の質問 - C言語何でも質問掲示板での質問で見られるように、GUIしか使ったことがないと「カレントディレクトリ」というものの存在を認識する機会に恵まれません。そんなものを意識せずとも作業ができるように、ある意味でUIが進化した結果なのだと思いますし、意識しなくてもできるようなことしかしないのならそれでいいと思います。

しかしいざプログラミングしようとしたときに、カレントディレクトリは結構詰まりやすいポイントだと思います。プログラムが現在動作しているディレクトリなんて、GUIしかやってなかったら想像つかないでしょう。

こう考えると、プログラミング初心者にプログラムを教えるときもターミナル上でコマンドを叩く方式で教えたほうが、なんだかいい気がしてきました。

2012年7月19日木曜日

Eclipse CDT C言語パーサーに好きなヘッダファイルを使わせる

今まで Eclipse CDT でC言語のパースをする場合

IncludeFileContentProvider
にはIncludeFileContentProvider.getEmptyFilesProvider()を指定していました。(CDTでASTを参照)

ところが今日、この方法を使うとある問題にぶち当たることがわかりました。
想像はしていましたが、ヘッダファイルがまったく #include されずにパースが行われるのです。それでもなんとなくパースできちゃうのがCDTのすごいところですが、問題は識別子の型を正確に取れないということです。
ソースコードに現れる名前、例えば「add」が変数名なのか何なのかは、その宣言が無いと分かりません。たとえ「add(2, 3)」のように、いかにも関数呼び出し風に書かれていたとしても、もしかしたら関数ポインタ、すなわち単なる変数かもしれないのです。

ということで、正確に識別子の型を判別するには #include を無視せずにヘッダファイルを読み込むようにしなければなりません。そこで登場するのが
IncludeFileContentProvider.getSavedFilesProvider()
です。 SavedFilesProvider は、パース対象のC言語ソースコードがある場所と IScannerInfo に設定したインクルード検索パスをヒントにして実際のヘッダーファイルを探し、 #include をきちんと処理してくれます。

基本的にはこれで良いのですが、僕のプラグインの作り方が特殊なため、不具合がでるのです。僕はプラグインを Eclipse のプラグインとしてではなく、通常のJavaアプリとして開発しているため、プラグインの実行時にはワークスペースが開かれていない状態となります(Eclipse 上で動いていないので当たり前)。
その状態で SavedFilesProvider を使うと
java.lang.IllegalStateException: Workspace is closed.
at org.eclipse.core.resources.ResourcesPlugin.getWorkspace(ResourcesPlugin.java:399)
なる例外が発生してしまいます。

SavedFilesProvider はユーザーのヘッダファイルも探してくれる機能を持っているため、ワークスペースが開かれていないとユーザーのヘッダファイルを探せなくて例外が出ます。困りました。これでは単体テストができないじゃないですか。
さらに僕がやりたいのは、GCCの汚れたヘッダではなく、 ANSI-C に準拠するミニマムなヘッダを食わせてパースしたいんです。

そこで、僕が考えた解決策は InternalFileContentProvider (SavedFilesProvider の親クラス)を継承して、独自のプロバイダを書くことです。このクラスはどうやら内部使用が前提のクラスらしく、継承元に指定しようとすると Discouraged access などと警告が出るので気持ち悪いですが、エラーにはなりませんので無視します。
public class MyFileContentProvider extends InternalFileContentProvider {
    final private Map<String, char[]> stdHeaders;

    public MyFileContentProvider() {
        stdHeaders = new HashMap<String, char[]>();
        stdHeaders.put("/usr/include/stdio.h", "int puts(const char* s);".toCharArray());
        stdHeaders.put("/usr/include/stdlib.h", "".toCharArray());
    }

    @SuppressWarnings("restriction")
    @Override
    public InternalFileContent getContentForInclusion(String filePath,
            IMacroDictionary macroDictionary) {
        if (!getInclusionExists(filePath)) {
            return null;
        }

        if (stdHeaders.containsKey(filePath)) {
            return (InternalFileContent) FileContent.create(filePath, stdHeaders.get(filePath));
        }
        return SavedFilesProvider.getInstance().getContentForInclusion(filePath, macroDictionary);
    }

    @SuppressWarnings("restriction")
    @Override
    public InternalFileContent getContentForInclusion(IIndexFileLocation ifl,
            String astPath) {
        return SavedFilesProvider.getInstance().getContentForInclusion(ifl, astPath);
    }

}
結局作ったのがこんなクラスです。まだ製作途中なので標準ヘッダの中身が超適当ですが、これを拡充していけばいけるはずです。
ポイントは

  • 標準ライブラリのファイル名が来たら、組み込みの文字列からFileContentを作って返す
  • それ以外のファイル名がきたら、 SavedFilesProvider に委譲する
の2点です。結局 SavedFilesProvider を使ってしまっていますが、単体テストでは標準ライブラリだけを使うようにすれば、 SavedFilesProvider は呼び出されませんので、例外が発生しません。

以上、ヘッダファイルを考慮に入れた CDT でのパース方法でした。

2012年7月8日日曜日

Eclipse の機能を使ったプログラムを java コマンドで実行する

Eclipse のプラグインを開発する場合、多かれ少なかれ他のプラグイン(Eclipse 自体がプラグインで出来ています)のクラス群を利用することになります。また、 Eclipse のプラグインではない普通のプログラムを作る場合にもそれらクラス群を利用可能です。実際に Eclipseプラグインの開発サイクル短縮化計画 では、Eclipseプラグインを通常のJavaアプリに変えて実行しています。


Eclipse をインストールしたディレクトリの plugins ディレクトリを開いてみれば、膨大な数の jar ファイルに驚くと思います。これらの jar ファイルに含まれるクラス群を自由に使っていいと思うと非常にワクワクしますね!

今回はコマンドラインから java コマンドを用いて、 Eclipse のクラス群を利用した通常のアプリを起動させる方法を模索しました。なぜかって?アプリのテストを自動化するためです。java コマンドで起動させられれば、 Eclipse の上で実行せずとも、シェルスクリプトなどを用いてアプリを起動でき、 Eclipse と疎結合なテストが書けるのです。

さて、ここで問題になるのは、 Eclipse のクラス群を CLASSPATH に設定しなくちゃいけないということです。例えば CLASSPATH を設定せずに僕が作っているアプリを起動させると

Exception in thread "main" java.lang.NoClassDefFoundError: org/eclipse/core/runtime/IPath
 at com.github.uchan_nos.c_helper.Launcher.main(Launcher.java:112)
Caused by: java.lang.ClassNotFoundException: org.eclipse.core.runtime.IPath
 at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
 ... 1 more
という出力が出てきます。
ここで「ふむふむ、 org.eclipse.core.runtime.IPath が見つからないのか。では org.eclipse.core.runtime_3.8.0.v20120521-2346.jar を CLASSPATH に追加しよう。」と考えても、実は IPath クラスはそのjarファイルに含まれておらず、先ほどの例外は解決しないのです。
どうも、Eclipseのプラグイン(プラグイン=jarファイルと考えていいだろう)の名前と、それに含まれるクラスのパッケージ名が一致しないらしいのです。うーん、こまった。


ということで、 Eclipse の plugins ディレクトリにあるすべてのjarファイル名を列挙して、それをコロン:区切りで結合した文字列を出力するだけのスクリプトを書いてみました。
import os
import sys
import re

if __name__ == '__main__':
 plugindir = '/Applications/eclipse-juno/plugins'
 if len(sys.argv) == 2:
  plugindir = sys.argv[1]
 elif len(sys.argv) != 1:
  print('Usage: python searchplugins.py [plugin-directory]')
 
 classpath = '.'
 jarpat = re.compile(r'.*\.jar')
 files = os.listdir(plugindir)
 for f in files:
  m = jarpat.match(f)
  if m:
   classpath += ':' + os.path.join(plugindir, f)
 print(classpath)
とても愚直な実装だが。。。このスクリプトは/Applications/eclipse-junoをデフォルトのEclipseインストールディレクトリとしていますから、使う場合には変えたほうがいいでしょう。このスクリプトを searchplugins.py のような名前で保存し
python searchplugins.py
と実行すれば、/Applications/eclipse-juno/pluginsディレクトリの中にあるすべてのjarファイルのフルパスが : 区切りで出力されます。
.:/Applications/eclipse-juno/plugins/ch.qos.logback.classic_1.0.0.v20111214-2030.jar:/Applications/eclipse-juno/plugins/ch.qos.logback.core_1.0.0.v20111214-2030.jar
というような感じに。先頭にカレントディレクトリ.を含めてあるので、この出力をそのまま CLASSPATH に設定すれば、Eclipseのクラス群を利用したアプリが起動できるということになります。

CLASSPATH=`python ../test/searchplugins.py` java com/github/uchan_nos/c_helper/Launcher
実際には上記のようなコマンドを実行することにより、 Eclipse プラグインがすべて CLASSPATH に設定された状態で目的のアプリが起動し、めでたく実行できました。やったね!

2012年7月4日水曜日

Eclipse subversive SSH で private key のパスフレーズを入力できない問題

Eclipse に subversive プラグインを載せて SVN を使っています。今まで sourceforge.jp のリポジトリに公開鍵暗号方式で正常にアクセスできていました。ところが今日、作業を少し中断してから作業を再開しようとすると、なんと秘密鍵用のパスフレーズを何度入力しても弾かれるという問題が発生しました。

Eclipse + subversive な組み合わせで SSH を用いてリポジトリにアクセスしようとすると SSH の秘密鍵とパスフレーズを入力する画面が出るのですが、そのパスフレーズに正しいパスフレーズを入れても、直後にまた同じ画面が出てきて、どうやらパスフレーズが弾かれてしまいます。同じパスフレーズを持った鍵を作りなおしてもダメ、空パスフレーズの鍵を作ってみてもダメ。

途方に暮れていましたが、試しにワークスペースを切り替え、 SVN リポジトリからのインポートを試してみると、なんと上手く行くのです。そこで、本物のワークスペースの .metadata ディレクトリを削除後、試してみました。結果は成功。ワークスペースにあるプロジェクトは全部インポートし直す必要はありますが、とりあえず問題は解決したのでよしとしましょう。

追記 2012/07/17
.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.team.*
を削除したら復旧するというところまで特定しました。

追記 2012/07/30

.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.team.svn.core.prefs
を削除したら復旧するというところまで特定しました。

追記 2012/08/26 解決!
Bug 239871 で同じようなバグが報告されていました(2008年)
それが最近(2012年7月24日)になってようやく修正されたらしいとのことで、
Early Access Build版の Subversive を試してみたところ、見事問題が修正されていました!
Early Access Build版については Latest Releases - Eclipse Subversive の

Early Access Build

という項目を見てください。アップデートサイトのURLが載っていますので、そこからインストールできます。

2012年7月3日火曜日

Greek on Mac OS X

最近はどういうことか「古典ギリシア語」を学習しております。それで、Macでギリシア語を入力するという需要がありましたので、環境構築をしてみました。といっても、かなりの部分はMacの標準機能で対応できました。

ギリシア語を入力するには幾つかの方法があるのだと思いますが、僕はUnicodeでギリシア語を入力する方法を使いました。幾つかキーポイントがあります。
  • 入力ソースに「Greek Polytonic」を追加する
    システム環境設定 > 言語とテキスト > 入力ソース から設定できます
  • Command + Space でギリシア語モードを選択する
    Command + Space を一度押したあと、Commandキーを離さずに押しっぱなしにするとポップアップが出て簡単に選択できます
  • キーボードビューアを表示する
    図の場所に「キーボードビューアを表示」という項目があります
以上はMac標準機能。これだけでギリシア語を入力できるようになります。
しかし、標準のフォントだとアクセント記号などが見にくかったりしますので、お気に入りフォントを探しましょう。参考記事: 古典ギリシャ語用のフォントがサンプル付きで沢山のフォントを比較していますので、非常に便利です。僕は、悩んだ末「Aristarcoj」というフォントを入れさせていただきました。

2012年7月2日月曜日

Dell Color Laser Printer 3110cn on Mac OS X Lion

DellのA4カラーレーザーネットワークプリンタ「Dell Color Laser Printer 3110cn」をMac OS X Lionに追加する方法です。
ポイントは
  • IPアドレスを直打ちすること
  • プロトコルを「LPD (Line Printer Daemon)」にすること
  • 使用するドライバを「一般的な PostScript プリンタ」とすること
です。

プロトコルをIPPにしたりドライバをPCLにしたりしてもプリンタをうまく認識した風な表示にはなりますが、いざ印刷する段階で「プリンタでの処理が混み合っています」というメッセージが出っぱなしになり、一向に印刷できませんのでご注意ください。

2012年6月29日金曜日

Eclipseプラグインの開発サイクル短縮化計画

みなさんはEclipseのプラグインを開発したことがあるでしょうか?

Eclipseのプラグインを開発するときは、普通の手順ではEclipseの上で「テスト用のEclipse」を起動させてプラグインを動かします。

Eclipse自体が非常に重たいソフトウェアですから、それを2つ起動するともなるとメモリ使用量がものすごいことになります。しかも、メソッドが追加・削除される度にテスト用Eclipseを再起動させねばなりません。
それはつまり、1回の開発サイクルにほぼ毎回15秒くらいの待ち時間が入ってくることを意味します。Eclipse終了→ビルド→Eclipse起動→プラグインテスト

開発サイクルを速めるのに効果的なのは、プラグインとして開発しているソフトウェアを普通のJavaアプリにしてしまうことです。要するに、どこかにmainメソッドを定義し、そこから起動する形式にするのです。(このやり方は、ラボユースにおいて社員さんの方々とのブレインストーミングで浮上してきた案を元にしています)

Eclipseプラグインは通常、様々なやり方で起動されます。ツールバーのボタンから、メインメニューから、右クリックのコンテキストメニューからなど。各部分に主要な処理を埋め込んでいると僕の提案するやり方はやりにくいでしょう。

僕の提案手法が適用しやすいのは、プラグインの主要機能が1つのメソッドにまとまっており、その機能の入力データが手動で生成しやすい形式であるような場合です。手動で生成しやすいデータは例えばプログラムのソースコードです。単に文字列として表現できますので、簡単にプログラム上で表現できます。

対して、プラグインが複雑なデータを入力として必要とする場合、そのデータを用意するにはプラグインをプラグインとして起動させないといけない可能性があります。そういう場合、単純に僕の提案手法を使おうとしてもダメかもしれません。しかし、プラグインを普通のJavaアプリとして開発していくことで、開発効率が上がる、という考え方は有用なのではないかと思います。

2012年6月26日火曜日

Mac OS X + Eclipse に日本語版APIドキュメントを入れる

Javaランタイムインストールが楽だったで書いた方法でJavaをインストールすると、標準クラスライブラリのAPIドキュメントがインストールされない、ということに後から気が付きました。そこで、手動で日本語版のAPIドキュメントをインストールする方法を探しましたので、以下メモ。

OS XでとりあえずJavaの開発環境を準備するを参考にしました。

1.日本語版APIドキュメントのダウンロード
http://oracle.co.jp/へ行く
「ミドルウェア」の「Java」
「Java Platform, Standard Edition」
「Java Platform, Standard Edition (Java SE)」

「Java SE概要」なるページが出てきたら「ドキュメント」タブの「API」
下の方に
Java SEのバージョン 1.3.0、1.4.0、5.0、6 の日本語ドキュメントは、こちらのページでアーカイブ・ファイルも提供しています。
という表記があるので、「こちら」をクリック
276MBのJava Platform Standard Edition 6.0をクリックしてダウンロードします。

ダウンロードが完了したら、適当な場所に解凍します。僕は~/javadoc/に配置しました。

2.Eclipseの設定
Eclipseの環境設定から「Java」「Installed JREs」を開き「Java SE 6 (MacOS X Default)」を選択して「Edit」をクリックします。
Edit画面が開いたら、「/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/classes.jar」を選択し、「Javadoc Location...」をクリック
「Browse...」から、先ほど展開した場所を開きます。
僕の場合は~/javadoc/ja/api/を指定しました。

以上で完了です。これで、ソースコード中の標準クラスライブラリのクラス名にマウスカーソルを乗せるとJavadocが表示されるようになりました!

2012年6月24日日曜日

Mac OS Xのウイルス対策 clamXav

某社では私物PCをLANにつなぐ際、ウイルス対策ソフトのインストールが必須だそうです。僕のMacBook Airには当然ながらウイルス対策ソフトなんてプリインストールされていませんのでなんとかしないといけません。

そこで僕が目をつけたのが「clamXav」と呼ばれる、無料のウイルス対策ソフトです。このソフトはバックエンドとしてclamavというオープンソースのエンジンを用いています。clamavはUNIX系OSではよく使われるウイルス対策ソフトです。

カスペルスキーとかシマンテックとかの企業製品でもいいのですが、僕はオープンソースが好きだし無料なのでclamavを使うことにしました。

clamXavはclamXavの公式サイトからダウンロードできます。App Storeにも登録されていたのですが、App Storeの方は少しバージョンが古いですし(執筆時点の公式サイトでの最新バージョンが2.2.5に対し、App Storeでは2.2.4でした)、App Storeのバージョンには「ClamXav Sentry」が含まれていないそうですから、僕は公式サイトからダウンロードしました。

設定(といかインストールも)まだしてないのですが、設定はMac のウイルス対策あたりが参考になりそうです。

2012年6月22日金曜日

Mac OSX Lionでアンチエイリアス

ターミナルを使ってて文字のアンチエイリアスがちょっと効きすぎているかなと思いましたのでどうやればいいか調査しました。

 以前のMac OSXならば「MacOSXのアンチエイリアスがウザい」で紹介されているように、アンチエイリアスの効きをシステム環境設定画面から調整できるようです。 しかし僕が使っているMac OSX Lionではそんな項目はなくなっており、「使用可能な場合は LCD で滑らかな文字を使用」というチェックボックスになっています。要するにアンチエイリアスするかしないかの二択しかできません。

 しかしもっと調べていると「MacOSX 10.7 LION フォントのアンチエイリアスが汚い場合の回避方法」というページを見つけました。重要なのは紹介されているコマンドです。

defaults -currentHost write -globalDomain AppleFontSmoothing -int 2

この最後の「2」を0(なし)から3(最大)のいずれかの整数に設定することで、アンチエイリアスの効き方を制御することができます。僕は「1」の設定が好みでした。1に設定し、ターミナルのフォントをRictyにしていますが、結構良い感じです。

2012年6月19日火曜日

CDTでAST

今日はちょっとだけC-Helperの開発として、EclipseのCDTを使って、C言語のソースコードから抽象構文木(AST)を生成する部分を実装しました。
同じような実装は卒論のときにもしたけれど、そのたびによくわからないのがAST生成メソッドの引数です。

ILanguage.getASTTranslationUnit(
        FileContent content,
        IScannerInfo scanInfo,
        IncludeFileContentProvider fileCreator,
        IIndex index,
        int options,
        IParserLogService log)

引数がいっぱいあるけれど、これらについてまともなドキュメントは存在しません。
何を渡せばいいのかはっきりせず、卒論のときも今も、自己流で引数を用意しています。こんな感じに。

        ILanguage language = GCCLanguage.getDefault();

        FileContent reader = FileContent.create(filePath, source);

        Map<String, String> macroDefinitions = null;
        String[] includeSearchPath = null;
        IScannerInfo scanInfo = new ScannerInfo(macroDefinitions, includeSearchPath );

        IncludeFileContentProvider fileCreator = IncludeFileContentProvider.getEmptyFilesProvider();
        IIndex index = null;
        int options = 0;
        IParserLogService log = new DefaultLogService();

        try {
            IASTTranslationUnit translationUnit = language.getASTTranslationUnit(reader, scanInfo, fileCreator, index, options, log);

とりあえずFileContentだけきちんと解析したいソースコードの内容を渡すようにすれば、とりあえずはそれなりの抽象構文木が手に入るなあという印象です。

ハマっている曲

最近は「すいみん不足」(キテレツ大百科OP)にハマっています。
星井美希が歌ってるバージョンとか小阪ちひろが歌ってるバージョンとか。

どうしてこんなに眠いの?

Javaランタイムインストールが楽だった

MacBook Air (Mid 2012)だけの機能なのか、OS X Lion共通の機能なのかはよくわかりませんが、eclipseを起動させようとしたり、javaやjavacコマンドを叩いたりすると
「Javaランタイムが必要。インストールする?」
という旨のダイアログが表示され、ボタンクリックだけでJava 1.6がインストールできました。楽ですね!

実はeclipseを起動させようとして、初めてこのダイアログに出会ったのですが、その時は「JREしかインストールされないのでは(javacコマンドが入らないのでは)」と心配したので、ターミナルでjavacを実行したところ同じ(ように見える)ダイアログが表示されました。そしてそのダイアログからインストールしたところ、きちんとjavacまで導入されました。eclipseを起動しようとして表示されたダイアログからインストールしたらどうなるかは闇の中ですが。とりあえずめでたし?

2012年6月18日月曜日

開封の儀

MacBook Airの開封時に写真を撮ったので載せておきます。完全に自己満足ですね。

到着直後

ダンボールを開封すると綺麗な箱が入っています

内容物。シンプルですね。本体と電源と薄い説明書。

初オープン!

ついに手に入れたMacBook Air (Mid 2012)

注文していたMacBook Air (Mid 2012)が先ほど届きました!
記念すべき初投稿は開けたばかりのMBAからです。

このほど購入したMBAのスペックは以下の通り。

MacBook Air 13インチモデル
CPUはIntel Core i5 1.8GHzからIntel Core i7 2.0GHzへアップグレード
RAMは4GBから8BGへアップグレード
SSDは標準の256GB

最初にMBAを触った感想としては、意外に重かった、という感じですね。
それから、キーボードは今まで使っていたMacBook Pro(研究室の支給品でして、いつのモデルか良く分かっていません)より打ちやすい感じ。乾いている感触と言ったらいいのだろうか?
画面はMBPより広くていいですね。さすがにRetinaさんにはぼろ負けなんですけども。あくまで今まで使っていたMBPに比べてってことで。

さて、これから開発環境を入れていきますよ。