B
Barry Schwarz
Alright now. I think I've turned a corner with this. And, of course,
everyone who said "use functions!" was spot on.
Hopefully this looks more C-worthy.
lexit-real
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int issign (int c){return !!strchr("+-",c);}
int israd (int c){return !!strchr("#", c);}
int isdot (int c){return !!strchr(".", c);}
Wouldn't return c == '.' be easier?
int ise (int c){return !!strchr("eE",c);}
int isdelim (int c){return !!strchr("()<>{}[]%/",c);}
int isregular(int c){return !isspace(c);}
typedef struct test test;
struct test {
int (*fp)(int); int y,n;
};
You could combine the typedef and the structure definition into a
single declaration.
test decimal[] = {
/* 0*/ { issign, 1, 1 },
/* 1*/ { isdigit, 2, -1 },
/* 2*/ { isdigit, 2, -1 }, //success
};
int dec_accept(int i){ return i==2; }
Would it not work just as well if you eliminated the third element of
decimal and changed this to return i == 1?
test radix[] = {
/* 0*/ { isdigit, 1, -1 },
/* 1*/ { isdigit, 1, 2 },
/* 2*/ { israd, 3, -1 },
/* 3*/ { isdigit, 4, -1 },
/* 4*/ { isdigit, 4, -1 }, //success
};
int rad_accept(int i){ return i==4; }
test real[] = {
/* 0*/ { issign, 1, 1 },
/* 1*/ { isdigit, 2, 4 },
/* 2*/ { isdigit, 2, 3 },
/* 3*/ { isdot, 6, 7 }, //success
/* 4*/ { isdot, 5, -1 },
/* 5*/ { isdigit, 6, -1 },
/* 6*/ { isdigit, 6, 7 }, //success
/* 7*/ { ise, 8, -1 },
/* 8*/ { issign, 9, 9 },
/* 9*/ { isdigit, 10, -1 },
/*10*/ { isdigit, 10, -1 }, //success
};
int real_accept(int i){switch(i){case 3: case 6:case 10:return 1;}
return 0;}
int check(char *buf, test *fsm, int(*yes)(int)){ char *s = buf; int
sta = 0;
Notice how usenet adds line breaks you didn't intend at inopportune
points. Additionally, multiple statements per line tend to hinder
readability.
while(sta!=-1 && *s) {
Why didn't you use buf directly instead of s?
if (fsm[sta].fp(*s))
{ sta = fsm[sta].y; s++; }
else { sta = fsm[sta].n; }
}
sta=yes(sta);
return sta; }
int grok(char *buf) {
if (check(buf,decimal,dec_accept)) { printf( "dec: %s\n",
buf); return 0; }
Here it is even worse. And it destroys your attempt at consistent
indentation.
else if (check(buf,radix, rad_accept)) { printf( "rad: %s\n",
buf); return 0; }
else if (check(buf,real, real_accept)) { printf("real: %s\n",
buf); return 0; }
else { printf("grok? %s\n", buf); return -1; }
}
int puff(char *buf, int nbuf) { char *s = buf; int c;
while ((c=getchar()) != EOF) {
It would be more user friendly if you used '\n' as your terminator
rather than EOF.
if(isspace(c) || isdelim(c))
break;
if(nbuf < s-buf-1)
return -1;
*s++ = c;
}
*s++ = 0;
As a matter of style, recommend '\0' when assigning to a char.
return 0; }
int toke(char *buf, int nbuf) { char *s=buf; int sta = 0;
while(isspace(*s=getchar())) /**/;
if( (sta=puff(buf+1,nbuf-1)) == -1) return -1;
The value assigned to sta is never used.
sta = grok(buf);
return sta; }
#define NBUF 10
int main() { char buf[NBUF] = ""; int sta;
while ( (sta=toke(buf,NBUF)) != -1 )
Ditto.
/**/;
return 0; }