-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpc.ml
189 lines (143 loc) · 3.99 KB
/
pc.ml
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
(* pc.ml
* A parsing-combinators package for ocaml
*
* Prorammer: Mayer Goldberg, 2018
*)
(* general list-processing procedures *)
let rec ormap f s =
match s with
| [] -> false
| car :: cdr -> (f car) || (ormap f cdr);;
let rec andmap f s =
match s with
| [] -> true
| car :: cdr -> (f car) && (andmap f cdr);;
let lowercase_ascii =
let delta = int_of_char 'A' - int_of_char 'a' in
fun ch ->
if ('A' <= ch && ch <= 'Z')
then char_of_int ((int_of_char ch) - delta)
else ch;;
let string_to_list str =
let rec loop i limit =
if i = limit then []
else (String.get str i) :: (loop (i + 1) limit)
in
loop 0 (String.length str);;
let list_to_string s =
String.concat "" (List.map (fun ch -> String.make 1 ch) s);;
module PC = struct
(* the parsing combinators defined here *)
exception X_not_yet_implemented;;
exception X_no_match;;
let const pred =
function
| [] -> raise X_no_match
| e :: s ->
if (pred e) then (e, s)
else raise X_no_match;;
let caten nt1 nt2 s =
let (e1, s) = (nt1 s) in
let (e2, s) = (nt2 s) in
((e1, e2), s);;
let pack nt f s =
let (e, s) = (nt s) in
((f e), s);;
let nt_epsilon s = ([], s);;
let caten_list nts =
List.fold_right
(fun nt1 nt2 ->
pack (caten nt1 nt2)
(fun (e, es) -> (e :: es)))
nts
nt_epsilon;;
let disj nt1 nt2 =
fun s ->
try (nt1 s)
with X_no_match -> (nt2 s);;
let nt_none _ = raise X_no_match;;
let disj_list nts = List.fold_right disj nts nt_none;;
let delayed thunk s =
thunk() s;;
let nt_end_of_input = function
| [] -> ([], [])
| _ -> raise X_no_match;;
let rec star nt s =
try let (e, s) = (nt s) in
let (es, s) = (star nt s) in
(e :: es, s)
with X_no_match -> ([], s);;
let plus nt =
pack (caten nt (star nt))
(fun (e, es) -> (e :: es));;
let guard nt pred s =
let ((e, _) as result) = (nt s) in
if (pred e) then result
else raise X_no_match;;
let diff nt1 nt2 s =
match (let result = nt1 s in
try let _ = nt2 s in
None
with X_no_match -> Some(result)) with
| None -> raise X_no_match
| Some(result) -> result;;
let not_followed_by nt1 nt2 s =
match (let ((_, s) as result) = (nt1 s) in
try let _ = (nt2 s) in
None
with X_no_match -> (Some(result))) with
| None -> raise X_no_match
| Some(result) -> result;;
let maybe nt s =
try let (e, s) = (nt s) in
(Some(e), s)
with X_no_match -> (None, s);;
(* useful general parsers for working with text *)
let make_char equal ch1 = const (fun ch2 -> equal ch1 ch2);;
let char = make_char (fun ch1 ch2 -> ch1 = ch2);;
let char_ci =
make_char (fun ch1 ch2 ->
(lowercase_ascii ch1) =
(lowercase_ascii ch2));;
let make_word char str =
List.fold_right
(fun nt1 nt2 -> pack (caten nt1 nt2) (fun (a, b) -> a :: b))
(List.map char (string_to_list str))
nt_epsilon;;
let word = make_word char;;
let word_ci = make_word char_ci;;
let make_one_of char str =
List.fold_right
disj
(List.map char (string_to_list str))
nt_none;;
let one_of = make_one_of char;;
let one_of_ci = make_one_of char_ci;;
let nt_whitespace = const (fun ch -> ch <= ' ');;
let make_range leq ch1 ch2 (s : char list) =
const (fun ch -> (leq ch1 ch) && (leq ch ch2)) s;;
let range = make_range (fun ch1 ch2 -> ch1 <= ch2);;
let range_ci =
make_range (fun ch1 ch2 ->
(lowercase_ascii ch1) <=
(lowercase_ascii ch2));;
let nt_any (s : char list) = const (fun ch -> true) s;;
let trace_pc desc nt s =
try let ((e, s') as args) = (nt s)
in
(Printf.printf ";;; %s matched the head of \"%s\", and the remaining string is \"%s\"\n"
desc
(list_to_string s)
(list_to_string s') ;
args)
with X_no_match ->
(Printf.printf ";;; %s failed on \"%s\"\n"
desc
(list_to_string s) ;
raise X_no_match);;
(* testing the parsers *)
let test_string nt str =
let (e, s) = (nt (string_to_list str)) in
(e, (Printf.sprintf "->[%s]" (list_to_string s)));;
end;; (* end of struct PC *)
(* end-of-input *)