diff options
author | Himbeer <himbeer@disroot.org> | 2024-09-25 19:20:04 +0200 |
---|---|---|
committer | Himbeer <himbeer@disroot.org> | 2024-09-25 19:20:04 +0200 |
commit | 91730d20c1c2befe5ccb52f63f2d4200393ae291 (patch) | |
tree | c8410e69b5ab477a200ff9f9f7731f472f8592e7 | |
parent | b740cc6f1e4c4ac77b4720316ef2e2854cb73a12 (diff) |
Implement expression parsing
-rw-r--r-- | include/expr.h | 20 | ||||
-rw-r--r-- | src/parse.c | 504 |
2 files changed, 513 insertions, 11 deletions
diff --git a/include/expr.h b/include/expr.h index 93b9204..8b4d8b0 100644 --- a/include/expr.h +++ b/include/expr.h @@ -4,10 +4,6 @@ #include "lex.h" #include "type.h" -struct grouping_e { - struct disjunction_e *inner; -}; - struct number_e { struct number value; struct type type; @@ -30,7 +26,7 @@ struct literal_e { enum literal kind; union { bool b; - const char *str; + char *str; struct number_e num; struct array_e arr; } lit; @@ -57,7 +53,7 @@ enum primary { struct primary_e { enum primary kind; union { - struct grouping_e grp; + struct disjunction_e *grp; struct literal_e lit; struct call_e call; struct path path; @@ -65,6 +61,7 @@ struct primary_e { }; enum unary_postfix { + UPS_NONE, UPS_DEREF, UPS_TRY, UPS_ASSERT, @@ -76,9 +73,10 @@ struct unarypost_e { }; enum unary_prefix { - UPR_NUMNEG, - UPR_BOOLNEG, - UPR_BITNEG, + UPR_NONE, + UPR_NEG, + UPR_INVERT, + UPR_BNEG, }; struct unarypre_e { @@ -142,7 +140,7 @@ enum term { struct term_e { enum term term; - struct num_e lhs, rhs; + struct num_e lhs, *rhs; }; enum comparison { @@ -165,7 +163,7 @@ struct cmp_e { struct eq_e { bool invert; - struct cmp_e lhs, rhs; + struct cmp_e lhs, *rhs; }; enum boolean { diff --git a/src/parse.c b/src/parse.c index ef4f4dc..8789d37 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1,9 +1,15 @@ +#define _POSIX_C_SOURCE 200809L + #include <stdarg.h> #include <stdlib.h> #include <stdnoreturn.h> +#include <string.h> #include "parse.h" #include "util.h" +static bool parse_disjunction_e(struct lexer *lexer, + struct disjunction_e *out); + static noreturn void error(struct location loc, const char *fmt, ...) { @@ -55,6 +61,504 @@ parse_path(struct lexer *lexer, struct path *out) } static bool +parse_grouping_e(struct lexer *lexer, struct disjunction_e *out) +{ + if (!match(lexer, T_LPAREN)) { + return false; + } + + if (!parse_disjunction_e(lexer, out)) { + error(lex_loc(lexer), "syntax error: expected expression"); + } + + if (!match(lexer, T_RPAREN)) { + error(lex_loc(lexer), "syntax error: expected ')'"); + } + + return true; +} + +static bool +parse_literal_e(struct lexer *lexer, struct literal_e *out) +{ + /* TODO */ + error(lex_loc(lexer), "unimplemented: literals"); +} + +// Invariant: Only called from parse_primary_e with path already consumed. +static bool +parse_call_e(struct lexer *lexer, struct call_e *out, struct path path) +{ + if (!match(lexer, T_LPAREN)) { + return false; + } + + out->path = path; + out->args = must_calloc(1, sizeof(struct disjunction_e)); + out->argsz = 1; + out->arglen = 0; + + struct disjunction_e expr; + while (parse_disjunction_e(lexer, &expr)) { + if (out->arglen >= out->argsz) { + out->argsz *= 2; + size_t sz = sizeof(struct disjunction_e) * out->argsz; + out->args = must_realloc(out->args, sz); + } + out->args[out->arglen++] = expr; + } + + if (!match(lexer, T_RPAREN)) { + error(lex_loc(lexer), "syntax error: expected ')'"); + } + + return true; +} + +static bool +parse_primary_e(struct lexer *lexer, struct primary_e *out) +{ + out->prim.grp = must_malloc(sizeof(struct disjunction_e)); + if (parse_grouping_e(lexer, out->prim.grp)) { + out->kind = PRM_GROUPING; + return true; + } + free(out->prim.grp); + if (parse_literal_e(lexer, &out->prim.lit)) { + out->kind = PRM_LITERAL; + return true; + } + if (parse_path(lexer, &out->prim.path)) { + out->kind = PRM_PATH; + if (parse_call_e(lexer, &out->prim.call, out->prim.path)) { + out->kind = PRM_CALL; + } + return true; + } +} + +static bool +parse_unarypost_e(struct lexer *lexer, struct unarypost_e *out) +{ + if (!parse_primary_e(lexer, &out->prim)) { + return false; + } + + if (match(lexer, T_STAR)) { + out->op = UPS_DEREF; + } else if (match(lexer, T_QUESTION)) { + out->op = UPS_TRY; + } else if (match(lexer, T_BANG)) { + out->op = UPS_ASSERT; + } else { + out->op = UPS_NONE; + } + + return true; +} + +static bool +parse_unarypre_e(struct lexer *lexer, struct unarypre_e *out) +{ + if (match(lexer, T_MINUS)) { + out->op = UPR_NEG; + } else if (match(lexer, T_BANG)) { + out->op = UPR_INVERT; + } else if (match(lexer, T_BNOT)) { + out->op = UPR_BNEG; + } else { + out->op = UPR_NONE; + } + + if (!parse_unarypost_e(lexer, &out->post)) { + error(lex_loc(lexer), + "syntax error: expected unary postfix expression"); + } + + return true; +} + +static bool +parse_bitfactor_rhs(struct lexer *lexer, struct unarypre_e *out) +{ + if (!match(lexer, T_BAND)) { + return false; + } + + if (!parse_unarypre_e(lexer, out)) { + error(lex_loc(lexer), + "syntax error: expected unary prefix expression"); + } + + return true; +} + +static bool +parse_bitfactor_e(struct lexer *lexer, struct bitfactor_e *out) +{ + if (!parse_unarypre_e(lexer, &out->lhs)) { + return false; + } + + out->rhs = must_calloc(1, sizeof(struct unarypre_e)); + out->rhssz = 1; + out->rhslen = 0; + + struct unarypre_e rhs; + while (parse_bitfactor_rhs(lexer, &rhs)) { + if (out->rhslen >= out->rhssz) { + out->rhssz *= 2; + size_t sz = sizeof(struct unarypre_e) * out->rhssz; + out->rhs = must_realloc(out->rhs, sz); + } + out->rhs[out->rhslen++] = rhs; + } + + return true; +} + +static bool +parse_bitsummand_rhs(struct lexer *lexer, struct bitfactor_e *out) +{ + if (!match(lexer, T_BXOR)) { + return false; + } + + if (!parse_bitfactor_e(lexer, out)) { + error(lex_loc(lexer), "syntax error: expected bit factor"); + } + + return true; +} + +static bool +parse_bitsummand_e(struct lexer *lexer, struct bitsummand_e *out) +{ + if (!parse_bitfactor_e(lexer, &out->lhs)) { + return false; + } + + out->rhs = must_calloc(1, sizeof(struct bitfactor_e)); + out->rhssz = 1; + out->rhslen = 0; + + struct bitfactor_e rhs; + while (parse_bitsummand_rhs(lexer, &rhs)) { + if (out->rhslen >= out->rhssz) { + out->rhssz *= 2; + size_t sz = sizeof(struct bitfactor_e) * out->rhssz; + out->rhs = must_realloc(out->rhs, sz); + } + out->rhs[out->rhslen++] = rhs; + } + + return true; +} + +static bool +parse_bin_rhs(struct lexer *lexer, struct bitsummand_e *out) +{ + if (!match(lexer, T_BOR)) { + return false; + } + + if (!parse_bitsummand_e(lexer, out)) { + error(lex_loc(lexer), "syntax error: expected bit summand"); + } + + return true; +} + +static bool +parse_bin_e(struct lexer *lexer, struct bin_e *out) +{ + if (!parse_bitsummand_e(lexer, &out->lhs)) { + return false; + } + + out->rhs = must_calloc(1, sizeof(struct bitsummand_e)); + out->rhssz = 1; + out->rhslen = 0; + + struct bitsummand_e rhs; + while (parse_bin_rhs(lexer, &rhs)) { + if (out->rhslen >= out->rhssz) { + out->rhssz *= 2; + size_t sz = sizeof(struct bitsummand_e) * out->rhssz; + out->rhs = must_realloc(out->rhs, sz); + } + out->rhs[out->rhslen++] = rhs; + } + + return true; +} + +static bool +parse_factor_rhs(struct lexer *lexer, struct factor_rhs *out) +{ + if (match(lexer, T_STAR)) { + out->factor = FCT_MUL; + } else if (match(lexer, T_DIV)) { + out->factor = FCT_DIV; + } else if (match(lexer, T_MODULO)) { + out->factor = FCT_REM; + } else { + return false; + } + + if (!parse_bin_e(lexer, &out->bin)) { + error(lex_loc(lexer), + "syntax error: expected bitwise expression"); + } + + return true; +} + +static bool +parse_factor_e(struct lexer *lexer, struct factor_e *out) +{ + if (!parse_bin_e(lexer, &out->lhs)) { + return false; + } + + out->rhs = must_calloc(1, sizeof(struct factor_rhs)); + out->rhssz = 1; + out->rhslen = 0; + + struct factor_rhs rhs; + while (parse_factor_rhs(lexer, &rhs)) { + if (out->rhslen >= out->rhssz) { + out->rhssz *= 2; + size_t sz = sizeof(struct factor_rhs) * out->rhssz; + out->rhs = must_realloc(out->rhs, sz); + } + out->rhs[out->rhslen++] = rhs; + } + + return true; +} + +static bool +parse_num_rhs(struct lexer *lexer, struct num_rhs *out) +{ + if (match(lexer, T_ADD)) { + out->num = NUM_ADD; + } else if (match(lexer, T_MINUS)) { + out->num = NUM_SUB; + } else { + return false; + } + + if (!parse_factor_e(lexer, &out->factor)) { + error(lex_loc(lexer), + "syntax error: expected factor expression"); + } + + return true; +} + +static bool +parse_num_e(struct lexer *lexer, struct num_e *out) +{ + if (!parse_factor_e(lexer, &out->lhs)) { + return false; + } + + out->rhs = must_calloc(1, sizeof(struct num_rhs)); + out->rhssz = 1; + out->rhslen = 0; + + struct num_rhs rhs; + while (parse_num_rhs(lexer, &rhs)) { + if (out->rhslen >= out->rhssz) { + out->rhssz *= 2; + size_t sz = sizeof(struct num_rhs) * out->rhssz; + out->rhs = must_realloc(out->rhs, sz); + } + out->rhs[out->rhslen++] = rhs; + } + + return true; +} + +static bool +parse_term_e(struct lexer *lexer, struct term_e *out) +{ + if (!parse_num_e(lexer, &out->lhs)) { + return false; + } + + if (match(lexer, T_BSHL)) { + out->term = TRM_SHL; + } else if (match(lexer, T_BSHR)) { + out->term = TRM_SHL; + } else { + out->term = TRM_NUM; + out->rhs = NULL; + return true; + } + + out->rhs = must_malloc(sizeof(struct num_e)); + if (!parse_num_e(lexer, out->rhs)) { + error(lex_loc(lexer), + "syntax error: expected numeral expression"); + } + + return true; +} + +static bool +parse_comparison_rhs(struct lexer *lexer, struct cmp_rhs *out) +{ + if (match(lexer, T_LT)) { + out->cmp = CMP_LT; + } else if (match(lexer, T_LE)) { + out->cmp = CMP_LE; + } else if (match(lexer, T_GT)) { + out->cmp = CMP_GT; + } else if (match(lexer, T_GE)) { + out->cmp = CMP_GE; + } else { + return false; + } + + if (!parse_term_e(lexer, &out->term)) { + error(lex_loc(lexer), "syntax error: expected term"); + } + + return true; +} + +static bool +parse_comparison_e(struct lexer *lexer, struct cmp_e *out) +{ + if (!parse_term_e(lexer, &out->lhs)) { + return false; + } + + out->rhs = must_calloc(1, sizeof(struct cmp_rhs)); + out->rhssz = 1; + out->rhslen = 0; + + struct cmp_rhs rhs; + while (parse_comparison_rhs(lexer, &rhs)) { + if (out->rhslen >= out->rhssz) { + out->rhssz *= 2; + size_t sz = sizeof(struct cmp_rhs) * out->rhssz; + out->rhs = must_realloc(out->rhs, sz); + } + out->rhs[out->rhslen++] = rhs; + } + + return true; +} + +static bool +parse_equality_e(struct lexer *lexer, struct eq_e *out) +{ + if (!parse_comparison_e(lexer, &out->lhs)) { + return false; + } + + if (match(lexer, T_EQ)) { + out->invert = false; + } else if (match(lexer, T_NEQ)) { + out->invert = true; + } else { + out->rhs = NULL; + return true; + } + + out->rhs = must_malloc(sizeof(struct cmp_e)); + if (!parse_comparison_e(lexer, out->rhs)) { + error(lex_loc(lexer), "syntax error: expected comparison"); + } + + return true; +} + +static bool +parse_bool_e(struct lexer *lexer, struct bool_e *out) +{ + if (parse_equality_e(lexer, &out->cond.eq)) { + out->kind = B_EQ; + return true; + } + if (parse_comparison_e(lexer, &out->cond.cmp)) { + out->kind = B_CMP; + return true; + } + + return false; +} + +static bool +parse_conjunction_e(struct lexer *lexer, struct conjunction_e *out) +{ + out->bools = must_calloc(1, sizeof(struct bool_e)); + out->boolsz = 1; + out->boollen = 0; + + struct bool_e b; + if (!parse_bool_e(lexer, &b)) { + return false; + } + out->bools[out->boollen++] = b; + + while (match(lexer, T_AND)) { + if (!parse_bool_e(lexer, &b)) { + error(lex_loc(lexer), + "syntax error: expected boolean expression"); + } + + if (out->boollen >= out->boolsz) { + out->boolsz *= 2; + size_t sz = sizeof(struct bool_e) * out->boolsz; + out->bools = must_realloc(out->bools, sz); + } + out->bools[out->boollen++] = b; + } + + return true; +} + +static bool +parse_disjunction_e(struct lexer *lexer, struct disjunction_e *out) +{ + out->cons = must_calloc(1, sizeof(struct conjunction_e)); + out->consz = 1; + out->conlen = 0; + + struct conjunction_e con; + if (!parse_conjunction_e(lexer, &con)) { + return false; + } + out->cons[out->conlen++] = con; + + while (match(lexer, T_OR)) { + if (!parse_conjunction_e(lexer, &con)) { + error(lex_loc(lexer), + "syntax error: expected conjunction"); + } + + if (out->conlen >= out->consz) { + out->consz *= 2; + size_t sz = sizeof(struct conjunction_e) * out->consz; + out->cons = must_realloc(out->cons, sz); + } + out->cons[out->conlen++] = con; + } + + return true; +} + +static bool +parse_expr(struct lexer *lexer, struct ast_expr *out) +{ + return !parse_disjunction_e(lexer, &out->dis); +} + +static bool parse_import(struct lexer *lexer, struct ast_import *out) { if (!match(lexer, T_IMPORT)) { |