From 5178027d9f4b1f4d03a0044007ea2cc9f4ebd07c Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Wed, 29 Jan 2025 12:55:52 +0100 Subject: [PATCH] Implement the sizeof operator --- example.elna | 55 +++++++++++++++++++++++++++------ gcc/elna-generic.cc | 7 +++++ include/elna/gcc/elna-generic.h | 1 + include/elna/source/ast.h | 19 ++++++++++++ source/ast.cc | 25 +++++++++++++++ source/lexer.ll | 3 ++ source/parser.yy | 8 +++-- 7 files changed, 106 insertions(+), 12 deletions(-) diff --git a/example.elna b/example.elna index e1260e1..2f856aa 100644 --- a/example.elna +++ b/example.elna @@ -13,8 +13,9 @@ type const SEEK_SET = 0, SEEK_CUR = 1, SEEK_END = 2, - POINTER_SIZE = 8, TOKEN_SIZE = 16, - TOKEN_IDENTIFIER = 1; + + TOKEN_IDENTIFIER = 1, TOKEN_IF = 2, TOKEN_THEN = 3, TOKEN_ELSE = 4, TOKEN_ELSIF = 5, + TOKEN_WHILE = 6, TOKEN_DO = 7; -- -- External procedures. @@ -195,14 +196,28 @@ begin 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); + tokens := cast(realloc(tokens, tokens_size + sizeof(Token)) 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); + if strncmp("if", input_pointer, token_length) = 0 then + current_token^.kind := TOKEN_IF + elsif strncmp("then", input_pointer, token_length) = 0 then + current_token^.kind := TOKEN_THEN + elsif strncmp("else", input_pointer, token_length) = 0 then + current_token^.kind := TOKEN_ELSE + elsif strncmp("elsif", input_pointer, token_length) = 0 then + current_token^.kind := TOKEN_ELSIF + elsif strncmp("while", input_pointer, token_length) = 0 then + current_token^.kind := TOKEN_WHILE + elsif strncmp("do", input_pointer, token_length) = 0 then + current_token^.kind := TOKEN_DO + else + 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) + end; - tokens_size := tokens_size + TOKEN_SIZE; + tokens_size := tokens_size + sizeof(Token); input_pointer := token_end else @@ -214,10 +229,30 @@ begin while i < tokens_size do current_token := tokens + i; - write_s(current_token^.value.stringValue); - write_c('\n'); + if current_token^.kind = TOKEN_IF then + write_s("IF") + elsif current_token^.kind = TOKEN_THEN then + write_s("THEN") + elsif current_token^.kind = TOKEN_ELSE then + write_s("ELSE") + elsif current_token^.kind = TOKEN_ELSIF then + write_s("ELSIF") + elsif current_token^.kind = TOKEN_WHILE then + write_s("WHILE") + elsif current_token^.kind = TOKEN_DO then + write_s("DO") + elsif current_token^.kind = TOKEN_IDENTIFIER then + write_s("IDENTIFIER<"); + write_s(current_token^.value.stringValue); + write_c('>') + else + write_s("UNKNOWN<"); + write_i(current_token^.kind); + write_s('>') + end; + write_c(' '); - i := i + TOKEN_SIZE + i := i + sizeof(Token) end; free(input) diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 99247e1..ca07c1c 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -67,6 +67,13 @@ namespace gcc cast_target, this->current_expression); } + void generic_visitor::visit(source::size_of_expression *expression) + { + auto body_type = build_type(expression->body()); + + this->current_expression = build1(CONVERT_EXPR, integer_type_node, TYPE_SIZE_UNIT(body_type)); + } + void generic_visitor::visit(source::program *program) { for (const auto definition : program->value_definitions) diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index 30d2b66..b994f3c 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -43,6 +43,7 @@ namespace gcc void visit(source::procedure_definition *definition) override; void visit(source::call_expression *expression) override; void visit(source::cast_expression *expression) override; + void visit(source::size_of_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/source/ast.h b/include/elna/source/ast.h index af1a4c3..c31e768 100644 --- a/include/elna/source/ast.h +++ b/include/elna/source/ast.h @@ -42,6 +42,7 @@ namespace source class type_definition; class call_expression; class cast_expression; + class size_of_expression; class assign_statement; class if_statement; class while_statement; @@ -76,6 +77,7 @@ namespace source virtual void visit(type_definition *) = 0; virtual void visit(call_expression *) = 0; virtual void visit(cast_expression *) = 0; + virtual void visit(size_of_expression *) = 0; virtual void visit(expression_statement *) = 0; virtual void visit(assign_statement *) = 0; virtual void visit(if_statement *) = 0; @@ -113,6 +115,7 @@ namespace source virtual void visit(type_definition *definition) override; virtual void visit(call_expression *expression) override; virtual void visit(cast_expression *expression) override; + virtual void visit(size_of_expression *expression) override; virtual void visit(expression_statement *statement) override; virtual void visit(assign_statement *statement) override; virtual void visit(if_statement *) override; @@ -438,6 +441,22 @@ namespace source virtual ~cast_expression() override; }; + /** + * sizeOf operator. + */ + class size_of_expression : public expression + { + type_expression *m_body; + + public: + size_of_expression(const struct position position, type_expression *body); + virtual void accept(parser_visitor *visitor) override; + + type_expression& body(); + + virtual ~size_of_expression() override; + }; + class expression_statement : public statement { expression *m_body; diff --git a/source/ast.cc b/source/ast.cc index a9c351a..ff6e6b7 100644 --- a/source/ast.cc +++ b/source/ast.cc @@ -47,6 +47,11 @@ namespace source expression->value().accept(this); } + void empty_visitor::visit(size_of_expression *expression) + { + expression->body().accept(this); + } + void empty_visitor::visit(expression_statement *statement) { statement->body().accept(this); @@ -754,6 +759,26 @@ namespace source delete m_value; } + size_of_expression::size_of_expression(const struct position position, type_expression *body) + : expression(position), m_body(body) + { + } + + void size_of_expression::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + type_expression& size_of_expression::body() + { + return *m_body; + } + + size_of_expression::~size_of_expression() + { + delete m_body; + } + 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 a6e50dd..8cf9fcf 100644 --- a/source/lexer.ll +++ b/source/lexer.ll @@ -112,6 +112,9 @@ cast { as { return yy::parser::make_AS(this->location); } +sizeof { + return yy::parser::make_SIZEOF(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 6ac3517..e0ffa81 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 CAST AS +%token AND OR NOT CAST AS SIZEOF %token GREATER_EQUAL LESS_EQUAL LESS_THAN GREATER_THAN NOT_EQUAL EQUALS %token PLUS MINUS MULTIPLICATION DIVISION REMAINDER %token ASSIGNMENT COLON HAT AT @@ -252,9 +252,13 @@ literal: pointer: literal { $$ = $1; } | designator_expression { $$ = $1; } + | SIZEOF LEFT_PAREN type_expression RIGHT_PAREN + { + $$ = new elna::source::size_of_expression(elna::source::make_position(@1), $3); + } | cast_expression { $$ = $1; } | call_expression { $$ = $1; } - | LEFT_PAREN expression RIGHT_PAREN { $$ = std::move($2); } + | LEFT_PAREN expression RIGHT_PAREN { $$ = $2; } summand: factor { $$ = std::move($1); } | factor MULTIPLICATION factor