Goto sanos source index
#include <os.h>
#include <math.h>
#include <float.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
double eval_expr(char **expr);
void skip_space(char **expr) {
while (**expr == ' ') (*expr)++;
}
void next(char **expr) {
if (**expr) (*expr)++;
while (**expr == ' ') (*expr)++;
}
double error(char **expr, char *msg) {
printf("%s: %s\n", msg, *expr);
while (**expr) (*expr)++;
return 0.0;
}
double eval_factor(char **expr) {
double result;
if (**expr == '(') {
next(expr);
result = eval_expr(expr);
if (**expr != ')') return error(expr, "')' missing");
next(expr);
} else if (**expr == '+') {
next(expr);
result = eval_factor(expr);
} else if (**expr == '-') {
next(expr);
result = -eval_factor(expr);
} else if (**expr == '.' || isdigit(**expr)) {
char *newpos;
result = strtod(*expr, &newpos);
if (!newpos || *expr == newpos) return error(expr, "error in number");
*expr = newpos;
skip_space(expr);
} else if (isalpha(**expr)) {
double arg1 = 0.0;
double arg2 = 0.0;
int n;
char *func = *expr;
while (isalnum(**expr)) (*expr)++;
n = *expr - func;
if (strncmp(func, "inf", n) == 0) return INFINITY;
if (strncmp(func, "nan", n) == 0) return NAN;
skip_space(expr);
if (**expr != '(') return error(expr, "'(' missing");
next(expr);
arg1 = eval_expr(expr);
if (**expr == ',') {
next(expr);
arg2 = eval_expr(expr);
}
if (**expr != ')') return error(expr, "')' missing");
next(expr);
if (strncmp(func, "asin", n) == 0) {
result = asin(arg1);
} else if (strncmp(func, "acos", n) == 0) {
result = acos(arg1);
} else if (strncmp(func, "atan", n) == 0) {
result = atan(arg1);
} else if (strncmp(func, "atan2", n) == 0) {
result = atan2(arg1, arg2);
} else if (strncmp(func, "ceil", n) == 0) {
result = ceil(arg1);
} else if (strncmp(func, "cos", n) == 0) {
result = cos(arg1);
} else if (strncmp(func, "cosh", n) == 0) {
result = cosh(arg1);
} else if (strncmp(func, "exp", n) == 0) {
result = exp(arg1);
} else if (strncmp(func, "fabs", n) == 0) {
result = fabs(arg1);
} else if (strncmp(func, "floor", n) == 0) {
result = floor(arg1);
} else if (strncmp(func, "fmod", n) == 0) {
result = fmod(arg1, arg2);
} else if (strncmp(func, "mant", n) == 0) {
int expo;
result = frexp(arg1, &expo);
} else if (strncmp(func, "expo", n) == 0) {
int expo;
frexp(arg1, &expo);
result = expo;
} else if (strncmp(func, "ldexp", n) == 0) {
result = fmod(arg1, (int) arg2);
} else if (strncmp(func, "log", n) == 0) {
result = log(arg1);
} else if (strncmp(func, "log10", n) == 0) {
result = log10(arg1);
} else if (strncmp(func, "frac", n) == 0) {
double intg;
result = modf(arg1, &intg);
} else if (strncmp(func, "int", n) == 0) {
modf(arg1, &result);
} else if (strncmp(func, "pow", n) == 0) {
result = pow(arg1, arg2);
} else if (strncmp(func, "sin", n) == 0) {
result = sin(arg1);
} else if (strncmp(func, "sinh", n) == 0) {
result = sinh(arg1);
} else if (strncmp(func, "sqrt", n) == 0) {
result = sqrt(arg1);
} else if (strncmp(func, "tan", n) == 0) {
result = tan(arg1);
} else if (strncmp(func, "tanh", n) == 0) {
result = tanh(arg1);
} else {
*expr = func;
return error(expr, "unknown function");
}
} else {
return error(expr, "syntax error");
}
return result;
}
double eval_term(char **expr) {
double result;
result = eval_factor(expr);
while (**expr == '*' || **expr == '/') {
if (**expr == '*') {
next(expr);
result *= eval_factor(expr);
} else {
next(expr);
result /= eval_factor(expr);
}
}
return result;
}
double eval_expr(char **expr) {
double result;
result = eval_term(expr);
while (**expr == '+' || **expr == '-') {
if (**expr == '+') {
next(expr);
result += eval_term(expr);
} else {
next(expr);
result -= eval_term(expr);
}
}
return result;
}
double eval(char **expr) {
skip_space(expr);
return eval_expr(expr);
}
int main(int argc, char *argv[]) {
int i;
double result;
char *expr;
for (i = 1; i < argc; i++) {
expr = argv[i];
result = eval(&expr);
if (*expr) {
printf("syntax error\n");
} else {
printf("%g\n", result);
}
}
return 0;
}