/*------------------------------------------------------* | Author: Maurizio Loreti, aka MLO or (HAM) I3NOO | | Work: University of Padova - Department of Physics | | Via F. Marzolo, 8 - 35131 PADOVA - Italy | | Phone: +39 (049) 827-7216 FAX: +39 (049) 827-7102 | | EMail: loreti@pd.infn.it | | WWW: http://www.pd.infn.it/~loreti/mlo.html | *------------------------------------------------------* BInary Number Decoder; the main program asks for strings to be decoded as binary numbers. Exit with EOF. *------------------------------------------------------*/ #include #include #include #define BUFFER_LENGTH 128 int bind(const char *, double *); int main() { for (;;) { char buffer[BUFFER_LENGTH]; char *pc; double result; int status; fputs("? ", stdout); if (fgets(buffer, BUFFER_LENGTH, stdin) == 0) break; if ((pc = strrchr(buffer, '\n')) != 0) *pc = '\0'; if ((status = bind(buffer, &result)) == -1) { printf("\"%s\" --> %f\n", buffer, result); } else { printf("\"%s\": error at buffer[%d] ", buffer, status); if (isprint(buffer[status])) printf("= '%c'\n", buffer[status]); else puts("(unprintable)"); } } puts(""); return 0; } int bind( const char *input, double *result ) { /*--------------------------------------------------------------------------* The procedure is coded as a finite state machine. The FSM driver table is the following: "S" is the sign; "I" the integer part; "F" the fractional part; the starting state is status=0, S=+, I=F=0. +---------+---------+---------+---------+---------+---------+ | /-------------------------INPUT-------------------------\ | | w/space | \0 | +,- | . | 0,1 | other | +-------------+---------+---------+---------+---------+---------+---------+ | state = 0 | - | exit | state=1 | state=3 | state=2 | error | | (initial) | | | set S | | chnge I | | +-------------+---------+---------+---------+---------+---------+---------+ | state = 1 | error | error | error | state=3 | state=2 | error | | (S read) | | | | | chnge I | | +-------------+---------+---------+---------+---------+---------+---------+ | state = 2 | exit | exit | error | state=3 | chnge I | error | | (reading I) | | | | | | | +-------------+---------+---------+---------+---------+---------+---------+ | state = 3 | exit | exit | error | error | chnge F | error | | (reading F) | | | | | | | +-------------+---------+---------+---------+---------+---------+---------+ The returned value is -1 (meaning OK), or the position in input[] of the illegal character where the procedure fails. The decoded value is stored into *result (that is left unchanged in case of errors). *----------------------------------------------------------------------*/ int sign = 1; /* Positive */ unsigned long integer_part = 0; double fraction = 1.0; double fractional_part = 0.0; unsigned int state = 0; const char *pc; char c; for (pc = input; ; ++pc) { switch (c = *pc) { case ' ': /* Whitespace */ case '\t': if (state == 1) goto error; else if (state != 0) goto done; break; case '\0': /* End-of-string */ if (state == 1) goto error; else goto done; break; case '+': /* + */ if (state != 0) goto error; state = 1; break; case '-': /* - */ if (state != 0) goto error; sign = -1; state = 1; break; case '.': /* . */ if (state == 3) goto error; state = 3; break; case '0': /* 0 */ if (state < 2) state = 2; if (state == 2) { integer_part <<= 1; } else { fraction *= 2.0; } break; case '1': /* 1 */ if (state < 2) state = 2; if (state == 2) { integer_part <<= 1; integer_part += 1; } else { fraction *= 2.0; fractional_part += (1.0 / fraction); } break; default: /* Other */ goto error; } /* switch (c) */ } /* for (;;) */ done: *result = integer_part; *result += fractional_part; if (sign != 1) *result = - *result; return -1; error: return pc - input; }