home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
archives
/
gwart.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-12-16
|
15KB
|
644 lines
/*
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
*
*/
VOID
setwstate(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
*
*/
int
teststate(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...
*
*/
trans
rdinput(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 %%.
*
*/
VOID
initial(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.
*
*/
int
isin(s,c) char *s; int c; {
for (; *s != '\0'; s++)
if (*s == (char) c) return(1);
return(0);
}
int
isword(c) int c; {
static char special[] = ".%_-$@"; /* these are allowable */
return(isalnum(c) || isin(special,c));
}
/*
* read the next word into the given buffer.
*
*/
VOID
rdword(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.
*
*/
VOID
rdstates(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
*
*/
trans
newtrans() {
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.
*
*/
trans
rdrules(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.
*
*/
VOID
statelist(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
*
*/
VOID
copyact(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.
*
*/
int
faction(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...
*
*/
VOID
emptytbl() {
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.
*
*/
VOID
addaction(act,state,chr) int act,state,chr; {
tbl[state*96 + chr] = act;
}
VOID
writetbl(fp) FILE *fp; {
warray(fp,"tbl",tbl,96*(nstates+1),TBL_TYPE);
}
/*
* write an array to the output file, given its name and size.
*
*/
VOID
warray(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]);
}
int
main(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
*
*/
VOID
fatal(msg) char *msg; {
fprintf(stderr,"error in line %d: %s\n",lines,msg);
exit(1);
}
VOID
prolog(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);
}
VOID
epilogue(outfp) FILE *outfp; {
int c;
while ((c = *txt3++) != '\0') putc(c,outfp);
}
VOID
copyrest(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.
*
*/
int
gettoken(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
*
*/
VOID
rdcmnt(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...
*
*/
VOID
clrhash() {
int i;
for (i=0; i<HASHSIZE; i++) htab[i] = NULL;
}
/*
* compute the value of the hash for a symbol
*
*/
int
hash(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
*
*/
VOID
enter(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.
*
*/
int
lkup(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);
}