Cast expressions
This commit is contained in:
		
							
								
								
									
										91
									
								
								example.elna
									
									
									
									
									
								
							
							
						
						
									
										91
									
								
								example.elna
									
									
									
									
									
								
							| @@ -1,7 +1,7 @@ | |||||||
| type | type | ||||||
|   TokenValue = union |   TokenValue = union | ||||||
|     intValue: Int; |     intValue: Int; | ||||||
|     stringValue: String |     stringValue: pointer to Char | ||||||
|   end, |   end, | ||||||
|   Token = record |   Token = record | ||||||
|     kind: Int; |     kind: Int; | ||||||
| @@ -12,7 +12,9 @@ type | |||||||
|   end; |   end; | ||||||
|  |  | ||||||
| const | 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. | -- 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 malloc(size: Int): pointer to Char; extern; | ||||||
| proc free(ptr: pointer to Char); extern; | proc free(ptr: pointer to Char); extern; | ||||||
| proc calloc(nmemb: Int, size: Int): 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 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 strlen(ptr: pointer to Char): Word; extern; | ||||||
|  |  | ||||||
| proc exit(code: Int); extern; | proc exit(code: Int); extern; | ||||||
| @@ -68,7 +74,7 @@ begin | |||||||
|     digit := value % 10; |     digit := value % 10; | ||||||
| 	value := value / 10; | 	value := value / 10; | ||||||
|  |  | ||||||
| 	buffer[n] := Char(Int('0') + digit); | 	buffer[n] := cast(cast('0' as Int) + digit as Char); | ||||||
| 	n := n - 1 | 	n := n - 1 | ||||||
|   end; |   end; | ||||||
|   while n < 10 do |   while n < 10 do | ||||||
| @@ -82,6 +88,26 @@ begin | |||||||
|   write_i(value) |   write_i(value) | ||||||
| end; | 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. | -- End of standard procedures. | ||||||
| -- | -- | ||||||
| @@ -130,17 +156,68 @@ begin | |||||||
|   return input |   return input | ||||||
| end; | 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(); | proc compile(); | ||||||
| var | var | ||||||
|   input: pointer to Char, |   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 | begin | ||||||
|  |   tokens_size := 0; | ||||||
|  |   tokens := cast(0 as pointer to Token); | ||||||
|  |  | ||||||
|   input := read_source("example.elna"); |   input := read_source("example.elna"); | ||||||
|  |  | ||||||
|   input_pointer := input; |   input_pointer := skip_spaces(input); | ||||||
|  |  | ||||||
|   while input_pointer^ /= '\0' do |   while input_pointer^ /= '\0' do | ||||||
|     write(0, input_pointer, 1); |     if is_alpha(input_pointer^) or input_pointer^ = '_' then | ||||||
|     input_pointer := input_pointer + 1 |       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; |   end; | ||||||
|  |  | ||||||
|   free(input) |   free(input) | ||||||
|   | |||||||
| @@ -20,40 +20,21 @@ namespace gcc | |||||||
|         this->symbol_map = symbol_table; |         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 (auto symbol = this->symbol_map->lookup(expression->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) |  | ||||||
|         { |         { | ||||||
|             tree return_type = TREE_TYPE(TREE_TYPE(symbol->payload)); |             tree return_type = TREE_TYPE(TREE_TYPE(symbol->payload)); | ||||||
|             tree fndecl_type = build_function_type(return_type, TYPE_ARG_TYPES(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); |             tree printf_fn = build1(ADDR_EXPR, build_pointer_type(fndecl_type), symbol->payload); | ||||||
|  |  | ||||||
|             std::vector<tree> arguments(statement->arguments().size()); |             std::vector<tree> arguments(expression->arguments().size()); | ||||||
|             for (std::size_t i = 0; i < statement->arguments().size(); ++i) |             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; |                 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()); |                     return_type, printf_fn, arguments.size(), arguments.data()); | ||||||
|  |  | ||||||
|             if (return_type == void_type_node) |             if (return_type == void_type_node) | ||||||
| @@ -68,12 +49,24 @@ namespace gcc | |||||||
|         } |         } | ||||||
|         else |         else | ||||||
|         { |         { | ||||||
|             error_at(get_location(&statement->position()), |             error_at(get_location(&expression->position()), | ||||||
|                     "procedure '%s' not declared", |                     "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) |     void generic_visitor::visit(source::program *program) | ||||||
|     { |     { | ||||||
|         for (const auto definition : program->value_definitions) |         for (const auto definition : program->value_definitions) | ||||||
|   | |||||||
| @@ -28,6 +28,12 @@ namespace gcc | |||||||
|             && TYPE_MAIN_VARIANT(TREE_TYPE(type)) == char_type_node; |             && 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() |     tree tree_chain_base::head() | ||||||
|     { |     { | ||||||
|         return first; |         return first; | ||||||
|   | |||||||
| @@ -41,7 +41,8 @@ namespace gcc | |||||||
|  |  | ||||||
|         void visit(source::program *program) override; |         void visit(source::program *program) override; | ||||||
|         void visit(source::procedure_definition *definition) 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<std::int32_t> *literal) override; |         void visit(source::number_literal<std::int32_t> *literal) override; | ||||||
|         void visit(source::number_literal<std::uint32_t> *literal) override; |         void visit(source::number_literal<std::uint32_t> *literal) override; | ||||||
|         void visit(source::number_literal<double> *literal) override; |         void visit(source::number_literal<double> *literal) override; | ||||||
|   | |||||||
| @@ -27,6 +27,7 @@ namespace gcc | |||||||
|     void init_ttree(); |     void init_ttree(); | ||||||
|     bool is_pointer_type(tree type); |     bool is_pointer_type(tree type); | ||||||
|     bool is_string_type(tree type); |     bool is_string_type(tree type); | ||||||
|  |     bool is_integral_type(tree type); | ||||||
|  |  | ||||||
|     class tree_chain_base |     class tree_chain_base | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -41,6 +41,7 @@ namespace source | |||||||
|     class procedure_definition; |     class procedure_definition; | ||||||
|     class type_definition; |     class type_definition; | ||||||
|     class call_expression; |     class call_expression; | ||||||
|  |     class cast_expression; | ||||||
|     class assign_statement; |     class assign_statement; | ||||||
|     class if_statement; |     class if_statement; | ||||||
|     class while_statement; |     class while_statement; | ||||||
| @@ -74,6 +75,7 @@ namespace source | |||||||
|         virtual void visit(procedure_definition *) = 0; |         virtual void visit(procedure_definition *) = 0; | ||||||
|         virtual void visit(type_definition *) = 0; |         virtual void visit(type_definition *) = 0; | ||||||
|         virtual void visit(call_expression *) = 0; |         virtual void visit(call_expression *) = 0; | ||||||
|  |         virtual void visit(cast_expression *) = 0; | ||||||
|         virtual void visit(expression_statement *) = 0; |         virtual void visit(expression_statement *) = 0; | ||||||
|         virtual void visit(assign_statement *) = 0; |         virtual void visit(assign_statement *) = 0; | ||||||
|         virtual void visit(if_statement *) = 0; |         virtual void visit(if_statement *) = 0; | ||||||
| @@ -109,7 +111,8 @@ namespace source | |||||||
|         virtual void visit(constant_definition *definition) override; |         virtual void visit(constant_definition *definition) override; | ||||||
|         virtual void visit(procedure_definition *definition) override; |         virtual void visit(procedure_definition *definition) override; | ||||||
|         virtual void visit(type_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(expression_statement *statement) override; | ||||||
|         virtual void visit(assign_statement *statement) override; |         virtual void visit(assign_statement *statement) override; | ||||||
|         virtual void visit(if_statement *) override; |         virtual void visit(if_statement *) override; | ||||||
| @@ -136,55 +139,6 @@ namespace source | |||||||
|         virtual void visit(string_literal *) override; |         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. |      * AST node. | ||||||
|      */ |      */ | ||||||
| @@ -219,9 +173,6 @@ namespace source | |||||||
|  |  | ||||||
|     class expression : public node |     class expression : public node | ||||||
|     { |     { | ||||||
|     public: |  | ||||||
|         std::shared_ptr<operand> place; |  | ||||||
|  |  | ||||||
|     protected: |     protected: | ||||||
|         /** |         /** | ||||||
|          * \param position Source code position. |          * \param position Source code position. | ||||||
| @@ -448,7 +399,7 @@ namespace source | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Call statement. |      * Procedure call expression. | ||||||
|      */ |      */ | ||||||
|     class call_expression : public expression |     class call_expression : public expression | ||||||
|     { |     { | ||||||
| @@ -469,6 +420,24 @@ namespace source | |||||||
|         virtual ~call_expression() override; |         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 |     class expression_statement : public statement | ||||||
|     { |     { | ||||||
|         expression *m_body; |         expression *m_body; | ||||||
|   | |||||||
| @@ -33,14 +33,20 @@ namespace source | |||||||
|         definition->body().accept(this); |         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); |             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) |     void empty_visitor::visit(expression_statement *statement) | ||||||
|     { |     { | ||||||
|         statement->body().accept(this); |         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) |     node::node(const struct position position) | ||||||
|         : source_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) |     expression_statement::expression_statement(const struct position position, expression *body) | ||||||
|         : statement(position), m_body(body) |         : statement(position), m_body(body) | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -106,6 +106,12 @@ not                     { | |||||||
| return                  { | return                  { | ||||||
|                             return yy::parser::make_RETURN(this->location); |                             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_]*  { | [A-Za-z_][A-Za-z0-9_]*  { | ||||||
|                             return yy::parser::make_IDENTIFIER(yytext, this->location); |                             return yy::parser::make_IDENTIFIER(yytext, this->location); | ||||||
|                         } |                         } | ||||||
|   | |||||||
| @@ -67,7 +67,7 @@ | |||||||
| %token CONST VAR PROCEDURE ARRAY OF TYPE RECORD POINTER TO UNION | %token CONST VAR PROCEDURE ARRAY OF TYPE RECORD POINTER TO UNION | ||||||
| %token BEGIN_BLOCK END_BLOCK EXTERN | %token BEGIN_BLOCK END_BLOCK EXTERN | ||||||
| %token LEFT_PAREN RIGHT_PAREN LEFT_SQUARE RIGHT_SQUARE SEMICOLON DOT COMMA | %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 GREATER_EQUAL LESS_EQUAL LESS_THAN GREATER_THAN NOT_EQUAL EQUALS | ||||||
| %token PLUS MINUS MULTIPLICATION DIVISION REMAINDER | %token PLUS MINUS MULTIPLICATION DIVISION REMAINDER | ||||||
| %token ASSIGNMENT COLON HAT AT | %token ASSIGNMENT COLON HAT AT | ||||||
| @@ -97,6 +97,7 @@ | |||||||
| %type <std::pair<std::string, elna::source::type_expression *>> field_declaration; | %type <std::pair<std::string, elna::source::type_expression *>> field_declaration; | ||||||
| %type <std::vector<std::pair<std::string, elna::source::type_expression *>>> field_list; | %type <std::vector<std::pair<std::string, elna::source::type_expression *>>> field_list; | ||||||
| %type <std::vector<elna::source::conditional_statements *>> elsif_statement_list; | %type <std::vector<elna::source::conditional_statements *>> elsif_statement_list; | ||||||
|  | %type <elna::source::cast_expression *> cast_expression; | ||||||
| %% | %% | ||||||
| program: | program: | ||||||
|     type_part constant_part procedure_part variable_part BEGIN_BLOCK optional_statements END_BLOCK DOT |     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); |             $$ = new elna::source::call_expression(elna::source::make_position(@1), $1); | ||||||
|             std::swap($$->arguments(), $2); |             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 | while_statement: WHILE expression DO optional_statements END_BLOCK | ||||||
|         { |         { | ||||||
|             auto body = new elna::source::conditional_statements($2); |             auto body = new elna::source::conditional_statements($2); | ||||||
| @@ -247,6 +252,7 @@ literal: | |||||||
| pointer: | pointer: | ||||||
|     literal { $$ = $1; } |     literal { $$ = $1; } | ||||||
|     | designator_expression { $$ = $1; } |     | designator_expression { $$ = $1; } | ||||||
|  |     | cast_expression { $$ = $1; } | ||||||
|     | call_expression { $$ = $1; } |     | call_expression { $$ = $1; } | ||||||
|     | LEFT_PAREN expression RIGHT_PAREN { $$ = std::move($2); } |     | LEFT_PAREN expression RIGHT_PAREN { $$ = std::move($2); } | ||||||
| summand: | summand: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user