Skip to content

Instantly share code, notes, and snippets.

@nazarov-yuriy
Last active April 19, 2016 07:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nazarov-yuriy/4c63b89fc1a5c5bd8aeed23fcfbfe86c to your computer and use it in GitHub Desktop.
Save nazarov-yuriy/4c63b89fc1a5c5bd8aeed23fcfbfe86c to your computer and use it in GitHub Desktop.
#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;
}
#!/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