簡體   English   中英

haskell命令行

[英]haskell command line

您好,我收到了可以在Haskell中運行的代碼,我對這種語言有點陌生。 我可以編譯它,但我不知道如何使用它。 通過瀏覽它,我相信它應該解析一個Java類文件,並且我已經嘗試解析file.class,但是它給了我一個“無法加載接口文件名”。 如果有人指出我做錯了(我敢肯定這是小事),我將不勝感激。

module Parse where

import Data.Binary
import Data.Binary.Get
import Data.Word
import Control.Monad
import qualified Data.ByteString          as B
import qualified Data.ByteString.Internal as B
import qualified Data.ByteString.Lazy     as L

{-
    ClassFile {
        u4 magic;
        u2 minor_version;
        u2 major_version;
        u2 constant_pool_count;
        cp_info constant_pool[constant_pool_count-1];
        u2 access_flags;
        u2 this_class;
        u2 super_class;
        u2 interfaces_count;
        u2 interfaces[interfaces_count];
        u2 fields_count;
        field_info fields[fields_count];
        u2 methods_count;
        method_info methods[methods_count];
        u2 attributes_count;
        attribute_info attributes[attributes_count];
     }
-}

getWord16 :: Get Word16
getWord16 = getWord16be

getWord32 :: Get Word32
getWord32 = getWord32be

data JavaClass = JavaClass {
    classMinorVersion :: Word16
  , classMajorVersion :: MajorVersion
  , classConstantPoolCount :: Word16
  } deriving Show

getJavaClass :: Get JavaClass
getJavaClass = do
  checkClassMagic
  minorVersion   <- getMinorVersion
  majorVersion   <- getMajorVersion
  constPoolCount <- getConstantsPoolCount
  return $ JavaClass minorVersion majorVersion constPoolCount

checkClassMagic :: Get ()
checkClassMagic = do
  magic <- getWord32
  if magic /= 0xCAFEBABE then
    fail "Invalid magic number for Java class"
    else
    return ()

getMinorVersion :: Get Word16
getMinorVersion = getWord16 >>= return

{-
J2SE 7.0 = 51 (0x33 hex),
J2SE 6.0 = 50 (0x32 hex),
J2SE 5.0 = 49 (0x31 hex),
JDK 1.4 = 48 (0x30 hex),
JDK 1.3 = 47 (0x2F hex),
JDK 1.2 = 46 (0x2E hex),
JDK 1.1 = 45 (0x2D hex).
-}

data MajorVersion
  = J2SE_7_0
  | J2SE_6_0
  | J2SE_5_0
  | JDK_1_4
  | JDK_1_3
  | JDK_1_2
  | JDK_1_1
  deriving (Eq, Show)

getMajorVersion :: Get MajorVersion
getMajorVersion = do
    version <- getWord16be
    return $ convert version
    where convert 51 = J2SE_7_0
          convert 50 = J2SE_6_0
          convert 49 = J2SE_5_0
          convert 48 = JDK_1_4
          convert 47 = JDK_1_3
          convert 46 = JDK_1_2
          convert 45 = JDK_1_1

getConstantsPoolCount :: Get Word16
getConstantsPoolCount = getWord16 >>= return

getConstantsPool = undefined

data Tag
 = TAG_STRING
 | TAG_INTEGER
 | TAG_FLOAT
 | TAG_LONG
 | TAG_DOUBLE
 | TAG_CLASS_REF
 | TAG_STRING_REF
 | TAG_FIELD_REF
 | TAG_METHOD_REF
 | TAG_INTERFACE_REF
 | TAG_NAME_AND_TYPE

getTag :: Get Tag
getTag = do
  tag <- getWord8
  return $ convert tag
  where convert 1 = TAG_STRING
        convert 3 = TAG_INTEGER
        convert 4 = TAG_FLOAT
        convert 5 = TAG_LONG
        convert 6 = TAG_DOUBLE
        convert 7 = TAG_CLASS_REF
        convert 8 = TAG_STRING_REF
        convert 9 = TAG_FIELD_REF
        convert 10 = TAG_METHOD_REF
        convert 11 = TAG_INTERFACE_REF
        convert 12 = TAG_NAME_AND_TYPE

parse :: B.ByteString -> JavaClass
parse b = runGet getJavaClass $ L.fromChunks [b]

您可以按照hairyhum的說明從GHCi調用它。

但是,如果您真正想做的是從程序中調用它(也許您與提出此要求的人在同一個類中: 剖析haskell中的java類文件 ),然后將其放在與您相同的目錄中主程序,在程序頂部,放置:

import Parse

然后在您的程序中,讀取Java類文件。 您可能已經看到過這樣的情況:

s <- readFile "MyJava.class"

如果我們想將文件的內容讀入String那將起作用。 但是parse命令需要一個ByteString ,因此我們需要使用readFile的不同實現。 因此,在程序的頂部,輸入:

import qualified Data.ByteString as BS

現在,您可以像這樣讀取文件:

s <- BS.readFile "MyJava.class"

現在您有了類數據,並且可以調用parse命令。 那應該是足夠的信息,以幫助您完成那部分任務。


UPDATE

讓我們看一下在給定代碼中函數parse的類型簽名。

parse :: B.ByteString -> JavaClass

因此, parse將使用ByteString並返回一個JavaClass 現在讓我們看一下JavaClass的定義。

data JavaClass = JavaClass {
    classMinorVersion :: Word16
  , classMajorVersion :: MajorVersion
  , classConstantPoolCount :: Word16
  } deriving Show

因此,正如所寫,所有parse將為您提供次要版本,主要版本和常量池數。 但是,如果您分析代碼,則應該能夠看到如何對其進行修改以獲取所需的其他信息。 我建議您詳細分析該代碼以了解其工作原理。


更新2

如果您只想在GHCI中嘗試,可以執行以下操作:

:load Parse
:m + Data.ByteString
classData <- Data.ByteString.readFile "file.class"
Parse.parse classData

在GHCi會議上,我正是這樣做的。

ghci> :load Parse
[1 of 1] Compiling Parse            ( Parse.hs, interpreted )
Ok, modules loaded: Parse.
ghci> :m + Data.ByteString
ghci> classData <- Data.ByteString.readFile "file.class"
Loading package array-0.4.0.1 ... linking ... done.
Loading package deepseq-1.3.0.1 ... linking ... done.
Loading package bytestring-0.10.0.2 ... linking ... done.
ghci> Parse.parse classData
Loading package containers-0.5.0.0 ... linking ... done.
Loading package binary-0.7.0.1 ... linking ... done.
JavaClass {classMinorVersion = 3, classMajorVersion = JDK_1_1, classConstantPoolCount = 85}

但是要進行下一步,您需要編寫一個程序來調用parse ,如上所述。 假設您的程序在名為“ MyProgram.hs”的文件中。 然后,您可以在命令行中輸入runghc MyProgram.hs來運行它。

我建議閱讀Real World Haskell的第1章。

編輯:因為“類”是Haskell關鍵字,所以將“類”更改為“ classData”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM