|
|
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, Trustees of Columbia University in the City of New
32: York. Permission is granted to any individual or institution to use this
33: software as long as it is not sold for profit. This copyright notice must be
34: retained. This software may not be included in commercial products without
35: written permission of Columbia University.
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, "char" 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: /* lt 1992-10-08 Begin
124: * provide definition for deblog variable
125: * ckcdeb.h declares as extern. DECC AXP is strict about ref/def model
126: * Variable is unused herein, to the best of my knowledge.
127: */
128: #ifdef VMS
129: int deblog;
130: #endif /* VMS */
131: /* lt 1992-10-08 End
132: */
133:
134: static int lines, nstates, nacts;
135:
136: static char tokval[MAXWORD];
137:
138: static int tbl[MAXSTATES*96];
139:
140: char *tbl_type = TBL_TYPE;
141:
142: char *txt1 = "\n#define BEGIN state =\n\nint state = 0;\n\nint\n";
143:
144: char *fname = FNAME; /* Generated function name goes here */
145:
146: /* rest of program... */
147:
148: char *txt2 = "()\n\
149: {\n\
150: int c,actno;\n\
151: extern ";
152:
153: /* Data type of state table is inserted here (short or int) */
154:
155: char *txt2a = " tbl[];\n while (1) {\n c = input() - 32;\n\
156: if (c < 0 || c > 95) c = 0;\n";
157:
158: char *txt2b = " if ((actno = tbl[c + state*96]) != -1)\n\
159: switch(actno) {\n";
160:
161: /* this program's output goes here, followed by final text... */
162:
163: char *txt3 = "\n }\n }\n}\n\n";
164:
165:
166: /*
167: * turn on the bit associated with the given state
168: *
169: */
170: VOID
171: setwstate(state,t) int state; trans t; {
172: int idx,msk;
173: idx = state/8; /* byte associated with state */
174: msk = 0x80 >> (state % 8); /* bit mask for state */
175: t->states[idx] |= msk;
176: }
177:
178: /*
179: * see if the state is involved in the transition
180: *
181: */
182: int
183: teststate(state,t) int state; trans t; {
184: int idx,msk;
185: idx = state/8;
186: msk = 0x80 >> (state % 8);
187: return(t->states[idx] & msk);
188: }
189:
190:
191: /*
192: * read input from here...
193: *
194: */
195:
196: trans
197: rdinput(infp,outfp) FILE *infp,*outfp; {
198: trans x,rdrules();
199: lines = 1; /* line counter */
200: nstates = 0; /* no states */
201: nacts = 0; /* no actions yet */
202: fprintf(outfp,"\n%c* WARNING -- This C source program generated by ",'/');
203: fprintf(outfp,"Wart preprocessor. */\n");
204: fprintf(outfp,"%c* Do not edit this file; edit the Wart-format ",'/');
205: fprintf(outfp,"source file instead, */\n");
206: fprintf(outfp,"%c* and then run it through Wart to produce a new ",'/');
207: fprintf(outfp,"C source file. */\n\n");
208: fprintf(outfp,"%c* Wart Version Info: */\n",'/');
209: fprintf(outfp,"char *wartv = \"%s\";\n\n",wartv);
210:
211: initial(infp,outfp); /* read state names, initial defs */
212: prolog(outfp); /* write out our initial code */
213: x = rdrules(infp,outfp); /* read rules */
214: epilogue(outfp); /* write out epilogue code */
215: return(x);
216: }
217:
218:
219: /*
220: * initial - read initial definitions and state names. Returns
221: * on EOF or %%.
222: *
223: */
224: VOID
225: initial(infp,outfp) FILE *infp, *outfp; {
226: int c;
227: char wordbuf[MAXWORD];
228: while ((c = getc(infp)) != EOF) {
229: if (c == '%') {
230: rdword(infp,wordbuf);
231: if (strcmp(wordbuf,"states") == 0)
232: rdstates(infp,outfp);
233: else if (strcmp(wordbuf,"%") == 0) return;
234: else fprintf(outfp,"%%%s",wordbuf);
235: }
236: else putc(c,outfp);
237: if (c == '\n') lines++;
238: }
239: }
240:
241: /*
242: * boolean function to tell if the given character can be part of
243: * a word.
244: *
245: */
246: int
247: isin(s,c) char *s; int c; {
248: for (; *s != '\0'; s++)
249: if (*s == (char) c) return(1);
250: return(0);
251: }
252: int
253: isword(c) int c; {
254: static char special[] = ".%_-$@"; /* these are allowable */
255: return(isalnum(c) || isin(special,c));
256: }
257:
258: /*
259: * read the next word into the given buffer.
260: *
261: */
262: VOID
263: rdword(fp,buf) FILE *fp; char *buf; {
264: int len = 0,c;
265: while (isword(c = getc(fp)) && ++len < MAXWORD) *buf++ = (char) c;
266: *buf++ = '\0'; /* tie off word */
267: ungetc(c,fp); /* put break char back */
268: }
269:
270: /*
271: * read state names, up to a newline.
272: *
273: */
274: VOID
275: rdstates(fp,ofp) FILE *fp,*ofp; {
276: int c;
277: char wordbuf[MAXWORD];
278: while ((c = getc(fp)) != EOF && c != '\n') {
279: if (isspace(c) || c == C_L) continue; /* skip whitespace */
280: ungetc(c,fp); /* put char back */
281: rdword(fp,wordbuf); /* read the whole word */
282: enter(wordbuf,++nstates); /* put into symbol tbl */
283: fprintf(ofp,"#define %s %d\n",wordbuf,nstates);
284: }
285: lines++;
286: }
287:
288: /*
289: * allocate a new, empty transition node
290: *
291: */
292: trans
293: newtrans() {
294: trans new;
295: int i;
296: new = (trans) malloc(sizeof (struct transx));
297: for (i=0; i<SBYTES; i++) new->states[i] = 0;
298: new->anyst = 0;
299: new->nxt = NULL;
300: return(new);
301: }
302:
303:
304: /*
305: * read all the rules.
306: *
307: */
308:
309: trans
310: rdrules(fp,out) FILE *fp,*out; {
311: trans head,cur,prev;
312: int curtok;
313: head = cur = prev = NULL;
314: while ((curtok = gettoken(fp)) != SEP)
315:
316: switch(curtok) {
317: case LBRACK:
318: if (cur == NULL)
319: cur = newtrans();
320: else
321: fatal("duplicate state list");
322: statelist(fp,cur); /* set states */
323: continue; /* prepare to read char */
324:
325: case WORD:
326: if ((int)strlen(tokval) != 1)
327: fatal("multiple chars in state");
328: if (cur == NULL) {
329: cur = newtrans();
330: cur->anyst = 1;
331: }
332: cur->actno = ++nacts;
333: cur->inchr = (char) (tokval[0] - 32);
334: if (head == NULL)
335: head = cur;
336: else
337: prev->nxt = cur;
338: prev = cur;
339: cur = NULL;
340: copyact(fp,out,nacts);
341: break;
342: default: fatal("bad input format");
343: }
344: return(head);
345: }
346:
347: /*
348: * read a list of (comma-separated) states, set them in the
349: * given transition.
350: *
351: */
352: VOID
353: statelist(fp,t) FILE *fp; trans t; {
354: int curtok,sval;
355: curtok = COMMA;
356: while (curtok != RBRACK) {
357: if (curtok != COMMA) fatal("missing comma");
358: if ((curtok = gettoken(fp)) != WORD) fatal("missing state name");
359: if ((sval = lkup(tokval)) == -1) {
360: fprintf(stderr,"state %s undefined\n",tokval);
361: fatal("undefined state");
362: }
363: setwstate(sval,t);
364: curtok = gettoken(fp);
365: }
366: }
367:
368: /*
369: * copy an action from the input to the output file
370: *
371: */
372: VOID
373: copyact(inp,outp,actno) FILE *inp,*outp; int actno; {
374: int c,bcnt;
375: fprintf(outp,"case %d:\n",actno);
376: while (c = getc(inp), (isspace(c) || c == C_L))
377: if (c == '\n') lines++;
378: if (c == '{') {
379: bcnt = 1;
380: fputs(" {",outp);
381: while (bcnt > 0 && (c = getc(inp)) != EOF) {
382: if (c == '{') bcnt++;
383: else if (c == '}') bcnt--;
384: else if (c == '\n') lines++;
385: putc(c,outp);
386: }
387: if (bcnt > 0) fatal("action doesn't end");
388: } else {
389: while (c != '\n' && c != EOF) {
390: putc(c,outp);
391: c = getc(inp);
392: }
393: lines++;
394: }
395: fprintf(outp,"\n break;\n");
396: }
397:
398: /*
399: * find the action associated with a given character and state.
400: * returns -1 if one can't be found.
401: *
402: */
403: int
404: faction(hd,state,chr) trans hd; int state,chr; {
405: while (hd != NULL) {
406: if (hd->anyst || teststate(state,hd))
407: if (hd->inchr == ('.' - 32) || hd->inchr == (char) chr)
408: return(hd->actno);
409: hd = hd->nxt;
410: }
411: return(-1);
412: }
413:
414: /*
415: * empty the table...
416: *
417: */
418: VOID
419: emptytbl() {
420: int i;
421: for (i=0; i<nstates*96; i++) tbl[i] = -1;
422: }
423:
424: /*
425: * add the specified action to the output for the given state and chr.
426: *
427: */
428: VOID
429: addaction(act,state,chr) int act,state,chr; {
430: tbl[state*96 + chr] = act;
431: }
432:
433: VOID
434: writetbl(fp) FILE *fp; {
435: warray(fp,"tbl",tbl,96*(nstates+1),TBL_TYPE);
436: }
437:
438:
439: /*
440: * write an array to the output file, given its name and size.
441: *
442: */
443: VOID
444: warray(fp,nam,cont,siz,typ) FILE *fp; char *nam; int cont[],siz; char *typ; {
445: int i;
446: fprintf(fp,"%s %s[] = {\n",typ,nam);
447: for (i = 0; i < siz - 1; ) {
448: fprintf(fp,"%2d, ",cont[i]);
449: if ((++i % 16) == 0) putc('\n',fp);
450: }
451: fprintf(fp,"%2d ",cont[siz-1]);
452: fprintf(fp,"};\n");
453: }
454:
455: VOID
456: main(argc,argv) int argc; char *argv[]; {
457: trans head;
458: int state,c;
459: FILE *infile,*outfile;
460:
461: if (argc > 1) {
462: if ((infile = fopen(argv[1],"r")) == NULL) {
463: fprintf(stderr,"Can't open %s\n",argv[1]);
464: fatal("unreadable input file");
465: }
466: } else infile = stdin;
467:
468: if (argc > 2) {
469: if ((outfile = fopen(argv[2],"w")) == NULL) {
470: fprintf(stderr,"Can't write to %s\n",argv[2]);
471: fatal("bad output file");
472: }
473: } else outfile = stdout;
474:
475: clrhash(); /* empty hash table */
476: head = rdinput(infile,outfile); /* read input file */
477: emptytbl(); /* empty our tables */
478: for (state = 0; state <= nstates; state++)
479: for (c = 1; c < 96; c++) /* find actions, */
480: addaction(faction(head,state,c),state,c); /* add to tbl */
481: writetbl(outfile);
482: copyrest(infile,outfile);
483: printf("%d states, %d actions\n",nstates,nacts);
484: exit(GOOD_EXIT);
485: }
486:
487:
488: /*
489: * fatal error handler
490: *
491: */
492:
493: VOID
494: fatal(msg) char *msg; {
495: fprintf(stderr,"error in line %d: %s\n",lines,msg);
496: exit(BAD_EXIT);
497: }
498:
499: VOID
500: prolog(outfp) FILE *outfp; {
501: int c;
502: while ((c = *txt1++) != '\0') putc(c,outfp);
503: while ((c = *fname++) != '\0') putc(c,outfp);
504: while ((c = *txt2++) != '\0') putc(c,outfp);
505: while ((c = *tbl_type++) != '\0') putc(c,outfp);
506: while ((c = *txt2a++) != '\0') putc(c,outfp);
507: while ((c = *txt2b++) != '\0') putc(c,outfp);
508: }
509:
510: VOID
511: epilogue(outfp) FILE *outfp; {
512: int c;
513: while ((c = *txt3++) != '\0') putc(c,outfp);
514: }
515:
516: VOID
517: copyrest(in,out) FILE *in,*out; {
518: int c;
519: while ((c = getc(in)) != EOF) putc(c,out);
520: }
521:
522: /*
523: * gettoken - returns token type of next token, sets tokval
524: * to the string value of the token if appropriate.
525: *
526: */
527:
528: int
529: gettoken(fp) FILE *fp; {
530: int c;
531: while (1) { /* loop if reading comments... */
532: do {
533: c = getc(fp);
534: if (c == '\n') lines++;
535: } while ((isspace(c) || c == C_L)); /* skip whitespace */
536: switch(c) {
537: case EOF:
538: return(SEP);
539: case '%':
540: if ((c = getc(fp)) == '%') return(SEP);
541: tokval[0] = '%';
542: tokval[1] = (char) c;
543: rdword(fp,tokval+2);
544: return(WORD);
545: case '<':
546: return(LBRACK);
547: case '>':
548: return(RBRACK);
549: case ',':
550: return(COMMA);
551: case '/':
552: if ((c = getc(fp)) == '*') {
553: rdcmnt(fp); /* skip over the comment */
554: continue;
555: } else { /* and keep looping */
556: ungetc(c,fp); /* put this back into input */
557: c = '/'; /* put character back, fall thru */
558: }
559:
560: default:
561: if (isword(c)) {
562: ungetc(c,fp);
563: rdword(fp,tokval);
564: return(WORD);
565: } else fatal("Invalid character in input");
566: }
567: }
568: }
569:
570: /*
571: * skip over a comment
572: *
573: */
574:
575: VOID
576: rdcmnt(fp) FILE *fp; {
577: int c,star,prcnt;
578: prcnt = star = 0; /* no star seen yet */
579: while (!((c = getc(fp)) == '/' && star)) {
580: if (c == EOF || (prcnt && c == '%')) fatal("Unterminated comment");
581: prcnt = (c == '%');
582: star = (c == '*');
583: if (c == '\n') lines++;
584: }
585: }
586:
587: /*
588: * symbol table management for wart
589: *
590: * entry points:
591: * clrhash - empty hash table.
592: * enter - enter a name into the symbol table
593: * lkup - find a name's value in the symbol table.
594: *
595: */
596:
597: #define HASHSIZE 101 /* # of entries in hash table */
598:
599: struct sym {
600: char *name; /* symbol name */
601: int val; /* value */
602: struct sym *hnxt; /* next on collision chain */
603: } *htab[HASHSIZE]; /* the hash table */
604:
605: /*
606: * empty the hash table before using it...
607: *
608: */
609: VOID
610: clrhash() {
611: int i;
612: for (i=0; i<HASHSIZE; i++) htab[i] = NULL;
613: }
614:
615: /*
616: * compute the value of the hash for a symbol
617: *
618: */
619: int
620: hash(name) char *name; {
621: int sum;
622: for (sum = 0; *name != '\0'; name++) sum += (sum + *name);
623: sum %= HASHSIZE; /* take sum mod hashsize */
624: if (sum < 0) sum += HASHSIZE; /* disallow negative hash value */
625: return(sum);
626: }
627:
628: /*
629: * make a private copy of a string...
630: *
631: */
632: static char*
633: copy(s) char *s; {
634: char *new;
635: new = (char *) malloc((int)strlen(s) + 1);
636: strcpy(new,s);
637: return(new);
638: }
639:
640: /*
641: * enter state name into the hash table
642: *
643: */
644: VOID
645: enter(name,svalue) char *name; int svalue; {
646: int h;
647: struct sym *cur;
648: if (lkup(name) != -1) {
649: fprintf(stderr,"state \"%s\" appears twice...\n", name);
650: exit(BAD_EXIT);
651: }
652: h = hash(name);
653: cur = (struct sym *)malloc(sizeof (struct sym));
654: cur->name = copy(name);
655: cur->val = svalue;
656: cur->hnxt = htab[h];
657: htab[h] = cur;
658: }
659:
660: /*
661: * find name in the symbol table, return its value. Returns -1
662: * if not found.
663: *
664: */
665: int
666: lkup(name) char *name; {
667: struct sym *cur;
668: for (cur = htab[hash(name)]; cur != NULL; cur = cur->hnxt)
669: if (strcmp(cur->name,name) == 0) return(cur->val);
670: return(-1);
671: }
672:
673:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.