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