|
|
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.