diff options
| author | Mustafa Quraish <[email protected]> | 2022-01-28 23:01:17 -0500 |
|---|---|---|
| committer | Mustafa Quraish <[email protected]> | 2022-01-28 23:01:17 -0500 |
| commit | f38482a373a1bf3e20c53e5d08f9af9ec16cb1bc (patch) | |
| tree | fc3929a34b3c45131574c1bbe80320faadd43060 | |
| parent | Corrent incorrect `break` in Lexer (diff) | |
| download | cup-f38482a373a1bf3e20c53e5d08f9af9ec16cb1bc.tar.xz cup-f38482a373a1bf3e20c53e5d08f9af9ec16cb1bc.zip | |
Add some arithmetic binary operations into lex+parse+generation
| -rw-r--r-- | cup/ast.c | 60 | ||||
| -rw-r--r-- | cup/ast.h | 19 | ||||
| -rw-r--r-- | cup/generator.c | 31 | ||||
| -rw-r--r-- | cup/parser.c | 90 | ||||
| -rw-r--r-- | examples/binary-ops.cup | 3 |
5 files changed, 184 insertions, 19 deletions
@@ -23,6 +23,50 @@ char *node_type_to_str(NodeType type) } } +bool is_binary_op(NodeType type) +{ + switch (type) + { + case OP_PLUS: + case OP_MINUS: + case OP_MUL: + case OP_DIV: + case OP_MOD: + case OP_LSHIFT: + case OP_RSHIFT: + case OP_AND: + case OP_OR: + case OP_XOR: + case OP_EQ: + case OP_NEQ: + case OP_LT: + case OP_LEQ: + case OP_GT: + case OP_GEQ: + return true; + default: return false; + } +} + +bool is_unary_op(NodeType type) +{ + switch (type) + { + case OP_NEG: + case OP_NOT: + case OP_BWINV: + return true; + default: return false; + } +} + +bool is_expression(NodeType type) +{ + if (is_unary_op(type) || is_binary_op(type)) + return true; + return type == AST_LITERAL; +} + static void do_print_ast(Node *node, int depth) { for (int i = 0; i < depth; i++) { @@ -59,17 +103,15 @@ static void do_print_ast(Node *node, int depth) } else if (node->type == AST_RETURN) { printf("return\n"); do_print_ast(node->unary_expr, depth + 1); - } else if (node->type == OP_NEG) { - printf("-\n"); - do_print_ast(node->unary_expr, depth + 1); - } else if (node->type == OP_NOT) { - printf("!\n"); - do_print_ast(node->unary_expr, depth + 1); - } else if (node->type == OP_BWINV) { - printf("~\n"); + } else if (is_unary_op(node->type)) { + printf("%s\n", node_type_to_str(node->type)); do_print_ast(node->unary_expr, depth + 1); + } else if (is_binary_op(node->type)) { + printf("%s\n", node_type_to_str(node->type)); + do_print_ast(node->binary.left, depth + 1); + do_print_ast(node->binary.right, depth + 1); } else { - printf("(unknown)\n"); + printf("Don't know how to handle: `%s`\n", node_type_to_str(node->type)); } } @@ -10,12 +10,23 @@ F(OP_MINUS, "-") \ F(OP_MUL, "*") \ F(OP_DIV, "/") \ + F(OP_MOD, "%") \ + F(OP_LSHIFT, "<<") \ + F(OP_RSHIFT, ">>") \ + F(OP_AND, "&&") \ + F(OP_OR, "||") \ + F(OP_XOR, "^") \ + F(OP_EQ, "==") \ + F(OP_NEQ, "!=") \ + F(OP_LT, "<") \ + F(OP_LEQ, "<=") \ + F(OP_GT, ">") \ + F(OP_GEQ, ">=") \ F(AST_LITERAL, "literal") \ F(AST_RETURN, "return") \ F(AST_FUNC, "func") \ F(AST_PROGRAM, "program") \ - F(AST_BLOCK, "block statements") \ - + F(AST_BLOCK, "block statements") typedef enum { #define DEFINE_ENUM(name, str) name, @@ -25,6 +36,10 @@ typedef enum { char *node_type_to_str(NodeType type); +bool is_binary_op(NodeType type); +bool is_unary_op(NodeType type); +bool is_expression(NodeType type); + typedef enum { TYPE_NONE, TYPE_INT, diff --git a/cup/generator.c b/cup/generator.c index edb38ad..6018e47 100644 --- a/cup/generator.c +++ b/cup/generator.c @@ -30,6 +30,37 @@ void generate_expr_into_rax(Node *expr, FILE *out) generate_expr_into_rax(expr->unary_expr, out); fprintf(out, " not rax\n"); + } else if (expr->type == OP_PLUS) { + generate_expr_into_rax(expr->binary.left, out); + fprintf(out, " push rax\n"); + generate_expr_into_rax(expr->binary.right, out); + fprintf(out, " pop rbx\n"); + fprintf(out, " add rax, rbx\n"); + + } else if (expr->type == OP_MINUS) { + generate_expr_into_rax(expr->binary.left, out); + fprintf(out, " push rax\n"); + generate_expr_into_rax(expr->binary.right, out); + fprintf(out, " mov rbx, rax\n"); + fprintf(out, " pop rax\n"); + fprintf(out, " sub rax, rbx\n"); + + } else if (expr->type == OP_DIV) { + generate_expr_into_rax(expr->binary.left, out); + fprintf(out, " push rax\n"); + generate_expr_into_rax(expr->binary.right, out); + fprintf(out, " mov rbx, rax\n"); + fprintf(out, " pop rax\n"); + fprintf(out, " cqo\n"); + fprintf(out, " idiv rbx\n"); + + } else if (expr->type == OP_MUL) { + generate_expr_into_rax(expr->binary.left, out); + fprintf(out, " push rax\n"); + generate_expr_into_rax(expr->binary.right, out); + fprintf(out, " pop rbx\n"); + fprintf(out, " imul rbx\n"); + } else { fprintf(stderr, "Unsupported expression type in generate_expr: %d\n", expr->type); exit(1); diff --git a/cup/parser.c b/cup/parser.c index 746a139..a6ea9b2 100644 --- a/cup/parser.c +++ b/cup/parser.c @@ -16,6 +16,37 @@ Token do_assert_token(Token token, TokenType type, char *filename, int line) #define assert_token(token, type) do_assert_token(token, type, __FILE__, __LINE__) +/****** + * Some helpers + */ + +NodeType binary_token_to_op(TokenType type) +{ + switch (type) + { + case TOKEN_PLUS: return OP_PLUS; + case TOKEN_MINUS: return OP_MINUS; + case TOKEN_STAR: return OP_MUL; + case TOKEN_SLASH: return OP_DIV; + case TOKEN_PERCENT: return OP_MOD; + case TOKEN_LSHIFT: return OP_LSHIFT; + case TOKEN_RSHIFT: return OP_RSHIFT; + case TOKEN_AND: return OP_AND; + case TOKEN_OR: return OP_OR; + case TOKEN_XOR: return OP_XOR; + case TOKEN_EQ: return OP_EQ; + case TOKEN_NEQ: return OP_NEQ; + case TOKEN_LT: return OP_LT; + case TOKEN_LEQ: return OP_LEQ; + case TOKEN_GT: return OP_GT; + case TOKEN_GEQ: return OP_GEQ; + + default: assert(false && "binary_token_to_op called with invalid token type"); + } +} + + + void Node_add_child(Node *parent, Node *child) { // TODO, use a vector @@ -59,7 +90,9 @@ Node *parse_literal(Lexer *lexer) return node; } -Node *parse_expression(Lexer *lexer) +Node *parse_expression(Lexer *); + +Node *parse_factor(Lexer *lexer) { // TODO: Parse more complicated things Token token = Lexer_peek(lexer); @@ -67,17 +100,60 @@ Node *parse_expression(Lexer *lexer) if (token.type == TOKEN_MINUS) { Lexer_next(lexer); expr = Node_new(OP_NEG); - expr->unary_expr = parse_expression(lexer); + expr->unary_expr = parse_factor(lexer); } else if (token.type == TOKEN_TILDE) { Lexer_next(lexer); expr = Node_new(OP_BWINV); - expr->unary_expr = parse_expression(lexer); + expr->unary_expr = parse_factor(lexer); } else if (token.type == TOKEN_EXCLAMATION) { Lexer_next(lexer); expr = Node_new(OP_NOT); - expr->unary_expr = parse_expression(lexer); + expr->unary_expr = parse_factor(lexer); + } else if (token.type == TOKEN_OPEN_PAREN) { + Lexer_next(lexer); + expr = parse_expression(lexer); + assert_token(Lexer_next(lexer), TOKEN_CLOSE_PAREN); + } else if (token.type == TOKEN_INTLIT) { + expr = parse_literal(lexer); } else { - return parse_literal(lexer); + die_location(token.loc, "Expected token found in parse_factor: `%s`", token_type_to_str(token.type)); + exit(1); + } + return expr; +} + +Node *parse_term(Lexer *lexer) +{ + Node *expr = parse_factor(lexer); + Token token = Lexer_peek(lexer); + while (token.type == TOKEN_STAR || + token.type == TOKEN_SLASH || + token.type == TOKEN_PERCENT) { + Lexer_next(lexer); + Node *op = Node_new(binary_token_to_op(token.type)); + Node *right = parse_factor(lexer); + op->binary.left = expr; + op->binary.right = right; + expr = op; + token = Lexer_peek(lexer); + } + return expr; +} + + +Node *parse_expression(Lexer *lexer) +{ + Node *expr = parse_term(lexer); + Token token = Lexer_peek(lexer); + while (token.type == TOKEN_PLUS || + token.type == TOKEN_MINUS) { + Lexer_next(lexer); + Node *op = Node_new(binary_token_to_op(token.type)); + Node *right = parse_term(lexer); + op->binary.left = expr; + op->binary.right = right; + expr = op; + token = Lexer_peek(lexer); } return expr; } @@ -93,9 +169,7 @@ Node *parse_statement(Lexer *lexer) node->unary_expr = parse_expression(lexer); assert_token(Lexer_next(lexer), TOKEN_SEMICOLON); } else { - printf("Unexpected token in parse_statement: "); - Token_print(stdout, &token); - printf("\n"); + die_location(token.loc, ": Unexpected token in parse_statement: %s\n", token_type_to_str(token.type)); exit(1); } diff --git a/examples/binary-ops.cup b/examples/binary-ops.cup new file mode 100644 index 0000000..13e5083 --- /dev/null +++ b/examples/binary-ops.cup @@ -0,0 +1,3 @@ +fn main() { + return 2 + 5 * (12 / 4) - 1; +}
\ No newline at end of file |