-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparse.sml
More file actions
140 lines (125 loc) · 4.87 KB
/
Copy pathparse.sml
File metadata and controls
140 lines (125 loc) · 4.87 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
structure Parser =
struct
fun parse s = let
val lex = Lexer.lexer s
fun eat (tok, c) = let
val (t, c') = lex c
in
if t = tok then c'
else raise Err.Peg (
"expected '" ^ Token.toString tok ^ "', found '" ^ Token.toString t ^ "'",
c)
end
fun getClass (cls, start) = let
fun loop (str, ls) = case str of
x1 :: #"-" :: x2 :: xs => loop (xs, (Ast.RGE (x1, x2)) :: ls)
| _ :: #"-" :: [] => raise Err.Peg ("incomplete range", start)
| x :: xs => loop (xs, Ast.CHR x :: ls)
| [] =>
let val alts = List.rev ls
in case alts of
[] => raise Err.Peg ("empty class not allowed", start)
| x :: [] => x
| _ => Ast.ALT alts
end
in loop (String.explode cls, []) end
fun getLiteral (lit, start) = let
val ls = map Ast.CHR (String.explode lit)
in case ls of
[] => raise Err.Peg ("empty string not allowed", start)
| x :: [] => x
| _ => Ast.SEQ ls
end
fun getPrimary (t, c, start) = case t of
Token.LIT lit => (getLiteral (lit, start), c)
| Token.CLASS cls => (getClass (cls, start), c)
| Token.ID id => (Ast.NT id, c)
| Token.DOT => (Ast.ANY, c)
| Token.LPAREN => let
val (e, c) = getExpression c
val c = eat (Token.RPAREN, c)
in (e, c) end
| _ => raise Err.Peg ("expected primary", start)
and getSuffix (t, c, start) = let
val (p, c) = getPrimary (t, c, start)
val (t, c') = lex c
in case t of
Token.QUESTION => (Ast.OPT p, c')
| Token.STAR => (Ast.REP0 p, c')
| Token.PLUS => (Ast.REP1 p, c')
| _ => (p, c)
end
and getPrefix (t, c, start) = let
val (t', c') = lex c
in case t of
Token.AND => let val (s, c) = getSuffix (t', c', c) in (Ast.PEEK s, c) end
| Token.NOT => let val (s, c) = getSuffix (t', c', c) in (Ast.NOT s, c) end
| _ => getSuffix (t, c, start)
end
and getSequence c = let
fun loop (ls, c) = let
val (t, c') = lex c
fun continue () = let
val (item, c) = getPrefix (t, c', c)
in loop (item :: ls, c) end
fun done () = case ls of
[] => raise Err.Peg ("expected expression", c)
| x :: [] => (x, c)
| _ => (Ast.SEQ (List.rev ls), c)
in
case t of
Token.ID id => let
val (t, _) = lex c'
in
if t = Token.LEFTARROW then done ()
else continue ()
end
| Token.AND => continue ()
| Token.NOT => continue ()
| Token.LIT _ => continue ()
| Token.CLASS _ => continue ()
| Token.DOT => continue ()
| Token.LPAREN => continue ()
| _ => done ()
end
in loop ([], c) end
and getExpression c = let
fun loop (ls, c) = let
val (t, c') = lex c
in
case t of
Token.SLASH => let val (seq, c) = getSequence c'
in loop (seq :: ls, c) end
| _ => (case ls of
[] => raise Err.Peg ("expected expression", c)
| x :: [] => (x, c)
| _ => (Ast.ALT (List.rev ls), c) )
end
val (seq, c) = getSequence c
in loop ([seq], c) end
fun getDef (grm, (t, c)) = let
val id = case t of
Token.ID s => s
| _ => raise Err.Peg (("expected identifier, found '"
^ (Token.toString t) ^ "'"), c)
val c = eat (Token.LEFTARROW, c)
val (exp, c) = getExpression c
in (Map.insert (grm, id, exp), c) end
fun getDefs (grm, c) = let
val (t, c) = lex c
in
case t of
Token.EOF => grm
| _ => getDefs (getDef (grm, (t, c)))
end
in
getDefs (Map.empty, 0)
handle Err.Peg (msg, p) => (Err.print (Err.formatMsg (s, msg, p)); Map.empty)
end
fun parseFile file = let
val input = TextIO.openIn file
val s = TextIO.inputAll input
val _ = TextIO.closeIn input
in parse s end
fun show s = let val g = parse ("a<-" ^ s) in Map.lookup (g, "a") end
end