-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLabelLink.x
78 lines (61 loc) · 2.07 KB
/
LabelLink.x
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
{
module LabelLink (replaceLabels) where
import Data.Either (fromRight)
import qualified Data.Map as Map
}
%wrapper "monadUserState"
@label = [A-Za-z][0-9A-Za-z]*
tokens :-
\".*\" { onGlob }
@label ":" { onLabel }
"<" @label ">" { onLabelAccess }
.|[\n] { onGlob }
{
type AlexUserState = (String, Map.Map String Int)
alexEOF = return ()
alexInitUserState :: AlexUserState
alexInitUserState = ("", Map.empty)
getUserState :: Alex AlexUserState
getUserState = Alex $ \s -> Right (s,alex_ust s)
modifyUserState :: (AlexUserState -> AlexUserState) -> Alex ()
modifyUserState f = Alex $ \s -> Right (s { alex_ust = (f $ alex_ust s) },())
runAlexScan :: String -> Either String AlexUserState
runAlexScan s = runAlex s $ alexMonadScan >> getUserState
alexRescan input map = case f (AlexState {
alex_bytes = [],
alex_pos = alexStartPos,
alex_inp = input,
alex_chr = '\n',
alex_scd = 0,
alex_ust = ("", map)
}) of
Left msg -> error "Linking Failed"
Right ( _, (newCode, _) ) -> newCode
where
Alex f = alexMonadScan >> getUserState
onLabel :: AlexAction()
onLabel ((AlexPn _ line _), _, _, s) len = modifyUserState (\(code, labelMap) -> (code, Map.insert labelName addr labelMap)) >> alexMonadScan
where
labelName = take (len-1) s
addr = 2056 + 2 *(line-1)
onLabelAccess :: AlexAction()
onLabelAccess (_, _, _, s) len = modifyUserState (replaceLabel old) >> alexMonadScan
where
old = take len s
replaceLabel :: String -> AlexUserState -> AlexUserState
replaceLabel label (code, labelMap) = (code ++ new, labelMap)
where
key = init $ tail label
new = case (Map.lookup key labelMap) of
Nothing -> label
Just addr -> show addr
onGlob :: AlexAction()
onGlob (_, _, _, s) len = modifyUserState (\(code, labelMap) -> (code ++ new, labelMap)) >> alexMonadScan
where
new = take len s
replaceLabels::String->String
replaceLabels code = replacedCode
where
(codeNew , map) = fromRight (error "Linking failed") (runAlexScan code)
replacedCode = alexRescan codeNew map
}