3a_asm: modified the datastructure for labels
[calu.git] / 3a_asm / Main.hs
1 -- as for deep thoughts ISA
2 -----------------------------------------------------------------------------
3
4 module Main where
5
6 import DT
7 import DTFormat
8
9 import Control.Applicative hiding ((<|>),many)
10
11 import System.IO
12 import System.Environment
13 import Text.Printf
14 import Text.Parsec
15 import Text.Parsec.String
16 import Text.Parsec.Combinator
17 import qualified Data.Map as M
18 import Data.List
19 import Data.Word
20 import qualified Data.ByteString.Lazy as BL
21 import Control.Monad
22
23
24 main :: IO ()
25 main = do
26         args <- getArgs
27         content <- getContents
28         let src = (filter (((/=) "") . snd) $ (zip [1..] (lines content)))
29         let (dict,formatedsrc) = convertDTF src NoState 0x00 0x00 []
30         printf "\nlabels:\n"
31         sequence_ [printf "%10s @ 0x%08x\n" l a | (l,a) <- (reverse dict)]
32         printf "\nparsed asm:\n"
33         sequence_ [printf "%s" (show x) | x <- formatedsrc]
34
35
36 type Counter = Word32
37
38 inc :: Counter -> Counter
39 inc = ((+) 4)
40
41
42 type DictLabel = (String,Word32)
43
44 get_label :: String -> [DictLabel] -> Maybe Word32
45 get_label = lookup
46
47 add_label :: [DictLabel] -> (String,Word32) -> [DictLabel]
48 add_label dic (s,w)
49         | s == "" = dic -- ignore empty string
50         | already_in =  error ("Label " ++ s ++ " already exists")
51         | otherwise = (s,w):dic
52         where
53         already_in = case (get_label s dic) of
54                 Just _ -> True
55                 Nothing -> False
56
57
58 convertDTF :: [(Int,String)] -> DT_State -> Counter -> Counter -> [DictLabel] -> ([DictLabel], [DTF])
59 convertDTF [] _ _ _ d = (d,[])
60 convertDTF ((lno,str):xs) state datacnt instrcnt dict = (newdict, (actlist newdtf))
61         where
62         actlist (DTF_Org _) = next
63         actlist (DTF_State _) = next
64         actlist y = y:next
65
66         (newdict,next) = convertDTF xs (nstate newdtf) (ndatacnt newdtf) (ninstrcnt newdtf) (ndict newdtf)
67
68         ndatacnt (DTF_Org adr)
69                 | state == InData = adr
70                 | otherwise = datacnt
71         ndatacnt (DTF_Data _ _ _ _ _) = inc datacnt
72         ndatacnt _ = datacnt
73
74         ninstrcnt (DTF_Org adr)
75                 | state == InText = adr
76                 | otherwise = instrcnt
77         ninstrcnt (DTF_Instr _ _ _ _ _) = inc instrcnt
78         ninstrcnt (DTF_InstrToParse _ _ _ _ _) = inc instrcnt
79         ninstrcnt _ = instrcnt
80
81         nstate (DTF_State s) = s
82         nstate _ = state
83
84         ndict (DTF_Label l _ a) = dict `add_label` (l,a)
85         ndict (DTF_SectionToDet a _ _ l _) = dict `add_label` (l,a)
86         ndict (DTF_InstrToParse a _ _ l _) = dict `add_label` (l,a)
87         ndict (DTF_Data a _ _ l _) = dict `add_label` (l,a)
88         ndict (DTF_Instr a _ _ l _) = dict `add_label` (l,a)
89         ndict _ = dict
90
91         newdtf = case (parse parseDTFLine "" (str++"\n")) of
92                 Left err -> error ("couldn't parse line " ++ (show lno) ++ ": " ++ (show err))
93                 Right (DTF_SectionToDet _ v c l s) ->
94                         case state of
95                                 NoState -> error "missing .data or .text"
96                                 InData -> (DTF_Data datacnt v c l s)
97                                 InText -> (DTF_Instr instrcnt v c l s)
98                 Right (DTF_InstrToParse _ v c l s) ->
99                         (DTF_InstrToParse instrcnt v c l s)
100                 Right y@(DTF_Org _) ->
101                         case state of
102                                 NoState -> error "missing .data or .text"
103                                 _ -> y
104                 Right (DTF_Label l c _) ->
105                         case state of
106                                 NoState -> error "missing .data or .text"
107                                 InData -> (DTF_Label l c datacnt)
108                                 InText -> (DTF_Label l c instrcnt)
109                 Right z -> z -- DTF_Comment, DTF_State
110
111
112
113 testDTF :: String -> IO ()
114 testDTF input =
115         case (parse parseDTFLine "" (input++"\n")) of
116                 Left err -> do { putStr "failz ;(\n"; print err}
117                 Right x -> do { print x }
118
119 parseDTFLine :: Parser DTF
120 parseDTFLine = foldl1 (<|>) (fmap try lineFormats) <* char '\n'
121
122 lineFormats = [lf_sdata, lf_stext, lf_org, lf_data, lf_comment, lf_toparse, lf_label]
123
124 -- helper
125 parseLabel :: Parser String
126 parseLabel = do
127         label <- letter 
128         labels <- many $ (letter <|> digit <|> char '_')
129         char ':'
130         return $ (label:labels)
131
132 parseComment :: Parser String
133 parseComment = do
134         skipMany space
135         char ';'
136         comment <- many $ noneOf "\n"
137         return $ comment
138
139 parseConst :: Parser Word32
140 parseConst = do
141         skipMany space
142         -- TODO: only decimal and hex (since this is supported by read)
143         -- TODO: howto check too big values? atm they get truncated
144         str <- try(do pref <- string "0x"; z <- many1 hexDigit; return $ (pref ++ z)) <|> (many1 digit)
145         let val = read str
146         return $ val
147
148 parseMySpaces :: Parser String
149 parseMySpaces = do
150         ret <- many $ oneOf "\t "
151         return $ ret
152
153 -- teh pars0rs
154 lf_data = do
155         l <- try (parseLabel) <|> string ""
156         skipMany space
157         fill <- string ".fill "
158         -- TODO: atm 32bit imm only
159         code <- many1 $ noneOf "\n;"
160         -- TODO: this is quite ugly here :/
161         let (Right val) = parse parseConst "" code
162         comment <- try(parseComment) <|> parseMySpaces
163         return $ DTF_SectionToDet 0 val (fill ++ code) l comment
164
165 lf_comment = do
166         comment <- parseComment
167         return $ DTF_Comment comment
168
169 lf_label = do
170         l <- parseLabel
171         comment <- try(parseComment) <|> parseMySpaces
172         return $ DTF_Label l comment 0
173
174 lf_toparse = do
175         l <- try(parseLabel) <|> string ""
176         skipMany space
177         code <- many1 $ noneOf "\n;"
178         comment <- try(parseComment) <|> parseMySpaces
179         return $ DTF_InstrToParse 0 code code l comment
180
181 lf_org = do
182         skipMany space
183         string ".org"
184         val <- parseConst
185         parseMySpaces
186         return $ DTF_Org val
187
188 lf_sdata = do
189         skipMany space
190         string ".data"
191         parseMySpaces
192         return $ DTF_State InData
193
194 lf_stext = do
195         skipMany space
196         string ".text"
197         parseMySpaces
198         return $ DTF_State InText