您好我获得了在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]
答案 0 :(得分:1)
你可以像毛茸茸说的那样从GHCi调用它。
但是,如果您真正想要做的是从程序中调用它(也许您与提出此问题的人在同一个类中:Dissecting java Class file in haskell),那么将它放在同一目录中作为您的主程序,并在程序的顶部,放置:
import Parse
然后在您的程序中,阅读Java类文件。你可能已经看过这样的事了:
s <- readFile "MyJava.class"
如果我们想要将文件的内容读入String
,那将会有效。但是parse
命令需要ByteString
,因此我们需要使用readFile
的不同实现。所以在你的程序的顶部,放置:
import qualified Data.ByteString as BS
现在您可以像这样阅读文件:
s <- BS.readFile "MyJava.class"
现在您拥有了类数据,并且可以调用parse
命令。这应该足以帮助您完成作业的这一部分。
<强>更新强>
让我们看看你给出的代码中函数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章。
编辑:将“class”更改为“classData”,因为“class”是Haskell关键字。