staload "grammar.sats"
staload _ = "prelude/DATS/array.dats"
staload _ = "prelude/DATS/array0.dats"
local
datatype symbol = {n:pos} SYMBOL of (string n, int)
assume symbol_t = symbol
in
implement symbol_make_string_int (name, ind) = SYMBOL (name, ind)
implement symbol_index_get (sym) = let
val+ SYMBOL (name, ind) = sym in ind end
implement symbol_is_term (sym) = ~(symbol_is_nonterm sym)
implement symbol_is_nonterm (sym) = let
val+ SYMBOL (name, _) = sym in char_isupper (name[0])
end
implement eq_symbol_symbol (s1, s2) = let
val+ SYMBOL (_, i1) = s1 and SYMBOL (_, i2) = s2
in
if i1 = i2 then true else false
end
implement compare_symbol_symbol (s1, s2) = let
val+ SYMBOL (_, i1) = s1 and SYMBOL (_, i2) = s2
in
compare_int_int (i1, i2)
end
implement print_symbol (sym) = let
val+ SYMBOL (name, _) = sym in print_string (name)
end
implement print_symbol_list (xs) = loop (xs, 0) where {
fun loop (xs: List symbol_t, i: int): void = case+ xs of
| list_cons (x, xs) => begin
if i > 0 then print ", "; print_symbol x; loop (xs, i+1)
end
| list_nil () => ()
}
end
local
assume symbolset_t = List (symbol_t)
in
implement symbolset_nil = list_nil ()
implement symbolset_sing (x) = list_cons (x, list_nil ())
implement symbolset_ismem (xs, x) = f (xs, x) where {
fun f (xs: List symbol_t, x: symbol_t): bool =
case+ xs of
| list_cons (x1, xs1) => if x = x1 then true else f (xs1, x)
| list_nil () => false
}
implement symbolset_add_flag (xs, x0, flag) = f (xs, x0, flag) where {
fun f (xs: List symbol_t, x0: symbol_t, flag: &int): List symbol_t =
case+ xs of
| list_cons (x1, xs1) => begin
case+ compare (x0, x1) of
| ~1 => (flag := flag + 1; list_cons (x0, xs))
| 1 => list_cons (x1, f (xs1, x0, flag))
| 0 => xs
end | list_nil () => (flag := flag + 1; list_cons (x0, xs))
}
implement symbolset_union_flag (xs, ys, flag) = f (xs, ys, flag) where {
fun f (xs: List symbol_t, ys: List symbol_t, flag: &int): List symbol_t =
case+ ys of
| list_cons (y1, ys1) => let
val xs = symbolset_add_flag (xs, y1, flag) in f (xs, ys1, flag)
end | list_nil () => xs
}
implement print_symbolset (xs) = begin
print "{ "; print_symbol_list (xs); print " }"
end
end
implement print_rule (r) = let
val+ RULE (name, S, alpha) = r
val sz = int_of_size (array0_size alpha)
var i: int in
print_symbol S;
print "\t->\t";
for (i := 0 ; i < sz; i := i+1)
(if i > 0 then print ", "; print_symbol alpha[i]);
printf ("\t(%s)", @(name))
end
implement print_grammar (G) = let
val () = begin
print "terminals: "; print_symbol_list G.termlst; print_newline ()
end val () = begin
print "nonterminals: "; print_symbol_list G.nontermlst; print_newline ()
end val () = begin
print "the production rules:\n"; loop (G.rules)
end where {
fun loop (rs: List rule): void = case+ rs of
| list_cons (r, rs) => begin
print_rule r; print_newline (); loop (rs)
end
| list_nil () => ()
} in
end
#define NSYMBOL_MAX 2048
val NULLABLEarr
: array (bool, NSYMBOL_MAX) = array_make_elt (NSYMBOL_MAX, false)
val FIRSTSETarr
: array (symbolset_t, NSYMBOL_MAX) = array_make_elt (NSYMBOL_MAX, symbolset_nil)
val FOLLOWSETarr
: array (symbolset_t, NSYMBOL_MAX) = array_make_elt (NSYMBOL_MAX, symbolset_nil)
implement symbol_is_nullable (sym) = let
val ind = symbol_index_get sym
val ind = int1_of_int ind
val () = assert (ind >= 0)
val () = assert (ind < NSYMBOL_MAX)
in
NULLABLEarr[ind]
end
implement symbol_isnot_nullable (sym) = ~(symbol_is_nullable sym)
implement symbol_nullable_set (sym, v) = let
val ind = symbol_index_get sym
val ind = int1_of_int ind
val () = assert (ind >= 0)
val () = assert (ind < NSYMBOL_MAX)
in
NULLABLEarr[ind] := v
end
implement symbol_FIRSTSET_get (sym) = let
val ind = symbol_index_get sym
val ind = int1_of_int ind
val () = assert (ind >= 0)
val () = assert (ind < NSYMBOL_MAX)
in
FIRSTSETarr[ind]
end
implement symbol_FIRSTSET_set (sym, v) = let
val ind = symbol_index_get sym
val ind = int1_of_int ind
val () = assert (ind >= 0)
val () = assert (ind < NSYMBOL_MAX)
in
FIRSTSETarr[ind] := v
end
implement symbol_FOLLOWSET_get (sym) = let
val ind = symbol_index_get sym
val ind = int1_of_int ind
val () = assert (ind >= 0)
val () = assert (ind < NSYMBOL_MAX)
in
FOLLOWSETarr[ind]
end
implement symbol_FOLLOWSET_set (sym, v) = let
val ind = symbol_index_get sym
val ind = int1_of_int ind
val () = assert (ind >= 0)
val () = assert (ind < NSYMBOL_MAX)
in
FOLLOWSETarr[ind] := v
end
fn test_nullability
(alpha: array0 symbol_t, i0: int, n: int): bool = let
fun loop (i: int):<cloref1> bool =
if i < i0 + n then
if symbol_is_nullable (alpha[i]) then loop (i+1) else false
else begin
true end in
loop (i0)
end
fun process_rule (r: rule, flag: &int): void = let
val+ RULE (name, x0, alpha) = r
val k = int_of_size (array0_size alpha)
val () = if symbol_isnot_nullable (x0) then
if test_nullability (alpha, 0, k) then let
val () = flag := flag + 1 in symbol_nullable_set (x0, true)
end val () = loop1 (0, flag) where {
fun loop1 (i: int, flag: &int):<cloref1> void = let
in
if i < k then let
val yi = alpha[i]
val test = test_nullability (alpha, 0, i)
val () = if test then let
val flag0 = flag
val fstset_x0 = symbol_FIRSTSET_get (x0);
val fstset_yi = symbol_FIRSTSET_get (yi)
val fstset_x0_new = symbolset_union_flag (fstset_x0, fstset_yi, flag)
in
if flag > flag0 then symbol_FIRSTSET_set (x0, fstset_x0_new)
end val test = test_nullability (alpha, i+1, k-i-1)
val () = if test then let
val flag0 = flag
val folset_x0 = symbol_FOLLOWSET_get (x0)
val folset_yi = symbol_FOLLOWSET_get (yi)
val folset_yi_new = symbolset_union_flag (folset_yi, folset_x0, flag)
in
if flag > flag0 then symbol_FOLLOWSET_set (yi, folset_yi_new)
end
val () = loop2 (i, i+1, flag) where {
fun loop2
(i: int, j: int, flag: &int):<cloref1> void = let
in
if j < k then let
val test = test_nullability (alpha, i+1, j-i-1)
val () = if test then let
val flag0 = flag
val yj = alpha[j]
val folset_yi = symbol_FOLLOWSET_get (yi)
val fstset_yj = symbol_FIRSTSET_get (yj)
val folset_yi_new = symbolset_union_flag (folset_yi, fstset_yj, flag)
in
if flag > flag0 then symbol_FOLLOWSET_set (yi, folset_yi_new)
end in
loop2 (i, j+1, flag)
end end } in
loop1 (i+1, flag)
end else begin
() end end } in
end
fun process_rules (rs: List rule, flag: &int): void =
case+ rs of
| list_cons (r, rs) => (process_rule (r, flag); process_rules (rs, flag))
| list_nil () => ()
implement compute_nullable_first_follow_tables (G) = let
var flag: int? val () = loop (G.termlst) where {
fun loop (xs: List symbol_t): void = case+ xs of
| list_cons (x, xs) => let
val () = symbol_FIRSTSET_set (x, symbolset_sing x)
in
loop (xs)
end | list_nil () => ()
} in
while (true) let
val () = flag := 0; val () = process_rules (G.rules, flag)
in
if flag = 0 then break
end end
implement print_nullable_first_follow_tables (G) = loop (G.nontermlst) where {
fun loop (xs: List symbol_t): void = case+ xs of
| list_cons (x, xs) => let
val () = print_symbol x
val () = print_string ": "
val v = symbol_is_nullable x
val () = print_bool v
val v = symbol_FIRSTSET_get x
val () = (print "; "; print_symbolset v)
val v = symbol_FOLLOWSET_get x
val () = (print "; "; print_symbolset v)
val () = print_newline ()
in
loop (xs)
end | list_nil () => ()
}