-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparser_standalone.hs
More file actions
161 lines (132 loc) · 4.43 KB
/
parser_standalone.hs
File metadata and controls
161 lines (132 loc) · 4.43 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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#!/usr/bin/env runhaskell
{-# LANGUAGE FlexibleInstances #-}
-- Standalone parser that can be run with: runhaskell parser.hs
-- This file is for quick testing and does not require compilation.
import Data.Char (isDigit, isAlpha, isAlphaNum, isSpace)
import Data.List (intercalate)
-- AST Data Types
data Expr
= Number Int
| BinOp Op Expr Expr
| Var String
deriving (Show, Eq)
data Op = Add | Sub | Mul | Div
deriving (Show, Eq)
data KVPair = KVPair String String
deriving (Show, Eq)
-- Tokenizer
data Token
= TNum Int
| TOp Char
| TVar String
| TLParen
| TRParen
| TEq
| EOF
deriving (Show, Eq)
tokenize :: String -> [Token]
tokenize [] = [EOF]
tokenize (c:cs)
| isSpace c = tokenize cs
| isDigit c =
let (num, rest) = span isDigit (c:cs)
in TNum (read num) : tokenize rest
| isAlpha c =
let (var, rest) = span isAlphaNum (c:cs)
in TVar var : tokenize rest
| c == '+' || c == '-' || c == '*' || c == '/' = TOp c : tokenize cs
| c == '(' = TLParen : tokenize cs
| c == ')' = TRParen : tokenize cs
| c == '=' = TEq : tokenize cs
| otherwise = tokenize cs
-- Parser for Arithmetic Expressions (with operator precedence)
parseExpr :: [Token] -> (Expr, [Token])
parseExpr tokens = parseAddSub tokens
parseAddSub :: [Token] -> (Expr, [Token])
parseAddSub tokens =
let (left, rest) = parseMulDiv tokens
in parseAddSub' left rest
parseAddSub' :: Expr -> [Token] -> (Expr, [Token])
parseAddSub' left (TOp '+' : rest) =
let (right, rest') = parseMulDiv rest
in parseAddSub' (BinOp Add left right) rest'
parseAddSub' left (TOp '-' : rest) =
let (right, rest') = parseMulDiv rest
in parseAddSub' (BinOp Sub left right) rest'
parseAddSub' left rest = (left, rest)
parseMulDiv :: [Token] -> (Expr, [Token])
parseMulDiv tokens =
let (left, rest) = parsePrimary tokens
in parseMulDiv' left rest
parseMulDiv' :: Expr -> [Token] -> (Expr, [Token])
parseMulDiv' left (TOp '*' : rest) =
let (right, rest') = parsePrimary rest
in parseMulDiv' (BinOp Mul left right) rest'
parseMulDiv' left (TOp '/' : rest) =
let (right, rest') = parsePrimary rest
in parseMulDiv' (BinOp Div left right) rest'
parseMulDiv' left rest = (left, rest)
parsePrimary :: [Token] -> (Expr, [Token])
parsePrimary (TNum n : rest) = (Number n, rest)
parsePrimary (TVar v : rest) = (Var v, rest)
parsePrimary (TLParen : rest) =
let (expr, rest') = parseExpr rest
in case rest' of
(TRParen : rest'') -> (expr, rest'')
_ -> error "Expected closing parenthesis"
parsePrimary _ = error "Expected a number, variable, or opening parenthesis"
-- Parser for Key-Value Pairs
parseKVPair :: [Token] -> (KVPair, [Token])
parseKVPair (TVar key : TEq : TVar value : rest) = (KVPair key value, rest)
parseKVPair (TVar key : TEq : TNum num : rest) = (KVPair key (show num), rest)
parseKVPair _ = error "Invalid key-value pair format (expected: key = value)"
-- Evaluator for Arithmetic Expressions
evalExpr :: Expr -> Int
evalExpr (Number n) = n
evalExpr (Var _) = error "Variable evaluation not supported"
evalExpr (BinOp op left right) =
let l = evalExpr left
r = evalExpr right
in case op of
Add -> l + r
Sub -> l - r
Mul -> l * r
Div -> if r == 0 then error "Division by zero" else l `div` r
-- Token Formatter
formatTokens :: [Token] -> String
formatTokens tokens = "[" ++ intercalate ", " (map show tokens) ++ "]"
-- Main
main :: IO ()
main = do
putStrLn ""
putStrLn "Welcome to Tiny Parser!"
putStrLn ""
putStrLn "Arithmetic Expression Parser"
putStrLn ""
let expr1 = "1 + 5 * 4"
putStrLn $ "Input: " ++ expr1
putStrLn $ "Tokens: " ++ formatTokens (tokenize expr1)
let (ast, _) = parseExpr (tokenize expr1)
putStrLn $ "AST: " ++ show ast
putStrLn $ "Result: " ++ show (evalExpr ast)
putStrLn ""
let expr2 = "(7 + 9) * 3"
putStrLn $ "Input: " ++ expr2
putStrLn $ "Tokens: " ++ formatTokens (tokenize expr2)
let (ast2, _) = parseExpr (tokenize expr2)
putStrLn $ "AST: " ++ show ast2
putStrLn $ "Result: " ++ show (evalExpr ast2)
putStrLn ""
putStrLn "Key-Value Pair Parser"
putStrLn ""
let kv1 = "name = bob"
putStrLn $ "Input: " ++ kv1
putStrLn $ "Tokens: " ++ formatTokens (tokenize kv1)
let (kvpair, _) = parseKVPair (tokenize kv1)
putStrLn $ "Parsed: " ++ show kvpair
putStrLn ""
let kv2 = "age = 45"
putStrLn $ "Input: " ++ kv2
putStrLn $ "Tokens: " ++ formatTokens (tokenize kv2)
let (kvpair2, _) = parseKVPair (tokenize kv2)
putStrLn $ "Parsed: " ++ show kvpair2