It is almost impossible code so as to guard against all possible
misunderstandings.
That is not right -- the ; is not part of the while. The above /does/
execute a statement conditionally, the question is simply about how
best to write that it. C offers two obvious choices: an expression
statement with no expression, and a "continue" statement. My
preference is, like you, for the empty expression statement but I have
used the other form in the past.
I would say the same about while(x--) continue;
I both agree and disagree with both of you. Although while(cond); is
syntactically valid, and any C programmer worth their salt should
understand this if they look at it. But one indulges in speculation
about how best to offer that minimum bit of help which may be needed
by some future reader without being obnoxious to those who can grok it
without such aid.
For more fuel to the fire, I've investigated the hodge-podge of int-
bool interpretations in this little program and am surprised at the
results. Is it normal for different functions in the same file to have
such wildly differing notions about good and evil?
#include <ctype.h>
#include <stdio.h>
#include <string.h>
/* character classes */
#define eq(a,b) (int)a==b
#define within(a,b) strchr(a,b)!=NULL
int israd (int c){return eq('#',c);}
int isdot (int c){return eq('.',c);}
int ise (int c){return within("eE",c);}
int issign (int c){return within("+-",c);}
int isdelim (int c){return within("()<>{}[]%/",c);}
int isregular(int c)
{return c!=EOF && !isspace(c) && !isdelim(c);}
#undef within
#undef eq
typedef struct { int (*fp)(int); int y, n; } test;
/* n.b. this machine has no x+, use xx* */
/* ^[+-]?\d+$ */
test fsm_dec[] = {
/* 0*/ { issign, 1, 1 },
/* 1*/ { isdigit, 2, -1 }, /* [+-]?! ??(\d)?? */
/* 2*/ { isdigit, 2, -1 }, /* [+-]?\d\d* yes! */
};
int acc_dec(int i){ return i==2; } /*acceptable decimal?*/
/* ^\d+[#][a-Z0-9]+$ */
test fsm_rad[] = {
/* 0*/ { isdigit, 1, -1 },
/* 1*/ { isdigit, 1, 2 }, /* \d\d* */
/* 2*/ { israd, 3, -1 }, /* \d\d*[^\d] */
/* 3*/ { isalnum, 4, -1 }, /* \d\d*# */
/* 4*/ { isalnum, 4, -1 }, /* \d\d*#\x\x* yes! */
};
int acc_rad(int i){ return i==4; } /*acceptable radix?*/
/* ^[+-]?(\d+(\.\d*)?)|(\d*\.\d+)([eE][+-]?\d+)?$ */
test fsm_real[] = {
/* 0*/ { issign, 1, 1 },
/* 1*/ { isdigit, 2, 4 }, /* [+-]? */
/* 2*/ { isdigit, 2, 3 }, /* [+-]?\d\d* yes! */
/* 3*/ { isdot, 6, 7 }, /* [+-]?\d\d*[^\d] */
/* 4*/ { isdot, 5, -1 }, /* [+-]?[^\d] */
/* 5*/ { isdigit, 6, -1 }, /* s?\. where s is [+-] */
/* 6*/ { isdigit, 6, 7 }, /* s?(\d\d*)?\.\d* yes! */
/* 7*/ { ise, 8, -1 }, /* s?(\d\d*)?(\.\d*)? */
/* 8*/ { issign, 9, 9 }, /* s?\d*(\.\d*)?[eE] */
/* 9*/ { isdigit, 10, -1 }, /* s?\d*(\.\d*)?[eE][+-]? */
/*10*/ { isdigit, 10, -1 }, /* s?\d*(\.\d*)?[eE]s?\d\d* yes! */
};
/*acceptable real*/
int acc_real(int i){
switch(i) { case 2: case 6: case 10: return 1; }
return 0; }
/*1/0*/
/*what's the reverse of reverse polish?*/
int czek(char *s, test *fsm, int(*yes)(int)){
int sta = 0;
while(sta!=-1 && *s) {
if (fsm[sta].fp((int)*s)) { sta=fsm[sta].y; s++; }
else { sta=fsm[sta].n; } }
return yes(sta); }
/*0/-1*/
int grok(char *s) { /*dig?*/
if (czek(s, fsm_dec, acc_dec )) {
printf( "dec: %s\n", s); return 0; }
else if (czek(s, fsm_rad, acc_rad )) {
printf( "rad: %s\n", s); return 0; }
else if (czek(s, fsm_real,acc_real)) {
printf("real: %s\n", s); return 0; }
/*else*/
printf("grok? %s\n", s);
return -1; }
/*0/-1*/
int puff(char *buf, int nbuf) {
int c; char *s = buf;
while ( (c=getchar()), isregular(c) ) {
if(s-buf >= nbuf-1) return -1;
*s++ = (char)c; }
*s = (char)0; (void)ungetc(c,stdin);
return 0; }
/*1/-1*/
int toke(char *buf, int nbuf) {
int sta = 0; char *s=buf;
while (isspace(*s=(char)getchar())) /*jump down, turn around*/;
if ((sta=puff(++s,nbuf-1))!=-1)
sta=grok(buf);
return sta; }
/*0/1*/
#define NBUF 10
int main(void) { char buf[NBUF] = "";
while (-1 != toke(buf,NBUF)) /*pick a bale a day*/;
return 0; }
/*eof*/