Skip to content

Commit

Permalink
cevil: Add the concept of precedence
Browse files Browse the repository at this point in the history
Fixes: #1
  • Loading branch information
Grillo-0 committed Aug 26, 2023
1 parent 1a6a384 commit 95ca9aa
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 25 deletions.
78 changes: 54 additions & 24 deletions cevil.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ enum cevil_tk_type {
CEVIL_MINUS_TK,
CEVIL_MULT_TK,
CEVIL_DIV_TK,
CEVIL_TK_SIZE,
};

struct cevil_tk;
Expand Down Expand Up @@ -134,6 +135,38 @@ void chop(const char **str) {
(*str)++;
}

static bool is_binary_op(enum cevil_tk_type tk) {
static bool is_binary_op_table[CEVIL_TK_SIZE] = {
[CEVIL_PLUS_TK] = true,
[CEVIL_MINUS_TK] = true,
[CEVIL_MULT_TK] = true,
[CEVIL_DIV_TK] = true,
};

return is_binary_op_table[tk];
}

/**
* Get the precedence value of an operation
* @tk: token to the precedence value
*
* Returns:
*
* Returns the precedence value or 0 if the token is not a operation.
* The bigger the number, the early the operation needs to be
* evaluated.
*/
static size_t precedence(enum cevil_tk_type tk) {
static size_t precedence_table[CEVIL_TK_SIZE] = {
[CEVIL_PLUS_TK] = 1,
[CEVIL_MINUS_TK] = 1,
[CEVIL_MULT_TK] = 2,
[CEVIL_DIV_TK] = 2,
};

return precedence_table[tk];
}

struct cevil_error next_tk(struct cevil_expr *expr, tkid_t *tk_id) {
*tk_id = tk_storage_alloc(&expr->stg);
struct cevil_tk *tk = tk_storage_get(expr->stg, *tk_id);
Expand All @@ -149,47 +182,43 @@ struct cevil_error next_tk(struct cevil_expr *expr, tkid_t *tk_id) {
expr->parser_cursor = end;
} else if (*expr->parser_cursor == '+') {
tk->type = CEVIL_PLUS_TK;
tk->as.lhs = expr->root;
expr->parser_cursor++;

struct cevil_error err;
err = next_tk(expr, &tk->as.rhs);
if (err.type != CEVIL_ERROK)
return err;
} else if (*expr->parser_cursor == '-') {
tk->type = CEVIL_MINUS_TK;
tk->as.lhs = expr->root;
expr->parser_cursor++;

struct cevil_error err;
err = next_tk(expr, &tk->as.rhs);
if (err.type != CEVIL_ERROK)
return err;
} else if (*expr->parser_cursor == '*') {
tk->type = CEVIL_MULT_TK;
tk->as.lhs = expr->root;
expr->parser_cursor++;

struct cevil_error err;
err = next_tk(expr, &tk->as.rhs);
if (err.type != CEVIL_ERROK)
return err;
} else if (*expr->parser_cursor == '/') {
tk->type = CEVIL_DIV_TK;
tk->as.lhs = expr->root;
expr->parser_cursor++;

struct cevil_error err;
err = next_tk(expr, &tk->as.rhs);
if (err.type != CEVIL_ERROK)
return err;
} else {
struct cevil_error err = {.type = CEVIL_ERRPAR};
snprintf(err.msg, CEVIL_ERROR_BUF_SIZE,
"error: Unexpected charcter '%c'\n", *expr->base);
return err;
}

if (is_binary_op(tk->type)) {
struct cevil_error err;

err = next_tk(expr, &tk->as.rhs);

struct cevil_tk *root = tk_storage_get(expr->stg, expr->root);

if (is_binary_op(root->type) &&
precedence(tk->type) > precedence(root->type)) {
tk->as.lhs = root->as.rhs;
root->as.rhs = *tk_id;
*tk_id = expr->root;
} else {
tk->as.lhs = expr->root;
}

if (err.type != CEVIL_ERROK)
return err;
};

return cevil_ok;
}

Expand Down Expand Up @@ -260,6 +289,7 @@ void eval(tkid_t root_id, struct tk_storage stg) {

root->value = lhs->value / rhs->value;
break;
case CEVIL_TK_SIZE:
default:
assert(false && "Unreachable");
break;
Expand Down
8 changes: 7 additions & 1 deletion test_cevil.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ void test_pos(char* expr, double expected, const char* file, size_t line) {
printf("[PASSSED]: \"%s\" == %f\n", expr, res);
}
else {
printf("[FAILED] %s:%zu: \"%s\" != %f\n", file, line, expr, res);
printf("[FAILED] %s:%zu: \"%s\" != %f (expected: %f)\n", file, line, expr, res, expected);
exit(-1);
}
}
Expand All @@ -41,4 +41,10 @@ int main(void) {
test("69 * 2", 69 * 2);

test("69 / 2", 69.0 / 2);

test("1 * 2 + 2", 2 + 1 * 2);
test("2 + 1 * 2", 2 + 1 * 2);

test("2 / 1 * 2", 2 / 1 * 2);
test("1 * 2 / 2", 1 * 2 / 2);
}

0 comments on commit 95ca9aa

Please sign in to comment.