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: }