From a32a61813ebaecf0c1e69fd1481bf09d8c8b1420 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Tue, 14 Jul 2026 18:08:44 +0200 Subject: Support more floating point literals --- boot/ast.cc | 18 +-- boot/driver.cc | 9 +- boot/lexer.ll | 16 ++- boot/parser.yy | 210 +++++++++++++++---------------- boot/result.cc | 17 ++- boot/semantic.cc | 4 +- doc/appendix.tex | 5 +- doc/language.tex | 12 +- gcc/gcc/elna-diagnostic.cc | 36 ++++-- gcc/gcc/elna-generic.cc | 10 +- include/elna/boot/ast.h | 10 +- include/elna/boot/result.h | 35 ++++-- include/elna/gcc/elna-diagnostic.h | 1 + testsuite/compilable/float_literals.elna | 9 ++ 14 files changed, 228 insertions(+), 164 deletions(-) create mode 100644 testsuite/compilable/float_literals.elna diff --git a/boot/ast.cc b/boot/ast.cc index 4af906f..14bad30 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -432,9 +432,9 @@ namespace elna::boot void walking_visitor::visit(traits_expression *trait) { - if (!trait->parameters.empty()) + if (!trait->arguments.empty()) { - trait->parameters.front()->accept(this); + trait->arguments.front()->accept(this); } } @@ -1148,8 +1148,9 @@ namespace elna::boot delete m_operand; } - procedure_call::procedure_call(const struct position position, designator_expression *callable) - : node(position), m_callable(callable) + procedure_call::procedure_call(const struct position position, designator_expression *callable, + std::vector&& arguments) + : node(position), m_callable(callable), arguments(std::move(arguments)) { } @@ -1208,16 +1209,17 @@ namespace elna::boot delete m_value; } - traits_expression::traits_expression(const struct position position, const std::string& name) - : node(position), name(name) + traits_expression::traits_expression(const struct position position, const std::string& name, + std::vector&& arguments) + : node(position), arguments(std::move(arguments)), name(name) { } traits_expression::~traits_expression() { - for (const type_expression *parameter : this->parameters) + for (const type_expression *argument : this->arguments) { - delete parameter; + delete argument; } } diff --git a/boot/driver.cc b/boot/driver.cc index b2ffe60..b51da32 100644 --- a/boot/driver.cc +++ b/boot/driver.cc @@ -21,11 +21,12 @@ namespace elna::boot { position make_position(const yy::location& location) { - position result; - result.line = static_cast(location.begin.line); - result.column = static_cast(location.begin.column); + auto start_location = boot::location(static_cast(location.begin.line), + static_cast(location.begin.column)); + auto end_location = boot::location(static_cast(location.end.line), + static_cast(location.end.column)); - return result; + return position(start_location, end_location); } syntax_error::syntax_error(const std::string& message, const yy::location& location) diff --git a/boot/lexer.ll b/boot/lexer.ll index 4367caa..faae3d7 100644 --- a/boot/lexer.ll +++ b/boot/lexer.ll @@ -196,8 +196,20 @@ of { return yy::parser::make_WORD(result, this->location); } } -[[:digit:]]+\.[[:digit:]]+ { - float result = strtof(yytext, NULL); +[[:digit:]]+\.[[:digit:]]+([eE][+-]?[[:digit:]]+)? { + double result = strtod(yytext, NULL); + + if (errno == ERANGE) + { + REJECT; + } + else + { + return yy::parser::make_FLOAT(result, this->location); + } +} +[[:digit:]]+[eE][+-]?[[:digit:]]+ { + double result = strtod(yytext, NULL); if (errno == ERANGE) { diff --git a/boot/parser.yy b/boot/parser.yy index 4ef2de4..ef887ab 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -60,6 +60,10 @@ along with GCC; see the file COPYING3. If not see %define api.token.raw %define api.token.constructor %define api.value.type variant +%define api.value.automove +%define parse.error detailed +%define parse.lac full +%expect 0 // Assert zero shift/reduce conflicts. %parse-param {elna::boot::lexer& lexer} %param {elna::boot::driver& driver} @@ -76,7 +80,7 @@ along with GCC; see the file COPYING3. If not see %token TRAIT %token INTEGER %token WORD -%token FLOAT +%token FLOAT %token CHARACTER %token STRING %token BOOLEAN @@ -162,78 +166,70 @@ along with GCC; see the file COPYING3. If not see program: import_part constant_part type_part variable_part procedure_part statement_part return_statement "end" "." { - boot::unit *tree = new boot::unit(boot::make_position(@1), - std::move($1), std::move($2), std::move($3), std::move($4), std::move($5), - std::move($6), $7); + boot::unit *tree = new boot::unit(boot::make_position(@$), $1, $2, $3, $4, $5, $6, $7); driver.tree.reset(tree); } procedure_body: constant_part variable_part statement_part return_statement "end" - { - $$ = std::make_unique(std::move($1), std::move($2), std::move($3), $4); - } + { $$ = std::make_unique($1, $2, $3, $4); } statement_part: /* no statements */ {} - | "begin" statements { std::swap($$, $2); } + | "begin" statements { $$ = $2; } identifier_definition: IDENTIFIER "*" { $$ = boot::identifier_definition{ $1, true }; } | IDENTIFIER { $$ = boot::identifier_definition{ $1, false }; } identifier_definitions: identifier_definition "," identifier_definitions { - std::swap($$, $3); + $$ = $3; $$.emplace($$.cbegin(), $1); } - | identifier_definition { $$.emplace_back(std::move($1)); } + | identifier_definition { $$.emplace_back($1); } return_declaration: /* proper procedure */ {} | ":" "!" { $$ = boot::procedure_type_expression::return_t(std::monostate{}); } | ":" type_expression { $$ = boot::procedure_type_expression::return_t($2); } procedure_heading: "(" optional_fields ")" return_declaration - { - $$ = new boot::procedure_type_expression(boot::make_position(@1), std::move($2), std::move($4)); - } + { $$ = new boot::procedure_type_expression(boot::make_position(@$), $2, $4); } procedure_declaration: "proc" identifier_definition procedure_heading procedure_body { - $$ = new boot::procedure_declaration(boot::make_position(@1), std::move($2), $3, - std::move(*$4)); + $$ = new boot::procedure_declaration(boot::make_position(@$), $2, $3, std::move(*$4)); } | "proc" identifier_definition procedure_heading "extern" { - $$ = new boot::procedure_declaration(boot::make_position(@1), std::move($2), $3); + $$ = new boot::procedure_declaration(boot::make_position(@$), $2, $3); } procedure_part: /* no procedure declarations */ {} | procedure_declaration procedure_part { - std::swap($$, $2); - $$.emplace($$.cbegin(), std::move($1)); + $$ = $2; + $$.emplace($$.cbegin(), $1); } call_expression: designator_expression actual_parameter_list { - $$ = new boot::procedure_call(boot::make_position(@1), $1); - std::swap($$->arguments, $2); + $$ = new boot::procedure_call(boot::make_position(@$), $1, $2); } cast_expression: "cast" "(" expression ":" type_expression ")" - { $$ = new boot::cast_expression(boot::make_position(@1), $5, $3); } + { $$ = new boot::cast_expression(boot::make_position(@$), $5, $3); } elsif_do_statements: "elsif" expression "do" statements elsif_do_statements { - boot::conditional_statements *branch = new boot::conditional_statements($2, std::move($4)); - std::swap($5, $$); + boot::conditional_statements *branch = new boot::conditional_statements($2, $4); + $$ = $5; $$.emplace($$.begin(), branch); } | /* no branches */ {} else_statements: - "else" statements { $$ = new std::vector(std::move($2)); } + "else" statements { $$ = new std::vector($2); } | { $$ = nullptr; } elsif_then_statements: "elsif" expression "then" statements elsif_then_statements { - boot::conditional_statements *branch = new boot::conditional_statements($2, std::move($4)); - std::swap($5, $$); + boot::conditional_statements *branch = new boot::conditional_statements($2, $4); + $$ = $5; $$.emplace($$.begin(), branch); } | /* no branches */ {} @@ -241,18 +237,17 @@ return_statement: "return" expression { $$ = $2; } | /* no return statement */ { $$ = nullptr; } literal: - INTEGER { $$ = new boot::literal(boot::make_position(@1), $1); } - | WORD { $$ = new boot::literal(boot::make_position(@1), $1); } - | FLOAT { $$ = new boot::literal(boot::make_position(@1), $1); } - | BOOLEAN { $$ = new boot::literal(boot::make_position(@1), $1); } - | CHARACTER { $$ = new boot::literal(boot::make_position(@1), $1.at(0)); } - | "nil" { $$ = new boot::literal(boot::make_position(@1), nullptr); } - | STRING { $$ = new boot::literal(boot::make_position(@1), $1); } + INTEGER { $$ = new boot::literal(boot::make_position(@$), $1); } + | WORD { $$ = new boot::literal(boot::make_position(@$), $1); } + | FLOAT { $$ = new boot::literal(boot::make_position(@$), $1); } + | BOOLEAN { $$ = new boot::literal(boot::make_position(@$), $1); } + | CHARACTER { $$ = new boot::literal(boot::make_position(@$), $1.at(0)); } + | "nil" { $$ = new boot::literal(boot::make_position(@$), nullptr); } + | STRING { $$ = new boot::literal(boot::make_position(@$), $1); } traits_expression: TRAIT "(" type_expressions ")" { - $$ = new boot::traits_expression(boot::make_position(@1), $1); - std::swap($3, $$->parameters); + $$ = new boot::traits_expression(boot::make_position(@$), $1, $3); } simple_expression: literal { $$ = $1; } @@ -263,11 +258,11 @@ simple_expression: | "(" expression ")" { $$ = $2; } | IDENTIFIER "{" field_initializers "}" { - $$ = new boot::record_constructor_expression(boot::make_position(@1), std::move($1), std::move($3)); + $$ = new boot::record_constructor_expression(boot::make_position(@$), $1, $3); } | "[" INTEGER "]" type_expression "{" expressions "}" { - $$ = new boot::array_constructor_expression(boot::make_position(@1), $2, $4, std::move($6)); + $$ = new boot::array_constructor_expression(boot::make_position(@$), $2, $4, $6); } operand: unary_expression { $$ = $1; } @@ -278,185 +273,183 @@ expression: binary_expression: expression "*" expression { - $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::multiplication); + $$ = new boot::binary_expression(boot::make_position(@$), $1, $3, boot::binary_operator::multiplication); } | expression "/" expression { - $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::division); + $$ = new boot::binary_expression(boot::make_position(@$), $1, $3, boot::binary_operator::division); } | expression "%" expression { - $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::remainder); + $$ = new boot::binary_expression(boot::make_position(@$), $1, $3, boot::binary_operator::remainder); } | expression "+" expression { - $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::sum); + $$ = new boot::binary_expression(boot::make_position(@$), $1, $3, boot::binary_operator::sum); } | expression "-" expression { - $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::subtraction); + $$ = new boot::binary_expression(boot::make_position(@$), $1, $3, boot::binary_operator::subtraction); } | expression "=" expression { - $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::equals); + $$ = new boot::binary_expression(boot::make_position(@$), $1, $3, boot::binary_operator::equals); } | expression "<>" expression { - $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::not_equals); + $$ = new boot::binary_expression(boot::make_position(@$), $1, $3, boot::binary_operator::not_equals); } | expression "<" expression { - $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::less); + $$ = new boot::binary_expression(boot::make_position(@$), $1, $3, boot::binary_operator::less); } | expression ">" expression { - $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::greater); + $$ = new boot::binary_expression(boot::make_position(@$), $1, $3, boot::binary_operator::greater); } | expression "<=" expression { - $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, - boot::binary_operator::less_equal); + $$ = new boot::binary_expression(boot::make_position(@$), $1, $3, boot::binary_operator::less_equal); } | expression ">=" expression { - $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::greater_equal); + $$ = new boot::binary_expression(boot::make_position(@$), $1, $3, boot::binary_operator::greater_equal); } | expression "&" expression { - $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::conjunction); + $$ = new boot::binary_expression(boot::make_position(@$), $1, $3, boot::binary_operator::conjunction); } | expression "or" expression { - $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::disjunction); + $$ = new boot::binary_expression(boot::make_position(@$), $1, $3, boot::binary_operator::disjunction); } | expression "xor" expression { - $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, - boot::binary_operator::exclusive_disjunction); + $$ = new boot::binary_expression(boot::make_position(@$), $1, $3, boot::binary_operator::exclusive_disjunction); } | expression "<<" expression { - $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::shift_left); + $$ = new boot::binary_expression(boot::make_position(@$), $1, $3, boot::binary_operator::shift_left); } | expression ">>" expression { - $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::shift_right); + $$ = new boot::binary_expression(boot::make_position(@$), $1, $3, boot::binary_operator::shift_right); } unary_expression: "@" operand { - $$ = new boot::unary_expression(boot::make_position(@1), $2, boot::unary_operator::reference); + $$ = new boot::unary_expression(boot::make_position(@$), $2, boot::unary_operator::reference); } | "~" operand { - $$ = new boot::unary_expression(boot::make_position(@1), $2, boot::unary_operator::negation); + $$ = new boot::unary_expression(boot::make_position(@$), $2, boot::unary_operator::negation); } | "-" operand { - $$ = new boot::unary_expression(boot::make_position(@1), $2, boot::unary_operator::minus); + $$ = new boot::unary_expression(boot::make_position(@$), $2, boot::unary_operator::minus); } expressions: expression "," expressions { - std::swap($$, $3); + $$ = $3; $$.emplace($$.cbegin(), $1); } | expression { $$.push_back($1); } type_expressions: type_expression "," type_expressions { - std::swap($$, $3); + $$ = $3; $$.emplace($$.cbegin(), $1); } | type_expression { $$.push_back($1); } designator_expression: simple_expression "[" expression "]" - { $$ = new boot::array_access_expression(boot::make_position(@2), $1, $3); } + { $$ = new boot::array_access_expression(boot::make_position(@$), $1, $3); } | simple_expression "." IDENTIFIER - { $$ = new boot::field_access_expression(boot::make_position(@2), $1, $3); } + { $$ = new boot::field_access_expression(boot::make_position(@$), $1, $3); } | simple_expression "^" - { $$ = new boot::dereference_expression(boot::make_position(@1), $1); } + { $$ = new boot::dereference_expression(boot::make_position(@$), $1); } | IDENTIFIER - { $$ = new boot::named_expression(boot::make_position(@1), $1); } + { $$ = new boot::named_expression(boot::make_position(@$), $1); } statement: designator_expression ":=" expression - { $$ = new boot::assign_statement(boot::make_position(@1), $1, $3); } + { $$ = new boot::assign_statement(boot::make_position(@$), $1, $3); } | "while" expression "do" statements elsif_do_statements "end" { - boot::conditional_statements *body = new boot::conditional_statements($2, std::move($4)); - $$ = new boot::while_statement(boot::make_position(@1), body, std::move($5)); + boot::conditional_statements *body = new boot::conditional_statements($2, $4); + $$ = new boot::while_statement(boot::make_position(@$), body, $5); } | "if" expression "then" statements elsif_then_statements else_statements "end" { - boot::conditional_statements *then = new boot::conditional_statements($2, std::move($4)); - $$ = new boot::if_statement(boot::make_position(@1), then, std::move($5), $6); + boot::conditional_statements *then = new boot::conditional_statements($2, $4); + $$ = new boot::if_statement(boot::make_position(@$), then, $5, $6); } | call_expression { $$ = $1; } | "defer" statements "end" - { $$ = new boot::defer_statement(boot::make_position(@1), std::move($2)); } + { $$ = new boot::defer_statement(boot::make_position(@$), $2); } | "case" expression "of" switch_cases else_statements "end" - { $$ = new boot::case_statement(boot::make_position(@1), $2, std::move($4), $5); } + { $$ = new boot::case_statement(boot::make_position(@$), $2, $4, $5); } | { $$ = new boot::empty_statement(boot::make_position(@$)); } switch_case: case_labels ":" statements - { $$ = { .labels = std::move($1), .statements = std::move($3) }; } + { $$ = { .labels = $1, .statements = $3 }; } switch_cases: switch_case "|" switch_cases { - std::swap($$, $3); + $$ = $3; $$.emplace($$.cbegin(), $1); } | switch_case { $$.push_back($1); } case_labels: expression "," case_labels { - std::swap($$, $3); + $$ = $3; $$.emplace($$.cbegin(), $1); } | expression { $$.push_back($1); } statements: statements ";" statement { - std::swap($$, $1); + $$ = $1; $$.insert($$.cend(), $3); } | statement { $$.push_back($1); } field_declaration: - identifiers ":" type_expression { $$ = std::make_pair(std::move($1), std::shared_ptr($3)); } + identifiers ":" type_expression { $$ = std::make_pair($1, std::shared_ptr($3)); } required_fields: field_declaration ";" required_fields { - std::swap($$, $3); + $$ = $3; $$.emplace($$.cbegin(), $1); } | field_declaration { $$.emplace_back($1); } optional_fields: - required_fields { std::swap($$, $1); } + required_fields { $$ = $1; } | /* no fields */ {} field_initializer: - IDENTIFIER ":" expression { $$.name = std::move($1); $$.value = $3; } + IDENTIFIER ":" expression { $$.name = $1; $$.value = $3; } field_initializers: field_initializer "," field_initializers { - std::swap($$, $3); + $$ = $3; $$.emplace($$.cbegin(), $1); } | field_initializer { $$.push_back($1); } type_expression: "[" INTEGER "]" type_expression { - $$ = new boot::array_type_expression(boot::make_position(@1), $4, $2); + $$ = new boot::array_type_expression(boot::make_position(@$), $4, $2); } | "^" type_expression { - $$ = new boot::pointer_type_expression(boot::make_position(@1), $2); + $$ = new boot::pointer_type_expression(boot::make_position(@$), $2); } | "record" optional_fields "end" { - $$ = new boot::record_type_expression(boot::make_position(@1), std::move($2)); + $$ = new boot::record_type_expression(boot::make_position(@$), $2); } | "record" "(" IDENTIFIER ")" optional_fields "end" { - $$ = new boot::record_type_expression(boot::make_position(@1), std::move($5), std::move($3)); + $$ = new boot::record_type_expression(boot::make_position(@$), $5, $3); } | "proc" procedure_heading { @@ -464,97 +457,96 @@ type_expression: } | "(" identifiers ")" { - $$ = new boot::enumeration_type_expression(boot::make_position(@1), std::move($2)); + $$ = new boot::enumeration_type_expression(boot::make_position(@$), $2); } | IDENTIFIER { - $$ = new boot::named_expression(boot::make_position(@1), $1); + $$ = new boot::named_expression(boot::make_position(@$), $1); } identifiers: IDENTIFIER "," identifiers { - std::swap($$, $3); - $$.emplace($$.cbegin(), std::move($1)); + $$ = $3; + $$.emplace($$.cbegin(), $1); } - | IDENTIFIER { $$.emplace_back(std::move($1)); } + | IDENTIFIER { $$.emplace_back($1); } variable_declaration: identifier_definitions ":" type_expression { std::shared_ptr shared_type{ $3 }; - $$ = new boot::variable_declaration( boot::make_position(@2), std::move($1), shared_type); + $$ = new boot::variable_declaration( boot::make_position(@$), $1, shared_type); } | identifier_definitions ":" type_expression ":=" "extern" { std::shared_ptr shared_type{ $3 }; - $$ = new boot::variable_declaration( boot::make_position(@2), std::move($1), shared_type, - std::monostate{}); + $$ = new boot::variable_declaration( boot::make_position(@$), $1, shared_type, std::monostate{}); } | identifier_definitions ":" type_expression ":=" expression { std::shared_ptr shared_type{ $3 }; - $$ = new boot::variable_declaration( boot::make_position(@2), std::move($1), shared_type, $5); + $$ = new boot::variable_declaration( boot::make_position(@$), $1, shared_type, $5); } variable_declarations: /* no variable declarations */ {} | variable_declaration variable_declarations { - std::swap($$, $2); + $$ = $2; $$.insert(std::cbegin($$), $1); } variable_part: /* no variable declarations */ {} - | "var" variable_declarations { std::swap($$, $2); } + | "var" variable_declarations { $$ = $2; } constant_declaration: identifier_definition ":=" expression { - $$ = new boot::constant_declaration(boot::make_position(@1), std::move($1), $3); + $$ = new boot::constant_declaration(boot::make_position(@$), $1, $3); } constant_declarations: constant_declaration constant_declarations { - std::swap($$, $2); + $$ = $2; $$.insert(std::cbegin($$), $1); } | /* no constant definitions */ {} constant_part: /* no constant definitions */ {} - | "const" constant_declarations { std::swap($$, $2); } + | "const" constant_declarations { $$ = $2; } import_declaration: IDENTIFIER "." import_declaration { - std::swap($$, $3); - $$.emplace($$.cbegin(), std::move($1)); + $$ = $3; + $$.emplace($$.cbegin(), $1); } - | IDENTIFIER { $$.emplace_back(std::move($1)); } + | IDENTIFIER { $$.emplace_back($1); } import_declarations: import_declaration "," import_declarations { - std::swap($$, $3); - $$.emplace($$.cbegin(), new boot::import_declaration(boot::make_position(@1), std::move($1))); + $$ = $3; + $$.emplace($$.cbegin(), new boot::import_declaration(boot::make_position(@$), $1)); } | import_declaration { - $$.emplace_back(new boot::import_declaration(boot::make_position(@1), std::move($1))); + $$.emplace_back(new boot::import_declaration(boot::make_position(@$), $1)); } import_part: /* no import declarations */ {} - | "import" import_declarations { std::swap($$, $2); } + | "import" import_declarations { $$ = $2; } type_declaration: identifier_definition "=" type_expression { - $$ = new boot::type_declaration(boot::make_position(@1), std::move($1), $3); + $$ = new boot::type_declaration(boot::make_position(@$), $1, $3); } type_declarations: type_declaration type_declarations { - std::swap($$, $2); + $$ = $2; $$.insert($$.cbegin(), $1); } | /* no type definitions */ {} type_part: /* no type definitions */ {} - | "type" type_declarations { std::swap($$, $2); } + | "type" type_declarations { $$ = $2; } actual_parameter_list: "(" ")" {} - | "(" expressions ")" { std::swap($$, $2); } + | "(" expressions ")" { $$ = $2; } %% void yy::parser::error(const location_type& loc, const std::string& message) diff --git a/boot/result.cc b/boot/result.cc index 2222bd5..90d0ad6 100644 --- a/boot/result.cc +++ b/boot/result.cc @@ -19,19 +19,24 @@ along with GCC; see the file COPYING3. If not see namespace elna::boot { - error::error(const struct position position) - : position(position) + location::location(std::size_t line, std::size_t column) + : line(line), column(column) { } - std::size_t error::line() const noexcept + bool location::available() const { - return this->position.line; + return this->line != 0 || this->column != 0; } - std::size_t error::column() const noexcept + position::position(location start, location end) + : start(start), end(end) + { + } + + error::error(const struct position position) + : position(position) { - return this->position.column; } std::deque>& error_container::errors() diff --git a/boot/semantic.cc b/boot/semantic.cc index f42b094..d7a23be 100644 --- a/boot/semantic.cc +++ b/boot/semantic.cc @@ -783,9 +783,9 @@ namespace elna::boot void name_analysis_visitor::visit(traits_expression *trait) { - if (!trait->parameters.empty()) + if (!trait->arguments.empty()) { - trait->parameters.front()->accept(this); + trait->arguments.front()->accept(this); trait->types.push_back(this->current_type); } diff --git a/doc/appendix.tex b/doc/appendix.tex index 71b0cc4..36bb72a 100644 --- a/doc/appendix.tex +++ b/doc/appendix.tex @@ -35,8 +35,11 @@ \alt{} `0' (`X' | `x') \{\} \alt{} `0' (`B' | `b') \{\}. + = (`e' | `E') [`+' | `-'] \{\}. + = `.\@' \{\} - \alt{} \} `e' [`+' | `-'] \{\}. + [] + \alt{} . = `\textquotesingle' `\textquotesingle'. diff --git a/doc/language.tex b/doc/language.tex index 04f8613..b7b8d9d 100644 --- a/doc/language.tex +++ b/doc/language.tex @@ -51,9 +51,10 @@ preceded by a prefix and followed by a suffix. The prefixes \verb|0x| and indicate binary representation. Unsigned integers have the suffix \verb|u|, signed integers have no suffix. -A \textit{real number} always contains a decimal point. Optionally it may -also contain a decimal scale factor. The letters \verb|e| or \verb|E| is -pronounced as `times ten to the power of'. +A \textit{real number} contains either a decimal point, or a scale factor, +or both. A decimal point must be followed by at least one digit. The letter +\verb|e| (or \verb|E|) introduces the scale factor and is pronounced +``times ten to the power of''. \begin{grammar} = `0' | \{\}. @@ -62,8 +63,11 @@ pronounced as `times ten to the power of'. \alt{} `0' (`X' | `x') \{\} \alt{} `0' (`B' | `b') \{\}. + = (`e' | `E') [`+' | `-'] \{\}. + = `.\@' \{\} - \alt{} \} `e' [`+' | `-'] \{\}. + [] + \alt{} . \end{grammar} Examples: diff --git a/gcc/gcc/elna-diagnostic.cc b/gcc/gcc/elna-diagnostic.cc index 42db5c9..f7b660d 100644 --- a/gcc/gcc/elna-diagnostic.cc +++ b/gcc/gcc/elna-diagnostic.cc @@ -40,9 +40,25 @@ namespace elna::gcc location_t get_location(const boot::position *position) { - linemap_line_start(line_table, position->line, 0); + linemap_line_start(line_table, position->start.line, 0); - return linemap_position_for_column(line_table, position->column); + return linemap_position_for_column(line_table, position->start.column); + } + + void fill_range(const boot::position& position, location_t& start, location_t& end) + { + linemap_line_start(line_table, position.start.line, 0); + start = linemap_position_for_column(line_table, position.start.column); + + if (position.start.line != position.end.line || position.start.column != position.end.column) + { + linemap_line_start(line_table, position.end.line, 0); + end = linemap_position_for_column(line_table, position.end.column); + } + else + { + end = start; + } } std::string print_aggregate_name(tree type, const std::string& kind_name) @@ -158,13 +174,19 @@ namespace elna::gcc { for (const auto& error : errors) { - location_t gcc_location{ UNKNOWN_LOCATION }; - - if (error->position.line != 0 || error->position.column != 0) + if (error->position.start.available()) + { + location_t start, end; + fill_range(error->position, start, end); + rich_location rich_loc(line_table, start); + rich_loc.add_range(end); + error_at(&rich_loc, error->what().c_str()); + } + else { - gcc_location = get_location(&error->position); + location_t gcc_location{ UNKNOWN_LOCATION }; + error_at(gcc_location, error->what().c_str()); } - error_at(gcc_location, error->what().c_str()); } } } diff --git a/gcc/gcc/elna-generic.cc b/gcc/gcc/elna-generic.cc index 928ca8d..f29828f 100644 --- a/gcc/gcc/elna-generic.cc +++ b/gcc/gcc/elna-generic.cc @@ -841,10 +841,10 @@ namespace elna::gcc bool generic_visitor::expect_trait_type_only(boot::traits_expression *trait) { - if (trait->parameters.size() != 1) + if (trait->arguments.size() != 1) { error_at(get_location(&trait->position()), "Trait '%s' expects 1 argument, got %lu", - trait->name.c_str(), trait->parameters.size()); + trait->name.c_str(), trait->arguments.size()); this->current_expression = error_mark_node; return false; } @@ -905,15 +905,15 @@ namespace elna::gcc } else if (trait->name == "offset") { - if (trait->parameters.size() != 2) + if (trait->arguments.size() != 2) { error_at(trait_location, "Trait '%s' expects 2 arguments, got %lu", - trait->name.c_str(), trait->parameters.size()); + trait->name.c_str(), trait->arguments.size()); this->current_expression = error_mark_node; return; } this->current_expression = get_inner_alias(trait->types.front(), this->symbols); - auto field_type = trait->parameters.at(1)->is_named(); + auto field_type = trait->arguments.at(1)->is_named(); if (field_type == nullptr) { diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index fbe65a4..04ffc22 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -533,11 +533,12 @@ namespace elna::boot class traits_expression : public expression { public: - std::vector parameters; + const std::vector arguments; const std::string name; std::vector types; - traits_expression(const struct position position, const std::string& name); + traits_expression(const struct position position, const std::string& name, + std::vector&& arguments); ~traits_expression(); void accept(parser_visitor *visitor) override; @@ -666,9 +667,10 @@ namespace elna::boot designator_expression *m_callable; public: - std::vector arguments; + const std::vector arguments; - procedure_call(const struct position position, designator_expression *callable); + procedure_call(const struct position position, designator_expression *callable, + std::vector&& arguments); void accept(parser_visitor *visitor) override; virtual procedure_call *is_call_expression() override; diff --git a/include/elna/boot/result.h b/include/elna/boot/result.h index 1b04bfb..0556dbe 100644 --- a/include/elna/boot/result.h +++ b/include/elna/boot/result.h @@ -26,15 +26,33 @@ along with GCC; see the file COPYING3. If not see namespace elna::boot { /** - * Position in the source text. + * Location in the source text. */ - struct position + struct location { /// Line. - std::size_t line = 1; + const std::size_t line; /// Column. - std::size_t column = 1; + const std::size_t column; + + location(std::size_t line, std::size_t column); + + bool available() const; + }; + + /** + * Span in the source text. + */ + struct position + { + /// Start location. + const location start; + + /// End location. + const location end; + + position(location start, location end); }; /** @@ -46,18 +64,11 @@ namespace elna::boot error(const struct position position); public: + /// Error position. const struct position position; - virtual ~error() = default; - /// Error text. virtual std::string what() const = 0; - - /// Error line in the source text. - std::size_t line() const; - - /// Error column in the source text. - std::size_t column() const; }; using error_list = typename std::deque>; diff --git a/include/elna/gcc/elna-diagnostic.h b/include/elna/gcc/elna-diagnostic.h index a8d4a69..3957003 100644 --- a/include/elna/gcc/elna-diagnostic.h +++ b/include/elna/gcc/elna-diagnostic.h @@ -42,6 +42,7 @@ namespace elna::gcc }; location_t get_location(const boot::position *position); + void fill_range(const boot::position& position, location_t& start, location_t& end); std::string print_type(tree type); void report_errors(const std::deque>& errors); } diff --git a/testsuite/compilable/float_literals.elna b/testsuite/compilable/float_literals.elna new file mode 100644 index 0000000..1ce914d --- /dev/null +++ b/testsuite/compilable/float_literals.elna @@ -0,0 +1,9 @@ +proc f() +const + x := 3.14 + y := 1e10 + z := 4.567e8 + t := 2.5E-3 +end + +end. -- cgit v1.2.3