From aab16e49413c378398e6a1d5d5c1d3d6a42ee0d2 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Mon, 3 Feb 2025 23:04:00 +0100 Subject: [PATCH] Allow comparing all pointer types to nil --- boot/ast.cc | 49 ++++++------ boot/parser.yy | 19 ++--- gcc/elna-generic.cc | 63 +++++++--------- gcc/elna-tree.cc | 6 ++ include/elna/boot/ast.h | 5 +- include/elna/gcc/elna-tree.h | 1 + source.elna | 142 +++++++++++++++++++++++++++++------ 7 files changed, 187 insertions(+), 98 deletions(-) diff --git a/boot/ast.cc b/boot/ast.cc index 80d52e7..49854ae 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -92,15 +92,15 @@ namespace boot void empty_visitor::visit(block *block) { - for (const auto constant : block->constants) + for (constant_definition *const constant : block->constants) { constant->accept(this); } - for (const auto variable : block->variables) + for (variable_declaration *const variable : block->variables) { variable->accept(this); } - for (const auto body_statement : block->body) + for (statement *const body_statement : block->body) { body_statement->accept(this); } @@ -108,11 +108,15 @@ namespace boot void empty_visitor::visit(program *program) { - for (auto definition : program->type_definitions) - { - definition->accept(this); - } visit(reinterpret_cast(program)); + for (type_definition *const type : program->types) + { + type->accept(this); + } + for (procedure_definition *const procedure : program->procedures) + { + procedure->accept(this); + } } void empty_visitor::visit(binary_expression *expression) @@ -490,23 +494,22 @@ namespace boot block::~block() { - for (auto variable : this->variables) - { - delete variable; - } - for (auto constant : this->constants) - { - delete constant; - } - for (auto body_statement : this->body) + for (statement *body_statement : this->body) { delete body_statement; } + for (variable_declaration *variable : this->variables) + { + delete variable; + } + for (constant_definition *constant : this->constants) + { + delete constant; + } } - program::program(const struct position position, std::vector&& type_definitions) - : block(position), - type_definitions(std::move(type_definitions)) + program::program(const struct position position) + : block(position) { } @@ -517,9 +520,13 @@ namespace boot program::~program() { - for (auto definition : type_definitions) + for (procedure_definition *procedure : this->procedures) { - delete definition; + delete procedure; + } + for (type_definition *type : this->types) + { + delete type; } } diff --git a/boot/parser.yy b/boot/parser.yy index efc7667..f2371ae 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -111,23 +111,14 @@ %type cast_expression; %% program: - type_part constant_part variable_part procedure_part BEGIN_BLOCK optional_statements END_BLOCK DOT + constant_part type_part variable_part procedure_part BEGIN_BLOCK optional_statements END_BLOCK DOT { - std::vector definitions($1.size() + $4.size()); - std::vector::iterator definition = definitions.begin(); + auto tree = new elna::boot::program(elna::boot::make_position(@5)); - for (auto type : $1) - { - *definition++ = type; - } - for (auto procedure : $4) - { - *definition++ = procedure; - } - auto tree = new elna::boot::program(elna::boot::make_position(@5), std::move(definitions)); - - std::swap(tree->constants, $2); + std::swap(tree->constants, $1); + std::swap(tree->types , $2); std::swap(tree->variables, $3); + std::swap(tree->procedures, $4); std::swap(tree->body, $6); driver.tree.reset(tree); diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 0bea5f3..ad9ab53 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -94,35 +94,21 @@ namespace gcc void generic_visitor::visit(boot::program *program) { - for (const auto& type_definition : program->type_definitions) - { - type_definition->accept(this); - } - for (const auto constant : program->constants) + for (boot::constant_definition *const constant : program->constants) { constant->accept(this); } - for (const auto declaration : program->variables) + for (boot::type_definition *const type : program->types) { - 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()); - } + type->accept(this); + } + for (boot::variable_declaration *const variable : program->variables) + { + variable->accept(this); + } + for (boot::procedure_definition *const procedure : program->procedures) + { + procedure->accept(this); } std::array parameter_types{ integer_type_node, @@ -149,7 +135,7 @@ namespace gcc } DECL_ARGUMENTS(this->main_fndecl) = argument_chain.head(); - for (const auto body_statement : program->body) + for (boot::statement *const body_statement : program->body) { body_statement->accept(this); } @@ -359,7 +345,7 @@ namespace gcc } return; } - if (left_type != right_type) + if (left_type != right_type && !are_compatible_pointers(left, right)) { error_at(expression_location, "invalid operands of type %s and %s for operator %s", @@ -601,12 +587,23 @@ namespace gcc tree declaration_type = build_type(declaration->type()); gcc_assert(declaration_type != NULL_TREE); - auto declaration_location = get_location(&declaration->position()); + location_t 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)); + bool result = this->symbol_map->enter(declaration->identifier(), boot::make_info(declaration_tree)); - if (result) + if (!result) + { + error_at(declaration_location, "variable '%s' already declared in this scope", + declaration->identifier().c_str()); + } + else if (this->main_fndecl == NULL_TREE) + { + TREE_STATIC(declaration_tree) = 1; + varpool_node::get_create(declaration_tree); + varpool_node::finalize_decl(declaration_tree); + } + else { DECL_CONTEXT(declaration_tree) = this->main_fndecl; variable_chain.append(declaration_tree); @@ -615,12 +612,6 @@ namespace gcc void_type_node, declaration_tree); append_to_statement_list(declaration_statement, &this->current_statements); } - else - { - error_at(declaration_location, - "variable '%s' already declared in this scope", - declaration->identifier().c_str()); - } } void generic_visitor::visit(boot::variable_expression *expression) diff --git a/gcc/elna-tree.cc b/gcc/elna-tree.cc index ce0d91d..7bf23cc 100644 --- a/gcc/elna-tree.cc +++ b/gcc/elna-tree.cc @@ -23,6 +23,12 @@ namespace gcc return TREE_CODE(type) == POINTER_TYPE; } + bool are_compatible_pointers(tree lhs, tree rhs) + { + return (lhs == null_pointer_node || rhs == null_pointer_node) + && is_pointer_type(TREE_TYPE(lhs)) && is_pointer_type(TREE_TYPE(rhs)); + } + tree tree_chain_base::head() { return first; diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index 7fce234..18150b1 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -650,9 +650,10 @@ namespace boot class program : public block { public: - std::vector type_definitions; + std::vector types; + std::vector procedures; - program(const struct position position, std::vector&& type_definitions); + program(const struct position position); virtual void accept(parser_visitor *visitor) override; virtual ~program() override; diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h index d2eacdf..536b50c 100644 --- a/include/elna/gcc/elna-tree.h +++ b/include/elna/gcc/elna-tree.h @@ -24,6 +24,7 @@ namespace gcc { void init_ttree(); bool is_pointer_type(tree type); + bool are_compatible_pointers(tree lhs, tree rhs); class tree_chain_base { diff --git a/source.elna b/source.elna index b66f7c0..4258e7d 100644 --- a/source.elna +++ b/source.elna @@ -1,3 +1,21 @@ +const + SEEK_SET = 0, SEEK_CUR = 1, SEEK_END = 2, + + TOKEN_IDENTIFIER = 1, TOKEN_IF = 2, TOKEN_THEN = 3, TOKEN_ELSE = 4, TOKEN_ELSIF = 5, + TOKEN_WHILE = 6, TOKEN_DO = 7, TOKEN_PROC = 8, TOKEN_BEGIN = 9, TOKEN_END = 10, + TOKEN_EXTERN = 11, TOKEN_CONST = 12, TOKEN_VAR = 13, TOKEN_ARRAY = 14, TOKEN_OF = 15, + TOKEN_TYPE = 16, TOKEN_RECORD = 17, TOKEN_UNION = 18, TOKEN_POINTER = 19, TOKEN_TO = 20, + TOKEN_BOOLEAN = 21, TOKEN_NIL = 22, TOKEN_AND = 23, TOKEN_OR = 24, TOKEN_NOT = 25, + TOKEN_RETURN = 26, TOKEN_CAST = 27, TOKEN_AS = 28, TOKEN_SIZEOF = 29, + TOKEN_LEFT_PAREN = 30, TOKEN_RIGHT_PAREN = 31, TOKEN_LEFT_SQUARE = 32, + TOKEN_RIGHT_SQUARE = 33, TOKEN_GREATER_EQUAL = 34, TOKEN_LESS_EQUAL = 35, + TOKEN_GREATER_THAN = 36, TOKEN_LESS_THAN = 37, TOKEN_NOT_EQUAL = 38, TOKEN_EQUAL = 39, + TOKEN_SEMICOLON = 40, TOKEN_DOT = 41, TOKEN_COMMA = 42, + TOKEN_PLUS = 43, TOKEN_MINUS = 44, TOKEN_MULTIPLICATION = 45, TOKEN_DIVISION = 46, + TOKEN_REMAINDER = 47, TOKEN_ASSIGNMENT = 48, TOKEN_COLON = 49, TOKEN_HAT = 50, + TOKEN_AT = 51, TOKEN_COMMENT = 52, TOKEN_INTEGER = 53, TOKEN_WORD = 54, + TOKEN_CHARACTER = 55, TOKEN_STRING = 56; + type Position = record line: Word; @@ -23,32 +41,29 @@ type end, CommandLine = record input: pointer to Char + end, + Literal = record + value: Int + end, + ConstantDefinition = record + name: pointer to Char; + body: pointer to Literal + end, + ConstantPart = record + elements: pointer to pointer to ConstantDefinition; + count: Word + end, + Program = record + constants: ConstantPart end; -const - SEEK_SET = 0, SEEK_CUR = 1, SEEK_END = 2, - - TOKEN_IDENTIFIER = 1, TOKEN_IF = 2, TOKEN_THEN = 3, TOKEN_ELSE = 4, TOKEN_ELSIF = 5, - TOKEN_WHILE = 6, TOKEN_DO = 7, TOKEN_PROC = 8, TOKEN_BEGIN = 9, TOKEN_END = 10, - TOKEN_EXTERN = 11, TOKEN_CONST = 12, TOKEN_VAR = 13, TOKEN_ARRAY = 14, TOKEN_OF = 15, - TOKEN_TYPE = 16, TOKEN_RECORD = 17, TOKEN_UNION = 18, TOKEN_POINTER = 19, TOKEN_TO = 20, - TOKEN_BOOLEAN = 21, TOKEN_NIL = 22, TOKEN_AND = 23, TOKEN_OR = 24, TOKEN_NOT = 25, - TOKEN_RETURN = 26, TOKEN_CAST = 27, TOKEN_AS = 28, TOKEN_SIZEOF = 29, - TOKEN_LEFT_PAREN = 30, TOKEN_RIGHT_PAREN = 31, TOKEN_LEFT_SQUARE = 32, - TOKEN_RIGHT_SQUARE = 33, TOKEN_GREATER_EQUAL = 34, TOKEN_LESS_EQUAL = 35, - TOKEN_GREATER_THAN = 36, TOKEN_LESS_THAN = 37, TOKEN_NOT_EQUAL = 38, TOKEN_EQUAL = 39, - TOKEN_SEMICOLON = 40, TOKEN_DOT = 41, TOKEN_COMMA = 42, - TOKEN_PLUS = 43, TOKEN_MINUS = 44, TOKEN_MULTIPLICATION = 45, TOKEN_DIVISION = 46, - TOKEN_REMAINDER = 47, TOKEN_ASSIGNMENT = 48, TOKEN_COLON = 49, TOKEN_HAT = 50, - TOKEN_AT = 51, TOKEN_COMMENT = 52, TOKEN_INTEGER = 53, TOKEN_WORD = 54, - TOKEN_CHARACTER = 55, TOKEN_STRING = 56; - (* External procedures. *) proc fopen(pathname: String, mode: String): pointer to FILE; extern; proc fclose(stream: pointer to FILE): Int; extern; proc fseek(stream: pointer to FILE, off: Int, whence: Int): Int; extern; +proc rewind(stream: pointer to FILE); extern; proc ftell(stream: pointer to FILE): Int; extern; proc fread(ptr: pointer to Byte, size: Word, nmemb: Word, stream: pointer to FILE): Word; extern; proc write(fd: Int, buf: pointer to Byte, Word: Int): Int; extern; @@ -63,10 +78,12 @@ proc memset(ptr: pointer to Char, c: Int, n: Int): pointer to Char; extern; proc strncmp(s1: pointer to Char, s2: pointer to Char, n: Word): Int; extern; proc strncpy(dst: pointer to Char, src: pointer to Char, dsize: Word): pointer to Char; extern; +proc strcpy(dst: pointer to Char, src: pointer to Char): pointer to Char; extern; proc strlen(ptr: pointer to Char): Word; extern; proc strtol(nptr: pointer to Char, endptr: pointer to pointer to Char, base: Int): Int; extern; +proc perror(s: pointer to Char); extern; proc exit(code: Int); extern; (* @@ -152,13 +169,24 @@ var begin input_file := fopen(filename, "rb"); - fseek(input_file, 0, SEEK_END); + if input_file = nil then + return nil + end; + if fseek(input_file, 0, SEEK_END) <> 0 then + fclose(input_file); + return nil + end; source_size := ftell(input_file); - fseek(input_file, 0, SEEK_SET); + if source_size < 0 then + fclose(input_file); + return nil + end; + rewind(input_file); input := calloc(source_size + 1, 1); - fread(input, source_size, 1, input_file); - + if fread(input, source_size, 1, input_file) <> 1u then + input := cast(nil as pointer to Byte) + end; fclose(input_file); return input @@ -551,7 +579,7 @@ begin if input_pointer^ = '*' then token_end := lex_comment(input_pointer + 1); - if token_end <> cast(nil as pointer to Char) then + if token_end <> nil then token_length := cast(token_end as Word) - cast(input_pointer as Word); current_token^.value.string_value := cast(calloc(token_length + 1u, 1) as pointer to Char); strncpy(current_token^.value.string_value, input_pointer, token_length); @@ -667,6 +695,65 @@ begin return tokens end; +proc parse_literal(tokens: pointer to pointer to Token, tokens_size: pointer to Word): pointer to Literal; +begin + return cast(calloc(1, sizeof(Literal)) as pointer to Literal) +end; + +proc parse_constant_definition(tokens: pointer to pointer to Token, + tokens_size: pointer to Word): pointer to ConstantDefinition; +var + result: pointer to ConstantDefinition; +begin + result := cast(calloc(1, sizeof(ConstantDefinition)) as pointer to ConstantDefinition); + + result^.name := cast(malloc(strlen(tokens^^.value.string_value)) as pointer to Char); + strcpy(result^.name, tokens^^.value.string_value); + + tokens^ := tokens^ + sizeof(Token) * 2u; + tokens_size := tokens_size - sizeof(Token) * 2u; + + write_s(result^.name); + write_c('\n'); + + result^.body := parse_literal(tokens, tokens_size); + + tokens^ := tokens^ + sizeof(Token) * 2u; + tokens_size := tokens_size - sizeof(Token) * 2u; + + return result +end; + +proc parse_program(tokens: pointer to pointer to Token, tokens_size: pointer to Word): pointer to Program; +var + result: pointer to Program, + current_constant: pointer to pointer to ConstantDefinition; +begin + result := cast(calloc(1, sizeof(Program)) as pointer to Program); + + result^.constants.elements := cast(nil as pointer to pointer to ConstantDefinition); + result^.constants.count := 0u; + + if tokens^^.kind = TOKEN_CONST then + tokens^ := tokens^ + sizeof(Token); + tokens_size^ := tokens_size^ - sizeof(Token); + + while tokens_size^ > 0u and tokens^^.kind = TOKEN_IDENTIFIER do + result^.constants.elements := cast( + reallocarray(result^.constants.elements, result^.constants.count + 1u, sizeof(pointer to ConstantDefinition)) + as pointer to pointer to ConstantDefinition); + current_constant := result^.constants.elements + result^.constants.count * sizeof(pointer to ConstantDefinition); + + result^.constants.count := result^.constants.count + 1u; + + current_constant^ := parse_constant_definition(tokens, tokens_size); + if current_constant^ = nil then + return nil + end + end + end +end; + proc parse_command_line(argc: Int, argv: pointer to pointer to Char): pointer to CommandLine; var parameter: pointer to pointer to Char, @@ -712,11 +799,16 @@ begin return 2 end; input := read_source(command_line^.input); + if input = nil then + perror(command_line^.input); + return 3 + end; tokens := tokenize(input, @tokens_size); - free(input); + print_tokens(tokens, tokens_size); - print_tokens(tokens, tokens_size) + parse_program(@tokens, @tokens_size); + return 0 end; begin