Read the input filename from the command line

This commit is contained in:
Eugen Wissner 2025-02-02 08:22:40 +01:00
parent b41d6fb907
commit 607bf09434
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
9 changed files with 213 additions and 182 deletions

View File

@ -92,9 +92,13 @@ namespace boot
void empty_visitor::visit(block *block) void empty_visitor::visit(block *block)
{ {
for (const auto definition : block->value_definitions) for (const auto constant : block->constants)
{ {
definition->accept(this); constant->accept(this);
}
for (const auto variable : block->variables)
{
variable->accept(this);
} }
for (const auto body_statement : block->body) for (const auto body_statement : block->body)
{ {
@ -474,9 +478,8 @@ namespace boot
delete m_body; delete m_body;
} }
block::block(const struct position position, std::vector<definition *>&& value_definitions, block::block(const struct position position)
std::vector<statement *>&& body) : node(position)
: node(position), value_definitions(std::move(value_definitions)), body(std::move(body))
{ {
} }
@ -487,9 +490,13 @@ namespace boot
block::~block() block::~block()
{ {
for (auto definition : this->value_definitions) for (auto variable : this->variables)
{ {
delete definition; delete variable;
}
for (auto constant : this->constants)
{
delete constant;
} }
for (auto body_statement : this->body) for (auto body_statement : this->body)
{ {
@ -497,10 +504,8 @@ namespace boot
} }
} }
program::program(const struct position position, program::program(const struct position position, std::vector<definition *>&& type_definitions)
std::vector<definition *>&& type_definitions, : block(position),
std::vector<definition *>&& value_definitions, std::vector<statement *>&& body)
: block(position, std::move(value_definitions), std::move(body)),
type_definitions(std::move(type_definitions)) type_definitions(std::move(type_definitions))
{ {
} }

View File

@ -111,49 +111,34 @@
%type <elna::boot::cast_expression *> cast_expression; %type <elna::boot::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 variable_part procedure_part BEGIN_BLOCK optional_statements END_BLOCK DOT
{ {
std::vector<elna::boot::definition *> definitions($1.size() + $3.size()); std::vector<elna::boot::definition *> definitions($1.size() + $4.size());
std::vector<elna::boot::definition *>::iterator definition = definitions.begin(); std::vector<elna::boot::definition *>::iterator definition = definitions.begin();
std::vector<elna::boot::definition *> value_definitions($2.size() + $4.size());
std::vector<elna::boot::definition *>::iterator value_definition = value_definitions.begin();
for (auto type : $1) for (auto type : $1)
{ {
*definition++ = type; *definition++ = type;
} }
for (auto constant : $2) for (auto procedure : $4)
{
*value_definition++ = constant;
}
for (auto procedure : $3)
{ {
*definition++ = procedure; *definition++ = procedure;
} }
for (auto variable : $4) auto tree = new elna::boot::program(elna::boot::make_position(@5), std::move(definitions));
{
*value_definition++ = variable; std::swap(tree->constants, $2);
} std::swap(tree->variables, $3);
auto tree = new elna::boot::program(elna::boot::make_position(@5), std::swap(tree->body, $6);
std::move(definitions), std::move(value_definitions), std::move($6));
driver.tree.reset(tree); driver.tree.reset(tree);
} }
block: constant_part variable_part BEGIN_BLOCK optional_statements END_BLOCK block: constant_part variable_part BEGIN_BLOCK optional_statements END_BLOCK
{ {
std::vector<elna::boot::definition *> definitions($1.size() + $2.size()); $$ = new elna::boot::block(elna::boot::make_position(@3));
std::vector<elna::boot::definition *>::iterator definition = definitions.begin();
for (auto constant : $1) std::swap($$->constants, $1);
{ std::swap($$->variables, $2);
*definition++ = constant; std::swap($$->body, $4);
}
for (auto variable : $2)
{
*definition++ = variable;
}
$$ = new elna::boot::block(elna::boot::make_position(@3),
std::move(definitions), std::move($4));
} }
procedure_definition: procedure_definition:
PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON block SEMICOLON PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON block SEMICOLON

View File

@ -36,10 +36,6 @@ namespace gcc
{ {
return "Char"; return "Char";
} }
else if (is_string_type(type))
{
return "String";
}
else if (is_pointer_type(type)) else if (is_pointer_type(type))
{ {
return "pointer"; return "pointer";

View File

@ -86,16 +86,44 @@ namespace gcc
|| type == this->symbol_map->lookup("Word")->payload; || type == this->symbol_map->lookup("Word")->payload;
} }
bool generic_visitor::is_numeric_type(tree type)
{
return is_integral_type(type)
|| type == this->symbol_map->lookup("Float")->payload;
}
void generic_visitor::visit(boot::program *program) void generic_visitor::visit(boot::program *program)
{ {
for (const auto definition : program->value_definitions) for (const auto& type_definition : program->type_definitions)
{ {
definition->accept(this); type_definition->accept(this);
} }
for (const auto& constant : program->type_definitions) for (const auto constant : program->constants)
{ {
constant->accept(this); constant->accept(this);
} }
for (const auto declaration : program->variables)
{
tree declaration_type = build_type(declaration->type());
gcc_assert(declaration_type != NULL_TREE);
auto declaration_location = get_location(&declaration->position());
tree declaration_tree = build_decl(declaration_location, VAR_DECL,
get_identifier(declaration->identifier().c_str()), declaration_type);
auto result = this->symbol_map->enter(declaration->identifier(), boot::make_info(declaration_tree));
if (result)
{
TREE_STATIC(declaration_tree) = 1;
varpool_node::get_create(declaration_tree);
varpool_node::finalize_decl(declaration_tree);
}
else
{
error_at(declaration_location, "variable '%s' already declared in this scope",
declaration->identifier().c_str());
}
}
std::array<tree, 2> parameter_types{ std::array<tree, 2> parameter_types{
integer_type_node, integer_type_node,
build_pointer_type(build_pointer_type(char_type_node)) build_pointer_type(build_pointer_type(char_type_node))
@ -278,49 +306,57 @@ namespace gcc
this->current_expression = build_string_literal(string->string().size() + 1, string->string().c_str()); this->current_expression = build_string_literal(string->string().size() + 1, string->string().c_str());
} }
void generic_visitor::build_binary_operation(bool condition, boot::binary_expression *expression, tree generic_visitor::build_arithmetic_operation(boot::binary_expression *expression,
tree_code operator_code, tree left, tree right, tree target_type) tree_code operator_code, tree left, tree right)
{ {
auto expression_location = get_location(&expression->position()); return build_binary_operation(is_numeric_type(TREE_TYPE(left)),
auto left_type = TREE_TYPE(left); expression, operator_code, left, right, TREE_TYPE(left));
auto right_type = TREE_TYPE(right); }
if (condition) tree generic_visitor::build_comparison_operation(boot::binary_expression *expression,
{ tree_code operator_code, tree left, tree right)
this->current_expression = build2_loc(expression_location, {
operator_code, target_type, left, right); return build_binary_operation(is_numeric_type(TREE_TYPE(left)) || is_pointer_type(TREE_TYPE(left)),
} expression, operator_code, left, right, this->symbol_map->lookup("Bool")->payload);
else }
{
error_at(expression_location, tree generic_visitor::build_logic_operation(boot::binary_expression *expression,
"invalid operands of type %s and %s for operator %s", tree_code operator_code, tree left, tree right)
print_type(left_type), print_type(right_type), {
elna::boot::print_binary_operator(expression->operation())); auto symbol = this->symbol_map->lookup("Bool");
this->current_expression = error_mark_node;
} return build_binary_operation(TREE_TYPE(left) == symbol->payload,
expression, operator_code, left, right, symbol->payload);
}
tree generic_visitor::build_equality_operation(boot::binary_expression *expression,
tree_code operator_code, tree left, tree right)
{
return build_binary_operation(true, expression,
operator_code, left, right, this->symbol_map->lookup("Bool")->payload);
} }
void generic_visitor::visit(boot::binary_expression *expression) void generic_visitor::visit(boot::binary_expression *expression)
{ {
expression->lhs().accept(this); expression->lhs().accept(this);
auto left = this->current_expression; tree left = this->current_expression;
auto left_type = TREE_TYPE(left); tree left_type = TREE_TYPE(left);
expression->rhs().accept(this); expression->rhs().accept(this);
auto right = this->current_expression; tree right = this->current_expression;
auto right_type = TREE_TYPE(right); tree right_type = TREE_TYPE(right);
auto expression_location = get_location(&expression->position()); location_t expression_location = get_location(&expression->position());
tree_code operator_code = ERROR_MARK;
tree target_type = error_mark_node;
if (is_pointer_type(left_type) && is_integral_type(right_type) if (is_pointer_type(left_type) && is_integral_type(right_type))
&& expression->operation() == boot::binary_operator::sum)
{ {
tree convert_expression = build1_loc(expression_location, CONVERT_EXPR, this->current_expression = do_pointer_arithmetic(expression->operation(), left, right);
sizetype, right); if (this->current_expression == error_mark_node)
this->current_expression = build2_loc(expression_location, {
POINTER_PLUS_EXPR, left_type, left, convert_expression); error_at(expression_location,
"invalid operation %s on a pointer and an integral type",
boot::print_binary_operator(expression->operation()));
}
return; return;
} }
if (left_type != right_type) if (left_type != right_type)
@ -335,87 +371,45 @@ namespace gcc
switch (expression->operation()) switch (expression->operation())
{ {
case boot::binary_operator::sum: case boot::binary_operator::sum:
operator_code = PLUS_EXPR; this->current_expression = build_arithmetic_operation(expression, PLUS_EXPR, left, right);
target_type = left_type;
break; break;
case boot::binary_operator::subtraction: case boot::binary_operator::subtraction:
operator_code = MINUS_EXPR; this->current_expression = build_arithmetic_operation(expression, MINUS_EXPR, left, right);
target_type = left_type;
break; break;
case boot::binary_operator::division: case boot::binary_operator::division:
operator_code = TRUNC_DIV_EXPR; this->current_expression = build_arithmetic_operation(expression, TRUNC_DIV_EXPR, left, right);
target_type = left_type;
break; break;
case boot::binary_operator::remainder: case boot::binary_operator::remainder:
operator_code = TRUNC_MOD_EXPR; this->current_expression = build_arithmetic_operation(expression, TRUNC_MOD_EXPR, left, right);
target_type = left_type;
break; break;
case boot::binary_operator::multiplication: case boot::binary_operator::multiplication:
operator_code = MULT_EXPR; this->current_expression = build_arithmetic_operation(expression, MULT_EXPR, left, right);
target_type = left_type;
break; break;
case boot::binary_operator::less: case boot::binary_operator::less:
operator_code = LT_EXPR; this->current_expression = build_comparison_operation(expression, LT_EXPR, left, right);
target_type = boolean_type_node;
break; break;
case boot::binary_operator::greater: case boot::binary_operator::greater:
operator_code = GT_EXPR; this->current_expression = build_comparison_operation(expression, GT_EXPR, left, right);
target_type = boolean_type_node;
break; break;
case boot::binary_operator::less_equal: case boot::binary_operator::less_equal:
operator_code = LE_EXPR; this->current_expression = build_comparison_operation(expression, LE_EXPR, left, right);
target_type = boolean_type_node;
break; break;
case boot::binary_operator::greater_equal: case boot::binary_operator::greater_equal:
operator_code = GE_EXPR; this->current_expression = build_comparison_operation(expression, GE_EXPR, left, right);
target_type = boolean_type_node;
break; break;
default:
break;
}
if (operator_code != ERROR_MARK) // An arithmetic operation.
{
build_binary_operation(is_integral_type(left_type) || left_type == double_type_node,
expression, operator_code, left, right, target_type);
return;
}
switch (expression->operation())
{
case boot::binary_operator::conjunction: case boot::binary_operator::conjunction:
operator_code = TRUTH_ANDIF_EXPR; this->current_expression = build_logic_operation(expression, TRUTH_ANDIF_EXPR, left, right);
target_type = boolean_type_node;
break; break;
case boot::binary_operator::disjunction: case boot::binary_operator::disjunction:
operator_code = TRUTH_ORIF_EXPR; this->current_expression = build_logic_operation(expression, TRUTH_ORIF_EXPR, left, right);
target_type = boolean_type_node;
break; break;
default:
break;
}
if (operator_code != ERROR_MARK) // A logical operation.
{
build_binary_operation(left_type == boolean_type_node,
expression, operator_code, left, right, target_type);
return;
}
switch (expression->operation())
{
case boot::binary_operator::equals: case boot::binary_operator::equals:
operator_code = EQ_EXPR; this->current_expression = build_equality_operation(expression, EQ_EXPR, left, right);
target_type = boolean_type_node;
break; break;
case boot::binary_operator::not_equals: case boot::binary_operator::not_equals:
operator_code = NE_EXPR; this->current_expression = build_equality_operation(expression, NE_EXPR, left, right);
target_type = boolean_type_node;
break;
default:
break; break;
} }
gcc_assert(operator_code != ERROR_MARK);
gcc_assert(target_type != error_mark_node);
this->current_expression = build2_loc(expression_location,
operator_code, target_type, left, right);
} }
void generic_visitor::visit(boot::unary_expression *expression) void generic_visitor::visit(boot::unary_expression *expression)

View File

@ -1,6 +1,9 @@
#include "elna/gcc/elna-tree.h" #include "elna/gcc/elna-tree.h"
#include "elna/gcc/elna-diagnostic.h"
#include "stor-layout.h" #include "stor-layout.h"
#include "fold-const.h"
#include "diagnostic-core.h"
tree elna_global_trees[ELNA_TI_MAX]; tree elna_global_trees[ELNA_TI_MAX];
@ -20,12 +23,6 @@ namespace gcc
return TREE_CODE(type) == POINTER_TYPE; return TREE_CODE(type) == POINTER_TYPE;
} }
bool is_string_type(tree type)
{
return is_pointer_type(type)
&& TYPE_MAIN_VARIANT(TREE_TYPE(type)) == char_type_node;
}
tree tree_chain_base::head() tree tree_chain_base::head()
{ {
return first; return first;
@ -81,5 +78,43 @@ namespace gcc
return initial_table; return initial_table;
} }
tree do_pointer_arithmetic(boot::binary_operator binary_operator, tree left, tree right)
{
tree result = error_mark_node;
tree convert_expression = fold_convert(sizetype, right);
if (binary_operator == boot::binary_operator::sum)
{
result = fold_build2(POINTER_PLUS_EXPR, TREE_TYPE(left), left, convert_expression);
}
else if (binary_operator == boot::binary_operator::subtraction)
{
convert_expression = fold_build1(NEGATE_EXPR, sizetype, convert_expression);
result = fold_build2(POINTER_PLUS_EXPR, TREE_TYPE(left), left, convert_expression);
}
return result;
}
tree build_binary_operation(bool condition, boot::binary_expression *expression,
tree_code operator_code, tree left, tree right, tree target_type)
{
location_t expression_location = get_location(&expression->position());
tree left_type = TREE_TYPE(left);
tree right_type = TREE_TYPE(right);
if (condition)
{
return build2_loc(expression_location, operator_code, target_type, left, right);
}
else
{
error_at(expression_location,
"invalid operands of type %s and %s for operator %s",
print_type(left_type), print_type(right_type),
elna::boot::print_binary_operator(expression->operation()));
return error_mark_node;
}
}
} }
} }

View File

@ -637,11 +637,11 @@ namespace boot
class block : public node class block : public node
{ {
public: public:
std::vector<definition *> value_definitions; std::vector<variable_declaration *> variables;
std::vector<constant_definition *> constants;
std::vector<statement *> body; std::vector<statement *> body;
block(const struct position position, std::vector<definition *>&& value_definitions, block(const struct position position);
std::vector<statement *>&& body);
virtual void accept(parser_visitor *visitor) override; virtual void accept(parser_visitor *visitor) override;
virtual ~block() override; virtual ~block() override;
@ -652,8 +652,7 @@ namespace boot
public: public:
std::vector<definition *> type_definitions; std::vector<definition *> type_definitions;
program(const struct position position, std::vector<definition *>&& type_definitions, program(const struct position position, std::vector<definition *>&& type_definitions);
std::vector<definition *>&& value_definitions, std::vector<statement *>&& body);
virtual void accept(parser_visitor *visitor) override; virtual void accept(parser_visitor *visitor) override;
virtual ~program() override; virtual ~program() override;

View File

@ -31,12 +31,19 @@ namespace gcc
void enter_scope(); void enter_scope();
tree_symbol_mapping leave_scope(); tree_symbol_mapping leave_scope();
void build_binary_operation(bool condition, boot::binary_expression *expression,
tree_code operator_code, tree left, tree right, tree target_type);
void make_if_branch(boot::conditional_statements& branch, tree goto_endif); void make_if_branch(boot::conditional_statements& branch, tree goto_endif);
bool is_integral_type(tree type); bool is_integral_type(tree type);
bool is_numeric_type(tree type);
tree build_arithmetic_operation(boot::binary_expression *expression,
tree_code operator_code, tree left, tree right);
tree build_comparison_operation(boot::binary_expression *expression,
tree_code operator_code, tree left, tree right);
tree build_logic_operation(boot::binary_expression *expression,
tree_code operator_code, tree left, tree right);
tree build_equality_operation(boot::binary_expression *expression,
tree_code operator_code, tree left, tree right);
public: public:
generic_visitor(std::shared_ptr<boot::symbol_table<tree>> symbol_table); generic_visitor(std::shared_ptr<boot::symbol_table<tree>> symbol_table);

View File

@ -4,8 +4,8 @@
#include "system.h" #include "system.h"
#include "coretypes.h" #include "coretypes.h"
#include "tree.h" #include "tree.h"
#include "tree.h"
#include "elna/boot/ast.h"
#include "elna/boot/symbol.h" #include "elna/boot/symbol.h"
enum elna_tree_index enum elna_tree_index
@ -24,7 +24,6 @@ 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);
class tree_chain_base class tree_chain_base
{ {
@ -58,5 +57,11 @@ namespace gcc
}; };
std::shared_ptr<boot::symbol_table<tree>> builtin_symbol_table(); std::shared_ptr<boot::symbol_table<tree>> builtin_symbol_table();
tree do_pointer_arithmetic(boot::binary_operator binary_operator, tree left, tree right);
tree build_binary_operation(bool condition, boot::binary_expression *expression,
tree_code operator_code, tree left, tree right, tree target_type);
tree build_arithmetic_operation(boot::binary_expression *expression,
tree_code operator_code, tree left, tree right);
} }
} }

View File

@ -20,6 +20,9 @@ type
end, end,
FILE = record FILE = record
dummy: Int dummy: Int
end,
CommandLine = record
input: pointer to Char
end; end;
const const
@ -141,19 +144,6 @@ end;
End of standard procedures. End of standard procedures.
*) *)
proc test_primitive();
begin
write_s("\nTest primitives:\n");
write_u(25u);
write_c('\n');
write_i(8);
write_c('\n');
write_b(true);
write_c('\n')
end;
proc read_source(filename: String): pointer to Char; proc read_source(filename: String): pointer to Char;
var var
input_file: pointer to FILE, input_file: pointer to FILE,
@ -272,7 +262,7 @@ var
is_valid: Bool; is_valid: Bool;
begin begin
token_end := input; token_end := input;
previous := cast(cast(input as Word) - 1u as pointer to Char); previous := input - 1;
while token_end^ <> '\0' and not (previous^ <> '\\' and token_end^ = '"') do while token_end^ <> '\0' and not (previous^ <> '\\' and token_end^ = '"') do
previous := token_end; previous := token_end;
@ -286,7 +276,7 @@ begin
is_valid := true; is_valid := true;
constructed_string := current_token^.value.string_value; constructed_string := current_token^.value.string_value;
while cast(input as Word) < cast(token_end as Word) and is_valid do while input < token_end and is_valid do
if input^ = '\\' then if input^ = '\\' then
input := input + 1; input := input + 1;
@ -677,32 +667,51 @@ begin
return tokens return tokens
end; end;
proc command_line(argc: Int, argv: pointer to pointer to Char); proc parse_command_line(argc: Int, argv: pointer to pointer to Char): pointer to CommandLine;
var var
parameter: pointer to pointer to Char, parameter: pointer to pointer to Char,
i: Int; i: Int,
result: pointer to CommandLine;
begin begin
write_s("Argument count: "); if argc < 2 then
write_i(argc - 1); write_s("Fatal error: no input files.\n");
write_s("\nArguments:"); return nil
end;
if argc > 2 then
write_s("Fatal error: Unknown command line options:");
i := 1; i := 2;
while i < argc do while i < argc do
parameter := argv + i * cast(sizeof(pointer to Char) as Int); parameter := argv + i * cast(sizeof(pointer to Char) as Int);
write_c(' ');
write_s(parameter^);
i := i + 1
end;
write_s(".\n");
return nil
end;
write_c(' '); parameter := argv + cast(sizeof(pointer to Char) as Int);
write_s(parameter^); result := cast(malloc(sizeof(CommandLine)) as pointer to CommandLine);
i := i + 1 result^.input := parameter^;
end
return result
end; end;
proc compile(); proc process(argc: Int, argv: pointer to pointer to Char): Int;
var var
input: pointer to Char, input: pointer to Char,
tokens: pointer to Token, tokens: pointer to Token,
tokens_size: Word; tokens_size: Word,
command_line: pointer to CommandLine;
begin begin
input := read_source("example.elna"); command_line := parse_command_line(argc, argv);
if cast(command_line as Word) = 0u then
return 2
end;
input := read_source(command_line^.input);
tokens := tokenize(input, @tokens_size); tokens := tokenize(input, @tokens_size);
free(input); free(input);
@ -711,9 +720,5 @@ begin
end; end;
begin begin
command_line(count, parameters); exit(process(count, parameters))
compile();
test_primitive();
exit(0)
end. end.