basic functions

General support for very basic functions (currently only sqrt()).
This commit is contained in:
r4 2021-11-21 18:15:22 +01:00
parent 7a65de22bb
commit d1cf60794d

61
main.c
View File

@ -11,11 +11,13 @@ typedef struct Tok {
enum {
TokOp,
TokNum,
TokFunc,
} kind;
union {
real Num;
char Char;
char *Str;
};
} Tok;
@ -47,6 +49,7 @@ enum {
};
#define IS_FLOAT(c) ((c >= '0' && c <= '9') || c == '.')
#define IS_ALPHA(c) ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
void push_tok(Tok t) {
if (toks_size+1 < TOKS_CAP)
@ -85,6 +88,23 @@ void tokenize(char *expr) {
continue;
}
if (IS_ALPHA(c)) {
char *buf = malloc(32);
buf[0] = c;
size_t i = 1;
while (i < 31 && IS_ALPHA(curr[i])) {
buf[i] = curr[i];
i++;
}
curr += i - 1;
buf[i++] = 0;
push_tok((Tok){.kind = TokFunc, .Str = buf});
can_be_neg_num = false;
continue;
}
if (c == '(')
paren_depth++;
else if (c == ')') {
@ -135,6 +155,9 @@ void print_toks() {
case TokNum:
printf("%.2f ", toks[i].Num);
break;
case TokFunc:
printf("%s ", toks[i].Str);
break;
default:
fprintf(stderr, "Error: unhandled token\n");
exit(1);
@ -160,11 +183,39 @@ real eval(Tok *t) {
real res = eval(t + 1);
size_t i;
for (i = 2; !(t[i].kind == TokOp && t[i].Char == ')'); i++);
del_toks(t + 1, t + i);
del_toks(t + 2, t + i + 1);
/* Put the newly evaluated value into place. */
t[1].kind = TokNum;
t[1].Num = res;
}
/* Collapse function. */
if (t[1].kind == TokFunc) {
print_toks();
if (!(t[2].kind == TokOp && t[2].Char == '(') || t + 2 >= toks + toks_size) {
fprintf(stderr, "Error: expected '(' token after function\n");
exit(1);
}
real inner_res = eval(t + 2);
size_t i;
for (i = 3; !(t[i].kind == TokOp && t[i].Char == ')'); i++);
del_toks(t + 2, t + i + 1);
real outer_res;
if (strcmp(t[1].Str, "sqrt") == 0) {
outer_res = sqrt(inner_res);
} else {
fprintf(stderr, "Error: unknown function name: %s\n", t[1].Str);
exit(1);
}
t[1].kind = TokNum;
t[1].Num = outer_res;
print_toks();
}
if (!(t[0].kind == TokOp && t[1].kind == TokNum && t[2].kind == TokOp)) {
fprintf(stderr, "Error: invalid token order\n");
@ -205,6 +256,13 @@ real eval(Tok *t) {
}
}
void cleanup() {
for (size_t i = 0; i < toks_size; i++) {
if (toks[i].kind == TokFunc)
free(toks[i].Str);
}
}
int main(int argc, char **argv) {
if (argc != 2 || strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) {
fprintf(stderr, "Usage: ./exp \"<expression>\"\n");
@ -214,4 +272,5 @@ int main(int argc, char **argv) {
print_toks();
real res = eval(toks);
printf("Result: %f\n", res);
cleanup();
}