aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--boot/ast.cc18
-rw-r--r--boot/driver.cc9
-rw-r--r--boot/lexer.ll16
-rw-r--r--boot/parser.yy210
-rw-r--r--boot/result.cc17
-rw-r--r--boot/semantic.cc4
-rw-r--r--doc/appendix.tex5
-rw-r--r--doc/language.tex12
-rw-r--r--gcc/gcc/elna-diagnostic.cc36
-rw-r--r--gcc/gcc/elna-generic.cc10
-rw-r--r--include/elna/boot/ast.h10
-rw-r--r--include/elna/boot/result.h35
-rw-r--r--include/elna/gcc/elna-diagnostic.h1
-rw-r--r--testsuite/compilable/float_literals.elna9
14 files changed, 228 insertions, 164 deletions
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<expression *>&& 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<type_expression *>&& 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<std::size_t>(location.begin.line);
- result.column = static_cast<std::size_t>(location.begin.column);
+ auto start_location = boot::location(static_cast<std::size_t>(location.begin.line),
+ static_cast<std::size_t>(location.begin.column));
+ auto end_location = boot::location(static_cast<std::size_t>(location.end.line),
+ static_cast<std::size_t>(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 <std::string> TRAIT
%token <std::int32_t> INTEGER
%token <std::uint32_t> WORD
-%token <float> FLOAT
+%token <double> FLOAT
%token <std::string> CHARACTER
%token <std::string> STRING
%token <bool> 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<boot::procedure_body>(std::move($1), std::move($2), std::move($3), $4);
- }
+ { $$ = std::make_unique<boot::procedure_body>($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<boot::statement *>(std::move($2)); }
+ "else" statements { $$ = new std::vector<boot::statement *>($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<std::int32_t>(boot::make_position(@1), $1); }
- | WORD { $$ = new boot::literal<std::uint32_t>(boot::make_position(@1), $1); }
- | FLOAT { $$ = new boot::literal<double>(boot::make_position(@1), $1); }
- | BOOLEAN { $$ = new boot::literal<bool>(boot::make_position(@1), $1); }
- | CHARACTER { $$ = new boot::literal<unsigned char>(boot::make_position(@1), $1.at(0)); }
- | "nil" { $$ = new boot::literal<std::nullptr_t>(boot::make_position(@1), nullptr); }
- | STRING { $$ = new boot::literal<std::string>(boot::make_position(@1), $1); }
+ INTEGER { $$ = new boot::literal<std::int32_t>(boot::make_position(@$), $1); }
+ | WORD { $$ = new boot::literal<std::uint32_t>(boot::make_position(@$), $1); }
+ | FLOAT { $$ = new boot::literal<double>(boot::make_position(@$), $1); }
+ | BOOLEAN { $$ = new boot::literal<bool>(boot::make_position(@$), $1); }
+ | CHARACTER { $$ = new boot::literal<unsigned char>(boot::make_position(@$), $1.at(0)); }
+ | "nil" { $$ = new boot::literal<std::nullptr_t>(boot::make_position(@$), nullptr); }
+ | STRING { $$ = new boot::literal<std::string>(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<boot::type_expression>($3)); }
+ identifiers ":" type_expression { $$ = std::make_pair($1, std::shared_ptr<boot::type_expression>($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<boot::type_expression> 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<boot::type_expression> 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<boot::type_expression> 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<std::unique_ptr<error>>& 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') <hex-digit> \{<hex-digit>\}
\alt{} `0' (`B' | `b') <binary-digit> \{<binary-digit>\}.
+<scale-factor> = (`e' | `E') [`+' | `-'] <decimal-digit> \{<decimal-digit>\}.
+
<real-literal> = <integer-literal> `.\@' <decimal-digit> \{<decimal-digit>\}
- \alt{} <integer-literal>\} `e' [`+' | `-'] <decimal-digit> \{<decimal-digit>\}.
+ [<scale-factor>]
+ \alt{} <integer-literal> <scale-factor>.
<character-literal> = `\textquotesingle' <character> `\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}
<integer-literal> = `0' | <counting-digit> \{<decimal-digit>\}.
@@ -62,8 +63,11 @@ pronounced as `times ten to the power of'.
\alt{} `0' (`X' | `x') <hex-digit> \{<hex-digit>\}
\alt{} `0' (`B' | `b') <binary-digit> \{<binary-digit>\}.
+<scale-factor> = (`e' | `E') [`+' | `-'] <decimal-digit> \{<decimal-digit>\}.
+
<real-literal> = <integer-literal> `.\@' <decimal-digit> \{<decimal-digit>\}
- \alt{} <integer-literal>\} `e' [`+' | `-'] <decimal-digit> \{<decimal-digit>\}.
+ [<scale-factor>]
+ \alt{} <integer-literal> <scale-factor>.
\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<type_expression *> parameters;
+ const std::vector<type_expression *> arguments;
const std::string name;
std::vector<type> types;
- traits_expression(const struct position position, const std::string& name);
+ traits_expression(const struct position position, const std::string& name,
+ std::vector<type_expression *>&& arguments);
~traits_expression();
void accept(parser_visitor *visitor) override;
@@ -666,9 +667,10 @@ namespace elna::boot
designator_expression *m_callable;
public:
- std::vector<expression *> arguments;
+ const std::vector<expression *> arguments;
- procedure_call(const struct position position, designator_expression *callable);
+ procedure_call(const struct position position, designator_expression *callable,
+ std::vector<expression *>&& 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<std::unique_ptr<error>>;
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<std::unique_ptr<boot::error>>& 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.