From bf4aa41a445986658f4ee931305d9caf496e9072 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Sun, 16 Jun 2024 21:36:49 +0200 Subject: Add parsing for logical operators --- Makefile | 2 +- src/main.c | 99 ++++++++++++++++++++++++++++++++++++++++++++------- tests/comparisons.bad | 13 +++++++ 3 files changed, 101 insertions(+), 13 deletions(-) create mode 100644 tests/comparisons.bad diff --git a/Makefile b/Makefile index 7fed16b..082ab87 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ SRC_DIR := src BUILD_DIR := build SRC_MAIN := $(SRC_DIR)/main.c -SRC_BAD := tests/expressions.bad +SRC_BAD := tests/comparisons.bad WATCH_SRC := $(shell find $(SRC_DIR) -name "*.c" -or -name "*.s" -or -name "*.h") INC_DIRS := $(shell find $(SRC_DIR) -type d) INC_FLAGS := $(addprefix -I,$(INC_DIRS)) diff --git a/src/main.c b/src/main.c index f15afed..1c71a6e 100644 --- a/src/main.c +++ b/src/main.c @@ -39,14 +39,28 @@ print_tokens(Str path, Token *tokens) { // typedef enum NodeKind { - NODE_NUM_INT, - NODE_NUM_FLOAT, - // TODO: probably want to handle ints/unsigneds/floats separately. + // Arithmetic. NODE_ADD, NODE_SUB, NODE_DIV, NODE_MUL, NODE_MOD, + // Logical. + NODE_NOT, + NODE_AND, + NODE_OR, + NODE_EQ, + NODE_NOTEQ, + NODE_LT, + NODE_GT, + NODE_LE, + NODE_GE, + // Literals. + NODE_NUM_INT, + NODE_NUM_FLOAT, + NODE_TRUE, + NODE_FALSE, + NODE_NIL, } NodeKind; Str node_str[] = { @@ -56,10 +70,22 @@ Str node_str[] = { [NODE_DIV] = cstr("DIV"), [NODE_MUL] = cstr("MUL"), [NODE_MOD] = cstr("MOD"), - + // Logical. + [NODE_NOT] = cstr("NOT"), + [NODE_AND] = cstr("AND"), + [NODE_OR] = cstr("OR"), + [NODE_EQ] = cstr("EQ"), + [NODE_NOTEQ] = cstr("NOTEQ"), + [NODE_LT] = cstr("LT"), + [NODE_GT] = cstr("GT"), + [NODE_LE] = cstr("LE"), + [NODE_GE] = cstr("GE"), // Literals. [NODE_NUM_INT] = cstr("INT"), [NODE_NUM_FLOAT] = cstr("FLOAT"), + [NODE_TRUE] = cstr("TRUE"), + [NODE_FALSE] = cstr("FALSE"), + [NODE_NIL] = cstr("NIL"), }; typedef struct Node { @@ -135,16 +161,32 @@ void parse_grouping(Parser *parser); void parse_unary(Parser *parser); void parse_binary(Parser *parser); void parse_number(Parser *parser); +void parse_literal(Parser *parser); ParseRule parse_rules[] = { [TOK_LPAREN] = {parse_grouping, NULL, PREC_NONE}, + // Arithmetic. [TOK_SUB] = {parse_unary, parse_binary, PREC_TERM}, [TOK_ADD] = {NULL, parse_binary, PREC_TERM}, [TOK_DIV] = {NULL, parse_binary, PREC_FACTOR}, [TOK_MUL] = {NULL, parse_binary, PREC_FACTOR}, [TOK_MOD] = {NULL, parse_binary, PREC_FACTOR}, + // Logical. + [TOK_NOT] = {parse_unary, NULL, PREC_NONE}, + [TOK_AND] = {NULL, parse_binary, PREC_AND}, + [TOK_OR] = {NULL, parse_binary, PREC_OR}, + [TOK_EQ] = {NULL, parse_binary, PREC_EQUALITY}, + [TOK_NOTEQ] = {NULL, parse_binary, PREC_EQUALITY}, + [TOK_LT] = {NULL, parse_binary, PREC_COMPARISON}, + [TOK_GT] = {NULL, parse_binary, PREC_COMPARISON}, + [TOK_LE] = {NULL, parse_binary, PREC_COMPARISON}, + [TOK_GE] = {NULL, parse_binary, PREC_COMPARISON}, + // Literals. [TOK_NUM_INT] = {parse_number, NULL, PREC_NONE}, [TOK_NUM_FLOAT] = {parse_number, NULL, PREC_NONE}, + [TOK_TRUE] = {parse_literal, NULL, PREC_NONE}, + [TOK_FALSE] = {parse_literal, NULL, PREC_NONE}, + [TOK_NIL] = {parse_literal, NULL, PREC_NONE}, [TOK_EOF] = {NULL, NULL, PREC_NONE}, }; @@ -209,13 +251,37 @@ parse_unary(Parser *parser) { print("parsing unary "); print_token(prev); #endif - TokenKind kind = prev.kind; - parse_expr(parser, PREC_LOW); - // TODO: ... - switch (kind) { - // case TOKEN_MINUS: emitByte(OP_NEGATE); break; + parse_expr(parser, PREC_UNARY); + Node *node = NULL; + switch (prev.kind) { + case TOK_NOT: node = node_alloc(NODE_NOT, prev, parser->storage); break; + default: break; // Unreachable. + } + node->left = array_pop(parser->nodes); + array_push(parser->nodes, node, parser->storage); +} + +void +parse_literal(Parser *parser) { + Token prev = parser->previous; +#if DEBUG == 1 + print("parsing literal "); + print_token(prev); +#endif + Node *node = NULL; + switch (prev.kind) { + case TOK_TRUE: { + node = node_alloc(NODE_TRUE, prev, parser->storage); + } break; + case TOK_FALSE: { + node = node_alloc(NODE_FALSE, prev, parser->storage); + } break; + case TOK_NIL: { + node = node_alloc(NODE_NIL, prev, parser->storage); + } break; default: return; // Unreachable. } + array_push(parser->nodes, node, parser->storage); } void @@ -225,17 +291,26 @@ parse_binary(Parser *parser) { print("parsing binary "); print_token(prev); #endif - TokenKind kind = prev.kind; - ParseRule rule = parse_rules[kind]; + ParseRule rule = parse_rules[prev.kind]; parse_expr(parser, rule.precedence + 1); Node *node; - switch (kind) { + switch (prev.kind) { case TOK_ADD: node = node_alloc(NODE_ADD, prev, parser->storage); break; case TOK_SUB: node = node_alloc(NODE_SUB, prev, parser->storage); break; case TOK_MUL: node = node_alloc(NODE_MUL, prev, parser->storage); break; case TOK_DIV: node = node_alloc(NODE_DIV, prev, parser->storage); break; case TOK_MOD: node = node_alloc(NODE_MOD, prev, parser->storage); break; + case TOK_AND: node = node_alloc(NODE_AND, prev, parser->storage); break; + case TOK_OR: node = node_alloc(NODE_OR, prev, parser->storage); break; + case TOK_EQ: node = node_alloc(NODE_EQ, prev, parser->storage); break; + case TOK_NOTEQ: + node = node_alloc(NODE_NOTEQ, prev, parser->storage); + break; + case TOK_LT: node = node_alloc(NODE_LT, prev, parser->storage); break; + case TOK_GT: node = node_alloc(NODE_GT, prev, parser->storage); break; + case TOK_LE: node = node_alloc(NODE_LE, prev, parser->storage); break; + case TOK_GE: node = node_alloc(NODE_GE, prev, parser->storage); break; default: { parse_emit_err(parser, prev, cstr("unreachable")); return; diff --git a/tests/comparisons.bad b/tests/comparisons.bad new file mode 100644 index 0000000..7bc5d33 --- /dev/null +++ b/tests/comparisons.bad @@ -0,0 +1,13 @@ +true != false +!true == false +!(true == !false) != true +(true == true) != true != false +!(true || false) + +2 >= 1 && 2 > 1 +3 >= 3 || 4 <= 5 +4 < (5 + 6) == true + +nil != false +nil != true +nil != 1 -- cgit v1.2.1