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