|
|
1.1 root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2: static char rcsid[] = "$Header: gram.c,v 2.5 85/08/22 16:03:16 timo Exp $";
3:
4: /*
5: * B editor -- All routines referencing the grammar table are in this file.
6: */
7:
8: #include "b.h"
9: #include "feat.h"
10: #include "bobj.h"
11: #include "node.h"
12: #include "gram.h"
13: #include "supr.h"
14: #include "tabl.h"
15:
16: extern bool dflag;
17:
18: #include <ctype.h>
19:
20:
21: /*
22: * Test whether sym is in the given class.
23: */
24:
25: Visible bool
26: isinclass(sym, ci)
27: register int sym;
28: struct classinfo *ci;
29: {
30: register classptr cp;
31:
32: Assert(ci && ci->c_class);
33: if (sym == Hole)
34: return !isinclass(Optional, ci);
35: for (cp = ci->c_class; *cp; ++cp)
36: if (sym == *cp)
37: return Yes;
38: return No;
39: }
40:
41:
42: /*
43: * Deliver the representation array for the given node.
44: * If the node is actually just a "text" value, construct
45: * one in static storage -- which is overwritten at each call.
46: * In this case there are two deficiencies: the next call to
47: * noderepr which uses the same feature overwrites the reply
48: * value of the previous call, AND if the text value itself
49: * is changed, the representation may change, too.
50: * In practical use this is no problem at all, however.
51: */
52:
53: Visible string *
54: noderepr(n)
55: register node n;
56: {
57: register int sym;
58:
59: if (n && Type(n) == Tex) {
60: static string buf[2];
61: buf[0] = Str((value)n);
62: return buf;
63: }
64: sym = symbol(n);
65: return table[sym].r_repr;
66: }
67:
68:
69: /*
70: * Deliver the prototype node for the given symbol.
71: */
72:
73: Visible node
74: gram(sym)
75: register int sym;
76: {
77: Assert(sym == 0 || sym > 0 && sym < TABLEN && table[sym].r_symbol);
78: return table[sym].r_node;
79: }
80:
81: #ifdef SAVEBUF
82:
83: /*
84: * Deliver the name of a symbol.
85: */
86:
87: Visible string
88: symname(sym)
89: int sym;
90: {
91: static char buf[20];
92:
93: if (sym >= 0 && sym < TABLEN && table[sym].r_name)
94: return table[sym].r_name;
95: sprintf(buf, "%d", sym);
96: return buf;
97: }
98:
99:
100: /*
101: * Find the symbol corresponding to a given name.
102: * Return -1 if not found.
103: */
104:
105: Visible int
106: nametosym(str)
107: register string str;
108: {
109: register int sym;
110: register string name;
111:
112: for (sym = 0; sym < TABLEN; ++sym) {
113: name = table[sym].r_name;
114: if (name && Strequ(name, str))
115: return sym;
116: }
117: return -1;
118: }
119:
120: #endif SAVEBUF
121:
122: /*
123: * Test whether `sym' may replace the node in the path `p'.
124: */
125:
126: Visible bool
127: allowed(p, sym)
128: register path p;
129: register int sym;
130: {
131: register path pa = parent(p);
132: register int ich = ichild(p);
133: register int sympa = pa ? symbol(tree(pa)) : Rootsymbol;
134:
135: Assert(sympa >= 0 && sympa < TABLEN && ich > 0 && ich <= MAXCHILD);
136: return isinclass(sym, table[sympa].r_class[ich-1]);
137: }
138:
139:
140: /*
141: * Initialize (and verify) the grammar table.
142: */
143:
144: Visible Procedure
145: initgram()
146: {
147: register int sym;
148: register int nch;
149: register struct classinfo **cp;
150: register struct classinfo *sp;
151: node ch[MAXCHILD];
152:
153: #ifndef NDEBUG
154: if (dflag)
155: fprintf(stderr, "*** initgram();\n\r");
156: #endif NDEBUG
157: /* Set the node pointers in the table and check the representations.
158: The code assumes Optional and Hole are the last
159: symbols in the table, i.e. the first processed by the loop. */
160:
161: for (sym = TABLEN-1; sym >= 0; --sym) {
162: if (table[sym].r_symbol != sym) {
163: if (sym != Hole && sym != Optional && table[sym].r_symbol == 0)
164: continue; /* Disabled table entry */
165: syserr("initgram: table order (%s=%d, should be %d)",
166: table[sym].r_name, table[sym].r_symbol, sym);
167: }
168: cp = table[sym].r_class;
169: for (nch = 0; nch < MAXCHILD && (sp = cp[nch]); ++nch)
170: ch[nch] =
171: table[sp->c_class[0] == Optional ?
172: Optional : Hole].r_node;
173: table[sym].r_node = newnode(nch, sym, ch);
174: fix((value) table[sym].r_node);
175: }
176:
177: initcodes();
178: #ifdef USERSUGG
179: initclasses();
180: #endif USERSUGG
181: }
182:
183:
184: #ifdef USERSUGG
185:
186: /*
187: * Add built-in commands to the suggestion tables.
188: */
189:
190: Hidden Procedure
191: initclasses()
192: {
193: register int i;
194: register int j;
195: register struct table *tp;
196:
197: for (i = 0; i < TABLEN; ++i) {
198: tp = &table[i];
199: if (tp->r_symbol != i || i == Suggestion)
200: continue; /* Dead entry */
201: for (j = 0; j < MAXCHILD && tp->r_class[j]; ++j) {
202: if (isinclass(Suggestion, tp->r_class[j]))
203: makesugg(tp->r_class[j]->c_class);
204: }
205: }
206: }
207:
208:
209: /*
210: * Extract suggestions from class list.
211: */
212:
213: Hidden Procedure
214: makesugg(cp)
215: classptr cp;
216: {
217: struct table *tp;
218: string *rp;
219: char buffer[1000];
220: string bp;
221: string sp;
222: int i;
223: int nch;
224:
225: for (; *cp; ++cp) {
226: if (*cp >= TABLEN || *cp < 0)
227: continue;
228: tp = &table[*cp];
229: rp = tp->r_repr;
230: if (rp[0] && isupper(rp[0][0])) {
231: bp = buffer;
232: nch = nchildren(tp->r_node);
233: for (i = 0; i <= nch; ++i) {
234: if (rp[i]) {
235: for (sp = rp[i]; *sp >= ' '; ++sp)
236: *bp++ = *sp;
237: }
238: if (i < nch && !isinclass(Optional, tp->r_class[i]))
239: *bp++ = '?';
240: }
241: if (bp > buffer) {
242: *bp = 0;
243: addsugg(buffer, Yes);
244: }
245: }
246: }
247: }
248:
249: #endif USERSUGG
250:
251:
252: /*
253: * Compaction scheme for characters to save space in grammar tables
254: * by combining characters with similar properties (digits, l.c. letters).
255: */
256:
257: #define RANGE 128 /* ASCII characters are in {0 .. RANGE-1} */
258:
259: Visible char code_array[RANGE];
260: Visible char invcode_array[RANGE];
261: Visible int lastcode;
262:
263: Hidden Procedure
264: initcodes()
265: {
266: register int c;
267:
268: code_array['\n'] = ++lastcode;
269: invcode_array[lastcode] = '\n';
270: for (c = ' '; c <= '0'; ++c) {
271: code_array[c] = ++lastcode;
272: invcode_array[lastcode] = c;
273: }
274: for (; c <= '9'; ++c)
275: code_array[c] = lastcode;
276: for (; c <= 'a'; ++c) {
277: code_array[c] = ++lastcode;
278: invcode_array[lastcode] = c;
279: }
280: for (; c <= 'z'; ++c)
281: code_array[c] = lastcode;
282: for (; c < RANGE; ++c) {
283: code_array[c] = ++lastcode;
284: invcode_array[lastcode] = c;
285: }
286: }
287:
288:
289: /*
290: * Set the root of the grammar to the given symbol. It must exist.
291: */
292:
293: Visible Procedure
294: setroot(name)
295: string name;
296: {
297: register int k;
298: register int i;
299:
300: for (k = 1; k < TABLEN; ++k) {
301: if (table[k].r_name && Strequ(name, table[k].r_name)) {
302: table[Rootsymbol].r_symbol = table[k].r_symbol;
303: table[Rootsymbol].r_name = table[k].r_name;
304: for (i = 0; i < MAXCHILD; ++i) {
305: table[Rootsymbol].r_repr[i] = table[k].r_repr[i];
306: table[Rootsymbol].r_class[i] = table[k].r_class[i];
307: }
308: table[Rootsymbol].r_repr[i] = table[k].r_repr[i];
309: table[Rootsymbol].r_node = table[k].r_node;
310: table[Rootsymbol].r_symbol = Rootsymbol;
311: return;
312: }
313: }
314: syserr("Can't set root of grammar to <%s>", name);
315: }
316:
317:
318: /*
319: * The remainder of this file is specific for the currently used grammar.
320: */
321:
322:
323: #include "boot.h" /* Has static data, so should be included only once! */
324: #include "syms.h"
325:
326: Visible struct table *table = b_grammar;
327:
328:
329: /*
330: * Table indicating which symbols are used to form lists of items.
331: * Consulted via predicate 'issublist' in "gram.c".
332: */
333:
334: Hidden classelem Asublists[] = {
335: E_plus, F_e_plus,
336: And, And_kw, Or, Or_kw,
337: 0,
338: };
339:
340: Hidden struct classinfo sublists[] = {Asublists};
341:
342:
343: /*
344: * Predicate telling whether two symbols can form lists together.
345: * This is important for list whose elements must alternate in some
346: * way, as is the case for [KEYWORD [expression] ]*.
347: *
348: * This code must be in this file, otherwise the names and values
349: * of the symbols would have to be made public.
350: */
351:
352: Visible bool
353: samelevel(sym, sym1)
354: register int sym;
355: register int sym1;
356: {
357: register int zzz;
358:
359: if (sym1 == sym)
360: return Yes;
361: if (sym1 < sym)
362: zzz = sym, sym = sym1, sym1 = zzz; /* Ensure sym <= sym1 */
363: /* Now always sym < sym1 */
364: return sym == Kw_plus && sym1 == E_plus
365: || sym == F_kw_plus && sym1 == F_e_plus
366: || sym == And && sym1 == And_kw
367: || sym == Or && sym1 == Or_kw;
368: }
369:
370:
371: /*
372: * Predicate to tell whether a symbol can form chained lists.
373: * By definition, all right-recursive symbols can do so;
374: * in addition, those listed in the class 'sublists' can do
375: * it, too (this is used for lists formed of alternating members
376: * such as KW expr KW ...).
377: */
378:
379: Visible bool
380: issublist(sym)
381: register int sym;
382: {
383: register int i;
384: register string repr;
385:
386: Assert(sym < TABLEN);
387: if (isinclass(sym, sublists))
388: return Yes;
389: repr = table[sym].r_repr[0];
390: if (Fw_positive(repr))
391: return No;
392: for (i = 0; i < MAXCHILD && table[sym].r_class[i]; ++i)
393: ;
394: if (i <= 0)
395: return No;
396: repr = table[sym].r_repr[i];
397: if (!Fw_zero(repr))
398: return No;
399: return isinclass(sym, table[sym].r_class[i-1]);
400: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.