-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSemanticAnalyzer.hs
More file actions
136 lines (129 loc) · 5.81 KB
/
SemanticAnalyzer.hs
File metadata and controls
136 lines (129 loc) · 5.81 KB
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
module SemanticAnalyzer where
import qualified Data.Map as Map
import Parser (AST(..), Expression(..))
type SymbolTable = Map.Map String String
analyze :: AST -> Either String ()
analyze (Program _ varDecls stmts) = do
symbolTable <- buildSymbolTable varDecls
analyzeStatements symbolTable stmts
buildSymbolTable :: [VarDecl] -> Either String SymbolTable
buildSymbolTable = foldl addVarDecl (Right Map.empty)
where
addVarDecl (Right table) (VarDecl typ ids) =
foldl (\t id -> case t of
Right m -> if Map.member id m
then Left $ "Duplicate variable declaration: " ++ id
else Right $ Map.insert id typ m
Left err -> Left err) (Right table) ids
addVarDecl (Left err) _ = Left err
analyzeStatements :: SymbolTable -> [Statement] -> Either String ()
analyzeStatements table = mapM_ (analyzeStatement table)
analyzeStatement :: SymbolTable -> Statement -> Either String ()
analyzeStatement table (AssignStatement id expr) = do
exprType <- typeCheck table expr
case Map.lookup id table of
Just varType -> if varType == exprType || (varType == "numero" && exprType == "binario")
then Right ()
else Left $ "Type mismatch in assignment to " ++ id
Nothing -> Left $ "Undeclared variable: " ++ id
analyzeStatement table (IfStatement cond thenStmts elseStmts) = do
condType <- typeCheck table cond
if condType /= "binario"
then Left "Condition must be boolean"
else do
analyzeStatements table thenStmts
case elseStmts of
Just stmts -> analyzeStatements table stmts
Nothing -> Right ()
analyzeStatement table (WhileStatement cond stmts) = do
condType <- typeCheck table cond
if condType /= "binario"
then Left "Condition must be boolean"
else analyzeStatements table stmts
analyzeStatement table (RepeatStatement count stmts) = do
countType <- typeCheck table count
if countType /= "numero"
then Left "Repeat count must be a number"
else analyzeStatements table stmts
analyzeStatement table (CommandStatement func args) =
mapM_ (typeCheck table) args
typeCheck :: SymbolTable -> Expression -> Either String String
typeCheck table (BinaryOp op left right) = do
leftType <- typeCheck table left
rightType <- typeCheck table right
case op of
"+" -> if leftType == "numero" && rightType == "numero"
then Right "numero"
else Left "Arithmetic operation requires numbers"
"-" -> if leftType == "numero" && rightType == "numero"
then Right "numero"
else Left "Arithmetic operation requires numbers"
"*" -> if leftType == "numero" && rightType == "numero"
then Right "numero"
else Left "Arithmetic operation requires numbers"
"/" -> if leftType == "numero" && rightType == "numero"
then Right "numero"
else Left "Arithmetic operation requires numbers"
"%" -> if leftType == "numero" && rightType == "numero"
then Right "numero"
else Left "Arithmetic operation requires numbers"
"^" -> if leftType == "numero" && rightType == "numero"
then Right "numero"
else Left "Arithmetic operation requires numbers"
"=" -> if leftType == rightType
then Right "binario"
else Left "Comparison requires same types"
"!=" -> if leftType == rightType
then Right "binario"
else Left "Comparison requires same types"
"<" -> if leftType == "numero" && rightType == "numero"
then Right "binario"
else Left "Comparison requires numbers"
"<=" -> if leftType == "numero" && rightType == "numero"
then Right "binario"
else Left "Comparison requires numbers"
">" -> if leftType == "numero" && rightType == "numero"
then Right "binario"
else Left "Comparison requires numbers"
">=" -> if leftType == "numero" && rightType == "numero"
then Right "binario"
else Left "Comparison requires numbers"
"e" -> if leftType == "binario" && rightType == "binario"
then Right "binario"
else Left "Logical operation requires booleans"
"ou" -> if leftType == "binario" && rightType == "binario"
then Right "binario"
else Left "Logical operation requires booleans"
_ -> Left $ "Unknown operator: " ++ op
typeCheck table (UnaryOp op expr) = do
exprType <- typeCheck table expr
case op of
"+" -> if exprType == "numero"
then Right "numero"
else Left "Unary plus requires a number"
"-" -> if exprType == "numero"
then Right "numero"
else Left "Unary minus requires a number"
"nao" -> if exprType == "binario"
then Right "binario"
else Left "Logical not requires a boolean"
_ -> Left $ "Unknown unary operator: " ++ op
typeCheck _ (Literal val)
| val `elem` ["v", "f"] = Right "binario"
| all (`elem` ['0'..'9']) val = Right "numero"
| otherwise = Right "texto"
typeCheck table (Identifier id) =
case Map.lookup id table of
Just t -> Right t
Nothing -> Left $ "Undeclared variable: " ++ id
typeCheck table (FunctionCall func args) =
case func of
"ler_numero" -> Right "numero"
"ler_binario" -> Right "binario"
"ler" -> Right "numero"
"consultar" -> Right "numero"
"criar_figura" -> Right "numero"
"criar_imagem" -> Right "numero"
"colidiu" -> Right "binario"
"aleatorio" -> Right "numero"
_ -> Left $ "Unknown function: " ++ func