[英]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.