📄 gwart.c
字号:
/* G W A R T -- GNU version of Wart A small subset of "lex" sufficient for converting the Kermit protocol state table from lex notation to C. Authors: Jeff Damens, Frank da Cruz The Kermit Project, Columbia University http://www.columbia.edu/kermit/ kermit@columbia.edu Copyright (C) 1984, 1999, The Trustees of Columbia University in the City of New York. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*//* * input format is: * lines to be copied | %state <state names...> * %% * <state> | <state,state,...> CHAR { actions } * ... * %% * more lines to be copied */#include <stdio.h>#include <ctype.h>#include "gkermit.h"#define TBL_TYPE "short" /* C data type of state table */#define C_L 014 /* Formfeed */#define SEP 1 /* Token types */#define LBRACK 2#define RBRACK 3#define WORD 4#define COMMA 5/* Storage sizes */#define MAXSTATES 50 /* max number of states */#define MAXWORD 50 /* max # of chars/word */#define SBYTES ((MAXSTATES+6)/8) /* # of bytes for state bitmask *//* Name of gwart function in generated program */#ifndef FNAME#define FNAME "gwart"#endif /* FNAME *//* Structure for state information */struct transx { CHAR states[SBYTES]; /* included states */ int anyst; /* true if this good from any state */ CHAR inchr; /* input character */ int actno; /* associated action */ struct transx *nxt;}; /* next transition */typedef struct transx *trans;/* Function prototypes */_MYPROTOTYPE( VOID fatal, (char *) );_MYPROTOTYPE( VOID setwstate, (int, trans) );_MYPROTOTYPE( int teststate, (int, trans) );_MYPROTOTYPE( trans rdinput, (FILE *, FILE *) );_MYPROTOTYPE( VOID initial, (FILE *, FILE *) );_MYPROTOTYPE( int isin, (char *, int) );_MYPROTOTYPE( int isword, (int) );_MYPROTOTYPE( VOID rdword, (FILE *, char *) );_MYPROTOTYPE( VOID rdstates, (FILE *, FILE *) );_MYPROTOTYPE( trans newtrans, (void) );_MYPROTOTYPE( trans rdrules, (FILE *, FILE *) );_MYPROTOTYPE( VOID statelist, (FILE *, trans) );_MYPROTOTYPE( VOID copyact, (FILE *, FILE *, int) );_MYPROTOTYPE( int faction, (trans, int, int) );_MYPROTOTYPE( VOID emptytbl, (void) );_MYPROTOTYPE( VOID addaction, (int, int, int) );_MYPROTOTYPE( VOID writetbl, (FILE *) );_MYPROTOTYPE( VOID warray, (FILE *, char *, int [], int, char *) );_MYPROTOTYPE( VOID prolog, (FILE *) );_MYPROTOTYPE( VOID epilogue, (FILE *) );_MYPROTOTYPE( VOID copyrest, (FILE *, FILE *) );_MYPROTOTYPE( int gettoken, (FILE *) );_MYPROTOTYPE( VOID rdcmnt, (FILE *) );_MYPROTOTYPE( VOID clrhash, (void) );_MYPROTOTYPE( int hash, (char *) );_MYPROTOTYPE( VOID enter, (char *, int) );_MYPROTOTYPE( int lkup, (char *) );_MYPROTOTYPE( static char* copy, (char *s) );/* Variables and tables */int lines, nstates, nacts;int tbl[MAXSTATES*96];char tokval[MAXWORD];char *tbl_type = TBL_TYPE;char *txt1 = "\n#define BEGIN state =\n\nint state = 0;\n\nint\n";char *fname = FNAME; /* Generated function name goes here *//* Rest of program... */char *txt2 = "()\n\{\n\ int c,actno;\n\ extern ";/* Data type of state table is inserted here (short or int) */char *txt2a =" tbl[];\n\ while (1) {\n\ c = input() - 32;\n\ if (c < 0 || c > 95) c = 0;\n";char *txt2b = " if ((actno = tbl[c + state*96]) != -1)\n\ switch(actno) {\n";/* this program's output goes here, followed by final text... */char *txt3 = "\n }\n }\n}\n\n";/* * turn on the bit associated with the given state * */VOIDsetwstate(state,t) int state; trans t; { int idx,msk; idx = state/8; /* byte associated with state */ msk = 0x80 >> (state % 8); /* bit mask for state */ t->states[idx] |= msk;}/* * see if the state is involved in the transition * */intteststate(state,t) int state; trans t; { int idx,msk; idx = state/8; msk = 0x80 >> (state % 8); return(t->states[idx] & msk);}/* * read input from here... * */transrdinput(infp,outfp) FILE *infp, *outfp; { trans x; lines = 1; /* line counter */ nstates = 0; /* no states */ nacts = 0; /* no actions yet */ fprintf(outfp,"\n%c* WARNING -- This C source program generated by ",'/'); fprintf(outfp,"gwart preprocessor. */\n"); fprintf(outfp,"%c* Do not edit this file; edit the gwart-format ",'/'); fprintf(outfp,"source file instead, */\n"); fprintf(outfp,"%c* and then run it through gwart to produce a new ",'/'); fprintf(outfp,"C source file. */\n\n"); initial(infp,outfp); /* read state names, initial defs */ prolog(outfp); /* write out our initial code */ x = rdrules(infp,outfp); /* read rules */ epilogue(outfp); /* write out epilogue code */ return(x);}/* * initial - read initial definitions and state names. Returns * on EOF or %%. * */VOIDinitial(infp,outfp) FILE *infp, *outfp; { int c; char wordbuf[MAXWORD]; while ((c = getc(infp)) != EOF) { if (c == '%') { rdword(infp,wordbuf); if (strcmp(wordbuf,"states") == 0) rdstates(infp,outfp); else if (strcmp(wordbuf,"%") == 0) return; else fprintf(outfp,"%%%s",wordbuf); } else putc(c,outfp); if (c == '\n') lines++; }}/* * boolean function to tell if the given character can be part of * a word. * */intisin(s,c) char *s; int c; { for (; *s != '\0'; s++) if (*s == (char) c) return(1); return(0);}intisword(c) int c; { static char special[] = ".%_-$@"; /* these are allowable */ return(isalnum(c) || isin(special,c));}/* * read the next word into the given buffer. * */VOIDrdword(fp,buf) FILE *fp; char *buf; { int len = 0,c; while (isword(c = getc(fp)) && ++len < MAXWORD) *buf++ = (char) c; *buf++ = '\0'; /* tie off word */ ungetc(c,fp); /* put break char back */}/* * read state names, up to a newline. * */VOIDrdstates(fp,ofp) FILE *fp,*ofp; { int c; char wordbuf[MAXWORD]; while ((c = getc(fp)) != EOF && c != '\n') { if (isspace(c) || c == C_L) continue; /* skip whitespace */ ungetc(c,fp); /* put char back */ rdword(fp,wordbuf); /* read the whole word */ enter(wordbuf,++nstates); /* put into symbol tbl */ fprintf(ofp,"#define %s %d\n",wordbuf,nstates); } lines++;}/* * allocate a new, empty transition node * */transnewtrans() { trans new; int i; new = (trans) malloc(sizeof (struct transx)); for (i=0; i<SBYTES; i++) new->states[i] = 0; new->anyst = 0; new->nxt = NULL; return(new);}/* * read all the rules. * */transrdrules(fp,out) FILE *fp,*out; { trans head,cur,prev; int curtok; head = cur = prev = NULL; while ((curtok = gettoken(fp)) != SEP) switch(curtok) { case LBRACK: if (cur == NULL) cur = newtrans(); else fatal("duplicate state list"); statelist(fp,cur); /* set states */ continue; /* prepare to read char */ case WORD: if ((int)strlen(tokval) != 1) fatal("multiple chars in state"); if (cur == NULL) { cur = newtrans(); cur->anyst = 1; } cur->actno = ++nacts; cur->inchr = (char) (tokval[0] - 32); if (head == NULL) head = cur; else prev->nxt = cur; prev = cur; cur = NULL; copyact(fp,out,nacts); break; default: fatal("bad input format"); } return(head);}/* * read a list of (comma-separated) states, set them in the * given transition. * */VOIDstatelist(fp,t) FILE *fp; trans t; { int curtok,sval; curtok = COMMA; while (curtok != RBRACK) { if (curtok != COMMA) fatal("missing comma"); if ((curtok = gettoken(fp)) != WORD) fatal("missing state name"); if ((sval = lkup(tokval)) == -1) { fprintf(stderr,"state %s undefined\n",tokval); fatal("undefined state"); } setwstate(sval,t); curtok = gettoken(fp); }}/* * copy an action from the input to the output file * */VOIDcopyact(inp,outp,actno) FILE *inp,*outp; int actno; { int c,bcnt; fprintf(outp,"case %d:\n",actno); while (c = getc(inp), (isspace(c) || c == C_L)) if (c == '\n') lines++; if (c == '{') { bcnt = 1; fputs(" {",outp); while (bcnt > 0 && (c = getc(inp)) != EOF) { if (c == '{') bcnt++; else if (c == '}') bcnt--; else if (c == '\n') lines++; putc(c,outp); } if (bcnt > 0) fatal("action doesn't end"); } else { while (c != '\n' && c != EOF) { putc(c,outp); c = getc(inp); } lines++; } fprintf(outp,"\n break;\n");}/* * find the action associated with a given character and state. * returns -1 if one can't be found. * */intfaction(hd,state,chr) trans hd; int state,chr; { while (hd != NULL) { if (hd->anyst || teststate(state,hd)) if (hd->inchr == ('.' - 32) || hd->inchr == (char) chr) return(hd->actno); hd = hd->nxt; } return(-1);}/* * empty the table... * */VOIDemptytbl() { int i; for (i=0; i<nstates*96; i++) tbl[i] = -1;}/* * add the specified action to the output for the given state and chr. * */VOIDaddaction(act,state,chr) int act,state,chr; { tbl[state*96 + chr] = act;}VOIDwritetbl(fp) FILE *fp; { warray(fp,"tbl",tbl,96*(nstates+1),TBL_TYPE);}/* * write an array to the output file, given its name and size. * */VOIDwarray(fp,nam,cont,siz,typ) FILE *fp; char *nam; int cont[],siz; char *typ; { int i; fprintf(fp,"%s %s[] = {\n",typ,nam); for (i = 0; i < siz - 1; ) { fprintf(fp," %2d,",cont[i]); if ((++i % 16) == 0) putc('\n',fp); } fprintf(fp,"%2d\n};\n",cont[siz-1]);}intmain(argc,argv) int argc; char **argv; { trans head; int state,c; FILE *infile,*outfile; if (argc > 1) { if ((infile = fopen(argv[1],"r")) == NULL) { fprintf(stderr,"Can't open %s\n",argv[1]); fatal("unreadable input file"); } } else infile = stdin; if (argc > 2) { if ((outfile = fopen(argv[2],"w")) == NULL) { fprintf(stderr,"Can't write to %s\n",argv[2]); fatal("bad output file"); } } else outfile = stdout; clrhash(); /* empty hash table */ head = rdinput(infile,outfile); /* read input file */ emptytbl(); /* empty our tables */ for (state = 0; state <= nstates; state++) for (c = 1; c < 96; c++) /* find actions, */ addaction(faction(head,state,c),state,c); /* add to tbl */ writetbl(outfile); copyrest(infile,outfile); printf("%d states, %d actions\n",nstates,nacts); exit(0);}/* * fatal error handler * */VOIDfatal(msg) char *msg; { fprintf(stderr,"error in line %d: %s\n",lines,msg); exit(1);}VOIDprolog(outfp) FILE *outfp; { int c; while ((c = *txt1++) != '\0') putc(c,outfp); while ((c = *fname++) != '\0') putc(c,outfp); while ((c = *txt2++) != '\0') putc(c,outfp); while ((c = *tbl_type++) != '\0') putc(c,outfp); while ((c = *txt2a++) != '\0') putc(c,outfp); while ((c = *txt2b++) != '\0') putc(c,outfp);}VOIDepilogue(outfp) FILE *outfp; { int c; while ((c = *txt3++) != '\0') putc(c,outfp);}VOIDcopyrest(in,out) FILE *in,*out; { int c; while ((c = getc(in)) != EOF) putc(c,out);}/* * gettoken - returns token type of next token, sets tokval * to the string value of the token if appropriate. * */intgettoken(fp) FILE *fp; { int c; while (1) { /* loop if reading comments... */ do { c = getc(fp); if (c == '\n') lines++; } while ((isspace(c) || c == C_L)); /* skip whitespace */ switch(c) { case EOF: return(SEP); case '%': if ((c = getc(fp)) == '%') return(SEP); tokval[0] = '%'; tokval[1] = (char) c; rdword(fp,tokval+2); return(WORD); case '<': return(LBRACK); case '>': return(RBRACK); case ',': return(COMMA); case '/': if ((c = getc(fp)) == '*') { rdcmnt(fp); /* skip over the comment */ continue; } else { /* and keep looping */ ungetc(c,fp); /* put this back into input */ c = '/'; /* put character back, fall thru */ } default: if (isword(c)) { ungetc(c,fp); rdword(fp,tokval); return(WORD); } else fatal("Invalid character in input"); } }}/* * skip over a comment * */VOIDrdcmnt(fp) FILE *fp; { int c,star,prcnt; prcnt = star = 0; /* no star seen yet */ while (!((c = getc(fp)) == '/' && star)) { if (c == EOF || (prcnt && c == '%')) fatal("Unterminated comment"); prcnt = (c == '%'); star = (c == '*'); if (c == '\n') lines++; }}/* * symbol table management for gwart * * entry points: * clrhash - empty hash table. * enter - enter a name into the symbol table * lkup - find a name's value in the symbol table. */#define HASHSIZE 101 /* # of entries in hash table */struct sym { char *name; /* symbol name */ int val; /* value */ struct sym *hnxt; /* next on collision chain */} *htab[HASHSIZE]; /* the hash table *//* * empty the hash table before using it... * */VOIDclrhash() { int i; for (i=0; i<HASHSIZE; i++) htab[i] = NULL;}/* * compute the value of the hash for a symbol * */inthash(name) char *name; { int sum; for (sum = 0; *name != '\0'; name++) sum += (sum + *name); sum %= HASHSIZE; /* take sum mod hashsize */ if (sum < 0) sum += HASHSIZE; /* disallow negative hash value */ return(sum);}/* * make a private copy of a string... * */static char*copy(s) char *s; { char *new; new = (char *) malloc((int)strlen(s) + 1); strcpy(new,s); return(new);}/* * enter state name into the hash table * */VOIDenter(name,svalue) char *name; int svalue; { int h; struct sym *cur; if (lkup(name) != -1) { fprintf(stderr,"state \"%s\" appears twice...\n", name); exit(1); } h = hash(name); cur = (struct sym *)malloc(sizeof (struct sym)); cur->name = copy(name); cur->val = svalue; cur->hnxt = htab[h]; htab[h] = cur;}/* * find name in the symbol table, return its value. Returns -1 * if not found. * */intlkup(name) char *name; { struct sym *cur; for (cur = htab[hash(name)]; cur != NULL; cur = cur->hnxt) if (strcmp(cur->name,name) == 0) return(cur->val); return(-1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -