/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ static char rcsid[]= "$Header: mkboot.c,v 1.1 85/08/22 15:44:31 timo Exp $"; /* * B editor -- Program to create the "boot.h" file (the grammar tables). */ #include "b.h" #include "node.h" #include "gram.h" #include "tabl.h" #include /* * Test whether sym is in the given class. */ Visible bool isinclass(sym, ci) int sym; struct classinfo *ci; { classptr cp; Assert(ci && ci->c_class); if (sym == Hole) return !isinclass(Optional, ci); for (cp = ci->c_class; *cp; ++cp) if (sym == *cp) return Yes; return No; } main() { int sym; int nch; struct classinfo **cp; struct classinfo *sp; printf("/* boot.h -- data file for grammar tables. */\n\n"); /* Check the representations. The code assumes Optional and Hole are the last symbols in the table, i.e. the first processed by the loop. */ for (sym = TABLEN-1; sym >= 0; --sym) { if (table[sym].r_symbol != sym) { if (sym != Hole && sym != Optional && table[sym].r_symbol == 0) continue; /* Disabled table entry */ syserr("initgram: table order (%s=%d, should be %d)", table[sym].r_name, table[sym].r_symbol, sym); } cp = table[sym].r_class; for (nch = 0; nch < MAXCHILD && (sp = cp[nch]); ++nch) ; ckrepr(table[sym].r_repr, nch); } initcodes(); initclasses(); dumptable(); exit(0); } /* * Check a representation array (subroutine for initgram). */ Hidden Procedure ckrepr(rp, nch) string *rp; int nch; { string cp; int i; int ich; for (ich = 0; ich <= nch; ++ich) { cp = rp[ich]; if (!cp) continue; for (i = 0; cp[i]; ++i) { switch (cp[i]) { case '\n': case '\r': if (i || ich) syserr("initgram (ckrepr): badly placed \\n/\\r"); break; case '\t': case '\b': if (cp[i+1]) syserr("initgram (ckrepr): badly placed \\t/\\b"); break; default: if (cp[i] < ' ' || cp[i] >= 0177) syserr("initgram (ckrepr): illegal control char"); } } } } /* * Compaction scheme for characters to save space in grammar tables * by combining characters with similar properties (digits, l.c. letters). */ #define RANGE 128 /* ASCII characters are in {0 .. RANGE-1} */ Visible char code_array[RANGE]; Visible char invcode_array[RANGE]; Visible int lastcode; Hidden Procedure initcodes() { int c; code_array['\n'] = ++lastcode; invcode_array[lastcode] = '\n'; for (c = ' '; c <= '0'; ++c) { code_array[c] = ++lastcode; invcode_array[lastcode] = c; } for (; c <= '9'; ++c) code_array[c] = lastcode; for (; c <= 'a'; ++c) { code_array[c] = ++lastcode; invcode_array[lastcode] = c; } for (; c <= 'z'; ++c) code_array[c] = lastcode; for (; c < RANGE; ++c) { code_array[c] = ++lastcode; invcode_array[lastcode] = c; } } /* * Initialization routine for the 'struct classinfo' stuff. * * "Suggestion" is skipped: * what can be inserted there is not computed from this table. */ Hidden Procedure initclasses() { int i; int j; struct table *tp; for (i = 0; i < TABLEN; ++i) { tp = &table[i]; if (tp->r_symbol != i || i == Suggestion) continue; /* Dead entry */ for (j = 0; j < MAXCHILD && tp->r_class[j]; ++j) { if (!tp->r_class[j]->c_insert) defclass(tp->r_class[j]); } } } classptr makelist(); /* Forward */ Hidden Procedure defclass(p) struct classinfo *p; { int c; struct table *tp; classptr cp; classptr cp1; classelem insert[1024]; classelem append[1024]; classelem join[1024]; int inslen = 0; int applen = 0; int joinlen = 0; string *rp; int fw1; cp = p->c_class; Assert(cp); for (; *cp; ++cp) { if (*cp == Optional) continue; if (*cp >= TABLEN) { /* Insert direct lexical item */ for (c = 1; c <= lastcode; ++c) { if (maystart(Invcode(c), *cp)) { Assert(inslen+3 < sizeof insert / sizeof insert[0]); insert[inslen] = c; insert[inslen+1] = *cp; inslen += 2; } } continue; } tp = &table[*cp]; rp = tp->r_repr; if (!Fw_zero(rp[0])) { /* Insert fixed text */ c = Code(rp[0][0]); Assert(inslen+3 < sizeof insert / sizeof insert[0]); insert[inslen] = c; insert[inslen+1] = *cp; inslen += 2; continue; } Assert(tp->r_class[0]); cp1 = tp->r_class[0]->c_class; Assert(cp1); for (; *cp1; ++cp1) { if (*cp1 < TABLEN) continue; for (c = 1; c <= lastcode; ++c) { /* Insert indir. lex. items */ if (maystart(Invcode(c), *cp1)) { Assert(inslen+3 < sizeof insert / sizeof insert[0]); insert[inslen] = c; insert[inslen+1] = *cp; inslen += 2; } } } fw1 = Fwidth(rp[1]); if (fw1) { /* Append */ c = rp[1][0]; Assert(c > 0 && c < RANGE); if (c == ' ') { c = rp[1][1]; if (!c || c == '\b' || c == '\t') c = ' '; else c |= 0200; } Assert(applen+3 < sizeof append / sizeof append[0]); append[applen] = c; append[applen+1] = *cp; applen += 2; } if ((!fw1 || fw1 == 1 && rp[1][0] == ' ') && tp->r_class[1]) { /* Join */ Assert(joinlen+3 < sizeof join / sizeof join[0]); join[joinlen] = 1 + fw1; join[joinlen+1] = *cp; joinlen += 2; } } Assert(inslen); /* Dead alley */ insert[inslen] = 0; p->c_insert = makelist(insert, inslen + 1); if (applen) { append[applen] = 0; p->c_append = makelist(append, applen + 1); } if (joinlen) { join[joinlen] = 0; p->c_join = makelist(join, joinlen + 1); } } Hidden classptr makelist(list, len) classptr list; int len; { classptr cp = (classptr) malloc((unsigned) (len*sizeof(classelem))); int i; if (!cp) syserr("makelist: malloc"); for (i = 0; i < len; ++i, ++list) cp[i] = *list; #ifndef NDEBUG if (index(cp, '\0') != cp+len-1) printf("makelist: zero in string!\n"); #endif return cp; } #define MAXLOOKUP 1000 Hidden struct classinfo **known; Hidden int nknown; Hidden Procedure dumptable() { int sym; getclassinfos(); printf("Hidden struct table b_grammar[%d] = {\n", TABLEN); for (sym= 0; sym < TABLEN; ++sym) dumpentry(table+sym); printf("};\n"); free(known); } Hidden Procedure getclassinfos() { int sym, k; known= (struct classinfo **) malloc(MAXLOOKUP * sizeof(struct classinfo*)); if (known == NULL) syserr("getclassinfos: can't malloc 'known' array"); nknown= 0; printf("Hidden struct classinfo cl[] = {\n"); for (sym= 0; sym < TABLEN; ++sym) { for (k= 0; k < MAXCHILD; ++k) lookup(table[sym].r_class[k]); } printf("};\n\n"); } Hidden int lookup(ci) struct classinfo *ci; { int k; if (ci == NULL) return -1; for (k= 0; k < nknown; ++k) { if (known[k] == ci) return k; } if (k < MAXLOOKUP) { ++nknown; known[k]= ci; printf("/*%d*/", k); dumpclassinfo(ci); } } Hidden Procedure dumpclassinfo(ci) struct classinfo *ci; { printf("\t{"); dumpstring(ci->c_class); printf("\n\t"); dumpstring(ci->c_insert); printf("\n\t"); dumpstring(ci->c_append); printf("\n\t"); dumpstring(ci->c_join); printf("},\n"); } Hidden Procedure dumpentry(p) struct table *p; { int k; printf("\t{%2d, ", p->r_symbol); dumpstring(p->r_name); printf(" {"); for (k= 0; k <= MAXCHILD; ++k) dumpstring(p->r_repr[k]); printf("}, {"); for (k= 0; k < MAXCHILD; ++k) refclassinfo(p->r_class[k]); printf("}, 0},\n"); } Hidden Procedure dumpstring(s) string s; { char c; if (s == NULL) { printf("0, "); return; } printf("\""); for (; (c= *s) != '\0'; ++s) { if (c >= ' ' && c < 0177) { if (c == '\\' || c == '"') printf("\\"); printf("%c", c); } else if (c == '\t') printf("\\t"); else if (c == '\b') printf("\\b"); else printf("\\%03o", c&0377); } printf("\", "); } Hidden Procedure refclassinfo(ci) struct classinfo ci; { int k= lookup(ci); if (k >= 0) printf("&cl[%d], ", k); else printf("0, "); } /* * Yield the width of a piece of fixed text as found in a node's repr, * excluding \b or \t. If \n or \r is found, -1 is returned. * It assumes that \n or \r only occur as first * character, and \b or \t only as last. */ Visible int fwidth(str) register string str; { register int c; register int n = 0; if (!str) return 0; c = str[0]; if (c == '\r' || c == '\n') return -1; for (; c; c = *++str) ++n; if (n > 0) { c = str[-1]; if (c == '\t' || c == '\b') --n; } return n; } Visible Procedure syserr(fmt, a1, a2, a3, a4, a5) string fmt; { fprintf(stderr, "mkboot system error:\n"); fprintf(stderr, fmt, a1, a2, a3, a4, a5); fprintf(stderr, "\n"); exit(1); } Visible Procedure asserr(file, line) string file; int line; { syserr("assertion error: %s, line %d", file, line); }