Add lexer and parser sources
This commit is contained in:
77
Rakefile
77
Rakefile
@ -3,74 +3,39 @@
|
|||||||
# obtain one at https://mozilla.org/MPL/2.0/.
|
# obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
require 'pathname'
|
require 'pathname'
|
||||||
require 'open3'
|
|
||||||
require 'rake/clean'
|
require 'rake/clean'
|
||||||
require_relative 'tools/support'
|
|
||||||
|
|
||||||
# Dependencies.
|
TMP = Pathname.new('./build')
|
||||||
GCC_VERSION = "15.1.0"
|
|
||||||
|
|
||||||
# Paths.
|
|
||||||
HOST_GCC = TMP + 'host/gcc'
|
|
||||||
HOST_INSTALL = TMP + 'host/install'
|
HOST_INSTALL = TMP + 'host/install'
|
||||||
|
|
||||||
CLOBBER.include TMP
|
CLOBBER.include TMP
|
||||||
|
CLEAN.include(TMP + 'boot')
|
||||||
|
|
||||||
directory(TMP + 'tools')
|
|
||||||
directory HOST_GCC
|
|
||||||
directory HOST_INSTALL
|
directory HOST_INSTALL
|
||||||
|
|
||||||
task default: [TMP + 'elna'] do
|
task default: ['source/main.elna', TMP + 'boot/elna'] do |t|
|
||||||
sh (TMP + 'elna').to_path, '--parse', 'source.elna'
|
sources, compiler = t.prerequisites.partition { |f| f.end_with? '.elna' }
|
||||||
|
|
||||||
|
sh *compiler, '--parse', *sources
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace :boot do
|
rule(/boot\/.+\.o$/ => ->(file) {
|
||||||
desc 'Download and configure the bootstrap compiler'
|
Pathname.new('source') +
|
||||||
task configure: [TMP + 'tools', HOST_GCC, HOST_INSTALL] do
|
Pathname.new(file).relative_path_from(TMP + 'boot').sub_ext('.elna')
|
||||||
url = URI.parse "https://gcc.gnu.org/pub/gcc/releases/gcc-#{GCC_VERSION}/gcc-#{GCC_VERSION}.tar.xz"
|
}) do |t|
|
||||||
options = find_build_target GCC_VERSION
|
Pathname.new(t.name).dirname.mkpath
|
||||||
source_directory = TMP + "tools/gcc-#{GCC_VERSION}"
|
compiler = HOST_INSTALL + 'bin/gelna'
|
||||||
frontend_link = source_directory + 'gcc'
|
|
||||||
|
|
||||||
download_and_pipe url, source_directory.dirname, ['tar', '-Jxv']
|
sh compiler.to_path, '-c', '-o', t.name, *t.prerequisites
|
||||||
|
|
||||||
sh 'contrib/download_prerequisites', chdir: source_directory.to_path
|
|
||||||
File.symlink Pathname.new('.').relative_path_from(frontend_link), (frontend_link + 'elna')
|
|
||||||
|
|
||||||
configure_options = [
|
|
||||||
"--prefix=#{HOST_INSTALL.realpath}",
|
|
||||||
"--with-sysroot=#{options.sysroot.realpath}",
|
|
||||||
'--enable-languages=c,c++,elna',
|
|
||||||
'--disable-bootstrap',
|
|
||||||
'--disable-multilib',
|
|
||||||
"--target=#{options.build}",
|
|
||||||
"--build=#{options.build}",
|
|
||||||
"--host=#{options.build}"
|
|
||||||
]
|
|
||||||
flags = '-O0 -g -fPIC -I/opt/homebrew/Cellar/flex/2.6.4_2/include'
|
|
||||||
env = {
|
|
||||||
'CC' => options.gcc,
|
|
||||||
'CXX' => options.gxx,
|
|
||||||
'CFLAGS' => flags,
|
|
||||||
'CXXFLAGS' => flags,
|
|
||||||
}
|
|
||||||
configure = source_directory.relative_path_from(HOST_GCC) + 'configure'
|
|
||||||
sh env, configure.to_path, *configure_options, chdir: HOST_GCC.to_path
|
|
||||||
end
|
|
||||||
|
|
||||||
desc 'Make and install the bootstrap compiler'
|
|
||||||
task :make do
|
|
||||||
cwd = HOST_GCC.to_path
|
|
||||||
|
|
||||||
sh 'make', '-j', Etc.nprocessors.to_s, chdir: cwd
|
|
||||||
sh 'make', 'install', chdir: cwd
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
desc 'Build the bootstrap compiler'
|
file TMP + 'boot/elna' => FileList['source/**/*.elna'].reject { |file|
|
||||||
task boot: %w[boot:configure boot:make]
|
file != file.downcase
|
||||||
|
}.map { |file|
|
||||||
|
TMP + 'boot' +
|
||||||
|
Pathname.new(file).relative_path_from('source').sub_ext('.o')
|
||||||
|
} do |t|
|
||||||
|
compiler = HOST_INSTALL + 'bin/gcc'
|
||||||
|
|
||||||
file (TMP + 'elna').to_path => ['source.elna']
|
sh compiler.to_path, '-o', t.name, *t.prerequisites
|
||||||
file (TMP + 'elna').to_path => [(HOST_INSTALL + 'bin/gelna').to_path] do |task|
|
|
||||||
sh (HOST_INSTALL + 'bin/gelna').to_path, '-o', task.name, task.prerequisites.first
|
|
||||||
end
|
end
|
||||||
|
50
boot/ast.cc
50
boot/ast.cc
@ -225,7 +225,7 @@ namespace elna::boot
|
|||||||
|
|
||||||
variable_declaration::variable_declaration(const struct position position, identifier_definition identifier,
|
variable_declaration::variable_declaration(const struct position position, identifier_definition identifier,
|
||||||
std::shared_ptr<type_expression> variable_type)
|
std::shared_ptr<type_expression> variable_type)
|
||||||
: definition(position, identifier), m_variable_type(variable_type)
|
: declaration(position, identifier), m_variable_type(variable_type)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,28 +239,28 @@ namespace elna::boot
|
|||||||
return *m_variable_type;
|
return *m_variable_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
definition::definition(const struct position position, identifier_definition identifier)
|
declaration::declaration(const struct position position, identifier_definition identifier)
|
||||||
: node(position), identifier(identifier)
|
: node(position), identifier(identifier)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
constant_definition::constant_definition(const struct position position, identifier_definition identifier,
|
constant_declaration::constant_declaration(const struct position position, identifier_definition identifier,
|
||||||
expression *body)
|
expression *body)
|
||||||
: definition(position, identifier), m_body(body)
|
: declaration(position, identifier), m_body(body)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void constant_definition::accept(parser_visitor *visitor)
|
void constant_declaration::accept(parser_visitor *visitor)
|
||||||
{
|
{
|
||||||
visitor->visit(this);
|
visitor->visit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
expression& constant_definition::body()
|
expression& constant_declaration::body()
|
||||||
{
|
{
|
||||||
return *m_body;
|
return *m_body;
|
||||||
}
|
}
|
||||||
|
|
||||||
constant_definition::~constant_definition()
|
constant_declaration::~constant_declaration()
|
||||||
{
|
{
|
||||||
delete m_body;
|
delete m_body;
|
||||||
}
|
}
|
||||||
@ -307,55 +307,55 @@ namespace elna::boot
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
procedure_definition::procedure_definition(const struct position position, identifier_definition identifier,
|
procedure_declaration::procedure_declaration(const struct position position, identifier_definition identifier,
|
||||||
procedure_type_expression *heading, block&& body)
|
procedure_type_expression *heading, block&& body)
|
||||||
: definition(position, identifier), m_heading(heading), body(std::move(body))
|
: declaration(position, identifier), m_heading(heading), body(std::move(body))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
procedure_definition::procedure_definition(const struct position position, identifier_definition identifier,
|
procedure_declaration::procedure_declaration(const struct position position, identifier_definition identifier,
|
||||||
procedure_type_expression *heading)
|
procedure_type_expression *heading)
|
||||||
: definition(position, identifier), m_heading(heading), body(std::nullopt)
|
: declaration(position, identifier), m_heading(heading), body(std::nullopt)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void procedure_definition::accept(parser_visitor *visitor)
|
void procedure_declaration::accept(parser_visitor *visitor)
|
||||||
{
|
{
|
||||||
visitor->visit(this);
|
visitor->visit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
procedure_type_expression& procedure_definition::heading()
|
procedure_type_expression& procedure_declaration::heading()
|
||||||
{
|
{
|
||||||
return *m_heading;
|
return *m_heading;
|
||||||
}
|
}
|
||||||
|
|
||||||
procedure_definition::~procedure_definition()
|
procedure_declaration::~procedure_declaration()
|
||||||
{
|
{
|
||||||
delete m_heading;
|
delete m_heading;
|
||||||
}
|
}
|
||||||
|
|
||||||
type_definition::type_definition(const struct position position, identifier_definition identifier,
|
type_declaration::type_declaration(const struct position position, identifier_definition identifier,
|
||||||
type_expression *body)
|
type_expression *body)
|
||||||
: definition(position, identifier), m_body(body)
|
: declaration(position, identifier), m_body(body)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
type_definition::~type_definition()
|
type_declaration::~type_declaration()
|
||||||
{
|
{
|
||||||
delete m_body;
|
delete m_body;
|
||||||
}
|
}
|
||||||
|
|
||||||
void type_definition::accept(parser_visitor *visitor)
|
void type_declaration::accept(parser_visitor *visitor)
|
||||||
{
|
{
|
||||||
visitor->visit(this);
|
visitor->visit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_expression& type_definition::body()
|
type_expression& type_declaration::body()
|
||||||
{
|
{
|
||||||
return *m_body;
|
return *m_body;
|
||||||
}
|
}
|
||||||
|
|
||||||
block::block(std::vector<constant_definition *>&& constants, std::vector<variable_declaration *>&& variables,
|
block::block(std::vector<constant_declaration *>&& constants, std::vector<variable_declaration *>&& variables,
|
||||||
std::vector<statement *>&& body)
|
std::vector<statement *>&& body)
|
||||||
: m_variables(std::move(variables)), m_constants(std::move(constants)), m_body(std::move(body))
|
: m_variables(std::move(variables)), m_constants(std::move(constants)), m_body(std::move(body))
|
||||||
{
|
{
|
||||||
@ -381,7 +381,7 @@ namespace elna::boot
|
|||||||
return m_variables;
|
return m_variables;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<constant_definition *>& block::constants()
|
const std::vector<constant_declaration *>& block::constants()
|
||||||
{
|
{
|
||||||
return m_constants;
|
return m_constants;
|
||||||
}
|
}
|
||||||
@ -401,7 +401,7 @@ namespace elna::boot
|
|||||||
{
|
{
|
||||||
delete variable;
|
delete variable;
|
||||||
}
|
}
|
||||||
for (constant_definition *constant : this->constants())
|
for (constant_declaration *constant : this->constants())
|
||||||
{
|
{
|
||||||
delete constant;
|
delete constant;
|
||||||
}
|
}
|
||||||
@ -419,7 +419,7 @@ namespace elna::boot
|
|||||||
|
|
||||||
unit::~unit()
|
unit::~unit()
|
||||||
{
|
{
|
||||||
for (procedure_definition *procedure : this->procedures)
|
for (procedure_declaration *procedure : this->procedures)
|
||||||
{
|
{
|
||||||
delete procedure;
|
delete procedure;
|
||||||
}
|
}
|
||||||
@ -427,11 +427,11 @@ namespace elna::boot
|
|||||||
{
|
{
|
||||||
delete variable;
|
delete variable;
|
||||||
}
|
}
|
||||||
for (type_definition *type : this->types)
|
for (type_declaration *type : this->types)
|
||||||
{
|
{
|
||||||
delete type;
|
delete type;
|
||||||
}
|
}
|
||||||
for (constant_definition *constant : this->constants)
|
for (constant_declaration *constant : this->constants)
|
||||||
{
|
{
|
||||||
delete constant;
|
delete constant;
|
||||||
}
|
}
|
||||||
|
@ -133,8 +133,8 @@ along with GCC; see the file COPYING3. If not see
|
|||||||
%type <std::vector<elna::boot::expression *>> case_labels;
|
%type <std::vector<elna::boot::expression *>> case_labels;
|
||||||
%type <elna::boot::switch_case> switch_case;
|
%type <elna::boot::switch_case> switch_case;
|
||||||
%type <std::vector<elna::boot::switch_case>> switch_cases;
|
%type <std::vector<elna::boot::switch_case>> switch_cases;
|
||||||
%type <elna::boot::constant_definition *> constant_definition;
|
%type <elna::boot::constant_declaration *> constant_declaration;
|
||||||
%type <std::vector<elna::boot::constant_definition *>> constant_part constant_definitions;
|
%type <std::vector<elna::boot::constant_declaration *>> constant_part constant_declarations;
|
||||||
%type <std::vector<elna::boot::variable_declaration *>> variable_declarations variable_part variable_declaration;
|
%type <std::vector<elna::boot::variable_declaration *>> variable_declarations variable_part variable_declaration;
|
||||||
%type <elna::boot::type_expression *> type_expression;
|
%type <elna::boot::type_expression *> type_expression;
|
||||||
%type <std::vector<elna::boot::type_expression *>> type_expressions;
|
%type <std::vector<elna::boot::type_expression *>> type_expressions;
|
||||||
@ -148,12 +148,12 @@ along with GCC; see the file COPYING3. If not see
|
|||||||
%type <elna::boot::return_statement *> return_statement;
|
%type <elna::boot::return_statement *> return_statement;
|
||||||
%type <elna::boot::statement *> statement;
|
%type <elna::boot::statement *> statement;
|
||||||
%type <std::vector<elna::boot::statement *>> required_statements optional_statements statement_part;
|
%type <std::vector<elna::boot::statement *>> required_statements optional_statements statement_part;
|
||||||
%type <elna::boot::procedure_definition *> procedure_definition;
|
%type <elna::boot::procedure_declaration *> procedure_declaration;
|
||||||
%type <std::pair<std::vector<std::string>, elna::boot::procedure_type_expression *>> procedure_heading;
|
%type <std::pair<std::vector<std::string>, elna::boot::procedure_type_expression *>> procedure_heading;
|
||||||
%type <elna::boot::procedure_type_expression::return_t> return_declaration;
|
%type <elna::boot::procedure_type_expression::return_t> return_declaration;
|
||||||
%type <std::vector<elna::boot::procedure_definition *>> procedure_definitions procedure_part;
|
%type <std::vector<elna::boot::procedure_declaration *>> procedure_declarations procedure_part;
|
||||||
%type <elna::boot::type_definition *> type_definition;
|
%type <elna::boot::type_declaration *> type_declaration;
|
||||||
%type <std::vector<elna::boot::type_definition *>> type_definitions type_part;
|
%type <std::vector<elna::boot::type_declaration *>> type_declarations type_part;
|
||||||
%type <std::unique_ptr<elna::boot::block>> block;
|
%type <std::unique_ptr<elna::boot::block>> block;
|
||||||
%type <elna::boot::field_declaration> field_declaration formal_parameter;
|
%type <elna::boot::field_declaration> field_declaration formal_parameter;
|
||||||
%type <std::vector<std::pair<std::string, elna::boot::type_expression *>>>
|
%type <std::vector<std::pair<std::string, elna::boot::type_expression *>>>
|
||||||
@ -167,28 +167,28 @@ along with GCC; see the file COPYING3. If not see
|
|||||||
%type <std::vector<elna::boot::import_declaration *>> import_declarations import_part;
|
%type <std::vector<elna::boot::import_declaration *>> import_declarations import_part;
|
||||||
%%
|
%%
|
||||||
program:
|
program:
|
||||||
"program" import_part constant_part type_part variable_part procedure_part "begin" optional_statements "end" "."
|
"program" ";" import_part constant_part type_part variable_part procedure_part statement_part "end" "."
|
||||||
{
|
{
|
||||||
auto tree = new boot::program(boot::make_position(@7));
|
auto tree = new boot::program(boot::make_position(@1));
|
||||||
|
|
||||||
std::swap(tree->imports, $2);
|
std::swap(tree->imports, $3);
|
||||||
std::swap(tree->constants, $3);
|
std::swap(tree->constants, $4);
|
||||||
std::swap(tree->types , $4);
|
std::swap(tree->types , $5);
|
||||||
std::swap(tree->variables, $5);
|
std::swap(tree->variables, $6);
|
||||||
std::swap(tree->procedures, $6);
|
std::swap(tree->procedures, $7);
|
||||||
std::swap(tree->body, $8);
|
std::swap(tree->body, $8);
|
||||||
|
|
||||||
driver.tree.reset(tree);
|
driver.tree.reset(tree);
|
||||||
}
|
}
|
||||||
| "module" import_part constant_part type_part variable_part procedure_part "end" "."
|
| "module" ";" import_part constant_part type_part variable_part procedure_part "end" "."
|
||||||
{
|
{
|
||||||
auto tree = new boot::program(boot::make_position(@7));
|
auto tree = new boot::program(boot::make_position(@1));
|
||||||
|
|
||||||
std::swap(tree->imports, $2);
|
std::swap(tree->imports, $3);
|
||||||
std::swap(tree->constants, $3);
|
std::swap(tree->constants, $4);
|
||||||
std::swap(tree->types , $4);
|
std::swap(tree->types , $5);
|
||||||
std::swap(tree->variables, $5);
|
std::swap(tree->variables, $6);
|
||||||
std::swap(tree->procedures, $6);
|
std::swap(tree->procedures, $7);
|
||||||
|
|
||||||
driver.tree.reset(tree);
|
driver.tree.reset(tree);
|
||||||
}
|
}
|
||||||
@ -228,27 +228,27 @@ procedure_heading: formal_parameter_list return_declaration
|
|||||||
$$.second->parameters.push_back(type);
|
$$.second->parameters.push_back(type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
procedure_definition:
|
procedure_declaration:
|
||||||
"proc" identifier_definition procedure_heading ";" block
|
"proc" identifier_definition procedure_heading ";" block ";"
|
||||||
{
|
{
|
||||||
$$ = new boot::procedure_definition(boot::make_position(@1), std::move($2), $3.second, std::move(*$5));
|
$$ = new boot::procedure_declaration(boot::make_position(@1), std::move($2), $3.second, std::move(*$5));
|
||||||
std::swap($3.first, $$->parameter_names);
|
std::swap($3.first, $$->parameter_names);
|
||||||
}
|
}
|
||||||
| "proc" identifier_definition procedure_heading ";" "extern"
|
| "proc" identifier_definition procedure_heading ";" "extern" ";"
|
||||||
{
|
{
|
||||||
$$ = new boot::procedure_definition(boot::make_position(@1), std::move($2), $3.second);
|
$$ = new boot::procedure_declaration(boot::make_position(@1), std::move($2), $3.second);
|
||||||
std::swap($3.first, $$->parameter_names);
|
std::swap($3.first, $$->parameter_names);
|
||||||
}
|
}
|
||||||
procedure_definitions:
|
procedure_declarations:
|
||||||
procedure_definition procedure_definitions
|
procedure_declaration procedure_declarations
|
||||||
{
|
{
|
||||||
std::swap($$, $2);
|
std::swap($$, $2);
|
||||||
$$.emplace($$.cbegin(), std::move($1));
|
$$.emplace($$.cbegin(), std::move($1));
|
||||||
}
|
}
|
||||||
| procedure_definition { $$.emplace_back(std::move($1)); }
|
| procedure_declaration { $$.emplace_back(std::move($1)); }
|
||||||
procedure_part:
|
procedure_part:
|
||||||
/* no procedure definitions */ {}
|
/* no procedure definitions */ {}
|
||||||
| procedure_definitions { std::swap($$, $1); }
|
| procedure_declarations { std::swap($$, $1); }
|
||||||
call_expression: designator_expression actual_parameter_list
|
call_expression: designator_expression actual_parameter_list
|
||||||
{
|
{
|
||||||
$$ = new boot::procedure_call(boot::make_position(@1), $1);
|
$$ = new boot::procedure_call(boot::make_position(@1), $1);
|
||||||
@ -454,9 +454,9 @@ optional_statements:
|
|||||||
field_declaration:
|
field_declaration:
|
||||||
IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); }
|
IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); }
|
||||||
required_fields:
|
required_fields:
|
||||||
field_declaration required_fields
|
field_declaration ";" required_fields
|
||||||
{
|
{
|
||||||
std::swap($$, $2);
|
std::swap($$, $3);
|
||||||
$$.emplace($$.cbegin(), $1);
|
$$.emplace($$.cbegin(), $1);
|
||||||
}
|
}
|
||||||
| field_declaration { $$.emplace_back($1); }
|
| field_declaration { $$.emplace_back($1); }
|
||||||
@ -501,7 +501,7 @@ identifiers:
|
|||||||
$$.emplace($$.cbegin(), std::move($1));
|
$$.emplace($$.cbegin(), std::move($1));
|
||||||
}
|
}
|
||||||
| IDENTIFIER { $$.emplace_back(std::move($1)); }
|
| IDENTIFIER { $$.emplace_back(std::move($1)); }
|
||||||
variable_declaration: identifier_definitions ":" type_expression
|
variable_declaration: identifier_definitions ":" type_expression ";"
|
||||||
{
|
{
|
||||||
std::shared_ptr<boot::type_expression> shared_type{ $3 };
|
std::shared_ptr<boot::type_expression> shared_type{ $3 };
|
||||||
|
|
||||||
@ -523,12 +523,12 @@ variable_declarations:
|
|||||||
variable_part:
|
variable_part:
|
||||||
/* no variable declarations */ {}
|
/* no variable declarations */ {}
|
||||||
| "var" variable_declarations { std::swap($$, $2); }
|
| "var" variable_declarations { std::swap($$, $2); }
|
||||||
constant_definition: identifier_definition ":=" expression
|
constant_declaration: identifier_definition ":=" expression ";"
|
||||||
{
|
{
|
||||||
$$ = new boot::constant_definition(boot::make_position(@1), std::move($1), $3);
|
$$ = new boot::constant_declaration(boot::make_position(@1), std::move($1), $3);
|
||||||
}
|
}
|
||||||
constant_definitions:
|
constant_declarations:
|
||||||
constant_definition constant_definitions
|
constant_declaration constant_declarations
|
||||||
{
|
{
|
||||||
std::swap($$, $2);
|
std::swap($$, $2);
|
||||||
$$.insert($$.cbegin(), $1);
|
$$.insert($$.cbegin(), $1);
|
||||||
@ -536,7 +536,7 @@ constant_definitions:
|
|||||||
| /* no constant definitions */ {}
|
| /* no constant definitions */ {}
|
||||||
constant_part:
|
constant_part:
|
||||||
/* no constant definitions */ {}
|
/* no constant definitions */ {}
|
||||||
| "const" constant_definitions { std::swap($$, $2); }
|
| "const" constant_declarations { std::swap($$, $2); }
|
||||||
import_declaration:
|
import_declaration:
|
||||||
IDENTIFIER "." import_declaration
|
IDENTIFIER "." import_declaration
|
||||||
{
|
{
|
||||||
@ -545,8 +545,7 @@ import_declaration:
|
|||||||
}
|
}
|
||||||
| IDENTIFIER { $$.emplace_back(std::move($1)); }
|
| IDENTIFIER { $$.emplace_back(std::move($1)); }
|
||||||
import_declarations:
|
import_declarations:
|
||||||
/* no import declarations */ {}
|
import_declaration "," import_declarations
|
||||||
| import_declaration "," import_declarations
|
|
||||||
{
|
{
|
||||||
std::swap($$, $3);
|
std::swap($$, $3);
|
||||||
$$.emplace($$.cbegin(), new boot::import_declaration(boot::make_position(@1), std::move($1)));
|
$$.emplace($$.cbegin(), new boot::import_declaration(boot::make_position(@1), std::move($1)));
|
||||||
@ -557,13 +556,13 @@ import_declarations:
|
|||||||
}
|
}
|
||||||
import_part:
|
import_part:
|
||||||
/* no import declarations */ {}
|
/* no import declarations */ {}
|
||||||
| "import" import_declarations { std::swap($$, $2); }
|
| "import" import_declarations ";" { std::swap($$, $2); }
|
||||||
type_definition: identifier_definition "=" type_expression
|
type_declaration: identifier_definition "=" type_expression ";"
|
||||||
{
|
{
|
||||||
$$ = new boot::type_definition(boot::make_position(@1), std::move($1), $3);
|
$$ = new boot::type_declaration(boot::make_position(@1), std::move($1), $3);
|
||||||
}
|
}
|
||||||
type_definitions:
|
type_declarations:
|
||||||
type_definition type_definitions
|
type_declaration type_declarations
|
||||||
{
|
{
|
||||||
std::swap($$, $2);
|
std::swap($$, $2);
|
||||||
$$.insert($$.cbegin(), $1);
|
$$.insert($$.cbegin(), $1);
|
||||||
@ -571,7 +570,7 @@ type_definitions:
|
|||||||
| /* no type definitions */ {}
|
| /* no type definitions */ {}
|
||||||
type_part:
|
type_part:
|
||||||
/* no type definitions */ {}
|
/* no type definitions */ {}
|
||||||
| "type" type_definitions { std::swap($$, $2); }
|
| "type" type_declarations { std::swap($$, $2); }
|
||||||
formal_parameter:
|
formal_parameter:
|
||||||
IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); }
|
IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); }
|
||||||
formal_parameter_list:
|
formal_parameter_list:
|
||||||
|
@ -83,7 +83,7 @@ namespace elna::boot
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void declaration_visitor::visit(type_definition *definition)
|
void declaration_visitor::visit(type_declaration *definition)
|
||||||
{
|
{
|
||||||
definition->body().accept(this);
|
definition->body().accept(this);
|
||||||
auto unresolved_declaration = this->unresolved.at(definition->identifier.identifier);
|
auto unresolved_declaration = this->unresolved.at(definition->identifier.identifier);
|
||||||
@ -164,9 +164,12 @@ namespace elna::boot
|
|||||||
void declaration_visitor::visit(variable_declaration *declaration)
|
void declaration_visitor::visit(variable_declaration *declaration)
|
||||||
{
|
{
|
||||||
declaration->variable_type().accept(this);
|
declaration->variable_type().accept(this);
|
||||||
|
|
||||||
|
this->symbols->enter(declaration->identifier.identifier,
|
||||||
|
std::make_shared<variable_info>(this->current_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
void declaration_visitor::visit(constant_definition *definition)
|
void declaration_visitor::visit(constant_declaration *definition)
|
||||||
{
|
{
|
||||||
definition->body().accept(this);
|
definition->body().accept(this);
|
||||||
|
|
||||||
@ -174,7 +177,7 @@ namespace elna::boot
|
|||||||
std::make_shared<constant_info>(this->current_literal));
|
std::make_shared<constant_info>(this->current_literal));
|
||||||
}
|
}
|
||||||
|
|
||||||
void declaration_visitor::visit(procedure_definition *definition)
|
void declaration_visitor::visit(procedure_declaration *definition)
|
||||||
{
|
{
|
||||||
std::shared_ptr<procedure_info> info = std::make_shared<procedure_info>(
|
std::shared_ptr<procedure_info> info = std::make_shared<procedure_info>(
|
||||||
build_procedure(definition->heading()), definition->parameter_names);
|
build_procedure(definition->heading()), definition->parameter_names);
|
||||||
@ -184,7 +187,7 @@ namespace elna::boot
|
|||||||
|
|
||||||
if (definition->body.has_value())
|
if (definition->body.has_value())
|
||||||
{
|
{
|
||||||
for (constant_definition *const constant : definition->body.value().constants())
|
for (constant_declaration *const constant : definition->body.value().constants())
|
||||||
{
|
{
|
||||||
constant->accept(this);
|
constant->accept(this);
|
||||||
}
|
}
|
||||||
@ -293,7 +296,7 @@ namespace elna::boot
|
|||||||
|
|
||||||
void declaration_visitor::visit(unit *unit)
|
void declaration_visitor::visit(unit *unit)
|
||||||
{
|
{
|
||||||
for (type_definition *const type : unit->types)
|
for (type_declaration *const type : unit->types)
|
||||||
{
|
{
|
||||||
const std::string& type_identifier = type->identifier.identifier;
|
const std::string& type_identifier = type->identifier.identifier;
|
||||||
|
|
||||||
@ -303,7 +306,7 @@ namespace elna::boot
|
|||||||
add_error<already_declared_error>(type->identifier.identifier, this->input_file, type->position());
|
add_error<already_declared_error>(type->identifier.identifier, this->input_file, type->position());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (type_definition *const type : unit->types)
|
for (type_declaration *const type : unit->types)
|
||||||
{
|
{
|
||||||
type->accept(this);
|
type->accept(this);
|
||||||
}
|
}
|
||||||
@ -316,7 +319,7 @@ namespace elna::boot
|
|||||||
{
|
{
|
||||||
variable->accept(this);
|
variable->accept(this);
|
||||||
}
|
}
|
||||||
for (procedure_definition *const procedure : unit->procedures)
|
for (procedure_declaration *const procedure : unit->procedures)
|
||||||
{
|
{
|
||||||
procedure->accept(this);
|
procedure->accept(this);
|
||||||
}
|
}
|
||||||
|
@ -332,8 +332,8 @@ namespace elna::boot
|
|||||||
return std::static_pointer_cast<constant_info>(shared_from_this());
|
return std::static_pointer_cast<constant_info>(shared_from_this());
|
||||||
}
|
}
|
||||||
|
|
||||||
variable_info::variable_info(const std::string& name, const type symbol)
|
variable_info::variable_info(const type symbol)
|
||||||
: name(name), symbol(symbol)
|
: symbol(symbol)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,23 +99,25 @@ namespace elna::gcc
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::deque<std::unique_ptr<boot::error>> do_semantic_analysis(const char *path,
|
std::unordered_map<std::string, tree> do_semantic_analysis(std::shared_ptr<boot::symbol_table> info_table,
|
||||||
const std::unique_ptr<boot::program>& ast, std::shared_ptr<boot::symbol_table> info_table,
|
std::shared_ptr<symbol_table> symbols)
|
||||||
std::shared_ptr<symbol_table> symbols, std::unordered_map<std::string, tree>& unresolved)
|
|
||||||
{
|
{
|
||||||
boot::declaration_visitor declaration_visitor(path, info_table);
|
std::unordered_map<std::string, tree> unresolved;
|
||||||
|
|
||||||
declaration_visitor.visit(ast.get());
|
for (auto& [symbol_name, symbol_info] : *info_table)
|
||||||
|
|
||||||
if (declaration_visitor.errors().empty())
|
|
||||||
{
|
{
|
||||||
for (auto& [symbol_name, symbol_info] : declaration_visitor.unresolved)
|
std::vector<std::string> type_path;
|
||||||
|
|
||||||
|
// The top level symbol table has basic (builtin) types in it which are not aliases.
|
||||||
|
if (auto type_info = symbol_info->is_type())
|
||||||
{
|
{
|
||||||
std::vector<std::string> type_path;
|
if (auto alias_type = type_info->symbol.get<boot::alias_type>())
|
||||||
handle_symbol(symbol_name, symbol_info, symbols, unresolved, type_path);
|
{
|
||||||
|
handle_symbol(symbol_name, alias_type, symbols, unresolved, type_path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return std::move(declaration_visitor.errors());
|
return unresolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
generic_visitor::generic_visitor(std::shared_ptr<symbol_table> symbol_table,
|
generic_visitor::generic_visitor(std::shared_ptr<symbol_table> symbol_table,
|
||||||
@ -318,7 +320,7 @@ namespace elna::gcc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void generic_visitor::declare_procedure(boot::procedure_definition *const definition)
|
void generic_visitor::declare_procedure(boot::procedure_declaration *const definition)
|
||||||
{
|
{
|
||||||
tree declaration_type = build_procedure_type(definition->heading());
|
tree declaration_type = build_procedure_type(definition->heading());
|
||||||
tree fndecl = build_fn_decl(definition->identifier.identifier.c_str(), declaration_type);
|
tree fndecl = build_fn_decl(definition->identifier.identifier.c_str(), declaration_type);
|
||||||
@ -409,11 +411,11 @@ namespace elna::gcc
|
|||||||
{
|
{
|
||||||
declaration->accept(this);
|
declaration->accept(this);
|
||||||
}
|
}
|
||||||
for (boot::constant_definition *const constant : unit->constants)
|
for (boot::constant_declaration *const constant : unit->constants)
|
||||||
{
|
{
|
||||||
constant->accept(this);
|
constant->accept(this);
|
||||||
}
|
}
|
||||||
for (boot::type_definition *const type : unit->types)
|
for (boot::type_declaration *const type : unit->types)
|
||||||
{
|
{
|
||||||
type->accept(this);
|
type->accept(this);
|
||||||
}
|
}
|
||||||
@ -421,17 +423,17 @@ namespace elna::gcc
|
|||||||
{
|
{
|
||||||
variable->accept(this);
|
variable->accept(this);
|
||||||
}
|
}
|
||||||
for (boot::procedure_definition *const procedure : unit->procedures)
|
for (boot::procedure_declaration *const procedure : unit->procedures)
|
||||||
{
|
{
|
||||||
declare_procedure(procedure);
|
declare_procedure(procedure);
|
||||||
}
|
}
|
||||||
for (boot::procedure_definition *const procedure : unit->procedures)
|
for (boot::procedure_declaration *const procedure : unit->procedures)
|
||||||
{
|
{
|
||||||
procedure->accept(this);
|
procedure->accept(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void generic_visitor::visit(boot::procedure_definition *definition)
|
void generic_visitor::visit(boot::procedure_declaration *definition)
|
||||||
{
|
{
|
||||||
if (!definition->body.has_value())
|
if (!definition->body.has_value())
|
||||||
{
|
{
|
||||||
@ -449,7 +451,7 @@ namespace elna::gcc
|
|||||||
{
|
{
|
||||||
this->symbols->enter(IDENTIFIER_POINTER(DECL_NAME(argument_chain)), argument_chain);
|
this->symbols->enter(IDENTIFIER_POINTER(DECL_NAME(argument_chain)), argument_chain);
|
||||||
}
|
}
|
||||||
for (boot::constant_definition *const constant : definition->body.value().constants())
|
for (boot::constant_declaration *const constant : definition->body.value().constants())
|
||||||
{
|
{
|
||||||
constant->accept(this);
|
constant->accept(this);
|
||||||
}
|
}
|
||||||
@ -818,7 +820,7 @@ namespace elna::gcc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void generic_visitor::visit(boot::constant_definition *definition)
|
void generic_visitor::visit(boot::constant_declaration *definition)
|
||||||
{
|
{
|
||||||
location_t definition_location = get_location(&definition->position());
|
location_t definition_location = get_location(&definition->position());
|
||||||
definition->body().accept(this);
|
definition->body().accept(this);
|
||||||
@ -858,7 +860,7 @@ namespace elna::gcc
|
|||||||
this->current_expression = NULL_TREE;
|
this->current_expression = NULL_TREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void generic_visitor::visit(boot::type_definition *definition)
|
void generic_visitor::visit(boot::type_declaration *definition)
|
||||||
{
|
{
|
||||||
location_t definition_location = get_location(&definition->position());
|
location_t definition_location = get_location(&definition->position());
|
||||||
this->current_expression = this->unresolved.at(definition->identifier.identifier);
|
this->current_expression = this->unresolved.at(definition->identifier.identifier);
|
||||||
|
12
gcc/elna1.cc
12
gcc/elna1.cc
@ -84,19 +84,21 @@ static void elna_parse_file(const char *filename)
|
|||||||
{
|
{
|
||||||
for (const std::unique_ptr<elna::boot::program>& module_tree : outcome.modules)
|
for (const std::unique_ptr<elna::boot::program>& module_tree : outcome.modules)
|
||||||
{
|
{
|
||||||
std::unordered_map<std::string, tree> unresolved;
|
elna::boot::declaration_visitor declaration_visitor(filename, info_table);
|
||||||
|
|
||||||
auto semantic_errors = elna::gcc::do_semantic_analysis(filename, module_tree,
|
declaration_visitor.visit(module_tree.get());
|
||||||
info_table, symbol_table, unresolved);
|
|
||||||
|
|
||||||
if (semantic_errors.empty())
|
if (declaration_visitor.errors().empty())
|
||||||
{
|
{
|
||||||
|
std::unordered_map<std::string, tree> unresolved = elna::gcc::do_semantic_analysis(
|
||||||
|
info_table, symbol_table);
|
||||||
|
|
||||||
elna::gcc::generic_visitor generic_visitor{ symbol_table, std::move(unresolved) };
|
elna::gcc::generic_visitor generic_visitor{ symbol_table, std::move(unresolved) };
|
||||||
generic_visitor.visit(module_tree.get());
|
generic_visitor.visit(module_tree.get());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
elna::gcc::report_errors(semantic_errors);
|
elna::gcc::report_errors(declaration_visitor.errors());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,9 +54,9 @@ namespace elna::boot
|
|||||||
};
|
};
|
||||||
|
|
||||||
class variable_declaration;
|
class variable_declaration;
|
||||||
class constant_definition;
|
class constant_declaration;
|
||||||
class procedure_definition;
|
class procedure_declaration;
|
||||||
class type_definition;
|
class type_declaration;
|
||||||
class procedure_call;
|
class procedure_call;
|
||||||
class cast_expression;
|
class cast_expression;
|
||||||
class assign_statement;
|
class assign_statement;
|
||||||
@ -93,9 +93,9 @@ namespace elna::boot
|
|||||||
struct parser_visitor
|
struct parser_visitor
|
||||||
{
|
{
|
||||||
virtual void visit(variable_declaration *) = 0;
|
virtual void visit(variable_declaration *) = 0;
|
||||||
virtual void visit(constant_definition *) = 0;
|
virtual void visit(constant_declaration *) = 0;
|
||||||
virtual void visit(procedure_definition *) = 0;
|
virtual void visit(procedure_declaration *) = 0;
|
||||||
virtual void visit(type_definition *) = 0;
|
virtual void visit(type_declaration *) = 0;
|
||||||
virtual void visit(procedure_call *) = 0;
|
virtual void visit(procedure_call *) = 0;
|
||||||
virtual void visit(cast_expression *) = 0;
|
virtual void visit(cast_expression *) = 0;
|
||||||
virtual void visit(traits_expression *) = 0;
|
virtual void visit(traits_expression *) = 0;
|
||||||
@ -178,10 +178,10 @@ namespace elna::boot
|
|||||||
/**
|
/**
|
||||||
* Symbol definition.
|
* Symbol definition.
|
||||||
*/
|
*/
|
||||||
class definition : public node
|
class declaration : public node
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
definition(const struct position position, identifier_definition identifier);
|
declaration(const struct position position, identifier_definition identifier);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const identifier_definition identifier;
|
const identifier_definition identifier;
|
||||||
@ -292,7 +292,7 @@ namespace elna::boot
|
|||||||
/**
|
/**
|
||||||
* Variable declaration.
|
* Variable declaration.
|
||||||
*/
|
*/
|
||||||
class variable_declaration : public definition
|
class variable_declaration : public declaration
|
||||||
{
|
{
|
||||||
std::shared_ptr<type_expression> m_variable_type;
|
std::shared_ptr<type_expression> m_variable_type;
|
||||||
|
|
||||||
@ -320,18 +320,18 @@ namespace elna::boot
|
|||||||
/**
|
/**
|
||||||
* Constant definition.
|
* Constant definition.
|
||||||
*/
|
*/
|
||||||
class constant_definition : public definition
|
class constant_declaration : public declaration
|
||||||
{
|
{
|
||||||
expression *m_body;
|
expression *m_body;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constant_definition(const struct position position, identifier_definition identifier,
|
constant_declaration(const struct position position, identifier_definition identifier,
|
||||||
expression *body);
|
expression *body);
|
||||||
void accept(parser_visitor *visitor) override;
|
void accept(parser_visitor *visitor) override;
|
||||||
|
|
||||||
expression& body();
|
expression& body();
|
||||||
|
|
||||||
virtual ~constant_definition() override;
|
virtual ~constant_declaration() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -354,7 +354,7 @@ namespace elna::boot
|
|||||||
|
|
||||||
struct block
|
struct block
|
||||||
{
|
{
|
||||||
block(std::vector<constant_definition *>&& constants, std::vector<variable_declaration *>&& variables,
|
block(std::vector<constant_declaration*>&& constants, std::vector<variable_declaration *>&& variables,
|
||||||
std::vector<statement *>&& body);
|
std::vector<statement *>&& body);
|
||||||
block(const block&) = delete;
|
block(const block&) = delete;
|
||||||
block(block&& that);
|
block(block&& that);
|
||||||
@ -363,14 +363,14 @@ namespace elna::boot
|
|||||||
block& operator=(block&& that);
|
block& operator=(block&& that);
|
||||||
|
|
||||||
const std::vector<variable_declaration *>& variables();
|
const std::vector<variable_declaration *>& variables();
|
||||||
const std::vector<constant_definition *>& constants();
|
const std::vector<constant_declaration *>& constants();
|
||||||
const std::vector<statement *>& body();
|
const std::vector<statement *>& body();
|
||||||
|
|
||||||
virtual ~block();
|
virtual ~block();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<variable_declaration *> m_variables;
|
std::vector<variable_declaration *> m_variables;
|
||||||
std::vector<constant_definition *> m_constants;
|
std::vector<constant_declaration *> m_constants;
|
||||||
std::vector<statement *> m_body;
|
std::vector<statement *> m_body;
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -378,7 +378,7 @@ namespace elna::boot
|
|||||||
/**
|
/**
|
||||||
* Procedure definition.
|
* Procedure definition.
|
||||||
*/
|
*/
|
||||||
class procedure_definition : public definition
|
class procedure_declaration : public declaration
|
||||||
{
|
{
|
||||||
procedure_type_expression *m_heading;
|
procedure_type_expression *m_heading;
|
||||||
|
|
||||||
@ -386,28 +386,28 @@ namespace elna::boot
|
|||||||
std::optional<block> body;
|
std::optional<block> body;
|
||||||
std::vector<std::string> parameter_names;
|
std::vector<std::string> parameter_names;
|
||||||
|
|
||||||
procedure_definition(const struct position position, identifier_definition identifier,
|
procedure_declaration(const struct position position, identifier_definition identifier,
|
||||||
procedure_type_expression *heading, block&& body);
|
procedure_type_expression *heading, block&& body);
|
||||||
procedure_definition(const struct position position, identifier_definition identifier,
|
procedure_declaration(const struct position position, identifier_definition identifier,
|
||||||
procedure_type_expression *heading);
|
procedure_type_expression *heading);
|
||||||
void accept(parser_visitor *visitor) override;
|
void accept(parser_visitor *visitor) override;
|
||||||
|
|
||||||
procedure_type_expression& heading();
|
procedure_type_expression& heading();
|
||||||
|
|
||||||
virtual ~procedure_definition() override;
|
virtual ~procedure_declaration() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type definition.
|
* Type definition.
|
||||||
*/
|
*/
|
||||||
class type_definition : public definition
|
class type_declaration : public declaration
|
||||||
{
|
{
|
||||||
type_expression *m_body;
|
type_expression *m_body;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
type_definition(const struct position position, identifier_definition identifier,
|
type_declaration(const struct position position, identifier_definition identifier,
|
||||||
type_expression *expression);
|
type_expression *expression);
|
||||||
~type_definition();
|
~type_declaration();
|
||||||
|
|
||||||
void accept(parser_visitor *visitor) override;
|
void accept(parser_visitor *visitor) override;
|
||||||
|
|
||||||
@ -670,10 +670,10 @@ namespace elna::boot
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::vector<import_declaration *> imports;
|
std::vector<import_declaration *> imports;
|
||||||
std::vector<constant_definition *> constants;
|
std::vector<constant_declaration *> constants;
|
||||||
std::vector<type_definition *> types;
|
std::vector<type_declaration *> types;
|
||||||
std::vector<variable_declaration *> variables;
|
std::vector<variable_declaration *> variables;
|
||||||
std::vector<procedure_definition *> procedures;
|
std::vector<procedure_declaration *> procedures;
|
||||||
|
|
||||||
unit(const struct position position);
|
unit(const struct position position);
|
||||||
virtual void accept(parser_visitor *visitor) override;
|
virtual void accept(parser_visitor *visitor) override;
|
||||||
|
@ -54,27 +54,26 @@ namespace elna::boot
|
|||||||
constant_info::variant current_literal;
|
constant_info::variant current_literal;
|
||||||
|
|
||||||
std::shared_ptr<symbol_table> symbols;
|
std::shared_ptr<symbol_table> symbols;
|
||||||
|
std::unordered_map<std::string, std::shared_ptr<alias_type>> unresolved;
|
||||||
|
|
||||||
procedure_type build_procedure(procedure_type_expression& type_expression);
|
procedure_type build_procedure(procedure_type_expression& type_expression);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::unordered_map<std::string, std::shared_ptr<alias_type>> unresolved;
|
|
||||||
|
|
||||||
explicit declaration_visitor(const char *path, std::shared_ptr<symbol_table> symbols);
|
explicit declaration_visitor(const char *path, std::shared_ptr<symbol_table> symbols);
|
||||||
|
|
||||||
void visit(named_type_expression *type_expression) override;
|
void visit(named_type_expression *type_expression) override;
|
||||||
void visit(array_type_expression *type_expression) override;
|
void visit(array_type_expression *type_expression) override;
|
||||||
void visit(pointer_type_expression *type_expression) override;
|
void visit(pointer_type_expression *type_expression) override;
|
||||||
void visit(program *program) override;
|
void visit(program *program) override;
|
||||||
void visit(type_definition *definition) override;
|
void visit(type_declaration *definition) override;
|
||||||
void visit(record_type_expression *type_expression) override;
|
void visit(record_type_expression *type_expression) override;
|
||||||
void visit(union_type_expression *type_expression) override;
|
void visit(union_type_expression *type_expression) override;
|
||||||
void visit(procedure_type_expression *type_expression) override;
|
void visit(procedure_type_expression *type_expression) override;
|
||||||
void visit(enumeration_type_expression *type_expression) override;
|
void visit(enumeration_type_expression *type_expression) override;
|
||||||
|
|
||||||
void visit(variable_declaration *declaration) override;
|
void visit(variable_declaration *declaration) override;
|
||||||
void visit(constant_definition *definition) override;
|
void visit(constant_declaration *definition) override;
|
||||||
void visit(procedure_definition *definition) override;
|
void visit(procedure_declaration *definition) override;
|
||||||
void visit(assign_statement *statement) override;
|
void visit(assign_statement *statement) override;
|
||||||
void visit(if_statement *statement) override;
|
void visit(if_statement *statement) override;
|
||||||
void visit(import_declaration *) override;
|
void visit(import_declaration *) override;
|
||||||
|
@ -202,10 +202,9 @@ namespace elna::boot
|
|||||||
class variable_info : public info
|
class variable_info : public info
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const std::string name;
|
|
||||||
const type symbol;
|
const type symbol;
|
||||||
|
|
||||||
variable_info(const std::string& name, const type symbol);
|
variable_info(const type symbol);
|
||||||
std::shared_ptr<variable_info> is_variable() override;
|
std::shared_ptr<variable_info> is_variable() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -33,9 +33,8 @@ along with GCC; see the file COPYING3. If not see
|
|||||||
|
|
||||||
namespace elna::gcc
|
namespace elna::gcc
|
||||||
{
|
{
|
||||||
std::deque<std::unique_ptr<boot::error>> do_semantic_analysis(const char *path,
|
std::unordered_map<std::string, tree> do_semantic_analysis(std::shared_ptr<boot::symbol_table> info_table,
|
||||||
const std::unique_ptr<boot::program>& ast, std::shared_ptr<boot::symbol_table> info_table,
|
std::shared_ptr<symbol_table> symbols);
|
||||||
std::shared_ptr<symbol_table> symbols, std::unordered_map<std::string, tree>& unresolved);
|
|
||||||
tree handle_symbol(const std::string& symbol_name, std::shared_ptr<boot::alias_type> reference,
|
tree handle_symbol(const std::string& symbol_name, std::shared_ptr<boot::alias_type> reference,
|
||||||
std::shared_ptr<symbol_table> symbols, std::unordered_map<std::string, tree>& unresolved,
|
std::shared_ptr<symbol_table> symbols, std::unordered_map<std::string, tree>& unresolved,
|
||||||
std::vector<std::string>& path);
|
std::vector<std::string>& path);
|
||||||
@ -46,7 +45,7 @@ namespace elna::gcc
|
|||||||
std::shared_ptr<symbol_table> symbols;
|
std::shared_ptr<symbol_table> symbols;
|
||||||
std::unordered_map<std::string, tree> unresolved;
|
std::unordered_map<std::string, tree> unresolved;
|
||||||
|
|
||||||
void declare_procedure(boot::procedure_definition *const definition);
|
void declare_procedure(boot::procedure_declaration *const definition);
|
||||||
tree build_procedure_type(boot::procedure_type_expression& type);
|
tree build_procedure_type(boot::procedure_type_expression& type);
|
||||||
void build_composite_type(const std::vector<boot::field_declaration>& fields,
|
void build_composite_type(const std::vector<boot::field_declaration>& fields,
|
||||||
tree composite_type_node);
|
tree composite_type_node);
|
||||||
@ -79,7 +78,7 @@ namespace elna::gcc
|
|||||||
std::unordered_map<std::string, tree>&& unresolved);
|
std::unordered_map<std::string, tree>&& unresolved);
|
||||||
|
|
||||||
void visit(boot::program *program) override;
|
void visit(boot::program *program) override;
|
||||||
void visit(boot::procedure_definition *definition) override;
|
void visit(boot::procedure_declaration *definition) override;
|
||||||
void visit(boot::procedure_call *call) override;
|
void visit(boot::procedure_call *call) override;
|
||||||
void visit(boot::cast_expression *expression) override;
|
void visit(boot::cast_expression *expression) override;
|
||||||
void visit(boot::traits_expression *trait) override;
|
void visit(boot::traits_expression *trait) override;
|
||||||
@ -92,8 +91,8 @@ namespace elna::gcc
|
|||||||
void visit(boot::literal<std::string> *string) override;
|
void visit(boot::literal<std::string> *string) override;
|
||||||
void visit(boot::binary_expression *expression) override;
|
void visit(boot::binary_expression *expression) override;
|
||||||
void visit(boot::unary_expression *expression) override;
|
void visit(boot::unary_expression *expression) override;
|
||||||
void visit(boot::constant_definition *definition) override;
|
void visit(boot::constant_declaration *definition) override;
|
||||||
void visit(boot::type_definition *definition) override;
|
void visit(boot::type_declaration *definition) override;
|
||||||
void visit(boot::variable_declaration *declaration) override;
|
void visit(boot::variable_declaration *declaration) override;
|
||||||
void visit(boot::variable_expression *expression) override;
|
void visit(boot::variable_expression *expression) override;
|
||||||
void visit(boot::array_access_expression *expression) override;
|
void visit(boot::array_access_expression *expression) override;
|
||||||
|
107
rakelib/boot.rake
Normal file
107
rakelib/boot.rake
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||||
|
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||||
|
# obtain one at https://mozilla.org/MPL/2.0/. -}
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'uri'
|
||||||
|
require 'net/http'
|
||||||
|
require 'open3'
|
||||||
|
|
||||||
|
def gcc_verbose(gcc_binary)
|
||||||
|
read, write = IO.pipe
|
||||||
|
sh({'LANG' => 'C'}, gcc_binary, '--verbose', err: write)
|
||||||
|
write.close
|
||||||
|
output = read.read
|
||||||
|
read.close
|
||||||
|
output
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_build_target(gcc_version)
|
||||||
|
gcc_verbose('gcc')
|
||||||
|
.lines
|
||||||
|
.find { |line| line.start_with? 'Target: ' }
|
||||||
|
.split(' ')
|
||||||
|
.last
|
||||||
|
.strip
|
||||||
|
end
|
||||||
|
|
||||||
|
def download_and_pipe(url, target, command)
|
||||||
|
target.mkpath
|
||||||
|
|
||||||
|
Net::HTTP.start(url.host, url.port, use_ssl: url.scheme == 'https') do |http|
|
||||||
|
request = Net::HTTP::Get.new url.request_uri
|
||||||
|
|
||||||
|
http.request request do |response|
|
||||||
|
case response
|
||||||
|
when Net::HTTPRedirection
|
||||||
|
download_and_pipe URI.parse(response['location']), target, command
|
||||||
|
when Net::HTTPSuccess
|
||||||
|
Dir.chdir target.to_path do
|
||||||
|
Open3.popen2(*command) do |stdin, stdout, wait_thread|
|
||||||
|
Thread.new do
|
||||||
|
stdout.each { |line| puts line }
|
||||||
|
end
|
||||||
|
|
||||||
|
response.read_body do |chunk|
|
||||||
|
stdin.write chunk
|
||||||
|
end
|
||||||
|
stdin.close
|
||||||
|
|
||||||
|
wait_thread.value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
response.error!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
namespace :boot do
|
||||||
|
# Dependencies.
|
||||||
|
GCC_VERSION = "15.1.0"
|
||||||
|
HOST_GCC = TMP + 'host/gcc'
|
||||||
|
|
||||||
|
directory HOST_GCC
|
||||||
|
directory(TMP + 'tools')
|
||||||
|
|
||||||
|
desc 'Download and configure the bootstrap compiler'
|
||||||
|
task configure: [TMP + 'tools', HOST_GCC, HOST_INSTALL] do
|
||||||
|
url = URI.parse "https://gcc.gnu.org/pub/gcc/releases/gcc-#{GCC_VERSION}/gcc-#{GCC_VERSION}.tar.xz"
|
||||||
|
build_target = find_build_target GCC_VERSION
|
||||||
|
source_directory = TMP + "tools/gcc-#{GCC_VERSION}"
|
||||||
|
frontend_link = source_directory + 'gcc'
|
||||||
|
|
||||||
|
download_and_pipe url, source_directory.dirname, ['tar', '-Jxv']
|
||||||
|
|
||||||
|
sh 'contrib/download_prerequisites', chdir: source_directory.to_path
|
||||||
|
File.symlink Pathname.new('.').relative_path_from(frontend_link), (frontend_link + 'elna')
|
||||||
|
|
||||||
|
configure_options = [
|
||||||
|
"--prefix=#{HOST_INSTALL.realpath}",
|
||||||
|
'--with-sysroot=/',
|
||||||
|
'--enable-languages=c,c++,m2,elna',
|
||||||
|
'--disable-bootstrap',
|
||||||
|
'--disable-multilib',
|
||||||
|
"--target=#{build_target}",
|
||||||
|
"--build=#{build_target}",
|
||||||
|
"--host=#{build_target}"
|
||||||
|
]
|
||||||
|
flags = '-O0 -g -fPIC'
|
||||||
|
env = {
|
||||||
|
'CFLAGS' => flags,
|
||||||
|
'CXXFLAGS' => flags,
|
||||||
|
}
|
||||||
|
configure = source_directory.relative_path_from(HOST_GCC) + 'configure'
|
||||||
|
sh env, configure.to_path, *configure_options, chdir: HOST_GCC
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'Make and install the bootstrap compiler'
|
||||||
|
task :make do
|
||||||
|
sh 'make', '-j', Etc.nprocessors.to_s, chdir: HOST_GCC
|
||||||
|
sh 'make', 'install', chdir: HOST_GCC
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'Build the bootstrap compiler'
|
||||||
|
task boot: %w[boot:configure boot:make]
|
16
source/CommandLineInterface.def
Normal file
16
source/CommandLineInterface.def
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
DEFINITION MODULE CommandLineInterface;
|
||||||
|
|
||||||
|
FROM Common IMPORT ShortString;
|
||||||
|
|
||||||
|
TYPE
|
||||||
|
CommandLine = RECORD
|
||||||
|
input: ShortString;
|
||||||
|
output: ShortString;
|
||||||
|
lex: BOOLEAN;
|
||||||
|
parse: BOOLEAN
|
||||||
|
END;
|
||||||
|
PCommandLine = POINTER TO CommandLine;
|
||||||
|
|
||||||
|
PROCEDURE parse_command_line(): PCommandLine;
|
||||||
|
|
||||||
|
END CommandLineInterface.
|
89
source/CommandLineInterface.elna
Normal file
89
source/CommandLineInterface.elna
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
module;
|
||||||
|
|
||||||
|
from SYSTEM import ADR, TSIZE;
|
||||||
|
|
||||||
|
from Args import GetArg, Narg;
|
||||||
|
from FIO import WriteString, WriteChar, WriteLine, StdErr;
|
||||||
|
from Storage import ALLOCATE;
|
||||||
|
from Strings import CompareStr, Length;
|
||||||
|
from MemUtils import MemZero;
|
||||||
|
|
||||||
|
from Common import ShortString;
|
||||||
|
|
||||||
|
proc parse_command_line() -> PCommandLine;
|
||||||
|
var
|
||||||
|
parameter: ShortString;
|
||||||
|
i: CARDINAL;
|
||||||
|
result: PCommandLine;
|
||||||
|
parsed: BOOLEAN;
|
||||||
|
begin
|
||||||
|
i := 1;
|
||||||
|
NEW(result);
|
||||||
|
result^.lex := false;
|
||||||
|
result^.parse := false;
|
||||||
|
MemZero(ADR(result^.input), 256);
|
||||||
|
result^.output[1] := CHAR(0);
|
||||||
|
|
||||||
|
while (i < Narg()) & (result <> nil) do
|
||||||
|
parsed := GetArg(parameter, i);
|
||||||
|
parsed := false;
|
||||||
|
|
||||||
|
if CompareStr(parameter, '--lex') = 0 then
|
||||||
|
parsed := true;
|
||||||
|
result^.lex := true
|
||||||
|
end;
|
||||||
|
if CompareStr(parameter, '--parse') = 0 then
|
||||||
|
parsed := true;
|
||||||
|
result^.parse := true
|
||||||
|
end;
|
||||||
|
if CompareStr(parameter, '-o') = 0 then
|
||||||
|
INC(i);
|
||||||
|
|
||||||
|
if i = Narg() then
|
||||||
|
WriteString(StdErr, 'Fatal error: expecting a file name following -o.');
|
||||||
|
result := nil
|
||||||
|
end;
|
||||||
|
if i < Narg() then
|
||||||
|
parsed := GetArg(parameter, i);
|
||||||
|
result^.output := parameter
|
||||||
|
end;
|
||||||
|
parsed := true
|
||||||
|
end;
|
||||||
|
if (parameter[1] <> '-') & (parsed = false) then
|
||||||
|
parsed := true;
|
||||||
|
|
||||||
|
if Length(result^.input) > 0 then
|
||||||
|
WriteString(StdErr, 'Fatal error: only one source file can be compiled at once. First given "');
|
||||||
|
WriteString(StdErr, result^.input);
|
||||||
|
WriteString(StdErr, '", then "');
|
||||||
|
WriteString(StdErr, parameter);
|
||||||
|
WriteString(StdErr, '".');
|
||||||
|
WriteLine(StdErr);
|
||||||
|
result := nil
|
||||||
|
end;
|
||||||
|
if result <> nil then
|
||||||
|
result^.input := parameter
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
if parsed = false then
|
||||||
|
WriteString(StdErr, 'Fatal error: unknown command line options: ');
|
||||||
|
|
||||||
|
WriteString(StdErr, parameter);
|
||||||
|
WriteChar(StdErr, '.');
|
||||||
|
WriteLine(StdErr);
|
||||||
|
|
||||||
|
result := nil
|
||||||
|
end;
|
||||||
|
|
||||||
|
i := i + 1
|
||||||
|
end;
|
||||||
|
if (result <> nil) & (Length(result^.input) = 0) then
|
||||||
|
WriteString(StdErr, 'Fatal error: no input files.');
|
||||||
|
WriteLine(StdErr);
|
||||||
|
result := nil
|
||||||
|
end;
|
||||||
|
|
||||||
|
return result
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
12
source/Common.def
Normal file
12
source/Common.def
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
DEFINITION MODULE Common;
|
||||||
|
|
||||||
|
TYPE
|
||||||
|
ShortString = ARRAY[1..256] OF CHAR;
|
||||||
|
Identifier = ARRAY[1..256] OF CHAR;
|
||||||
|
PIdentifier = POINTER TO Identifier;
|
||||||
|
TextLocation = RECORD
|
||||||
|
line: CARDINAL;
|
||||||
|
column: CARDINAL
|
||||||
|
END;
|
||||||
|
|
||||||
|
END Common.
|
3
source/Common.elna
Normal file
3
source/Common.elna
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module;
|
||||||
|
|
||||||
|
end.
|
73
source/Compiler.elna
Normal file
73
source/Compiler.elna
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
program;
|
||||||
|
|
||||||
|
from FIO import Close, IsNoError, File, OpenToRead, OpenToWrite, StdErr, StdOut, WriteLine, WriteString;
|
||||||
|
from SYSTEM import ADR;
|
||||||
|
from M2RTS import HALT, ExitOnHalt;
|
||||||
|
|
||||||
|
from Lexer import Lexer, lexer_destroy, lexer_initialize;
|
||||||
|
from Parser import Parser;
|
||||||
|
from Transpiler import transpile;
|
||||||
|
from CommandLineInterface import PCommandLine, parse_command_line;
|
||||||
|
from Parser import PAstModule, parse;
|
||||||
|
from Strings import Length;
|
||||||
|
|
||||||
|
var
|
||||||
|
command_line: PCommandLine;
|
||||||
|
|
||||||
|
proc compile_from_stream();
|
||||||
|
var
|
||||||
|
lexer: Lexer;
|
||||||
|
source_input: File;
|
||||||
|
source_output: File;
|
||||||
|
ast_module: PAstModule;
|
||||||
|
begin
|
||||||
|
source_input := OpenToRead(command_line^.input);
|
||||||
|
|
||||||
|
if IsNoError(source_input) = false then
|
||||||
|
WriteString(StdErr, 'Fatal error: failed to read the input file "');
|
||||||
|
WriteString(StdErr, command_line^.input);
|
||||||
|
WriteString(StdErr, '".');
|
||||||
|
WriteLine(StdErr);
|
||||||
|
|
||||||
|
ExitOnHalt(2)
|
||||||
|
end;
|
||||||
|
source_output := nil;
|
||||||
|
|
||||||
|
if Length(command_line^.output) > 0 then
|
||||||
|
source_output := OpenToWrite(command_line^.output);
|
||||||
|
|
||||||
|
if IsNoError(source_output) = false then
|
||||||
|
WriteString(StdErr, 'Fatal error: failed to create the output file "');
|
||||||
|
WriteString(StdErr, command_line^.output);
|
||||||
|
WriteString(StdErr, '".');
|
||||||
|
WriteLine(StdErr);
|
||||||
|
|
||||||
|
ExitOnHalt(2)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
if IsNoError(source_input) then
|
||||||
|
lexer_initialize(ADR(lexer), source_input);
|
||||||
|
|
||||||
|
ast_module := parse(ADR(lexer));
|
||||||
|
transpile(ast_module, StdOut, source_output, command_line^.input);
|
||||||
|
|
||||||
|
lexer_destroy(ADR(lexer));
|
||||||
|
|
||||||
|
Close(source_output);
|
||||||
|
Close(source_input)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
ExitOnHalt(0);
|
||||||
|
command_line := parse_command_line();
|
||||||
|
|
||||||
|
if command_line <> nil then
|
||||||
|
compile_from_stream()
|
||||||
|
end;
|
||||||
|
if command_line = nil then
|
||||||
|
ExitOnHalt(1)
|
||||||
|
end;
|
||||||
|
HALT()
|
||||||
|
end.
|
107
source/Lexer.def
Normal file
107
source/Lexer.def
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
DEFINITION MODULE Lexer;
|
||||||
|
|
||||||
|
FROM FIO IMPORT File;
|
||||||
|
|
||||||
|
FROM Common IMPORT Identifier, ShortString, TextLocation;
|
||||||
|
|
||||||
|
TYPE
|
||||||
|
PLexerBuffer = POINTER TO CHAR;
|
||||||
|
BufferPosition = RECORD
|
||||||
|
iterator: PLexerBuffer;
|
||||||
|
location: TextLocation
|
||||||
|
END;
|
||||||
|
PBufferPosition = POINTER TO BufferPosition;
|
||||||
|
Lexer = RECORD
|
||||||
|
input: File;
|
||||||
|
buffer: PLexerBuffer;
|
||||||
|
size: CARDINAL;
|
||||||
|
length: CARDINAL;
|
||||||
|
start: BufferPosition;
|
||||||
|
current: BufferPosition
|
||||||
|
END;
|
||||||
|
PLexer = POINTER TO Lexer;
|
||||||
|
LexerKind = (
|
||||||
|
lexerKindEof,
|
||||||
|
lexerKindIdentifier,
|
||||||
|
lexerKindIf,
|
||||||
|
lexerKindThen,
|
||||||
|
lexerKindElse,
|
||||||
|
lexerKindElsif,
|
||||||
|
lexerKindWhile,
|
||||||
|
lexerKindDo,
|
||||||
|
lexerKindProc,
|
||||||
|
lexerKindBegin,
|
||||||
|
lexerKindEnd,
|
||||||
|
lexerKindXor,
|
||||||
|
lexerKindConst,
|
||||||
|
lexerKindVar,
|
||||||
|
lexerKindCase,
|
||||||
|
lexerKindOf,
|
||||||
|
lexerKindType,
|
||||||
|
lexerKindRecord,
|
||||||
|
lexerKindUnion,
|
||||||
|
lexerKindPipe,
|
||||||
|
lexerKindTo,
|
||||||
|
lexerKindBoolean,
|
||||||
|
lexerKindNull,
|
||||||
|
lexerKindAnd,
|
||||||
|
lexerKindOr,
|
||||||
|
lexerKindTilde,
|
||||||
|
lexerKindReturn,
|
||||||
|
lexerKindDefer,
|
||||||
|
lexerKindRange,
|
||||||
|
lexerKindLeftParen,
|
||||||
|
lexerKindRightParen,
|
||||||
|
lexerKindLeftSquare,
|
||||||
|
lexerKindRightSquare,
|
||||||
|
lexerKindGreaterEqual,
|
||||||
|
lexerKindLessEqual,
|
||||||
|
lexerKindGreaterThan,
|
||||||
|
lexerKindLessThan,
|
||||||
|
lexerKindNotEqual,
|
||||||
|
lexerKindEqual,
|
||||||
|
lexerKindSemicolon,
|
||||||
|
lexerKindDot,
|
||||||
|
lexerKindComma,
|
||||||
|
lexerKindPlus,
|
||||||
|
lexerKindMinus,
|
||||||
|
lexerKindAsterisk,
|
||||||
|
lexerKindDivision,
|
||||||
|
lexerKindRemainder,
|
||||||
|
lexerKindAssignment,
|
||||||
|
lexerKindColon,
|
||||||
|
lexerKindHat,
|
||||||
|
lexerKindAt,
|
||||||
|
lexerKindComment,
|
||||||
|
lexerKindInteger,
|
||||||
|
lexerKindWord,
|
||||||
|
lexerKindCharacter,
|
||||||
|
lexerKindString,
|
||||||
|
lexerKindFrom,
|
||||||
|
lexerKindPointer,
|
||||||
|
lexerKindArray,
|
||||||
|
lexerKindArrow,
|
||||||
|
lexerKindProgram,
|
||||||
|
lexerKindModule,
|
||||||
|
lexerKindImport
|
||||||
|
);
|
||||||
|
LexerToken = RECORD
|
||||||
|
CASE kind: LexerKind OF
|
||||||
|
lexerKindBoolean: booleanKind: BOOLEAN |
|
||||||
|
lexerKindIdentifier: identifierKind: Identifier |
|
||||||
|
lexerKindInteger: integerKind: INTEGER |
|
||||||
|
lexerKindString: stringKind: ShortString
|
||||||
|
END;
|
||||||
|
start_location: TextLocation;
|
||||||
|
end_location: TextLocation
|
||||||
|
END;
|
||||||
|
PLexerToken = POINTER TO LexerToken;
|
||||||
|
|
||||||
|
PROCEDURE lexer_initialize(lexer: PLexer; input: File);
|
||||||
|
PROCEDURE lexer_destroy(lexer: PLexer);
|
||||||
|
(* Returns the last read token. *)
|
||||||
|
PROCEDURE lexer_current(lexer: PLexer): LexerToken;
|
||||||
|
(* Read and return the next token. *)
|
||||||
|
PROCEDURE lexer_lex(lexer: PLexer): LexerToken;
|
||||||
|
|
||||||
|
END Lexer.
|
876
source/Lexer.elna
Normal file
876
source/Lexer.elna
Normal file
@ -0,0 +1,876 @@
|
|||||||
|
module;
|
||||||
|
|
||||||
|
from FIO import ReadNBytes;
|
||||||
|
from SYSTEM import ADR, TSIZE;
|
||||||
|
|
||||||
|
from DynamicStrings import String, InitStringCharStar, KillString;
|
||||||
|
from StringConvert import StringToInteger;
|
||||||
|
from Storage import DEALLOCATE, ALLOCATE;
|
||||||
|
from Strings import Length;
|
||||||
|
from MemUtils import MemCopy, MemZero;
|
||||||
|
from StrCase import Lower;
|
||||||
|
|
||||||
|
const
|
||||||
|
CHUNK_SIZE = 85536;
|
||||||
|
|
||||||
|
type
|
||||||
|
(*
|
||||||
|
* Classification table assigns each possible character to a group (class). All
|
||||||
|
* characters of the same group a handled equivalently.
|
||||||
|
*
|
||||||
|
* Classification:
|
||||||
|
*)
|
||||||
|
TransitionClass = (
|
||||||
|
transitionClassInvalid,
|
||||||
|
transitionClassDigit,
|
||||||
|
transitionClassAlpha,
|
||||||
|
transitionClassSpace,
|
||||||
|
transitionClassColon,
|
||||||
|
transitionClassEquals,
|
||||||
|
transitionClassLeftParen,
|
||||||
|
transitionClassRightParen,
|
||||||
|
transitionClassAsterisk,
|
||||||
|
transitionClassUnderscore,
|
||||||
|
transitionClassSingle,
|
||||||
|
transitionClassHex,
|
||||||
|
transitionClassZero,
|
||||||
|
transitionClassX,
|
||||||
|
transitionClassEof,
|
||||||
|
transitionClassDot,
|
||||||
|
transitionClassMinus,
|
||||||
|
transitionClassSingleQuote,
|
||||||
|
transitionClassDoubleQuote,
|
||||||
|
transitionClassGreater,
|
||||||
|
transitionClassLess,
|
||||||
|
transitionClassOther
|
||||||
|
);
|
||||||
|
TransitionState = (
|
||||||
|
transitionStateStart,
|
||||||
|
transitionStateColon,
|
||||||
|
transitionStateIdentifier,
|
||||||
|
transitionStateDecimal,
|
||||||
|
transitionStateGreater,
|
||||||
|
transitionStateMinus,
|
||||||
|
transitionStateLeftParen,
|
||||||
|
transitionStateLess,
|
||||||
|
transitionStateDot,
|
||||||
|
transitionStateComment,
|
||||||
|
transitionStateClosingComment,
|
||||||
|
transitionStateCharacter,
|
||||||
|
transitionStateString,
|
||||||
|
transitionStateLeadingZero,
|
||||||
|
transitionStateDecimalSuffix,
|
||||||
|
transitionStateEnd
|
||||||
|
);
|
||||||
|
TransitionAction = proc(PLexer, PLexerToken);
|
||||||
|
Transition = record
|
||||||
|
action: TransitionAction;
|
||||||
|
next_state: TransitionState
|
||||||
|
end;
|
||||||
|
TransitionClasses = [22]Transition;
|
||||||
|
|
||||||
|
var
|
||||||
|
classification: [128]TransitionClass;
|
||||||
|
transitions: [16]TransitionClasses;
|
||||||
|
|
||||||
|
proc initialize_classification();
|
||||||
|
var
|
||||||
|
i: CARDINAL;
|
||||||
|
begin
|
||||||
|
classification[1] := transitionClassEof; (* NUL *)
|
||||||
|
classification[2] := transitionClassInvalid; (* SOH *)
|
||||||
|
classification[3] := transitionClassInvalid; (* STX *)
|
||||||
|
classification[4] := transitionClassInvalid; (* ETX *)
|
||||||
|
classification[5] := transitionClassInvalid; (* EOT *)
|
||||||
|
classification[6] := transitionClassInvalid; (* EMQ *)
|
||||||
|
classification[7] := transitionClassInvalid; (* ACK *)
|
||||||
|
classification[8] := transitionClassInvalid; (* BEL *)
|
||||||
|
classification[9] := transitionClassInvalid; (* BS *)
|
||||||
|
classification[10] := transitionClassSpace; (* HT *)
|
||||||
|
classification[11] := transitionClassSpace; (* LF *)
|
||||||
|
classification[12] := transitionClassInvalid; (* VT *)
|
||||||
|
classification[13] := transitionClassInvalid; (* FF *)
|
||||||
|
classification[14] := transitionClassSpace; (* CR *)
|
||||||
|
classification[15] := transitionClassInvalid; (* SO *)
|
||||||
|
classification[16] := transitionClassInvalid; (* SI *)
|
||||||
|
classification[17] := transitionClassInvalid; (* DLE *)
|
||||||
|
classification[18] := transitionClassInvalid; (* DC1 *)
|
||||||
|
classification[19] := transitionClassInvalid; (* DC2 *)
|
||||||
|
classification[20] := transitionClassInvalid; (* DC3 *)
|
||||||
|
classification[21] := transitionClassInvalid; (* DC4 *)
|
||||||
|
classification[22] := transitionClassInvalid; (* NAK *)
|
||||||
|
classification[23] := transitionClassInvalid; (* SYN *)
|
||||||
|
classification[24] := transitionClassInvalid; (* ETB *)
|
||||||
|
classification[25] := transitionClassInvalid; (* CAN *)
|
||||||
|
classification[26] := transitionClassInvalid; (* EM *)
|
||||||
|
classification[27] := transitionClassInvalid; (* SUB *)
|
||||||
|
classification[28] := transitionClassInvalid; (* ESC *)
|
||||||
|
classification[29] := transitionClassInvalid; (* FS *)
|
||||||
|
classification[30] := transitionClassInvalid; (* GS *)
|
||||||
|
classification[31] := transitionClassInvalid; (* RS *)
|
||||||
|
classification[32] := transitionClassInvalid; (* US *)
|
||||||
|
classification[33] := transitionClassSpace; (* Space *)
|
||||||
|
classification[34] := transitionClassSingle; (* ! *)
|
||||||
|
classification[35] := transitionClassDoubleQuote; (* " *)
|
||||||
|
classification[36] := transitionClassOther; (* # *)
|
||||||
|
classification[37] := transitionClassOther; (* $ *)
|
||||||
|
classification[38] := transitionClassSingle; (* % *)
|
||||||
|
classification[39] := transitionClassSingle; (* & *)
|
||||||
|
classification[40] := transitionClassSingleQuote; (* ' *)
|
||||||
|
classification[41] := transitionClassLeftParen; (* ( *)
|
||||||
|
classification[42] := transitionClassRightParen; (* ) *)
|
||||||
|
classification[43] := transitionClassAsterisk; (* * *)
|
||||||
|
classification[44] := transitionClassSingle; (* + *)
|
||||||
|
classification[45] := transitionClassSingle; (* , *)
|
||||||
|
classification[46] := transitionClassMinus; (* - *)
|
||||||
|
classification[47] := transitionClassDot; (* . *)
|
||||||
|
classification[48] := transitionClassSingle; (* / *)
|
||||||
|
classification[49] := transitionClassZero; (* 0 *)
|
||||||
|
classification[50] := transitionClassDigit; (* 1 *)
|
||||||
|
classification[51] := transitionClassDigit; (* 2 *)
|
||||||
|
classification[52] := transitionClassDigit; (* 3 *)
|
||||||
|
classification[53] := transitionClassDigit; (* 4 *)
|
||||||
|
classification[54] := transitionClassDigit; (* 5 *)
|
||||||
|
classification[55] := transitionClassDigit; (* 6 *)
|
||||||
|
classification[56] := transitionClassDigit; (* 7 *)
|
||||||
|
classification[57] := transitionClassDigit; (* 8 *)
|
||||||
|
classification[58] := transitionClassDigit; (* 9 *)
|
||||||
|
classification[59] := transitionClassColon; (* : *)
|
||||||
|
classification[60] := transitionClassSingle; (* ; *)
|
||||||
|
classification[61] := transitionClassLess; (* < *)
|
||||||
|
classification[62] := transitionClassEquals; (* = *)
|
||||||
|
classification[63] := transitionClassGreater; (* > *)
|
||||||
|
classification[64] := transitionClassOther; (* ? *)
|
||||||
|
classification[65] := transitionClassSingle; (* @ *)
|
||||||
|
classification[66] := transitionClassAlpha; (* A *)
|
||||||
|
classification[67] := transitionClassAlpha; (* B *)
|
||||||
|
classification[68] := transitionClassAlpha; (* C *)
|
||||||
|
classification[69] := transitionClassAlpha; (* D *)
|
||||||
|
classification[70] := transitionClassAlpha; (* E *)
|
||||||
|
classification[71] := transitionClassAlpha; (* F *)
|
||||||
|
classification[72] := transitionClassAlpha; (* G *)
|
||||||
|
classification[73] := transitionClassAlpha; (* H *)
|
||||||
|
classification[74] := transitionClassAlpha; (* I *)
|
||||||
|
classification[75] := transitionClassAlpha; (* J *)
|
||||||
|
classification[76] := transitionClassAlpha; (* K *)
|
||||||
|
classification[77] := transitionClassAlpha; (* L *)
|
||||||
|
classification[78] := transitionClassAlpha; (* M *)
|
||||||
|
classification[79] := transitionClassAlpha; (* N *)
|
||||||
|
classification[80] := transitionClassAlpha; (* O *)
|
||||||
|
classification[81] := transitionClassAlpha; (* P *)
|
||||||
|
classification[82] := transitionClassAlpha; (* Q *)
|
||||||
|
classification[83] := transitionClassAlpha; (* R *)
|
||||||
|
classification[84] := transitionClassAlpha; (* S *)
|
||||||
|
classification[85] := transitionClassAlpha; (* T *)
|
||||||
|
classification[86] := transitionClassAlpha; (* U *)
|
||||||
|
classification[87] := transitionClassAlpha; (* V *)
|
||||||
|
classification[88] := transitionClassAlpha; (* W *)
|
||||||
|
classification[89] := transitionClassAlpha; (* X *)
|
||||||
|
classification[90] := transitionClassAlpha; (* Y *)
|
||||||
|
classification[91] := transitionClassAlpha; (* Z *)
|
||||||
|
classification[92] := transitionClassSingle; (* [ *)
|
||||||
|
classification[93] := transitionClassOther; (* \ *)
|
||||||
|
classification[94] := transitionClassSingle; (* ] *)
|
||||||
|
classification[95] := transitionClassSingle; (* ^ *)
|
||||||
|
classification[96] := transitionClassUnderscore; (* _ *)
|
||||||
|
classification[97] := transitionClassOther; (* ` *)
|
||||||
|
classification[98] := transitionClassHex; (* a *)
|
||||||
|
classification[99] := transitionClassHex; (* b *)
|
||||||
|
classification[100] := transitionClassHex; (* c *)
|
||||||
|
classification[101] := transitionClassHex; (* d *)
|
||||||
|
classification[102] := transitionClassHex; (* e *)
|
||||||
|
classification[103] := transitionClassHex; (* f *)
|
||||||
|
classification[104] := transitionClassAlpha; (* g *)
|
||||||
|
classification[105] := transitionClassAlpha; (* h *)
|
||||||
|
classification[106] := transitionClassAlpha; (* i *)
|
||||||
|
classification[107] := transitionClassAlpha; (* j *)
|
||||||
|
classification[108] := transitionClassAlpha; (* k *)
|
||||||
|
classification[109] := transitionClassAlpha; (* l *)
|
||||||
|
classification[110] := transitionClassAlpha; (* m *)
|
||||||
|
classification[111] := transitionClassAlpha; (* n *)
|
||||||
|
classification[112] := transitionClassAlpha; (* o *)
|
||||||
|
classification[113] := transitionClassAlpha; (* p *)
|
||||||
|
classification[114] := transitionClassAlpha; (* q *)
|
||||||
|
classification[115] := transitionClassAlpha; (* r *)
|
||||||
|
classification[116] := transitionClassAlpha; (* s *)
|
||||||
|
classification[117] := transitionClassAlpha; (* t *)
|
||||||
|
classification[118] := transitionClassAlpha; (* u *)
|
||||||
|
classification[119] := transitionClassAlpha; (* v *)
|
||||||
|
classification[120] := transitionClassAlpha; (* w *)
|
||||||
|
classification[121] := transitionClassX; (* x *)
|
||||||
|
classification[122] := transitionClassAlpha; (* y *)
|
||||||
|
classification[123] := transitionClassAlpha; (* z *)
|
||||||
|
classification[124] := transitionClassOther; (* { *)
|
||||||
|
classification[125] := transitionClassSingle; (* | *)
|
||||||
|
classification[126] := transitionClassOther; (* } *)
|
||||||
|
classification[127] := transitionClassSingle; (* ~ *)
|
||||||
|
classification[128] := transitionClassInvalid; (* DEL *)
|
||||||
|
|
||||||
|
i := 129;
|
||||||
|
while i <= 256 do
|
||||||
|
classification[i] := transitionClassOther;
|
||||||
|
INC(i)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc compare_keyword(keyword: ARRAY OF CHAR, token_start: BufferPosition, token_end: PLexerBuffer) -> BOOLEAN;
|
||||||
|
var
|
||||||
|
result: BOOLEAN;
|
||||||
|
index: CARDINAL;
|
||||||
|
keyword_length: CARDINAL;
|
||||||
|
continue: BOOLEAN;
|
||||||
|
begin
|
||||||
|
index := 0;
|
||||||
|
result := true;
|
||||||
|
keyword_length := Length(keyword);
|
||||||
|
continue := (index < keyword_length) & (token_start.iterator <> token_end);
|
||||||
|
|
||||||
|
while continue & result do
|
||||||
|
result := (keyword[index] = token_start.iterator^) or (Lower(keyword[index]) = token_start.iterator^);
|
||||||
|
INC(token_start.iterator);
|
||||||
|
INC(index);
|
||||||
|
continue := (index < keyword_length) & (token_start.iterator <> token_end)
|
||||||
|
end;
|
||||||
|
result := result & (index = Length(keyword));
|
||||||
|
|
||||||
|
return result & (token_start.iterator = token_end)
|
||||||
|
end;
|
||||||
|
|
||||||
|
(* Reached the end of file. *)
|
||||||
|
proc transition_action_eof(lexer: PLexer, token: PLexerToken);
|
||||||
|
begin
|
||||||
|
token^.kind := lexerKindEof
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc increment(position: PBufferPosition);
|
||||||
|
begin
|
||||||
|
INC(position^.iterator)
|
||||||
|
end;
|
||||||
|
|
||||||
|
(* Add the character to the token currently read and advance to the next character. *)
|
||||||
|
proc transition_action_accumulate(lexer: PLexer, token: PLexerToken);
|
||||||
|
begin
|
||||||
|
increment(ADR(lexer^.current))
|
||||||
|
end;
|
||||||
|
|
||||||
|
(* The current character is not a part of the token. Finish the token already
|
||||||
|
* read. Don't advance to the next character. *)
|
||||||
|
proc transition_action_finalize(lexer: PLexer, token: PLexerToken);
|
||||||
|
begin
|
||||||
|
if lexer^.start.iterator^ = ':' then
|
||||||
|
token^.kind := lexerKindColon
|
||||||
|
end;
|
||||||
|
if lexer^.start.iterator^ = '>' then
|
||||||
|
token^.kind := lexerKindGreaterThan
|
||||||
|
end;
|
||||||
|
if lexer^.start.iterator^ = '<' then
|
||||||
|
token^.kind := lexerKindLessThan
|
||||||
|
end;
|
||||||
|
if lexer^.start.iterator^ = '(' then
|
||||||
|
token^.kind := lexerKindLeftParen
|
||||||
|
end;
|
||||||
|
if lexer^.start.iterator^ = '-' then
|
||||||
|
token^.kind := lexerKindMinus
|
||||||
|
end;
|
||||||
|
if lexer^.start.iterator^ = '.' then
|
||||||
|
token^.kind := lexerKindDot
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
(* An action for tokens containing multiple characters. *)
|
||||||
|
proc transition_action_composite(lexer: PLexer, token: PLexerToken);
|
||||||
|
begin
|
||||||
|
if lexer^.start.iterator^ = '<' then
|
||||||
|
if lexer^.current.iterator^ = '>' then
|
||||||
|
token^.kind := lexerKindNotEqual
|
||||||
|
end;
|
||||||
|
if lexer^.current.iterator^ = '=' then
|
||||||
|
token^.kind := lexerKindLessEqual
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
if (lexer^.start.iterator^ = '>') & (lexer^.current.iterator^ = '=') then
|
||||||
|
token^.kind := lexerKindGreaterEqual
|
||||||
|
end;
|
||||||
|
if (lexer^.start.iterator^ = '.') & (lexer^.current.iterator^ = '.') then
|
||||||
|
token^.kind := lexerKindRange
|
||||||
|
end;
|
||||||
|
if (lexer^.start.iterator^ = ':') & (lexer^.current.iterator^ = '=') then
|
||||||
|
token^.kind := lexerKindAssignment
|
||||||
|
end;
|
||||||
|
if (lexer^.start.iterator^ = '-') & (lexer^.current.iterator^ = '>') then
|
||||||
|
token^.kind := lexerKindArrow
|
||||||
|
end;
|
||||||
|
increment(ADR(lexer^.current))
|
||||||
|
end;
|
||||||
|
|
||||||
|
(* Skip a space. *)
|
||||||
|
proc transition_action_skip(lexer: PLexer, token: PLexerToken);
|
||||||
|
begin
|
||||||
|
increment(ADR(lexer^.start));
|
||||||
|
|
||||||
|
if ORD(lexer^.start.iterator^) = 10 then
|
||||||
|
INC(lexer^.start.location.line);
|
||||||
|
lexer^.start.location.column := 1
|
||||||
|
end;
|
||||||
|
lexer^.current := lexer^.start
|
||||||
|
end;
|
||||||
|
|
||||||
|
(* Delimited string action. *)
|
||||||
|
proc transition_action_delimited(lexer: PLexer, token: PLexerToken);
|
||||||
|
var
|
||||||
|
text_length: CARDINAL;
|
||||||
|
begin
|
||||||
|
if lexer^.start.iterator^ = '(' then
|
||||||
|
token^.kind := lexerKindComment
|
||||||
|
end;
|
||||||
|
if lexer^.start.iterator^ = '"' then
|
||||||
|
text_length := lexer^.current.iterator;
|
||||||
|
DEC(text_length, lexer^.start.iterator);
|
||||||
|
INC(text_length);
|
||||||
|
|
||||||
|
MemZero(ADR(token^.stringKind), TSIZE(ShortString));
|
||||||
|
MemCopy(lexer^.start.iterator, text_length, ADR(token^.stringKind));
|
||||||
|
|
||||||
|
token^.kind := lexerKindCharacter
|
||||||
|
end;
|
||||||
|
if lexer^.start.iterator^ = "'" then
|
||||||
|
text_length := lexer^.current.iterator;
|
||||||
|
DEC(text_length, lexer^.start.iterator);
|
||||||
|
INC(text_length);
|
||||||
|
|
||||||
|
MemZero(ADR(token^.stringKind), TSIZE(ShortString));
|
||||||
|
MemCopy(lexer^.start.iterator, text_length, ADR(token^.stringKind));
|
||||||
|
|
||||||
|
token^.kind := lexerKindString
|
||||||
|
end;
|
||||||
|
increment(ADR(lexer^.current))
|
||||||
|
end;
|
||||||
|
|
||||||
|
(* Finalize keyword or identifier. *)
|
||||||
|
proc transition_action_key_id(lexer: PLexer, token: PLexerToken);
|
||||||
|
begin
|
||||||
|
token^.kind := lexerKindIdentifier;
|
||||||
|
|
||||||
|
token^.identifierKind[1] := lexer^.current.iterator;
|
||||||
|
DEC(token^.identifierKind[1], lexer^.start.iterator);
|
||||||
|
MemCopy(lexer^.start.iterator, ORD(token^.identifierKind[1]), ADR(token^.identifierKind[2]));
|
||||||
|
|
||||||
|
if compare_keyword('program', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindProgram
|
||||||
|
end;
|
||||||
|
if compare_keyword('import', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindImport
|
||||||
|
end;
|
||||||
|
if compare_keyword('const', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindConst
|
||||||
|
end;
|
||||||
|
if compare_keyword('var', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindVar
|
||||||
|
end;
|
||||||
|
if compare_keyword('if', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindIf
|
||||||
|
end;
|
||||||
|
if compare_keyword('then', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindThen
|
||||||
|
end;
|
||||||
|
if compare_keyword('elsif', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindElsif
|
||||||
|
end;
|
||||||
|
if compare_keyword('else', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindElse
|
||||||
|
end;
|
||||||
|
if compare_keyword('while', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindWhile
|
||||||
|
end;
|
||||||
|
if compare_keyword('do', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindDo
|
||||||
|
end;
|
||||||
|
if compare_keyword('proc', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindProc
|
||||||
|
end;
|
||||||
|
if compare_keyword('begin', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindBegin
|
||||||
|
end;
|
||||||
|
if compare_keyword('end', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindEnd
|
||||||
|
end;
|
||||||
|
if compare_keyword('type', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindType
|
||||||
|
end;
|
||||||
|
if compare_keyword('record', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindRecord
|
||||||
|
end;
|
||||||
|
if compare_keyword('union', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindUnion
|
||||||
|
end;
|
||||||
|
if compare_keyword('NIL', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindNull
|
||||||
|
end;
|
||||||
|
if compare_keyword('or', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindOr
|
||||||
|
end;
|
||||||
|
if compare_keyword('return', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindReturn
|
||||||
|
end;
|
||||||
|
if compare_keyword('defer', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindDefer
|
||||||
|
end;
|
||||||
|
if compare_keyword('TO', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindTo
|
||||||
|
end;
|
||||||
|
if compare_keyword('CASE', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindCase
|
||||||
|
end;
|
||||||
|
if compare_keyword('OF', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindOf
|
||||||
|
end;
|
||||||
|
if compare_keyword('FROM', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindFrom
|
||||||
|
end;
|
||||||
|
if compare_keyword('module', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindModule
|
||||||
|
end;
|
||||||
|
if compare_keyword('xor', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindXor
|
||||||
|
end;
|
||||||
|
if compare_keyword('POINTER', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindPointer
|
||||||
|
end;
|
||||||
|
if compare_keyword('ARRAY', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindArray
|
||||||
|
end;
|
||||||
|
if compare_keyword('TRUE', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindBoolean;
|
||||||
|
token^.booleanKind := true
|
||||||
|
end;
|
||||||
|
if compare_keyword('FALSE', lexer^.start, lexer^.current.iterator) then
|
||||||
|
token^.kind := lexerKindBoolean;
|
||||||
|
token^.booleanKind := false
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
(* Action for tokens containing only one character. The character cannot be
|
||||||
|
* followed by other characters forming a composite token. *)
|
||||||
|
proc transition_action_single(lexer: PLexer, token: PLexerToken);
|
||||||
|
begin
|
||||||
|
if lexer^.current.iterator^ = '&' then
|
||||||
|
token^.kind := lexerKindAnd
|
||||||
|
end;
|
||||||
|
if lexer^.current.iterator^ = ';' then
|
||||||
|
token^.kind := lexerKindSemicolon
|
||||||
|
end;
|
||||||
|
if lexer^.current.iterator^ = ',' then
|
||||||
|
token^.kind := lexerKindComma
|
||||||
|
end;
|
||||||
|
if lexer^.current.iterator^ = '~' then
|
||||||
|
token^.kind := lexerKindTilde
|
||||||
|
end;
|
||||||
|
if lexer^.current.iterator^ = ')' then
|
||||||
|
token^.kind := lexerKindRightParen
|
||||||
|
end;
|
||||||
|
if lexer^.current.iterator^ = '[' then
|
||||||
|
token^.kind := lexerKindLeftSquare
|
||||||
|
end;
|
||||||
|
if lexer^.current.iterator^ = ']' then
|
||||||
|
token^.kind := lexerKindRightSquare
|
||||||
|
end;
|
||||||
|
if lexer^.current.iterator^ = '^' then
|
||||||
|
token^.kind := lexerKindHat
|
||||||
|
end;
|
||||||
|
if lexer^.current.iterator^ = '=' then
|
||||||
|
token^.kind := lexerKindEqual
|
||||||
|
end;
|
||||||
|
if lexer^.current.iterator^ = '+' then
|
||||||
|
token^.kind := lexerKindPlus
|
||||||
|
end;
|
||||||
|
if lexer^.current.iterator^ = '*' then
|
||||||
|
token^.kind := lexerKindAsterisk
|
||||||
|
end;
|
||||||
|
if lexer^.current.iterator^ = '/' then
|
||||||
|
token^.kind := lexerKindDivision
|
||||||
|
end;
|
||||||
|
if lexer^.current.iterator^ = '%' then
|
||||||
|
token^.kind := lexerKindRemainder
|
||||||
|
end;
|
||||||
|
if lexer^.current.iterator^ = '@' then
|
||||||
|
token^.kind := lexerKindAt
|
||||||
|
end;
|
||||||
|
if lexer^.current.iterator^ = '|' then
|
||||||
|
token^.kind := lexerKindPipe
|
||||||
|
end;
|
||||||
|
increment(ADR(lexer^.current.iterator))
|
||||||
|
end;
|
||||||
|
|
||||||
|
(* Handle an integer literal. *)
|
||||||
|
proc transition_action_integer(lexer: PLexer, token: PLexerToken);
|
||||||
|
var
|
||||||
|
buffer: String;
|
||||||
|
integer_length: CARDINAL;
|
||||||
|
found: BOOLEAN;
|
||||||
|
begin
|
||||||
|
token^.kind := lexerKindInteger;
|
||||||
|
|
||||||
|
integer_length := lexer^.current.iterator;
|
||||||
|
DEC(integer_length, lexer^.start.iterator);
|
||||||
|
MemZero(ADR(token^.identifierKind), TSIZE(Identifier));
|
||||||
|
MemCopy(lexer^.start.iterator, integer_length, ADR(token^.identifierKind[1]));
|
||||||
|
|
||||||
|
buffer := InitStringCharStar(ADR(token^.identifierKind[1]));
|
||||||
|
token^.integerKind := StringToInteger(buffer, 10, found);
|
||||||
|
buffer := KillString(buffer)
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc set_default_transition(current_state: TransitionState, default_action: TransitionAction, next_state: TransitionState);
|
||||||
|
var
|
||||||
|
default_transition: Transition;
|
||||||
|
begin
|
||||||
|
default_transition.action := default_action;
|
||||||
|
default_transition.next_state := next_state;
|
||||||
|
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassInvalid) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassDigit) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassAlpha) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassSpace) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassColon) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassEquals) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassLeftParen) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassRightParen) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassAsterisk) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassUnderscore) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassSingle) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassHex) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassZero) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassX) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassEof) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassDot) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassMinus) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassSingleQuote) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassDoubleQuote) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassGreater) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassLess) + 1] := default_transition;
|
||||||
|
transitions[ORD(current_state) + 1][ORD(transitionClassOther) + 1] := default_transition
|
||||||
|
end;
|
||||||
|
|
||||||
|
(*
|
||||||
|
* The transition table describes transitions from one state to another, given
|
||||||
|
* a symbol (character class).
|
||||||
|
*
|
||||||
|
* The table has m rows and n columns, where m is the amount of states and n is
|
||||||
|
* the amount of classes. So given the current state and a classified character
|
||||||
|
* the table can be used to look up the next state.
|
||||||
|
*
|
||||||
|
* Each cell is a word long.
|
||||||
|
* - The least significant byte of the word is a row number (beginning with 0).
|
||||||
|
* It specifies the target state. "ff" means that this is an end state and no
|
||||||
|
* transition is possible.
|
||||||
|
* - The next byte is the action that should be performed when transitioning.
|
||||||
|
* For the meaning of actions see labels in the lex_next function, which
|
||||||
|
* handles each action.
|
||||||
|
*)
|
||||||
|
proc initialize_transitions();
|
||||||
|
begin
|
||||||
|
(* Start state. *)
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassInvalid) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassInvalid) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassDigit) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassDigit) + 1].next_state := transitionStateDecimal;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassAlpha) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassAlpha) + 1].next_state := transitionStateIdentifier;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassSpace) + 1].action := transition_action_skip;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassSpace) + 1].next_state := transitionStateStart;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassColon) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassColon) + 1].next_state := transitionStateColon;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassEquals) + 1].action := transition_action_single;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassEquals) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassLeftParen) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassLeftParen) + 1].next_state := transitionStateLeftParen;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassRightParen) + 1].action := transition_action_single;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassRightParen) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassAsterisk) + 1].action := transition_action_single;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassAsterisk) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassUnderscore) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassUnderscore) + 1].next_state := transitionStateIdentifier;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassSingle) + 1].action := transition_action_single;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassSingle) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassHex) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassHex) + 1].next_state := transitionStateIdentifier;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassZero) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassZero) + 1].next_state := transitionStateLeadingZero;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassX) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassX) + 1].next_state := transitionStateIdentifier;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassEof) + 1].action := transition_action_eof;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassEof) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassDot) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassDot) + 1].next_state := transitionStateDot;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassMinus) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassMinus) + 1].next_state := transitionStateMinus;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassSingleQuote) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassSingleQuote) + 1].next_state := transitionStateCharacter;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassDoubleQuote) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassDoubleQuote) + 1].next_state := transitionStateString;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassGreater) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassGreater) + 1].next_state := transitionStateGreater;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassLess) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassLess) + 1].next_state := transitionStateLess;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassOther) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateStart) + 1][ORD(transitionClassOther) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
(* Colon state. *)
|
||||||
|
set_default_transition(transitionStateColon, transition_action_finalize, transitionStateEnd);
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateColon) + 1][ORD(transitionClassEquals) + 1].action := transition_action_composite;
|
||||||
|
transitions[ORD(transitionStateColon) + 1][ORD(transitionClassEquals) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
(* Identifier state. *)
|
||||||
|
set_default_transition(transitionStateIdentifier, transition_action_key_id, transitionStateEnd);
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateIdentifier) + 1][ORD(transitionClassDigit) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateIdentifier) + 1][ORD(transitionClassDigit) + 1].next_state := transitionStateIdentifier;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateIdentifier) + 1][ORD(transitionClassAlpha) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateIdentifier) + 1][ORD(transitionClassAlpha) + 1].next_state := transitionStateIdentifier;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateIdentifier) + 1][ORD(transitionClassUnderscore) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateIdentifier) + 1][ORD(transitionClassUnderscore) + 1].next_state := transitionStateIdentifier;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateIdentifier) + 1][ORD(transitionClassHex) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateIdentifier) + 1][ORD(transitionClassHex) + 1].next_state := transitionStateIdentifier;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateIdentifier) + 1][ORD(transitionClassZero) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateIdentifier) + 1][ORD(transitionClassZero) + 1].next_state := transitionStateIdentifier;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateIdentifier) + 1][ORD(transitionClassX) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateIdentifier) + 1][ORD(transitionClassX) + 1].next_state := transitionStateIdentifier;
|
||||||
|
|
||||||
|
(* Decimal state. *)
|
||||||
|
set_default_transition(transitionStateDecimal, transition_action_integer, transitionStateEnd);
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateDecimal) + 1][ORD(transitionClassDigit) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateDecimal) + 1][ORD(transitionClassDigit) + 1].next_state := transitionStateDecimal;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateDecimal) + 1][ORD(transitionClassAlpha) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateDecimal) + 1][ORD(transitionClassAlpha) + 1].next_state := transitionStateDecimalSuffix;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateDecimal) + 1][ORD(transitionClassUnderscore) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateDecimal) + 1][ORD(transitionClassUnderscore) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateDecimal) + 1][ORD(transitionClassHex) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateDecimal) + 1][ORD(transitionClassHex) + 1].next_state := transitionStateDecimalSuffix;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateDecimal) + 1][ORD(transitionClassZero) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateDecimal) + 1][ORD(transitionClassZero) + 1].next_state := transitionStateDecimal;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateDecimal) + 1][ORD(transitionClassX) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateDecimal) + 1][ORD(transitionClassX) + 1].next_state := transitionStateDecimalSuffix;
|
||||||
|
|
||||||
|
(* Greater state. *)
|
||||||
|
set_default_transition(transitionStateGreater, transition_action_finalize, transitionStateEnd);
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateGreater) + 1][ORD(transitionClassEquals) + 1].action := transition_action_composite;
|
||||||
|
transitions[ORD(transitionStateGreater) + 1][ORD(transitionClassEquals) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
(* Minus state. *)
|
||||||
|
set_default_transition(transitionStateMinus, transition_action_finalize, transitionStateEnd);
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateMinus) + 1][ORD(transitionClassGreater) + 1].action := transition_action_composite;
|
||||||
|
transitions[ORD(transitionStateMinus) + 1][ORD(transitionClassGreater) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
(* Left paren state. *)
|
||||||
|
set_default_transition(transitionStateLeftParen, transition_action_finalize, transitionStateEnd);
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateLeftParen) + 1][ORD(transitionClassAsterisk) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateLeftParen) + 1][ORD(transitionClassAsterisk) + 1].next_state := transitionStateComment;
|
||||||
|
|
||||||
|
(* Less state. *)
|
||||||
|
set_default_transition(transitionStateLess, transition_action_finalize, transitionStateEnd);
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateLess) + 1][ORD(transitionClassEquals) + 1].action := transition_action_composite;
|
||||||
|
transitions[ORD(transitionStateLess) + 1][ORD(transitionClassEquals) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateLess) + 1][ORD(transitionClassGreater) + 1].action := transition_action_composite;
|
||||||
|
transitions[ORD(transitionStateLess) + 1][ORD(transitionClassGreater) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
(* Hexadecimal after 0x. *)
|
||||||
|
set_default_transition(transitionStateDot, transition_action_finalize, transitionStateEnd);
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateDot) + 1][ORD(transitionClassDot) + 1].action := transition_action_composite;
|
||||||
|
transitions[ORD(transitionStateDot) + 1][ORD(transitionClassDot) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
(* Comment. *)
|
||||||
|
set_default_transition(transitionStateComment, transition_action_accumulate, transitionStateComment);
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateComment) + 1][ORD(transitionClassAsterisk) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateComment) + 1][ORD(transitionClassAsterisk) + 1].next_state := transitionStateClosingComment;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateComment) + 1][ORD(transitionClassEof) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateComment) + 1][ORD(transitionClassEof) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
(* Closing comment. *)
|
||||||
|
set_default_transition(transitionStateClosingComment, transition_action_accumulate, transitionStateComment);
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateClosingComment) + 1][ORD(transitionClassInvalid) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateClosingComment) + 1][ORD(transitionClassInvalid) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateClosingComment) + 1][ORD(transitionClassRightParen) + 1].action := transition_action_delimited;
|
||||||
|
transitions[ORD(transitionStateClosingComment) + 1][ORD(transitionClassRightParen) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateClosingComment) + 1][ORD(transitionClassAsterisk) + 1].action := transition_action_accumulate;
|
||||||
|
transitions[ORD(transitionStateClosingComment) + 1][ORD(transitionClassAsterisk) + 1].next_state := transitionStateClosingComment;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateClosingComment) + 1][ORD(transitionClassEof) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateClosingComment) + 1][ORD(transitionClassEof) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
(* Character. *)
|
||||||
|
set_default_transition(transitionStateCharacter, transition_action_accumulate, transitionStateCharacter);
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateCharacter) + 1][ORD(transitionClassInvalid) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateCharacter) + 1][ORD(transitionClassInvalid) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateCharacter) + 1][ORD(transitionClassEof) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateCharacter) + 1][ORD(transitionClassEof) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateCharacter) + 1][ORD(transitionClassSingleQuote) + 1].action := transition_action_delimited;
|
||||||
|
transitions[ORD(transitionStateCharacter) + 1][ORD(transitionClassSingleQuote) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
(* String. *)
|
||||||
|
set_default_transition(transitionStateString, transition_action_accumulate, transitionStateString);
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateString) + 1][ORD(transitionClassInvalid) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateString) + 1][ORD(transitionClassInvalid) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateString) + 1][ORD(transitionClassEof) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateString) + 1][ORD(transitionClassEof) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateString) + 1][ORD(transitionClassDoubleQuote) + 1].action := transition_action_delimited;
|
||||||
|
transitions[ORD(transitionStateString) + 1][ORD(transitionClassDoubleQuote) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
(* Leading zero. *)
|
||||||
|
set_default_transition(transitionStateLeadingZero, transition_action_integer, transitionStateEnd);
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateLeadingZero) + 1][ORD(transitionClassDigit) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateLeadingZero) + 1][ORD(transitionClassDigit) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateLeadingZero) + 1][ORD(transitionClassAlpha) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateLeadingZero) + 1][ORD(transitionClassAlpha) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateLeadingZero) + 1][ORD(transitionClassUnderscore) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateLeadingZero) + 1][ORD(transitionClassUnderscore) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateLeadingZero) + 1][ORD(transitionClassHex) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateLeadingZero) + 1][ORD(transitionClassHex) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateLeadingZero) + 1][ORD(transitionClassZero) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateLeadingZero) + 1][ORD(transitionClassZero) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateLeadingZero) + 1][ORD(transitionClassX) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateLeadingZero) + 1][ORD(transitionClassX) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
(* Digit with a character suffix. *)
|
||||||
|
set_default_transition(transitionStateDecimalSuffix, transition_action_integer, transitionStateEnd);
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateDecimalSuffix) + 1][ORD(transitionClassAlpha) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateDecimalSuffix) + 1][ORD(transitionClassAlpha) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateDecimalSuffix) + 1][ORD(transitionClassDigit) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateDecimalSuffix) + 1][ORD(transitionClassDigit) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateDecimalSuffix) + 1][ORD(transitionClassHex) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateDecimalSuffix) + 1][ORD(transitionClassHex) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateDecimalSuffix) + 1][ORD(transitionClassZero) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateDecimalSuffix) + 1][ORD(transitionClassZero) + 1].next_state := transitionStateEnd;
|
||||||
|
|
||||||
|
transitions[ORD(transitionStateDecimalSuffix) + 1][ORD(transitionClassX) + 1].action := nil;
|
||||||
|
transitions[ORD(transitionStateDecimalSuffix) + 1][ORD(transitionClassX) + 1].next_state := transitionStateEnd
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc lexer_initialize(lexer: PLexer, input: File);
|
||||||
|
begin
|
||||||
|
lexer^.input := input;
|
||||||
|
lexer^.length := 0;
|
||||||
|
|
||||||
|
ALLOCATE(lexer^.buffer, CHUNK_SIZE);
|
||||||
|
MemZero(lexer^.buffer, CHUNK_SIZE);
|
||||||
|
lexer^.size := CHUNK_SIZE
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc lexer_current(lexer: PLexer) -> LexerToken;
|
||||||
|
var
|
||||||
|
current_class: TransitionClass;
|
||||||
|
current_state: TransitionState;
|
||||||
|
current_transition: Transition;
|
||||||
|
result: LexerToken;
|
||||||
|
index1: CARDINAL;
|
||||||
|
index2: CARDINAL;
|
||||||
|
begin
|
||||||
|
lexer^.current := lexer^.start;
|
||||||
|
current_state := transitionStateStart;
|
||||||
|
|
||||||
|
while current_state <> transitionStateEnd DO
|
||||||
|
index1 := ORD(lexer^.current.iterator^);
|
||||||
|
INC(index1);
|
||||||
|
current_class := classification[index1];
|
||||||
|
|
||||||
|
index1 := ORD(current_state);
|
||||||
|
INC(index1);
|
||||||
|
index2 := ORD(current_class);
|
||||||
|
INC(index2);
|
||||||
|
|
||||||
|
current_transition := transitions[index1][index2];
|
||||||
|
if current_transition.action <> nil then
|
||||||
|
current_transition.action(lexer, ADR(result))
|
||||||
|
end;
|
||||||
|
current_state := current_transition.next_state
|
||||||
|
end;
|
||||||
|
result.start_location := lexer^.start.location;
|
||||||
|
result.end_location := lexer^.current.location;
|
||||||
|
|
||||||
|
return result
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc lexer_lex(lexer: PLexer) -> LexerToken;
|
||||||
|
var
|
||||||
|
result: LexerToken;
|
||||||
|
begin
|
||||||
|
if lexer^.length = 0 then
|
||||||
|
lexer^.length := ReadNBytes(lexer^.input, CHUNK_SIZE, lexer^.buffer);
|
||||||
|
lexer^.current.location.column := 1;
|
||||||
|
lexer^.current.location.line := 1;
|
||||||
|
lexer^.current.iterator := lexer^.buffer
|
||||||
|
end;
|
||||||
|
lexer^.start := lexer^.current;
|
||||||
|
|
||||||
|
result := lexer_current(lexer);
|
||||||
|
return result
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc lexer_destroy(lexer: PLexer);
|
||||||
|
begin
|
||||||
|
DEALLOCATE(lexer^.buffer, lexer^.size)
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
initialize_classification();
|
||||||
|
initialize_transitions()
|
||||||
|
end.
|
200
source/Parser.def
Normal file
200
source/Parser.def
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
DEFINITION MODULE Parser;
|
||||||
|
|
||||||
|
FROM Common IMPORT Identifier, PIdentifier, ShortString;
|
||||||
|
FROM Lexer IMPORT PLexer;
|
||||||
|
|
||||||
|
TYPE
|
||||||
|
Parser = RECORD
|
||||||
|
lexer: PLexer
|
||||||
|
END;
|
||||||
|
PParser = POINTER TO Parser;
|
||||||
|
|
||||||
|
AstLiteralKind = (
|
||||||
|
astLiteralKindInteger,
|
||||||
|
astLiteralKindString,
|
||||||
|
astLiteralKindNull,
|
||||||
|
astLiteralKindBoolean
|
||||||
|
);
|
||||||
|
AstLiteral = RECORD
|
||||||
|
CASE kind: AstLiteralKind OF
|
||||||
|
astLiteralKindInteger: integer: INTEGER |
|
||||||
|
astLiteralKindString: string: ShortString |
|
||||||
|
astLiteralKindNull: |
|
||||||
|
astLiteralKindBoolean: boolean: BOOLEAN
|
||||||
|
END
|
||||||
|
END;
|
||||||
|
PAstLiteral = POINTER TO AstLiteral;
|
||||||
|
|
||||||
|
AstUnaryOperator = (
|
||||||
|
astUnaryOperatorReference,
|
||||||
|
astUnaryOperatorNot,
|
||||||
|
astUnaryOperatorMinus
|
||||||
|
);
|
||||||
|
AstBinaryOperator = (
|
||||||
|
astBinaryOperatorSum,
|
||||||
|
astBinaryOperatorSubtraction,
|
||||||
|
astBinaryOperatorMultiplication,
|
||||||
|
astBinaryOperatorDivision,
|
||||||
|
astBinaryOperatorRemainder,
|
||||||
|
astBinaryOperatorEquals,
|
||||||
|
astBinaryOperatorNotEquals,
|
||||||
|
astBinaryOperatorLess,
|
||||||
|
astBinaryOperatorGreater,
|
||||||
|
astBinaryOperatorLessEqual,
|
||||||
|
astBinaryOperatorGreaterEqual,
|
||||||
|
astBinaryOperatorDisjunction,
|
||||||
|
astBinaryOperatorConjunction,
|
||||||
|
astBinaryOperatorExclusiveDisjunction,
|
||||||
|
astBinaryOperatorShiftLeft,
|
||||||
|
astBinaryOperatorShiftRight
|
||||||
|
);
|
||||||
|
|
||||||
|
AstExpressionKind = (
|
||||||
|
astExpressionKindLiteral,
|
||||||
|
astExpressionKindIdentifier,
|
||||||
|
astExpressionKindArrayAccess,
|
||||||
|
astExpressionKindDereference,
|
||||||
|
astExpressionKindFieldAccess,
|
||||||
|
astExpressionKindUnary,
|
||||||
|
astExpressionKindBinary,
|
||||||
|
astExpressionKindCall
|
||||||
|
);
|
||||||
|
AstExpression = RECORD
|
||||||
|
CASE kind: AstExpressionKind OF
|
||||||
|
astExpressionKindLiteral: literal: PAstLiteral |
|
||||||
|
astExpressionKindIdentifier: identifier: Identifier |
|
||||||
|
astExpressionKindDereference: reference: PAstExpression |
|
||||||
|
astExpressionKindArrayAccess:
|
||||||
|
array: PAstExpression;
|
||||||
|
index: PAstExpression |
|
||||||
|
astExpressionKindFieldAccess:
|
||||||
|
aggregate: PAstExpression;
|
||||||
|
field: Identifier |
|
||||||
|
astExpressionKindUnary:
|
||||||
|
unary_operator: AstUnaryOperator;
|
||||||
|
unary_operand: PAstExpression |
|
||||||
|
astExpressionKindBinary:
|
||||||
|
binary_operator: AstBinaryOperator;
|
||||||
|
lhs: PAstExpression;
|
||||||
|
rhs: PAstExpression |
|
||||||
|
astExpressionKindCall:
|
||||||
|
callable: PAstExpression;
|
||||||
|
argument_count: CARDINAL;
|
||||||
|
arguments: PPAstExpression
|
||||||
|
END
|
||||||
|
END;
|
||||||
|
PAstExpression = POINTER TO AstExpression;
|
||||||
|
PPAstExpression = POINTER TO PAstExpression;
|
||||||
|
|
||||||
|
AstStatementKind = (
|
||||||
|
astStatementKindIf,
|
||||||
|
astStatementKindWhile,
|
||||||
|
astStatementKindAssignment,
|
||||||
|
astStatementKindReturn,
|
||||||
|
astStatementKindCall
|
||||||
|
);
|
||||||
|
AstStatement = RECORD
|
||||||
|
CASE kind: AstStatementKind OF
|
||||||
|
astStatementKindIf:
|
||||||
|
if_condition: PAstExpression;
|
||||||
|
if_branch: AstCompoundStatement |
|
||||||
|
astStatementKindWhile:
|
||||||
|
while_condition: PAstExpression;
|
||||||
|
while_body: AstCompoundStatement |
|
||||||
|
astStatementKindAssignment:
|
||||||
|
assignee: PAstExpression;
|
||||||
|
assignment: PAstExpression |
|
||||||
|
astStatementKindReturn: returned: PAstExpression |
|
||||||
|
astStatementKindCall: call: PAstExpression
|
||||||
|
END
|
||||||
|
END;
|
||||||
|
PAstStatement = POINTER TO AstStatement;
|
||||||
|
PPAstStatement = POINTER TO PAstStatement;
|
||||||
|
AstCompoundStatement = RECORD
|
||||||
|
count: CARDINAL;
|
||||||
|
statements: PPAstStatement
|
||||||
|
END;
|
||||||
|
|
||||||
|
AstImportStatement = RECORD
|
||||||
|
package: Identifier;
|
||||||
|
symbols: PIdentifier
|
||||||
|
END;
|
||||||
|
PAstImportStatement = POINTER TO AstImportStatement;
|
||||||
|
PPAstImportStatement = POINTER TO PAstImportStatement;
|
||||||
|
|
||||||
|
AstConstantDeclaration = RECORD
|
||||||
|
constant_name: Identifier;
|
||||||
|
constant_value: INTEGER
|
||||||
|
END;
|
||||||
|
PAstConstantDeclaration = POINTER TO AstConstantDeclaration;
|
||||||
|
PPAstConstantDeclaration = POINTER TO PAstConstantDeclaration;
|
||||||
|
|
||||||
|
AstFieldDeclaration = RECORD
|
||||||
|
field_name: Identifier;
|
||||||
|
field_type: PAstTypeExpression
|
||||||
|
END;
|
||||||
|
PAstFieldDeclaration = POINTER TO AstFieldDeclaration;
|
||||||
|
|
||||||
|
AstTypeExpressionKind = (
|
||||||
|
astTypeExpressionKindNamed,
|
||||||
|
astTypeExpressionKindRecord,
|
||||||
|
astTypeExpressionKindEnumeration,
|
||||||
|
astTypeExpressionKindArray,
|
||||||
|
astTypeExpressionKindPointer,
|
||||||
|
astTypeExpressionKindProcedure
|
||||||
|
);
|
||||||
|
AstTypeExpression = RECORD
|
||||||
|
CASE kind: AstTypeExpressionKind OF
|
||||||
|
astTypeExpressionKindNamed: name: Identifier |
|
||||||
|
astTypeExpressionKindEnumeration: cases: PIdentifier |
|
||||||
|
astTypeExpressionKindPointer: target: PAstTypeExpression |
|
||||||
|
astTypeExpressionKindRecord: fields: PAstFieldDeclaration |
|
||||||
|
astTypeExpressionKindArray:
|
||||||
|
base: PAstTypeExpression;
|
||||||
|
length: CARDINAL |
|
||||||
|
astTypeExpressionKindProcedure: parameters: PPAstTypeExpression
|
||||||
|
END
|
||||||
|
END;
|
||||||
|
PAstTypeExpression = POINTER TO AstTypeExpression;
|
||||||
|
PPAstTypeExpression = POINTER TO PAstTypeExpression;
|
||||||
|
|
||||||
|
AstTypedDeclaration = RECORD
|
||||||
|
identifier: Identifier;
|
||||||
|
type_expression: PAstTypeExpression
|
||||||
|
END;
|
||||||
|
PAstTypedDeclaration = POINTER TO AstTypedDeclaration;
|
||||||
|
PPAstTypedDeclaration = POINTER TO PAstTypedDeclaration;
|
||||||
|
|
||||||
|
AstVariableDeclaration = RECORD
|
||||||
|
variable_name: Identifier;
|
||||||
|
variable_type: PAstTypeExpression
|
||||||
|
END;
|
||||||
|
PAstVariableDeclaration = POINTER TO AstVariableDeclaration;
|
||||||
|
PPAstVariableDeclaration = POINTER TO PAstVariableDeclaration;
|
||||||
|
|
||||||
|
AstProcedureDeclaration = RECORD
|
||||||
|
name: Identifier;
|
||||||
|
parameter_count: CARDINAL;
|
||||||
|
parameters: PAstTypedDeclaration;
|
||||||
|
return_type: PAstTypeExpression;
|
||||||
|
constants: PPAstConstantDeclaration;
|
||||||
|
variables: PPAstVariableDeclaration;
|
||||||
|
statements: AstCompoundStatement
|
||||||
|
END;
|
||||||
|
PAstProcedureDeclaration = POINTER TO AstProcedureDeclaration;
|
||||||
|
PPAstProcedureDeclaration = POINTER TO PAstProcedureDeclaration;
|
||||||
|
|
||||||
|
AstModule = RECORD
|
||||||
|
main: BOOLEAN;
|
||||||
|
imports: PPAstImportStatement;
|
||||||
|
constants: PPAstConstantDeclaration;
|
||||||
|
types: PPAstTypedDeclaration;
|
||||||
|
variables: PPAstVariableDeclaration;
|
||||||
|
procedures: PPAstProcedureDeclaration;
|
||||||
|
statements: AstCompoundStatement
|
||||||
|
END;
|
||||||
|
PAstModule = POINTER TO AstModule;
|
||||||
|
|
||||||
|
PROCEDURE parse(lexer: PLexer): PAstModule;
|
||||||
|
|
||||||
|
END Parser.
|
1008
source/Parser.elna
Normal file
1008
source/Parser.elna
Normal file
File diff suppressed because it is too large
Load Diff
20
source/Transpiler.def
Normal file
20
source/Transpiler.def
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
DEFINITION MODULE Transpiler;
|
||||||
|
|
||||||
|
FROM FIO IMPORT File;
|
||||||
|
|
||||||
|
FROM Common IMPORT ShortString;
|
||||||
|
FROM Lexer IMPORT PLexer, Lexer;
|
||||||
|
FROM Parser IMPORT PAstModule;
|
||||||
|
|
||||||
|
TYPE
|
||||||
|
TranspilerContext = RECORD
|
||||||
|
input_name: ShortString;
|
||||||
|
output: File;
|
||||||
|
definition: File;
|
||||||
|
indentation: CARDINAL
|
||||||
|
END;
|
||||||
|
PTranspilerContext = POINTER TO TranspilerContext;
|
||||||
|
|
||||||
|
PROCEDURE transpile(ast_module: PAstModule; output: File; definition: File; input_name: ShortString);
|
||||||
|
|
||||||
|
END Transpiler.
|
658
source/Transpiler.elna
Normal file
658
source/Transpiler.elna
Normal file
@ -0,0 +1,658 @@
|
|||||||
|
module;
|
||||||
|
|
||||||
|
from FIO import WriteNBytes, WriteLine, WriteChar, WriteString;
|
||||||
|
from SYSTEM import ADR, TSIZE;
|
||||||
|
|
||||||
|
from NumberIO import IntToStr;
|
||||||
|
|
||||||
|
from Common import Identifier, PIdentifier, ShortString;
|
||||||
|
from Parser import AstTypeExpressionKind, AstExpressionKind, AstLiteralKind, AstUnaryOperator, AstBinaryOperator,
|
||||||
|
PAstModule, PPAstExpression, PAstExpression, PAstLiteral, PPAstProcedureDeclaration,
|
||||||
|
PAstConstantDeclaration, PPAstConstantDeclaration, PPAstStatement, PAstStatement, AstStatementKind,
|
||||||
|
AstTypedDeclaration, PAstTypedDeclaration, PPAstTypedDeclaration, AstCompoundStatement, PAstProcedureDeclaration,
|
||||||
|
PAstVariableDeclaration, PPAstVariableDeclaration, PAstImportStatement, PPAstImportStatement,
|
||||||
|
PAstTypeExpression, PPAstTypeExpression, AstFieldDeclaration, PAstFieldDeclaration;
|
||||||
|
|
||||||
|
proc indent(context: PTranspilerContext);
|
||||||
|
var
|
||||||
|
count: CARDINAL;
|
||||||
|
begin
|
||||||
|
count := 0;
|
||||||
|
|
||||||
|
while count < context^.indentation do
|
||||||
|
WriteString(context^.output, ' ');
|
||||||
|
INC(count)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
(* Write a semicolon followed by a newline. *)
|
||||||
|
proc write_semicolon(output: File);
|
||||||
|
begin
|
||||||
|
WriteChar(output, ';');
|
||||||
|
WriteLine(output)
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_import_statement(context: PTranspilerContext, import_statement: PAstImportStatement);
|
||||||
|
var
|
||||||
|
written_bytes: CARDINAL;
|
||||||
|
current_symbol: PIdentifier;
|
||||||
|
begin
|
||||||
|
WriteString(context^.output, 'FROM ');
|
||||||
|
written_bytes := WriteNBytes(context^.output, ORD(import_statement^.package[1]), ADR(import_statement^.package[2]));
|
||||||
|
|
||||||
|
WriteString(context^.output, ' IMPORT ');
|
||||||
|
|
||||||
|
current_symbol := import_statement^.symbols;
|
||||||
|
written_bytes := WriteNBytes(context^.output, ORD(current_symbol^[1]), ADR(current_symbol^[2]));
|
||||||
|
INC(current_symbol, TSIZE(Identifier));
|
||||||
|
|
||||||
|
while ORD(current_symbol^[1]) <> 0 do
|
||||||
|
WriteString(context^.output, ', ');
|
||||||
|
written_bytes := WriteNBytes(context^.output, ORD(current_symbol^[1]), ADR(current_symbol^[2]));
|
||||||
|
INC(current_symbol, TSIZE(Identifier))
|
||||||
|
end;
|
||||||
|
write_semicolon(context^.output)
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_import_part(context: PTranspilerContext, imports: PPAstImportStatement);
|
||||||
|
var
|
||||||
|
import_statement: PAstImportStatement;
|
||||||
|
begin
|
||||||
|
while imports^ <> nil do
|
||||||
|
transpile_import_statement(context, imports^);
|
||||||
|
INC(imports, TSIZE(PAstImportStatement))
|
||||||
|
end;
|
||||||
|
WriteLine(context^.output)
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_constant_declaration(context: PTranspilerContext, declaration: PAstConstantDeclaration);
|
||||||
|
var
|
||||||
|
buffer: [20]CHAR;
|
||||||
|
written_bytes: CARDINAL;
|
||||||
|
begin
|
||||||
|
WriteString(context^.output, ' ');
|
||||||
|
written_bytes := WriteNBytes(context^.output, ORD(declaration^.constant_name[1]), ADR(declaration^.constant_name[2]));
|
||||||
|
|
||||||
|
WriteString(context^.output, ' = ');
|
||||||
|
|
||||||
|
IntToStr(declaration^.constant_value, 0, buffer);
|
||||||
|
WriteString(context^.output, buffer);
|
||||||
|
|
||||||
|
write_semicolon(context^.output)
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_constant_part(context: PTranspilerContext, declarations: PPAstConstantDeclaration, extra_newline: BOOLEAN);
|
||||||
|
var
|
||||||
|
current_declaration: PPAstConstantDeclaration;
|
||||||
|
begin
|
||||||
|
if declarations^ <> nil then
|
||||||
|
WriteString(context^.output, 'CONST');
|
||||||
|
WriteLine(context^.output);
|
||||||
|
|
||||||
|
current_declaration := declarations;
|
||||||
|
while current_declaration^ <> nil do
|
||||||
|
transpile_constant_declaration(context, current_declaration^);
|
||||||
|
|
||||||
|
INC(current_declaration, TSIZE(PAstConstantDeclaration))
|
||||||
|
end;
|
||||||
|
if extra_newline then
|
||||||
|
WriteLine(context^.output)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_module(context: PTranspilerContext, result: PAstModule);
|
||||||
|
begin
|
||||||
|
if result^.main = false then
|
||||||
|
WriteString(context^.output, 'IMPLEMENTATION ')
|
||||||
|
end;
|
||||||
|
WriteString(context^.output, 'MODULE ');
|
||||||
|
|
||||||
|
(* Write the module name and end the line with a semicolon and newline. *)
|
||||||
|
transpile_module_name(context);
|
||||||
|
|
||||||
|
write_semicolon(context^.output);
|
||||||
|
WriteLine(context^.output);
|
||||||
|
|
||||||
|
(* Write the module body. *)
|
||||||
|
|
||||||
|
transpile_import_part(context, result^.imports);
|
||||||
|
transpile_constant_part(context, result^.constants, true);
|
||||||
|
transpile_type_part(context, result^.types);
|
||||||
|
transpile_variable_part(context, result^.variables, true);
|
||||||
|
transpile_procedure_part(context, result^.procedures);
|
||||||
|
transpile_statement_part(context, result^.statements);
|
||||||
|
|
||||||
|
WriteString(context^.output, 'END ');
|
||||||
|
transpile_module_name(context);
|
||||||
|
|
||||||
|
WriteChar(context^.output, '.');
|
||||||
|
WriteLine(context^.output)
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_type_fields(context: PTranspilerContext, fields: PAstFieldDeclaration);
|
||||||
|
var
|
||||||
|
written_bytes: CARDINAL;
|
||||||
|
current_field: PAstFieldDeclaration;
|
||||||
|
begin
|
||||||
|
current_field := fields;
|
||||||
|
|
||||||
|
while ORD(current_field^.field_name[1]) <> 0 do
|
||||||
|
WriteString(context^.output, ' ');
|
||||||
|
written_bytes := WriteNBytes(context^.output, ORD(current_field^.field_name[1]), ADR(current_field^.field_name[2]));
|
||||||
|
|
||||||
|
WriteString(context^.output, ': ');
|
||||||
|
transpile_type_expression(context, current_field^.field_type);
|
||||||
|
|
||||||
|
INC(current_field , TSIZE(AstFieldDeclaration));
|
||||||
|
|
||||||
|
if ORD(current_field^.field_name[1]) <> 0 then
|
||||||
|
WriteChar(context^.output, ';')
|
||||||
|
end;
|
||||||
|
WriteLine(context^.output)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_record_type(context: PTranspilerContext, type_expression: PAstTypeExpression);
|
||||||
|
begin
|
||||||
|
WriteString(context^.output, 'RECORD');
|
||||||
|
WriteLine(context^.output);
|
||||||
|
transpile_type_fields(context, type_expression^.fields);
|
||||||
|
WriteString(context^.output, ' END')
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_pointer_type(context: PTranspilerContext, type_expression: PAstTypeExpression);
|
||||||
|
begin
|
||||||
|
WriteString(context^.output, 'POINTER TO ');
|
||||||
|
|
||||||
|
transpile_type_expression(context, type_expression^.target)
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_array_type(context: PTranspilerContext, type_expression: PAstTypeExpression);
|
||||||
|
var
|
||||||
|
buffer: [20]CHAR;
|
||||||
|
begin
|
||||||
|
WriteString(context^.output, 'ARRAY');
|
||||||
|
|
||||||
|
if type_expression^.length <> 0 then
|
||||||
|
WriteString(context^.output, '[1..');
|
||||||
|
|
||||||
|
IntToStr(type_expression^.length, 0, buffer);
|
||||||
|
WriteString(context^.output, buffer);
|
||||||
|
|
||||||
|
WriteChar(context^.output, ']')
|
||||||
|
end;
|
||||||
|
WriteString(context^.output, ' OF ');
|
||||||
|
|
||||||
|
transpile_type_expression(context, type_expression^.base)
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_enumeration_type(context: PTranspilerContext, type_expression: PAstTypeExpression);
|
||||||
|
var
|
||||||
|
current_case: PIdentifier;
|
||||||
|
written_bytes: CARDINAL;
|
||||||
|
begin
|
||||||
|
current_case := type_expression^.cases;
|
||||||
|
|
||||||
|
WriteString(context^.output, '(');
|
||||||
|
WriteLine(context^.output);
|
||||||
|
WriteString(context^.output, ' ');
|
||||||
|
written_bytes := WriteNBytes(context^.output, ORD(current_case^[1]), ADR(current_case^[2]));
|
||||||
|
INC(current_case, TSIZE(Identifier));
|
||||||
|
|
||||||
|
while ORD(current_case^[1]) <> 0 do
|
||||||
|
WriteChar(context^.output, ',');
|
||||||
|
WriteLine(context^.output);
|
||||||
|
WriteString(context^.output, ' ');
|
||||||
|
written_bytes := WriteNBytes(context^.output, ORD(current_case^[1]), ADR(current_case^[2]));
|
||||||
|
|
||||||
|
INC(current_case, TSIZE(Identifier))
|
||||||
|
end;
|
||||||
|
WriteLine(context^.output);
|
||||||
|
WriteString(context^.output, ' )')
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_named_type(context: PTranspilerContext, type_expression: PAstTypeExpression);
|
||||||
|
var
|
||||||
|
written_bytes: CARDINAL;
|
||||||
|
begin
|
||||||
|
written_bytes := WriteNBytes(context^.output, ORD(type_expression^.name[1]), ADR(type_expression^.name[2]))
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_procedure_type(context: PTranspilerContext, type_expression: PAstTypeExpression);
|
||||||
|
var
|
||||||
|
result: PAstTypeExpression;
|
||||||
|
current_parameter: PPAstTypeExpression;
|
||||||
|
parameter_count: CARDINAL;
|
||||||
|
begin
|
||||||
|
WriteString(context^.output, 'PROCEDURE(');
|
||||||
|
current_parameter := type_expression^.parameters;
|
||||||
|
|
||||||
|
while current_parameter^ <> nil do
|
||||||
|
transpile_type_expression(context, current_parameter^);
|
||||||
|
|
||||||
|
INC(current_parameter, TSIZE(PAstTypeExpression));
|
||||||
|
|
||||||
|
if current_parameter^ <> nil then
|
||||||
|
WriteString(context^.output, ', ')
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
WriteChar(context^.output, ')')
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_type_expression(context: PTranspilerContext, type_expression: PAstTypeExpression);
|
||||||
|
begin
|
||||||
|
if type_expression^.kind = astTypeExpressionKindRecord then
|
||||||
|
transpile_record_type(context, type_expression)
|
||||||
|
end;
|
||||||
|
if type_expression^.kind = astTypeExpressionKindEnumeration then
|
||||||
|
transpile_enumeration_type(context, type_expression)
|
||||||
|
end;
|
||||||
|
if type_expression^.kind = astTypeExpressionKindArray then
|
||||||
|
transpile_array_type(context, type_expression)
|
||||||
|
end;
|
||||||
|
if type_expression^.kind = astTypeExpressionKindPointer then
|
||||||
|
transpile_pointer_type(context, type_expression)
|
||||||
|
end;
|
||||||
|
if type_expression^.kind = astTypeExpressionKindProcedure then
|
||||||
|
transpile_procedure_type(context, type_expression)
|
||||||
|
end;
|
||||||
|
if type_expression^.kind = astTypeExpressionKindNamed then
|
||||||
|
transpile_named_type(context, type_expression)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_type_declaration(context: PTranspilerContext, declaration: PAstTypedDeclaration);
|
||||||
|
var
|
||||||
|
written_bytes: CARDINAL;
|
||||||
|
begin
|
||||||
|
WriteString(context^.output, ' ');
|
||||||
|
|
||||||
|
written_bytes := WriteNBytes(context^.output, ORD(declaration^.identifier[1]), ADR(declaration^.identifier[2]));
|
||||||
|
WriteString(context^.output, ' = ');
|
||||||
|
|
||||||
|
transpile_type_expression(context, declaration^.type_expression);
|
||||||
|
write_semicolon(context^.output)
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_type_part(context: PTranspilerContext, declarations: PPAstTypedDeclaration);
|
||||||
|
var
|
||||||
|
current_declaration: PPAstTypedDeclaration;
|
||||||
|
begin
|
||||||
|
if declarations^ <> nil then
|
||||||
|
WriteString(context^.output, 'TYPE');
|
||||||
|
WriteLine(context^.output);
|
||||||
|
|
||||||
|
current_declaration := declarations;
|
||||||
|
while current_declaration^ <> nil do
|
||||||
|
transpile_type_declaration(context, current_declaration^);
|
||||||
|
|
||||||
|
INC(current_declaration, TSIZE(PAstTypedDeclaration))
|
||||||
|
end;
|
||||||
|
WriteLine(context^.output)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_variable_declaration(context: PTranspilerContext, declaration: PAstVariableDeclaration);
|
||||||
|
var
|
||||||
|
written_bytes: CARDINAL;
|
||||||
|
begin
|
||||||
|
WriteString(context^.output, ' ');
|
||||||
|
written_bytes := WriteNBytes(context^.output, ORD(declaration^.variable_name[1]), ADR(declaration^.variable_name[2]));
|
||||||
|
|
||||||
|
WriteString(context^.output, ': ');
|
||||||
|
|
||||||
|
transpile_type_expression(context, declaration^.variable_type);
|
||||||
|
write_semicolon(context^.output)
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_variable_part(context: PTranspilerContext, declarations: PPAstVariableDeclaration, extra_newline: BOOLEAN);
|
||||||
|
var
|
||||||
|
current_declaration: PPAstVariableDeclaration;
|
||||||
|
begin
|
||||||
|
if declarations^ <> nil then
|
||||||
|
WriteString(context^.output, 'VAR');
|
||||||
|
WriteLine(context^.output);
|
||||||
|
|
||||||
|
current_declaration := declarations;
|
||||||
|
while current_declaration^ <> nil do
|
||||||
|
transpile_variable_declaration(context, current_declaration^);
|
||||||
|
|
||||||
|
INC(current_declaration, TSIZE(PAstVariableDeclaration))
|
||||||
|
end;
|
||||||
|
if extra_newline then
|
||||||
|
WriteLine(context^.output)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_procedure_heading(context: PTranspilerContext, declaration: PAstProcedureDeclaration);
|
||||||
|
var
|
||||||
|
written_bytes: CARDINAL;
|
||||||
|
parameter_index: CARDINAL;
|
||||||
|
current_parameter: PAstTypedDeclaration;
|
||||||
|
begin
|
||||||
|
WriteString(context^.output, 'PROCEDURE ');
|
||||||
|
written_bytes := WriteNBytes(context^.output, ORD(declaration^.name[1]), ADR(declaration^.name[2]));
|
||||||
|
WriteChar(context^.output, '(');
|
||||||
|
|
||||||
|
parameter_index := 0;
|
||||||
|
current_parameter := declaration^.parameters;
|
||||||
|
|
||||||
|
while parameter_index < declaration^.parameter_count do
|
||||||
|
written_bytes := WriteNBytes(context^.output, ORD(current_parameter^.identifier[1]), ADR(current_parameter^.identifier[2]));
|
||||||
|
WriteString(context^.output, ': ');
|
||||||
|
transpile_type_expression(context, current_parameter^.type_expression);
|
||||||
|
|
||||||
|
INC(parameter_index);
|
||||||
|
INC(current_parameter, TSIZE(AstTypedDeclaration));
|
||||||
|
|
||||||
|
if parameter_index <> declaration^.parameter_count then
|
||||||
|
WriteString(context^.output, '; ')
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
WriteString(context^.output, ')');
|
||||||
|
|
||||||
|
(* Check for the return type and write it. *)
|
||||||
|
if declaration^.return_type <> nil then
|
||||||
|
WriteString(context^.output, ': ');
|
||||||
|
transpile_type_expression(context, declaration^.return_type)
|
||||||
|
end;
|
||||||
|
write_semicolon(context^.output)
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_unary_operator(context: PTranspilerContext, operator: AstUnaryOperator);
|
||||||
|
begin
|
||||||
|
if operator = astUnaryOperatorMinus then
|
||||||
|
WriteChar(context^.output, '-')
|
||||||
|
end;
|
||||||
|
if operator = astUnaryOperatorNot then
|
||||||
|
WriteChar(context^.output, '~')
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_binary_operator(context: PTranspilerContext, operator: AstBinaryOperator);
|
||||||
|
begin
|
||||||
|
if operator = astBinaryOperatorSum then
|
||||||
|
WriteChar(context^.output, '+')
|
||||||
|
end;
|
||||||
|
if operator = astBinaryOperatorSubtraction then
|
||||||
|
WriteChar(context^.output, '-')
|
||||||
|
end;
|
||||||
|
if operator = astBinaryOperatorMultiplication then
|
||||||
|
WriteChar(context^.output, '*')
|
||||||
|
end;
|
||||||
|
if operator = astBinaryOperatorEquals then
|
||||||
|
WriteChar(context^.output, '=')
|
||||||
|
end;
|
||||||
|
if operator = astBinaryOperatorNotEquals then
|
||||||
|
WriteChar(context^.output, '#')
|
||||||
|
end;
|
||||||
|
if operator = astBinaryOperatorLess then
|
||||||
|
WriteChar(context^.output, '<')
|
||||||
|
end;
|
||||||
|
if operator = astBinaryOperatorGreater then
|
||||||
|
WriteChar(context^.output, '>')
|
||||||
|
end;
|
||||||
|
if operator = astBinaryOperatorLessEqual then
|
||||||
|
WriteString(context^.output, '<=')
|
||||||
|
end;
|
||||||
|
if operator = astBinaryOperatorGreaterEqual then
|
||||||
|
WriteString(context^.output, '>=')
|
||||||
|
end;
|
||||||
|
if operator = astBinaryOperatorDisjunction then
|
||||||
|
WriteString(context^.output, 'OR')
|
||||||
|
end;
|
||||||
|
if operator = astBinaryOperatorConjunction then
|
||||||
|
WriteString(context^.output, 'AND')
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_expression(context: PTranspilerContext, expression: PAstExpression);
|
||||||
|
var
|
||||||
|
literal: PAstLiteral;
|
||||||
|
buffer: [20]CHAR;
|
||||||
|
written_bytes: CARDINAL;
|
||||||
|
argument_index: CARDINAL;
|
||||||
|
current_argument: PPAstExpression;
|
||||||
|
begin
|
||||||
|
if expression^.kind = astExpressionKindLiteral then
|
||||||
|
literal := expression^.literal;
|
||||||
|
|
||||||
|
if literal^.kind = astLiteralKindInteger then
|
||||||
|
IntToStr(literal^.integer, 0, buffer);
|
||||||
|
WriteString(context^.output, buffer)
|
||||||
|
end;
|
||||||
|
if literal^.kind = astLiteralKindString then
|
||||||
|
WriteString(context^.output, literal^.string)
|
||||||
|
end;
|
||||||
|
if literal^.kind = astLiteralKindNull then
|
||||||
|
WriteString(context^.output, 'NIL')
|
||||||
|
end;
|
||||||
|
if (literal^.kind = astLiteralKindBoolean) & literal^.boolean then
|
||||||
|
WriteString(context^.output, 'TRUE')
|
||||||
|
end;
|
||||||
|
if (literal^.kind = astLiteralKindBoolean) & (literal^.boolean = false) then
|
||||||
|
WriteString(context^.output, 'FALSE')
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
if expression^.kind = astExpressionKindIdentifier then
|
||||||
|
written_bytes := WriteNBytes(context^.output, ORD(expression^.identifier[1]), ADR(expression^.identifier[2]))
|
||||||
|
end;
|
||||||
|
if expression^.kind = astExpressionKindDereference then
|
||||||
|
transpile_expression(context, expression^.reference);
|
||||||
|
WriteChar(context^.output, '^')
|
||||||
|
end;
|
||||||
|
if expression^.kind = astExpressionKindArrayAccess then
|
||||||
|
transpile_expression(context, expression^.array);
|
||||||
|
WriteChar(context^.output, '[');
|
||||||
|
transpile_expression(context, expression^.index);
|
||||||
|
WriteChar(context^.output, ']')
|
||||||
|
end;
|
||||||
|
if expression^.kind = astExpressionKindFieldAccess then
|
||||||
|
transpile_expression(context, expression^.aggregate);
|
||||||
|
WriteChar(context^.output, '.');
|
||||||
|
written_bytes := WriteNBytes(context^.output, ORD(expression^.field[1]), ADR(expression^.field[2]))
|
||||||
|
end;
|
||||||
|
if expression^.kind = astExpressionKindUnary then
|
||||||
|
transpile_unary_operator(context, expression^.unary_operator);
|
||||||
|
transpile_expression(context, expression^.unary_operand)
|
||||||
|
end;
|
||||||
|
if expression^.kind = astExpressionKindBinary then
|
||||||
|
WriteChar(context^.output, '(');
|
||||||
|
transpile_expression(context, expression^.lhs);
|
||||||
|
WriteChar(context^.output, ' ');
|
||||||
|
transpile_binary_operator(context, expression^.binary_operator);
|
||||||
|
WriteChar(context^.output, ' ');
|
||||||
|
transpile_expression(context, expression^.rhs);
|
||||||
|
WriteChar(context^.output, ')')
|
||||||
|
end;
|
||||||
|
if expression^.kind = astExpressionKindCall then
|
||||||
|
transpile_expression(context, expression^.callable);
|
||||||
|
WriteChar(context^.output, '(');
|
||||||
|
|
||||||
|
current_argument := expression^.arguments;
|
||||||
|
if expression^.argument_count > 0 then
|
||||||
|
transpile_expression(context, current_argument^);
|
||||||
|
|
||||||
|
argument_index := 1;
|
||||||
|
INC(current_argument, TSIZE(PAstExpression));
|
||||||
|
|
||||||
|
while argument_index < expression^.argument_count do
|
||||||
|
WriteString(context^.output, ', ');
|
||||||
|
|
||||||
|
transpile_expression(context, current_argument^);
|
||||||
|
|
||||||
|
INC(current_argument, TSIZE(PAstExpression));
|
||||||
|
INC(argument_index)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
WriteChar(context^.output, ')')
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_if_statement(context: PTranspilerContext, statement: PAstStatement);
|
||||||
|
begin
|
||||||
|
WriteString(context^.output, 'IF ');
|
||||||
|
transpile_expression(context, statement^.if_condition);
|
||||||
|
|
||||||
|
WriteString(context^.output, ' THEN');
|
||||||
|
WriteLine(context^.output);
|
||||||
|
INC(context^.indentation);
|
||||||
|
|
||||||
|
transpile_compound_statement(context, statement^.if_branch);
|
||||||
|
DEC(context^.indentation);
|
||||||
|
indent(context);
|
||||||
|
WriteString(context^.output, 'END')
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_while_statement(context: PTranspilerContext, statement: PAstStatement);
|
||||||
|
begin
|
||||||
|
WriteString(context^.output, 'WHILE ');
|
||||||
|
transpile_expression(context, statement^.while_condition);
|
||||||
|
|
||||||
|
WriteString(context^.output, ' DO');
|
||||||
|
WriteLine(context^.output);
|
||||||
|
INC(context^.indentation);
|
||||||
|
|
||||||
|
transpile_compound_statement(context, statement^.while_body);
|
||||||
|
DEC(context^.indentation);
|
||||||
|
indent(context);
|
||||||
|
WriteString(context^.output, 'END')
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_assignment_statement(context: PTranspilerContext, statement: PAstStatement);
|
||||||
|
begin
|
||||||
|
transpile_expression(context, statement^.assignee);
|
||||||
|
WriteString(context^.output, ' := ');
|
||||||
|
transpile_expression(context, statement^.assignment)
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_return_statement(context: PTranspilerContext, statement: PAstStatement);
|
||||||
|
begin
|
||||||
|
WriteString(context^.output, 'RETURN ');
|
||||||
|
|
||||||
|
transpile_expression(context, statement^.returned)
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_compound_statement(context: PTranspilerContext, statement: AstCompoundStatement);
|
||||||
|
var
|
||||||
|
current_statement: PPAstStatement;
|
||||||
|
index: CARDINAL;
|
||||||
|
begin
|
||||||
|
index := 0;
|
||||||
|
current_statement := statement.statements;
|
||||||
|
|
||||||
|
while index < statement.count do
|
||||||
|
transpile_statement(context, current_statement^);
|
||||||
|
|
||||||
|
INC(current_statement, TSIZE(PAstStatement));
|
||||||
|
INC(index);
|
||||||
|
|
||||||
|
if index <> statement.count then
|
||||||
|
WriteChar(context^.output, ';')
|
||||||
|
end;
|
||||||
|
WriteLine(context^.output)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_statement(context: PTranspilerContext, statement: PAstStatement);
|
||||||
|
begin
|
||||||
|
indent(context);
|
||||||
|
|
||||||
|
if statement^.kind = astStatementKindIf then
|
||||||
|
transpile_if_statement(context, statement)
|
||||||
|
end;
|
||||||
|
if statement^.kind = astStatementKindWhile then
|
||||||
|
transpile_while_statement(context, statement)
|
||||||
|
end;
|
||||||
|
if statement^.kind = astStatementKindReturn then
|
||||||
|
transpile_return_statement(context, statement)
|
||||||
|
end;
|
||||||
|
if statement^.kind = astStatementKindAssignment then
|
||||||
|
transpile_assignment_statement(context, statement)
|
||||||
|
end;
|
||||||
|
if statement^.kind = astStatementKindCall then
|
||||||
|
transpile_expression(context, statement^.call)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_statement_part(context: PTranspilerContext, compound: AstCompoundStatement);
|
||||||
|
begin
|
||||||
|
if compound.count > 0 then
|
||||||
|
WriteString(context^.output, 'BEGIN');
|
||||||
|
WriteLine(context^.output);
|
||||||
|
|
||||||
|
INC(context^.indentation);
|
||||||
|
transpile_compound_statement(context, compound);
|
||||||
|
DEC(context^.indentation)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_procedure_declaration(context: PTranspilerContext, declaration: PAstProcedureDeclaration);
|
||||||
|
var
|
||||||
|
written_bytes: CARDINAL;
|
||||||
|
begin
|
||||||
|
transpile_procedure_heading(context, declaration);
|
||||||
|
|
||||||
|
transpile_constant_part(context, declaration^.constants, false);
|
||||||
|
transpile_variable_part(context, declaration^.variables, false);
|
||||||
|
transpile_statement_part(context, declaration^.statements);
|
||||||
|
|
||||||
|
WriteString(context^.output, 'END ');
|
||||||
|
written_bytes := WriteNBytes(context^.output, ORD(declaration^.name[1]), ADR(declaration^.name[2]));
|
||||||
|
|
||||||
|
write_semicolon(context^.output)
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_procedure_part(context: PTranspilerContext, declaration: PPAstProcedureDeclaration);
|
||||||
|
begin
|
||||||
|
while declaration^ <> nil do
|
||||||
|
transpile_procedure_declaration(context, declaration^);
|
||||||
|
WriteLine(context^.output);
|
||||||
|
|
||||||
|
INC(declaration, TSIZE(PAstProcedureDeclaration))
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile_module_name(context: PTranspilerContext);
|
||||||
|
var
|
||||||
|
counter: CARDINAL;
|
||||||
|
last_slash: CARDINAL;
|
||||||
|
begin
|
||||||
|
counter := 1;
|
||||||
|
last_slash := 0;
|
||||||
|
|
||||||
|
while (context^.input_name[counter] <> '.') & (ORD(context^.input_name[counter]) <> 0) do
|
||||||
|
if context^.input_name[counter] = '/' then
|
||||||
|
last_slash := counter
|
||||||
|
end;
|
||||||
|
INC(counter)
|
||||||
|
end;
|
||||||
|
|
||||||
|
if last_slash = 0 then
|
||||||
|
counter := 1
|
||||||
|
end;
|
||||||
|
if last_slash <> 0 then
|
||||||
|
counter := last_slash + 1
|
||||||
|
end;
|
||||||
|
while (context^.input_name[counter] <> '.') & (ORD(context^.input_name[counter]) <> 0) do
|
||||||
|
WriteChar(context^.output, context^.input_name[counter]);
|
||||||
|
INC(counter)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc transpile(ast_module: PAstModule, output: File, definition: File, input_name: ShortString);
|
||||||
|
var
|
||||||
|
context: TranspilerContext;
|
||||||
|
begin
|
||||||
|
context.input_name := input_name;
|
||||||
|
context.output := output;
|
||||||
|
context.definition := definition;
|
||||||
|
context.indentation := 0;
|
||||||
|
|
||||||
|
transpile_module(ADR(context), ast_module)
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
@ -1,17 +1,17 @@
|
|||||||
(* This Source Code Form is subject to the terms of the Mozilla Public License,
|
(* This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||||
v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||||
obtain one at https://mozilla.org/MPL/2.0/. *)
|
obtain one at https://mozilla.org/MPL/2.0/. *)
|
||||||
program
|
program;
|
||||||
|
|
||||||
import dummy
|
import dummy;
|
||||||
|
|
||||||
const
|
const
|
||||||
SEEK_SET* := 0
|
SEEK_SET* := 0;
|
||||||
SEEK_CUR* := 1
|
SEEK_CUR* := 1;
|
||||||
SEEK_END* := 2
|
SEEK_END* := 2;
|
||||||
STDIN := 0
|
STDIN := 0;
|
||||||
STDOUT := 1
|
STDOUT := 1;
|
||||||
STDERR := 2
|
STDERR := 2;
|
||||||
|
|
||||||
type
|
type
|
||||||
TokenKind* = (
|
TokenKind* = (
|
||||||
@ -79,82 +79,82 @@ type
|
|||||||
_program,
|
_program,
|
||||||
_module,
|
_module,
|
||||||
_import
|
_import
|
||||||
)
|
);
|
||||||
Position* = record
|
Position* = record
|
||||||
line: Word
|
line: Word;
|
||||||
column: Word
|
column: Word
|
||||||
end
|
end;
|
||||||
Location* = record
|
Location* = record
|
||||||
first: Position
|
first: Position;
|
||||||
last: Position
|
last: Position
|
||||||
end
|
end;
|
||||||
SourceFile* = record
|
SourceFile* = record
|
||||||
buffer: [1024]Char
|
buffer: [1024]Char;
|
||||||
handle: ^FILE
|
handle: ^FILE;
|
||||||
size: Word
|
size: Word;
|
||||||
index: Word
|
index: Word
|
||||||
end
|
end;
|
||||||
FILE* = record end
|
FILE* = record end;
|
||||||
StringBuffer* = record
|
StringBuffer* = record
|
||||||
data: Pointer
|
data: Pointer;
|
||||||
size: Word
|
size: Word;
|
||||||
capacity: Word
|
capacity: Word
|
||||||
end
|
end;
|
||||||
SourceCode = record
|
SourceCode = record
|
||||||
position: Position
|
position: Position;
|
||||||
|
|
||||||
input: Pointer
|
input: Pointer;
|
||||||
empty: proc(Pointer) -> Bool
|
empty: proc(Pointer) -> Bool;
|
||||||
advance: proc(Pointer)
|
advance: proc(Pointer);
|
||||||
head: proc(Pointer) -> Char
|
head: proc(Pointer) -> Char
|
||||||
end
|
end;
|
||||||
Token* = record
|
Token* = record
|
||||||
kind: TokenKind
|
kind: TokenKind;
|
||||||
value: union
|
value: union
|
||||||
int_value: Int
|
int_value: Int;
|
||||||
string: String
|
string: String;
|
||||||
boolean_value: Bool
|
boolean_value: Bool;
|
||||||
char_value: Char
|
char_value: Char
|
||||||
end
|
end;
|
||||||
location: Location
|
location: Location
|
||||||
end
|
end;
|
||||||
CommandLine* = record
|
CommandLine* = record
|
||||||
input: ^Char
|
input: ^Char;
|
||||||
lex: Bool
|
lex: Bool;
|
||||||
parse: Bool
|
parse: Bool
|
||||||
end
|
end;
|
||||||
Lexer* = record
|
Lexer* = record
|
||||||
length: Word
|
length: Word;
|
||||||
data: ^Token
|
data: ^Token
|
||||||
end
|
end;
|
||||||
|
|
||||||
(*
|
(*
|
||||||
External procedures.
|
External procedures.
|
||||||
*)
|
*)
|
||||||
|
|
||||||
proc fopen(pathname: ^Char, mode: ^Char) -> ^FILE; extern
|
proc fopen(pathname: ^Char, mode: ^Char) -> ^FILE; extern;
|
||||||
proc fclose(stream: ^FILE) -> Int; extern
|
proc fclose(stream: ^FILE) -> Int; extern;
|
||||||
proc fseek(stream: ^FILE, off: Int, whence: Int) -> Int; extern
|
proc fseek(stream: ^FILE, off: Int, whence: Int) -> Int; extern;
|
||||||
proc rewind(stream: ^FILE); extern
|
proc rewind(stream: ^FILE); extern;
|
||||||
proc ftell(stream: ^FILE) -> Int; extern
|
proc ftell(stream: ^FILE) -> Int; extern;
|
||||||
proc fread(ptr: Pointer, size: Word, nmemb: Word, stream: ^FILE) -> Word; extern
|
proc fread(ptr: Pointer, size: Word, nmemb: Word, stream: ^FILE) -> Word; extern;
|
||||||
proc write(fd: Int, buf: Pointer, Word: Int) -> Int; extern
|
proc write(fd: Int, buf: Pointer, Word: Int) -> Int; extern;
|
||||||
|
|
||||||
proc malloc(size: Word) -> Pointer; extern
|
proc malloc(size: Word) -> Pointer; extern;
|
||||||
proc free(ptr: Pointer); extern
|
proc free(ptr: Pointer); extern;
|
||||||
proc calloc(nmemb: Word, size: Word) -> Pointer; extern
|
proc calloc(nmemb: Word, size: Word) -> Pointer; extern;
|
||||||
proc realloc(ptr: Pointer, size: Word) -> Pointer; extern
|
proc realloc(ptr: Pointer, size: Word) -> Pointer; extern;
|
||||||
|
|
||||||
proc memset(ptr: ^Char, c: Int, n: Int) -> ^Char; extern
|
proc memset(ptr: ^Char, c: Int, n: Int) -> ^Char; extern;
|
||||||
|
|
||||||
proc strcmp(s1: ^Char, s2: ^Char) -> Int; extern
|
proc strcmp(s1: ^Char, s2: ^Char) -> Int; extern;
|
||||||
proc strncmp(s1: ^Char, s2: ^Char, n: Word) -> Int; extern
|
proc strncmp(s1: ^Char, s2: ^Char, n: Word) -> Int; extern;
|
||||||
proc strncpy(dst: ^Char, src: ^Char, dsize: Word) -> ^Char; extern
|
proc strncpy(dst: ^Char, src: ^Char, dsize: Word) -> ^Char; extern;
|
||||||
proc strcpy(dst: ^Char, src: ^Char) -> ^Char; extern
|
proc strcpy(dst: ^Char, src: ^Char) -> ^Char; extern;
|
||||||
proc strlen(ptr: ^Char) -> Word; extern
|
proc strlen(ptr: ^Char) -> Word; extern;
|
||||||
|
|
||||||
proc perror(s: ^Char); extern
|
proc perror(s: ^Char); extern;
|
||||||
proc exit(code: Int) -> !; extern
|
proc exit(code: Int) -> !; extern;
|
||||||
|
|
||||||
(*
|
(*
|
||||||
Standard procedures.
|
Standard procedures.
|
||||||
@ -162,17 +162,17 @@ proc exit(code: Int) -> !; extern
|
|||||||
|
|
||||||
proc reallocarray(ptr: Pointer, n: Word, size: Word) -> Pointer;
|
proc reallocarray(ptr: Pointer, n: Word, size: Word) -> Pointer;
|
||||||
return realloc(ptr, n * size)
|
return realloc(ptr, n * size)
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc write_s(value: String);
|
proc write_s(value: String);
|
||||||
begin
|
begin
|
||||||
write(0, cast(value.ptr: Pointer), cast(value.length: Int))
|
write(0, cast(value.ptr: Pointer), cast(value.length: Int))
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc write_z(value: ^Char);
|
proc write_z(value: ^Char);
|
||||||
begin
|
begin
|
||||||
write(0, cast(value: Pointer), cast(strlen(value): Int))
|
write(0, cast(value: Pointer), cast(strlen(value): Int))
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc write_b(value: Bool);
|
proc write_b(value: Bool);
|
||||||
begin
|
begin
|
||||||
@ -181,18 +181,18 @@ begin
|
|||||||
else
|
else
|
||||||
write_s("false")
|
write_s("false")
|
||||||
end
|
end
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc write_c(value: Char);
|
proc write_c(value: Char);
|
||||||
begin
|
begin
|
||||||
write(0, cast(@value: Pointer), 1)
|
write(0, cast(@value: Pointer), 1)
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc write_i(value: Int);
|
proc write_i(value: Int);
|
||||||
var
|
var
|
||||||
digit: Int
|
digit: Int;
|
||||||
n: Word
|
n: Word;
|
||||||
buffer: [10]Char
|
buffer: [10]Char;
|
||||||
begin
|
begin
|
||||||
n := 10u;
|
n := 10u;
|
||||||
|
|
||||||
@ -210,57 +210,57 @@ begin
|
|||||||
n := n + 1u;
|
n := n + 1u;
|
||||||
write_c(buffer[n])
|
write_c(buffer[n])
|
||||||
end
|
end
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc write_u(value: Word);
|
proc write_u(value: Word);
|
||||||
begin
|
begin
|
||||||
write_i(cast(value: Int))
|
write_i(cast(value: Int))
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc is_digit(c: Char) -> Bool;
|
proc is_digit(c: Char) -> Bool;
|
||||||
return cast(c: Int) >= cast('0': Int) & cast(c: Int) <= cast('9': Int)
|
return cast(c: Int) >= cast('0': Int) & cast(c: Int) <= cast('9': Int)
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc is_alpha(c: Char) -> Bool;
|
proc is_alpha(c: Char) -> Bool;
|
||||||
return cast(c: Int) >= cast('A': Int) & cast(c: Int) <= cast('z': Int)
|
return cast(c: Int) >= cast('A': Int) & cast(c: Int) <= cast('z': Int)
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc is_alnum(c: Char) -> Bool;
|
proc is_alnum(c: Char) -> Bool;
|
||||||
return is_digit(c) or is_alpha(c)
|
return is_digit(c) or is_alpha(c)
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc is_space(c: Char) -> Bool;
|
proc is_space(c: Char) -> Bool;
|
||||||
return c = ' ' or c = '\n' or c = '\t'
|
return c = ' ' or c = '\n' or c = '\t'
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc substring(string: String, start: Word, count: Word) -> String;
|
proc substring(string: String, start: Word, count: Word) -> String;
|
||||||
return String(string.ptr + start, count)
|
return String(string.ptr + start, count)
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc open_substring(string: String, start: Word) -> String;
|
proc open_substring(string: String, start: Word) -> String;
|
||||||
return substring(string, start, string.length - start)
|
return substring(string, start, string.length - start)
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc string_dup(origin: String) -> String;
|
proc string_dup(origin: String) -> String;
|
||||||
var
|
var
|
||||||
copy: ^Char
|
copy: ^Char;
|
||||||
begin
|
begin
|
||||||
copy := cast(malloc(origin.length): ^Char);
|
copy := cast(malloc(origin.length): ^Char);
|
||||||
strncpy(copy, origin.ptr, origin.length);
|
strncpy(copy, origin.ptr, origin.length);
|
||||||
|
|
||||||
return String(copy, origin.length)
|
return String(copy, origin.length)
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc string_buffer_new() -> StringBuffer;
|
proc string_buffer_new() -> StringBuffer;
|
||||||
var
|
var
|
||||||
result: StringBuffer
|
result: StringBuffer;
|
||||||
begin
|
begin
|
||||||
result.capacity := 64u;
|
result.capacity := 64u;
|
||||||
result.data := malloc(result.capacity);
|
result.data := malloc(result.capacity);
|
||||||
result.size := 0u;
|
result.size := 0u;
|
||||||
|
|
||||||
return result
|
return result
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc string_buffer_push(buffer: ^StringBuffer, char: Char);
|
proc string_buffer_push(buffer: ^StringBuffer, char: Char);
|
||||||
begin
|
begin
|
||||||
@ -270,21 +270,21 @@ begin
|
|||||||
end;
|
end;
|
||||||
cast(buffer^.data + buffer^.size: ^Char)^ := cast(char: Char);
|
cast(buffer^.data + buffer^.size: ^Char)^ := cast(char: Char);
|
||||||
buffer^.size := buffer^.size + 1u
|
buffer^.size := buffer^.size + 1u
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc string_buffer_pop(buffer: ^StringBuffer, count: Word);
|
proc string_buffer_pop(buffer: ^StringBuffer, count: Word);
|
||||||
begin
|
begin
|
||||||
buffer^.size := buffer^.size - count
|
buffer^.size := buffer^.size - count
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc string_buffer_clear(buffer: ^StringBuffer) -> String;
|
proc string_buffer_clear(buffer: ^StringBuffer) -> String;
|
||||||
var
|
var
|
||||||
result: String
|
result: String;
|
||||||
begin
|
begin
|
||||||
result := String(cast(buffer^.data: ^Char), buffer^.size);
|
result := String(cast(buffer^.data: ^Char), buffer^.size);
|
||||||
buffer^.size := 0u;
|
buffer^.size := 0u;
|
||||||
return result
|
return result
|
||||||
end
|
end;
|
||||||
|
|
||||||
(*
|
(*
|
||||||
Source code stream procedures.
|
Source code stream procedures.
|
||||||
@ -292,8 +292,8 @@ end
|
|||||||
|
|
||||||
proc read_source(filename: ^Char) -> ^SourceFile;
|
proc read_source(filename: ^Char) -> ^SourceFile;
|
||||||
var
|
var
|
||||||
result: ^SourceFile
|
result: ^SourceFile;
|
||||||
file_handle: ^FILE
|
file_handle: ^FILE;
|
||||||
begin
|
begin
|
||||||
file_handle := fopen(filename, "rb\0".ptr);
|
file_handle := fopen(filename, "rb\0".ptr);
|
||||||
|
|
||||||
@ -304,11 +304,11 @@ begin
|
|||||||
result^.index := 1u
|
result^.index := 1u
|
||||||
end;
|
end;
|
||||||
return result
|
return result
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc source_file_empty(source_input: Pointer) -> Bool;
|
proc source_file_empty(source_input: Pointer) -> Bool;
|
||||||
var
|
var
|
||||||
source_file: ^SourceFile
|
source_file: ^SourceFile;
|
||||||
begin
|
begin
|
||||||
source_file := cast(source_input: ^SourceFile);
|
source_file := cast(source_input: ^SourceFile);
|
||||||
|
|
||||||
@ -318,49 +318,49 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
return source_file^.size = 0u
|
return source_file^.size = 0u
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc source_file_head(source_input: Pointer) -> Char;
|
proc source_file_head(source_input: Pointer) -> Char;
|
||||||
var
|
var
|
||||||
source_file: ^SourceFile
|
source_file: ^SourceFile;
|
||||||
begin
|
begin
|
||||||
source_file := cast(source_input: ^SourceFile);
|
source_file := cast(source_input: ^SourceFile);
|
||||||
|
|
||||||
return source_file^.buffer[source_file^.index]
|
return source_file^.buffer[source_file^.index]
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc source_file_advance(source_input: Pointer);
|
proc source_file_advance(source_input: Pointer);
|
||||||
var
|
var
|
||||||
source_file: ^SourceFile
|
source_file: ^SourceFile;
|
||||||
begin
|
begin
|
||||||
source_file := cast(source_input: ^SourceFile);
|
source_file := cast(source_input: ^SourceFile);
|
||||||
|
|
||||||
source_file^.index := source_file^.index + 1u
|
source_file^.index := source_file^.index + 1u
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc source_code_empty(source_code: ^SourceCode) -> Bool;
|
proc source_code_empty(source_code: ^SourceCode) -> Bool;
|
||||||
return source_code^.empty(source_code^.input)
|
return source_code^.empty(source_code^.input)
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc source_code_head(source_code: SourceCode) -> Char;
|
proc source_code_head(source_code: SourceCode) -> Char;
|
||||||
return source_code.head(source_code.input)
|
return source_code.head(source_code.input)
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc source_code_advance(source_code: ^SourceCode);
|
proc source_code_advance(source_code: ^SourceCode);
|
||||||
begin
|
begin
|
||||||
source_code^.advance(source_code^.input);
|
source_code^.advance(source_code^.input);
|
||||||
source_code^.position.column := source_code^.position.column
|
source_code^.position.column := source_code^.position.column
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc source_code_break(source_code: ^SourceCode);
|
proc source_code_break(source_code: ^SourceCode);
|
||||||
begin
|
begin
|
||||||
source_code^.position.line := source_code^.position.line + 1u;
|
source_code^.position.line := source_code^.position.line + 1u;
|
||||||
source_code^.position.column := 0u
|
source_code^.position.column := 0u
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc source_code_expect(source_code: ^SourceCode, expected: Char) -> Bool;
|
proc source_code_expect(source_code: ^SourceCode, expected: Char) -> Bool;
|
||||||
return ~source_code_empty(source_code) & source_code_head(source_code^) = expected
|
return ~source_code_empty(source_code) & source_code_head(source_code^) = expected
|
||||||
end
|
end;
|
||||||
|
|
||||||
(*
|
(*
|
||||||
Token procedures.
|
Token procedures.
|
||||||
@ -368,7 +368,7 @@ end
|
|||||||
|
|
||||||
proc lexer_escape(escape: Char, result: ^Char) -> Bool;
|
proc lexer_escape(escape: Char, result: ^Char) -> Bool;
|
||||||
var
|
var
|
||||||
successful: Bool
|
successful: Bool;
|
||||||
begin
|
begin
|
||||||
if escape = 'n' then
|
if escape = 'n' then
|
||||||
result^ := '\n';
|
result^ := '\n';
|
||||||
@ -410,12 +410,12 @@ begin
|
|||||||
successful := false
|
successful := false
|
||||||
end;
|
end;
|
||||||
return successful
|
return successful
|
||||||
end
|
end;
|
||||||
|
|
||||||
(* Skip spaces. *)
|
(* Skip spaces. *)
|
||||||
proc lexer_spaces(source_code: ^SourceCode);
|
proc lexer_spaces(source_code: ^SourceCode);
|
||||||
var
|
var
|
||||||
current: Char
|
current: Char;
|
||||||
begin
|
begin
|
||||||
while ~source_code_empty(source_code) & is_space(source_code_head(source_code^)) do
|
while ~source_code_empty(source_code) & is_space(source_code_head(source_code^)) do
|
||||||
current := source_code_head(source_code^);
|
current := source_code_head(source_code^);
|
||||||
@ -425,26 +425,26 @@ begin
|
|||||||
end;
|
end;
|
||||||
source_code_advance(source_code)
|
source_code_advance(source_code)
|
||||||
end
|
end
|
||||||
end
|
end;
|
||||||
|
|
||||||
(* Checker whether the character is allowed in an identificator. *)
|
(* Checker whether the character is allowed in an identificator. *)
|
||||||
proc lexer_is_ident(char: Char) -> Bool;
|
proc lexer_is_ident(char: Char) -> Bool;
|
||||||
return is_alnum(char) or char = '_'
|
return is_alnum(char) or char = '_'
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc lexer_identifier(source_code: ^SourceCode, token_content: ^StringBuffer);
|
proc lexer_identifier(source_code: ^SourceCode, token_content: ^StringBuffer);
|
||||||
var
|
var
|
||||||
content_length: Word
|
content_length: Word;
|
||||||
begin
|
begin
|
||||||
while ~source_code_empty(source_code) & lexer_is_ident(source_code_head(source_code^)) do
|
while ~source_code_empty(source_code) & lexer_is_ident(source_code_head(source_code^)) do
|
||||||
string_buffer_push(token_content, source_code_head(source_code^));
|
string_buffer_push(token_content, source_code_head(source_code^));
|
||||||
source_code_advance(source_code)
|
source_code_advance(source_code)
|
||||||
end
|
end
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc lexer_comment(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool;
|
proc lexer_comment(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool;
|
||||||
var
|
var
|
||||||
trailing: Word
|
trailing: Word;
|
||||||
begin
|
begin
|
||||||
trailing := 0u;
|
trailing := 0u;
|
||||||
|
|
||||||
@ -463,11 +463,11 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
return trailing = 2u
|
return trailing = 2u
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc lexer_character(source_code: ^SourceCode, token_content: ^Char) -> Bool;
|
proc lexer_character(source_code: ^SourceCode, token_content: ^Char) -> Bool;
|
||||||
var
|
var
|
||||||
successful: Bool
|
successful: Bool;
|
||||||
begin
|
begin
|
||||||
successful := ~source_code_empty(source_code);
|
successful := ~source_code_empty(source_code);
|
||||||
|
|
||||||
@ -485,14 +485,14 @@ begin
|
|||||||
source_code_advance(source_code)
|
source_code_advance(source_code)
|
||||||
end;
|
end;
|
||||||
return successful
|
return successful
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc lexer_string(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool;
|
proc lexer_string(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool;
|
||||||
var
|
var
|
||||||
token_end, constructed_string: ^Char
|
token_end, constructed_string: ^Char;
|
||||||
token_length: Word
|
token_length: Word;
|
||||||
is_valid: Bool
|
is_valid: Bool;
|
||||||
next_char: Char
|
next_char: Char;
|
||||||
begin
|
begin
|
||||||
is_valid := true;
|
is_valid := true;
|
||||||
|
|
||||||
@ -510,7 +510,7 @@ begin
|
|||||||
is_valid := false
|
is_valid := false
|
||||||
end;
|
end;
|
||||||
return is_valid
|
return is_valid
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc lexer_number(source_code: ^SourceCode, token_content: ^Int);
|
proc lexer_number(source_code: ^SourceCode, token_content: ^Int);
|
||||||
begin
|
begin
|
||||||
@ -521,12 +521,12 @@ begin
|
|||||||
|
|
||||||
source_code_advance(source_code)
|
source_code_advance(source_code)
|
||||||
end
|
end
|
||||||
end
|
end;
|
||||||
|
|
||||||
(* Categorize an identifier. *)
|
(* Categorize an identifier. *)
|
||||||
proc lexer_categorize(token_content: String) -> Token;
|
proc lexer_categorize(token_content: String) -> Token;
|
||||||
var
|
var
|
||||||
current_token: Token
|
current_token: Token;
|
||||||
begin
|
begin
|
||||||
if token_content = "if" then
|
if token_content = "if" then
|
||||||
current_token.kind := TokenKind._if
|
current_token.kind := TokenKind._if
|
||||||
@ -590,23 +590,23 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
return current_token
|
return current_token
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc lexer_add_token(lexer: ^Lexer, token: Token);
|
proc lexer_add_token(lexer: ^Lexer, token: Token);
|
||||||
var
|
var
|
||||||
new_length: Word
|
new_length: Word;
|
||||||
begin
|
begin
|
||||||
new_length := lexer^.length + 1u;
|
new_length := lexer^.length + 1u;
|
||||||
lexer^.data := cast(reallocarray(cast(lexer^.data: Pointer), new_length, #size(Token)): ^Token);
|
lexer^.data := cast(reallocarray(cast(lexer^.data: Pointer), new_length, #size(Token)): ^Token);
|
||||||
(lexer^.data + lexer^.length)^ := token;
|
(lexer^.data + lexer^.length)^ := token;
|
||||||
lexer^.length := new_length
|
lexer^.length := new_length
|
||||||
end
|
end;
|
||||||
|
|
||||||
(* Read the next token from the input. *)
|
(* Read the next token from the input. *)
|
||||||
proc lexer_next(source_code: SourceCode, token_buffer: ^StringBuffer) -> Token;
|
proc lexer_next(source_code: SourceCode, token_buffer: ^StringBuffer) -> Token;
|
||||||
var
|
var
|
||||||
current_token: Token
|
current_token: Token;
|
||||||
first_char: Char
|
first_char: Char;
|
||||||
begin
|
begin
|
||||||
current_token.kind := TokenKind.unknown;
|
current_token.kind := TokenKind.unknown;
|
||||||
|
|
||||||
@ -775,14 +775,14 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
return current_token
|
return current_token
|
||||||
end
|
end;
|
||||||
|
|
||||||
(* Split the source text into tokens. *)
|
(* Split the source text into tokens. *)
|
||||||
proc lexer_text(source_code: SourceCode) -> Lexer;
|
proc lexer_text(source_code: SourceCode) -> Lexer;
|
||||||
var
|
var
|
||||||
current_token: Token
|
current_token: Token;
|
||||||
token_buffer: StringBuffer
|
token_buffer: StringBuffer;
|
||||||
lexer: Lexer
|
lexer: Lexer;
|
||||||
begin
|
begin
|
||||||
lexer := Lexer(0u, nil);
|
lexer := Lexer(0u, nil);
|
||||||
token_buffer := string_buffer_new();
|
token_buffer := string_buffer_new();
|
||||||
@ -803,7 +803,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
return lexer
|
return lexer
|
||||||
end
|
end;
|
||||||
|
|
||||||
(*
|
(*
|
||||||
Command line handling.
|
Command line handling.
|
||||||
@ -811,9 +811,9 @@ end
|
|||||||
|
|
||||||
proc parse_command_line*(argc: Int, argv: ^^Char) -> ^CommandLine;
|
proc parse_command_line*(argc: Int, argv: ^^Char) -> ^CommandLine;
|
||||||
var
|
var
|
||||||
parameter: ^^Char
|
parameter: ^^Char;
|
||||||
i: Int
|
i: Int;
|
||||||
result: ^CommandLine
|
result: ^CommandLine;
|
||||||
begin
|
begin
|
||||||
i := 1;
|
i := 1;
|
||||||
result := cast(malloc(#size(CommandLine)): ^CommandLine);
|
result := cast(malloc(#size(CommandLine)): ^CommandLine);
|
||||||
@ -852,7 +852,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
return result
|
return result
|
||||||
end
|
end;
|
||||||
|
|
||||||
(*
|
(*
|
||||||
Parser.
|
Parser.
|
||||||
@ -860,8 +860,8 @@ end
|
|||||||
|
|
||||||
proc parse(tokens: ^Token, tokens_size: Word);
|
proc parse(tokens: ^Token, tokens_size: Word);
|
||||||
var
|
var
|
||||||
current_token: ^Token
|
current_token: ^Token;
|
||||||
i: Word
|
i: Word;
|
||||||
begin
|
begin
|
||||||
i := 0u;
|
i := 0u;
|
||||||
while i < tokens_size do
|
while i < tokens_size do
|
||||||
@ -1015,7 +1015,7 @@ begin
|
|||||||
i := i + 1u
|
i := i + 1u
|
||||||
end;
|
end;
|
||||||
write_c('\n')
|
write_c('\n')
|
||||||
end
|
end;
|
||||||
|
|
||||||
(*
|
(*
|
||||||
Compilation entry.
|
Compilation entry.
|
||||||
@ -1023,8 +1023,8 @@ end
|
|||||||
|
|
||||||
proc compile_in_stages(command_line: ^CommandLine, source_code: SourceCode) -> Int;
|
proc compile_in_stages(command_line: ^CommandLine, source_code: SourceCode) -> Int;
|
||||||
var
|
var
|
||||||
return_code: Int
|
return_code: Int;
|
||||||
lexer: Lexer
|
lexer: Lexer;
|
||||||
begin
|
begin
|
||||||
return_code := 0;
|
return_code := 0;
|
||||||
|
|
||||||
@ -1036,16 +1036,16 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
return return_code
|
return return_code
|
||||||
end
|
end;
|
||||||
|
|
||||||
proc process(argc: Int, argv: ^^Char) -> Int;
|
proc process(argc: Int, argv: ^^Char) -> Int;
|
||||||
var
|
var
|
||||||
tokens: ^Token
|
tokens: ^Token;
|
||||||
tokens_size: Word
|
tokens_size: Word;
|
||||||
source_code: SourceCode
|
source_code: SourceCode;
|
||||||
command_line: ^CommandLine
|
command_line: ^CommandLine;
|
||||||
return_code: Int
|
return_code: Int;
|
||||||
source_file: ^SourceFile
|
source_file: ^SourceFile;
|
||||||
begin
|
begin
|
||||||
return_code := 0;
|
return_code := 0;
|
||||||
|
|
||||||
@ -1077,7 +1077,7 @@ begin
|
|||||||
return_code := compile_in_stages(command_line, source_code)
|
return_code := compile_in_stages(command_line, source_code)
|
||||||
end;
|
end;
|
||||||
return return_code
|
return return_code
|
||||||
end
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
exit(process(count, parameters))
|
exit(process(count, parameters))
|
@ -1,89 +0,0 @@
|
|||||||
# This Source Code Form is subject to the terms of the Mozilla Public License,
|
|
||||||
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
||||||
# obtain one at https://mozilla.org/MPL/2.0/. -}
|
|
||||||
|
|
||||||
require 'uri'
|
|
||||||
require 'net/http'
|
|
||||||
require 'open3'
|
|
||||||
|
|
||||||
TMP = Pathname.new('./build')
|
|
||||||
|
|
||||||
class BuildTarget
|
|
||||||
attr_accessor(:build, :gcc, :sysroot, :tmp)
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
@sysroot = Pathname.new '/'
|
|
||||||
end
|
|
||||||
|
|
||||||
def gxx
|
|
||||||
@gcc.gsub 'c', '+'
|
|
||||||
end
|
|
||||||
|
|
||||||
def rootfs
|
|
||||||
tmp + 'rootfs'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def gcc_verbose(gcc_binary)
|
|
||||||
read, write = IO.pipe
|
|
||||||
sh({'LANG' => 'C'}, gcc_binary, '--verbose', err: write)
|
|
||||||
write.close
|
|
||||||
output = read.read
|
|
||||||
read.close
|
|
||||||
output
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_build_target(gcc_version)
|
|
||||||
gcc_binary = 'gcc'
|
|
||||||
output = gcc_verbose gcc_binary
|
|
||||||
|
|
||||||
if output.start_with? 'Apple clang'
|
|
||||||
gcc_binary = "gcc-#{gcc_version.split('.').first}"
|
|
||||||
output = gcc_verbose gcc_binary
|
|
||||||
sdk = Pathname.new '/Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk'
|
|
||||||
end
|
|
||||||
result = output
|
|
||||||
.lines
|
|
||||||
.each_with_object(BuildTarget.new) do |line, accumulator|
|
|
||||||
if line.start_with? 'Target: '
|
|
||||||
accumulator.build = line.split(' ').last.strip
|
|
||||||
elsif line.start_with? 'COLLECT_GCC'
|
|
||||||
accumulator.gcc = line.split('=').last.strip
|
|
||||||
end
|
|
||||||
end
|
|
||||||
result.tmp = TMP
|
|
||||||
result.sysroot = sdk unless sdk.nil?
|
|
||||||
result
|
|
||||||
end
|
|
||||||
|
|
||||||
def download_and_pipe(url, target, command)
|
|
||||||
target.mkpath
|
|
||||||
|
|
||||||
Net::HTTP.start(url.host, url.port, use_ssl: url.scheme == 'https') do |http|
|
|
||||||
request = Net::HTTP::Get.new url.request_uri
|
|
||||||
|
|
||||||
http.request request do |response|
|
|
||||||
case response
|
|
||||||
when Net::HTTPRedirection
|
|
||||||
download_and_pipe URI.parse(response['location']), target, command
|
|
||||||
when Net::HTTPSuccess
|
|
||||||
Dir.chdir target.to_path do
|
|
||||||
Open3.popen2(*command) do |stdin, stdout, wait_thread|
|
|
||||||
Thread.new do
|
|
||||||
stdout.each { |line| puts line }
|
|
||||||
end
|
|
||||||
|
|
||||||
response.read_body do |chunk|
|
|
||||||
stdin.write chunk
|
|
||||||
end
|
|
||||||
stdin.close
|
|
||||||
|
|
||||||
wait_thread.value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
response.error!
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
Reference in New Issue
Block a user