|
|
1.1 ! root 1: char *wartv = "Wart Version 2A(009) 14 Jan 92"; ! 2: ! 3: #ifdef MDEBUG ! 4: /* Use the real ones in this module only */ ! 5: #ifdef malloc ! 6: #undef malloc ! 7: #endif /* malloc */ ! 8: #ifdef calloc ! 9: #undef calloc ! 10: #endif /* calloc */ ! 11: #ifdef realloc ! 12: #undef realloc ! 13: #endif /* realloc */ ! 14: #ifdef free ! 15: #undef free ! 16: #endif /* free */ ! 17: #endif /* MDEBUG */ ! 18: ! 19: #ifdef MAC ! 20: #define VOID void ! 21: #endif /* MAC */ ! 22: ! 23: /* W A R T */ ! 24: ! 25: /* ! 26: A small subset of "lex". ! 27: ! 28: Authors: Jeff Damens, Frank da Cruz ! 29: Columbia University Center for Computing Activites. ! 30: First released November 1984. ! 31: Copyright (C) 1984, 1992, ! 32: Trustees of Columbia University in the City of New York. ! 33: Permission is granted to any individual or institution to use, copy, or ! 34: redistribute this software so long as it is not sold for profit, provided ! 35: this copyright notice is retained. ! 36: */ ! 37: ! 38: /* ! 39: * input format is: ! 40: * lines to be copied | %state <state names...> ! 41: * %% ! 42: * <state> | <state,state,...> CHAR { actions } ! 43: * ... ! 44: * %% ! 45: * more lines to be copied ! 46: */ ! 47: ! 48: #include "ckcdeb.h" /* Includes */ ! 49: ! 50: /* ! 51: The following "char" should be changed to "short", "int", or "long" if your ! 52: wart program will generate more than 127 states. Since wart is used mainly ! 53: with C-Kermit, which has about 50 states, "short" is adequate. This ! 54: keeps the program about 3K-4K smaller. ! 55: */ ! 56: ! 57: #define TBL_TYPE "char" /* C data type of state table */ ! 58: ! 59: #define C_L 014 /* Formfeed */ ! 60: ! 61: #define SEP 1 /* Token types */ ! 62: #define LBRACK 2 ! 63: #define RBRACK 3 ! 64: #define WORD 4 ! 65: #define COMMA 5 ! 66: ! 67: /* Storage sizes */ ! 68: ! 69: #define MAXSTATES 50 /* max number of states */ ! 70: #define MAXWORD 50 /* max # of chars/word */ ! 71: #define SBYTES ((MAXSTATES+6)/8) /* # of bytes for state bitmask */ ! 72: ! 73: /* Name of wart function in generated program */ ! 74: ! 75: #ifndef FNAME ! 76: #define FNAME "wart" ! 77: #endif /* FNAME */ ! 78: ! 79: /* Structure for state information */ ! 80: ! 81: struct transx { ! 82: CHAR states[SBYTES]; /* included states */ ! 83: int anyst; /* true if this good from any state */ ! 84: CHAR inchr; /* input character */ ! 85: int actno; /* associated action */ ! 86: struct transx *nxt; ! 87: }; /* next transition */ ! 88: typedef struct transx *trans; ! 89: ! 90: /* Function prototypes */ ! 91: ! 92: _PROTOTYP( VOID setwstate, (int, trans) ); ! 93: _PROTOTYP( int teststate, (int, trans) ); ! 94: _PROTOTYP( trans rdinput, (FILE *, FILE *) ); ! 95: _PROTOTYP( VOID initial, (FILE *, FILE *) ); ! 96: _PROTOTYP( int isin, (char *, int) ); ! 97: _PROTOTYP( int isword, (int) ); ! 98: _PROTOTYP( VOID rdword, (FILE *, char *) ); ! 99: _PROTOTYP( VOID rdstates, (FILE *, FILE *) ); ! 100: _PROTOTYP( trans newtrans, (void) ); ! 101: _PROTOTYP( trans rdrules, (FILE *, FILE *) ); ! 102: _PROTOTYP( VOID statelist, (FILE *, trans) ); ! 103: _PROTOTYP( VOID copyact, (FILE *, FILE *, int) ); ! 104: _PROTOTYP( int faction, (trans, int, int) ); ! 105: _PROTOTYP( VOID emptytbl, (void) ); ! 106: _PROTOTYP( VOID addaction, (int, int, int) ); ! 107: _PROTOTYP( VOID writetbl, (FILE *) ); ! 108: _PROTOTYP( VOID warray, (FILE *, char *, int *, int, char *) ); ! 109: _PROTOTYP( VOID fatal, (char *) ); ! 110: _PROTOTYP( VOID prolog, (FILE *) ); ! 111: _PROTOTYP( VOID epilogue, (FILE *) ); ! 112: _PROTOTYP( VOID copyrest, (FILE *, FILE *) ); ! 113: _PROTOTYP( int gettoken, (FILE *) ); ! 114: _PROTOTYP( VOID rdcmnt, (FILE *) ); ! 115: _PROTOTYP( VOID clrhash, (void) ); ! 116: _PROTOTYP( int hash, (char *) ); ! 117: _PROTOTYP( VOID enter, (char *, int) ); ! 118: _PROTOTYP( int lkup, (char *) ); ! 119: _PROTOTYP( static char* copy, (char *s) ); ! 120: ! 121: /* Variables and tables */ ! 122: ! 123: static int lines, nstates, nacts; ! 124: ! 125: static char tokval[MAXWORD]; ! 126: ! 127: static int tbl[MAXSTATES*96]; ! 128: ! 129: char *tbl_type = TBL_TYPE; ! 130: ! 131: char *txt1 = "\n#define BEGIN state =\n\nint state = 0;\n\nint\n"; ! 132: ! 133: char *fname = FNAME; /* Generated function name goes here */ ! 134: ! 135: /* rest of program... */ ! 136: ! 137: char *txt2 = "()\n\ ! 138: {\n\ ! 139: int c,actno;\n\ ! 140: extern "; ! 141: ! 142: /* Data type of state table is inserted here (short or int) */ ! 143: ! 144: char *txt2a = " tbl[];\n while (1) {\n c = input() - 32;\n\ ! 145: if (c < 0 || c > 95) c = 0;\n"; ! 146: ! 147: char *txt2b = " if ((actno = tbl[c + state*96]) != -1)\n\ ! 148: switch(actno) {\n"; ! 149: ! 150: /* this program's output goes here, followed by final text... */ ! 151: ! 152: char *txt3 = "\n }\n }\n}\n\n"; ! 153: ! 154: ! 155: /* ! 156: * turn on the bit associated with the given state ! 157: * ! 158: */ ! 159: VOID ! 160: setwstate(state,t) int state; trans t; { ! 161: int idx,msk; ! 162: idx = state/8; /* byte associated with state */ ! 163: msk = 0x80 >> (state % 8); /* bit mask for state */ ! 164: t->states[idx] |= msk; ! 165: } ! 166: ! 167: /* ! 168: * see if the state is involved in the transition ! 169: * ! 170: */ ! 171: int ! 172: teststate(state,t) int state; trans t; { ! 173: int idx,msk; ! 174: idx = state/8; ! 175: msk = 0x80 >> (state % 8); ! 176: return(t->states[idx] & msk); ! 177: } ! 178: ! 179: ! 180: /* ! 181: * read input from here... ! 182: * ! 183: */ ! 184: ! 185: trans ! 186: rdinput(infp,outfp) FILE *infp,*outfp; { ! 187: trans x,rdrules(); ! 188: lines = 1; /* line counter */ ! 189: nstates = 0; /* no states */ ! 190: nacts = 0; /* no actions yet */ ! 191: fprintf(outfp,"\n%c* WARNING -- This C source program generated by ",'/'); ! 192: fprintf(outfp,"Wart preprocessor. */\n"); ! 193: fprintf(outfp,"%c* Do not edit this file; edit the Wart-format ",'/'); ! 194: fprintf(outfp,"source file instead, */\n"); ! 195: fprintf(outfp,"%c* and then run it through Wart to produce a new ",'/'); ! 196: fprintf(outfp,"C source file. */\n\n"); ! 197: fprintf(outfp,"%c* Wart Version Info: */\n",'/'); ! 198: fprintf(outfp,"char *wartv = \"%s\";\n\n",wartv); ! 199: ! 200: initial(infp,outfp); /* read state names, initial defs */ ! 201: prolog(outfp); /* write out our initial code */ ! 202: x = rdrules(infp,outfp); /* read rules */ ! 203: epilogue(outfp); /* write out epilogue code */ ! 204: return(x); ! 205: } ! 206: ! 207: ! 208: /* ! 209: * initial - read initial definitions and state names. Returns ! 210: * on EOF or %%. ! 211: * ! 212: */ ! 213: VOID ! 214: initial(infp,outfp) FILE *infp, *outfp; { ! 215: int c; ! 216: char wordbuf[MAXWORD]; ! 217: while ((c = getc(infp)) != EOF) { ! 218: if (c == '%') { ! 219: rdword(infp,wordbuf); ! 220: if (strcmp(wordbuf,"states") == 0) ! 221: rdstates(infp,outfp); ! 222: else if (strcmp(wordbuf,"%") == 0) return; ! 223: else fprintf(outfp,"%%%s",wordbuf); ! 224: } ! 225: else putc(c,outfp); ! 226: if (c == '\n') lines++; ! 227: } ! 228: } ! 229: ! 230: /* ! 231: * boolean function to tell if the given character can be part of ! 232: * a word. ! 233: * ! 234: */ ! 235: int ! 236: isin(s,c) char *s; int c; { ! 237: for (; *s != '\0'; s++) ! 238: if (*s == (char) c) return(1); ! 239: return(0); ! 240: } ! 241: int ! 242: isword(c) int c; { ! 243: static char special[] = ".%_-$@"; /* these are allowable */ ! 244: return(isalnum(c) || isin(special,c)); ! 245: } ! 246: ! 247: /* ! 248: * read the next word into the given buffer. ! 249: * ! 250: */ ! 251: VOID ! 252: rdword(fp,buf) FILE *fp; char *buf; { ! 253: int len = 0,c; ! 254: while (isword(c = getc(fp)) && ++len < MAXWORD) *buf++ = (char) c; ! 255: *buf++ = '\0'; /* tie off word */ ! 256: ungetc(c,fp); /* put break char back */ ! 257: } ! 258: ! 259: /* ! 260: * read state names, up to a newline. ! 261: * ! 262: */ ! 263: VOID ! 264: rdstates(fp,ofp) FILE *fp,*ofp; { ! 265: int c; ! 266: char wordbuf[MAXWORD]; ! 267: while ((c = getc(fp)) != EOF && c != '\n') { ! 268: if (isspace(c) || c == C_L) continue; /* skip whitespace */ ! 269: ungetc(c,fp); /* put char back */ ! 270: rdword(fp,wordbuf); /* read the whole word */ ! 271: enter(wordbuf,++nstates); /* put into symbol tbl */ ! 272: fprintf(ofp,"#define %s %d\n",wordbuf,nstates); ! 273: } ! 274: lines++; ! 275: } ! 276: ! 277: /* ! 278: * allocate a new, empty transition node ! 279: * ! 280: */ ! 281: trans ! 282: newtrans() { ! 283: trans new; ! 284: int i; ! 285: new = (trans) malloc(sizeof (struct transx)); ! 286: for (i=0; i<SBYTES; i++) new->states[i] = 0; ! 287: new->anyst = 0; ! 288: new->nxt = NULL; ! 289: return(new); ! 290: } ! 291: ! 292: ! 293: /* ! 294: * read all the rules. ! 295: * ! 296: */ ! 297: ! 298: trans ! 299: rdrules(fp,out) FILE *fp,*out; { ! 300: trans head,cur,prev; ! 301: int curtok; ! 302: head = cur = prev = NULL; ! 303: while ((curtok = gettoken(fp)) != SEP) ! 304: ! 305: switch(curtok) { ! 306: case LBRACK: ! 307: if (cur == NULL) ! 308: cur = newtrans(); ! 309: else ! 310: fatal("duplicate state list"); ! 311: statelist(fp,cur); /* set states */ ! 312: continue; /* prepare to read char */ ! 313: ! 314: case WORD: ! 315: if ((int)strlen(tokval) != 1) ! 316: fatal("multiple chars in state"); ! 317: if (cur == NULL) { ! 318: cur = newtrans(); ! 319: cur->anyst = 1; ! 320: } ! 321: cur->actno = ++nacts; ! 322: cur->inchr = (char) (tokval[0] - 32); ! 323: if (head == NULL) ! 324: head = cur; ! 325: else ! 326: prev->nxt = cur; ! 327: prev = cur; ! 328: cur = NULL; ! 329: copyact(fp,out,nacts); ! 330: break; ! 331: default: fatal("bad input format"); ! 332: } ! 333: return(head); ! 334: } ! 335: ! 336: /* ! 337: * read a list of (comma-separated) states, set them in the ! 338: * given transition. ! 339: * ! 340: */ ! 341: VOID ! 342: statelist(fp,t) FILE *fp; trans t; { ! 343: int curtok,sval; ! 344: curtok = COMMA; ! 345: while (curtok != RBRACK) { ! 346: if (curtok != COMMA) fatal("missing comma"); ! 347: if ((curtok = gettoken(fp)) != WORD) fatal("missing state name"); ! 348: if ((sval = lkup(tokval)) == -1) { ! 349: fprintf(stderr,"state %s undefined\n",tokval); ! 350: fatal("undefined state"); ! 351: } ! 352: setwstate(sval,t); ! 353: curtok = gettoken(fp); ! 354: } ! 355: } ! 356: ! 357: /* ! 358: * copy an action from the input to the output file ! 359: * ! 360: */ ! 361: VOID ! 362: copyact(inp,outp,actno) FILE *inp,*outp; int actno; { ! 363: int c,bcnt; ! 364: fprintf(outp,"case %d:\n",actno); ! 365: while (c = getc(inp), (isspace(c) || c == C_L)) ! 366: if (c == '\n') lines++; ! 367: if (c == '{') { ! 368: bcnt = 1; ! 369: fputs(" {",outp); ! 370: while (bcnt > 0 && (c = getc(inp)) != EOF) { ! 371: if (c == '{') bcnt++; ! 372: else if (c == '}') bcnt--; ! 373: else if (c == '\n') lines++; ! 374: putc(c,outp); ! 375: } ! 376: if (bcnt > 0) fatal("action doesn't end"); ! 377: } else { ! 378: while (c != '\n' && c != EOF) { ! 379: putc(c,outp); ! 380: c = getc(inp); ! 381: } ! 382: lines++; ! 383: } ! 384: fprintf(outp,"\n break;\n"); ! 385: } ! 386: ! 387: /* ! 388: * find the action associated with a given character and state. ! 389: * returns -1 if one can't be found. ! 390: * ! 391: */ ! 392: int ! 393: faction(hd,state,chr) trans hd; int state,chr; { ! 394: while (hd != NULL) { ! 395: if (hd->anyst || teststate(state,hd)) ! 396: if (hd->inchr == ('.' - 32) || hd->inchr == (char) chr) ! 397: return(hd->actno); ! 398: hd = hd->nxt; ! 399: } ! 400: return(-1); ! 401: } ! 402: ! 403: /* ! 404: * empty the table... ! 405: * ! 406: */ ! 407: VOID ! 408: emptytbl() { ! 409: int i; ! 410: for (i=0; i<nstates*96; i++) tbl[i] = -1; ! 411: } ! 412: ! 413: /* ! 414: * add the specified action to the output for the given state and chr. ! 415: * ! 416: */ ! 417: VOID ! 418: addaction(act,state,chr) int act,state,chr; { ! 419: tbl[state*96 + chr] = act; ! 420: } ! 421: ! 422: VOID ! 423: writetbl(fp) FILE *fp; { ! 424: warray(fp,"tbl",tbl,96*(nstates+1),TBL_TYPE); ! 425: } ! 426: ! 427: ! 428: /* ! 429: * write an array to the output file, given its name and size. ! 430: * ! 431: */ ! 432: VOID ! 433: warray(fp,nam,cont,siz,typ) FILE *fp; char *nam; int cont[],siz; char *typ; { ! 434: int i; ! 435: fprintf(fp,"%s %s[] = {\n",typ,nam); ! 436: for (i = 0; i < siz - 1; ) { ! 437: fprintf(fp,"%2d, ",cont[i]); ! 438: if ((++i % 16) == 0) putc('\n',fp); ! 439: } ! 440: fprintf(fp,"%2d ",cont[siz-1]); ! 441: fprintf(fp,"};\n"); ! 442: } ! 443: ! 444: VOID ! 445: main(argc,argv) int argc; char *argv[]; { ! 446: trans head; ! 447: int state,c; ! 448: FILE *infile,*outfile; ! 449: ! 450: if (argc > 1) { ! 451: if ((infile = fopen(argv[1],"r")) == NULL) { ! 452: fprintf(stderr,"Can't open %s\n",argv[1]); ! 453: fatal("unreadable input file"); ! 454: } ! 455: } else infile = stdin; ! 456: ! 457: if (argc > 2) { ! 458: if ((outfile = fopen(argv[2],"w")) == NULL) { ! 459: fprintf(stderr,"Can't write to %s\n",argv[2]); ! 460: fatal("bad output file"); ! 461: } ! 462: } else outfile = stdout; ! 463: ! 464: clrhash(); /* empty hash table */ ! 465: head = rdinput(infile,outfile); /* read input file */ ! 466: emptytbl(); /* empty our tables */ ! 467: for (state = 0; state <= nstates; state++) ! 468: for (c = 1; c < 96; c++) /* find actions, */ ! 469: addaction(faction(head,state,c),state,c); /* add to tbl */ ! 470: writetbl(outfile); ! 471: copyrest(infile,outfile); ! 472: printf("%d states, %d actions\n",nstates,nacts); ! 473: exit(GOOD_EXIT); ! 474: } ! 475: ! 476: ! 477: /* ! 478: * fatal error handler ! 479: * ! 480: */ ! 481: ! 482: VOID ! 483: fatal(msg) char *msg; { ! 484: fprintf(stderr,"error in line %d: %s\n",lines,msg); ! 485: exit(BAD_EXIT); ! 486: } ! 487: ! 488: VOID ! 489: prolog(outfp) FILE *outfp; { ! 490: int c; ! 491: while ((c = *txt1++) != '\0') putc(c,outfp); ! 492: while ((c = *fname++) != '\0') putc(c,outfp); ! 493: while ((c = *txt2++) != '\0') putc(c,outfp); ! 494: while ((c = *tbl_type++) != '\0') putc(c,outfp); ! 495: while ((c = *txt2a++) != '\0') putc(c,outfp); ! 496: while ((c = *txt2b++) != '\0') putc(c,outfp); ! 497: } ! 498: ! 499: VOID ! 500: epilogue(outfp) FILE *outfp; { ! 501: int c; ! 502: while ((c = *txt3++) != '\0') putc(c,outfp); ! 503: } ! 504: ! 505: VOID ! 506: copyrest(in,out) FILE *in,*out; { ! 507: int c; ! 508: while ((c = getc(in)) != EOF) putc(c,out); ! 509: } ! 510: ! 511: /* ! 512: * gettoken - returns token type of next token, sets tokval ! 513: * to the string value of the token if appropriate. ! 514: * ! 515: */ ! 516: ! 517: int ! 518: gettoken(fp) FILE *fp; { ! 519: int c; ! 520: while (1) { /* loop if reading comments... */ ! 521: do { ! 522: c = getc(fp); ! 523: if (c == '\n') lines++; ! 524: } while ((isspace(c) || c == C_L)); /* skip whitespace */ ! 525: switch(c) { ! 526: case EOF: ! 527: return(SEP); ! 528: case '%': ! 529: if ((c = getc(fp)) == '%') return(SEP); ! 530: tokval[0] = '%'; ! 531: tokval[1] = (char) c; ! 532: rdword(fp,tokval+2); ! 533: return(WORD); ! 534: case '<': ! 535: return(LBRACK); ! 536: case '>': ! 537: return(RBRACK); ! 538: case ',': ! 539: return(COMMA); ! 540: case '/': ! 541: if ((c = getc(fp)) == '*') { ! 542: rdcmnt(fp); /* skip over the comment */ ! 543: continue; ! 544: } else { /* and keep looping */ ! 545: ungetc(c,fp); /* put this back into input */ ! 546: c = '/'; /* put character back, fall thru */ ! 547: } ! 548: ! 549: default: ! 550: if (isword(c)) { ! 551: ungetc(c,fp); ! 552: rdword(fp,tokval); ! 553: return(WORD); ! 554: } else fatal("Invalid character in input"); ! 555: } ! 556: } ! 557: } ! 558: ! 559: /* ! 560: * skip over a comment ! 561: * ! 562: */ ! 563: ! 564: VOID ! 565: rdcmnt(fp) FILE *fp; { ! 566: int c,star,prcnt; ! 567: prcnt = star = 0; /* no star seen yet */ ! 568: while (!((c = getc(fp)) == '/' && star)) { ! 569: if (c == EOF || (prcnt && c == '%')) fatal("Unterminated comment"); ! 570: prcnt = (c == '%'); ! 571: star = (c == '*'); ! 572: if (c == '\n') lines++; ! 573: } ! 574: } ! 575: ! 576: /* ! 577: * symbol table management for wart ! 578: * ! 579: * entry points: ! 580: * clrhash - empty hash table. ! 581: * enter - enter a name into the symbol table ! 582: * lkup - find a name's value in the symbol table. ! 583: * ! 584: */ ! 585: ! 586: #define HASHSIZE 101 /* # of entries in hash table */ ! 587: ! 588: struct sym { ! 589: char *name; /* symbol name */ ! 590: int val; /* value */ ! 591: struct sym *hnxt; /* next on collision chain */ ! 592: } *htab[HASHSIZE]; /* the hash table */ ! 593: ! 594: /* ! 595: * empty the hash table before using it... ! 596: * ! 597: */ ! 598: VOID ! 599: clrhash() { ! 600: int i; ! 601: for (i=0; i<HASHSIZE; i++) htab[i] = NULL; ! 602: } ! 603: ! 604: /* ! 605: * compute the value of the hash for a symbol ! 606: * ! 607: */ ! 608: int ! 609: hash(name) char *name; { ! 610: int sum; ! 611: for (sum = 0; *name != '\0'; name++) sum += (sum + *name); ! 612: sum %= HASHSIZE; /* take sum mod hashsize */ ! 613: if (sum < 0) sum += HASHSIZE; /* disallow negative hash value */ ! 614: return(sum); ! 615: } ! 616: ! 617: /* ! 618: * make a private copy of a string... ! 619: * ! 620: */ ! 621: static char* ! 622: copy(s) char *s; { ! 623: char *new; ! 624: new = (char *) malloc((int)strlen(s) + 1); ! 625: strcpy(new,s); ! 626: return(new); ! 627: } ! 628: ! 629: /* ! 630: * enter state name into the hash table ! 631: * ! 632: */ ! 633: VOID ! 634: enter(name,svalue) char *name; int svalue; { ! 635: int h; ! 636: struct sym *cur; ! 637: if (lkup(name) != -1) { ! 638: fprintf(stderr,"state \"%s\" appears twice...\n", name); ! 639: exit(BAD_EXIT); ! 640: } ! 641: h = hash(name); ! 642: cur = (struct sym *)malloc(sizeof (struct sym)); ! 643: cur->name = copy(name); ! 644: cur->val = svalue; ! 645: cur->hnxt = htab[h]; ! 646: htab[h] = cur; ! 647: } ! 648: ! 649: /* ! 650: * find name in the symbol table, return its value. Returns -1 ! 651: * if not found. ! 652: * ! 653: */ ! 654: int ! 655: lkup(name) char *name; { ! 656: struct sym *cur; ! 657: for (cur = htab[hash(name)]; cur != NULL; cur = cur->hnxt) ! 658: if (strcmp(cur->name,name) == 0) return(cur->val); ! 659: return(-1); ! 660: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.