ç¹å®ã®ããŒããŠã§ã¢ãšãœãããŠã§ã¢ã®è€åäœãéçºããå Žåãã¯ã©ã€ã¢ã³ãããã€ã¹ãäœæããå¿
èŠããããŸãããä»ã®ããã€ã¹ã§ã¯ãéåžžã®USBãã©ãã·ã¥ãã©ã€ãããŸãã¯ããæ£åŒã«ã¯USB倧容éèšæ¶è£
眮ã®ããã«èŠããŸãã ããã€ã¹ã¯ãããã€ã¹äžã®ãã¡ã€ã«èªäœãååšããããããã¯ãŒã¯äžã«ãããšããäºå®ã«ãããããããå€ã®äžçã«å¯ŸããŠååã«å€§ãããµã€ãºïŒ2GB以äžïŒã®ãã¡ã€ã«ã§FATãã¡ã€ã«ã·ã¹ãã ãã·ãã¥ã¬ãŒãããå¿
èŠããããšããç¹ã§ç°åžžã§ãã ãšã«ããããããã¯ãã¡ã€ã«ã§ã¯ãªããããçš®ã®ãªãŒãã£ãªã¹ããªãŒã ã§ãã
ã¿ã¹ã¯ã¯ãäžèŠã·ã³ãã«ã§ãããããã¯ãèªã¿åãèŠæ±ïŒSCSIã³ãã³ãïŒããšã«ããã®ãããã¯ã®å
容ãæäŸããŸãã ãããã¯ã¯ãããã¡ã€ã«ãã®ããããã«å±ããããFATãªãŒããŒãããæ
å ±ãå«ãããšãã§ããŸãã
ãã¡ãããæåã«èããã®ã¯ãFATã€ã¡ãŒãžãããšãã°bzip2ã§å§çž®ããå¿
èŠã«å¿ããŠããã€ã¹ã§è§£åããããšã§ããã ããã«3ã€ã®åé¡ãçºçããŸãã
- 100ã¡ã¬ãã€ãã®ãã¡ã€ã«ãšããã€ãã®ãã£ã¬ã¯ããªã®ãããšããå§çž®ããããã¡ã€ã«ã·ã¹ãã ã®ã€ã¡ãŒãžã¯ãããã€ã¹äžã®RAMã®éãè¶
ããçŽ125 KBãæ¶è²»ããŸãã
- æããã«ãBzip2ã¯ã»ã¯ã¿ãŒã«ã€ããŠäœãç¥ãããã¹ã¬ããã¬ãã«ã§åäœãããããã»ã¯ã¿ãŒããšã«ããã¯ããå¿
èŠããããŸãããããã£ãŠãã€ã¡ãŒãžãµã€ãºã¯éåžžã«çŠæ¢ãããŸãïŒãåç¥ã®ããã«ãå°ããªãããã¯ã§ã®ããã¯ã¯åçããããŸãã-å§çž®ã«ããã²ã€ã³ã«æ¯ã¹ãŠãªãŒããŒãããã倧ãããªããŸã
- ã€ã¡ãŒãžã®æºåïŒç©ºã®ãã¡ã€ã«ã®ããŠã³ãããã¡ã€ã«ã·ã¹ãã ã®äœæããããã³ã°ïŒã«ã¯å€ãã®æéãããããæšå®æ°å人ã®ãŠãŒã¶ãŒããããµãŒããŒã§ã®å®è£
ã«ã¯ã»ãšãã©åãå
¥ããããŸããã ãŸããäœæäžã®ã€ã¡ãŒãžèªäœã«ã¯ãããªãé¡èãªãã£ã¹ã¯é åãå¿
èŠã§ãã
ããŠãbzip2ããã€ã¯ãã³ã³ãããŒã©ãŒã«ç§»æ€ããå¿
èŠããããšããäºå®ã¯èšããŸã§ããããŸããã
ãã®ãããäœãä»ã®ãã®ãèãåºãå¿
èŠããããŸããã
ãã®åé¡ã¯æ¬¡ã®ããã«æèµ·ããããšãã§ããŸãããã¡ã€ã«ã·ã¹ãã ã®èšè¿°ãäœããã®åœ¢åŒã§å
¥åãšããŠåãåããã»ã¯ã¿ãŒçªå·ã®åèŠæ±ã«å¯ŸããŠãã®å
容ãè¿ãã³ãŒããèšè¿°ããå¿
èŠããããŸãã ã³ã³ãã³ãã¯ãµãŒãã¹æ
å ±ãŸãã¯ãã¡ã€ã«ããŒã¿ã®ããããã§ãããæå®ãããURLã®å¯Ÿå¿ãããªãŒãã£ãªã¹ããªãŒã ããååŸãããŸãã
ãã®è³ªåã®å®åŒåã«ãããèŠåã®ã·ã¹ãã ã«å°ãããŸãã
=>
ã¯ã©ã¹ã¿ãŒã¯FATãã¡ã€ã«ã·ã¹ãã èªäœã®æŠå¿µã§ããããããã¯ã©ã¹ã¿ãŒãã§ã¯ãªãã»ã¯ã¿ãŒã«ã€ããŠèª¬æããŠããããšã«æ³šæããŠãã ããã ããã€ã¹ã¯ãããã¯ã¬ãã«ã§åäœããã»ã¯ã¿ãŒã§ããããŸãã ããã¬ã€ãªã¹ããã«ãããã2Gbã®10åã®ããã¡ã€ã«ããå«ãŸããŠãããšããŸãïŒ2Gbã¯ç¡éãžã®å®çšçãªã¢ãããŒãã§ãïŒã åã«ãŒã«ã®ãµã€ãºã1ãã€ãã§ããå Žåããã¡ããããã¯äžå¯èœã§ããå ŽåãååŸããŸãã
2*1024*1024*1024 * 10 / 512 = 41 943 040
ãã¹ãŠã®ã«ãŒã«ã®ãã€ãã ããåççã ãããããã¡ãããã«ãŒã«ã¯åã»ã¯ã¿ãŒã«åºæã®ãã®ã§ã¯ãããŸããã ã»ã¯ã¿ãŒã®ç¯å²ã«ã«ãŒã«ãèšå®ããŸãã ããã«ãããäžé£ã®ã«ãŒã«ã«å°ãããŸãã
(A) =>
(A,B) =>
ãŸããã»ã¯ã¿ãŒèªäœãããã¯ããããšããŸãã ããŒã¿ãå§çž®ããã¿ã¹ã¯ã«çŽé¢ããŠããªããããããŒã¿èªäœã¯ããã€ã¹ã§äœ¿çšã§ãããWebããååŸãããããããã¡ã€ã«ã·ã¹ãã èªäœã®ãµãŒãã¹ããŒã¿ãå€å°ãªããšãã³ã³ãã¯ãã«è¡šç€ºããå¿
èŠããããŸãã äžèŠãããšããã®ããŒã¿ã«ã¯å€ãã®ç¹°ãè¿ãã·ãŒã±ã³ã¹ãå«ãŸããŠãããããæ¬¡ã®ããã«ã³ãŒãã£ã³ã°ããŸããç¹°ãè¿ãã·ãŒã±ã³ã¹ã¯æ¬¡ã®ããã«è¡šãããŸãã
( RLE, , )
éå埩ã·ãŒã±ã³ã¹ã次ã®ããã«è¡šããŸã
( Sequence, )
ããã«ããã§ã«ãšã³ã³ãŒãããã·ãŒã±ã³ã¹ãŸãã¯ãã®äžéšã¯ãåæ¿å
¥ããã«åç
§ããã®ãããã§ãããã ããããå¥ã®ã·ãŒã±ã³ã¹ããããŸã
( , )
ããããå®è£
ããã»ã¹äžã«ããã¡ã€ã«ã·ã¹ãã æ§é ã®ããã³ã³ãã¯ããªè¡šçŸã®ããã«ä»ã®ã·ãŒã±ã³ã¹ã衚瀺ãããå ŽåããããŸãã
ããã¯ãã¹ãŠãä»®æ³ãã·ã³ã®ã³ãã³ãã·ã¹ãã ã«éåžžã«äŒŒãŠãããåŒã³åºããã€ãŸãã¹ã¿ãã¯ãããããã§ãã æãåçŽãªæ¢ç¥ã®ä»®æ³ãã·ã³ã¯ãç Šã®çš®é¡ã®1ã€ã§ãã å®éãããã¯éã§ãã
åŒã³åºãããã®æ»ãã¢ãã¬ã¹ã®ã¹ã¿ãã¯ã远å ãããã¹ããã€ãã«é¢ããããŒã©ã³ãèªã®ã¬ã³ãŒããããã«ããã颿°ãã¬ãŒã ã®æŽçã«ç
©ããããå¿
èŠããªããªããŸãããã¹ãŠãéåžžã«åçŽã§ã-åŒã³åºãããæ»ããšãã«åé€ããŸã
ã¹ã¿ãã¯Rã®æäžäœã¯ãŒãã§ããããæãã¢ãã¬ã¹ã«ç§»åããŸãã
ããã«ã2ã¹ã¿ãã¯ãã·ã³ã®ããŒã¯ã³ã¹ã¬ããã³ãŒãïŒããã³ããã«ãªããŸãïŒã®å¯åºŠã¯éåžžã«è¯å¥œã§ããããã®å Žåãéåžžã«é©ããŠããŸãã
ãã®ãããªã³ãŒãã®è§£éã¯é«éã§ããã€ãã£ãã³ãŒããããå¹³åã§5åé
ãã ãã§ãªããéåžžã«ç°¡åã§ãã
ãããã£ãŠãããçš®ã®ã³ãŒãã£ã³ã°ã·ã¹ãã ãã«ãŒã«ã®ã·ã¹ãã ãããã³ãããã®ã«ãŒã«ãå®è¡ãããä»®æ³ãã·ã³ããããŸãã
ç¹å®ã®èšè¿°ãããããã®ã«ãŒã«ãçæãããã€ãã³ãŒããååŸãããã®è§£éã®ããã«ãã·ã³ãå®è£
ããããšãæ®ã£ãŠããŸãã ãããŠããã®åŸã«ã®ã¿äœãèµ·ãã£ãã®ããããããŸãã
ä»®æ³ãã·ã³ã®å®è£
ã«ãããç¶æ³ã¯åçŽã§ãããããããã€ã¯ãã³ã³ãããŒã©ãŒã§åäœããŸããããããŸã§Cãªãã·ã§ã³ã¯ãããŸããã 確ãã«ãããã«æžã蟌ããã®ãäœããªãå¯èœæ§ããããŸã-ã©ãããããããããçæããããšã倿ããŸã
æ¹æ³ã
æ®ã£ãŠããã®ã¯ã説æããã®ã«ãŒã«ã·ã¹ãã ã®çæã説æèªäœãã³ãŒãçæãããã³ãã®ã³ãŒãã®ã³ãã³ãã®èª¬æã ãã§ãã ããã«ãã«ãŒã«ãé çªã«ãã§ãã¯ããã®ã§ã¯ãªããäœããã®åœ¢ã§åççã«ãã§ãã¯ããããšããå§ãããŸãããã©ãŒã ã§ãã§ãã¯ãæŽçããŸã
ã»ã¯ã¿ãŒãããã®æ¯èŒæ°ãæ¯èŒæ°ã®2é²å¯Ÿæ°ã®ãªãŒããŒã«ãªãããã«ãæ¯èŒããªãŒã
æåã®åæã¯çµäºããŸããããããã¿ã€ããäœæããŠãåŸããããã®ã確èªããå¿
èŠããããŸãã
ããŸããŸãªæ¬¡å
ãšãšã³ãã£ã¢ã³ã®ãã€ããªããŒã¿ãçæããå Žåã«ãã£ãŠã¯èªã¿èŸŒãå¿
èŠãããïŒFATãµãŒãã¹ããŒã¿ã¯ããŒãšã³ãã£ã¢ã³åœ¢åŒã§æžã蟌ãŸããŸãïŒããã¹ããããããŒã¿æ§é ãæäœããå¿
èŠããããŸãã
ããã¯äœã«å®è£
ãããŸããïŒ CãC ++ããŸãã¯Pythonã§ããïŒ ãããšãã«ããŒïŒ åè«ã
ãã¡ãããHaskellã§ãããè¡ããŸããã¿ã¹ã¯ã¯æãåçŽã§ã¯ãªããäœããã®ããã©ãŒãã³ã¹ãå¿
èŠã§ãããæéã¯ã»ãšãã©ãããŸããã ãŸãããšã«ããããã®ã³ãŒããåŒã³åºããµãŒããŒãå®è£
ãããŠããŸã
Haskellã®ã§ãéžæã¯éåžžã«èªç¶ã§ãã
å§ããŸãããã
ã·ã¹ãã ã®äžå¿çãªãã®ã¯ãã«ãŒã«ãã§ãã ãããã¯ãã¡ã€ã«ã·ã¹ãã ã®èšè¿°ã倿ãããããããã³ãŒããçæãããŸãã ãããã«ã€ããŠèª¬æããŸãã
data Rule = REQ Int [Chunk] | RANGE Int Int [Chunk] deriving Show
data Chunk = SEQ BS.ByteString
| RLE Int Word8
deriving (Eq, Ord)
ããã«ããã£ã¬ã¯ããªãšãã¡ã€ã«ã§æ§æããããã¡ã€ã«ã·ã¹ãã èªäœã®èª¬æããããFATèªäœã®è©³çްãèšèŒãããŠããŸãã
data Entry = DirRoot Int [Entry] | DirDot Int | DirDotDot Int | Dir Int String [Entry] | File Int String Int BS.ByteString deriving (Eq, Ord, Data, Typeable, Show)
data Entry = DirRoot Int [Entry] | DirDot Int | DirDotDot Int | Dir Int String [Entry] | File Int String Int BS.ByteString deriving (Eq, Ord, Data, Typeable, Show)
ããã§ããã«è©³ãã説æããŸãã å¥åŠãªã³ã³ã¹ãã©ã¯ã¿DirDorãšDirDotDotã¯ãããããã£ã¬ã¯ããªã«ãããŸããã ãããŠãã..ãã¯ãããã§é©ãã¹ãããšã«ãäžæµã®ç©ççã«ååšãããã£ã¬ã¯ããªãšã³ããªã§ãã 幞ããªããšã«
ã¯åãªããªã³ã¯ã§ãããã¯ã©ã¹ã¿ãŒã®å²ãåœãŠãå¿
èŠãšããŸããã
ãã以å€ã®å Žåããã¹ãŠãæããã§ããåã³ã³ã¹ãã©ã¯ã¿ã®æåã®å±æ§ã¯äžæã®èå¥åã§ãã ããŒã¿ã®ããã¡ã€ã«ããèŠæ±ããããã¡ãŒã ãŠã§ã¢ãçè§£ããããã«ãç§ãã¡ã«ãšã£ãŠæããã«åœ¹ç«ã€ããšããããŸãã
2çªç®ã®å±æ§ã¯ãã¡ã€ã«åã§ãã ãã¡ã€ã«ã®å Žåããµã€ãºãšããŒã¿ã远å ããŸãã ãã¡ãããããã¯ãã¡ã€ã«èªäœã®ããŒã¿ã§ã¯ãªãããã®ããŒã¿ãååŸããããã€ã¹ã®ãã¡ãŒã ãŠã§ã¢ã瀺ããã®ã§ãã ããã§ãããšãã°ãsysshæ§é äœãŸãã¯ã¹ããªãŒã URLãèšè¿°ã§ããŸãã ãããã£ãŠãByteStringã
ããã§ããã¡ã€ã«ã·ã¹ãã ã®èŠä»¶ãèæ
®ããŠãäœããã®æ¹æ³ã§ãšã³ããªãäœæããå¿
èŠããããŸããã«ãŒããé€ãåãã£ã¬ã¯ããªã«ã¯ããšã³ããªããããå«ãŸããŠããå¿
èŠããããŸãã ããã³ '..'ã¯ã察å¿ãããã£ã¬ã¯ããªãåç
§ããå¿
èŠããããŸãã
åãã¬ã³ãŒãåãååã«çŠæ¢æåãªã©ãå«ããããšã¯ã§ããŸããã ãã®æ§é ãæåã§äœæããããšã¯é£ãããããã«ãAPIã®ãŠãŒã¶ãŒã¯ããã«å¯ŸåŠããå¿
èŠããããééããªãäœããæ··ä¹±ãããŠãã¹ãŠãå£ããŠããŸãããšãããããŸãããããã¯æ·±å»ãªåé¡ã§ãã ãããã£ãŠãã¢ãžã¥ãŒã«ããã®ãšã³ããªã¿ã€ãã®ã³ã³ãã³ãã®ã€ã³ããŒããçŠæ¢ãããŠãŒã¶ãŒã«ãã䟿å©ã§ãšã©ãŒä¿è·ããããœãªã¥ãŒã·ã§ã³ãæäŸããããšããå§ãããŸãã æ¬¡ã®ãããªãã®ïŒ
fileContents = ... fatSample2 = filesystem $ do file "file0" (16384) fileContents dir "A" $ do file "file1" (megs 100) fileContents dir "C" $ do file "file3" (megs 100) fileContents file "file4" (megs 100) fileContents file "file5" (megs 100) fileContents dir "E" $ emptyDir dir "B" $ do file "file2" (megs 50) emptyFile
fileContents = ... fatSample2 = filesystem $ do file "file0" (16384) fileContents dir "A" $ do file "file1" (megs 100) fileContents dir "C" $ do file "file3" (megs 100) fileContents file "file4" (megs 100) fileContents file "file5" (megs 100) fileContents dir "E" $ emptyDir dir "B" $ do file "file2" (megs 50) emptyFile
èšèªãç¥ããªã人ã§ããããã§èª¬æãããŠããããšãçè§£ã§ããŸãã
å®è£
ã¯ç°¡åã§ããäœããçæããããã«ããã§ã«æ¢è£œã®Monad WriterããããŸãã
ããã«ãäžæã®èå¥åãé
åžããå¿
èŠããããŸãããã®ãããäœããã®ã«ãŠã³ã¿ãŒãé
眮ããStateã圹ç«ã¡ãŸãã StateãšWriterãã¯ãã¹ããããã®ã§ãã¢ãã倿åã¯ç§ãã¡ãå·ã€ããŸããã ãã®ãããªãã®ïŒ
newtype EntryIdT ma = EntryIdT { runF :: (WriterT [Entry] (StateT (Int, Int) m)) a } deriving (Monad, MonadWriter [Entry], MonadState (Int, Int)) type EntryIdM = EntryIdT Identity runEntryIdM :: (Int, Int) -> EntryIdM a -> ([Entry], (Int, Int)) runEntryIdM init f = runState (execWriterT (runF f)) init filesystem :: EntryIdM () -> Entry filesystem f = DirRoot 0 dirs where dirs = fst $ runEntryIdM (1,0) f dir :: String -> EntryIdM () -> EntryIdM () file :: String -> Int -> (EntryInfo -> BS.ByteString) -> EntryIdM ()
newtype EntryIdT ma = EntryIdT { runF :: (WriterT [Entry] (StateT (Int, Int) m)) a } deriving (Monad, MonadWriter [Entry], MonadState (Int, Int)) type EntryIdM = EntryIdT Identity runEntryIdM :: (Int, Int) -> EntryIdM a -> ([Entry], (Int, Int)) runEntryIdM init f = runState (execWriterT (runF f)) init filesystem :: EntryIdM () -> Entry filesystem f = DirRoot 0 dirs where dirs = fst $ runEntryIdM (1,0) f dir :: String -> EntryIdM () -> EntryIdM () file :: String -> Int -> (EntryInfo -> BS.ByteString) -> EntryIdM ()
å颿°ã¯ãååããµã€ãºããã¹ããããã¬ã³ãŒããæ§ç¯ããããã®å¥ã®ã¢ããå€ãªã©ã®ãã©ã¡ãŒã¿ãŒãåããŸãã ãã®ãããªèšç®ã¯ããããåå¥ã®ã©ã€ã¿ãŒã§å®è¡ãããèå¥åãäžæã«ãªãããã«ç¶æ
ããã©ãã°ãããŸãã
ããã§ããã£ã¬ã¯ããªæ§é ãèšå®ããŸãããä»åºŠã¯ãªããšãããŠã«ãŒã«ãå€ãå¿
èŠããããŸãã
ãããè¡ãã«ã¯ãäœããã®æ¹æ³ã§ããŒã¿ãã¡ã€ã«ãšãã£ã¬ã¯ããªãããã£ã¹ã¯ãã«é
眮ããŸãã
ãããã¯ãæåã«ãã£ã¬ã¯ããªã次ã«ãã¡ã€ã«ã®é ã«é
眮ããããšæ³å®ããŠããŸãã
data AllocEntry = AllocEntry { beginSect :: Int , endSect :: Int , entry :: Entry } deriving (Show) allocate :: ClustSize32 -> Int -> Entry -> [AllocEntry] allocate cl from = eFix . eAlloc . eOrder . filter eFilt . universe where eFilt (File _ _ _ _) = True eFilt (Dir _ _ _) = True eFilt (DirRoot _ _) = True eFilt _ = False eOrder = uncurry (++) . partition (not.isFile) eAlloc = reverse . snd . foldl fentry (from, []) fentry (n, xs) e = let sectors = entryLen cl e `div` fatSectLen begin = n end = begin + sectors - 1 n' = n + sectors allocated = AllocEntry begin end e in (n', allocated : xs) eFix = id
data AllocEntry = AllocEntry { beginSect :: Int , endSect :: Int , entry :: Entry } deriving (Show) allocate :: ClustSize32 -> Int -> Entry -> [AllocEntry] allocate cl from = eFix . eAlloc . eOrder . filter eFilt . universe where eFilt (File _ _ _ _) = True eFilt (Dir _ _ _) = True eFilt (DirRoot _ _) = True eFilt _ = False eOrder = uncurry (++) . partition (not.isFile) eAlloc = reverse . snd . foldl fentry (from, []) fentry (n, xs) e = let sectors = entryLen cl e `div` fatSectLen begin = n end = begin + sectors - 1 n' = n + sectors allocated = AllocEntry begin end e in (n', allocated : xs) eFix = id
ã³ãŒãå
šäœã¯éåžžã«æçœã§ãããã¹ãŠã®ã¬ã³ãŒããååŸããããããåé€ããŸãã ç¬èªã®ã¯ã©ã¹ã¿ãŒãæãããèŠç¥ãã¬äººãæãã ãã§ããã£ã¬ã¯ããªãæåã«ã次ã«ãã¡ã€ã«ãäœæããŸãïŒéãã¯ãããŸããããããè«ççã§ãã
ããªã¥ãŒã ã®ç®æ¬¡ãèªã¿ããããªããŸãïŒãã»ã¯ã¿ãŒãéžæããŸãïŒã»ã¯ã¿ãŒãæäœããæ¹ã䟿å©ã§ãããã¯ã©ã¹ã¿ãŒãã¯äººå·¥çãªæŠå¿µã§ãïŒãããã ãã§ãã
uniplateã¢ãžã¥ãŒã«ã®ãŠãããŒã¹é¢æ°ã«æ³šç®ãã䟡å€ããããŸãã ãã¹ããããæ§é ã®ãã¹ãŠã®èŠçŽ ããªã¹ãã«ãªã¹ããïŒå¿
èŠã«å¿ããŠãªã¹ãå
å
衚èšã䜿çšïŒãååž°çãªèµ°æ»é¢æ°ã®ã«ãŒãã³äœæãåé¿ã§ããŸãã
圌女ã®ããã«ããšã³ããªæŽŸçåïŒDataãTypeableïŒãäžèšã§å®£èšããŸããã
ãã¡ã€ã«ãã»ã¯ã¿ãŒããšã«é
眮ãããšããããã®ã«ãŒã«ãçæããã®ã«è²»çšã¯ããããŸããã
generateData :: Maybe CalendarTime -> ClustSize32 -> [AllocEntry] -> [Rule] generateData ct cl es = mergeRules $ execWriter $ do forM_ es $ \(AllocEntry {beginSect = a, endSect = b, entry = e}) -> do case e of DirRoot _ es -> writeEntries ab es Dir _ _ es -> writeEntries ab es File _ _ _ bs -> tell [RANGE ab (encodeBlock (BS.take (fatSectLen) bs))] where ...
generateData :: Maybe CalendarTime -> ClustSize32 -> [AllocEntry] -> [Rule] generateData ct cl es = mergeRules $ execWriter $ do forM_ es $ \(AllocEntry {beginSect = a, endSect = b, entry = e}) -> do case e of DirRoot _ es -> writeEntries ab es Dir _ _ es -> writeEntries ab es File _ _ _ bs -> tell [RANGE ab (encodeBlock (BS.take (fatSectLen) bs))] where ...
ããã®encodeBlock颿°ã¯ByteStringãäžé£ã®ã«ãŒã«ã«ãšã³ã³ãŒãããwriteEntriesã¯ãã£ã¬ã¯ããªãšã³ããªãçæããŠãããããšã³ã³ãŒãããmergeRuleã¯é£ç¶ããã«ãŒã«ã®ã»ã¯ã¿ãŒã®ç¯å²ãçµåããããšããŸãã
åäžã®ãã£ã¬ã¯ããªãšã³ããªã®çæã¯æ¬¡ã®ããã«ãªããŸãã
entryRecordShort :: String -> Int -> Int -> Maybe CalendarTime -> [ATTR] -> BS.ByteString entryRecordShort nm size clust clk a = runPut $ do putNameASCII nm
entryRecordShort :: String -> Int -> Int -> Maybe CalendarTime -> [ATTR] -> BS.ByteString entryRecordShort nm size clust clk a = runPut $ do putNameASCII nm -- Name putWord8 (fatAttrB a) -- Attr putWord8 0 -- NTRes putWord8 0 -- CrtTimeTenth putWord16le cT -- CrtTime putWord16le cD -- CrtDate putWord16le cD -- LstAccDate putWord16le cHi -- FstClusHI putWord16le cT -- WrtTime putWord16le cD -- WrdDate putWord16le cLo -- FstClusLO putWord32le (fromIntegral size) -- FileSize where ...
ããã§ã¯ãData.Binary.Putã®éåžžã«äŸ¿å©ãªPutMã¢ããã䜿çšããŸããããã«ãããä»»æã®ãããæ·±åºŠãšãšã³ãã£ã¢ã³ã®ããŒã¿ãé
å»¶ãã€ãæååã«åºåã§ããŸãã
ãããã£ãŠãFATããªã¥ãŒã ã®ãã£ã¬ã¯ããªæ§é ãã»ã¯ã¿ãŒå¥ã®å²ãåœãŠãããã³å¯Ÿå¿ããã«ãŒã«ããããŸãã ç§ãã¡ã¯äœãæ®ããŸãããïŒ
ããã§ãå°ãåŸéããŠFATããã€ã¹ãèŠããŠããå¿
èŠããããŸãã Webãæç®ã§åºãå©çšãããŠããäžå¿
èŠãªè©³çްã«è§Šããªãå ŽåãFAT32ã¯æ¬¡ã®ããã«èšèšãããŠããŸãã
| BootSect | FAT32æ
å ±| FAT1 | FAT2 |ããŒã¿|
ãããŸã§ã®ãšãããDATAã®ã«ãŒã«ã®ã¿ããããŸãã FAT1ããã³FAT2ã¯ã¯ã©ã¹ã¿ãŒå²ãåœãŠããŒãã«ã§ãã åãã¡ã€ã«ãŸãã¯ãã£ã¬ã¯ããªïŒãã¡ã€ã«ã§ããããŸãïŒã¯ãããŒã¿é åå
ã®ã¯ã©ã¹ã¿ãŒã®ãã§ãŒã³ãå æããããŒã¿é åå
ã®åã¯ã©ã¹ã¿ãŒã¯ãFAT1ããã³FAT2ïŒåäžïŒã®32ãããå€ã§è¡šãããŸãã
åFATã»ã«ã«ã¯ãã¡ã€ã«ã®æ¬¡ã®ã¯ã©ã¹ã¿ãŒã®çªå·ãå«ãŸããæåŸã®ã¯ã©ã¹ã¿ãŒã«ã¯ç¹å¥ãªå€ãããŒã¯ãããŸãã ãã¡ã€ã«ã®æåã®ã¯ã©ã¹ã¿ãŒã®çªå·ã¯ããã£ã¬ã¯ããªãšã³ããªã«ç€ºãããŠããŸãã ãã§ãŒã³ã®åã»ã«ã«æ°å€N + 1ãæžã蟌ãŸããããã«ãããŒã¿ã¯é çªã«é
眮ãããŸãïŒNã¯åã®å€ã§ãïŒã
ããã§æåã®åé¡ãçºçããŸããèšç®ããã10 x 20Gbã®å Žåããã®ããŒãã«ã¯655360ã®32ãããå€ãå æãã䜿çšå¯èœãªRAMãåã³è¶
ããŸãã ãã ãããããã®ã«ãŒã«ã¯å§çž®ã§ããŸããã
éè€ããå€ããªããããããªããã£ãRLEãããã³ã°ã¢ã«ãŽãªãºã ã ãã ãããã®ã·ãŒã±ã³ã¹ã1åçæã§ããã®ã§ãããããæ¢ã«ããã€ã¹äžã§å床çæã§ããŸãã
ããèŠããšãå²ãåœãŠããŒãã«ã®1ã€ã®ã»ã¯ã¿ãŒã®å€ã¯åã®ã»ã¯ã¿ãŒã®æå€§å€ã«äŸåããŠãããäžè¬ã«ãã·ãŒã±ã³ã¹ã¯æ¬¡ã®åŒã§æ±ºå®ãããŸãã
Na = BASE +ïŒNsect-MïŒ*ã¹ããã
Ni <-[NaãNa + 1 ..]
ããã§ãNaã¯ãã®ã»ã¯ã¿ãŒã®æåã®å€ãNsectã¯èŠæ±ãããã»ã¯ã¿ãŒã®æ°ïŒããã¯ãã©ãŒããã·ã³ã®ã¹ã¿ãã¯ã®äžçªäžã«ãªããŸãïŒãMãBASEããã³STEPã¯éçã«èšç®ããã宿°ãNiã¯ã·ãŒã±ã³ã¹ã®içªç®ã®æ°ãã»ã¯ã¿ãŒå
šäœã§ãæããã«512/4ã
ãããã£ãŠãåçããŒã¿ïŒã»ã¯ã¿ãŒçªå·ïŒã«åºã¥ããŠäžé£ã®å€ãçæããæ°ããã·ãŒã±ã³ã¹ãååŸããŸããã ãã®ã·ãŒã±ã³ã¹ãšé£æ¥ããã·ãŒã±ã³ã¹ã®ã¿ã€ãã远å ããŸãã
data Chunk = SEQ BS.ByteString | RLE Int Word8 | SER Word32 Word32 | NSER Word32 Int Word32
data Chunk = SEQ BS.ByteString | RLE Int Word8 | SER Word32 Word32 | NSER Word32 Int Word32 -- base offset step | CALLBACK Word8 deriving (Eq, Ord)
ä»åŸã¯ãã³ãŒã«ããã¯ã«å¥ã®ã«ãŒã«ã远å ããŸããããã¯ãã¡ã€ã«ããŒã¿ã»ã¯ã¿ãŒã®çæåŸã«åŒã³åºãå¿
èŠããããŸããããã«ãããããã€ã¹ãã¡ãŒã ãŠã§ã¢ããããã¡ãŒãååŸããå®ããŒã¿ã§åããŸãã
ã«ãŒã«ã®ã»ããã®åœ¢åŒã§ããŒãã«ãããã«çæããããšã¯å¯èœã§ãããäœããã®çç±ã§ãã€ããªåœ¢åŒã§å¿
èŠã§ãããããã«ããã€ããªæååããšã³ã³ãŒãããããã®ãããã°é¢æ°ãæ¢ã«ãããçŽæ¥çæã§ã¯ç°¡åã§ã
ééããŸãã
ãã®ããŒãã«ã¯éåžžã«å€§ããã倧ããªããŒã¿é åãšå°ããªã¯ã©ã¹ã¿ãŒãµã€ãºã®å Žåã貧匱ãªHaskellã¯èŠåŽããŸãã
ããæç¹ã§ã倧ããªã¬ã€ãžãŒãªWord32ãªã¹ããããã¢ããªã±ãŒã·ã§ã³ã¯æ¬åœã«æªããšæããã®ã§ãã¬ã€ãžãŒãªãã€ãã©ã€ã³ã«ãã°ããæžãæããrunPut / runGetã䜿çšããŠ32ãããå€ãããã«å
¥ããŠååŸããå¿
èŠããããŸããã
é©ãã¹ãããšã«ãããã¯çŽ10åã®å éãããããããã¹ãŠã蚱容å¯èœãªé床ã§åäœãå§ããŸãããããã¡ãããã«ãŒã«ãããã«çæããããŒã¿ãäœæããªãããã«æžãæããå¿
èŠããããŸãã
ããããã³ã³ã»ããã«ã€ããŠã¯ããããªããŸãã
ããŒãã«ã®çæé¢æ°ãšãã®ã«ãŒã«ãçç¥ããŸãããããã¯éåžžã«å€§ããã§ãããåæã«éåžžã«æçœã§ãã
type ClusterTable = BS.ByteString genFAT :: ClustSize32 -> Int -> [AllocEntry] -> ClusterTable encodeFAT :: Int -> ClusterTable -> [Rule]
type ClusterTable = BS.ByteString genFAT :: ClustSize32 -> Int -> [AllocEntry] -> ClusterTable encodeFAT :: Int -> ClusterTable -> [Rule]
ããŒãã«ãšã³ã³ãŒãã£ã³ã°é¢æ°ã¯ãæåã«åã»ã¯ã¿ãŒã1ã€ã®ã«ãŒã«REQ aïŒNSER _ _ _ïŒã«é¢é£ä»ããæ¬¡ã«ã»ã¯ã¿ãŒããã¢ã§èæ
®ãã2ã€ã®ã»ã¯ã¿ãŒãå€ã®å
±éã·ãŒã±ã³ã¹ã圢æããå Žåãã»ã¯ã¿ãŒã®ã«ãŒã«ã¯ã»ã¯ã¿ãŒã®ç¯å²ã®ã«ãŒã«ã«çœ®ãæããããçµæã¯éåžžã«ã³ã³ãã¯ãã«ãªããŸãããã«æã£ãŠããããšãã§ããããã«ïŒ
REQ 32 [SEQ [F8]ãRLE 2 255ãSEQ [0F]ãRLE 3 255ãSEQ [0F]ã
RLE 3 255ãSEQ [0F]ãRLE 3 255ãSEQ [0F]ãRLE 3 255ã
SEQ [0F]ãRLE 3 255ãSEQ [0F]ãRLE 3 255ãSEQ [0F]ã
SEQ [08]ãRLE 3 0ãSEQ [09]ãRLE 3 0ãSEQ [0A]ã
RLE 3 0ãRLE 3 255ãSEQ [0F]ãSER 12128]
ç¯å²33,231 [NSER 129 33 128]
REQ 232 [SER 25601 25610ãRLE 3 255ãSEQ [0F]ãSER 25612 25728]
ç¯å²233431 [NSER 25729 233128]
REQ 432 [SER 51201 51210ãRLE 3 255ãSEQ [0F]ãSER 51212 51328]
ç¯å²433 631 [NSER 51329 433 128]
REQ 632 [SER 76801 76810ãRLE 3 255ãSEQ [0F]ãSER 76812 76928]
ç¯å²633 831 [NSER 76929 633 128]
REQ 832 [SER 102401 102410ãRLE 3 255ãSEQ [0F]ãSER 102412 102528]
ç¯å²833 931 [NSER 102529 833 128]
REQ 932 [SER 115201 115210ãRLE 3 255ãSEQ [0F]ãRLE 468 0]
ç¯å²933 1056 [RLE 512 0]
2ã¡ã¬ãã€ãã®ããŒã¿ãããæããã«åªããŠãããææã«èŠããŸãã
ããŒãã«ã®2çªç®ã®ã³ããŒã¯å®æ°ã«å¯ŸããŠæ£ç¢ºã§ãããããå°æ¥ããªãã»ãããã宿°ãæžç®ããŠæåã®ããŒãã«ãåŒã³åºãããšã«ããããã®ã·ãŒã±ã³ã¹ã眮ãæããããšãã§ããŸãã ããããããã¯åŸã§ã
ãããã£ãŠãFAT1ãFAT2ãããã³DATAããããŸãã BootSectããã³FAT32æ
å ±ã®ã¿ãååŸããŸãã ããã¯éçãªãã€ããªããŒã¿ãªã®ã§ãåã³Data.Binary.Putã䜿çšããŠãããã«ãŒã«ã«ããã¯ããŸãã
ãããã®2ã€ã®ã¢ãžã¥ãŒã«ïŒPutããã³GetïŒã¯æåéãäžå¯æ¬ ã§ãããå人çã«ã¯ãErlangã®ãã€ããªãã¿ãŒã³ãããé«ãåŒçšããŠããŸãããããã¯äž»èгçãªãã®ã§ãã
fatGenBoot32 :: FAT32GenInfo -> BS.ByteString fatGenBoot32 info = addRsvd $ runPut $ do
fatGenBoot32 :: FAT32GenInfo -> BS.ByteString fatGenBoot32 info = addRsvd $ runPut $ do -- BOOT AREA sect0 putBytes [0xEB, 0x58, 0x90] -- 0 JmpBoot putBytes bsOEMName -- OEMName putWord16le bps -- BytesPerSec putWord8 spc -- SectPerClust putWord16le rsvd -- ReservedSecCnt putWord8 2 -- NumFATs putWord16le 0 -- RootEntCnt putWord16le 0 -- TotSec16 putWord8 0xF8 -- Media putWord16le 0 -- FAT16Sz putWord16le 0x3F -- SectPerTract putWord16le 0xFF -- NumHeads putWord32le 0 -- HiddSec putWord32le sectNum -- TotSec32 -- FAT32 Structure putWord32le fsect -- FATSz32 -- ... --
çµæã«ããã«ãŒã眮ããã«ãŒã«ãç¯å²ã«ããŒãžãããã¡ã€ã«ã·ã¹ãã å
šäœã説æããã«ãŒã«ã®æçµãªã¹ããååŸããŸãã
ãããã£ãŠãäžé£ã®ã«ãŒã«ããããŸãã ãããã®ããã®æ¯èŒããªãŒãçæããããšã¯æ®ã£ãŠããŸã
ãã¹ãŠããã€ãã³ãŒãã§ã³ã³ãã€ã«ããŸãã
ããªãŒããå§ããŸãããïŒ
data CmpTree = GEQ Int CmpTree CmpTree | CODE [Rule] deriving (Show) mkCmpTree :: [Rule] -> CmpTree mkCmpTree r = mkTree' rulemap where rulemap = M.fromList $ map (\x -> (fsect x, x)) r splitGeq nm = let (a, b, c) = M.splitLookup nm in (a, c `M.union` (maybe M.empty (M.singleton n) b)) mkTree' xs | M.null xs = CODE [] | M.size xs < 3 = CODE (map snd (M.toList xs)) | otherwise = let ks = map fst $ M.toAscList xs n = ks !! (length ks `div` 2) (le, geq) = splitGeq n xs in GEQ n (mkTree' le) (mkTree' geq)
data CmpTree = GEQ Int CmpTree CmpTree | CODE [Rule] deriving (Show) mkCmpTree :: [Rule] -> CmpTree mkCmpTree r = mkTree' rulemap where rulemap = M.fromList $ map (\x -> (fsect x, x)) r splitGeq nm = let (a, b, c) = M.splitLookup nm in (a, c `M.union` (maybe M.empty (M.singleton n) b)) mkTree' xs | M.null xs = CODE [] | M.size xs < 3 = CODE (map snd (M.toList xs)) | otherwise = let ks = map fst $ M.toAscList xs n = ks !! (length ks `div` 2) (le, geq) = splitGeq n xs in GEQ n (mkTree' le) (mkTree' geq)
ããã¯æè¯ã®éžæè¢ã§ã¯ãªããããããŸããããã«ãŒã«ã¯100æªæºã§ããããšã倿ãããŸã å¿é
ããããšã¯ã§ããŸããã
ä»®æ³ãã·ã³ãã³ãã³ãã»ãããããã³ã³ã³ãã€ã©æ¬¡ç¬¬ã§ãã
- , - class OpcodeCL a where isRLE :: a -> Bool arity0 :: a -> Bool arity1 :: a -> Bool arity2 :: a -> Bool arity3 :: a -> Bool firstCode :: a lastCode :: a data Opcode = DUP | DROP | CONST | CRNG | JNZ | JZ | JGQ | JNE | JMP | CALLT | CALL | RET | NOT | EQ | NEQ | GT | LE | GQ | LQ | RNG | LOADS2 | LOADS3 | LOADS4 | LOADS5 | LOADS6 | LOADS7 | LOADS8 | LOADS9 | LOADS10 | LOADSN | SER | NSER | NSER128 | RLE1 | RLE2 | RLE3 | RLE4 | RLE5 | RLE6 | RLE7 | RLE8 | RLE16 | RLE32 | RLE64 | RLE128 | RLE256 | RLE512 | RLEN | OUTLE | OUTBE | OUTB | NOP | CALLN | DEBUG | EXIT deriving (Eq, Ord, Enum, Show) data CmdArg = W32 Word32 | W16 Word16 | W8 Word8 | ADDR Addr data Addr = ALabel Label | AOffset Int data Cmd = Cmd0 Opcode | CmdConst Word32 | Cmd1 Opcode CmdArg | Cmd2 Opcode CmdArg CmdArg | Cmd3 Opcode CmdArg CmdArg CmdArg | CmdJmp Opcode Addr | CmdCondJmp Opcode Addr | CmdLabel Label | RawByte Word8 type Label = Int type Block = (Label, [Cmd])
- , - class OpcodeCL a where isRLE :: a -> Bool arity0 :: a -> Bool arity1 :: a -> Bool arity2 :: a -> Bool arity3 :: a -> Bool firstCode :: a lastCode :: a data Opcode = DUP | DROP | CONST | CRNG | JNZ | JZ | JGQ | JNE | JMP | CALLT | CALL | RET | NOT | EQ | NEQ | GT | LE | GQ | LQ | RNG | LOADS2 | LOADS3 | LOADS4 | LOADS5 | LOADS6 | LOADS7 | LOADS8 | LOADS9 | LOADS10 | LOADSN | SER | NSER | NSER128 | RLE1 | RLE2 | RLE3 | RLE4 | RLE5 | RLE6 | RLE7 | RLE8 | RLE16 | RLE32 | RLE64 | RLE128 | RLE256 | RLE512 | RLEN | OUTLE | OUTBE | OUTB | NOP | CALLN | DEBUG | EXIT deriving (Eq, Ord, Enum, Show) data CmdArg = W32 Word32 | W16 Word16 | W8 Word8 | ADDR Addr data Addr = ALabel Label | AOffset Int data Cmd = Cmd0 Opcode | CmdConst Word32 | Cmd1 Opcode CmdArg | Cmd2 Opcode CmdArg CmdArg | Cmd3 Opcode CmdArg CmdArg CmdArg | CmdJmp Opcode Addr | CmdCondJmp Opcode Addr | CmdLabel Label | RawByte Word8 type Label = Int type Block = (Label, [Cmd])
æ®å¿µãªãããããã§ã¯åçŽãªHaskellåã·ã¹ãã ãèŠéããå§ããŠããŸããã³ãã³ããšãã®ã¯ã©ã¹ã«ã³ã³ãã€ã«æã®äžå€åŒãèšå®ãããã®ã§ãããšãã°ãééã£ããªãã³ãŒãã§ããŒã ãäœæããããšã¯ã§ããŸããã ãã ãããããè¡ãããšã¯ã§ããŸããããåãªãã³ãŒãã«åå¥ã®åãã³ãã³ãã®å®åšããŒã¿åãå°å
¥ãããã¯ãããŸããããã¡ã¿ããã°ã©ãã³ã°ã䜿çšããŠãªãã³ãŒããçæããå¿
èŠã¯ãããŸããã
è¯ãæãæ¥ããŸã§å
éãããŠãç§ãã¡ãæã£ãŠãããã®ã§ããŸãè¡ããã ãšã«ãããä»®æ³ãã·ã³ã®å®è£
ã®ããã«ããã¹ããæžãå¿
èŠãããã®ã§ãããã«çŸãããšã©ãŒããããã¢ããããŸãã
ãã®ãããä»®æ³ãã·ã³ã³ãã³ãã·ã¹ãã ããããŸããã«ãŒã«ããæ§ç¯ãããæ¯èŒããªãŒãã³ã³ãã€ã«ããå¿
èŠããããŸãã
mkVMCode :: CmpTree -> [Block] mkVMCode xs = normalize maxl code -- skip scanT :: CmpTree -> GenM () scanT (GEQ n left right) = do s <- newLabel l <- runGen' (scanT left) >>= withLabel r <- runGen' (scanT right) >>= withLabel _ex <- newLabel label s dup cnst n jgq (labelOf r) block l >> jmp _ex block r >> label _ex scanT (CODE []) = op0 EXIT scanT (CODE rules) = mapM_ scanR rules scanR :: Rule -> GenM () scanR ( REQ n code ) = do s <- newLabel code' <- runGen' (scanmC code) >>= withLabel ex <- newLabel label s dup cnst n jne ex block code' label ex scanR ( RANGE ab code ) = do s <- newLabel code' <- runGen' (scanmC code) >>= withLabel ex <- newLabel label s dup crng ab jz ex block code' label ex -- skip
mkVMCode :: CmpTree -> [Block] mkVMCode xs = normalize maxl code -- skip scanT :: CmpTree -> GenM () scanT (GEQ n left right) = do s <- newLabel l <- runGen' (scanT left) >>= withLabel r <- runGen' (scanT right) >>= withLabel _ex <- newLabel label s dup cnst n jgq (labelOf r) block l >> jmp _ex block r >> label _ex scanT (CODE []) = op0 EXIT scanT (CODE rules) = mapM_ scanR rules scanR :: Rule -> GenM () scanR ( REQ n code ) = do s <- newLabel code' <- runGen' (scanmC code) >>= withLabel ex <- newLabel label s dup cnst n jne ex block code' label ex scanR ( RANGE ab code ) = do s <- newLabel code' <- runGen' (scanmC code) >>= withLabel ex <- newLabel label s dup crng ab jz ex block code' label ex -- skip
Writerã¢ããã®äžã«æ§ç¯ããããeDSLã䜿çšãããã®ãçæãããæ°ã«å
¥ãã®æ¹æ³ã次ã«ç€ºããŸãã
æ¯èŒããªãŒãããã©ããã³ãŒããçæãããšãããšãã°ããããã¯ããã®é·ãåºå£ãã§ãŒã³ãçºçãããªã©ãå€ãã®ãã¹ããŒããçºçããŸãã
L1: ... JMP L2 L2: JMP L3 L3: JMP L4 L4: EXIT
L1: ... JMP L2 L2: JMP L3 L3: JMP L4 L4: EXIT
次ã®ãããã¯ã«ãžã£ã³ããããªã©ã normalizeã¯ãããã®äžåèªãåãé€ããã³ãŒãããããã¯ã«åå²ããŸããåãããã¯ã¯ã©ãã«ã§å§ãŸããæ¬¡ã®ãããã¯ã³ãã³ããžã®ç¡æ¡ä»¶ãžã£ã³ãã§çµãããŸãã ãããã¯å
ã«ã¯æ¡ä»¶ä»ããŸãã¯ç¡æ¡ä»¶ã®ãžã£ã³ãã³ãã³ãã¯ãããŸãã;ãããã¯æåŸã§ã®ã¿æå¹ã§ãã ã©ãã«ãªãã»ãããèšç®ããã«ã¯ããã®ãããªãããã¯ãå¿
èŠã§ãã ãã®åŸããããã¯ãããŒãžããŠãäžèŠãªãã©ã³ãžã·ã§ã³ãå®å
šã«åãé€ãããšãã§ããŸãã
çŸããç Šã®å°å·çšã«ãã€ãã³ãŒãã®Showã€ã³ã¹ã¿ã³ã¹ãäœæãããããã¯ãæé©åããåŸã®çµæã確èªããŸãã
... L215: DUP CONST 2122 JGQ L220 DUP CRNG 00000843 00000849 JZ L235 RLE512 00 EXIT L220: DUP CRNG 0000084A 000C8869 JZ L223 LOADS2 BYTE 48 BYTE 45 RLE2 4C LOADS7 BYTE 4F BYTE 20 BYTE 57 BYTE 4F BYTE 52 BYTE 4C BYTE 44 RLE2 21 CALLN 00 EXIT L223: DUP CRNG 000C886A 000E1869 JZ L235 RLE512 00 CALLN 00 ;; --- , EXIT ;; L235: EXIT ... L0: LOADS5 BYTE 02 BYTE 08 BYTE 20 BYTE 00 BYTE 02 RET ...
... L215: DUP CONST 2122 JGQ L220 DUP CRNG 00000843 00000849 JZ L235 RLE512 00 EXIT L220: DUP CRNG 0000084A 000C8869 JZ L223 LOADS2 BYTE 48 BYTE 45 RLE2 4C LOADS7 BYTE 4F BYTE 20 BYTE 57 BYTE 4F BYTE 52 BYTE 4C BYTE 44 RLE2 21 CALLN 00 EXIT L223: DUP CRNG 000C886A 000E1869 JZ L235 RLE512 00 CALLN 00 ;; --- , EXIT ;; L235: EXIT ... L0: LOADS5 BYTE 02 BYTE 08 BYTE 20 BYTE 00 BYTE 02 RET ...
çæ³çã§ã¯ãããŸãããã錻氎ã¯ãããŸãããäžè¬çãªã³ãŒãã¯ããã·ãŒãžã£ã«éšåçã«å²ãåœãŠãããŠããããã©ã³ãããªãŒããããŸãã ããŸã
ãããäœãã§å®è¡ããããšã¯æ®ã£ãŠããŸãããã®ããã«ã¯ãæçµçã«ä»®æ³ãã·ã³èªäœãå®è£
ããå¿
èŠããããŸãããªãã³ãŒãã®ã¿ã倧å¹
ã«å€æŽããããããåçŽã«Cã§äœæã§ããŸãããçµéšããããªãã³ãŒããšCã³ãŒãã®æŽåæ§ãåŸã§ç£èŠãããããããã¹ãŠãçæããæ¹ãè¯ãããšã瀺ãããŠããŸãããããæ€èšŒããæ¹æ³ã¯ãããŸããããŸããã³ã³ãã€ã©ãŒããããçæããvmãå®å
šã«ç°ãªããã®ãè§£éãããç¶æ³ã¯ãããªãããããã§ãããããã£ãŠããã¹ãŠãçæããæ¹ãè¯ãã§ããç¹°ãè¿ããŸãããCãçæããããã®ããeDSLã®æŠèŠã¯ãæ¬åŒ§ãã€ã³ãã³ããã»ãã³ãã³ãéããå¿
èŠããããŸãããåã³äœå®¶ãããŸããŸãª... stubs :: String stubs = envFile $ do comment "top of the file" put "#include <stdint.h>" put "#include \"emufatstubs.h\"" defines ... stmt (pt codeType ++ op `assign` "code") endl push a "n" put "for(;;)" braces $ indented $ do put "switch(*op)" braces $ do forM_ codes $ \op -> do put (printf "case %s:" (show op)) indented $ decode op endl put "default:" indented $ exit exitLabel indented $ stmt "return 0" ... decode (CRNG) = do skip "1" stmt (tmp0 `assign` pop a) stmt (tmp1 `assign` decode32) >> skip "4" stmt (tmp2 `assign` decode32) >> skip "4" push a ( _and (tmp0 `gq` tmp1) (tmp0 `lq` tmp2) ) next decode (CALL) = do skip "1" stmt (tmp0 `assign` decode32) >> skip "4" stmt (push' r pc') jump tmp0 ...
stubs :: String stubs = envFile $ do comment "top of the file" put "#include <stdint.h>" put "#include \"emufatstubs.h\"" defines ... stmt (pt codeType ++ op `assign` "code") endl push a "n" put "for(;;)" braces $ indented $ do put "switch(*op)" braces $ do forM_ codes $ \op -> do put (printf "case %s:" (show op)) indented $ decode op endl put "default:" indented $ exit exitLabel indented $ stmt "return 0" ... decode (CRNG) = do skip "1" stmt (tmp0 `assign` pop a) stmt (tmp1 `assign` decode32) >> skip "4" stmt (tmp2 `assign` decode32) >> skip "4" push a ( _and (tmp0 `gq` tmp1) (tmp0 `lq` tmp2) ) next decode (CALL) = do skip "1" stmt (tmp0 `assign` decode32) >> skip "4" stmt (push' r pc') jump tmp0 ...
ç§ãã¡ãåŸããã®ãèŠãŠã¿ãŸãããïŒ #define DEFSTACK(n, t, l) ... #define RESET(a) ... #define PTOP(a) ... #define TOP(a) ... #define POP(a) ... #define PUSH(a,v) ... #define NEXT(x) ... #define JUMP(x, b, o) ... #define SKIP(x, n) ... #define PC(x, b) ... #define DECODE32(op) ... #define DECODE8(op) ... ... DEFSTACK(a, uint32_t, 16); DEFSTACK(r, uint32_t, 8); uint32_t tmp0; uint32_t tmp1; uint32_t tmp2; uint32_t tmp3; ... uint8_t *op = code; PUSH(a, n); for(;;) { switch(*op) { ... case CRNG: SKIP(op, (1)); tmp0 = POP(a); tmp1 = DECODE32(op); SKIP(op, (4)); tmp2 = DECODE32(op); SKIP(op, (4)); PUSH(a, ((tmp0 >= tmp1) && (tmp0 <= tmp2))); NEXT(op); ... case CALL: SKIP(op, (1)); tmp0 = DECODE32(op); SKIP(op, (4)); PUSH(r, PC(op, code)); JUMP(op, code, tmp0); ... case EXIT: goto _exit; default: goto _exit; } } _exit: return 0; ...
#define DEFSTACK(n, t, l) ... #define RESET(a) ... #define PTOP(a) ... #define TOP(a) ... #define POP(a) ... #define PUSH(a,v) ... #define NEXT(x) ... #define JUMP(x, b, o) ... #define SKIP(x, n) ... #define PC(x, b) ... #define DECODE32(op) ... #define DECODE8(op) ... ... DEFSTACK(a, uint32_t, 16); DEFSTACK(r, uint32_t, 8); uint32_t tmp0; uint32_t tmp1; uint32_t tmp2; uint32_t tmp3; ... uint8_t *op = code; PUSH(a, n); for(;;) { switch(*op) { ... case CRNG: SKIP(op, (1)); tmp0 = POP(a); tmp1 = DECODE32(op); SKIP(op, (4)); tmp2 = DECODE32(op); SKIP(op, (4)); PUSH(a, ((tmp0 >= tmp1) && (tmp0 <= tmp2))); NEXT(op); ... case CALL: SKIP(op, (1)); tmp0 = DECODE32(op); SKIP(op, (4)); PUSH(r, PC(op, code)); JUMP(op, code, tmp0); ... case EXIT: goto _exit; default: goto _exit; } } _exit: return 0; ...
ãŸããããã¯ããå¿
èŠããããŸããéèŠãªãã¥ã¢ã³ã¹ïŒã¹ã€ãããé·ç§»ããŒãã«ã«ã³ã³ãã€ã«ãããããã«ã¯ãã©ãã«ã®å€ãé çªã«ç§»åãã穎ããªãããšãå¿
èŠã§ãããããŠããããããã€ãã«åãŸããŸãããããã®ãã¥ãŒãªã¹ãã£ãã¯ã«éåããå ŽåãCã³ã³ãã€ã©ã¯æ¯èŒããªãŒãçæã§ããŸããããã®å Žåã¯ãŸã£ããé©åããŸããããªãã³ãŒãã¿ã€ãã®Enumã€ã³ã¹ã¿ã³ã¹ã®å®çŸ©ããªãã³ãŒãã·ãŒã±ã³ã¹ã«æäŸããŸããïŒäžèšãåç
§ïŒãGCCããã®ãããªæ¡åŒµæ©èœããµããŒãããŠãããšããŠããCã«ã¯å€æ°ã¢ãã¬ã¹ã«ããã²ãŒãããæšæºçãªæ¹æ³ããªãããã«æããŸãããã¹ãŠã®è峿·±ããã©ãããã©ãŒã ã«ã®ã¿GCCãããããã§ã¯ãªããããã¹ã€ããããŒã¹ã®è§£éã«éå®ããŠããŸããä»®æ³ãã·ã³ã®æºåãã§ããŸããã圌女ã®ãã¹ããæžããŸããããããã¯ç°¡åã§ãããã¹ãVMãå
¥åãšããŠãã€ãã³ãŒãã¹ããªãŒã ãåãåããè§£éã®çµæãšããŠãããã¡ã®ã³ã³ãã³ããçæããåºåã¹ããªãŒã ã«éä¿¡ã§ããããã«ããŸãããããã£ãŠãåãã¹ãã±ãŒã¹ã¯ããããã¡ãŒã®å
容ãæçµçã«æåŸ
ãæºãããŠããå Žåã«åæ ŒãšèŠãªãããŸãããã¹ããæžããŸããã... testJne = makeTest $ do [l1, l2] <- replicateM 2 newLabel cnst 1 cnst 2 jne l1 exit label l1 cnst 0xCAFEBABE -- 1 outle cnst 1 cnst 1 jne l2 cnst 0xCAFEBABE -- 2 outle exit label l2 cnst 0xFFFFFFFF outle
testJne = makeTest $ do [l1, l2] <- replicateM 2 newLabel cnst 1 cnst 2 jne l1 exit label l1 cnst 0xCAFEBABE -- 1 outle cnst 1 cnst 1 jne l2 cnst 0xCAFEBABE -- 2 outle exit label l2 cnst 0xFFFFFFFF outle
...ããã³ãã¹ãã±ãŒã¹ïŒ tests = testSuite $ do ... test "testJne" testJne (assert $ do a <- getWord32le b <- getWord32le return $ a == 0xCAFEBABE && b == 0xCAFEBABE)
tests = testSuite $ do ... test "testJne" testJne (assert $ do a <- getWord32le b <- getWord32le return $ a == 0xCAFEBABE && b == 0xCAFEBABE)
ãããŠããããå®è¡ããã·ã§ã«ïŒ runTest :: String -> Test -> IO Bool runTest path (T{tname=nm, tcode=code, tcheck = tc})= do let bin = toBinary code (inp,out,err,pid) <- runInteractiveProcess path [] Nothing Nothing BS.hPut inp bin hClose inp res <- BS.hGetContents out let r = tc res hPutStrLn stderr (printf "test %-24s : %s" nm (if r then "PASSED" else "FAILED !")) return r ... case args of ... ... -> mapM_ (runTest path) tests ... ...
runTest :: String -> Test -> IO Bool runTest path (T{tname=nm, tcode=code, tcheck = tc})= do let bin = toBinary code (inp,out,err,pid) <- runInteractiveProcess path [] Nothing Nothing BS.hPut inp bin hClose inp res <- BS.hGetContents out let r = tc res hPutStrLn stderr (printf "test %-24s : %s" nm (if r then "PASSED" else "FAILED !")) return r ... case args of ... ... -> mapM_ (runTest path) tests ... ...
å®è¡ãããã¹ãŠã®åé¡ãä¿®æ£ããã³ã¢ã§ã¯ã©ãã·ã¥ããŸãïŒé©ãã»ã©å°æ°ïŒ ... test testJgq : PASSED test testJne : PASSED test testCallRet1 : PASSED ...
... test testJgq : PASSED test testJne : PASSED test testCallRet1 : PASSED ...
ãã¹ãŠäžç·ã«å®è¡ããŸãã ... helloFile = const $ BS8.pack "HELLO WORLD!!" fatSample2 = filesystem $ do file "file0" (16384) helloFile dir "A" $ do file "file1" (megs 100) helloFile dir "C" $ do file "file3" (megs 100) helloFile file "file4" (megs 100) helloFile file "file5" (megs 100) helloFile dir "E" $ emptyDir dir "B" $ do file "file2" (megs 50) emptyFile ... $ ./FatGen bin | cbits/genfat 1000000 > fat.img 521106 / 1000000 ( 13027 kb/s) $ fsck.vfat ./fat.img dosfsck 3.0.9, 31 Jan 2010, FAT32, LFN Free cluster summary uninitialized (should be 15863) ./fat.img: 10 files, 115209/131072 clusters $ sudo mount -o loop ./fat.img /mnt/test2/ $ find /mnt/test2/ /mnt/test2/ /mnt/test2/FILE0 /mnt/test2/A /mnt/test2/A/FILE1 /mnt/test2/A/C /mnt/test2/A/C/FILE3 /mnt/test2/A/C/FILE4 /mnt/test2/A/C/FILE5 /mnt/test2/A/C/E /mnt/test2/B /mnt/test2/B/FILE2
... helloFile = const $ BS8.pack "HELLO WORLD!!" fatSample2 = filesystem $ do file "file0" (16384) helloFile dir "A" $ do file "file1" (megs 100) helloFile dir "C" $ do file "file3" (megs 100) helloFile file "file4" (megs 100) helloFile file "file5" (megs 100) helloFile dir "E" $ emptyDir dir "B" $ do file "file2" (megs 50) emptyFile ... $ ./FatGen bin | cbits/genfat 1000000 > fat.img 521106 / 1000000 ( 13027 kb/s) $ fsck.vfat ./fat.img dosfsck 3.0.9, 31 Jan 2010, FAT32, LFN Free cluster summary uninitialized (should be 15863) ./fat.img: 10 files, 115209/131072 clusters $ sudo mount -o loop ./fat.img /mnt/test2/ $ find /mnt/test2/ /mnt/test2/ /mnt/test2/FILE0 /mnt/test2/A /mnt/test2/A/FILE1 /mnt/test2/A/C /mnt/test2/A/C/FILE3 /mnt/test2/A/C/FILE4 /mnt/test2/A/C/FILE5 /mnt/test2/A/C/E /mnt/test2/B /mnt/test2/B/FILE2
ãã¹ãŠãæåŸ
ã©ããã«æ©èœããŸãããã¡ã€ã«ã·ã¹ãã ã€ã¡ãŒãžãçæããã¹ããããã³ããŠã³ããããŸããã³ã³ãã³ãã¯ãeDSLã«èšèŒãããŠãããšããã§ãããã®å Žåã®ã³ã³ãã€ã«æžã¿ã«ãŒã«ãã¡ã€ã«ã®ãµã€ãºã¯2Kbãå°ãäžåãããããªãæé©åã«åœ¹ç«ã¡ãŸãã3Gã¯èšããŸã§ããªããGSM / EDGEãä»ããåçããŠã³ããŒãã§ã2Kbã¯éåžžã«èš±å®¹å¯èœãªãµã€ãºã§ããFortããã©ãŒãã³ã¹ã¯æé©åã«ã圹ç«ã¡ãŸããæã極端ãªå ŽåãCã§ã³ã³ãã€ã«ããŠãããã€ãã£ãããã»ããµã³ãŒãã«ã³ã³ãã€ã«ã§ãããšããäºå®ã¯èšããŸã§ããããŸãããããã«ãåœæ°çµæžã«ãããHaskellã®å©ç¹ã«ã€ããŠã®çã話ããããŸãã