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
|
signature PARSE_STATE = sig
type ('argument, 'result) state
val create: unit -> ('argument, 'result) state
type ('argument, 'result) handler =
TextIO.instream * 'argument -> 'result
datatype whichCharacters = These of char list | Any
val build: {
state: ('argument, 'result) state
, characters:
(whichCharacters * ('argument, 'result) handler) list
, endOfFile: ('argument, 'result) handler
} -> unit
val enter:
('argument, 'result) state
* TextIO.instream
* 'argument
-> 'result
end
structure ParseState :> PARSE_STATE = struct
type ('argument, 'result) handler =
TextIO.instream * 'argument -> 'result
datatype whichCharacters = These of char list | Any
type ('argument, 'result) state = {
byCharacter: Int8.int vector ref
, byIndex: ('argument, 'result) handler vector ref
, endOfFile: ('argument, 'result) handler option ref
}
fun create () = {
byCharacter = ref (Vector.fromList nil)
, byIndex = ref (Vector.fromList nil)
, endOfFile = ref NONE
}
fun build {
state = {byCharacter, byIndex, endOfFile}
, characters
, endOfFile = newEndOfFile
} =
let
val characters = vector characters
fun equal (one: char) (two: char) =
one = two
fun shallHandle ((whichToHandle, _), char) =
case whichToHandle of
Any => true
| These charactersToHandle =>
List.exists (equal char)
charactersToHandle
fun charToIndex char =
case
Vector.findi (fn (_, handler) =>
shallHandle (handler, char)
) characters
of
NONE => raise Fail (
"ParseState.build: "
^ Char.toString char
^ " not found"
) | SOME (index, _) =>
Int8.fromInt index
fun handlerToFunction (_, function) = function
fun indexToFunction index = handlerToFunction (
Vector.sub (characters, index)
)
in
byCharacter := Vector.tabulate (
Char.maxOrd + 1
, charToIndex o chr
); byIndex :=
Vector.map (fn (_, function) =>
function
) characters
; endOfFile := SOME newEndOfFile
end
fun enter (
{
byCharacter = ref byCharacter
, byIndex = ref byIndex
, endOfFile = ref endOfFile
}
, instream
, argument
) = case TextIO.input1 instream of
NONE => (valOf endOfFile) (instream, argument)
| SOME char => Vector.sub (
byIndex
, Int8.toInt (Vector.sub (byCharacter, ord char))
) (instream, argument)
end
|