diff options
| -rw-r--r-- | main.c | 126 |
1 files changed, 71 insertions, 55 deletions
@@ -69,12 +69,27 @@ typedef struct AExp { // Token_t* t; } AExp_t; +static const union { + struct { + u8 grouping; + u8 operator; + } parts; + u16 sum; +} precedence_tbl[] = { + [e_error] = {0}, + [e_mul] = {.parts = {.grouping = 0, .operator = 2}}, + [e_div] = {.parts = {.grouping = 0, .operator = 2}}, + [e_add] = {.parts = {.grouping = 0, .operator = 1}}, + [e_sub] = {.parts = {.grouping = 0, .operator = 1}}, + [e_number] = {.parts = {.grouping = 0, .operator = 3}}, +}; + static usize f_read(FILE* restrict stream, char** restrict dst); static usize f_size(FILE* restrict stream); static line_offsets_t* l_read(char const* restrict text, usize text_length, TokenList_t** restrict dst); static AExp_t* p_arith(char const* restrict text, TokenList_t* restrict tokens); -static AExp_t p_number(char const* restrict text, Token_t* restrict tnum); +static AExp_t p_number(char const* restrict text, Token_t const* restrict tnum); static void print_aexp(AExp_t* t); int @@ -341,83 +356,84 @@ p_arith(char const* restrict text, TokenList_t* restrict tokens) { // Root is the "current working root" AExp_t* root = NULL; - // Exp is the return expression, or the "root" of the expression that has - // parsed. - AExp_t* exp = NULL; + // Top is the "top-level" return expression, or the "root" of the expression + // that has parsed. + AExp_t* top = NULL; for (int tokenidx = 0; tokenidx < num_tokens; tokenidx++) { + // Currently inspected token + Token_t const* const token = &tokens->elements[tokenidx]; + // Destination for currently fabricated expression + AExp_t* const expr = &expression[exp_idx]; + // ignore whitespace - if (tokens->elements[tokenidx].type == t_space || - tokens->elements[tokenidx].type == t_tab || - tokens->elements[tokenidx].type == t_newline) { + if (token->type == t_space || token->type == t_tab || + token->type == t_newline) { continue; } - if (tokens->elements[tokenidx].type == t_number && root == NULL) { - expression[exp_idx] = p_number(text, &tokens->elements[tokenidx]); - root = &expression[exp_idx]; - exp = &expression[exp_idx]; + if (token->type == t_number && root == NULL) { + *expr = p_number(text, token); + root = expr; + top = expr; exp_idx++; - } else if (tokens->elements[tokenidx].type == t_number && root != NULL && + } else if (token->type == t_number && root != NULL && root->type == e_number) { - fprintf(stderr, "Unexpected number at %d:%d\n", - tokens->elements[tokenidx].pos.line, - tokens->elements[tokenidx].pos.column); - return exp; + fprintf(stderr, "Unexpected number at %d:%d\n", token->pos.line, + token->pos.column); + return top; - } else if (tokens->elements[tokenidx].type == t_number && root != NULL && + } else if (token->type == t_number && root != NULL && root->type != e_number) { + + // Consequtive nullary expressions are invalid if (exp_idx > 0 && expression[exp_idx - 1].type == e_number) { - fprintf(stderr, "Unexpected number at %d:%d\n", - tokens->elements[tokenidx].pos.line, - tokens->elements[tokenidx].pos.column); - return exp; + fprintf(stderr, "Unexpected number at %d:%d\n", token->pos.line, + token->pos.column); + return top; } - expression[exp_idx] = p_number(text, &tokens->elements[tokenidx]); - root->data.e_binary.b = &expression[exp_idx]; + *expr = p_number(text, token); + root->data.e_binary.b = expr; // "pop" "root" stack here? - root = exp; + root = top; exp_idx++; - } else if (tokens->elements[tokenidx].type != t_number && root == NULL) { - fprintf(stderr, "Unexpected operator at %d:%d\n", - tokens->elements[tokenidx].pos.line, - tokens->elements[tokenidx].pos.column); - return exp; + } else if (token->type != t_number && root == NULL) { + fprintf(stderr, "Unexpected operator at %d:%d\n", token->pos.line, + token->pos.column); + return top; - } else if (tokens->elements[tokenidx].type != t_number && root != NULL) { + } else if (token->type != t_number && root != NULL) { - if (tokens->elements[tokenidx].type == t_multiply) { - expression[exp_idx] = (AExp_t){.type = e_mul}; - } else if (tokens->elements[tokenidx].type == t_divide) { - expression[exp_idx] = (AExp_t){.type = e_div}; - } else if (tokens->elements[tokenidx].type == t_add) { - expression[exp_idx] = (AExp_t){.type = e_add}; - } else if (tokens->elements[tokenidx].type == t_subtract) { - expression[exp_idx] = (AExp_t){.type = e_sub}; + if (token->type == t_multiply) { + *expr = (AExp_t){.type = e_mul}; + } else if (token->type == t_divide) { + *expr = (AExp_t){.type = e_div}; + } else if (token->type == t_add) { + *expr = (AExp_t){.type = e_add}; + } else if (token->type == t_subtract) { + *expr = (AExp_t){.type = e_sub}; } // Currently best way to test if "leaf" or binary operator, also only // binary are handled if (root->type == e_number) { - expression[exp_idx].data.e_binary.a = root; - root = &expression[exp_idx]; - exp = root; + expr->data.e_binary.a = root; + root = expr; + top = root; } else { - // Currently best way to test precendence (root < expression) :( - if ((expression[exp_idx].type == e_mul || - expression[exp_idx].type == e_div) && - (root->type == e_add || root->type == e_sub)) { - expression[exp_idx].data.e_binary.a = root->data.e_binary.b; - // TODO: check precedence of exp vs root - exp = root; - root->data.e_binary.b = &expression[exp_idx]; - root = &expression[exp_idx]; + // If expr has stronger precedence than root, yoink rhs of root + if (precedence_tbl[root->type].sum < precedence_tbl[expr->type].sum) { + expr->data.e_binary.a = root->data.e_binary.b; + // TODO: check precedence of top vs root + top = root; + root->data.e_binary.b = expr; + root = expr; } else { - expression[exp_idx].data.e_binary.a = root; - root = &expression[exp_idx]; - exp = root; + expr->data.e_binary.a = root; + root = expr; + top = root; } } @@ -427,12 +443,12 @@ p_arith(char const* restrict text, TokenList_t* restrict tokens) { // We store the "root" as the first element, returning a pointer to the // beginning of the memory also makes it much easier to free. - expression[0] = *exp; + expression[0] = *top; return expression; } static AExp_t -p_number(char const* restrict text, Token_t* restrict tnum) { +p_number(char const* restrict text, Token_t const* restrict tnum) { i32 number = 0; char* start = (char*)&text[tnum->pos.offset]; |
