harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit f664c18186054f8fe7f4e1a54c71ab5a5eb6b86b
parent 79f1461700b9db41bed4c5650e984045dac5e7d4
Author: Drew DeVault <sir@cmpwn.com>
Date:   Tue, 22 Dec 2020 14:01:48 -0500

parse: implement binary arithmetic

Diffstat:
Minclude/ast.h | 6++++++
Minclude/expr.h | 28++++++++++++++++++++++++++++
Minclude/lex.h | 6+++---
Msrc/check.c | 1+
Msrc/lex.c | 8++++----
Msrc/parse.c | 223++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
6 files changed, 236 insertions(+), 36 deletions(-)

diff --git a/include/ast.h b/include/ast.h @@ -88,6 +88,11 @@ struct ast_expression_access { struct identifier ident; }; +struct ast_expression_binarithm { + enum binarithm_operator op; + struct ast_expression *lvalue, *rvalue; +}; + struct ast_expression_binding { char *name; struct ast_type *type; @@ -121,6 +126,7 @@ struct ast_expression { enum expr_type type; union { struct ast_expression_access access; + struct ast_expression_binarithm binarithm; struct ast_expression_binding binding; struct ast_expression_constant constant; struct ast_expression_list list; diff --git a/include/expr.h b/include/expr.h @@ -37,6 +37,34 @@ struct expression_access { const struct scope_object *object; }; +enum binarithm_operator { + BIN_BAND, + BIN_BNOT, + BIN_BOR, + BIN_DIV, + BIN_GREATER, + BIN_GREATEREQ, + BIN_LAND, + BIN_LEQUAL, + BIN_LESS, + BIN_LESSEQ, + BIN_LOR, + BIN_LSHIFT, + BIN_LXOR, + BIN_MINUS, + BIN_MODULO, + BIN_NEQUAL, + BIN_PLUS, + BIN_RSHIFT, + BIN_TIMES, + BIN_BXOR, +}; + +struct expression_binarithm { + enum binarithm_operator op; + struct expression *lvalue, *rvalue; +}; + struct expression_binding { const struct scope_object *object; struct expression *initializer; diff --git a/include/lex.h b/include/lex.h @@ -107,9 +107,9 @@ enum lexical_token { T_SLICE, T_TIMES, T_TIMESEQ, - T_XOR, - T_XOREQ, - T_LAST_OPERATOR = T_XOREQ, + T_BXOR, + T_BXOREQ, + T_LAST_OPERATOR = T_BXOREQ, // Tokens with additional information T_LABEL, diff --git a/src/check.c b/src/check.c @@ -212,6 +212,7 @@ check_expression(struct context *ctx, break; case EXPR_ASSERT: case EXPR_ASSIGN: + assert(0); // TODO case EXPR_BINARITHM: assert(0); // TODO case EXPR_BINDING: diff --git a/src/lex.c b/src/lex.c @@ -115,8 +115,8 @@ static const char *tokens[] = { [T_SLICE] = "..", [T_TIMES] = "*", [T_TIMESEQ] = "*=", - [T_XOR] = "^", - [T_XOREQ] = "^=", + [T_BXOR] = "^", + [T_BXOREQ] = "^=", }; void @@ -625,11 +625,11 @@ lex2(struct lexer *lexer, struct token *out, uint32_t c) out->token = T_LXOR; break; case '=': - out->token = T_XOREQ; + out->token = T_BXOREQ; break; default: push(lexer, c, false); - out->token = T_XOR; + out->token = T_BXOR; break; } break; diff --git a/src/parse.c b/src/parse.c @@ -65,6 +65,43 @@ want(struct parser *par, enum lexical_token ltok, struct token *tok) } } +// Returns true if this token may be the first token of a complex-expression +/* +static bool +is_expr_start(struct token *tok) +{ + switch (tok->token) { + case T_ABORT: + case T_ASSERT: + case T_FALSE: + case T_FOR: + case T_IF: + case T_LEN: + case T_MATCH: + case T_NULL: + case T_RUNE: + case T_STRUCT: + case T_SWITCH: + case T_TRUE: + case T_UNION: + case T_VOID: + case T_WHILE: + case T_LNOT: + case T_LPAREN: + case T_MINUS: + case T_PLUS: + case T_TIMES: + case T_LABEL: + case T_LITERAL: + case T_NAME: + return true; + default: + return false; + } + assert(0); // Unreachable +} +*/ + static void parse_identifier(struct parser *par, struct identifier *ident) { @@ -339,6 +376,7 @@ static void parse_complex_expression(struct parser *par, static void parse_simple_expression(struct parser *par, struct ast_expression *exp); +/* static void parse_access(struct parser *par, struct ast_expression *exp) { @@ -347,6 +385,7 @@ parse_access(struct parser *par, struct ast_expression *exp) parse_identifier(par, &exp->access.ident); trleave(TR_PARSE, NULL); } +*/ static void parse_binding_list(struct parser *par, struct ast_expression *exp) @@ -363,6 +402,8 @@ parse_binding_list(struct parser *par, struct ast_expression *exp) case T_LET: // no-op break; + case T_STATIC: + assert(0); // TODO default: synassert(false, &tok, T_LET, T_CONST, T_EOF); } @@ -450,46 +491,168 @@ parse_constant(struct parser *par, struct ast_expression *exp) } static void -parse_simple_expression(struct parser *par, struct ast_expression *exp) +parse_cast_expression(struct parser *par, struct ast_expression *exp) { - trenter(TR_PARSE, "simple-expression"); + parse_constant(par, exp); // TODO +} - // TODO: This will need to be refactored once we finish the grammar - // connecting postfix-expression to logical-or-expression - struct token tok = {0}; - lex(par->lex, &tok); - switch (tok.token) { - // plain-expression - case T_NAME: - unlex(par->lex, &tok); - parse_access(par, exp); - break; - case T_LITERAL: - unlex(par->lex, &tok); - parse_constant(par, exp); - break; - case T_LBRACKET: - assert(0); // TODO: array/slice literal - case T_LBRACE: - assert(0); // TODO: array/slice literal - // nested-expression - case T_LPAREN: - assert(0); // TODO: nested-expression - // syntax error +static int +precedence(enum lexical_token token) +{ + switch (token) { + case T_LOR: + return 0; + case T_LAND: + return 1; + case T_BOR: + return 2; + case T_BXOR: + return 3; + case T_BAND: + return 4; + case T_LEQUAL: + case T_NEQUAL: + return 5; + case T_LESS: + case T_LESSEQ: + case T_GREATER: + case T_GREATEREQ: + return 6; + case T_LSHIFT: + case T_RSHIFT: + return 7; + case T_PLUS: + case T_MINUS: + return 8; + case T_TIMES: + case T_DIV: + case T_MODULO: + return 9; default: - synassert(false, &tok, T_LITERAL, T_NAME, T_EOF); - break; + return -1; } + assert(0); // Unreachable +} - trleave(TR_PARSE, NULL); +static enum binarithm_operator +binop_for_token(enum lexical_token tok) +{ + switch (tok) { + case T_LOR: + return BIN_LOR; + case T_LAND: + return BIN_LAND; + case T_BOR: + return BIN_BOR; + case T_BXOR: + return BIN_BXOR; + case T_BAND: + return BIN_BAND; + case T_LEQUAL: + return BIN_LEQUAL; + case T_NEQUAL: + return BIN_NEQUAL; + case T_LESS: + return BIN_LESS; + case T_LESSEQ: + return BIN_LESSEQ; + case T_GREATER: + return BIN_GREATER; + case T_GREATEREQ: + return BIN_GREATEREQ; + case T_LSHIFT: + return BIN_LSHIFT; + case T_RSHIFT: + return BIN_RSHIFT; + case T_PLUS: + return BIN_PLUS; + case T_MINUS: + return BIN_MINUS; + case T_TIMES: + return BIN_TIMES; + case T_DIV: + return BIN_DIV; + case T_MODULO: + return BIN_MODULO; + default: + assert(0); // Invariant + } + assert(0); // Unreachable +} + +static void +parse_bin_expression2(struct parser *par, struct ast_expression *exp, + struct ast_expression *lvalue, int i) +{ + if (!lvalue) { + // XXX: This probably creates a memory leak + lvalue = calloc(1, sizeof(struct ast_expression)); + parse_cast_expression(par, lvalue); + } + + struct token tok; + lex(par->lex, &tok); + + int j; + while ((j = precedence(tok.token)) >= i) { + exp->type = EXPR_BINARITHM; + exp->binarithm.op = binop_for_token(tok.token); + + struct ast_expression *rvalue = + calloc(1, sizeof(struct ast_expression)); + parse_cast_expression(par, rvalue); + + lex(par->lex, &tok); + + int k; + while ((k = precedence(tok.token)) > j) { + struct ast_expression *rvalue2 = + calloc(1, sizeof(struct ast_expression)); + unlex(par->lex, &tok); + parse_bin_expression2(par, rvalue2, rvalue, k); + rvalue = rvalue2; + lex(par->lex, &tok); + } + + exp->binarithm.lvalue = lvalue; + exp->binarithm.rvalue = rvalue; + lvalue = exp; + } + + unlex(par->lex, &tok); + *exp = *lvalue; +} + +static void +parse_bin_expression(struct parser *par, struct ast_expression *exp) +{ + parse_bin_expression2(par, exp, NULL, 0); +} + +static void +parse_simple_expression(struct parser *par, struct ast_expression *exp) +{ + parse_bin_expression(par, exp); } static void parse_complex_expression(struct parser *par, struct ast_expression *exp) { - // TODO: other complex expressions trenter(TR_PARSE, "complex-expression"); - parse_simple_expression(par, exp); + + struct token tok; + switch (lex(par->lex, &tok)) { + case T_IF: + case T_FOR: + case T_MATCH: + case T_SWITCH: + assert(0); // TODO + default: + unlex(par->lex, &tok); + parse_simple_expression(par, exp); + break; + } + trleave(TR_PARSE, NULL); } @@ -505,6 +668,8 @@ parse_scope_expression(struct parser *par, struct ast_expression *exp) unlex(par->lex, &tok); parse_binding_list(par, exp); break; + case T_STATIC: + assert(0); // Binding list or assert default: unlex(par->lex, &tok); parse_complex_expression(par, exp);