Allow only one return
This commit is contained in:
parent
f091344cce
commit
18602d00a1
62
boot/ast.cc
62
boot/ast.cc
@ -86,24 +86,6 @@ namespace boot
|
||||
}
|
||||
}
|
||||
|
||||
void empty_visitor::visit(return_statement *statement)
|
||||
{
|
||||
expression *return_expression = statement->return_expression();
|
||||
|
||||
if (return_expression != nullptr)
|
||||
{
|
||||
return_expression->accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void empty_visitor::visit(defer_statement *defer)
|
||||
{
|
||||
for (statement *const body_statement : defer->statements)
|
||||
{
|
||||
body_statement->accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void empty_visitor::visit(block *block)
|
||||
{
|
||||
for (constant_definition *const constant : block->constants)
|
||||
@ -448,8 +430,9 @@ namespace boot
|
||||
}
|
||||
|
||||
procedure_definition::procedure_definition(const struct position position, const std::string& identifier,
|
||||
const bool exported, std::shared_ptr<procedure_type> heading, block *body)
|
||||
: definition(position, identifier, exported), m_heading(heading), body(body)
|
||||
const bool exported, std::shared_ptr<procedure_type> heading,
|
||||
block *const body, expression *const returning)
|
||||
: definition(position, identifier, exported), m_heading(heading), body(body), returning(returning)
|
||||
{
|
||||
}
|
||||
|
||||
@ -466,6 +449,7 @@ namespace boot
|
||||
procedure_definition::~procedure_definition()
|
||||
{
|
||||
delete body;
|
||||
delete returning;
|
||||
}
|
||||
|
||||
type_definition::type_definition(const struct position position, const std::string& identifier,
|
||||
@ -536,24 +520,6 @@ namespace boot
|
||||
{
|
||||
}
|
||||
|
||||
defer_statement::defer_statement(const struct position position)
|
||||
: node(position)
|
||||
{
|
||||
}
|
||||
|
||||
void defer_statement::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
defer_statement::~defer_statement()
|
||||
{
|
||||
for (statement *body_statement : statements)
|
||||
{
|
||||
delete body_statement;
|
||||
}
|
||||
}
|
||||
|
||||
designator_expression::designator_expression()
|
||||
{
|
||||
}
|
||||
@ -805,26 +771,6 @@ namespace boot
|
||||
}
|
||||
}
|
||||
|
||||
return_statement::return_statement(const struct position position, expression *return_expression)
|
||||
: node(position), m_return_expression(return_expression)
|
||||
{
|
||||
}
|
||||
|
||||
void return_statement::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
expression *return_statement::return_expression()
|
||||
{
|
||||
return m_return_expression;
|
||||
}
|
||||
|
||||
return_statement::~return_statement()
|
||||
{
|
||||
delete m_return_expression;
|
||||
}
|
||||
|
||||
void assign_statement::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
|
@ -125,9 +125,6 @@ return {
|
||||
cast {
|
||||
return yy::parser::make_CAST(this->location);
|
||||
}
|
||||
defer {
|
||||
return yy::parser::make_DEFER(this->location);
|
||||
}
|
||||
[A-Za-z_][A-Za-z0-9_]* {
|
||||
return yy::parser::make_IDENTIFIER(yytext, this->location);
|
||||
}
|
||||
|
@ -106,7 +106,6 @@ along with GCC; see the file COPYING3. If not see
|
||||
RETURN "return"
|
||||
BEGIN_BLOCK "begin"
|
||||
END_BLOCK "end"
|
||||
DEFER "defer"
|
||||
%token OR "or" AND "and" XOR "xor"
|
||||
EQUALS "=" NOT_EQUAL "<>" LESS_THAN "<" GREATER_THAN ">" LESS_EQUAL "<=" GREATER_EQUAL ">="
|
||||
SHIFT_LEFT "<<" SHIFT_RIGHT ">>"
|
||||
@ -134,12 +133,12 @@ along with GCC; see the file COPYING3. If not see
|
||||
%type <elna::boot::procedure_call*> call_expression;
|
||||
%type <elna::boot::while_statement *> while_statement;
|
||||
%type <elna::boot::if_statement *> if_statement;
|
||||
%type <elna::boot::return_statement *> return_statement;
|
||||
%type <elna::boot::expression *> return_statement;
|
||||
%type <elna::boot::statement *> statement;
|
||||
%type <std::vector<elna::boot::statement *>> statements optional_statements;
|
||||
%type <std::vector<elna::boot::statement *>> statements statement_part;
|
||||
%type <elna::boot::procedure_definition *> procedure_definition;
|
||||
%type <std::shared_ptr<elna::boot::procedure_type>> procedure_heading;
|
||||
%type <std::vector<elna::boot::procedure_definition *>> procedure_definitions procedure_part;
|
||||
%type <std::vector<elna::boot::procedure_definition *>> procedure_definitions;
|
||||
%type <elna::boot::type_definition *> type_definition;
|
||||
%type <std::vector<elna::boot::type_definition *>> type_definitions type_part;
|
||||
%type <elna::boot::block *> block;
|
||||
@ -147,12 +146,11 @@ along with GCC; see the file COPYING3. If not see
|
||||
%type <std::vector<std::pair<std::string, std::shared_ptr<elna::boot::top_type>>>> optional_fields fields;
|
||||
%type <std::vector<elna::boot::conditional_statements *>> elsif_then_statements elsif_do_statements;
|
||||
%type <elna::boot::cast_expression *> cast_expression;
|
||||
%type <elna::boot::defer_statement *> defer_statement;
|
||||
%type <std::pair<std::string, bool>> identifier_definition;
|
||||
%type <std::vector<std::pair<std::string, bool>>> identifier_definitions;
|
||||
%%
|
||||
program:
|
||||
constant_part type_part variable_part procedure_part "begin" optional_statements "end" "."
|
||||
constant_part type_part variable_part procedure_definitions "begin" statements "end" "."
|
||||
{
|
||||
auto tree = new elna::boot::program(elna::boot::make_position(@5));
|
||||
|
||||
@ -164,13 +162,13 @@ program:
|
||||
|
||||
driver.tree.reset(tree);
|
||||
}
|
||||
block: constant_part variable_part "begin" optional_statements "end"
|
||||
block: constant_part variable_part statement_part
|
||||
{
|
||||
$$ = new elna::boot::block(elna::boot::make_position(@3));
|
||||
$$ = new elna::boot::block(elna::boot::make_position(@1));
|
||||
|
||||
std::swap($$->constants, $1);
|
||||
std::swap($$->variables, $2);
|
||||
std::swap($$->body, $4);
|
||||
std::swap($$->body, $3);
|
||||
}
|
||||
identifier_definition:
|
||||
IDENTIFIER "*"
|
||||
@ -205,9 +203,10 @@ procedure_heading:
|
||||
std::swap($1, $$->parameters);
|
||||
}
|
||||
procedure_definition:
|
||||
"proc" identifier_definition procedure_heading ";" block
|
||||
"proc" identifier_definition procedure_heading ";" block return_statement "end"
|
||||
{
|
||||
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1), $2.first, $2.second, $3, $5);
|
||||
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1), $2.first, $2.second,
|
||||
$3, $5, $6);
|
||||
}
|
||||
| "proc" identifier_definition procedure_heading ";" "extern"
|
||||
{
|
||||
@ -219,10 +218,7 @@ procedure_definitions:
|
||||
std::swap($$, $2);
|
||||
$$.emplace($$.cbegin(), std::move($1));
|
||||
}
|
||||
| procedure_definition { $$.emplace_back(std::move($1)); }
|
||||
procedure_part:
|
||||
/* no procedure definitions */ {}
|
||||
| procedure_definitions { std::swap($$, $1); }
|
||||
| /* no procedure definitions */ {}
|
||||
assign_statement: designator_expression ":=" expression
|
||||
{
|
||||
$$ = new elna::boot::assign_statement(elna::boot::make_position(@1), $1, $3);
|
||||
@ -237,7 +233,7 @@ cast_expression: "cast" "(" expression ":" type_expression ")"
|
||||
$$ = new elna::boot::cast_expression(elna::boot::make_position(@1), $5, $3);
|
||||
}
|
||||
elsif_do_statements:
|
||||
"elsif" expression "do" optional_statements elsif_do_statements
|
||||
"elsif" expression "do" statements elsif_do_statements
|
||||
{
|
||||
elna::boot::conditional_statements *branch = new elna::boot::conditional_statements($2);
|
||||
std::swap(branch->statements, $4);
|
||||
@ -245,7 +241,7 @@ elsif_do_statements:
|
||||
$$.emplace($$.begin(), branch);
|
||||
}
|
||||
| {}
|
||||
while_statement: "while" expression "do" optional_statements elsif_do_statements "end"
|
||||
while_statement: "while" expression "do" statements elsif_do_statements "end"
|
||||
{
|
||||
auto body = new elna::boot::conditional_statements($2);
|
||||
std::swap($4, body->statements);
|
||||
@ -253,7 +249,7 @@ while_statement: "while" expression "do" optional_statements elsif_do_statements
|
||||
std::swap($5, $$->branches);
|
||||
}
|
||||
elsif_then_statements:
|
||||
"elsif" expression "then" optional_statements elsif_then_statements
|
||||
"elsif" expression "then" statements elsif_then_statements
|
||||
{
|
||||
elna::boot::conditional_statements *branch = new elna::boot::conditional_statements($2);
|
||||
std::swap(branch->statements, $4);
|
||||
@ -262,14 +258,14 @@ elsif_then_statements:
|
||||
}
|
||||
| {}
|
||||
if_statement:
|
||||
"if" expression "then" optional_statements elsif_then_statements "end"
|
||||
"if" expression "then" statements elsif_then_statements "end"
|
||||
{
|
||||
auto then = new elna::boot::conditional_statements($2);
|
||||
std::swap($4, then->statements);
|
||||
$$ = new elna::boot::if_statement(elna::boot::make_position(@1), then);
|
||||
std::swap($5, $$->branches);
|
||||
}
|
||||
| "if" expression "then" optional_statements elsif_then_statements "else" optional_statements "end"
|
||||
| "if" expression "then" statements elsif_then_statements "else" statements "end"
|
||||
{
|
||||
auto then = new elna::boot::conditional_statements($2);
|
||||
std::swap($4, then->statements);
|
||||
@ -277,15 +273,12 @@ if_statement:
|
||||
$$ = new elna::boot::if_statement(elna::boot::make_position(@1), then, _else);
|
||||
std::swap($5, $$->branches);
|
||||
}
|
||||
return_statement: "return" expression
|
||||
return_statement:
|
||||
"return" expression
|
||||
{
|
||||
$$ = new elna::boot::return_statement(elna::boot::make_position(@1), $2);
|
||||
}
|
||||
defer_statement: DEFER optional_statements "end"
|
||||
{
|
||||
$$ = new elna::boot::defer_statement(elna::boot::make_position(@1));
|
||||
std::swap($2, $$->statements);
|
||||
$$ = $2;
|
||||
}
|
||||
| /* no return statement */ { $$ = nullptr; }
|
||||
literal:
|
||||
INTEGER
|
||||
{
|
||||
@ -454,19 +447,17 @@ statement:
|
||||
assign_statement { $$ = $1; }
|
||||
| while_statement { $$ = $1; }
|
||||
| if_statement { $$ = $1; }
|
||||
| return_statement { $$ = $1; }
|
||||
| call_expression { $$ = $1; }
|
||||
| defer_statement { $$ = $1; }
|
||||
statements:
|
||||
statement statements
|
||||
{
|
||||
std::swap($$, $2);
|
||||
$$.emplace($$.cbegin(), $1);
|
||||
}
|
||||
| statement { $$.push_back($1); }
|
||||
optional_statements:
|
||||
statements { std::swap($$, $1); }
|
||||
| /* no statements */ {}
|
||||
statement_part:
|
||||
"begin" statements { std::swap($$, $2); }
|
||||
| {}
|
||||
field_declaration:
|
||||
IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); }
|
||||
fields:
|
||||
|
@ -294,6 +294,7 @@ namespace gcc
|
||||
if (definition->body != nullptr)
|
||||
{
|
||||
definition->body->accept(this);
|
||||
visit_return(definition->returning);
|
||||
tree mapping = leave_scope();
|
||||
|
||||
BLOCK_SUPERCONTEXT(BIND_EXPR_BLOCK(mapping)) = fndecl;
|
||||
@ -334,7 +335,7 @@ namespace gcc
|
||||
{
|
||||
BLOCK_SUPERCONTEXT(it) = new_block;
|
||||
}
|
||||
tree bind_expr = build3(BIND_EXPR, void_type_node, variables, chain_defer(), new_block);
|
||||
tree bind_expr = build3(BIND_EXPR, void_type_node, variables, f_binding_level->statement_list, new_block);
|
||||
this->symbol_map = this->symbol_map->scope();
|
||||
|
||||
f_binding_level = f_binding_level->level_chain;
|
||||
@ -1174,10 +1175,8 @@ namespace gcc
|
||||
}
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::return_statement *statement)
|
||||
void generic_visitor::visit_return(boot::expression *const return_expression)
|
||||
{
|
||||
boot::expression *return_expression = statement->return_expression();
|
||||
|
||||
if (return_expression == nullptr)
|
||||
{
|
||||
return;
|
||||
@ -1191,12 +1190,5 @@ namespace gcc
|
||||
|
||||
this->current_expression = NULL_TREE;
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::defer_statement *statement)
|
||||
{
|
||||
enter_scope();
|
||||
visit_statements(statement->statements);
|
||||
defer(leave_scope());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -91,40 +91,7 @@ namespace gcc
|
||||
|
||||
void append_statement(tree statement_tree)
|
||||
{
|
||||
if (!vec_safe_is_empty(f_binding_level->defers))
|
||||
{
|
||||
append_to_statement_list(statement_tree, &f_binding_level->defers->begin()->try_statements);
|
||||
}
|
||||
else
|
||||
{
|
||||
append_to_statement_list(statement_tree, &f_binding_level->statement_list);
|
||||
}
|
||||
}
|
||||
|
||||
void defer(tree statement_tree)
|
||||
{
|
||||
defer_scope new_defer{ statement_tree, alloc_stmt_list() };
|
||||
vec_safe_insert(f_binding_level->defers, 0, new_defer);
|
||||
}
|
||||
|
||||
tree chain_defer()
|
||||
{
|
||||
if (vec_safe_is_empty(f_binding_level->defers))
|
||||
{
|
||||
return f_binding_level->statement_list;
|
||||
}
|
||||
defer_scope *defer_iterator = f_binding_level->defers->begin();
|
||||
tree defer_tree = build2(TRY_FINALLY_EXPR, void_type_node,
|
||||
defer_iterator->try_statements, defer_iterator->defer_block);
|
||||
int i;
|
||||
|
||||
FOR_EACH_VEC_ELT_FROM(*f_binding_level->defers, i, defer_iterator, 1)
|
||||
{
|
||||
append_to_statement_list(defer_tree, &defer_iterator->try_statements);
|
||||
defer_tree = build2(TRY_FINALLY_EXPR, void_type_node,
|
||||
defer_iterator->try_statements, defer_iterator->defer_block);
|
||||
}
|
||||
return build2(COMPOUND_EXPR, TREE_TYPE(defer_tree), f_binding_level->statement_list, defer_tree);
|
||||
append_to_statement_list(statement_tree, &f_binding_level->statement_list);
|
||||
}
|
||||
|
||||
tree build_field(location_t location, tree record_type, const std::string name, tree type)
|
||||
|
@ -63,7 +63,6 @@ namespace boot
|
||||
class assign_statement;
|
||||
class if_statement;
|
||||
class while_statement;
|
||||
class return_statement;
|
||||
class traits_expression;
|
||||
class block;
|
||||
class program;
|
||||
@ -81,7 +80,6 @@ namespace boot
|
||||
class dereference_expression;
|
||||
template<typename T>
|
||||
class number_literal;
|
||||
class defer_statement;
|
||||
|
||||
/**
|
||||
* Interface for AST visitors.
|
||||
@ -98,8 +96,6 @@ namespace boot
|
||||
virtual void visit(assign_statement *) = 0;
|
||||
virtual void visit(if_statement *) = 0;
|
||||
virtual void visit(while_statement *) = 0;
|
||||
virtual void visit(return_statement *) = 0;
|
||||
virtual void visit(defer_statement *) = 0;
|
||||
virtual void visit(block *) = 0;
|
||||
virtual void visit(program *) = 0;
|
||||
virtual void visit(binary_expression *) = 0;
|
||||
@ -138,8 +134,6 @@ namespace boot
|
||||
virtual void visit(assign_statement *statement) override;
|
||||
virtual void visit(if_statement *) override;
|
||||
virtual void visit(while_statement *) override;
|
||||
virtual void visit(return_statement *) override;
|
||||
virtual void visit(defer_statement *defer) override;
|
||||
virtual void visit(block *block) override;
|
||||
virtual void visit(program *program) override;
|
||||
virtual void visit(binary_expression *expression) override;
|
||||
@ -383,9 +377,11 @@ namespace boot
|
||||
|
||||
public:
|
||||
block *const body;
|
||||
expression *const returning;
|
||||
|
||||
procedure_definition(const struct position position, const std::string& identifier,
|
||||
const bool exported, std::shared_ptr<procedure_type> heading, block *body = nullptr);
|
||||
const bool exported, std::shared_ptr<procedure_type> heading,
|
||||
block *const body = nullptr, expression *const returning = nullptr);
|
||||
virtual void accept(parser_visitor *visitor) override;
|
||||
|
||||
procedure_type& heading();
|
||||
@ -456,19 +452,6 @@ namespace boot
|
||||
virtual ~conditional_statements();
|
||||
};
|
||||
|
||||
class return_statement : public statement
|
||||
{
|
||||
expression *m_return_expression{ nullptr };
|
||||
|
||||
public:
|
||||
return_statement(const struct position position, expression *return_expression);
|
||||
virtual void accept(parser_visitor *visitor) override;
|
||||
|
||||
expression *return_expression();
|
||||
|
||||
virtual ~return_statement() override;
|
||||
};
|
||||
|
||||
class designator_expression : public expression
|
||||
{
|
||||
public:
|
||||
@ -661,17 +644,6 @@ namespace boot
|
||||
}
|
||||
};
|
||||
|
||||
class defer_statement : public statement
|
||||
{
|
||||
public:
|
||||
std::vector<statement *> statements;
|
||||
|
||||
defer_statement(const struct position position);
|
||||
virtual void accept(parser_visitor *visitor) override;
|
||||
|
||||
virtual ~defer_statement() override;
|
||||
};
|
||||
|
||||
class binary_expression : public expression
|
||||
{
|
||||
expression *m_lhs;
|
||||
|
@ -61,6 +61,7 @@ namespace gcc
|
||||
void build_record_call(location_t call_location,
|
||||
tree symbol, const std::vector<boot::expression *>& arguments);
|
||||
void visit_statements(const std::vector<boot::statement *>& statements);
|
||||
void visit_return(boot::expression *const return_expression);
|
||||
|
||||
public:
|
||||
generic_visitor(std::shared_ptr<symbol_table> symbol_table);
|
||||
@ -90,8 +91,6 @@ namespace gcc
|
||||
void visit(boot::assign_statement *statement) override;
|
||||
void visit(boot::if_statement *statement) override;
|
||||
void visit(boot::while_statement *statement) override;
|
||||
void visit(boot::return_statement *statement) override;
|
||||
void visit(boot::defer_statement *statement) override;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -72,8 +72,6 @@ namespace gcc
|
||||
bool is_assignable_from(tree assignee, tree assignment);
|
||||
|
||||
void append_statement(tree statement_tree);
|
||||
void defer(tree statement_tree);
|
||||
tree chain_defer();
|
||||
|
||||
tree do_pointer_arithmetic(boot::binary_operator binary_operator, tree left, tree right);
|
||||
tree build_binary_operation(bool condition, boot::binary_expression *expression,
|
||||
|
@ -58,12 +58,6 @@ struct GTY (()) lang_decl
|
||||
{
|
||||
};
|
||||
|
||||
struct GTY (()) defer_scope
|
||||
{
|
||||
tree defer_block;
|
||||
tree try_statements;
|
||||
};
|
||||
|
||||
struct GTY ((chain_next ("%h.level_chain"))) binding_level
|
||||
{
|
||||
// A block chain is needed to call defer statements beloning to each block.
|
||||
@ -74,9 +68,6 @@ struct GTY ((chain_next ("%h.level_chain"))) binding_level
|
||||
|
||||
// Statements before the first defer has been seen.
|
||||
tree statement_list;
|
||||
|
||||
// Defer statement coupled with statements following it.
|
||||
vec<defer_scope, va_gc> *defers;
|
||||
};
|
||||
|
||||
struct GTY (()) language_function
|
||||
|
20
source.elna
20
source.elna
@ -140,7 +140,6 @@ proc exit(code: Int) -> !; extern
|
||||
Standard procedures.
|
||||
*)
|
||||
proc reallocarray(ptr: ^Byte, n: Word, size: Word) -> ^Byte;
|
||||
begin
|
||||
return realloc(ptr, n * size)
|
||||
end
|
||||
|
||||
@ -198,32 +197,26 @@ begin
|
||||
end
|
||||
|
||||
proc is_digit(c: Char) -> Bool;
|
||||
begin
|
||||
return cast(c: Int) >= cast('0': Int) and cast(c: Int) <= cast('9': Int)
|
||||
end
|
||||
|
||||
proc is_alpha(c: Char) -> Bool;
|
||||
begin
|
||||
return cast(c: Int) >= cast('A': Int) and cast(c: Int) <= cast('z': Int)
|
||||
end
|
||||
|
||||
proc is_alnum(c: Char) -> Bool;
|
||||
begin
|
||||
return is_digit(c) or is_alpha(c)
|
||||
end
|
||||
|
||||
proc is_space(c: Char) -> Bool;
|
||||
begin
|
||||
return c = ' ' or c = '\n' or c = '\t'
|
||||
end
|
||||
|
||||
proc substring(string: String, start: Word, count: Word) -> String;
|
||||
begin
|
||||
return String(string.ptr + start, count)
|
||||
end
|
||||
|
||||
proc open_substring(string: String, start: Word) -> String;
|
||||
begin
|
||||
return substring(string, start, string.length - start)
|
||||
end
|
||||
|
||||
@ -277,7 +270,6 @@ end
|
||||
*)
|
||||
|
||||
proc make_position() -> Position;
|
||||
begin
|
||||
return Position(1u, 1u)
|
||||
end
|
||||
|
||||
@ -376,12 +368,10 @@ begin
|
||||
end
|
||||
|
||||
proc source_code_empty(source_code: ^SourceCode) -> Bool;
|
||||
begin
|
||||
return source_code^.empty(source_code^.input)
|
||||
end
|
||||
|
||||
proc source_code_head(source_code: SourceCode) -> Char;
|
||||
begin
|
||||
return source_code.head(source_code.input)
|
||||
end
|
||||
|
||||
@ -398,7 +388,6 @@ begin
|
||||
end
|
||||
|
||||
proc source_code_expect(source_code: ^SourceCode, expected: Char) -> Bool;
|
||||
begin
|
||||
return not source_code_empty(source_code) and source_code_head(source_code^) = expected
|
||||
end
|
||||
|
||||
@ -413,7 +402,6 @@ begin
|
||||
end
|
||||
|
||||
proc is_ident(char: Char) -> Bool;
|
||||
begin
|
||||
return is_alnum(char) or char = '_'
|
||||
end
|
||||
|
||||
@ -916,7 +904,7 @@ begin
|
||||
result^.syntax_tree := false
|
||||
result^.input := nil
|
||||
|
||||
while i < argc do
|
||||
while i < argc and result <> nil do
|
||||
parameter := argv + i
|
||||
|
||||
if strcmp(parameter^, "--tokenize\0".ptr) = 0 then
|
||||
@ -932,14 +920,14 @@ begin
|
||||
write_z(parameter^)
|
||||
write_s(".\n")
|
||||
|
||||
return nil
|
||||
result := nil
|
||||
end
|
||||
|
||||
i := i + 1
|
||||
end
|
||||
if result^.input = nil then
|
||||
if result <> nil and result^.input = nil then
|
||||
write_s("Fatal error: no input files.\n")
|
||||
return nil
|
||||
result := nil
|
||||
end
|
||||
|
||||
return result
|
||||
|
Loading…
x
Reference in New Issue
Block a user