Last active
April 19, 2016 07:26
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdbool.h> | |
enum states { | |
in_sum, in_mult | |
}; | |
enum errors { | |
no_error, unexpected_character, unbalanced_parentheses | |
}; | |
void skip_spaces(char **str){ | |
while (**str == ' ') { | |
(*str)++; | |
} | |
} | |
double calc(char **str, enum errors *error, bool parentheses_expected) { | |
double sum = 0; | |
int sum_sign = 1; | |
double mult; | |
int mult_sign; | |
enum states state = in_sum; | |
skip_spaces(str); | |
while (**str != '\0') { | |
int val = 0; | |
if (**str == '(') { | |
(*str)++; | |
val = calc(str, error, true); | |
if (*error != no_error) { | |
return 0; | |
} | |
} else { | |
while ('0' <= **str && **str <= '9') { | |
val = val * 10 + *((*str)++) - '0'; | |
} | |
} | |
skip_spaces(str); | |
char op = **str; | |
if (**str != '\0') | |
(*str)++; | |
if (state == in_sum) { | |
if (op == '+' || op == '-') { | |
sum += sum_sign * val; | |
sum_sign = op == '+' ? 1 : -1; | |
} else if (op == '*' || op == '/') { | |
mult = val; | |
mult_sign = op == '*' ? 1 : -1; | |
state = in_mult; | |
} else if (op == ')' || op == '\0') { | |
if ((parentheses_expected && op != ')') | |
|| (!parentheses_expected && op == ')')) { | |
*error = unbalanced_parentheses; | |
return 0; | |
} | |
sum += sum_sign * val; | |
break; | |
} else { | |
*error = unexpected_character; | |
return 0; | |
} | |
} else { | |
if (op == '+' || op == '-') { | |
mult = mult_sign > 0 ? mult * val : mult / val; | |
sum += sum_sign * mult; | |
sum_sign = op == '+' ? 1 : -1; | |
state = in_sum; | |
} else if (op == '*' || op == '/') { | |
mult = mult_sign > 0 ? mult * val : mult / val; | |
mult_sign = op == '*' ? 1 : -1; | |
} else { | |
mult = mult_sign > 0 ? mult * val : mult / val; | |
sum += sum_sign * mult; | |
break; | |
} | |
} | |
skip_spaces(str); | |
} | |
return sum; | |
} | |
int main(int argc, char **argv) { | |
char buf[100] = "2+2*2"; | |
char *p = argc > 1 ? argv[1] : buf; | |
enum errors error = no_error; | |
double res = calc(&p, &error, false); | |
switch (error) { | |
case no_error: | |
printf("%g\n", res); | |
break; | |
case unexpected_character: | |
printf("Unexpected character.\n"); | |
break; | |
case unbalanced_parentheses: | |
printf("Unbalanced parentheses.\n"); | |
break; | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
calc="./calc" | |
check(){ | |
expected="$1" | |
expression="`$calc $2`" | |
if [ "$expected" == "$expression" ] | |
then | |
echo "ok $expected" | |
else | |
echo "fail $expected != $expression" | |
fi | |
} | |
while read line; do | |
eval check $line | |
done <<EOF | |
2 2 | |
4 2*2 | |
6 2+2*2 | |
8 2*2+2*2 | |
16 2*2*2*2 | |
0 2*2*2*2* | |
0.5 1/2 | |
100 10*10 | |
1000 10*10*10 | |
"Unbalanced parentheses." "(2+2" | |
4 " (2+2)" | |
"Unbalanced parentheses." "(2+2))" | |
"Unexpected character." abc | |
"Unexpected character." 0x10 | |
0 1--1 #Not the same as 1-(-1) but 1-0-1 | |
2 "1-(-1)" | |
EOF |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment