-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathLexer.x
138 lines (110 loc) · 4 KB
/
Lexer.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
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
{
module Lexer
( lexer
, alexScanTokens
) where
import Tokens (Pos(..), Token(..), isTokenError, printError)
}
%wrapper "posn"
$digit = 0-9 -- digits
$alpha = [a-zA-Z] -- alphabetic characters
tokens :-
-- whitespace --
$white+ ;
-- comments --
"#".* ;
-- language --
program { tok TokenProgram }
using { tok TokenUsing }
in { tok TokenIn }
= { tok TokenAssign }
-- brackets --
"{" { tok TokenCurlyOpen }
"}" { tok TokenCurlyClose }
"(" { tok TokenParenOpen }
")" { tok TokenParenClose }
-- types --
int { tok TokenIntT }
bool { tok TokenBoolT }
set { tok TokenSetT }
-- boolean constants --
true { tok TokenTrue }
false { tok TokenFalse }
-- separators --
"," { tok TokenComma }
";" { tok TokenSemicolon }
-- operators --
-- -- int --
"+" { tok TokenPlus }
"-" { tok TokenMinus }
"*" { tok TokenTimes }
"/" { tok TokenDiv }
"%" { tok TokenMod }
-- -- set --
"++" { tok TokenSetUnion }
\\ { tok TokenSetMinus }
"><" { tok TokenSetInter }
">?" { tok TokenSetMax }
"<?" { tok TokenSetMin }
"$?" { tok TokenSetSize }
-- -- map --
"<+>" { tok TokenMapPlus }
"<->" { tok TokenMapMinus }
"<*>" { tok TokenMapTimes }
"</>" { tok TokenMapDiv }
"<%>" { tok TokenMapMod }
-- -- bool --
and { tok TokenAnd }
or { tok TokenOr }
not { tok TokenNot }
-- -- relational --
"<" { tok TokenLT }
"<=" { tok TokenLE }
">" { tok TokenGT }
">=" { tok TokenGE }
"==" { tok TokenEQ }
"/=" { tok TokenNE }
@ { tok TokenAt }
-- control statements --
if { tok TokenIf }
else { tok TokenElse }
for { tok TokenFor }
min { tok TokenMin }
max { tok TokenMax }
repeat { tok TokenRepeat }
while { tok TokenWhile }
do { tok TokenDo }
-- IO functions --
scan { tok TokenScan }
print { tok TokenPrint }
println { tok TokenPrintln }
-- variables --
(\-?)$digit+ { lexInt }
\"([^\"]|(\\\"))*\" { toq TokenString read }
$alpha[$alpha$digit\_\']* { toq TokenIdent id }
-- error --
. { toq TokenError id }
{
toPos :: AlexPosn -> Pos
toPos (AlexPn _ line column) = Pos line column
tok :: (Pos -> Token) -> AlexPosn -> String -> Token
tok f p _ = f (toPos p)
toq :: (a -> Pos -> Token) -> (String -> a) -> AlexPosn -> String -> Token
toq f g p s = f (g s) (toPos p)
lexInt :: AlexPosn -> String -> Token
lexInt p s
| n < -2^31 = TokenIntError s (toPos p)
| n < 2^31 = TokenInt n (toPos p)
| otherwise = TokenIntError s (toPos p)
where n = (read s :: (Num a, Read a) => a)
lexer :: String -> String -> IO ()
-- Calls the Alex token scanner and then prints found tokens. If there are any
-- TokenErrors, it only prints those.
lexer text name = do
putStrLn $ "Lexer (" ++ name ++ "):\n"
let toks = alexScanTokens text
if any isTokenError toks
then mapM_ printError $ filter isTokenError toks
else mapM_ print toks
putStrLn ""
}