source: trunk/third/kermit/ckwart.c @ 10780

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