From 607bf09434fabc50ef76a357460f25987f5b4f5c Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Sun, 2 Feb 2025 08:22:40 +0100 Subject: [PATCH] Read the input filename from the command line --- boot/ast.cc | 27 +++-- boot/parser.yy | 39 +++----- gcc/elna-diagnostic.cc | 4 - gcc/elna-generic.cc | 172 +++++++++++++++----------------- gcc/elna-tree.cc | 47 +++++++-- include/elna/boot/ast.h | 9 +- include/elna/gcc/elna-generic.h | 13 ++- include/elna/gcc/elna-tree.h | 9 +- source.elna | 75 +++++++------- 9 files changed, 213 insertions(+), 182 deletions(-) diff --git a/boot/ast.cc b/boot/ast.cc index ccca46e..80d52e7 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -92,9 +92,13 @@ namespace boot void empty_visitor::visit(block *block) { - for (const auto definition : block->value_definitions) + for (const auto constant : block->constants) { - definition->accept(this); + constant->accept(this); + } + for (const auto variable : block->variables) + { + variable->accept(this); } for (const auto body_statement : block->body) { @@ -474,9 +478,8 @@ namespace boot delete m_body; } - block::block(const struct position position, std::vector&& value_definitions, - std::vector&& body) - : node(position), value_definitions(std::move(value_definitions)), body(std::move(body)) + block::block(const struct position position) + : node(position) { } @@ -487,9 +490,13 @@ namespace boot block::~block() { - for (auto definition : this->value_definitions) + for (auto variable : this->variables) { - delete definition; + delete variable; + } + for (auto constant : this->constants) + { + delete constant; } for (auto body_statement : this->body) { @@ -497,10 +504,8 @@ namespace boot } } - program::program(const struct position position, - std::vector&& type_definitions, - std::vector&& value_definitions, std::vector&& body) - : block(position, std::move(value_definitions), std::move(body)), + program::program(const struct position position, std::vector&& type_definitions) + : block(position), type_definitions(std::move(type_definitions)) { } diff --git a/boot/parser.yy b/boot/parser.yy index af986ce..efc7667 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -111,49 +111,34 @@ %type cast_expression; %% program: - type_part constant_part procedure_part variable_part BEGIN_BLOCK optional_statements END_BLOCK DOT + type_part constant_part variable_part procedure_part BEGIN_BLOCK optional_statements END_BLOCK DOT { - std::vector definitions($1.size() + $3.size()); + std::vector definitions($1.size() + $4.size()); std::vector::iterator definition = definitions.begin(); - std::vector value_definitions($2.size() + $4.size()); - std::vector::iterator value_definition = value_definitions.begin(); for (auto type : $1) { *definition++ = type; } - for (auto constant : $2) - { - *value_definition++ = constant; - } - for (auto procedure : $3) + for (auto procedure : $4) { *definition++ = procedure; } - for (auto variable : $4) - { - *value_definition++ = variable; - } - auto tree = new elna::boot::program(elna::boot::make_position(@5), - std::move(definitions), std::move(value_definitions), std::move($6)); + auto tree = new elna::boot::program(elna::boot::make_position(@5), std::move(definitions)); + + std::swap(tree->constants, $2); + std::swap(tree->variables, $3); + std::swap(tree->body, $6); driver.tree.reset(tree); } block: constant_part variable_part BEGIN_BLOCK optional_statements END_BLOCK { - std::vector definitions($1.size() + $2.size()); - std::vector::iterator definition = definitions.begin(); + $$ = new elna::boot::block(elna::boot::make_position(@3)); - for (auto constant : $1) - { - *definition++ = constant; - } - for (auto variable : $2) - { - *definition++ = variable; - } - $$ = new elna::boot::block(elna::boot::make_position(@3), - std::move(definitions), std::move($4)); + std::swap($$->constants, $1); + std::swap($$->variables, $2); + std::swap($$->body, $4); } procedure_definition: PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON block SEMICOLON diff --git a/gcc/elna-diagnostic.cc b/gcc/elna-diagnostic.cc index edd52dd..c05321c 100644 --- a/gcc/elna-diagnostic.cc +++ b/gcc/elna-diagnostic.cc @@ -36,10 +36,6 @@ namespace gcc { return "Char"; } - else if (is_string_type(type)) - { - return "String"; - } else if (is_pointer_type(type)) { return "pointer"; diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 35e451a..0bea5f3 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -86,16 +86,44 @@ namespace gcc || type == this->symbol_map->lookup("Word")->payload; } + bool generic_visitor::is_numeric_type(tree type) + { + return is_integral_type(type) + || type == this->symbol_map->lookup("Float")->payload; + } + void generic_visitor::visit(boot::program *program) { - for (const auto definition : program->value_definitions) + for (const auto& type_definition : program->type_definitions) { - definition->accept(this); + type_definition->accept(this); } - for (const auto& constant : program->type_definitions) + for (const auto constant : program->constants) { constant->accept(this); } + for (const auto declaration : program->variables) + { + tree declaration_type = build_type(declaration->type()); + gcc_assert(declaration_type != NULL_TREE); + + auto declaration_location = get_location(&declaration->position()); + tree declaration_tree = build_decl(declaration_location, VAR_DECL, + get_identifier(declaration->identifier().c_str()), declaration_type); + auto result = this->symbol_map->enter(declaration->identifier(), boot::make_info(declaration_tree)); + + if (result) + { + TREE_STATIC(declaration_tree) = 1; + varpool_node::get_create(declaration_tree); + varpool_node::finalize_decl(declaration_tree); + } + else + { + error_at(declaration_location, "variable '%s' already declared in this scope", + declaration->identifier().c_str()); + } + } std::array parameter_types{ integer_type_node, build_pointer_type(build_pointer_type(char_type_node)) @@ -278,49 +306,57 @@ namespace gcc this->current_expression = build_string_literal(string->string().size() + 1, string->string().c_str()); } - void generic_visitor::build_binary_operation(bool condition, boot::binary_expression *expression, - tree_code operator_code, tree left, tree right, tree target_type) + tree generic_visitor::build_arithmetic_operation(boot::binary_expression *expression, + tree_code operator_code, tree left, tree right) { - auto expression_location = get_location(&expression->position()); - auto left_type = TREE_TYPE(left); - auto right_type = TREE_TYPE(right); + return build_binary_operation(is_numeric_type(TREE_TYPE(left)), + expression, operator_code, left, right, TREE_TYPE(left)); + } - if (condition) - { - this->current_expression = build2_loc(expression_location, - operator_code, target_type, left, right); - } - else - { - error_at(expression_location, - "invalid operands of type %s and %s for operator %s", - print_type(left_type), print_type(right_type), - elna::boot::print_binary_operator(expression->operation())); - this->current_expression = error_mark_node; - } + tree generic_visitor::build_comparison_operation(boot::binary_expression *expression, + tree_code operator_code, tree left, tree right) + { + return build_binary_operation(is_numeric_type(TREE_TYPE(left)) || is_pointer_type(TREE_TYPE(left)), + expression, operator_code, left, right, this->symbol_map->lookup("Bool")->payload); + } + + tree generic_visitor::build_logic_operation(boot::binary_expression *expression, + tree_code operator_code, tree left, tree right) + { + auto symbol = this->symbol_map->lookup("Bool"); + + return build_binary_operation(TREE_TYPE(left) == symbol->payload, + expression, operator_code, left, right, symbol->payload); + } + + tree generic_visitor::build_equality_operation(boot::binary_expression *expression, + tree_code operator_code, tree left, tree right) + { + return build_binary_operation(true, expression, + operator_code, left, right, this->symbol_map->lookup("Bool")->payload); } void generic_visitor::visit(boot::binary_expression *expression) { expression->lhs().accept(this); - auto left = this->current_expression; - auto left_type = TREE_TYPE(left); + tree left = this->current_expression; + tree left_type = TREE_TYPE(left); expression->rhs().accept(this); - auto right = this->current_expression; - auto right_type = TREE_TYPE(right); + tree right = this->current_expression; + tree right_type = TREE_TYPE(right); - auto expression_location = get_location(&expression->position()); - tree_code operator_code = ERROR_MARK; - tree target_type = error_mark_node; + location_t expression_location = get_location(&expression->position()); - if (is_pointer_type(left_type) && is_integral_type(right_type) - && expression->operation() == boot::binary_operator::sum) + if (is_pointer_type(left_type) && is_integral_type(right_type)) { - tree convert_expression = build1_loc(expression_location, CONVERT_EXPR, - sizetype, right); - this->current_expression = build2_loc(expression_location, - POINTER_PLUS_EXPR, left_type, left, convert_expression); + this->current_expression = do_pointer_arithmetic(expression->operation(), left, right); + if (this->current_expression == error_mark_node) + { + error_at(expression_location, + "invalid operation %s on a pointer and an integral type", + boot::print_binary_operator(expression->operation())); + } return; } if (left_type != right_type) @@ -335,87 +371,45 @@ namespace gcc switch (expression->operation()) { case boot::binary_operator::sum: - operator_code = PLUS_EXPR; - target_type = left_type; + this->current_expression = build_arithmetic_operation(expression, PLUS_EXPR, left, right); break; case boot::binary_operator::subtraction: - operator_code = MINUS_EXPR; - target_type = left_type; + this->current_expression = build_arithmetic_operation(expression, MINUS_EXPR, left, right); break; case boot::binary_operator::division: - operator_code = TRUNC_DIV_EXPR; - target_type = left_type; + this->current_expression = build_arithmetic_operation(expression, TRUNC_DIV_EXPR, left, right); break; case boot::binary_operator::remainder: - operator_code = TRUNC_MOD_EXPR; - target_type = left_type; + this->current_expression = build_arithmetic_operation(expression, TRUNC_MOD_EXPR, left, right); break; case boot::binary_operator::multiplication: - operator_code = MULT_EXPR; - target_type = left_type; + this->current_expression = build_arithmetic_operation(expression, MULT_EXPR, left, right); break; case boot::binary_operator::less: - operator_code = LT_EXPR; - target_type = boolean_type_node; + this->current_expression = build_comparison_operation(expression, LT_EXPR, left, right); break; case boot::binary_operator::greater: - operator_code = GT_EXPR; - target_type = boolean_type_node; + this->current_expression = build_comparison_operation(expression, GT_EXPR, left, right); break; case boot::binary_operator::less_equal: - operator_code = LE_EXPR; - target_type = boolean_type_node; + this->current_expression = build_comparison_operation(expression, LE_EXPR, left, right); break; case boot::binary_operator::greater_equal: - operator_code = GE_EXPR; - target_type = boolean_type_node; + this->current_expression = build_comparison_operation(expression, GE_EXPR, left, right); break; - default: - break; - } - if (operator_code != ERROR_MARK) // An arithmetic operation. - { - build_binary_operation(is_integral_type(left_type) || left_type == double_type_node, - expression, operator_code, left, right, target_type); - return; - } - switch (expression->operation()) - { case boot::binary_operator::conjunction: - operator_code = TRUTH_ANDIF_EXPR; - target_type = boolean_type_node; + this->current_expression = build_logic_operation(expression, TRUTH_ANDIF_EXPR, left, right); break; case boot::binary_operator::disjunction: - operator_code = TRUTH_ORIF_EXPR; - target_type = boolean_type_node; + this->current_expression = build_logic_operation(expression, TRUTH_ORIF_EXPR, left, right); break; - default: - break; - } - if (operator_code != ERROR_MARK) // A logical operation. - { - build_binary_operation(left_type == boolean_type_node, - expression, operator_code, left, right, target_type); - return; - } - switch (expression->operation()) - { case boot::binary_operator::equals: - operator_code = EQ_EXPR; - target_type = boolean_type_node; + this->current_expression = build_equality_operation(expression, EQ_EXPR, left, right); break; case boot::binary_operator::not_equals: - operator_code = NE_EXPR; - target_type = boolean_type_node; - break; - default: + this->current_expression = build_equality_operation(expression, NE_EXPR, left, right); break; } - gcc_assert(operator_code != ERROR_MARK); - gcc_assert(target_type != error_mark_node); - - this->current_expression = build2_loc(expression_location, - operator_code, target_type, left, right); } void generic_visitor::visit(boot::unary_expression *expression) diff --git a/gcc/elna-tree.cc b/gcc/elna-tree.cc index 56d916c..ce0d91d 100644 --- a/gcc/elna-tree.cc +++ b/gcc/elna-tree.cc @@ -1,6 +1,9 @@ #include "elna/gcc/elna-tree.h" +#include "elna/gcc/elna-diagnostic.h" #include "stor-layout.h" +#include "fold-const.h" +#include "diagnostic-core.h" tree elna_global_trees[ELNA_TI_MAX]; @@ -20,12 +23,6 @@ namespace gcc return TREE_CODE(type) == POINTER_TYPE; } - bool is_string_type(tree type) - { - return is_pointer_type(type) - && TYPE_MAIN_VARIANT(TREE_TYPE(type)) == char_type_node; - } - tree tree_chain_base::head() { return first; @@ -81,5 +78,43 @@ namespace gcc return initial_table; } + + tree do_pointer_arithmetic(boot::binary_operator binary_operator, tree left, tree right) + { + tree result = error_mark_node; + tree convert_expression = fold_convert(sizetype, right); + + if (binary_operator == boot::binary_operator::sum) + { + result = fold_build2(POINTER_PLUS_EXPR, TREE_TYPE(left), left, convert_expression); + } + else if (binary_operator == boot::binary_operator::subtraction) + { + convert_expression = fold_build1(NEGATE_EXPR, sizetype, convert_expression); + result = fold_build2(POINTER_PLUS_EXPR, TREE_TYPE(left), left, convert_expression); + } + return result; + } + + tree build_binary_operation(bool condition, boot::binary_expression *expression, + tree_code operator_code, tree left, tree right, tree target_type) + { + location_t expression_location = get_location(&expression->position()); + tree left_type = TREE_TYPE(left); + tree right_type = TREE_TYPE(right); + + if (condition) + { + return build2_loc(expression_location, operator_code, target_type, left, right); + } + else + { + error_at(expression_location, + "invalid operands of type %s and %s for operator %s", + print_type(left_type), print_type(right_type), + elna::boot::print_binary_operator(expression->operation())); + return error_mark_node; + } + } } } diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index fee9759..7fce234 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -637,11 +637,11 @@ namespace boot class block : public node { public: - std::vector value_definitions; + std::vector variables; + std::vector constants; std::vector body; - block(const struct position position, std::vector&& value_definitions, - std::vector&& body); + block(const struct position position); virtual void accept(parser_visitor *visitor) override; virtual ~block() override; @@ -652,8 +652,7 @@ namespace boot public: std::vector type_definitions; - program(const struct position position, std::vector&& type_definitions, - std::vector&& value_definitions, std::vector&& body); + program(const struct position position, std::vector&& type_definitions); virtual void accept(parser_visitor *visitor) override; virtual ~program() override; diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index cc9c471..c93f938 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -31,12 +31,19 @@ namespace gcc void enter_scope(); tree_symbol_mapping leave_scope(); - void build_binary_operation(bool condition, boot::binary_expression *expression, - tree_code operator_code, tree left, tree right, tree target_type); - void make_if_branch(boot::conditional_statements& branch, tree goto_endif); bool is_integral_type(tree type); + bool is_numeric_type(tree type); + + tree build_arithmetic_operation(boot::binary_expression *expression, + tree_code operator_code, tree left, tree right); + tree build_comparison_operation(boot::binary_expression *expression, + tree_code operator_code, tree left, tree right); + tree build_logic_operation(boot::binary_expression *expression, + tree_code operator_code, tree left, tree right); + tree build_equality_operation(boot::binary_expression *expression, + tree_code operator_code, tree left, tree right); public: generic_visitor(std::shared_ptr> symbol_table); diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h index dada145..d2eacdf 100644 --- a/include/elna/gcc/elna-tree.h +++ b/include/elna/gcc/elna-tree.h @@ -4,8 +4,8 @@ #include "system.h" #include "coretypes.h" #include "tree.h" -#include "tree.h" +#include "elna/boot/ast.h" #include "elna/boot/symbol.h" enum elna_tree_index @@ -24,7 +24,6 @@ namespace gcc { void init_ttree(); bool is_pointer_type(tree type); - bool is_string_type(tree type); class tree_chain_base { @@ -58,5 +57,11 @@ namespace gcc }; std::shared_ptr> builtin_symbol_table(); + + tree do_pointer_arithmetic(boot::binary_operator binary_operator, tree left, tree right); + tree build_binary_operation(bool condition, boot::binary_expression *expression, + tree_code operator_code, tree left, tree right, tree target_type); + tree build_arithmetic_operation(boot::binary_expression *expression, + tree_code operator_code, tree left, tree right); } } diff --git a/source.elna b/source.elna index c53c785..b66f7c0 100644 --- a/source.elna +++ b/source.elna @@ -20,6 +20,9 @@ type end, FILE = record dummy: Int + end, + CommandLine = record + input: pointer to Char end; const @@ -141,19 +144,6 @@ end; End of standard procedures. *) -proc test_primitive(); -begin - write_s("\nTest primitives:\n"); - write_u(25u); - write_c('\n'); - - write_i(8); - write_c('\n'); - - write_b(true); - write_c('\n') -end; - proc read_source(filename: String): pointer to Char; var input_file: pointer to FILE, @@ -272,7 +262,7 @@ var is_valid: Bool; begin token_end := input; - previous := cast(cast(input as Word) - 1u as pointer to Char); + previous := input - 1; while token_end^ <> '\0' and not (previous^ <> '\\' and token_end^ = '"') do previous := token_end; @@ -286,7 +276,7 @@ begin is_valid := true; constructed_string := current_token^.value.string_value; - while cast(input as Word) < cast(token_end as Word) and is_valid do + while input < token_end and is_valid do if input^ = '\\' then input := input + 1; @@ -677,32 +667,51 @@ begin return tokens end; -proc command_line(argc: Int, argv: pointer to pointer to Char); +proc parse_command_line(argc: Int, argv: pointer to pointer to Char): pointer to CommandLine; var parameter: pointer to pointer to Char, - i: Int; + i: Int, + result: pointer to CommandLine; begin - write_s("Argument count: "); - write_i(argc - 1); - write_s("\nArguments:"); + if argc < 2 then + write_s("Fatal error: no input files.\n"); + return nil + end; + if argc > 2 then + write_s("Fatal error: Unknown command line options:"); - i := 1; - while i < argc do - parameter := argv + i * cast(sizeof(pointer to Char) as Int); + i := 2; + while i < argc do + parameter := argv + i * cast(sizeof(pointer to Char) as Int); + + write_c(' '); + write_s(parameter^); + i := i + 1 + end; + write_s(".\n"); + return nil + end; - write_c(' '); - write_s(parameter^); - i := i + 1 - end + parameter := argv + cast(sizeof(pointer to Char) as Int); + result := cast(malloc(sizeof(CommandLine)) as pointer to CommandLine); + result^.input := parameter^; + + return result end; -proc compile(); +proc process(argc: Int, argv: pointer to pointer to Char): Int; var input: pointer to Char, tokens: pointer to Token, - tokens_size: Word; + tokens_size: Word, + command_line: pointer to CommandLine; begin - input := read_source("example.elna"); + command_line := parse_command_line(argc, argv); + + if cast(command_line as Word) = 0u then + return 2 + end; + input := read_source(command_line^.input); tokens := tokenize(input, @tokens_size); free(input); @@ -711,9 +720,5 @@ begin end; begin - command_line(count, parameters); - compile(); - test_primitive(); - - exit(0) + exit(process(count, parameters)) end.