Compare commits
2 Commits
dfc515b7df
...
dacf01e83e
Author | SHA1 | Date | |
---|---|---|---|
|
dacf01e83e | ||
|
0fcef2a860 |
38
main.c
38
main.c
@ -35,6 +35,7 @@ uint8_t op_prec[256] = {
|
|||||||
['/'] = 2,
|
['/'] = 2,
|
||||||
['^'] = 3,
|
['^'] = 3,
|
||||||
};
|
};
|
||||||
|
#define OP_PREC(tok_char) (op_prec[(size_t)tok_char])
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
OrderLtr,
|
OrderLtr,
|
||||||
@ -48,6 +49,7 @@ enum {
|
|||||||
['/'] = OrderLtr,
|
['/'] = OrderLtr,
|
||||||
['^'] = OrderRtl,
|
['^'] = OrderRtl,
|
||||||
};
|
};
|
||||||
|
#define OP_ORDER(tok_char) (op_order[(size_t)tok_char])
|
||||||
|
|
||||||
#define IS_FLOAT(c) ((c >= '0' && c <= '9') || c == '.')
|
#define IS_FLOAT(c) ((c >= '0' && c <= '9') || c == '.')
|
||||||
#define IS_ALPHA(c) ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
|
#define IS_ALPHA(c) ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
|
||||||
@ -62,15 +64,12 @@ void tokenize(char *expr) {
|
|||||||
|
|
||||||
size_t paren_depth = 0;
|
size_t paren_depth = 0;
|
||||||
|
|
||||||
bool can_be_neg_num = true;
|
|
||||||
|
|
||||||
char *curr = expr;
|
char *curr = expr;
|
||||||
for (char c = *curr; c != 0; c = *(++curr)) {
|
for (char c = *curr; c != 0; c = *(++curr)) {
|
||||||
if (c == ' ')
|
if (c == ' ')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (IS_FLOAT(c) ||
|
if (IS_FLOAT(c)) {
|
||||||
(can_be_neg_num && c == '-' && IS_FLOAT(curr[1]))) {
|
|
||||||
char buf[16];
|
char buf[16];
|
||||||
buf[0] = c;
|
buf[0] = c;
|
||||||
size_t i = 1;
|
size_t i = 1;
|
||||||
@ -84,8 +83,6 @@ void tokenize(char *expr) {
|
|||||||
real num = strtod(buf, NULL);
|
real num = strtod(buf, NULL);
|
||||||
|
|
||||||
push_tok((Tok){.kind = TokNum, .Num = num});
|
push_tok((Tok){.kind = TokNum, .Num = num});
|
||||||
|
|
||||||
can_be_neg_num = false;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,8 +98,6 @@ void tokenize(char *expr) {
|
|||||||
buf[i++] = 0;
|
buf[i++] = 0;
|
||||||
|
|
||||||
push_tok((Tok){.kind = TokFunc, .Str = buf});
|
push_tok((Tok){.kind = TokFunc, .Str = buf});
|
||||||
|
|
||||||
can_be_neg_num = false;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,8 +127,6 @@ void tokenize(char *expr) {
|
|||||||
fprintf(stderr, "Error: unrecognized token at %zd: '%c'\n", curr - expr, c);
|
fprintf(stderr, "Error: unrecognized token at %zd: '%c'\n", curr - expr, c);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
can_be_neg_num = c != ')';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (paren_depth > 0) {
|
if (paren_depth > 0) {
|
||||||
@ -168,23 +161,34 @@ void print_toks() {
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Delete tokens from begin to end (excluding end itself). */
|
||||||
void del_toks(Tok *begin, Tok *end) {
|
void del_toks(Tok *begin, Tok *end) {
|
||||||
memmove(begin, end, (toks_size - (end - toks)) * sizeof(Tok));
|
memmove(begin, end, (toks_size - (end - toks)) * sizeof(Tok));
|
||||||
toks_size -= end - begin;
|
toks_size -= end - begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
real eval(Tok *t) {
|
real eval(Tok *t) {
|
||||||
if (!(t[0].kind == TokOp && op_prec[(size_t)t[0].Char] == 0)) {
|
if (!(t[0].kind == TokOp && OP_PREC(t[0].Char) == 0)) {
|
||||||
fprintf(stderr, "Error: expected delimiter at beginning of expression\n");
|
fprintf(stderr, "Error: expected delimiter at beginning of expression\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
/* Collapse factor. */
|
||||||
|
if (t[1].kind == TokOp && t[1].Char == '-') {
|
||||||
|
if (t[2].kind != TokNum) {
|
||||||
|
fprintf(stderr, "Error: expected number token after minus factor\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
t[2].Num *= -1.0;
|
||||||
|
del_toks(t + 1, t + 2);
|
||||||
|
}
|
||||||
|
|
||||||
/* Collapse parentheses. */
|
/* Collapse parentheses. */
|
||||||
if (t[1].kind == TokOp && t[1].Char == '(') {
|
if (t[1].kind == TokOp && t[1].Char == '(') {
|
||||||
real res = eval(t + 1);
|
real res = eval(t + 1);
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 2; !(t[i].kind == TokOp && op_prec[(size_t)t[i].Char] == 0); i++);
|
for (i = 2; !(t[i].kind == TokOp && OP_PREC(t[i].Char) == 0); i++);
|
||||||
del_toks(t + 2, t + i + 1);
|
del_toks(t + 2, t + i + 1);
|
||||||
/* Put the newly evaluated value into place. */
|
/* Put the newly evaluated value into place. */
|
||||||
t[1].kind = TokNum;
|
t[1].kind = TokNum;
|
||||||
@ -206,7 +210,7 @@ real eval(Tok *t) {
|
|||||||
while (1) {
|
while (1) {
|
||||||
arg_results[arg_results_size++] = eval(t); /* TODO: Overflow protection. */
|
arg_results[arg_results_size++] = eval(t); /* TODO: Overflow protection. */
|
||||||
size_t i = 1;
|
size_t i = 1;
|
||||||
for (; !(t[i].kind == TokOp && op_prec[(size_t)t[i].Char] == 0); i++);
|
for (; !(t[i].kind == TokOp && OP_PREC(t[i].Char) == 0); i++);
|
||||||
bool end = t[i].Char == ')';
|
bool end = t[i].Char == ')';
|
||||||
if (t[i].Char == ',')
|
if (t[i].Char == ',')
|
||||||
del_toks(t, t + i);
|
del_toks(t, t + i);
|
||||||
@ -244,18 +248,18 @@ real eval(Tok *t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char curr_op = t[0].Char;
|
const char curr_op = t[0].Char;
|
||||||
const uint8_t curr_prec = op_prec[(size_t)curr_op];
|
const uint8_t curr_prec = OP_PREC(curr_op);
|
||||||
|
|
||||||
const char next_op = t[2].Char;
|
const char next_op = t[2].Char;
|
||||||
const uint8_t next_prec = op_prec[(size_t)next_op];
|
const uint8_t next_prec = OP_PREC(next_op);
|
||||||
|
|
||||||
/* Delimiters have a precedence of 0; if we have a number between two delimiters, we're done. */
|
/* Delimiters have a precedence of 0; if we have a number between two delimiters, we're done. */
|
||||||
if (curr_prec == 0 && next_prec == 0)
|
if (curr_prec == 0 && next_prec == 0)
|
||||||
return t[1].Num;
|
return t[1].Num;
|
||||||
|
|
||||||
if (next_prec > curr_prec || (next_prec == curr_prec && op_order[(size_t)curr_op] == OrderRtl)) {
|
if (next_prec > curr_prec || (next_prec == curr_prec && OP_ORDER(curr_op) == OrderRtl)) {
|
||||||
t += 2;
|
t += 2;
|
||||||
} else if (next_prec < curr_prec || (next_prec == curr_prec && op_order[(size_t)curr_op] == OrderLtr)) {
|
} else if (next_prec < curr_prec || (next_prec == curr_prec && OP_ORDER(curr_op) == OrderLtr)) {
|
||||||
real res;
|
real res;
|
||||||
real lhs = t[-1].Num, rhs = t[1].Num;
|
real lhs = t[-1].Num, rhs = t[1].Num;
|
||||||
switch (curr_op) {
|
switch (curr_op) {
|
||||||
|
Loading…
Reference in New Issue
Block a user