summaryrefslogtreecommitdiff
path: root/tests/general/gc2.icn
diff options
context:
space:
mode:
Diffstat (limited to 'tests/general/gc2.icn')
-rw-r--r--tests/general/gc2.icn222
1 files changed, 222 insertions, 0 deletions
diff --git a/tests/general/gc2.icn b/tests/general/gc2.icn
new file mode 100644
index 0000000..e89902c
--- /dev/null
+++ b/tests/general/gc2.icn
@@ -0,0 +1,222 @@
+global defs, ifile, in, limit, tswitch, prompt
+
+record nonterm(name)
+record charset(chars)
+record query(name)
+
+procedure main(x)
+ local line, plist
+ plist := [define,generate,grammar,source,comment,prompter,error]
+ defs := table()
+ defs["lb"] := [["<"]]
+ defs["rb"] := [[">"]]
+ defs["vb"] := [["|"]]
+ defs["nl"] := [["\n"]]
+ defs[""] := [[""]]
+ defs["&lcase"] := [[charset(&lcase)]]
+ defs["&ucase"] := [[charset(&ucase)]]
+ defs["&digit"] := [[charset('0123456789')]]
+ i := 0
+ while i < *x do {
+ s := x[i +:= 1] | break
+ case s of {
+ "-t": tswitch := 1
+ "-l": limit := integer(x[i +:= 1]) | stop("usage: [-t] [-l n]")
+ default: stop("usage: [-t] [-l n]")
+ }
+ }
+ ifile := [&input]
+ prompt := ""
+ test := ["<a>::=1|2|3","<a>10","->","<b>::=<a>|<a><a>|<b><b>","<b>5",
+ "<c>::=<b><b><b>","<c>100","<b>100"]
+ every line := !test do {
+ (!plist)(line)
+ collect()
+ every write(&collections)
+ write("----------")
+ }
+end
+
+procedure comment(line)
+ if line[1] == "#" then return
+end
+
+procedure define(line)
+ return line ?
+ defs[(="<",tab(find(">::=")))] := (move(4),alts(tab(0)))
+end
+
+procedure defnon(sym)
+ if sym ? {
+ ="'" &
+ chars := cset(tab(-1)) &
+ ="'"
+ }
+ then return charset(chars)
+ else if sym ? {
+ ="?" &
+ name := tab(0)
+ }
+ then return query(name)
+ else return nonterm(sym)
+end
+
+procedure error(line)
+ write("*** erroneous line: ",line)
+ return
+end
+
+procedure gener(goal)
+ local pending, genstr, symbol
+ repeat {
+ pending := [nonterm(goal)]
+ genstr := ""
+ while symbol := get(pending) do {
+ if \tswitch then write(genstr,symimage(symbol),listimage(pending))
+ case type(symbol) of {
+ "string": genstr ||:= symbol
+ "charset": genstr ||:= ?symbol.chars
+ "query": {
+ writes("*** supply string for ",symbol.name," ")
+ genstr ||:= read() | {
+ write("*** no value for query to ",symbol.name)
+ suspend genstr
+ break next
+ }
+ }
+ "nonterm": {
+ pending := ?\defs[symbol.name] ||| pending | {
+ write("*** undefined nonterminal: <",symbol.name,">")
+ suspend genstr
+ break next
+ }
+ if *pending > \limit then {
+ write("*** excessive symbols remaining")
+ suspend genstr
+ break next
+ }
+ }
+ }
+ }
+ suspend genstr
+ }
+end
+
+procedure generate(line)
+ local goal, count
+ if line ? {
+ ="<" &
+ goal := tab(upto('>')) \ 1 &
+ move(1) &
+ count := (pos(0) & 1) | integer(tab(0))
+ }
+ then {
+ every write(gener(goal)) \ count
+ return
+ }
+ else fail
+end
+
+procedure getrhs(a)
+ local rhs
+ rhs := ""
+ every rhs ||:= sform(!a) || "|"
+ return rhs[1:-1]
+end
+
+procedure grammar(line)
+ local file, out
+ if line ? {
+ name := tab(find("->")) &
+ move(2) &
+ file := tab(0) &
+ out := if *file = 0 then &output else {
+ open(file,"w") | {
+ write("*** cannot open ",file)
+ fail
+ }
+ }
+ }
+ then {
+ (*name = 0) | (name[1] == "<" & name[-1] == ">") | fail
+ pwrite(name,out)
+ if *file ~= 0 then close(out)
+ return
+ }
+ else fail
+end
+
+procedure listimage(a)
+ local s, x
+ s := ""
+ every x := !a do
+ s ||:= symimage(x)
+ return s
+end
+
+procedure alts(defn)
+ local alist
+ alist := []
+ defn ? while put(alist,syms(tab(many(~'|')))) do move(1)
+ return alist
+end
+
+procedure prompter(line)
+ if line[1] == "=" then {
+ prompt := line[2:0]
+ return
+ }
+end
+
+procedure pwrite(name,ofile)
+ local nt, a
+ static builtin
+ initial builtin := ["lb","rb","vb","nl","","&lcase","&ucase","&digit"]
+ if *name = 0 then {
+ a := sort(defs)
+ every nt := !a do {
+ if nt[1] == !builtin then next
+ write(ofile,"<",nt[1],">::=",getrhs(nt[2]))
+ }
+ }
+ else write(ofile,name,"::=",getrhs(\defs[name[2:-1]])) |
+ write("*** undefined nonterminal: ",name)
+end
+
+procedure sform(alt)
+ local s, x
+ s := ""
+ every x := !alt do
+ s ||:= case type(x) of {
+ "string": x
+ "nonterm": "<" || x.name || ">"
+ "charset": "<'" || x.chars || "'>"
+ }
+ return s
+end
+
+procedure source(line)
+ return line ? (="@" & push(ifile,in) & {
+ in := open(file := tab(0)) | {
+ write("*** cannot open ",file)
+ fail
+ }
+ })
+end
+
+procedure symimage(x)
+ return case type(x) of {
+ "string": x
+ "nonterm": "<" || x.name || ">"
+ "charset": "<'" || x.chars || "'>"
+ }
+end
+
+procedure syms(alt)
+ local slist
+ slist := []
+ alt ? while put(slist,tab(many(~'<')) |
+ defnon(2(="<",tab(upto('>')),move(1))))
+ return slist
+end
+