Hatena::ブログ(Diary)

らくがきえんじん

リンク切れ記事の多くは http://d.hatena.ne.jp/keigoi/ に移動しています. たとえば http://d.hatena.ne.jp/syd_syd/20080302#p1 の記事は http://d.hatena.ne.jp/keigoi/20080302#p1 にあります.

2020-12-31

別アカウントに移動しました。

2009-06-22

セッション型 on Haskell

Haskell の型レベルプログラミングによるセッション型の実装 full-sessions を 晒します

くわしくはこちら → http://d.hatena.ne.jp/keigoi/20090622

2009-03-10

[][] A full implementation of Session Types

π計算の型に セッション型というのがあって、そいつを Haskell上に実装して PPL2009 で発表しました。

2008-10-02

Language.C の意味解析 (1)

気をとりなおして。 Haskell用の C言語のパーザライブラリ Language.C の意味解析機能を使ってみる。

まずはグローバルスコープシンボルテーブルを表示してみる。

こんなことができる

入力 (sample.c)
enum enum1 {x, y, z};

void fundec1();

struct st1 {
  int a, b;
};

typedef struct st2_ {
  int c, d;
} st2;

static int i;
static int j = 2;
int k, l;
int m = 3;

static void staticfunc(){
}

int main(int argc, char** argv) {
  func();
  exit(-1);
}
実行
./test1 sample.c

(本来なら gcc -E とかで プリプロセスしたファイルを食わせないといけない。 sample.c はそれ自身で閉じているためそのまま食わせた。gcc -Eの処理もLanguage.Cに任せたい場合はProcessMain.hsのコメント参照)

出力
Global Declarations
    enumerators
            x  ~>  <econst enum1> x  =  0
            y  ~>  <econst enum1> y  =  1
            z  ~>  <econst enum1> z  =  2
    declarations
            fundec1  ~>  declaration fundec1 | function/external | void ()
    objects i  ~>  object i | static/internal | int
            j  ~>  object j | static/internal | int = 2
            k  ~>  object k | static/external | int
            l  ~>  object l | static/external | int
            m  ~>  object m | static/external | int = 3
    functions
            main  ~>  function main | function/external | int (int argc,
                                                               char * * argv)
            staticfunc  ~>  function staticfunc | function/internal | void ()
    tags    st1  ~>  struct st1 {a :: int; b :: int;}
            st2_  ~>  struct st2_ {c :: int; d :: int;}
            enum1  ~>  enum enum1 {x  =  0; y  =  1; z  =  2;}
    typeDefs
            st2  ~>  typedef st2 as struct st2_
            __builtin_va_list  ~>  typedef __builtin_va_list as va_list

うまくできてますね。

関数内の解析はまだできない模様。

ソースおよびコンパイル

ProcessMain.hs
module ProcessMain where

import System
import Language.C
import Language.C.System.GCC
import Control.Monad


-- Language.C を使ってソースを parse
parseMyFile :: FilePath -> IO CTranslUnit
parseMyFile input_file =
  do 
     content <- readFile input_file
     let parse_result = parseC (inputStreamFromString content) (Position input_file 0 0) -- プリプロセスしない場合
     -- parse_result <- parseCFile (newGCC "/usr/bin/gcc") Nothing [] input_file -- プリプロセスする場合
     case parse_result of
       Left parse_err -> error (show parse_err)
       Right ast      -> return ast

-- 第一引数のファイルを読み込み 処理
processMain :: (CTranslUnit -> IO ()) -> IO ()
processMain process = do
  [path] <- getArgs 
  ast <- parseMyFile path
  process ast
test1.hs
import System
import Language.C
import Language.C.Analysis
import ProcessMain
import Text.PrettyPrint

process unit = do
    putStrLn (fst $ either (error . show) id $ runTrav () trav)
  where
   trav = do
     decls <- analyseAST unit
     return (render $ pretty decls)

main = processMain process
コンパイル
ghc --make test1.hs

syd_sydsyd_syd 2008/10/02 00:35 fromEither って何だ。。 素直に either使えって。

2008-08-14

Language.C (cont.) - flexible array member(C99) を サイズ0の配列(GNU C互換)に変換

深追い日記

jhcが生成した手元のコードgcc 2.95でコンパイルするにはもうひとつ障害があった.

JHCはサンクを以下の構造体で管理するようだ:

typedef struct node {
        fptr_t head;
        sptr_t rest[];
} A_MAYALIAS node_t;

typedef struct dnode {
        what_t what;
        sptr_t rest[];
} A_MAYALIAS dnode_t;

ここで、 rest[] は flexible array member とよばれ、そのままだと(おおむね)サイズ0の配列として扱われる.この構造体を使うには、malloc(sizeof(node_t)+ほげほげ)のようにして、rest分の領域を確保する.

これのp.103, 6.7.2.1節の16に載ってます:

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

しかし gcc 2.95 は flexible array memberをサポートしてない.代わりに、GNU Cでサポートされている長さ0の配列を使うように変換したい.

5.12 Arrays of Length Zero - Using the GNU Compiler Collection (GCC)

flexible array memberを使っているのは現状ここだけなので、もうsedで書き換えても良い(もしくはjhcのコードを書き換えるか…)くらいなのだけど、あえて Language.Cでこれを実装した.

リファレンスとLanguage.C.Syntax.ASTの型名とにらめっこすれば大抵のことは分かるので気合いで書けます

converting flexible array member to an array of size 0

可読性が超悪くてごめんなさい

convFlexibleArrayMember :: CTranslUnit -> CTranslUnit
convFlexibleArrayMember = everywhere (mkT conv)
  where 
   conv :: CStructUnion -> CStructUnion
   conv (CStruct CStructTag ident (Just members@(_:_)) attrs ninfo) = CStruct CStructTag ident (Just $ init members ++ [conv_ $ last members]) attrs ninfo
   conv x = x
   conv_ (CDecl specs vars@(_:_) ninfo) = CDecl specs (init vars ++ [conv__ $ last vars]) ninfo
   conv_ x = x
   conv__ (Just (CDeclr ident vars@(_:_) lit attrs ninfo), cinit, expr) = (Just $ CDeclr ident (init vars++[convArrDeclr $ last vars]) lit attrs ninfo,cinit,expr)
   conv__ x = x
   convArrDeclr :: CDerivedDeclr -> CDerivedDeclr
   convArrDeclr (CArrDeclr quals (CNoArrSize False) ninfo) =  (CArrDeclr quals (CArrSize False (CConst (CIntConst (fromRight (readCInteger DecRepr "0")) (OnlyPos (Position (posFile $ posOfNode ninfo) 0 0))))) ninfo)
   convArrDeclr x = x
   fromRight (Right i) = i
   fromRight _ = error "impossible"

usage

こんな感じで使ってます:

arm-linux-gcc -E hs.out_code.c |./MoveVarDecls |./ConvIncompleteArray >converted.c && arm-linux-gcc -mstructure-size-boundary=8 converted.c

-mstructure-size-boundary=4 は ARM専用のオプションでアラインメントを4の倍数にするために使ってます (現状、意図通りに動いているもよう)嘘でした。boundaryは8の倍数でないとダメです。

JHCはポインタの下位2ビットをガベコレ用フラグと遅延評価フラグに使ってるのでこれをやらないとまずいことになるっぽいですこれをやってもassert failureは起きます。なんでだろう。