diff --git a/doc/grammar.bnf b/doc/grammar.bnf index 1c938c8..a067bb9 100644 --- a/doc/grammar.bnf +++ b/doc/grammar.bnf @@ -1,4 +1,11 @@ ROOT ::= EXPR* -EXPR ::= BUILTIN +EXPR ::= TERM +TERM ::= FACTOR ((add|sub) FACTOR)* +FACTOR ::= USUB ((mul|div|mod) USUB)* +USUB ::= sub* POW +POW ::= LITERAL (pow LITERAL)? +LITERAL ::= +| BUILTIN +| opar EXPR cpar BUILTIN ::= | int diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index e21a5f6..cce0a2d 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -42,6 +42,10 @@ target_include_directories(skopy-lib PUBLIC ${CMAKE_SOURCE_DIR}/lib/include ) +target_link_options(skopy-lib + PUBLIC -lm +) + target_compile_options(skopy-lib PUBLIC -Wall -Wextra -g ) diff --git a/lib/include/commons.h b/lib/include/commons.h index aedde43..658d560 100644 --- a/lib/include/commons.h +++ b/lib/include/commons.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "str.h" #include "vec.h" diff --git a/lib/include/compiler.h b/lib/include/compiler.h index 9109439..5f4c0c6 100644 --- a/lib/include/compiler.h +++ b/lib/include/compiler.h @@ -15,5 +15,8 @@ void compiler_compile(struct compiler* self, struct node* node, struct prog* prog); +void compiler_compile_children(struct compiler* self, + struct node* node, + struct prog* prog); #endif diff --git a/lib/include/lexer.h b/lib/include/lexer.h index 97e759b..1c4e236 100644 --- a/lib/include/lexer.h +++ b/lib/include/lexer.h @@ -24,7 +24,11 @@ void lexer_skip_spaces(struct lexer* self); bool lexer_next_is(struct lexer* self, TokenKind kind); +void lexer_consume_next(struct lexer* self); struct token* lexer_try_new_next(struct lexer* self); struct token* lexer_try_scan_int(struct lexer* self); +struct token* lexer_try_scan_text(struct lexer* self, + char const* text, + TokenKind kind); #endif diff --git a/lib/include/node.h b/lib/include/node.h index 02b95c2..002754e 100644 --- a/lib/include/node.h +++ b/lib/include/node.h @@ -5,7 +5,10 @@ #define NODE_KIND(G) \ G(NODE_ROOT), \ -G(NODE_INT) +G(NODE_INT), \ +G(NODE_ADD), G(NODE_SUB), G(NODE_MUL),\ +G(NODE_DIV), G(NODE_POW), G(NODE_MOD),\ +G(NODE_USUB) SK_ENUM_H(NodeKind, NODE_KIND); diff --git a/lib/include/parser.h b/lib/include/parser.h index 2f38076..34d757e 100644 --- a/lib/include/parser.h +++ b/lib/include/parser.h @@ -19,6 +19,11 @@ struct node* parser_try(struct parser* self, struct node* parser_try_parse(struct parser* self); struct node* parser_try_root(struct parser* self); struct node* parser_try_expr(struct parser* self); +struct node* parser_try_term(struct parser* self); +struct node* parser_try_factor(struct parser* self); +struct node* parser_try_usub(struct parser* self); +struct node* parser_try_pow(struct parser* self); +struct node* parser_try_literal(struct parser* self); struct node* parser_try_builtin(struct parser* self); #endif diff --git a/lib/include/prog.h b/lib/include/prog.h index 7bbab95..e4a81f7 100644 --- a/lib/include/prog.h +++ b/lib/include/prog.h @@ -6,7 +6,10 @@ #define SK_NO_PARAM (-1) #define OPCODE(G) \ -G(OP_PUSH) +G(OP_PUSH), \ +G(OP_ADD), G(OP_SUB), G(OP_MUL), \ +G(OP_DIV), G(OP_MOD), G(OP_POW), \ +G(OP_USUB) SK_ENUM_H(Opcode, OPCODE); diff --git a/lib/include/state.h b/lib/include/state.h index 1306d4a..4a0b9ef 100644 --- a/lib/include/state.h +++ b/lib/include/state.h @@ -42,6 +42,16 @@ bool state_has_top(struct state* self); SK state_top(struct state* self); struct value* state_try_get_value(struct state* self, SK value); +SK state_pop(struct state* self); + SK state_push_int(struct state* self, int integer); +SK state_add(struct state* self); +SK state_sub(struct state* self); +SK state_usub(struct state* self); +SK state_mul(struct state* self); +SK state_div(struct state* self); +SK state_mod(struct state* self); +SK state_pow(struct state* self); + #endif diff --git a/lib/include/token.h b/lib/include/token.h index 78888a6..464ce3f 100644 --- a/lib/include/token.h +++ b/lib/include/token.h @@ -5,7 +5,10 @@ #define TOKEN_KIND(G) \ G(TOKEN_ROOT), \ -G(TOKEN_INT) +G(TOKEN_INT), \ +G(TOKEN_ADD), G(TOKEN_SUB), \ +G(TOKEN_MUL), G(TOKEN_DIV), G(TOKEN_MOD), \ +G(TOKEN_POW), G(TOKEN_OPAR), G(TOKEN_CPAR) SK_ENUM_H(TokenKind, TOKEN_KIND); @@ -20,6 +23,7 @@ void token_init(struct token* self, TokenKind kind, char const* value, int line); + void token_free(struct token* self); void token_str(struct token* self, struct str* dest); diff --git a/lib/include/vec.h b/lib/include/vec.h index 09f290c..17779d9 100644 --- a/lib/include/vec.h +++ b/lib/include/vec.h @@ -17,6 +17,7 @@ void vec_free_elements(struct vec* self, void vec_free(struct vec* self); void vec_push(struct vec* self, void* element); +void* vec_pop(struct vec* self); #endif diff --git a/lib/src/compiler.c b/lib/src/compiler.c index 73b97d0..fa1ef14 100644 --- a/lib/src/compiler.c +++ b/lib/src/compiler.c @@ -39,6 +39,41 @@ void compiler_compile(struct compiler* self, prog_add_instr(prog, OP_PUSH, idx); } break; + case NODE_ADD: { + compiler_compile_children(self, node, prog); + prog_add_instr(prog, OP_ADD, SK_NO_PARAM); + } break; + + case NODE_SUB: { + compiler_compile_children(self, node, prog); + prog_add_instr(prog, OP_SUB, SK_NO_PARAM); + } break; + + case NODE_MUL: { + compiler_compile_children(self, node, prog); + prog_add_instr(prog, OP_MUL, SK_NO_PARAM); + } break; + + case NODE_DIV: { + compiler_compile_children(self, node, prog); + prog_add_instr(prog, OP_DIV, SK_NO_PARAM); + } break; + + case NODE_MOD: { + compiler_compile_children(self, node, prog); + prog_add_instr(prog, OP_MOD, SK_NO_PARAM); + } break; + + case NODE_POW: { + compiler_compile_children(self, node, prog); + prog_add_instr(prog, OP_POW, SK_NO_PARAM); + } break; + + case NODE_USUB: { + compiler_compile_children(self, node, prog); + prog_add_instr(prog, OP_USUB, SK_NO_PARAM); + } break; + default: { fprintf(stderr, "cannot compile node '%s'\n", NodeKindStr[node->kind]); @@ -46,3 +81,18 @@ void compiler_compile(struct compiler* self, } break; } } + +void compiler_compile_children(struct compiler* self, + struct node* node, + struct prog* prog) +{ + assert(self); + assert(node); + assert(prog); + + for (size_t i=0; ichildren.size; i++) + { + struct node* child = node->children.data[i]; + compiler_compile(self, child, prog); + } +} diff --git a/lib/src/exec.c b/lib/src/exec.c index 4dfd672..0cac7cd 100644 --- a/lib/src/exec.c +++ b/lib/src/exec.c @@ -38,6 +38,41 @@ void exec_execute(struct exec* self, self->pc++; } break; + case OP_ADD: { + state_add(state); + self->pc++; + } break; + + case OP_SUB: { + state_sub(state); + self->pc++; + } break; + + case OP_MUL: { + state_mul(state); + self->pc++; + } break; + + case OP_DIV: { + state_div(state); + self->pc++; + } break; + + case OP_MOD: { + state_mod(state); + self->pc++; + } break; + + case OP_POW: { + state_pow(state); + self->pc++; + } break; + + case OP_USUB: { + state_usub(state); + self->pc++; + } break; + default: { fprintf(stderr, "cannot execute opcode '%s'\n", OpcodeStr[opcode]); diff --git a/lib/src/lexer.c b/lib/src/lexer.c index 059de43..0fdd01c 100644 --- a/lib/src/lexer.c +++ b/lib/src/lexer.c @@ -1,10 +1,16 @@ #include "lexer.h" +#define SK_SCAN_TEXT(TXT, TOK) \ +if ( (tok=lexer_try_scan_text(self, TXT, TOK)) )\ +{\ + return tok;\ +} + void lexer_init(struct lexer* self, char const* source) { assert(self); - self->source = strdup(source); - self->len = strlen(self->source); + self->len = source ? strlen(source) : 0; + self->source = (self->len > 0) ? strdup(source) : strdup(""); self->context.line = 1; self->context.cursor = 0; } @@ -12,7 +18,11 @@ void lexer_init(struct lexer* self, char const* source) void lexer_free(struct lexer* self) { assert(self); - free(self->source); + + if (self->source) + { + free(self->source); + } } void lexer_skip_spaces(struct lexer* self) @@ -31,6 +41,22 @@ void lexer_skip_spaces(struct lexer* self) } } +bool lexer_is_sep(struct lexer* self, size_t index) +{ + if (index >= self->len) { return true; } + char c = self->source[index]; + + return isspace(c) + || c == '(' + || c == ')' + || c == '+' + || c == '-' + || c == '*' + || c == '/' + || c == '%' + || c == '^'; +} + bool lexer_next_is(struct lexer* self, TokenKind kind) { struct context ctx = self->context; @@ -51,6 +77,17 @@ bool lexer_next_is(struct lexer* self, TokenKind kind) return res; } +void lexer_consume_next(struct lexer* self) +{ + struct token* tok = lexer_try_new_next(self); + + if (tok) + { + token_free(tok); + free(tok); + } +} + struct token* lexer_try_new_next(struct lexer* self) { assert(self); @@ -69,13 +106,22 @@ struct token* lexer_try_new_next(struct lexer* self) return tok; } + SK_SCAN_TEXT("+", TOKEN_ADD); + SK_SCAN_TEXT("-", TOKEN_SUB); + SK_SCAN_TEXT("*", TOKEN_MUL); + SK_SCAN_TEXT("/", TOKEN_DIV); + SK_SCAN_TEXT("^", TOKEN_POW); + SK_SCAN_TEXT("%", TOKEN_MOD); + SK_SCAN_TEXT("(", TOKEN_OPAR); + SK_SCAN_TEXT(")", TOKEN_CPAR); + if (self->context.cursor < self->len) { struct str str; str_init(&str); while (self->context.cursor < self->len - && !isspace(self->source[self->context.cursor])) + && !lexer_is_sep(self, self->context.cursor)) { str_push(&str, self->source[self->context.cursor]); self->context.cursor++; @@ -112,7 +158,8 @@ struct token* lexer_try_scan_int(struct lexer* self) struct token* tok = NULL; - if (value.size > 0) + if (value.size > 0 + && (value.value[0] != '-' || value.size > 1)) { tok = malloc(sizeof(struct token)); token_init(tok, TOKEN_INT, @@ -125,3 +172,30 @@ struct token* lexer_try_scan_int(struct lexer* self) return tok; } +struct token* lexer_try_scan_text(struct lexer* self, + char const* text, + TokenKind kind) +{ + assert(self); + assert(text); + size_t txt_sz = strlen(text); + + if (self->context.cursor + txt_sz > self->len) + { + return NULL; + } + + for (size_t i=0; isource[self->context.cursor + i] + != text[i]) + { + return NULL; + } + } + + struct token* tok = malloc(sizeof(struct token)); + token_init(tok, kind, "", self->context.line); + self->context.cursor += txt_sz; + return tok; +} diff --git a/lib/src/parser.c b/lib/src/parser.c index 1014d61..b36f22a 100644 --- a/lib/src/parser.c +++ b/lib/src/parser.c @@ -43,8 +43,8 @@ struct node* parser_try_root(struct parser* self) assert(self); struct node* node = malloc(sizeof(struct node)); struct token* tok = malloc(sizeof(struct token)); - token_init(tok, - TOKEN_ROOT, + token_init(tok, + TOKEN_ROOT, "", self->lexer.context.line); @@ -58,11 +58,191 @@ struct node* parser_try_root(struct parser* self) node_push_new_child(node, expr); } + if (self->lexer.context.cursor < self->lexer.len) + { + errors_push(self->lexer.context.line, "unexpected end"); + } + return node; } struct node* parser_try_expr(struct parser* self) { + return SK_TRY(parser_try_term); +} + +struct node* parser_try_term(struct parser* self) +{ + assert(self); + struct node* lhs = SK_TRY(parser_try_factor); + if (!lhs) { return NULL; } + + while (lexer_next_is(&self->lexer, TOKEN_ADD) + || lexer_next_is(&self->lexer, TOKEN_SUB)) + { + struct node* node = malloc(sizeof(struct node)); + + if (lexer_next_is(&self->lexer, TOKEN_ADD)) + { + node_init(node, NODE_ADD, lexer_try_new_next( + &self->lexer + )); + } + else + { + node_init(node, NODE_SUB, lexer_try_new_next( + &self->lexer + )); + } + + node_push_new_child(node, lhs); + struct node* rhs = SK_TRY(parser_try_factor); + + if (!rhs) + { + node_free(node); + free(node); + return NULL; + } + + node_push_new_child(node, rhs); + lhs = node; + } + + return lhs; +} + +struct node* parser_try_factor(struct parser* self) +{ + assert(self); + struct node* lhs = SK_TRY(parser_try_usub); + if (!lhs) { return NULL; } + + while (lexer_next_is(&self->lexer, TOKEN_MUL) + || lexer_next_is(&self->lexer, TOKEN_DIV) + || lexer_next_is(&self->lexer, TOKEN_MOD)) + { + struct node* node = malloc(sizeof(struct node)); + + if (lexer_next_is(&self->lexer, TOKEN_MUL)) + { + node_init(node, NODE_MUL, lexer_try_new_next( + &self->lexer + )); + } + else if (lexer_next_is(&self->lexer, TOKEN_DIV)) + { + node_init(node, NODE_DIV, lexer_try_new_next( + &self->lexer + )); + } + else + { + node_init(node, NODE_MOD, lexer_try_new_next( + &self->lexer + )); + } + node_push_new_child(node, lhs); + struct node* rhs = SK_TRY(parser_try_usub); + + if (!rhs) + { + node_free(node); + free(node); + return NULL; + } + + node_push_new_child(node, rhs); + lhs = node; + } + + return lhs; +} + +struct node* parser_try_usub(struct parser* self) +{ + assert(self); + + if (lexer_next_is(&self->lexer, TOKEN_SUB)) + { + struct node* node = malloc(sizeof(struct node)); + node_init(node, NODE_USUB, lexer_try_new_next( + &self->lexer + )); + + struct node* child = SK_TRY(parser_try_usub); + + if (!child) + { + node_free(node); + free(node); + return NULL; + } + + node_push_new_child(node, child); + return node; + } + + return SK_TRY(parser_try_pow); +} + +struct node* parser_try_pow(struct parser* self) +{ + assert(self); + + struct node* lhs = SK_TRY(parser_try_literal); + if (!lhs) { return NULL; } + + if (lexer_next_is(&self->lexer, TOKEN_POW)) + { + struct node* node = malloc(sizeof(struct node)); + node_init(node, NODE_POW, lexer_try_new_next( + &self->lexer + )); + + struct node* rhs = SK_TRY(parser_try_literal); + + if (!rhs) + { + node_free(node); + free(node); + return NULL; + } + + node_push_new_child(node, lhs); + node_push_new_child(node, rhs); + lhs = node; + } + + return lhs; +} + +struct node* parser_try_literal(struct parser* self) +{ + assert(self); + + if (lexer_next_is(&self->lexer, TOKEN_OPAR)) + { + lexer_consume_next(&self->lexer); + struct node* node = SK_TRY(parser_try_expr); + + if (!node) + { + return NULL; + } + + if (!lexer_next_is(&self->lexer, TOKEN_CPAR)) + { + node_free(node); + free(node); + return NULL; + } + + lexer_consume_next(&self->lexer); + + return node; + } + return SK_TRY(parser_try_builtin); } diff --git a/lib/src/state.c b/lib/src/state.c index f2fc688..fba4a0d 100644 --- a/lib/src/state.c +++ b/lib/src/state.c @@ -82,7 +82,7 @@ struct value* state_try_get_value(struct state* self, SK value) { assert(self); struct frame* frame = state_frame(self); - + for (size_t i=0; ilocals.size; i++) { struct local* local = frame->locals.data[i]; @@ -96,6 +96,17 @@ struct value* state_try_get_value(struct state* self, SK value) return NULL; } +SK state_pop(struct state* self) +{ + assert(self); + + struct frame* frame = state_frame(self); + assert(frame->stack.size > 0); + SK value = (SK) vec_pop(&frame->stack); + + return value; +} + SK state_push_int(struct state* self, int integer) { assert(self); @@ -115,3 +126,99 @@ SK state_push_int(struct state* self, int integer) self->addr++; return self->addr - 1; } + +SK state_add(struct state* self) +{ + SK rhs = state_pop(self); + SK lhs = state_pop(self); + + struct value* left = state_try_get_value(self, lhs); + struct value* right = state_try_get_value(self, rhs); + + return state_push_int( + self, + left->val.integer + right->val.integer + ); +} + +SK state_sub(struct state* self) +{ + SK rhs = state_pop(self); + SK lhs = state_pop(self); + + struct value* left = state_try_get_value(self, lhs); + struct value* right = state_try_get_value(self, rhs); + + return state_push_int( + self, + left->val.integer - right->val.integer + ); +} + +SK state_usub(struct state* self) +{ + SK lhs = state_pop(self); + + struct value* left = state_try_get_value(self, lhs); + + return state_push_int( + self, + -left->val.integer + ); +} + +SK state_mul(struct state* self) +{ + SK rhs = state_pop(self); + SK lhs = state_pop(self); + + struct value* left = state_try_get_value(self, lhs); + struct value* right = state_try_get_value(self, rhs); + + return state_push_int( + self, + left->val.integer * right->val.integer + ); +} + +SK state_div(struct state* self) +{ + SK rhs = state_pop(self); + SK lhs = state_pop(self); + + struct value* left = state_try_get_value(self, lhs); + struct value* right = state_try_get_value(self, rhs); + + return state_push_int( + self, + left->val.integer / right->val.integer + ); +} + +SK state_mod(struct state* self) +{ + SK rhs = state_pop(self); + SK lhs = state_pop(self); + + struct value* left = state_try_get_value(self, lhs); + struct value* right = state_try_get_value(self, rhs); + + return state_push_int( + self, + fmod(left->val.integer, right->val.integer) + ); +} + +SK state_pow(struct state* self) +{ + SK rhs = state_pop(self); + SK lhs = state_pop(self); + + struct value* left = state_try_get_value(self, lhs); + struct value* right = state_try_get_value(self, rhs); + + return state_push_int( + self, + powf(left->val.integer, right->val.integer) + ); +} diff --git a/lib/src/vec.c b/lib/src/vec.c index 9684f67..9240ee9 100644 --- a/lib/src/vec.c +++ b/lib/src/vec.c @@ -57,3 +57,13 @@ void vec_push(struct vec* self, void* element) self->data[self->size] = element; self->size++; } + +void* vec_pop(struct vec* self) +{ + assert(self); + assert(self->size > 0); + + void* element = self->data[self->size - 1]; + self->size--; + return element; +} diff --git a/tests/lexer.h b/tests/lexer.h index f1b18db..445fb0c 100644 --- a/tests/lexer.h +++ b/tests/lexer.h @@ -43,6 +43,11 @@ static void test_lexer_int() "INT[-23]", "INT[720]" ); + + test_lexer("+-*/^%()", 8, + "ADD", "SUB", "MUL", "DIV", + "POW", "MOD", "OPAR", "CPAR" + ); } void register_lexer() diff --git a/tests/parser.h b/tests/parser.h index 6370d2e..6b99020 100644 --- a/tests/parser.h +++ b/tests/parser.h @@ -26,7 +26,16 @@ static void test_parser(char const* oracle, char const* source) static void test_parser_int() { test_parser("ROOT(INT[32])", " 32 "); + test_parser("ROOT(INT[32],INT[-2],INT[24])", " 32 -2 24"); + + test_parser("ROOT(ADD(INT[1],MUL(INT[2],INT[3])))", + " 1 + 2 * 3 "); + + test_parser("ROOT(DIV(SUB(INT[1],INT[2]),INT[3]))", + " (1 - 2) / 3 "); + + test_parser("ROOT(USUB(INT[32]))", " -(32) "); } void register_parser()