Compare commits
No commits in common. "b4ea1650b71ec6373403c64f20df54ca2519136f" and "dacf01e83e89c7295fd048aafaa2572f31da21e7" have entirely different histories.
b4ea1650b7
...
dacf01e83e
73
main.c
73
main.c
@ -22,10 +22,10 @@ typedef struct Tok {
|
|||||||
} Tok;
|
} Tok;
|
||||||
|
|
||||||
#define TOKS_CAP 65536
|
#define TOKS_CAP 65536
|
||||||
static Tok toks[TOKS_CAP];
|
Tok toks[TOKS_CAP];
|
||||||
static size_t toks_size = 0;
|
size_t toks_size = 0;
|
||||||
|
|
||||||
static uint8_t op_prec[256] = {
|
uint8_t op_prec[256] = {
|
||||||
['('] = 0, /* A precedence of 0 is reserved for delimiters. */
|
['('] = 0, /* A precedence of 0 is reserved for delimiters. */
|
||||||
[')'] = 0,
|
[')'] = 0,
|
||||||
[','] = 0,
|
[','] = 0,
|
||||||
@ -37,7 +37,7 @@ static uint8_t op_prec[256] = {
|
|||||||
};
|
};
|
||||||
#define OP_PREC(tok_char) (op_prec[(size_t)tok_char])
|
#define OP_PREC(tok_char) (op_prec[(size_t)tok_char])
|
||||||
|
|
||||||
static enum {
|
enum {
|
||||||
OrderLtr,
|
OrderLtr,
|
||||||
OrderRtl,
|
OrderRtl,
|
||||||
} op_order[256] = {
|
} op_order[256] = {
|
||||||
@ -54,27 +54,12 @@ static enum {
|
|||||||
#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'))
|
||||||
|
|
||||||
typedef struct Function {
|
void push_tok(Tok t) {
|
||||||
const char *name;
|
|
||||||
real (*func)(real *args);
|
|
||||||
size_t n_args;
|
|
||||||
} Function;
|
|
||||||
|
|
||||||
#define FUNCTIONS_CAP 256
|
|
||||||
static Function functions[FUNCTIONS_CAP];
|
|
||||||
static size_t functions_size = 0;
|
|
||||||
|
|
||||||
static void push_tok(Tok t) {
|
|
||||||
if (toks_size+1 < TOKS_CAP)
|
if (toks_size+1 < TOKS_CAP)
|
||||||
toks[toks_size++] = t;
|
toks[toks_size++] = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_func(const char *name, real (*func)(real *args), size_t n_args) {
|
void tokenize(char *expr) {
|
||||||
if (functions_size+1 < FUNCTIONS_CAP)
|
|
||||||
functions[functions_size++] = (Function){.name = name, .func = func, .n_args = n_args};
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tokenize(char *expr) {
|
|
||||||
push_tok((Tok){.kind = TokOp, .Char = '('});
|
push_tok((Tok){.kind = TokOp, .Char = '('});
|
||||||
|
|
||||||
size_t paren_depth = 0;
|
size_t paren_depth = 0;
|
||||||
@ -152,7 +137,7 @@ static void tokenize(char *expr) {
|
|||||||
push_tok((Tok){.kind = TokOp, .Char = ')'});
|
push_tok((Tok){.kind = TokOp, .Char = ')'});
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_toks() {
|
void print_toks() {
|
||||||
for (size_t i = 0; i < toks_size; i++) {
|
for (size_t i = 0; i < toks_size; i++) {
|
||||||
switch (toks[i].kind) {
|
switch (toks[i].kind) {
|
||||||
case TokOp:
|
case TokOp:
|
||||||
@ -177,12 +162,12 @@ static void print_toks() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Delete tokens from begin to end (excluding end itself). */
|
/* Delete tokens from begin to end (excluding end itself). */
|
||||||
static 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
static real eval(Tok *t) {
|
real eval(Tok *t) {
|
||||||
if (!(t[0].kind == TokOp && OP_PREC(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);
|
||||||
@ -237,23 +222,22 @@ static real eval(Tok *t) {
|
|||||||
t -= 2;
|
t -= 2;
|
||||||
|
|
||||||
real outer_res;
|
real outer_res;
|
||||||
bool func_found = false;
|
if (strcmp(t[1].Str, "sqrt") == 0) {
|
||||||
for (size_t i = 0; i < functions_size; i++) {
|
if (arg_results_size != 1) {
|
||||||
if (strcmp(t[1].Str, functions[i].name) == 0) {
|
fprintf(stderr, "Error: function sqrt() requires exactly 1 argument\n");
|
||||||
func_found = true;
|
|
||||||
if (arg_results_size != functions[i].n_args) {
|
|
||||||
const char *plural = functions[i].n_args == 1 ? "" : "s";
|
|
||||||
fprintf(stderr, "Error: function %s() requires exactly 1 argument%s\n", functions[i].name, plural);
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
outer_res = functions[i].func(arg_results);
|
outer_res = sqrt(arg_results[0]);
|
||||||
}
|
} else if (strcmp(t[1].Str, "pow") == 0) {
|
||||||
}
|
if (arg_results_size != 2) {
|
||||||
if (!func_found) {
|
fprintf(stderr, "Error: function pow() requires exactly 2 arguments\n");
|
||||||
fprintf(stderr, "Error: unknown function: %s()\n", t[1].Str);
|
exit(1);
|
||||||
|
}
|
||||||
|
outer_res = pow(arg_results[0], arg_results[1]);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Error: unknown function name: %s\n", t[1].Str);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
t[1].kind = TokNum;
|
t[1].kind = TokNum;
|
||||||
t[1].Num = outer_res;
|
t[1].Num = outer_res;
|
||||||
}
|
}
|
||||||
@ -298,31 +282,18 @@ static real eval(Tok *t) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cleanup() {
|
void cleanup() {
|
||||||
for (size_t i = 0; i < toks_size; i++) {
|
for (size_t i = 0; i < toks_size; i++) {
|
||||||
if (toks[i].kind == TokFunc)
|
if (toks[i].kind == TokFunc)
|
||||||
free(toks[i].Str);
|
free(toks[i].Str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static real fn_sqrt(real *args) { return sqrt(args[0]); }
|
|
||||||
static real fn_pow(real *args) { return pow(args[0], args[1]); }
|
|
||||||
static real fn_mod(real *args) { return fmod(args[0], args[1]); }
|
|
||||||
static real fn_round(real *args) { return round(args[0]); }
|
|
||||||
static real fn_floor(real *args) { return floor(args[0]); }
|
|
||||||
static real fn_ceil(real *args) { return ceil(args[0]); }
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
if (argc != 2 || strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) {
|
if (argc != 2 || strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) {
|
||||||
fprintf(stderr, "Usage: ./exp \"<expression>\"\n");
|
fprintf(stderr, "Usage: ./exp \"<expression>\"\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
add_func("sqrt", fn_sqrt, 1);
|
|
||||||
add_func("pow", fn_pow, 2);
|
|
||||||
add_func("mod", fn_mod, 2);
|
|
||||||
add_func("round", fn_round, 1);
|
|
||||||
add_func("floor", fn_floor, 1);
|
|
||||||
add_func("ceil", fn_ceil, 1);
|
|
||||||
tokenize(argv[1]);
|
tokenize(argv[1]);
|
||||||
print_toks();
|
print_toks();
|
||||||
real res = eval(toks);
|
real res = eval(toks);
|
||||||
|
Loading…
Reference in New Issue
Block a user