harec

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

commit ed06275ff7d99a4d9a133ab9c789f435d529449e
parent 516a961cdf2e2ac3351685cfdf3af6400b36b68c
Author: Drew DeVault <sir@cmpwn.com>
Date:   Wed, 30 Dec 2020 13:32:09 -0500

parse: implement assertion expressions

Diffstat:
Minclude/ast.h | 7+++++++
Minclude/expr.h | 7+++++++
Minclude/lex.h | 6+++---
Msrc/lex.c | 15++++++++-------
Msrc/main.c | 2+-
Msrc/parse.c | 56+++++++++++++++++++++++++++++++++++++++++++++++++++++---
6 files changed, 79 insertions(+), 14 deletions(-)

diff --git a/include/ast.h b/include/ast.h @@ -112,6 +112,12 @@ struct ast_expression_access { }; }; +struct ast_expression_assert { + struct ast_expression *cond; + struct ast_expression *message; + bool is_static; +}; + struct ast_expression_assign { struct ast_expression *object, *value; bool indirect; @@ -227,6 +233,7 @@ struct ast_expression { enum expr_type type; union { struct ast_expression_access access; + struct ast_expression_assert assert; struct ast_expression_assign assign; struct ast_expression_binarithm binarithm; struct ast_expression_binding binding; diff --git a/include/expr.h b/include/expr.h @@ -48,6 +48,12 @@ struct expression_access { }; }; +struct expression_assert { + struct expression *cond; + struct expression *message; + bool is_static; +}; + struct expression_assign { struct expression *object, *value; bool indirect; @@ -179,6 +185,7 @@ struct expression { bool terminates; union { struct expression_access access; + struct expression_assert assert; struct expression_assign assign; struct expression_binarithm binarithm; struct expression_binding binding; diff --git a/include/lex.h b/include/lex.h @@ -5,14 +5,14 @@ // Keep sorted enum lexical_token { - T_AS, - T_ABORT, - T_ASSERT, T_ATTR_FINI, T_ATTR_INIT, T_ATTR_NORETURN, T_ATTR_SYMBOL, T_ATTR_TEST, + T_ABORT, + T_AS, + T_ASSERT, T_BOOL, T_BREAK, T_CHAR, diff --git a/src/lex.c b/src/lex.c @@ -14,7 +14,12 @@ #include "util.h" static const char *tokens[] = { - // Must be alpha sorted + // Must be alpha sorted and match lex.h + [T_ATTR_FINI] = "@fini", + [T_ATTR_INIT] = "@init", + [T_ATTR_NORETURN] = "@noreturn", + [T_ATTR_SYMBOL] = "@symbol", + [T_ATTR_TEST] = "@test", [T_ABORT] = "abort", [T_AS] = "as", [T_ASSERT] = "assert", @@ -64,11 +69,6 @@ static const char *tokens[] = { [T_USE] = "use", [T_VOID] = "void", [T_WHILE] = "while", - [T_ATTR_FINI] = "@fini", - [T_ATTR_INIT] = "@init", - [T_ATTR_NORETURN] = "@noreturn", - [T_ATTR_SYMBOL] = "@symbol", - [T_ATTR_TEST] = "@test", // Operators [T_ANDEQ] = "&=", @@ -985,7 +985,8 @@ token_str(const struct token *tok) int bytes = 0; switch (tok->token) { case T_NAME: - return tok->name; + snprintf(buf, sizeof(buf), "name %s", tok->name); + return buf; case T_LABEL: snprintf(buf, sizeof(buf), ":%s", tok->name); return buf; diff --git a/src/main.c b/src/main.c @@ -121,7 +121,7 @@ main(int argc, char *argv[]) lex_finish(&lexer); } - if (stage == STAGE_PARSE) { + if (stage == STAGE_PARSE || stage == STAGE_LEX) { return 0; } diff --git a/src/parse.c b/src/parse.c @@ -328,6 +328,8 @@ parse_primitive_type(struct lexer *lexer) static struct ast_expression *parse_simple_expression(struct lexer *lexer); static struct ast_expression *parse_complex_expression(struct lexer *lexer); static struct ast_expression *parse_compound_expression(struct lexer *lexer); +static struct ast_expression *parse_postfix_expression(struct lexer *lexer, + struct ast_expression *exp); static struct ast_expression *parse_scope_expression(struct lexer *lexer); static struct ast_expression *parse_binding_list(struct lexer *lexer); @@ -888,8 +890,55 @@ parse_plain_expression(struct lexer *lexer) assert(0); // Unreachable } -static struct ast_expression *parse_postfix_expression(struct lexer *lexer, - struct ast_expression *exp); +static struct ast_expression * +parse_assertion_expression(struct lexer *lexer) +{ + trace(TR_PARSE, "assertion"); + + struct ast_expression *exp = xcalloc(1, sizeof(struct ast_expression)); + exp->type = EXPR_ASSERT; + + struct token tok; + switch (lex(lexer, &tok)) { + case T_STATIC: + exp->assert.is_static = true; + lex(lexer, &tok); + break; + case T_ASSERT: + case T_ABORT: + break; + default: + synassert(false, &tok, T_STATIC, T_ASSERT, T_ABORT, T_EOF); + } + + switch (tok.token) { + case T_ASSERT: + want(lexer, T_LPAREN, &tok); + exp->assert.cond = parse_simple_expression(lexer); + if (lex(lexer, &tok) == T_COMMA) { + exp->assert.message = parse_constant(lexer); + } else { + unlex(lexer, &tok); + } + want(lexer, T_RPAREN, &tok); + break; + case T_ABORT: + if (exp->assert.is_static) { + synassert(false, &tok, T_ASSERT, T_EOF); + } + want(lexer, T_LPAREN, &tok); + if (lex(lexer, &tok) != T_RPAREN) { + unlex(lexer, &tok); + exp->assert.message = parse_constant(lexer); + want(lexer, T_RPAREN, &tok); + } + break; + default: + assert(0); // Invariant + } + + return exp; +} static struct ast_expression * parse_measurement_expression(struct lexer *lexer) @@ -1036,7 +1085,8 @@ parse_postfix_expression(struct lexer *lexer, struct ast_expression *lvalue) case T_ABORT: case T_ASSERT: case T_STATIC: - assert(0); // TODO: assertion expression + unlex(lexer, &tok); + return parse_assertion_expression(lexer); case T_SIZE: case T_LEN: case T_OFFSET: