Skip to content

Instantly share code, notes, and snippets.

@jrosskopf
Created November 14, 2011 13:15
Show Gist options
  • Save jrosskopf/1363927 to your computer and use it in GitHub Desktop.
Save jrosskopf/1363927 to your computer and use it in GitHub Desktop.
07_soupsum
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
//#define DEBUG
#define EOT 4
#define TO_CHAR(_x) ((unsigned char)_x)
#define TO_NUMBER(_x) ((_x >= '0' && _x <= '9') ? (double)(_x - '0') : 0.0)
#define SIGNUM(_x) (signbit(_x) ? -1.0 : 1.0)
#define TOKEN_PM 0
#define TOKEN_DOT 1
#define TOKEN_DIGIT 2
#define TOKEN_EXP 3
#define TOKEN_EOT 5
#define TOKEN_REST 4
#define S0 0
#define S1 1
#define S2 2
#define S3 3
#define S4 4
#define S5 5
#define S6 6
#define S7 7
#define STATE_INITIAL S0
#define STATE_TERMINAL 99
int T[8][6] = {
{1, 3, 2, 0, 0, 99}, // S0
{0, 3, 2, 0, 0, 99}, // S1
{0, 4, 2, 5, 0, 99}, // S2
{0, 0, 4, 0, 0, 99}, // S3
{0, 0, 4, 5, 0, 99}, // S4
{6, 0, 7, 0, 0, 99}, // S5
{0, 0, 7, 0, 0, 99}, // S6
{0, 0, 7, 0, 0, 99} // S7
};
int get_token_from_char(unsigned char ch) {
if (ch == '+' || ch == '-')
return TOKEN_PM;
if (ch == '.')
return TOKEN_DOT;
if (ch >= '0' && ch <= '9')
return TOKEN_DIGIT;
if (ch == 'e' || ch == 'E')
return TOKEN_EXP;
if (ch == EOT)
return TOKEN_EOT;
return TOKEN_REST;
}
double pow10floor(double x) {
return pow(10.0, floor(log10(x)));
}
int get_next_state(int state, unsigned char ch) {
int sym = get_token_from_char(ch);
if (state < 0 || state > 7) {
fprintf(stderr, "**Error** Invalid state %d at %c\n", state, ch);
exit(1);
}
if (sym < 0 || sym > 5) {
fprintf(stderr, "**Error** Invalid symbol %d at %c\n", sym, ch);
exit(1);
}
return T[state][sym];
}
void handle_state_transition(double *curr, double *exp, unsigned char ch, int decimal, int next_state) {
if (next_state == S1)
*curr *= ch == '-' ? -1.0 : 1.0;
if (next_state == S2)
*curr = (*curr * 10) + SIGNUM(*curr) * TO_NUMBER(ch);
if (next_state == S4)
*curr += SIGNUM(*curr) * TO_NUMBER(ch) / pow(10.0, decimal);
if (next_state == S6)
*exp *= ch == '-' ? -1.0 : 1.0;
if (next_state == S7)
*exp = (*exp * 10) + SIGNUM(*exp) * TO_NUMBER(ch);
}
char translate_char(unsigned char ch) {
if (ch == '\n')
return ' ';
return ch;
}
int main(int argc, char **argv) {
double sum = 0.0, curr = 0.0, exp = 0.0;
int state = STATE_INITIAL, next_state = STATE_INITIAL;
int ch = 0;
for(int decimal = 0; (ch = getchar()) != EOF; decimal++) {
next_state = get_next_state(state, TO_CHAR(ch));
#ifdef DEBUG
printf("%10fe%10f >> %c: %2d -> %2d >> ", curr, exp, translate_char(TO_CHAR(ch)), state, next_state);
#endif
handle_state_transition(&curr, &exp, ch, decimal, next_state);
#ifdef DEBUG
printf("%10fe%10f\n", curr, exp);
#endif
if (next_state == S4 && state == S2) {
decimal = 0;
}
if (next_state == S3 && state == S1) {
decimal = 0;
}
if (next_state == STATE_INITIAL || next_state == STATE_TERMINAL) {
sum += curr * pow(10.0, exp);
curr = 0.0;
exp = 0.0;
decimal = -1;
}
if (next_state == STATE_INITIAL && state != STATE_INITIAL) {
ungetc(ch, stdin);
}
if (next_state == STATE_TERMINAL)
break;
state = next_state;
}
printf("%.4f\n", sum);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment