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