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

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