From 8176da5f9b6bebb05d4cc7752f15cf07d19fce9b Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Tue, 31 Dec 2024 18:10:34 +0100 Subject: [PATCH] Introduce float type --- gcc/Make-lang.in | 1 - gcc/elna-diagnostic.cc | 6 +-- gcc/elna-generic.cc | 75 ++++++++++++++++++++++----------- include/elna/gcc/elna-generic.h | 3 +- include/elna/source/ast.h | 36 +++++++++++----- source/ast.cc | 25 +++-------- source/lexer.ll | 3 ++ source/parser.yy | 11 ++++- 8 files changed, 100 insertions(+), 60 deletions(-) diff --git a/gcc/Make-lang.in b/gcc/Make-lang.in index fb36799..56e2c02 100644 --- a/gcc/Make-lang.in +++ b/gcc/Make-lang.in @@ -30,7 +30,6 @@ elna_OBJS = \ elna/lexer.o \ elna/parser.o \ elna/result.o \ - elna/semantic.o \ elna/symbol_table.o \ elna/types.o \ $(END) diff --git a/gcc/elna-diagnostic.cc b/gcc/elna-diagnostic.cc index e388310..4990f52 100644 --- a/gcc/elna-diagnostic.cc +++ b/gcc/elna-diagnostic.cc @@ -22,11 +22,11 @@ namespace gcc } else if (type == boolean_type_node) { - return "Boolean"; + return "Bool"; } - else if (type == enumeral_node) + else if (type == double_type_node) { - return "Enum"; + return "Float"; } else { diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 74675a3..ca0a48e 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -7,6 +7,7 @@ #include "gimplify.h" #include "stringpool.h" #include "diagnostic.h" +#include "realmpfr.h" namespace elna { @@ -31,20 +32,27 @@ namespace gcc auto& argument = statement->arguments().at(0); argument->accept(this); auto argument_type = TREE_TYPE(this->current_expression); - auto argument_tree = this->current_expression; - this->current_expression = NULL_TREE; - if (argument_type != integer_type_node) + const char *format_number{ nullptr }; + if (argument_type == integer_type_node) + { + format_number = "%d\n"; + } + else if (argument_type == double_type_node) + { + format_number = "%f\n"; + } + else { error_at(get_location(&argument->position()), "invalid argument of type %s for procedure %s", print_type(argument_type), statement->name().c_str()); + this->current_expression = error_mark_node; return; } - constexpr const char *format_integer = "%d\n"; tree args[] = { - build_string_literal(strlen(format_integer) + 1, format_integer), - argument_tree + build_string_literal(strlen(format_number) + 1, format_number), + this->current_expression }; tree fndecl_type_param[] = { build_pointer_type(build_qualified_type(char_type_node, TYPE_QUAL_CONST)) /* const char* */ @@ -52,13 +60,14 @@ namespace gcc tree fndecl_type = build_varargs_function_type_array(integer_type_node, 1, fndecl_type_param); tree printf_fn_decl = build_fn_decl("printf", fndecl_type); - DECL_EXTERNAL (printf_fn_decl) = 1; + DECL_EXTERNAL(printf_fn_decl) = 1; tree printf_fn = build1(ADDR_EXPR, build_pointer_type(fndecl_type), printf_fn_decl); tree stmt = build_call_array(integer_type_node, printf_fn, 2, args); append_to_statement_list(stmt, &this->current_statements); + this->current_expression = NULL_TREE; } void generic_visitor::visit(source::program *program) @@ -96,11 +105,26 @@ namespace gcc cgraph_node::finalize_function(this->main_fndecl, true); } - void generic_visitor::visit(source::integer_literal *literal) + void generic_visitor::visit(source::number_literal *literal) { this->current_expression = build_int_cst_type(integer_type_node, literal->number()); } + void generic_visitor::visit(source::number_literal *literal) + { + REAL_VALUE_TYPE real_value1; + + mpfr_t number; + mpfr_init2(number, SIGNIFICAND_BITS); + mpfr_set_d(number, literal->number(), MPFR_RNDN); + + real_from_mpfr(&real_value1, number, double_type_node, MPFR_RNDN); + + this->current_expression = build_real(double_type_node, real_value1); + + mpfr_clear(number); + } + void generic_visitor::visit(source::boolean_literal *literal) { this->current_expression = build_int_cst_type(boolean_type_node, literal->boolean()); @@ -120,28 +144,37 @@ namespace gcc tree_code operator_code = ERROR_MARK; tree target_type = error_mark_node; + if (left_type != right_type) + { + error_at(expression_location, + "invalid operands of type %s and %s for operator %s", + print_type(left_type), print_type(right_type), + elna::source::print_binary_operator(expression->operation())); + this->current_expression = error_mark_node; + return; + } switch (expression->operation()) { case source::binary_operator::sum: operator_code = PLUS_EXPR; - target_type = integer_type_node; + target_type = left_type; break; case source::binary_operator::subtraction: operator_code = MINUS_EXPR; - target_type = integer_type_node; + target_type = left_type; break; case source::binary_operator::division: operator_code = TRUNC_DIV_EXPR; - target_type = integer_type_node; + target_type = left_type; break; case source::binary_operator::multiplication: operator_code = MULT_EXPR; - target_type = integer_type_node; + target_type = left_type; break; } if (operator_code != ERROR_MARK) // An arithmetic operation. { - if (left_type != integer_type_node || right_type != integer_type_node) + if (target_type != integer_type_node && target_type != double_type_node) { error_at(expression_location, "invalid operands of type %s and %s for operator %s", @@ -178,15 +211,6 @@ namespace gcc target_type = boolean_type_node; break; } - if (left_type != right_type) - { - error_at(expression_location, - "invalid operands of type %s and %s for operator %s", - print_type(left_type), print_type(right_type), - elna::source::print_binary_operator(expression->operation())); - this->current_expression = error_mark_node; - return; - } gcc_assert(operator_code != ERROR_MARK); gcc_assert(target_type != error_mark_node); @@ -234,6 +258,10 @@ namespace gcc { declaration_type = boolean_type_node; } + else if (declaration->type().base() == "Float") + { + declaration_type = double_type_node; + } else { error_at(get_location(&declaration->type().position()), @@ -385,8 +413,7 @@ namespace gcc { statement->prerequisite().accept(this); - if (TREE_TYPE(this->current_expression) != boolean_type_node - && TREE_TYPE(this->current_expression) != integer_type_node) + if (TREE_TYPE(this->current_expression) != boolean_type_node) { error_at(get_location(&statement->prerequisite().position()), "expected expression of boolean type but its type is %s", diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index c5ce340..6fa35b9 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -27,7 +27,8 @@ namespace gcc public: void visit(source::program *program) override; void visit(source::call_statement *statement) override; - void visit(source::integer_literal *literal) override; + void visit(source::number_literal *literal) override; + void visit(source::number_literal *literal) override; void visit(source::boolean_literal *literal) override; void visit(source::binary_expression *expression) override; void visit(source::constant_definition *definition) override; diff --git a/include/elna/source/ast.h b/include/elna/source/ast.h index 7fc3d7d..c9e797b 100644 --- a/include/elna/source/ast.h +++ b/include/elna/source/ast.h @@ -46,7 +46,8 @@ namespace source class unary_expression; class type_expression; class variable_expression; - class integer_literal; + template + class number_literal; class boolean_literal; /** @@ -68,7 +69,8 @@ namespace source virtual void visit(unary_expression *) = 0; virtual void visit(type_expression *) = 0; virtual void visit(variable_expression *) = 0; - virtual void visit(integer_literal *) = 0; + virtual void visit(number_literal *) = 0; + virtual void visit(number_literal *) = 0; virtual void visit(boolean_literal *) = 0; }; @@ -91,7 +93,8 @@ namespace source 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; + virtual void visit(number_literal *number) override; + virtual void visit(number_literal *) override; virtual void visit(boolean_literal *boolean) override; }; @@ -267,7 +270,7 @@ namespace source */ class constant_definition : public definition { - std::unique_ptr m_body; + std::unique_ptr> m_body; public: /** @@ -276,10 +279,10 @@ namespace source * \param body Constant value. */ constant_definition(const struct position position, const std::string& identifier, - std::unique_ptr&& body); + std::unique_ptr>&& body); virtual void accept(parser_visitor *visitor) override; - integer_literal& body(); + number_literal& body(); }; /** @@ -427,15 +430,26 @@ namespace source virtual void accept(parser_visitor *visitor) override; }; - class integer_literal : public expression + template + class number_literal : public expression { - std::int32_t m_number; + T m_number; public: - integer_literal(const struct position position, const std::int32_t value); - virtual void accept(parser_visitor *visitor) override; + number_literal(const struct position position, const T value) + : expression(position), m_number(value) + { + } - std::int32_t number() const noexcept; + virtual void accept(parser_visitor *visitor) override + { + visitor->visit(this); + } + + T number() const noexcept + { + return m_number; + } }; class boolean_literal : public expression diff --git a/source/ast.cc b/source/ast.cc index b74b64e..b1e72d5 100644 --- a/source/ast.cc +++ b/source/ast.cc @@ -95,7 +95,11 @@ namespace source { } - void empty_visitor::visit(integer_literal *number) + void empty_visitor::visit(number_literal *number) + { + } + + void empty_visitor::visit(number_literal *number) { } @@ -214,7 +218,7 @@ namespace source } constant_definition::constant_definition(const struct position position, const std::string& identifier, - std::unique_ptr&& body) + std::unique_ptr>&& body) : definition(position, identifier), m_body(std::move(body)) { } @@ -224,7 +228,7 @@ namespace source visitor->visit(this); } - integer_literal& constant_definition::body() + number_literal& constant_definition::body() { return *m_body; } @@ -290,21 +294,6 @@ namespace source visitor->visit(this); } - integer_literal::integer_literal(const struct position position, const std::int32_t value) - : expression(position), m_number(value) - { - } - - void integer_literal::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - std::int32_t integer_literal::number() const noexcept - { - return m_number; - } - boolean_literal::boolean_literal(const struct position position, const bool value) : expression(position), m_boolean(value) { diff --git a/source/lexer.ll b/source/lexer.ll index 1b558b2..8aab50f 100644 --- a/source/lexer.ll +++ b/source/lexer.ll @@ -73,6 +73,9 @@ false { [0-9]+ { return yy::parser::make_NUMBER(strtol(yytext, NULL, 10), this->location); } +[0-9]+\.[0-9] { + return yy::parser::make_FLOAT(strtof(yytext, NULL), this->location); + } \( { return yy::parser::make_LEFT_PAREN(this->location); } diff --git a/source/parser.yy b/source/parser.yy index be76e62..3e86256 100644 --- a/source/parser.yy +++ b/source/parser.yy @@ -58,6 +58,7 @@ %token IDENTIFIER "identifier" %token NUMBER "number" +%token FLOAT "float" %token BOOLEAN %token IF WHILE DO %token CONST VAR PROCEDURE @@ -70,7 +71,8 @@ %precedence THEN %precedence ELSE -%type > integer_literal; +%type >> integer_literal; +%type >> float_literal; %type > boolean_literal; %type > constant_definition; %type >> constant_definition_part constant_definitions; @@ -141,7 +143,11 @@ procedure_definition_part: | procedure_definitions { std::swap($$, $1); } integer_literal: NUMBER { - $$ = std::make_unique(elna::source::make_position(@1), $1); + $$ = std::make_unique>(elna::source::make_position(@1), $1); + }; +float_literal: FLOAT + { + $$ = std::make_unique>(elna::source::make_position(@1), $1); }; boolean_literal: BOOLEAN { @@ -179,6 +185,7 @@ if_statement: } pointer: integer_literal { $$ = std::move($1); } + | float_literal { $$ = std::move($1); } | boolean_literal { $$ = std::move($1); } | variable_expression { $$ = std::move($1); } | LEFT_PAREN expression RIGHT_PAREN { $$ = std::move($2); }