diff --git a/example.elna b/example.elna index eeef53d..e1260e1 100644 --- a/example.elna +++ b/example.elna @@ -1,7 +1,7 @@ type TokenValue = union intValue: Int; - stringValue: String + stringValue: pointer to Char end, Token = record kind: Int; @@ -12,7 +12,9 @@ type end; const - SEEK_SET = 0, SEEK_CUR = 1, SEEK_END = 2; + SEEK_SET = 0, SEEK_CUR = 1, SEEK_END = 2, + POINTER_SIZE = 8, TOKEN_SIZE = 16, + TOKEN_IDENTIFIER = 1; -- -- External procedures. @@ -27,9 +29,13 @@ proc write(fd: Int, buf: pointer to Char, count: Int): Int; extern; proc malloc(size: Int): pointer to Char; extern; proc free(ptr: pointer to Char); extern; proc calloc(nmemb: Int, size: Int): pointer to Char; extern; +proc realloc(ptr: pointer to Char, size: Int): pointer to Char; extern; 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 strncpy(dst: pointer to Char, src: pointer to Char, dsize: Word): pointer to Char; extern; proc strlen(ptr: pointer to Char): Word; extern; proc exit(code: Int); extern; @@ -68,7 +74,7 @@ begin digit := value % 10; value := value / 10; - buffer[n] := Char(Int('0') + digit); + buffer[n] := cast(cast('0' as Int) + digit as Char); n := n - 1 end; while n < 10 do @@ -82,6 +88,26 @@ begin write_i(value) end; +proc is_digit(c: Char): Bool; +begin + return cast(c as Int) >= cast('0' as Int) and cast(c as Int) <= cast('9' as Int) +end; + +proc is_alpha(c: Char): Bool; +begin + return cast(c as Int) >= cast('A' as Int) and cast(c as Int) <= cast('z' as Int) +end; + +proc is_alnum(c: Char): Bool; +begin + return is_digit(c) or is_alpha(c) +end; + +proc is_space(c: Char): Bool; +begin + return c = ' ' or c = '\n' +end; + -- -- End of standard procedures. -- @@ -130,17 +156,68 @@ begin return input end; +proc skip_spaces(input: pointer to Char): pointer to Char; +begin + while is_space(input^) do + input := input + 1 + end; + return input +end; + +proc lex_identifier(input: pointer to Char): pointer to Char; +begin + while is_alnum(input^) or input^ = '_' do + input := input + 1 + end; + return input +end; + proc compile(); var input: pointer to Char, - input_pointer: pointer to Char; + input_pointer: pointer to Char, + token_end: pointer to Char, + token_length: Int, + tokens: pointer to Token, + current_token: pointer to Token, + tokens_size: Int, + i: Int; begin + tokens_size := 0; + tokens := cast(0 as pointer to Token); + input := read_source("example.elna"); - input_pointer := input; + input_pointer := skip_spaces(input); + while input_pointer^ /= '\0' do - write(0, input_pointer, 1); - input_pointer := input_pointer + 1 + if is_alpha(input_pointer^) or input_pointer^ = '_' then + token_end := lex_identifier(input_pointer + 1); + token_length := cast(token_end as Int) - cast(input_pointer as Int); + + tokens := cast(realloc(tokens, tokens_size + TOKEN_SIZE) as pointer to Token); + current_token := tokens + tokens_size; + + current_token^.kind := TOKEN_IDENTIFIER; + current_token^.value.stringValue := cast(calloc(token_length + 1, 1) as pointer to Char); + strncpy(current_token^.value.stringValue, input_pointer, token_length); + + tokens_size := tokens_size + TOKEN_SIZE; + + input_pointer := token_end + else + input_pointer := input_pointer + 1 + end + end; + + i := 0; + while i < tokens_size do + current_token := tokens + i; + + write_s(current_token^.value.stringValue); + write_c('\n'); + + i := i + TOKEN_SIZE end; free(input) diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 5dd740d..99247e1 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -20,40 +20,21 @@ namespace gcc this->symbol_map = symbol_table; } - void generic_visitor::visit(source::call_expression *statement) + void generic_visitor::visit(source::call_expression *expression) { - auto symbol = this->symbol_map->lookup(statement->name()); - - if (statement->name() == "Int" || statement->name() == "Word" || statement->name() == "Bool" - || statement->name() == "Float" || statement->name() == "Char") - { - if (statement->arguments().size() != 1) - { - error_at(get_location(&statement->position()), - "procedure '%s' expects 1 argument, %lu given", - statement->name().c_str(), statement->arguments().size()); - return; - } - auto& argument = statement->arguments().at(0); - argument->accept(this); - tree argument_type = TREE_TYPE(this->current_expression); - - this->current_expression = build1_loc(get_location(&argument->position()), CONVERT_EXPR, - symbol->payload, this->current_expression); - } - else if (symbol) + if (auto symbol = this->symbol_map->lookup(expression->name())) { tree return_type = TREE_TYPE(TREE_TYPE(symbol->payload)); tree fndecl_type = build_function_type(return_type, TYPE_ARG_TYPES(symbol->payload)); tree printf_fn = build1(ADDR_EXPR, build_pointer_type(fndecl_type), symbol->payload); - std::vector arguments(statement->arguments().size()); - for (std::size_t i = 0; i < statement->arguments().size(); ++i) + std::vector arguments(expression->arguments().size()); + for (std::size_t i = 0; i < expression->arguments().size(); ++i) { - statement->arguments().at(i)->accept(this); + expression->arguments().at(i)->accept(this); arguments[i] = this->current_expression; } - tree stmt = build_call_array_loc(get_location(&statement->position()), + tree stmt = build_call_array_loc(get_location(&expression->position()), return_type, printf_fn, arguments.size(), arguments.data()); if (return_type == void_type_node) @@ -68,12 +49,24 @@ namespace gcc } else { - error_at(get_location(&statement->position()), + error_at(get_location(&expression->position()), "procedure '%s' not declared", - statement->name().c_str()); + expression->name().c_str()); + this->current_expression = error_mark_node; } } + void generic_visitor::visit(source::cast_expression *expression) + { + tree cast_target = build_type(expression->target()); + gcc_assert(cast_target != NULL_TREE); + + expression->value().accept(this); + + this->current_expression = build1_loc(get_location(&expression->position()), CONVERT_EXPR, + cast_target, this->current_expression); + } + void generic_visitor::visit(source::program *program) { for (const auto definition : program->value_definitions) diff --git a/gcc/elna-tree.cc b/gcc/elna-tree.cc index bca2a5b..f0fa4a1 100644 --- a/gcc/elna-tree.cc +++ b/gcc/elna-tree.cc @@ -28,6 +28,12 @@ namespace gcc && TYPE_MAIN_VARIANT(TREE_TYPE(type)) == char_type_node; } + bool is_integral_type(tree type) + { + gcc_assert(TYPE_P(type)); + return type == integer_type_node || type == unsigned_type_node; + } + tree tree_chain_base::head() { return first; diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index 207041f..30d2b66 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -41,7 +41,8 @@ namespace gcc void visit(source::program *program) override; void visit(source::procedure_definition *definition) override; - void visit(source::call_expression *statement) override; + void visit(source::call_expression *expression) override; + void visit(source::cast_expression *expression) override; void visit(source::number_literal *literal) override; void visit(source::number_literal *literal) override; void visit(source::number_literal *literal) override; diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h index 59d9c88..a3b6a8f 100644 --- a/include/elna/gcc/elna-tree.h +++ b/include/elna/gcc/elna-tree.h @@ -27,6 +27,7 @@ namespace gcc void init_ttree(); bool is_pointer_type(tree type); bool is_string_type(tree type); + bool is_integral_type(tree type); class tree_chain_base { diff --git a/include/elna/source/ast.h b/include/elna/source/ast.h index cb40570..af1a4c3 100644 --- a/include/elna/source/ast.h +++ b/include/elna/source/ast.h @@ -41,6 +41,7 @@ namespace source class procedure_definition; class type_definition; class call_expression; + class cast_expression; class assign_statement; class if_statement; class while_statement; @@ -74,6 +75,7 @@ namespace source virtual void visit(procedure_definition *) = 0; virtual void visit(type_definition *) = 0; virtual void visit(call_expression *) = 0; + virtual void visit(cast_expression *) = 0; virtual void visit(expression_statement *) = 0; virtual void visit(assign_statement *) = 0; virtual void visit(if_statement *) = 0; @@ -109,7 +111,8 @@ namespace source virtual void visit(constant_definition *definition) override; virtual void visit(procedure_definition *definition) override; virtual void visit(type_definition *definition) override; - virtual void visit(call_expression *statement) override; + virtual void visit(call_expression *expression) override; + virtual void visit(cast_expression *expression) override; virtual void visit(expression_statement *statement) override; virtual void visit(assign_statement *statement) override; virtual void visit(if_statement *) override; @@ -136,55 +139,6 @@ namespace source virtual void visit(string_literal *) override; }; - /** - * Operand representing a subexpression in the 3 address code. - */ - struct operand - { - public: - virtual ~operand() = 0; - }; - - struct integer_operand final : public operand - { - std::int32_t m_value; - - public: - explicit integer_operand(const std::int32_t value); - - std::int32_t value() const; - }; - - class variable_operand final : public operand - { - std::string m_name; - - public: - explicit variable_operand(const std::string& name); - - const std::string& name() const; - }; - - struct temporary_variable final : public operand - { - std::size_t m_counter; - - public: - explicit temporary_variable(const std::size_t counter); - - std::size_t counter() const; - }; - - struct label_operand final : public operand - { - std::size_t m_counter; - - public: - explicit label_operand(const std::size_t counter); - - std::size_t counter() const; - }; - /** * AST node. */ @@ -219,9 +173,6 @@ namespace source class expression : public node { - public: - std::shared_ptr place; - protected: /** * \param position Source code position. @@ -448,7 +399,7 @@ namespace source }; /** - * Call statement. + * Procedure call expression. */ class call_expression : public expression { @@ -469,6 +420,24 @@ namespace source virtual ~call_expression() override; }; + /** + * Cast expression. + */ + class cast_expression : public expression + { + type_expression *m_target; + expression *m_value; + + public: + cast_expression(const struct position position, type_expression *target, expression *value); + virtual void accept(parser_visitor *visitor) override; + + type_expression& target(); + expression& value(); + + virtual ~cast_expression() override; + }; + class expression_statement : public statement { expression *m_body; diff --git a/source/ast.cc b/source/ast.cc index 3fbbf98..a9c351a 100644 --- a/source/ast.cc +++ b/source/ast.cc @@ -33,14 +33,20 @@ namespace source definition->body().accept(this); } - void empty_visitor::visit(call_expression *statement) + void empty_visitor::visit(call_expression *expression) { - for (auto& argument : statement->arguments()) + for (auto& argument : expression->arguments()) { argument->accept(this); } } + void empty_visitor::visit(cast_expression *expression) + { + expression->target().accept(this); + expression->value().accept(this); + } + void empty_visitor::visit(expression_statement *statement) { statement->body().accept(this); @@ -185,50 +191,6 @@ namespace source { } - operand::~operand() - { - } - - integer_operand::integer_operand(const std::int32_t value) - : m_value(value) - { - } - - std::int32_t integer_operand::value() const - { - return m_value; - } - - variable_operand::variable_operand(const std::string& name) - : m_name(name) - { - } - - const std::string& variable_operand::name() const - { - return m_name; - } - - temporary_variable::temporary_variable(const std::size_t counter) - : m_counter(counter) - { - } - - std::size_t temporary_variable::counter() const - { - return m_counter; - } - - label_operand::label_operand(const std::size_t counter) - : m_counter(counter) - { - } - - std::size_t label_operand::counter() const - { - return m_counter; - } - node::node(const struct position position) : source_position(position) { @@ -766,6 +728,32 @@ namespace source } } + cast_expression::cast_expression(const struct position position, type_expression *target, expression *value) + : expression(position), m_target(target), m_value(value) + { + } + + void cast_expression::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + type_expression& cast_expression::target() + { + return *m_target; + } + + expression& cast_expression::value() + { + return *m_value; + } + + cast_expression::~cast_expression() + { + delete m_target; + delete m_value; + } + expression_statement::expression_statement(const struct position position, expression *body) : statement(position), m_body(body) { diff --git a/source/lexer.ll b/source/lexer.ll index 877660a..a6e50dd 100644 --- a/source/lexer.ll +++ b/source/lexer.ll @@ -106,6 +106,12 @@ not { return { return yy::parser::make_RETURN(this->location); } +cast { + return yy::parser::make_CAST(this->location); + } +as { + return yy::parser::make_AS(this->location); + } [A-Za-z_][A-Za-z0-9_]* { return yy::parser::make_IDENTIFIER(yytext, this->location); } diff --git a/source/parser.yy b/source/parser.yy index bf8cd09..6ac3517 100644 --- a/source/parser.yy +++ b/source/parser.yy @@ -67,7 +67,7 @@ %token CONST VAR PROCEDURE ARRAY OF TYPE RECORD POINTER TO UNION %token BEGIN_BLOCK END_BLOCK EXTERN %token LEFT_PAREN RIGHT_PAREN LEFT_SQUARE RIGHT_SQUARE SEMICOLON DOT COMMA -%token AND OR NOT +%token AND OR NOT CAST AS %token GREATER_EQUAL LESS_EQUAL LESS_THAN GREATER_THAN NOT_EQUAL EQUALS %token PLUS MINUS MULTIPLICATION DIVISION REMAINDER %token ASSIGNMENT COLON HAT AT @@ -97,6 +97,7 @@ %type > field_declaration; %type >> field_list; %type > elsif_statement_list; +%type cast_expression; %% program: type_part constant_part procedure_part variable_part BEGIN_BLOCK optional_statements END_BLOCK DOT @@ -183,6 +184,10 @@ call_expression: IDENTIFIER actual_parameter_list $$ = new elna::source::call_expression(elna::source::make_position(@1), $1); std::swap($$->arguments(), $2); } +cast_expression: CAST LEFT_PAREN expression AS type_expression RIGHT_PAREN + { + $$ = new elna::source::cast_expression(elna::source::make_position(@1), $5, $3); + } while_statement: WHILE expression DO optional_statements END_BLOCK { auto body = new elna::source::conditional_statements($2); @@ -247,6 +252,7 @@ literal: pointer: literal { $$ = $1; } | designator_expression { $$ = $1; } + | cast_expression { $$ = $1; } | call_expression { $$ = $1; } | LEFT_PAREN expression RIGHT_PAREN { $$ = std::move($2); } summand: