Implement enumeration type

This commit is contained in:
Eugen Wissner 2025-04-04 22:48:12 +02:00
parent 50970f3289
commit 4737b1b4b0
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
13 changed files with 373 additions and 228 deletions

View File

@ -103,7 +103,7 @@ namespace elna::boot
{ {
} }
primitive_type_expression *type_expression::is_primitive() named_type_expression *type_expression::is_named()
{ {
return nullptr; return nullptr;
} }
@ -133,17 +133,22 @@ namespace elna::boot
return nullptr; return nullptr;
} }
primitive_type_expression::primitive_type_expression(const struct position position, const std::string& name) enumeration_type_expression *type_expression::is_enumeration()
{
return nullptr;
}
named_type_expression::named_type_expression(const struct position position, const std::string& name)
: type_expression(position), name(name) : type_expression(position), name(name)
{ {
} }
void primitive_type_expression::accept(parser_visitor *visitor) void named_type_expression::accept(parser_visitor *visitor)
{ {
visitor->visit(this); visitor->visit(this);
} }
primitive_type_expression *primitive_type_expression::is_primitive() named_type_expression *named_type_expression::is_named()
{ {
return this; return this;
} }
@ -312,6 +317,26 @@ namespace elna::boot
visitor->visit(this); visitor->visit(this);
} }
procedure_type_expression *procedure_type_expression::is_procedure()
{
return this;
}
enumeration_type_expression::enumeration_type_expression(const struct position position, std::vector<std::string>&& members)
: type_expression(position), members(members)
{
}
void enumeration_type_expression::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
enumeration_type_expression *enumeration_type_expression::is_enumeration()
{
return this;
}
procedure_definition::procedure_definition(const struct position position, const std::string& identifier, procedure_definition::procedure_definition(const struct position position, const std::string& identifier,
const bool exported, procedure_type_expression *heading, block *body) const bool exported, procedure_type_expression *heading, block *body)
: definition(position, identifier, exported), m_heading(heading), body(body) : definition(position, identifier, exported), m_heading(heading), body(body)
@ -323,11 +348,6 @@ namespace elna::boot
visitor->visit(this); visitor->visit(this);
} }
procedure_type_expression *procedure_type_expression::is_procedure()
{
return this;
}
procedure_type_expression& procedure_definition::heading() procedure_type_expression& procedure_definition::heading()
{ {
return *m_heading; return *m_heading;

View File

@ -157,6 +157,7 @@ along with GCC; see the file COPYING3. If not see
%type <elna::boot::defer_statement *> defer_statement; %type <elna::boot::defer_statement *> defer_statement;
%type <std::pair<std::string, bool>> identifier_definition; %type <std::pair<std::string, bool>> identifier_definition;
%type <std::vector<std::pair<std::string, bool>>> identifier_definitions; %type <std::vector<std::pair<std::string, bool>>> identifier_definitions;
%type <std::vector<std::string>> identifiers;
%% %%
program: program:
constant_part type_part variable_part procedure_part "begin" statements "end" "." constant_part type_part variable_part procedure_part "begin" statements "end" "."
@ -507,10 +508,21 @@ type_expression:
std::swap(result->parameters, $3); std::swap(result->parameters, $3);
$$ = result; $$ = result;
} }
| "(" identifiers ")"
{
$$ = new boot::enumeration_type_expression(boot::make_position(@1), std::move($2));
}
| IDENTIFIER | IDENTIFIER
{ {
$$ = new boot::primitive_type_expression(boot::make_position(@1), $1); $$ = new boot::named_type_expression(boot::make_position(@1), $1);
} }
identifiers:
IDENTIFIER "," identifiers
{
std::swap($$, $3);
$$.emplace($$.cbegin(), 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 };
@ -561,16 +573,14 @@ type_definitions:
type_part: type_part:
/* no type definitions */ {} /* no type definitions */ {}
| "type" type_definitions { std::swap($$, $2); } | "type" type_definitions { std::swap($$, $2); }
formal_parameter: IDENTIFIER ":" type_expression formal_parameter:
{ IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); }
$$ = std::make_pair($1, $3);
}
formal_parameters: formal_parameters:
/* no formal parameters */ {} /* no formal parameters */ {}
| formal_parameter "," formal_parameters | formal_parameter "," formal_parameters
{ {
std::swap($$, $3); std::swap($$, $3);
$$.emplace($$.cbegin(), $1); $$.emplace($$.cbegin(), std::move($1));
} }
| formal_parameter { $$.emplace_back(std::move($1)); } | formal_parameter { $$.emplace_back(std::move($1)); }
actual_parameter_list: actual_parameter_list:

View File

@ -114,7 +114,7 @@ namespace elna::boot
unresolved_declaration->reference = this->current_type; unresolved_declaration->reference = this->current_type;
} }
void declaration_visitor::visit(primitive_type_expression *type_expression) void declaration_visitor::visit(named_type_expression *type_expression)
{ {
auto unresolved_alias = this->unresolved.find(type_expression->name); auto unresolved_alias = this->unresolved.find(type_expression->name);
@ -177,6 +177,13 @@ namespace elna::boot
this->current_type = type(result_type); this->current_type = type(result_type);
} }
void declaration_visitor::visit(enumeration_type_expression *type_expression)
{
std::shared_ptr<enumeration_type> result_type = std::make_shared<enumeration_type>(type_expression->members);
this->current_type = type(result_type);
}
void declaration_visitor::visit(variable_declaration *declaration) void declaration_visitor::visit(variable_declaration *declaration)
{ {
declaration->variable_type().accept(this); declaration->variable_type().accept(this);

View File

@ -58,6 +58,11 @@ namespace elna::boot
{ {
} }
type::type(std::shared_ptr<enumeration_type> enumeration)
: tag(type_tag::enumeration), enumeration(enumeration)
{
}
void type::copy(const type& other) void type::copy(const type& other)
{ {
switch (other.tag) switch (other.tag)
@ -85,6 +90,9 @@ namespace elna::boot
case type_tag::procedure: case type_tag::procedure:
new (&procedure) std::shared_ptr<procedure_type>(other.procedure); new (&procedure) std::shared_ptr<procedure_type>(other.procedure);
break; break;
case type_tag::enumeration:
new (&enumeration) std::shared_ptr<enumeration_type>(other.enumeration);
break;
} }
} }
@ -121,6 +129,9 @@ namespace elna::boot
case type_tag::procedure: case type_tag::procedure:
new (&procedure) std::shared_ptr<procedure_type>(std::move(other.procedure)); new (&procedure) std::shared_ptr<procedure_type>(std::move(other.procedure));
break; break;
case type_tag::enumeration:
new (&enumeration) std::shared_ptr<enumeration_type>(std::move(other.enumeration));
break;
} }
} }
@ -178,6 +189,9 @@ namespace elna::boot
case type_tag::procedure: case type_tag::procedure:
this->procedure.~shared_ptr<procedure_type>(); this->procedure.~shared_ptr<procedure_type>();
break; break;
case type_tag::enumeration:
this->enumeration.~shared_ptr<enumeration_type>();
break;
} }
} }
@ -223,6 +237,12 @@ namespace elna::boot
return tag == type_tag::procedure ? this->procedure : nullptr; return tag == type_tag::procedure ? this->procedure : nullptr;
} }
template<>
std::shared_ptr<enumeration_type> type::get<enumeration_type>() const
{
return tag == type_tag::enumeration ? this->enumeration : nullptr;
}
bool type::empty() const bool type::empty() const
{ {
return tag == type_tag::empty; return tag == type_tag::empty;
@ -253,6 +273,11 @@ namespace elna::boot
{ {
} }
enumeration_type::enumeration_type(const std::vector<std::string>& members)
: members(members)
{
}
info::~info() info::~info()
{ {
} }

View File

@ -129,6 +129,10 @@ namespace elna::gcc
{ {
return print_aggregate_name(unqualified_type, "union"); return print_aggregate_name(unqualified_type, "union");
} }
else if (TREE_CODE(type) == ENUMERAL_TYPE)
{
return print_aggregate_name(unqualified_type, "enumeration");
}
else else
{ {
return "<<unknown-type>>"; return "<<unknown-type>>";

View File

@ -57,6 +57,10 @@ namespace elna::gcc
{ {
return make_node(UNION_TYPE); return make_node(UNION_TYPE);
} }
else if (auto reference = type.get<boot::enumeration_type>())
{
return make_node(ENUMERAL_TYPE);
}
else if (auto reference = type.get<boot::pointer_type>()) else if (auto reference = type.get<boot::pointer_type>())
{ {
return build_global_pointer_type(get_inner_alias(reference->base, symbols, unresolved, path)); return build_global_pointer_type(get_inner_alias(reference->base, symbols, unresolved, path));
@ -247,8 +251,7 @@ namespace elna::gcc
expression->value().accept(this); expression->value().accept(this);
tree cast_source = TREE_TYPE(this->current_expression); tree cast_source = TREE_TYPE(this->current_expression);
if ((is_primitive_type(cast_target) || is_pointer_type(cast_target)) if (is_castable_type(cast_target) && (is_castable_type(cast_source)))
&& (is_primitive_type(cast_source) || is_pointer_type(cast_source)))
{ {
this->current_expression = build1_loc(get_location(&expression->position()), CONVERT_EXPR, this->current_expression = build1_loc(get_location(&expression->position()), CONVERT_EXPR,
cast_target, this->current_expression); cast_target, this->current_expression);
@ -1030,7 +1033,7 @@ namespace elna::gcc
return; return;
} }
trait->parameters.front()->accept(this); trait->parameters.front()->accept(this);
auto field_type = trait->parameters.at(1)->is_primitive(); auto field_type = trait->parameters.at(1)->is_named();
if (field_type == nullptr) if (field_type == nullptr)
{ {
@ -1076,6 +1079,21 @@ namespace elna::gcc
this->current_expression = build1(ADDR_EXPR, this->current_expression = build1(ADDR_EXPR,
build_qualified_type(ptr_type, TYPE_QUAL_CONST), this->current_expression); build_qualified_type(ptr_type, TYPE_QUAL_CONST), this->current_expression);
} }
else if (TREE_CODE(aggregate_type) == ENUMERAL_TYPE)
{
tree iterator{ NULL_TREE };
for (iterator = TYPE_VALUES(aggregate_type); iterator != NULL_TREE; iterator = TREE_CHAIN(iterator))
{
if (IDENTIFIER_POINTER(TREE_PURPOSE(iterator)) == expression->field())
{
this->current_expression = TREE_VALUE(iterator);
return;
}
}
this->current_expression = error_mark_node;
error_at(expression_location, "Unknown enumeration member '%s'", expression->field().c_str());
}
else else
{ {
tree field_declaration = find_field_by_name(expression_location, tree field_declaration = find_field_by_name(expression_location,
@ -1285,7 +1303,7 @@ namespace elna::gcc
this->current_expression = NULL_TREE; this->current_expression = NULL_TREE;
} }
void generic_visitor::visit(boot::primitive_type_expression *type) void generic_visitor::visit(boot::named_type_expression *type)
{ {
auto looked_up = this->unresolved.find(type->name); auto looked_up = this->unresolved.find(type->name);
tree symbol; tree symbol;
@ -1362,6 +1380,33 @@ namespace elna::gcc
this->current_expression = build_global_pointer_type(procedure_type_node); this->current_expression = build_global_pointer_type(procedure_type_node);
} }
void generic_visitor::visit(boot::enumeration_type_expression *type)
{
tree composite_type_node = this->current_expression == NULL_TREE
? make_node(ENUMERAL_TYPE)
: this->current_expression;
location_t enum_location = get_location(&type->position());
ENUM_IS_SCOPED(composite_type_node) = 1;
tree *pp = &TYPE_VALUES(composite_type_node);
std::size_t order{ 1 };
for (const std::string& member : type->members)
{
tree member_name = get_identifier(member.c_str());
tree member_declaration = build_decl(enum_location, CONST_DECL, member_name, composite_type_node);
DECL_INITIAL(member_declaration) = build_int_cst_type(integer_type_node, order++);
TREE_CONSTANT(member_declaration) = 1;
TREE_READONLY(member_declaration) = 1;
*pp = build_tree_list(member_name, member_declaration);
pp = &TREE_CHAIN(*pp);
}
layout_type(composite_type_node);
}
void generic_visitor::visit(boot::defer_statement *statement) void generic_visitor::visit(boot::defer_statement *statement)
{ {
enter_scope(); enter_scope();

View File

@ -62,10 +62,12 @@ namespace elna::gcc
return type == NULL_TREE || type == void_type_node; return type == NULL_TREE || type == void_type_node;
} }
bool is_aggregate_type(tree type) bool is_castable_type(tree type)
{ {
gcc_assert(TYPE_P(type)); gcc_assert(TYPE_P(type));
return TREE_CODE(type) == RECORD_TYPE || TREE_CODE(type) == UNION_TYPE; auto code = TREE_CODE(type);
return is_primitive_type(type) || is_pointer_type(type) || code == ENUMERAL_TYPE;
} }
bool are_compatible_pointers(tree lhs_type, tree rhs) bool are_compatible_pointers(tree lhs_type, tree rhs)
@ -224,9 +226,9 @@ namespace elna::gcc
} }
tree field_declaration = TYPE_FIELDS(type); tree field_declaration = TYPE_FIELDS(type);
if (!is_aggregate_type(type)) if (!RECORD_OR_UNION_TYPE_P(type))
{ {
error_at(expression_location, "type '%s' does not have a field named '%s'", error_at(expression_location, "Type '%s' does not have a field named '%s'",
print_type(type).c_str(), field_name.c_str()); print_type(type).c_str(), field_name.c_str());
return error_mark_node; return error_mark_node;
} }
@ -243,7 +245,7 @@ namespace elna::gcc
} }
if (field_declaration == NULL_TREE) if (field_declaration == NULL_TREE)
{ {
error_at(expression_location, "record type does not have a field named '%s'", field_name.c_str()); error_at(expression_location, "Aggregate type does not have a field '%s'", field_name.c_str());
return error_mark_node; return error_mark_node;
} }
return field_declaration; return field_declaration;

View File

@ -67,12 +67,13 @@ namespace elna::boot
class program; class program;
class binary_expression; class binary_expression;
class unary_expression; class unary_expression;
class primitive_type_expression; class named_type_expression;
class array_type_expression; class array_type_expression;
class pointer_type_expression; class pointer_type_expression;
class record_type_expression; class record_type_expression;
class union_type_expression; class union_type_expression;
class procedure_type_expression; class procedure_type_expression;
class enumeration_type_expression;
class variable_expression; class variable_expression;
class array_access_expression; class array_access_expression;
class field_access_expression; class field_access_expression;
@ -104,12 +105,13 @@ namespace elna::boot
virtual void visit(program *) = 0; virtual void visit(program *) = 0;
virtual void visit(binary_expression *) = 0; virtual void visit(binary_expression *) = 0;
virtual void visit(unary_expression *) = 0; virtual void visit(unary_expression *) = 0;
virtual void visit(primitive_type_expression *) = 0; virtual void visit(named_type_expression *) = 0;
virtual void visit(array_type_expression *) = 0; virtual void visit(array_type_expression *) = 0;
virtual void visit(pointer_type_expression *) = 0; virtual void visit(pointer_type_expression *) = 0;
virtual void visit(record_type_expression *) = 0; virtual void visit(record_type_expression *) = 0;
virtual void visit(union_type_expression *) = 0; virtual void visit(union_type_expression *) = 0;
virtual void visit(procedure_type_expression *) = 0; virtual void visit(procedure_type_expression *) = 0;
virtual void visit(enumeration_type_expression *) = 0;
virtual void visit(variable_expression *) = 0; virtual void visit(variable_expression *) = 0;
virtual void visit(array_access_expression *) = 0; virtual void visit(array_access_expression *) = 0;
virtual void visit(field_access_expression *) = 0; virtual void visit(field_access_expression *) = 0;
@ -188,28 +190,29 @@ namespace elna::boot
class type_expression : public node class type_expression : public node
{ {
public: public:
virtual primitive_type_expression *is_primitive(); virtual named_type_expression *is_named();
virtual array_type_expression *is_array(); virtual array_type_expression *is_array();
virtual pointer_type_expression *is_pointer(); virtual pointer_type_expression *is_pointer();
virtual record_type_expression *is_record(); virtual record_type_expression *is_record();
virtual union_type_expression *is_union(); virtual union_type_expression *is_union();
virtual procedure_type_expression *is_procedure(); virtual procedure_type_expression *is_procedure();
virtual enumeration_type_expression *is_enumeration();
protected: protected:
type_expression(const struct position position); type_expression(const struct position position);
}; };
/** /**
* Expression defining a basic type. * Expression refering to a type by its name.
*/ */
class primitive_type_expression : public type_expression class named_type_expression : public type_expression
{ {
public: public:
const std::string name; const std::string name;
primitive_type_expression(const struct position position, const std::string& name); named_type_expression(const struct position position, const std::string& name);
void accept(parser_visitor *visitor) override; void accept(parser_visitor *visitor) override;
primitive_type_expression *is_primitive() override; named_type_expression *is_named() override;
}; };
class array_type_expression : public type_expression class array_type_expression : public type_expression
@ -269,6 +272,20 @@ namespace elna::boot
union_type_expression *is_union() override; union_type_expression *is_union() override;
}; };
/**
* Enumeration type.
*/
class enumeration_type_expression : public type_expression
{
public:
const std::vector<std::string> members;
enumeration_type_expression(const struct position, std::vector<std::string>&& members);
void accept(parser_visitor *visitor) override;
enumeration_type_expression *is_enumeration() override;
};
/** /**
* Variable declaration. * Variable declaration.
*/ */

View File

@ -58,7 +58,7 @@ namespace elna::boot
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(primitive_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;
@ -66,6 +66,7 @@ namespace elna::boot
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(variable_declaration *declaration) override; void visit(variable_declaration *declaration) override;
void visit(constant_definition *) override; void visit(constant_definition *) override;

View File

@ -34,6 +34,7 @@ namespace elna::boot
class pointer_type; class pointer_type;
class array_type; class array_type;
class procedure_type; class procedure_type;
class enumeration_type;
class type class type
{ {
@ -46,7 +47,8 @@ namespace elna::boot
_union, _union,
pointer, pointer,
array, array,
procedure procedure,
enumeration
}; };
type_tag tag{ type_tag::empty }; type_tag tag{ type_tag::empty };
union union
@ -58,6 +60,7 @@ namespace elna::boot
std::shared_ptr<pointer_type> pointer; std::shared_ptr<pointer_type> pointer;
std::shared_ptr<array_type> array; std::shared_ptr<array_type> array;
std::shared_ptr<procedure_type> procedure; std::shared_ptr<procedure_type> procedure;
std::shared_ptr<enumeration_type> enumeration;
}; };
void copy(const type& other); void copy(const type& other);
@ -72,6 +75,7 @@ namespace elna::boot
explicit type(std::shared_ptr<pointer_type> pointer); explicit type(std::shared_ptr<pointer_type> pointer);
explicit type(std::shared_ptr<array_type> array); explicit type(std::shared_ptr<array_type> array);
explicit type(std::shared_ptr<procedure_type> procedure); explicit type(std::shared_ptr<procedure_type> procedure);
explicit type(std::shared_ptr<enumeration_type> enumeration);
type(const type& other); type(const type& other);
type& operator=(const type& other); type& operator=(const type& other);
@ -141,6 +145,13 @@ namespace elna::boot
procedure_type(return_t return_type = return_t()); procedure_type(return_t return_type = return_t());
}; };
struct enumeration_type
{
std::vector<std::string> members;
explicit enumeration_type(const std::vector<std::string>& members);
};
class type_info; class type_info;
class procedure_info; class procedure_info;

View File

@ -101,12 +101,13 @@ namespace elna::gcc
void visit(boot::assign_statement *statement) override; void visit(boot::assign_statement *statement) override;
void visit(boot::if_statement *statement) override; void visit(boot::if_statement *statement) override;
void visit(boot::while_statement *statement) override; void visit(boot::while_statement *statement) override;
void visit(boot::primitive_type_expression *type) override; void visit(boot::named_type_expression *type) override;
void visit(boot::array_type_expression *type) override; void visit(boot::array_type_expression *type) override;
void visit(boot::pointer_type_expression *type) override; void visit(boot::pointer_type_expression *type) override;
void visit(boot::record_type_expression *type) override; void visit(boot::record_type_expression *type) override;
void visit(boot::union_type_expression *type) override; void visit(boot::union_type_expression *type) override;
void visit(boot::procedure_type_expression *type) override; void visit(boot::procedure_type_expression *type) override;
void visit(boot::enumeration_type_expression *type) override;
void visit(boot::return_statement *statement) override; void visit(boot::return_statement *statement) override;
void visit(boot::defer_statement *statement) override; void visit(boot::defer_statement *statement) override;
}; };

View File

@ -42,9 +42,9 @@ namespace elna::gcc
/** /**
* \param type The type to evaluate. * \param type The type to evaluate.
* \return Whether the given type is record or union. * \return Whether this type can be converted to another type.
*/ */
bool is_aggregate_type(tree type); bool is_castable_type(tree type);
/** /**
* \param lhs Left hand value. * \param lhs Left hand value.

View File

@ -3,67 +3,69 @@ const
SEEK_CUR* = 1; SEEK_CUR* = 1;
SEEK_END* = 2; SEEK_END* = 2;
TOKEN_IDENTIFIER* = 1;
TOKEN_IF* = 2;
TOKEN_THEN* = 3;
TOKEN_ELSE* = 4;
TOKEN_ELSIF* = 5;
TOKEN_WHILE* = 6;
TOKEN_DO* = 7;
TOKEN_PROC* = 8;
TOKEN_BEGIN* = 9;
TOKEN_END* = 10;
TOKEN_EXTERN* = 11;
TOKEN_CONST* = 12;
TOKEN_VAR* = 13;
TOKEN_ARRAY* = 14;
TOKEN_OF* = 15;
TOKEN_TYPE* = 16;
TOKEN_RECORD* = 17;
TOKEN_UNION* = 18;
TOKEN_POINTER* = 19;
TOKEN_TO* = 20;
TOKEN_BOOLEAN* = 21;
TOKEN_NIL* = 22;
TOKEN_AND* = 23;
TOKEN_OR* = 24;
TOKEN_NOT* = 25;
TOKEN_RETURN* = 26;
TOKEN_CAST* = 27;
TOKEN_SHIFT_LEFT* = 28;
TOKEN_SHIFT_RIGHT* = 29;
TOKEN_LEFT_PAREN* = 30;
TOKEN_RIGHT_PAREN* = 31;
TOKEN_LEFT_SQUARE* = 32;
TOKEN_RIGHT_SQUARE* = 33;
TOKEN_GREATER_EQUAL* = 34;
TOKEN_LESS_EQUAL* = 35;
TOKEN_GREATER_THAN* = 36;
TOKEN_LESS_THAN* = 37;
TOKEN_NOT_EQUAL* = 38;
TOKEN_EQUAL* = 39;
TOKEN_SEMICOLON* = 40;
TOKEN_DOT* = 41;
TOKEN_COMMA* = 42;
TOKEN_PLUS* = 43;
TOKEN_MINUS* = 44;
TOKEN_MULTIPLICATION* = 45;
TOKEN_DIVISION* = 46;
TOKEN_REMAINDER* = 47;
TOKEN_ASSIGNMENT* = 48;
TOKEN_COLON* = 49;
TOKEN_HAT* = 50;
TOKEN_AT* = 51;
TOKEN_COMMENT* = 52;
TOKEN_INTEGER* = 53;
TOKEN_WORD* = 54;
TOKEN_CHARACTER* = 55;
TOKEN_STRING* = 56;
TOKEN_DEFER* = 57;
TOKEN_EXCLAMATION* = 58;
TOKEN_ARROW = 59;
type type
TokenKind* = (
unknown,
identifier,
_if,
_then,
_else,
_elsif,
_while,
_do,
_proc,
_begin,
_end,
_extern,
_const,
_var,
array,
of,
_type,
_record,
_union,
pointer,
to,
boolean,
_nil,
and,
or,
not,
_return,
_cast,
shift_left,
shift_right,
left_paren,
right_paren,
left_square,
right_square,
greater_equal,
less_equal,
greater_than,
less_than,
not_equal,
equal,
semicolon,
dot,
comma,
plus,
minus,
multiplication,
division,
remainder,
assignment,
colon,
hat,
at,
comment,
integer,
word,
character,
string,
_defer,
exclamation,
arrow
);
Position* = record Position* = record
line: Word; line: Word;
column: Word column: Word
@ -93,7 +95,7 @@ type
head: proc(^Byte) -> Char head: proc(^Byte) -> Char
end; end;
Token* = record Token* = record
kind: Int; kind: TokenKind;
value: union value: union
int_value: Int; int_value: Int;
string: String; string: String;
@ -516,137 +518,137 @@ begin
while i < tokens_size do while i < tokens_size do
current_token := tokens + i; current_token := tokens + i;
if current_token^.kind = TOKEN_IF then if current_token^.kind = TokenKind._if then
write_s("IF") write_s("IF")
elsif current_token^.kind = TOKEN_THEN then elsif current_token^.kind = TokenKind._then then
write_s("THEN") write_s("THEN")
elsif current_token^.kind = TOKEN_ELSE then elsif current_token^.kind = TokenKind._else then
write_s("ELSE") write_s("ELSE")
elsif current_token^.kind = TOKEN_ELSIF then elsif current_token^.kind = TokenKind._elsif then
write_s("ELSIF") write_s("ELSIF")
elsif current_token^.kind = TOKEN_WHILE then elsif current_token^.kind = TokenKind._while then
write_s("WHILE") write_s("WHILE")
elsif current_token^.kind = TOKEN_DO then elsif current_token^.kind = TokenKind._do then
write_s("DO") write_s("DO")
elsif current_token^.kind = TOKEN_PROC then elsif current_token^.kind = TokenKind._proc then
write_s("PROC") write_s("PROC")
elsif current_token^.kind = TOKEN_BEGIN then elsif current_token^.kind = TokenKind._begin then
write_s("BEGIN") write_s("BEGIN")
elsif current_token^.kind = TOKEN_END then elsif current_token^.kind = TokenKind._end then
write_s("END") write_s("END")
elsif current_token^.kind = TOKEN_EXTERN then elsif current_token^.kind = TokenKind._extern then
write_s("EXTERN") write_s("EXTERN")
elsif current_token^.kind = TOKEN_CONST then elsif current_token^.kind = TokenKind._const then
write_s("CONST") write_s("CONST")
elsif current_token^.kind = TOKEN_VAR then elsif current_token^.kind = TokenKind._var then
write_s("VAR") write_s("VAR")
elsif current_token^.kind = TOKEN_ARRAY then elsif current_token^.kind = TokenKind.array then
write_s("ARRAY") write_s("ARRAY")
elsif current_token^.kind = TOKEN_OF then elsif current_token^.kind = TokenKind.of then
write_s("OF") write_s("OF")
elsif current_token^.kind = TOKEN_TYPE then elsif current_token^.kind = TokenKind._type then
write_s("TYPE") write_s("TYPE")
elsif current_token^.kind = TOKEN_RECORD then elsif current_token^.kind = TokenKind._record then
write_s("RECORD") write_s("RECORD")
elsif current_token^.kind = TOKEN_UNION then elsif current_token^.kind = TokenKind._union then
write_s("UNION") write_s("UNION")
elsif current_token^.kind = TOKEN_POINTER then elsif current_token^.kind = TokenKind.pointer then
write_s("POINTER") write_s("POINTER")
elsif current_token^.kind = TOKEN_TO then elsif current_token^.kind = TokenKind.to then
write_s("TO") write_s("TO")
elsif current_token^.kind = TOKEN_BOOLEAN then elsif current_token^.kind = TokenKind.boolean then
write_s("BOOLEAN<"); write_s("BOOLEAN<");
write_b(current_token^.value.boolean_value); write_b(current_token^.value.boolean_value);
write_c('>') write_c('>')
elsif current_token^.kind = TOKEN_NIL then elsif current_token^.kind = TokenKind._nil then
write_s("NIL") write_s("NIL")
elsif current_token^.kind = TOKEN_AND then elsif current_token^.kind = TokenKind.and then
write_s("AND") write_s("AND")
elsif current_token^.kind = TOKEN_OR then elsif current_token^.kind = TokenKind.or then
write_s("OR") write_s("OR")
elsif current_token^.kind = TOKEN_NOT then elsif current_token^.kind = TokenKind.not then
write_s("NOT") write_s("NOT")
elsif current_token^.kind = TOKEN_RETURN then elsif current_token^.kind = TokenKind._return then
write_s("RETURN") write_s("RETURN")
elsif current_token^.kind = TOKEN_CAST then elsif current_token^.kind = TokenKind._cast then
write_s("CAST") write_s("CAST")
elsif current_token^.kind = TOKEN_SHIFT_LEFT then elsif current_token^.kind = TokenKind.shift_left then
write_s("<<") write_s("<<")
elsif current_token^.kind = TOKEN_SHIFT_RIGHT then elsif current_token^.kind = TokenKind.shift_right then
write_s(">>") write_s(">>")
elsif current_token^.kind = TOKEN_IDENTIFIER then elsif current_token^.kind = TokenKind.identifier then
write_c('<'); write_c('<');
write_s(current_token^.value.string); write_s(current_token^.value.string);
write_c('>') write_c('>')
elsif current_token^.kind = TOKEN_LEFT_PAREN then elsif current_token^.kind = TokenKind.left_paren then
write_s("(") write_s("(")
elsif current_token^.kind = TOKEN_RIGHT_PAREN then elsif current_token^.kind = TokenKind.right_paren then
write_s(")") write_s(")")
elsif current_token^.kind = TOKEN_LEFT_SQUARE then elsif current_token^.kind = TokenKind.left_square then
write_s("[") write_s("[")
elsif current_token^.kind = TOKEN_RIGHT_SQUARE then elsif current_token^.kind = TokenKind.right_square then
write_s("]") write_s("]")
elsif current_token^.kind = TOKEN_GREATER_EQUAL then elsif current_token^.kind = TokenKind.greater_equal then
write_s(">=") write_s(">=")
elsif current_token^.kind = TOKEN_LESS_EQUAL then elsif current_token^.kind = TokenKind.less_equal then
write_s("<=") write_s("<=")
elsif current_token^.kind = TOKEN_GREATER_THAN then elsif current_token^.kind = TokenKind.greater_than then
write_s(">") write_s(">")
elsif current_token^.kind = TOKEN_LESS_THAN then elsif current_token^.kind = TokenKind.less_than then
write_s("<") write_s("<")
elsif current_token^.kind = TOKEN_EQUAL then elsif current_token^.kind = TokenKind.equal then
write_s("=") write_s("=")
elsif current_token^.kind = TOKEN_NOT_EQUAL then elsif current_token^.kind = TokenKind.not_equal then
write_s("<>") write_s("<>")
elsif current_token^.kind = TOKEN_SEMICOLON then elsif current_token^.kind = TokenKind.semicolon then
write_c(';') write_c(';')
elsif current_token^.kind = TOKEN_DOT then elsif current_token^.kind = TokenKind.dot then
write_c('.') write_c('.')
elsif current_token^.kind = TOKEN_COMMA then elsif current_token^.kind = TokenKind.comma then
write_c(',') write_c(',')
elsif current_token^.kind = TOKEN_PLUS then elsif current_token^.kind = TokenKind.plus then
write_c('+') write_c('+')
elsif current_token^.kind = TOKEN_MINUS then elsif current_token^.kind = TokenKind.minus then
write_c('-') write_c('-')
elsif current_token^.kind = TOKEN_MULTIPLICATION then elsif current_token^.kind = TokenKind.multiplication then
write_c('*') write_c('*')
elsif current_token^.kind = TOKEN_DIVISION then elsif current_token^.kind = TokenKind.division then
write_c('/') write_c('/')
elsif current_token^.kind = TOKEN_REMAINDER then elsif current_token^.kind = TokenKind.remainder then
write_c('%') write_c('%')
elsif current_token^.kind = TOKEN_ASSIGNMENT then elsif current_token^.kind = TokenKind.assignment then
write_s(":=") write_s(":=")
elsif current_token^.kind = TOKEN_COLON then elsif current_token^.kind = TokenKind.colon then
write_c(':') write_c(':')
elsif current_token^.kind = TOKEN_HAT then elsif current_token^.kind = TokenKind.hat then
write_c('^') write_c('^')
elsif current_token^.kind = TOKEN_AT then elsif current_token^.kind = TokenKind.at then
write_c('@') write_c('@')
elsif current_token^.kind = TOKEN_COMMENT then elsif current_token^.kind = TokenKind.comment then
write_s("(* COMMENT *)") write_s("(* COMMENT *)")
elsif current_token^.kind = TOKEN_INTEGER then elsif current_token^.kind = TokenKind.integer then
write_c('<'); write_c('<');
write_i(current_token^.value.int_value); write_i(current_token^.value.int_value);
write_c('>') write_c('>')
elsif current_token^.kind = TOKEN_WORD then elsif current_token^.kind = TokenKind.word then
write_c('<'); write_c('<');
write_i(current_token^.value.int_value); write_i(current_token^.value.int_value);
write_s("u>") write_s("u>")
elsif current_token^.kind = TOKEN_CHARACTER then elsif current_token^.kind = TokenKind.character then
write_c('<'); write_c('<');
write_i(cast(current_token^.value.char_value: Int)); write_i(cast(current_token^.value.char_value: Int));
write_s("c>") write_s("c>")
elsif current_token^.kind = TOKEN_STRING then elsif current_token^.kind = TokenKind.string then
write_s("\"...\"") write_s("\"...\"")
elsif current_token^.kind = TOKEN_DEFER then elsif current_token^.kind = TokenKind._defer then
write_s("DEFER") write_s("DEFER")
elsif current_token^.kind = TOKEN_EXCLAMATION then elsif current_token^.kind = TokenKind.exclamation then
write_c('!') write_c('!')
elsif current_token^.kind = TOKEN_ARROW then elsif current_token^.kind = TokenKind.arrow then
write_s("->") write_s("->")
else else
write_s("UNKNOWN<"); write_s("UNKNOWN<");
write_i(current_token^.kind); write_i(cast(current_token^.kind: Int));
write_c('>') write_c('>')
end; end;
write_c(' '); write_c(' ');
@ -661,65 +663,65 @@ var
current_token: Token; current_token: Token;
begin begin
if "if" = token_content then if "if" = token_content then
current_token.kind := TOKEN_IF current_token.kind := TokenKind._if
elsif "then" = token_content then elsif "then" = token_content then
current_token.kind := TOKEN_THEN current_token.kind := TokenKind._then
elsif "else" = token_content then elsif "else" = token_content then
current_token.kind := TOKEN_ELSE current_token.kind := TokenKind._else
elsif "elsif" = token_content then elsif "elsif" = token_content then
current_token.kind := TOKEN_ELSIF current_token.kind := TokenKind._elsif
elsif "while" = token_content then elsif "while" = token_content then
current_token.kind := TOKEN_WHILE current_token.kind := TokenKind._while
elsif "do" = token_content then elsif "do" = token_content then
current_token.kind := TOKEN_DO current_token.kind := TokenKind._do
elsif "proc" = token_content then elsif "proc" = token_content then
current_token.kind := TOKEN_PROC current_token.kind := TokenKind._proc
elsif "begin" = token_content then elsif "begin" = token_content then
current_token.kind := TOKEN_BEGIN current_token.kind := TokenKind._begin
elsif "end" = token_content then elsif "end" = token_content then
current_token.kind := TOKEN_END current_token.kind := TokenKind._end
elsif "extern" = token_content then elsif "extern" = token_content then
current_token.kind := TOKEN_EXTERN current_token.kind := TokenKind._extern
elsif "const" = token_content then elsif "const" = token_content then
current_token.kind := TOKEN_CONST current_token.kind := TokenKind._const
elsif "var" = token_content then elsif "var" = token_content then
current_token.kind := TOKEN_VAR current_token.kind := TokenKind._var
elsif "array" = token_content then elsif "array" = token_content then
current_token.kind := TOKEN_ARRAY current_token.kind := TokenKind.array
elsif "of" = token_content then elsif "of" = token_content then
current_token.kind := TOKEN_OF current_token.kind := TokenKind.of
elsif "type" = token_content then elsif "type" = token_content then
current_token.kind := TOKEN_TYPE current_token.kind := TokenKind._type
elsif "record" = token_content then elsif "record" = token_content then
current_token.kind := TOKEN_RECORD current_token.kind := TokenKind._record
elsif "union" = token_content then elsif "union" = token_content then
current_token.kind := TOKEN_UNION current_token.kind := TokenKind._union
elsif "pointer" = token_content then elsif "pointer" = token_content then
current_token.kind := TOKEN_POINTER current_token.kind := TokenKind.pointer
elsif "to" = token_content then elsif "to" = token_content then
current_token.kind := TOKEN_TO current_token.kind := TokenKind.to
elsif "true" = token_content then elsif "true" = token_content then
current_token.kind := TOKEN_BOOLEAN; current_token.kind := TokenKind.boolean;
current_token.value.boolean_value := true current_token.value.boolean_value := true
elsif "false" = token_content then elsif "false" = token_content then
current_token.kind := TOKEN_BOOLEAN; current_token.kind := TokenKind.boolean;
current_token.value.boolean_value := false current_token.value.boolean_value := false
elsif "nil" = token_content then elsif "nil" = token_content then
current_token.kind := TOKEN_NIL current_token.kind := TokenKind._nil
elsif "and" = token_content then elsif "and" = token_content then
current_token.kind := TOKEN_AND current_token.kind := TokenKind.and
elsif "or" = token_content then elsif "or" = token_content then
current_token.kind := TOKEN_OR current_token.kind := TokenKind.or
elsif "not" = token_content then elsif "not" = token_content then
current_token.kind := TOKEN_NOT current_token.kind := TokenKind.not
elsif "return" = token_content then elsif "return" = token_content then
current_token.kind := TOKEN_RETURN current_token.kind := TokenKind._return
elsif "cast" = token_content then elsif "cast" = token_content then
current_token.kind := TOKEN_CAST current_token.kind := TokenKind._cast
elsif "defer" = token_content then elsif "defer" = token_content then
current_token.kind := TOKEN_DEFER current_token.kind := TokenKind._defer
else else
current_token.kind := TOKEN_IDENTIFIER; current_token.kind := TokenKind.identifier;
current_token.value.string := string_dup(token_content) current_token.value.string := string_dup(token_content)
end; end;
@ -750,147 +752,147 @@ begin
lex_number(@source_code, @current_token^.value.int_value); lex_number(@source_code, @current_token^.value.int_value);
if source_code_expect(@source_code, 'u') then if source_code_expect(@source_code, 'u') then
current_token^.kind := TOKEN_WORD; current_token^.kind := TokenKind.word;
source_code_advance(@source_code) source_code_advance(@source_code)
else else
current_token^.kind := TOKEN_INTEGER current_token^.kind := TokenKind.integer
end end
elsif first_char = '(' then elsif first_char = '(' then
source_code_advance(@source_code); source_code_advance(@source_code);
if source_code_empty(@source_code) then if source_code_empty(@source_code) then
current_token^.kind := TOKEN_LEFT_PAREN current_token^.kind := TokenKind.left_paren
elsif source_code_head(source_code) = '*' then elsif source_code_head(source_code) = '*' then
source_code_advance(@source_code); source_code_advance(@source_code);
if lex_comment(@source_code, @token_buffer) then if lex_comment(@source_code, @token_buffer) then
current_token^.value.string := string_dup(string_buffer_clear(@token_buffer)); current_token^.value.string := string_dup(string_buffer_clear(@token_buffer));
current_token^.kind := TOKEN_COMMENT current_token^.kind := TokenKind.comment
else else
current_token^.kind := 0 current_token^.kind := TokenKind.unknown
end end
else else
current_token^.kind := TOKEN_LEFT_PAREN current_token^.kind := TokenKind.left_paren
end end
elsif first_char = ')' then elsif first_char = ')' then
current_token^.kind := TOKEN_RIGHT_PAREN; current_token^.kind := TokenKind.right_paren;
source_code_advance(@source_code) source_code_advance(@source_code)
elsif first_char = '\'' then elsif first_char = '\'' then
source_code_advance(@source_code); source_code_advance(@source_code);
if lex_character(@source_code, @current_token^.value.char_value) & source_code_expect(@source_code, '\'') then if lex_character(@source_code, @current_token^.value.char_value) & source_code_expect(@source_code, '\'') then
current_token^.kind := TOKEN_CHARACTER; current_token^.kind := TokenKind.character;
source_code_advance(@source_code) source_code_advance(@source_code)
else else
current_token^.kind := 0 current_token^.kind := TokenKind.unknown
end end
elsif first_char = '"' then elsif first_char = '"' then
source_code_advance(@source_code); source_code_advance(@source_code);
if lex_string(@source_code, @token_buffer) then if lex_string(@source_code, @token_buffer) then
current_token^.kind := TOKEN_STRING; current_token^.kind := TokenKind.string;
current_token^.value.string := string_dup(string_buffer_clear(@token_buffer)) current_token^.value.string := string_dup(string_buffer_clear(@token_buffer))
else else
current_token^.kind := 0 current_token^.kind := TokenKind.unknown
end end
elsif first_char = '[' then elsif first_char = '[' then
current_token^.kind := TOKEN_LEFT_SQUARE; current_token^.kind := TokenKind.left_square;
source_code_advance(@source_code) source_code_advance(@source_code)
elsif first_char = ']' then elsif first_char = ']' then
current_token^.kind := TOKEN_RIGHT_SQUARE; current_token^.kind := TokenKind.right_square;
source_code_advance(@source_code) source_code_advance(@source_code)
elsif first_char = '>' then elsif first_char = '>' then
source_code_advance(@source_code); source_code_advance(@source_code);
if source_code_empty(@source_code) then if source_code_empty(@source_code) then
current_token^.kind := TOKEN_GREATER_THAN current_token^.kind := TokenKind.greater_than
elsif source_code_head(source_code) = '=' then elsif source_code_head(source_code) = '=' then
current_token^.kind := TOKEN_GREATER_EQUAL; current_token^.kind := TokenKind.greater_equal;
source_code_advance(@source_code) source_code_advance(@source_code)
elsif source_code_head(source_code) = '>' then elsif source_code_head(source_code) = '>' then
current_token^.kind := TOKEN_SHIFT_RIGHT; current_token^.kind := TokenKind.shift_right;
source_code_advance(@source_code) source_code_advance(@source_code)
else else
current_token^.kind := TOKEN_GREATER_THAN current_token^.kind := TokenKind.greater_than
end end
elsif first_char = '<' then elsif first_char = '<' then
source_code_advance(@source_code); source_code_advance(@source_code);
if source_code_empty(@source_code) then if source_code_empty(@source_code) then
current_token^.kind := TOKEN_LESS_THAN current_token^.kind := TokenKind.less_than
elsif source_code_head(source_code) = '=' then elsif source_code_head(source_code) = '=' then
current_token^.kind := TOKEN_LESS_EQUAL; current_token^.kind := TokenKind.less_equal;
source_code_advance(@source_code) source_code_advance(@source_code)
elsif source_code_head(source_code) = '<' then elsif source_code_head(source_code) = '<' then
current_token^.kind := TOKEN_SHIFT_LEFT; current_token^.kind := TokenKind.shift_left;
source_code_advance(@source_code) source_code_advance(@source_code)
elsif source_code_head(source_code) = '>' then elsif source_code_head(source_code) = '>' then
current_token^.kind := TOKEN_NOT_EQUAL; current_token^.kind := TokenKind.not_equal;
source_code_advance(@source_code) source_code_advance(@source_code)
else else
current_token^.kind := TOKEN_LESS_THAN current_token^.kind := TokenKind.less_than
end end
elsif first_char = '=' then elsif first_char = '=' then
current_token^.kind := TOKEN_EQUAL; current_token^.kind := TokenKind.equal;
source_code_advance(@source_code) source_code_advance(@source_code)
elsif first_char = ';' then elsif first_char = ';' then
current_token^.kind := TOKEN_SEMICOLON; current_token^.kind := TokenKind.semicolon;
source_code_advance(@source_code) source_code_advance(@source_code)
elsif first_char = '.' then elsif first_char = '.' then
current_token^.kind := TOKEN_DOT; current_token^.kind := TokenKind.dot;
source_code_advance(@source_code) source_code_advance(@source_code)
elsif first_char = ',' then elsif first_char = ',' then
current_token^.kind := TOKEN_COMMA; current_token^.kind := TokenKind.comma;
source_code_advance(@source_code) source_code_advance(@source_code)
elsif first_char = '+' then elsif first_char = '+' then
current_token^.kind := TOKEN_PLUS; current_token^.kind := TokenKind.plus;
source_code_advance(@source_code) source_code_advance(@source_code)
elsif first_char = '-' then elsif first_char = '-' then
source_code_advance(@source_code); source_code_advance(@source_code);
if source_code_empty(@source_code) then if source_code_empty(@source_code) then
current_token^.kind := TOKEN_MINUS current_token^.kind := TokenKind.minus
elsif source_code_head(source_code) = '>' then elsif source_code_head(source_code) = '>' then
current_token^.kind := TOKEN_ARROW; current_token^.kind := TokenKind.arrow;
source_code_advance(@source_code) source_code_advance(@source_code)
else else
current_token^.kind := TOKEN_MINUS current_token^.kind := TokenKind.minus
end end
elsif first_char = '*' then elsif first_char = '*' then
current_token^.kind := TOKEN_MULTIPLICATION; current_token^.kind := TokenKind.multiplication;
source_code_advance(@source_code) source_code_advance(@source_code)
elsif first_char = '/' then elsif first_char = '/' then
current_token^.kind := TOKEN_DIVISION; current_token^.kind := TokenKind.division;
source_code_advance(@source_code) source_code_advance(@source_code)
elsif first_char = '%' then elsif first_char = '%' then
current_token^.kind := TOKEN_REMAINDER; current_token^.kind := TokenKind.remainder;
source_code_advance(@source_code) source_code_advance(@source_code)
elsif first_char = ':' then elsif first_char = ':' then
source_code_advance(@source_code); source_code_advance(@source_code);
if source_code_empty(@source_code) then if source_code_empty(@source_code) then
current_token^.kind := TOKEN_COLON current_token^.kind := TokenKind.colon
elsif source_code_head(source_code) = '=' then elsif source_code_head(source_code) = '=' then
current_token^.kind := TOKEN_ASSIGNMENT; current_token^.kind := TokenKind.assignment;
source_code_advance(@source_code) source_code_advance(@source_code)
else else
current_token^.kind := TOKEN_COLON current_token^.kind := TokenKind.colon
end end
elsif first_char = '^' then elsif first_char = '^' then
current_token^.kind := TOKEN_HAT; current_token^.kind := TokenKind.hat;
source_code_advance(@source_code) source_code_advance(@source_code)
elsif first_char = '@' then elsif first_char = '@' then
current_token^.kind := TOKEN_AT; current_token^.kind := TokenKind.at;
source_code_advance(@source_code) source_code_advance(@source_code)
elsif first_char = '!' then elsif first_char = '!' then
current_token^.kind := TOKEN_EXCLAMATION; current_token^.kind := TokenKind.exclamation;
source_code_advance(@source_code) source_code_advance(@source_code)
else else
current_token^.kind := 0; current_token^.kind := TokenKind.unknown;
source_code_advance(@source_code) source_code_advance(@source_code)
end; end;
if current_token^.kind <> 0 then if current_token^.kind <> TokenKind.unknown then
tokens_size^ := tokens_size^ + 1u; tokens_size^ := tokens_size^ + 1u;
skip_spaces(@source_code) skip_spaces(@source_code)
else else