|
|
1.1 ! root 1: # This program generates randomly selected sentences from ! 2: # user-specified grammars. It is an extension of a program ! 3: # given in Chapter 20 of the Icon book and is included in ! 4: # the Icon program library. ! 5: ! 6: global defs, ifile, in, limit, tswitch, prompt ! 7: record nonterm(name) ! 8: record charset(chars) ! 9: record query(name) ! 10: procedure main(x) ! 11: local line, plist ! 12: plist := [define,generate,grammar,source,comment,prompter,error] ! 13: defs := table() ! 14: defs["lb"] := [["<"]] ! 15: defs["rb"] := [[">"]] ! 16: defs["vb"] := [["|"]] ! 17: defs["nl"] := [["\n"]] ! 18: defs[""] := [[""]] ! 19: defs["&lcase"] := [[charset(&lcase)]] ! 20: defs["&ucase"] := [[charset(&ucase)]] ! 21: defs["&digit"] := [[charset('0123456789')]] ! 22: i := 0 ! 23: while i < *x do { ! 24: s := x[i +:= 1] | break ! 25: case s of { ! 26: "-t": tswitch := 1 ! 27: "-l": limit := integer(x[i +:= 1]) | stop("usage: [-t] [-l n]") ! 28: default: stop("usage: [-t] [-l n]") ! 29: } ! 30: } ! 31: ifile := [&input] ! 32: prompt := "" ! 33: while in := pop(ifile) do { ! 34: repeat { ! 35: if *prompt ~= 0 then writes(prompt) ! 36: line := read(in) | break ! 37: while line[-1] == "\\" do line := line[1:-1] || read(in) | break ! 38: (!plist)(line) ! 39: } ! 40: close(in) ! 41: } ! 42: end ! 43: ! 44: procedure comment(line) ! 45: if line[1] == "#" then return ! 46: end ! 47: ! 48: procedure define(line) ! 49: return line ? ! 50: defs[(="<",tab(find(">::=")))] := (move(4),alts(tab(0))) ! 51: end ! 52: ! 53: procedure defnon(sym) ! 54: if sym ? { ! 55: ="'" & ! 56: chars := cset(tab(-1)) & ! 57: ="'" ! 58: } ! 59: then return charset(chars) ! 60: else if sym ? { ! 61: ="?" & ! 62: name := tab(0) ! 63: } ! 64: then return query(name) ! 65: else return nonterm(sym) ! 66: end ! 67: ! 68: procedure error(line) ! 69: write("*** erroneous line: ",line) ! 70: return ! 71: end ! 72: ! 73: procedure gener(goal) ! 74: local pending, genstr, symbol ! 75: repeat { ! 76: pending := [nonterm(goal)] ! 77: genstr := "" ! 78: while symbol := get(pending) do { ! 79: if \tswitch then write(&errout,genstr,symimage(symbol),listimage(pending)) ! 80: case type(symbol) of { ! 81: "string": genstr ||:= symbol ! 82: "charset": genstr ||:= ?symbol.chars ! 83: "query": { ! 84: writes("*** supply string for ",symbol.name," ") ! 85: genstr ||:= read() | { ! 86: write(&errout,"*** no value for query to ",symbol.name) ! 87: suspend genstr ! 88: break next ! 89: } ! 90: } ! 91: "nonterm": { ! 92: pending := ?\defs[symbol.name] ||| pending | { ! 93: write(&errout,"*** undefined nonterminal: <",symbol.name,">") ! 94: suspend genstr ! 95: break next ! 96: } ! 97: if *pending > \limit then { ! 98: write(&errout,"*** excessive symbols remaining") ! 99: suspend genstr ! 100: break next ! 101: } ! 102: } ! 103: } ! 104: } ! 105: suspend genstr ! 106: } ! 107: end ! 108: ! 109: procedure generate(line) ! 110: local goal, count ! 111: if line ? { ! 112: ="<" & ! 113: goal := tab(upto('>')) \ 1 & ! 114: move(1) & ! 115: count := (pos(0) & 1) | integer(tab(0)) ! 116: } ! 117: then { ! 118: every write(gener(goal)) \ count ! 119: return ! 120: } ! 121: else fail ! 122: end ! 123: ! 124: procedure getrhs(a) ! 125: local rhs ! 126: rhs := "" ! 127: every rhs ||:= sform(!a) || "|" ! 128: return rhs[1:-1] ! 129: end ! 130: ! 131: procedure grammar(line) ! 132: local file, out ! 133: if line ? { ! 134: name := tab(find("->")) & ! 135: move(2) & ! 136: file := tab(0) & ! 137: out := if *file = 0 then &output else { ! 138: open(file,"w") | { ! 139: write(&errout,"*** cannot open ",file) ! 140: fail ! 141: } ! 142: } ! 143: } ! 144: then { ! 145: (*name = 0) | (name[1] == "<" & name[-1] == ">") | fail ! 146: pwrite(name,out) ! 147: if *file ~= 0 then close(out) ! 148: return ! 149: } ! 150: else fail ! 151: end ! 152: ! 153: procedure listimage(a) ! 154: local s, x ! 155: s := "" ! 156: every x := !a do ! 157: s ||:= symimage(x) ! 158: return s ! 159: end ! 160: ! 161: procedure alts(defn) ! 162: local alist ! 163: alist := [] ! 164: defn ? while put(alist,syms(tab(many(~'|')))) do move(1) ! 165: return alist ! 166: end ! 167: ! 168: procedure prompter(line) ! 169: if line[1] == "=" then { ! 170: prompt := line[2:0] ! 171: return ! 172: } ! 173: end ! 174: ! 175: procedure pwrite(name,ofile) ! 176: local nt, a ! 177: static builtin ! 178: initial builtin := ["lb","rb","vb","nl","","&lcase","&ucase","&digit"] ! 179: if *name = 0 then { ! 180: a := sort(defs) ! 181: every nt := !a do { ! 182: if nt[1] == !builtin then next ! 183: write(ofile,"<",nt[1],">::=",getrhs(nt[2])) ! 184: } ! 185: } ! 186: else write(ofile,name,"::=",getrhs(\defs[name[2:-1]])) | ! 187: write("*** undefined nonterminal: ",name) ! 188: end ! 189: ! 190: procedure sform(alt) ! 191: local s, x ! 192: s := "" ! 193: every x := !alt do ! 194: s ||:= case type(x) of { ! 195: "string": x ! 196: "nonterm": "<" || x.name || ">" ! 197: "charset": "<'" || x.chars || "'>" ! 198: } ! 199: return s ! 200: end ! 201: ! 202: procedure source(line) ! 203: return line ? (="@" & push(ifile,in) & { ! 204: in := open(file := tab(0)) | { ! 205: write(&errout,"*** cannot open ",file) ! 206: fail ! 207: } ! 208: }) ! 209: end ! 210: ! 211: procedure symimage(x) ! 212: return case type(x) of { ! 213: "string": x ! 214: "nonterm": "<" || x.name || ">" ! 215: "charset": "<'" || x.chars || "'>" ! 216: } ! 217: end ! 218: ! 219: procedure syms(alt) ! 220: local slist ! 221: slist := [] ! 222: alt ? while put(slist,tab(many(~'<')) | ! 223: defnon(2(="<",tab(upto('>')),move(1)))) ! 224: return slist ! 225: end ! 226:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.