From 159a3a4f38a800e8b8c7f49ecbf4470eb5e40497 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Wed, 10 Apr 2024 22:43:12 +0200 Subject: [PATCH] Parse reference and dereference operators --- backend/riscv.cpp | 11 +++++ include/elna/backend/riscv.hpp | 1 + include/elna/source/parser.hpp | 24 +++++++++++ source/parser.cpp | 76 ++++++++++++++++++++++++++++++---- 4 files changed, 105 insertions(+), 7 deletions(-) diff --git a/backend/riscv.cpp b/backend/riscv.cpp index 12ede13..c36693c 100644 --- a/backend/riscv.cpp +++ b/backend/riscv.cpp @@ -398,6 +398,17 @@ namespace elna::riscv } } + void visitor::visit(source::unary_expression *expression) + { + const auto free_register = this->register_in_use ? x_register::a0 : x_register::t0; + auto operand_identifier = dynamic_cast(expression->operand()).name(); + auto variable_symbol = + std::dynamic_pointer_cast(this->table->lookup(operand_identifier)); + + this->instructions.push_back(instruction(base_opcode::opImm) + .i(free_register, funct3_t::addi, x_register::s0, variable_symbol->offset)); + } + void visitor::visit(source::integer_literal *number) { const auto free_register = this->register_in_use ? x_register::a0 : x_register::t0; diff --git a/include/elna/backend/riscv.hpp b/include/elna/backend/riscv.hpp index ed31c20..c55ea81 100644 --- a/include/elna/backend/riscv.hpp +++ b/include/elna/backend/riscv.hpp @@ -190,6 +190,7 @@ namespace elna::riscv virtual void visit(source::type_expression *variable) override; virtual void visit(source::variable_expression *variable) override; virtual void visit(source::binary_expression *expression) override; + virtual void visit(source::unary_expression *expression) override; virtual void visit(source::integer_literal *number) override; virtual void visit(source::boolean_literal *number) override; }; diff --git a/include/elna/source/parser.hpp b/include/elna/source/parser.hpp index 55e91f6..298cb8b 100644 --- a/include/elna/source/parser.hpp +++ b/include/elna/source/parser.hpp @@ -20,6 +20,12 @@ namespace elna::source greater_equal }; + enum class unary_operator + { + reference, + dereference + }; + class declaration; class constant_definition; class procedure_definition; @@ -31,6 +37,7 @@ namespace elna::source class block; class program; class binary_expression; + class unary_expression; class type_expression; class variable_expression; class integer_literal; @@ -52,6 +59,7 @@ namespace elna::source virtual void visit(block *) = 0; virtual void visit(program *) = 0; virtual void visit(binary_expression *) = 0; + virtual void visit(unary_expression *) = 0; virtual void visit(type_expression *) = 0; virtual void visit(variable_expression *) = 0; virtual void visit(integer_literal *) = 0; @@ -74,6 +82,7 @@ namespace elna::source virtual void visit(block *block) override; virtual void visit(program *program) override; virtual void visit(binary_expression *expression) override; + virtual void visit(unary_expression *expression) override; virtual void visit(type_expression *variable) override; virtual void visit(variable_expression *variable) override; virtual void visit(integer_literal *number) override; @@ -401,8 +410,23 @@ namespace elna::source binary_operator operation() const noexcept; }; + class unary_expression : public expression + { + std::unique_ptr m_operand; + unary_operator m_operator; + + public: + unary_expression(const struct position position, std::unique_ptr&& operand, + const unsigned char operation); + + virtual void accept(parser_visitor *visitor) override; + expression& operand(); + unary_operator operation() const noexcept; + }; + class parser : boost::noncopyable { + std::unique_ptr parse_unary_expression(); std::unique_ptr parse_factor(); std::unique_ptr parse_term(); std::unique_ptr parse_expression(); diff --git a/source/parser.cpp b/source/parser.cpp index 6f3a1a7..254ac9f 100644 --- a/source/parser.cpp +++ b/source/parser.cpp @@ -78,6 +78,11 @@ namespace elna::source expression->rhs().accept(this); } + void empty_visitor::visit(unary_expression *expression) + { + expression->operand().accept(this); + } + void empty_visitor::visit(type_expression *variable) { } @@ -343,6 +348,33 @@ namespace elna::source return m_operator; } + unary_expression::unary_expression(const struct position position, std::unique_ptr&& operand, + const unsigned char operation) + : expression(position), m_operand(std::move(operand)) + { + switch (operation) + { + case '@': + this->m_operator = unary_operator::reference; + break; + case '^': + this->m_operator = unary_operator::dereference; + break; + default: + throw std::logic_error("Invalid unary operator"); + } + } + + void unary_expression::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + expression& unary_expression::operand() + { + return *m_operand; + } + call_statement::call_statement(const struct position position, const std::string& name) : statement(position), m_name(name) { @@ -477,33 +509,63 @@ namespace elna::source return iterator.errors(); } + std::unique_ptr parser::parse_unary_expression() + { + std::unique_ptr result; + + if (iterator.current(token::type::at)) + { + std::unique_ptr body_expression; + + ++iterator; + if ((body_expression = parse_factor()) == nullptr) + { + return nullptr; + } + result = std::make_unique(iterator->position(), std::move(body_expression), '@'); + } + else + { + if ((result = parse_factor()) == nullptr) + { + return nullptr; + } + } + if (iterator.current(token::type::hat)) + { + ++iterator; + result = std::make_unique(iterator->position(), std::move(result), '^'); + } + return result; + } + std::unique_ptr parser::parse_factor() { - if (iterator->of() == source::token::type::identifier) + if (iterator->of() == token::type::identifier) { auto result = std::make_unique(iterator->position(), iterator->identifier()); ++iterator; return result; } - else if (iterator->of() == source::token::token::type::number) + else if (iterator->of() == token::token::type::number) { auto result = std::make_unique(iterator->position(), iterator->number()); ++iterator; return result; } - else if (iterator->of() == source::token::token::type::boolean) + else if (iterator->of() == token::token::type::boolean) { auto result = std::make_unique(iterator->position(), iterator->number()); ++iterator; return result; } - else if (iterator->of() == source::token::type::left_paren) + else if (iterator->of() == token::type::left_paren) { ++iterator; auto expression = parse_condition(); - ++iterator; + iterator.advance(token::type::right_paren); return expression; } @@ -512,7 +574,7 @@ namespace elna::source std::unique_ptr parser::parse_term() { - auto lhs = parse_factor(); + auto lhs = parse_unary_expression(); if (lhs == nullptr || iterator.current().of() != source::token::type::factor_operator) { return lhs; @@ -523,7 +585,7 @@ namespace elna::source const auto operator_position = iterator->position(); ++iterator; - auto rhs = parse_factor(); + auto rhs = parse_unary_expression(); lhs = std::make_unique(operator_position, std::move(lhs), std::move(rhs), _operator); }