-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathThreePass.hs
141 lines (117 loc) · 3.88 KB
/
ThreePass.hs
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
module TinyThreePassCompiler where
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Maybe (fromJust)
import Text.Parsec
import qualified Text.Parsec.Token as Tok
-- count number of arguments declared, how identifiers map to argument numbers
type CompilerState = (Int, Map String Int)
type Parser a = Parsec String CompilerState a
langDef :: Tok.LanguageDef CompilerState
langDef = Tok.LanguageDef
{ Tok.commentStart = ""
, Tok.commentEnd = ""
, Tok.commentLine = ""
, Tok.nestedComments = False
, Tok.identStart = letter
, Tok.identLetter = letter
, Tok.opStart = oneOf "+-*/"
, Tok.opLetter = oneOf "+-*/"
, Tok.reservedNames = []
, Tok.reservedOpNames = []
, Tok.caseSensitive = True
}
lexer :: Tok.TokenParser CompilerState
lexer = Tok.makeTokenParser langDef
parens :: Parser a -> Parser a
parens = Tok.parens lexer
brackets :: Parser a -> Parser a
brackets = Tok.brackets lexer
identifier :: Parser String
identifier = Tok.identifier lexer
reservedOp :: String -> Parser ()
reservedOp = Tok.reservedOp lexer
integer :: Parser Integer
integer = Tok.integer lexer
data AST = Imm Int
| Arg Int
| Add AST AST
| Sub AST AST
| Mul AST AST
| Div AST AST
deriving (Eq, Show)
function :: Parser AST
function = do
brackets argList
expression
argList :: Parser ()
argList = do
many variableDec
return ()
-- for each variable declaration, we add a mapping from the argument name to the argument number
-- as well as incrementing the Int in CompilerState, which tracks what argument number we're on
variableDec :: Parser ()
variableDec = do
varName <- identifier
(varNum, _) <- getState
modifyState (\(num, args) -> (num + 1, Map.insert varName varNum args))
return ()
expression :: Parser AST
expression = term `chainl1` addSubOp
addSubOp :: Parser (AST -> AST -> AST)
addSubOp = (reservedOp "+" >> return Add)
<|> (reservedOp "-" >> return Sub)
term :: Parser AST
term = factor `chainl1` multDivOp
multDivOp :: Parser (AST -> AST -> AST)
multDivOp = (reservedOp "*" >> return Mul)
<|> (reservedOp "/" >> return Div)
factor :: Parser AST
factor = number
<|> variableUse
<|> parens expression
number :: Parser AST
number = do
num <- integer
return $ Imm $ fromIntegral num
-- using fromJust because we don't care about error handling
-- per problem, all programs will be valid
variableUse :: Parser AST
variableUse = do
varName <- identifier
(_, varMap) <- getState
return $ Arg $ fromJust $ Map.lookup varName varMap
compile :: String -> [String]
compile = pass3 . pass2 . pass1
-- parsing pass
pass1 :: String -> AST
pass1 str = case (runParser function (0, Map.empty) "" str) of
(Left _) -> error "Parse error"
(Right ast) -> ast
-- constant folding pass
-- do a postorder traversal of the AST, checking for optimization opportunities at each node
pass2 :: AST -> AST
pass2 ast = case ast of
Add left right -> case (pass2 left, pass2 right) of
((Imm m), (Imm n)) -> Imm (m + n)
(l, r) -> Add l r
Sub left right -> case (pass2 left, pass2 right) of
((Imm m), (Imm n)) -> Imm (m - n)
(l, r) -> Sub l r
Mul left right -> case (pass2 left, pass2 right) of
((Imm m), (Imm n)) -> Imm (m * n)
(l, r) -> Mul l r
Div left right -> case (pass2 left, pass2 right) of
((Imm m), (Imm n)) -> Imm (m `div` n)
(l, r) -> Div l r
_ -> ast
-- code generation pass
-- postorder traversal of the AST, generating code at each node
pass3 :: AST -> [String]
pass3 ast = case ast of
Imm n -> ["IM " ++ show n, "PU"]
Arg a -> ["AR " ++ show a, "PU"]
Add l r -> pass3 l ++ pass3 r ++ ["PO", "SW", "PO", "AD", "PU"]
Sub l r -> pass3 l ++ pass3 r ++ ["PO", "SW", "PO", "SU", "PU"]
Mul l r -> pass3 l ++ pass3 r ++ ["PO", "SW", "PO", "MU", "PU"]
Div l r -> pass3 l ++ pass3 r ++ ["PO", "SW", "PO", "DI", "PU"]