Update to GCC 15.1
This commit is contained in:
		
							
								
								
									
										6
									
								
								Rakefile
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								Rakefile
									
									
									
									
									
								
							@@ -8,8 +8,7 @@ require 'rake/clean'
 | 
				
			|||||||
require_relative 'tools/support'
 | 
					require_relative 'tools/support'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Dependencies.
 | 
					# Dependencies.
 | 
				
			||||||
GCC_VERSION = "14.2.0"
 | 
					GCC_VERSION = "15.1.0"
 | 
				
			||||||
GCC_PATCH = 'https://raw.githubusercontent.com/Homebrew/formula-patches/f30c309442a60cfb926e780eae5d70571f8ab2cb/gcc/gcc-14.2.0-r2.diff'
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Paths.
 | 
					# Paths.
 | 
				
			||||||
HOST_GCC = TMP + 'host/gcc'
 | 
					HOST_GCC = TMP + 'host/gcc'
 | 
				
			||||||
@@ -22,7 +21,7 @@ directory HOST_GCC
 | 
				
			|||||||
directory HOST_INSTALL
 | 
					directory HOST_INSTALL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
task default: [TMP + 'elna'] do
 | 
					task default: [TMP + 'elna'] do
 | 
				
			||||||
  sh (TMP + 'elna').to_path, '--tokenize', 'source.elna'
 | 
					  sh (TMP + 'elna').to_path, '--lex', 'source.elna'
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace :boot do
 | 
					namespace :boot do
 | 
				
			||||||
@@ -34,7 +33,6 @@ namespace :boot do
 | 
				
			|||||||
    frontend_link = source_directory + 'gcc'
 | 
					    frontend_link = source_directory + 'gcc'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    download_and_pipe url, source_directory.dirname, ['tar', '-Jxv']
 | 
					    download_and_pipe url, source_directory.dirname, ['tar', '-Jxv']
 | 
				
			||||||
    download_and_pipe URI.parse(GCC_PATCH), source_directory, ['patch', '-p1']
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sh 'contrib/download_prerequisites', chdir: source_directory.to_path
 | 
					    sh 'contrib/download_prerequisites', chdir: source_directory.to_path
 | 
				
			||||||
    File.symlink Pathname.new('.').relative_path_from(frontend_link), (frontend_link + 'elna')
 | 
					    File.symlink Pathname.new('.').relative_path_from(frontend_link), (frontend_link + 'elna')
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -128,8 +128,8 @@ return                  {
 | 
				
			|||||||
break                   {
 | 
					break                   {
 | 
				
			||||||
                            return yy::parser::make_BREAK(this->location);
 | 
					                            return yy::parser::make_BREAK(this->location);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
repeat                  {
 | 
					program                 {
 | 
				
			||||||
                            return yy::parser::make_REPEAT(this->location);
 | 
					                            return yy::parser::make_PROGRAM(this->location);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
cast                    {
 | 
					cast                    {
 | 
				
			||||||
                            return yy::parser::make_CAST(this->location);
 | 
					                            return yy::parser::make_CAST(this->location);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -108,7 +108,7 @@ along with GCC; see the file COPYING3.  If not see
 | 
				
			|||||||
    ELSE "else"
 | 
					    ELSE "else"
 | 
				
			||||||
    ELSIF "elsif"
 | 
					    ELSIF "elsif"
 | 
				
			||||||
    RETURN "return"
 | 
					    RETURN "return"
 | 
				
			||||||
    REPEAT "repeat"
 | 
					    PROGRAM "program"
 | 
				
			||||||
    BREAK "break"
 | 
					    BREAK "break"
 | 
				
			||||||
    BEGIN_BLOCK "begin"
 | 
					    BEGIN_BLOCK "begin"
 | 
				
			||||||
    END_BLOCK "end"
 | 
					    END_BLOCK "end"
 | 
				
			||||||
@@ -166,15 +166,15 @@ along with GCC; see the file COPYING3.  If not see
 | 
				
			|||||||
%type <std::vector<std::string>> identifiers;
 | 
					%type <std::vector<std::string>> identifiers;
 | 
				
			||||||
%%
 | 
					%%
 | 
				
			||||||
program:
 | 
					program:
 | 
				
			||||||
    constant_part type_part variable_part procedure_part "begin" statements "end" "."
 | 
					    "program" constant_part type_part variable_part procedure_part "begin" statements "end" "."
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            auto tree = new boot::program(boot::make_position(@5));
 | 
					            auto tree = new boot::program(boot::make_position(@6));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            std::swap(tree->constants, $1);
 | 
					            std::swap(tree->constants, $2);
 | 
				
			||||||
            std::swap(tree->types , $2);
 | 
					            std::swap(tree->types , $3);
 | 
				
			||||||
            std::swap(tree->variables, $3);
 | 
					            std::swap(tree->variables, $4);
 | 
				
			||||||
            std::swap(tree->procedures, $4);
 | 
					            std::swap(tree->procedures, $5);
 | 
				
			||||||
            std::swap(tree->body, $6);
 | 
					            std::swap(tree->body, $7);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            driver.tree.reset(tree);
 | 
					            driver.tree.reset(tree);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -211,12 +211,12 @@ procedure_heading:
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
procedure_definition:
 | 
					procedure_definition:
 | 
				
			||||||
    "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, $5);
 | 
					            $$ = new boot::procedure_definition(boot::make_position(@1), std::move($2), $3.second, $4);
 | 
				
			||||||
            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_definition(boot::make_position(@1), std::move($2), $3.second);
 | 
				
			||||||
            std::swap($3.first, $$->parameter_names);
 | 
					            std::swap($3.first, $$->parameter_names);
 | 
				
			||||||
@@ -419,8 +419,6 @@ statement:
 | 
				
			|||||||
    | return_statement { $$ = $1; }
 | 
					    | return_statement { $$ = $1; }
 | 
				
			||||||
    | "break" IDENTIFIER
 | 
					    | "break" IDENTIFIER
 | 
				
			||||||
        { $$ = new boot::escape_statement(boot::make_position(@1), boot::escape_direction::end, $2); }
 | 
					        { $$ = new boot::escape_statement(boot::make_position(@1), boot::escape_direction::end, $2); }
 | 
				
			||||||
    | "repeat" IDENTIFIER
 | 
					 | 
				
			||||||
        { $$ = new boot::escape_statement(boot::make_position(@1), boot::escape_direction::begin, $2); }
 | 
					 | 
				
			||||||
    | call_expression { $$ = $1; }
 | 
					    | call_expression { $$ = $1; }
 | 
				
			||||||
    | "defer" statements "end" { $$ = new boot::defer_statement(boot::make_position(@1), std::move($2)); }
 | 
					    | "defer" statements "end" { $$ = new boot::defer_statement(boot::make_position(@1), std::move($2)); }
 | 
				
			||||||
    | "case" expression "of" switch_cases else_statements "end"
 | 
					    | "case" expression "of" switch_cases else_statements "end"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										373
									
								
								source.elna
									
									
									
									
									
								
							
							
						
						
									
										373
									
								
								source.elna
									
									
									
									
									
								
							@@ -1,7 +1,12 @@
 | 
				
			|||||||
 | 
					program
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const
 | 
					const
 | 
				
			||||||
  SEEK_SET* := 0
 | 
					  SEEK_SET* := 0
 | 
				
			||||||
  SEEK_CUR* := 1
 | 
					  SEEK_CUR* := 1
 | 
				
			||||||
  SEEK_END* := 2
 | 
					  SEEK_END* := 2
 | 
				
			||||||
 | 
					  STDIN := 0
 | 
				
			||||||
 | 
					  STDOUT := 1
 | 
				
			||||||
 | 
					  STDERR := 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type
 | 
					type
 | 
				
			||||||
  TokenKind* = (
 | 
					  TokenKind* = (
 | 
				
			||||||
@@ -19,12 +24,12 @@ type
 | 
				
			|||||||
    _extern,
 | 
					    _extern,
 | 
				
			||||||
    _const,
 | 
					    _const,
 | 
				
			||||||
    _var,
 | 
					    _var,
 | 
				
			||||||
    array,
 | 
					    _case,
 | 
				
			||||||
    _of,
 | 
					    _of,
 | 
				
			||||||
    _type,
 | 
					    _type,
 | 
				
			||||||
    _record,
 | 
					    _record,
 | 
				
			||||||
    _union,
 | 
					    _union,
 | 
				
			||||||
    pointer,
 | 
					    pipe,
 | 
				
			||||||
    to,
 | 
					    to,
 | 
				
			||||||
    boolean,
 | 
					    boolean,
 | 
				
			||||||
    _nil,
 | 
					    _nil,
 | 
				
			||||||
@@ -64,7 +69,9 @@ type
 | 
				
			|||||||
    string,
 | 
					    string,
 | 
				
			||||||
    _defer,
 | 
					    _defer,
 | 
				
			||||||
    exclamation,
 | 
					    exclamation,
 | 
				
			||||||
    arrow
 | 
					    arrow,
 | 
				
			||||||
 | 
						trait,
 | 
				
			||||||
 | 
						_program
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
  Position* = record
 | 
					  Position* = record
 | 
				
			||||||
    line: Word;
 | 
					    line: Word;
 | 
				
			||||||
@@ -106,56 +113,58 @@ type
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
  CommandLine* = record
 | 
					  CommandLine* = record
 | 
				
			||||||
    input: ^Char;
 | 
					    input: ^Char;
 | 
				
			||||||
	tokenize: Bool;
 | 
						lex: Bool;
 | 
				
			||||||
	syntax_tree: Bool
 | 
						parse: Bool
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(*
 | 
					(*
 | 
				
			||||||
  External procedures.
 | 
					  External procedures.
 | 
				
			||||||
*)
 | 
					*)
 | 
				
			||||||
proc fopen(pathname: ^Char, mode: ^Char) -> ^FILE; extern
 | 
					 | 
				
			||||||
proc fclose(stream: ^FILE) -> Int; extern
 | 
					 | 
				
			||||||
proc fseek(stream: ^FILE, off: Int, whence: Int) -> Int; extern
 | 
					 | 
				
			||||||
proc rewind(stream: ^FILE); extern
 | 
					 | 
				
			||||||
proc ftell(stream: ^FILE) -> Int; extern
 | 
					 | 
				
			||||||
proc fread(ptr: ^Byte, size: Word, nmemb: Word, stream: ^FILE) -> Word; extern
 | 
					 | 
				
			||||||
proc write(fd: Int, buf: ^Byte, Word: Int) -> Int; extern
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc malloc(size: Word) -> ^Byte; extern
 | 
					proc fopen(pathname: ^Char, mode: ^Char) -> ^FILE extern
 | 
				
			||||||
proc free(ptr: ^Byte); extern
 | 
					proc fclose(stream: ^FILE) -> Int extern
 | 
				
			||||||
proc calloc(nmemb: Word, size: Word) -> ^Byte; extern
 | 
					proc fseek(stream: ^FILE, off: Int, whence: Int) -> Int extern
 | 
				
			||||||
proc realloc(ptr: ^Byte, size: Word) -> ^Byte; extern
 | 
					proc rewind(stream: ^FILE) extern
 | 
				
			||||||
 | 
					proc ftell(stream: ^FILE) -> Int extern
 | 
				
			||||||
 | 
					proc fread(ptr: ^Byte, size: Word, nmemb: Word, stream: ^FILE) -> Word extern
 | 
				
			||||||
 | 
					proc write(fd: Int, buf: ^Byte, Word: Int) -> Int extern
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc memset(ptr: ^Char, c: Int, n: Int) -> ^Char; extern
 | 
					proc malloc(size: Word) -> ^Byte extern
 | 
				
			||||||
 | 
					proc free(ptr: ^Byte) extern
 | 
				
			||||||
 | 
					proc calloc(nmemb: Word, size: Word) -> ^Byte extern
 | 
				
			||||||
 | 
					proc realloc(ptr: ^Byte, size: Word) -> ^Byte extern
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc strcmp(s1: ^Char, s2: ^Char) -> Int; extern
 | 
					proc memset(ptr: ^Char, c: Int, n: Int) -> ^Char extern
 | 
				
			||||||
proc strncmp(s1: ^Char, s2: ^Char, n: Word) -> Int; extern
 | 
					 | 
				
			||||||
proc strncpy(dst: ^Char, src: ^Char, dsize: Word) -> ^Char; extern
 | 
					 | 
				
			||||||
proc strcpy(dst: ^Char, src: ^Char) -> ^Char; extern
 | 
					 | 
				
			||||||
proc strlen(ptr: ^Char) -> Word; extern
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc perror(s: ^Char); extern
 | 
					proc strcmp(s1: ^Char, s2: ^Char) -> Int extern
 | 
				
			||||||
proc exit(code: Int) -> !; extern
 | 
					proc strncmp(s1: ^Char, s2: ^Char, n: Word) -> Int extern
 | 
				
			||||||
 | 
					proc strncpy(dst: ^Char, src: ^Char, dsize: Word) -> ^Char extern
 | 
				
			||||||
 | 
					proc strcpy(dst: ^Char, src: ^Char) -> ^Char extern
 | 
				
			||||||
 | 
					proc strlen(ptr: ^Char) -> Word extern
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					proc perror(s: ^Char) extern
 | 
				
			||||||
 | 
					proc exit(code: Int) -> ! extern
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(*
 | 
					(*
 | 
				
			||||||
  Standard procedures.
 | 
					  Standard procedures.
 | 
				
			||||||
*)
 | 
					*)
 | 
				
			||||||
proc reallocarray(ptr: ^Byte, n: Word, size: Word) -> ^Byte;
 | 
					
 | 
				
			||||||
 | 
					proc reallocarray(ptr: ^Byte, n: Word, size: Word) -> ^Byte
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
  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: ^Byte), cast(value.length: Int))
 | 
					  write(0, cast(value.ptr: ^Byte), cast(value.length: Int))
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc write_z(value: ^Char);
 | 
					proc write_z(value: ^Char)
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
  write(0, cast(value: ^Byte), cast(strlen(value): Int))
 | 
					  write(0, cast(value: ^Byte), cast(strlen(value): Int))
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc write_b(value: Bool);
 | 
					proc write_b(value: Bool)
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
  if value then
 | 
					  if value then
 | 
				
			||||||
    write_s("true")
 | 
					    write_s("true")
 | 
				
			||||||
@@ -164,12 +173,12 @@ begin
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc write_c(value: Char);
 | 
					proc write_c(value: Char)
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
  write(0, cast(@value: ^Byte), 1)
 | 
					  write(0, cast(@value: ^Byte), 1)
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc write_i(value: Int);
 | 
					proc write_i(value: Int)
 | 
				
			||||||
var
 | 
					var
 | 
				
			||||||
  digit: Int
 | 
					  digit: Int
 | 
				
			||||||
  n: Word
 | 
					  n: Word
 | 
				
			||||||
@@ -193,42 +202,42 @@ begin
 | 
				
			|||||||
  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
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
  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
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
  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
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
  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
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
  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
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
  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
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
  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
 | 
				
			||||||
@@ -238,7 +247,7 @@ begin
 | 
				
			|||||||
  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
 | 
				
			||||||
@@ -249,7 +258,7 @@ begin
 | 
				
			|||||||
  return result
 | 
					  return result
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc string_buffer_push(buffer: ^StringBuffer, char: Char);
 | 
					proc string_buffer_push(buffer: ^StringBuffer, char: Char)
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
  if buffer^.size >= buffer^.capacity then
 | 
					  if buffer^.size >= buffer^.capacity then
 | 
				
			||||||
    buffer^.capacity := buffer^.capacity + 1024u;
 | 
					    buffer^.capacity := buffer^.capacity + 1024u;
 | 
				
			||||||
@@ -259,12 +268,12 @@ begin
 | 
				
			|||||||
  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
 | 
				
			||||||
@@ -274,15 +283,10 @@ begin
 | 
				
			|||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(*
 | 
					(*
 | 
				
			||||||
  End of standard procedures.
 | 
					  Source code stream procedures.
 | 
				
			||||||
*)
 | 
					*)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc make_position() -> Position;
 | 
					proc read_source(filename: ^Char) -> ^SourceFile
 | 
				
			||||||
begin
 | 
					 | 
				
			||||||
  return Position(1u, 1u)
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc read_source(filename: ^Char) -> ^SourceFile;
 | 
					 | 
				
			||||||
var
 | 
					var
 | 
				
			||||||
  result: ^SourceFile
 | 
					  result: ^SourceFile
 | 
				
			||||||
  file_handle: ^FILE
 | 
					  file_handle: ^FILE
 | 
				
			||||||
@@ -298,7 +302,70 @@ begin
 | 
				
			|||||||
  return result
 | 
					  return result
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc escape_char(escape: Char, result: ^Char) -> Bool;
 | 
					proc source_file_empty(source_input: ^Byte) -> Bool
 | 
				
			||||||
 | 
					var
 | 
				
			||||||
 | 
					  source_file: ^SourceFile
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					  source_file := cast(source_input: ^SourceFile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if source_file^.index > source_file^.size then
 | 
				
			||||||
 | 
					    source_file^.size := fread(cast(@source_file^.buffer: ^Byte), 1u, 1024u, source_file^.handle);
 | 
				
			||||||
 | 
						source_file^.index := 1u
 | 
				
			||||||
 | 
					  end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return source_file^.size = 0u
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					proc source_file_head(source_input: ^Byte) -> Char
 | 
				
			||||||
 | 
					var
 | 
				
			||||||
 | 
					  source_file: ^SourceFile
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					  source_file := cast(source_input: ^SourceFile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return source_file^.buffer[source_file^.index]
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					proc source_file_advance(source_input: ^Byte)
 | 
				
			||||||
 | 
					var
 | 
				
			||||||
 | 
					  source_file: ^SourceFile
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					  source_file := cast(source_input: ^SourceFile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  source_file^.index := source_file^.index + 1u
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					proc source_code_empty(source_code: ^SourceCode) -> Bool
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					  return source_code^.empty(source_code^.input)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					proc source_code_head(source_code: SourceCode) -> Char
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					  return source_code.head(source_code.input)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					proc source_code_advance(source_code: ^SourceCode)
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					  source_code^.advance(source_code^.input);
 | 
				
			||||||
 | 
					  source_code^.position.column := source_code^.position.column
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					proc source_code_break(source_code: ^SourceCode)
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					  source_code^.position.line := source_code^.position.line + 1u;
 | 
				
			||||||
 | 
					  source_code^.position.column := 0u
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					proc source_code_expect(source_code: ^SourceCode, expected: Char) -> Bool
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					  return ~source_code_empty(source_code) & source_code_head(source_code^) = expected
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(*
 | 
				
			||||||
 | 
					  Token procedures.
 | 
				
			||||||
 | 
					*)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					proc escape_char(escape: Char, result: ^Char) -> Bool
 | 
				
			||||||
var
 | 
					var
 | 
				
			||||||
  successful: Bool
 | 
					  successful: Bool
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
@@ -344,66 +411,7 @@ begin
 | 
				
			|||||||
  return successful
 | 
					  return successful
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc source_file_empty(source_input: ^Byte) -> Bool;
 | 
					proc skip_spaces(source_code: ^SourceCode)
 | 
				
			||||||
var
 | 
					 | 
				
			||||||
  source_file: ^SourceFile
 | 
					 | 
				
			||||||
begin
 | 
					 | 
				
			||||||
  source_file := cast(source_input: ^SourceFile);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if source_file^.index > source_file^.size then
 | 
					 | 
				
			||||||
    source_file^.size := fread(cast(@source_file^.buffer: ^Byte), 1u, 1024u, source_file^.handle);
 | 
					 | 
				
			||||||
	source_file^.index := 1u
 | 
					 | 
				
			||||||
  end;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return source_file^.size = 0u
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc source_file_head(source_input: ^Byte) -> Char;
 | 
					 | 
				
			||||||
var
 | 
					 | 
				
			||||||
  source_file: ^SourceFile
 | 
					 | 
				
			||||||
begin
 | 
					 | 
				
			||||||
  source_file := cast(source_input: ^SourceFile);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return source_file^.buffer[source_file^.index]
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc source_file_advance(source_input: ^Byte);
 | 
					 | 
				
			||||||
var
 | 
					 | 
				
			||||||
  source_file: ^SourceFile
 | 
					 | 
				
			||||||
begin
 | 
					 | 
				
			||||||
  source_file := cast(source_input: ^SourceFile);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  source_file^.index := source_file^.index + 1u
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc source_code_empty(source_code: ^SourceCode) -> Bool;
 | 
					 | 
				
			||||||
begin
 | 
					 | 
				
			||||||
  return source_code^.empty(source_code^.input)
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc source_code_head(source_code: SourceCode) -> Char;
 | 
					 | 
				
			||||||
begin
 | 
					 | 
				
			||||||
  return source_code.head(source_code.input)
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc source_code_advance(source_code: ^SourceCode);
 | 
					 | 
				
			||||||
begin
 | 
					 | 
				
			||||||
  source_code^.advance(source_code^.input);
 | 
					 | 
				
			||||||
  source_code^.position.column := source_code^.position.column
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc source_code_break(source_code: ^SourceCode);
 | 
					 | 
				
			||||||
begin
 | 
					 | 
				
			||||||
  source_code^.position.line := source_code^.position.line + 1u;
 | 
					 | 
				
			||||||
  source_code^.position.column := 0u
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc source_code_expect(source_code: ^SourceCode, expected: Char) -> Bool;
 | 
					 | 
				
			||||||
begin
 | 
					 | 
				
			||||||
  return ~source_code_empty(source_code) & source_code_head(source_code^) = expected
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc skip_spaces(source_code: ^SourceCode);
 | 
					 | 
				
			||||||
var
 | 
					var
 | 
				
			||||||
  current: Char
 | 
					  current: Char
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
@@ -419,12 +427,12 @@ begin
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc is_ident(char: Char) -> Bool;
 | 
					proc is_ident(char: Char) -> Bool
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
  return is_alnum(char) or char = '_'
 | 
					  return is_alnum(char) or char = '_'
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc lex_identifier(source_code: ^SourceCode, token_content: ^StringBuffer);
 | 
					proc lex_identifier(source_code: ^SourceCode, token_content: ^StringBuffer)
 | 
				
			||||||
var
 | 
					var
 | 
				
			||||||
  content_length: Word
 | 
					  content_length: Word
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
@@ -434,7 +442,7 @@ begin
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc lex_comment(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool;
 | 
					proc lex_comment(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool
 | 
				
			||||||
var
 | 
					var
 | 
				
			||||||
  trailing: Word
 | 
					  trailing: Word
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
@@ -457,7 +465,7 @@ begin
 | 
				
			|||||||
  return trailing = 2u
 | 
					  return trailing = 2u
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc lex_character(source_code: ^SourceCode, token_content: ^Char) -> Bool;
 | 
					proc lex_character(source_code: ^SourceCode, token_content: ^Char) -> Bool
 | 
				
			||||||
var
 | 
					var
 | 
				
			||||||
  successful: Bool
 | 
					  successful: Bool
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
@@ -479,7 +487,7 @@ begin
 | 
				
			|||||||
  return successful
 | 
					  return successful
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc lex_string(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool;
 | 
					proc lex_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
 | 
				
			||||||
@@ -504,7 +512,7 @@ begin
 | 
				
			|||||||
  return is_valid
 | 
					  return is_valid
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc lex_number(source_code: ^SourceCode, token_content: ^Int);
 | 
					proc lex_number(source_code: ^SourceCode, token_content: ^Int)
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
  token_content^ := 0;
 | 
					  token_content^ := 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -515,7 +523,7 @@ begin
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc print_tokens(tokens: ^Token, tokens_size: Word);
 | 
					proc print_tokens(tokens: ^Token, tokens_size: Word)
 | 
				
			||||||
var
 | 
					var
 | 
				
			||||||
  current_token: ^Token
 | 
					  current_token: ^Token
 | 
				
			||||||
  i: Word
 | 
					  i: Word
 | 
				
			||||||
@@ -549,8 +557,8 @@ begin
 | 
				
			|||||||
	    write_s("CONST")
 | 
						    write_s("CONST")
 | 
				
			||||||
	  | TokenKind._var:
 | 
						  | TokenKind._var:
 | 
				
			||||||
	    write_s("VAR")
 | 
						    write_s("VAR")
 | 
				
			||||||
   	  | TokenKind.array:
 | 
					   	  | TokenKind._case:
 | 
				
			||||||
	    write_s("ARRAY")
 | 
						    write_s("CASE")
 | 
				
			||||||
	  | TokenKind._of:
 | 
						  | TokenKind._of:
 | 
				
			||||||
	    write_s("OF")
 | 
						    write_s("OF")
 | 
				
			||||||
	  | TokenKind._type:
 | 
						  | TokenKind._type:
 | 
				
			||||||
@@ -559,8 +567,8 @@ begin
 | 
				
			|||||||
	    write_s("RECORD")
 | 
						    write_s("RECORD")
 | 
				
			||||||
	  | TokenKind._union:
 | 
						  | TokenKind._union:
 | 
				
			||||||
	    write_s("UNION")
 | 
						    write_s("UNION")
 | 
				
			||||||
	  | TokenKind.pointer:
 | 
						  | TokenKind.pipe:
 | 
				
			||||||
	    write_s("POINTER")
 | 
						    write_s("|")
 | 
				
			||||||
	  | TokenKind.to:
 | 
						  | TokenKind.to:
 | 
				
			||||||
	    write_s("TO")
 | 
						    write_s("TO")
 | 
				
			||||||
	  | TokenKind.boolean:
 | 
						  | TokenKind.boolean:
 | 
				
			||||||
@@ -570,11 +578,11 @@ begin
 | 
				
			|||||||
	  | TokenKind._nil:
 | 
						  | TokenKind._nil:
 | 
				
			||||||
	    write_s("NIL")
 | 
						    write_s("NIL")
 | 
				
			||||||
	  | TokenKind.and:
 | 
						  | TokenKind.and:
 | 
				
			||||||
	    write_s("AND")
 | 
						    write_s("&")
 | 
				
			||||||
	  | TokenKind._or:
 | 
						  | TokenKind._or:
 | 
				
			||||||
	    write_s("OR")
 | 
						    write_s("OR")
 | 
				
			||||||
	  | TokenKind.not:
 | 
						  | TokenKind.not:
 | 
				
			||||||
	    write_s("NOT")
 | 
						    write_s("~")
 | 
				
			||||||
	  | TokenKind._return:
 | 
						  | TokenKind._return:
 | 
				
			||||||
	    write_s("RETURN")
 | 
						    write_s("RETURN")
 | 
				
			||||||
	  | TokenKind._cast:
 | 
						  | TokenKind._cast:
 | 
				
			||||||
@@ -587,6 +595,9 @@ begin
 | 
				
			|||||||
	    write_c('<');
 | 
						    write_c('<');
 | 
				
			||||||
        write_s(current_token^.value.string);
 | 
					        write_s(current_token^.value.string);
 | 
				
			||||||
	    write_c('>')
 | 
						    write_c('>')
 | 
				
			||||||
 | 
						  | TokenKind.trait:
 | 
				
			||||||
 | 
						    write_c('#');
 | 
				
			||||||
 | 
							write_s(current_token^.value.string)
 | 
				
			||||||
	  | TokenKind.left_paren:
 | 
						  | TokenKind.left_paren:
 | 
				
			||||||
	    write_s("(")
 | 
						    write_s("(")
 | 
				
			||||||
	  | TokenKind.right_paren:
 | 
						  | TokenKind.right_paren:
 | 
				
			||||||
@@ -653,6 +664,8 @@ begin
 | 
				
			|||||||
	    write_c('!')
 | 
						    write_c('!')
 | 
				
			||||||
	  | TokenKind.arrow:
 | 
						  | TokenKind.arrow:
 | 
				
			||||||
	    write_s("->")
 | 
						    write_s("->")
 | 
				
			||||||
 | 
						  | TokenKind._program:
 | 
				
			||||||
 | 
						    write_s("PROGRAM")
 | 
				
			||||||
	  else
 | 
						  else
 | 
				
			||||||
	    write_s("UNKNOWN<");
 | 
						    write_s("UNKNOWN<");
 | 
				
			||||||
	    write_i(cast(current_token^.kind: Int));
 | 
						    write_i(cast(current_token^.kind: Int));
 | 
				
			||||||
@@ -665,68 +678,62 @@ begin
 | 
				
			|||||||
  write_c('\n')
 | 
					  write_c('\n')
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc categorize_identifier(token_content: String) -> Token;
 | 
					proc categorize_identifier(token_content: String) -> Token
 | 
				
			||||||
var
 | 
					var
 | 
				
			||||||
  current_token: Token
 | 
					  current_token: Token
 | 
				
			||||||
begin
 | 
					begin
 | 
				
			||||||
  if "if" = token_content then
 | 
					  if token_content = "if" then
 | 
				
			||||||
	current_token.kind := TokenKind._if
 | 
						current_token.kind := TokenKind._if
 | 
				
			||||||
  elsif "then" = token_content then
 | 
					  elsif token_content = "then" then
 | 
				
			||||||
	current_token.kind := TokenKind._then
 | 
						current_token.kind := TokenKind._then
 | 
				
			||||||
  elsif "else" = token_content then
 | 
					  elsif token_content = "else" then
 | 
				
			||||||
	current_token.kind := TokenKind._else
 | 
						current_token.kind := TokenKind._else
 | 
				
			||||||
  elsif "elsif" = token_content then
 | 
					  elsif token_content = "elsif" then
 | 
				
			||||||
	current_token.kind := TokenKind._elsif
 | 
						current_token.kind := TokenKind._elsif
 | 
				
			||||||
  elsif "while" = token_content then
 | 
					  elsif token_content = "while" then
 | 
				
			||||||
	current_token.kind := TokenKind._while
 | 
						current_token.kind := TokenKind._while
 | 
				
			||||||
  elsif "do" = token_content then
 | 
					  elsif token_content = "do" then
 | 
				
			||||||
	current_token.kind := TokenKind._do
 | 
						current_token.kind := TokenKind._do
 | 
				
			||||||
  elsif "proc" = token_content then
 | 
					  elsif token_content = "proc" then
 | 
				
			||||||
	current_token.kind := TokenKind._proc
 | 
						current_token.kind := TokenKind._proc
 | 
				
			||||||
  elsif "begin" = token_content then
 | 
					  elsif token_content = "begin" then
 | 
				
			||||||
	current_token.kind := TokenKind._begin
 | 
						current_token.kind := TokenKind._begin
 | 
				
			||||||
  elsif "end" = token_content then
 | 
					  elsif token_content = "end" then
 | 
				
			||||||
	current_token.kind := TokenKind._end
 | 
						current_token.kind := TokenKind._end
 | 
				
			||||||
  elsif "extern" = token_content then
 | 
					  elsif token_content = "extern" then
 | 
				
			||||||
	current_token.kind := TokenKind._extern
 | 
						current_token.kind := TokenKind._extern
 | 
				
			||||||
  elsif "const" = token_content then
 | 
					  elsif token_content = "const" then
 | 
				
			||||||
	current_token.kind := TokenKind._const
 | 
						current_token.kind := TokenKind._const
 | 
				
			||||||
  elsif "var" = token_content then
 | 
					  elsif token_content = "var" then
 | 
				
			||||||
	current_token.kind := TokenKind._var
 | 
						current_token.kind := TokenKind._var
 | 
				
			||||||
  elsif "array" = token_content then
 | 
					  elsif token_content = "case" then
 | 
				
			||||||
	current_token.kind := TokenKind.array
 | 
						current_token.kind := TokenKind._case
 | 
				
			||||||
  elsif "of" = token_content then
 | 
					  elsif token_content = "of" then
 | 
				
			||||||
	current_token.kind := TokenKind._of
 | 
						current_token.kind := TokenKind._of
 | 
				
			||||||
  elsif "type" = token_content then
 | 
					  elsif token_content = "type" then
 | 
				
			||||||
	current_token.kind := TokenKind._type
 | 
						current_token.kind := TokenKind._type
 | 
				
			||||||
  elsif "record" = token_content then
 | 
					  elsif token_content = "record" then
 | 
				
			||||||
	current_token.kind := TokenKind._record
 | 
						current_token.kind := TokenKind._record
 | 
				
			||||||
  elsif "union" = token_content then
 | 
					  elsif token_content = "union" then
 | 
				
			||||||
	current_token.kind := TokenKind._union
 | 
						current_token.kind := TokenKind._union
 | 
				
			||||||
  elsif "pointer" = token_content then
 | 
					  elsif token_content = "true" then
 | 
				
			||||||
	current_token.kind := TokenKind.pointer
 | 
					 | 
				
			||||||
  elsif "to" = token_content then
 | 
					 | 
				
			||||||
	current_token.kind := TokenKind.to
 | 
					 | 
				
			||||||
  elsif "true" = token_content then
 | 
					 | 
				
			||||||
	current_token.kind := TokenKind.boolean;
 | 
						current_token.kind := TokenKind.boolean;
 | 
				
			||||||
	current_token.value.boolean_value := true
 | 
						current_token.value.boolean_value := true
 | 
				
			||||||
  elsif "false" = token_content then
 | 
					  elsif token_content = "false" then
 | 
				
			||||||
	current_token.kind := TokenKind.boolean;
 | 
						current_token.kind := TokenKind.boolean;
 | 
				
			||||||
	current_token.value.boolean_value := false
 | 
						current_token.value.boolean_value := false
 | 
				
			||||||
  elsif "nil" = token_content then
 | 
					  elsif token_content = "nil" then
 | 
				
			||||||
	current_token.kind := TokenKind._nil
 | 
						current_token.kind := TokenKind._nil
 | 
				
			||||||
  elsif "and" = token_content then
 | 
					  elsif token_content = "or" then
 | 
				
			||||||
	current_token.kind := TokenKind.and
 | 
					 | 
				
			||||||
  elsif "or" = token_content then
 | 
					 | 
				
			||||||
	current_token.kind := TokenKind._or
 | 
						current_token.kind := TokenKind._or
 | 
				
			||||||
  elsif "not" = token_content then
 | 
					  elsif token_content = "return" then
 | 
				
			||||||
	current_token.kind := TokenKind.not
 | 
					 | 
				
			||||||
  elsif "return" = token_content then
 | 
					 | 
				
			||||||
	current_token.kind := TokenKind._return
 | 
						current_token.kind := TokenKind._return
 | 
				
			||||||
  elsif "cast" = token_content then
 | 
					  elsif token_content = "cast" then
 | 
				
			||||||
	current_token.kind := TokenKind._cast
 | 
						current_token.kind := TokenKind._cast
 | 
				
			||||||
  elsif "defer" = token_content then
 | 
					  elsif token_content = "defer" then
 | 
				
			||||||
	current_token.kind := TokenKind._defer
 | 
						current_token.kind := TokenKind._defer
 | 
				
			||||||
 | 
					  elsif token_content = "program" then
 | 
				
			||||||
 | 
						current_token.kind := TokenKind._program
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
	current_token.kind := TokenKind.identifier;
 | 
						current_token.kind := TokenKind.identifier;
 | 
				
			||||||
	current_token.value.string := string_dup(token_content)
 | 
						current_token.value.string := string_dup(token_content)
 | 
				
			||||||
@@ -735,7 +742,7 @@ begin
 | 
				
			|||||||
  return current_token
 | 
					  return current_token
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc tokenize(source_code: SourceCode, tokens_size: ^Word) -> ^Token;
 | 
					proc tokenize(source_code: SourceCode, tokens_size: ^Word) -> ^Token
 | 
				
			||||||
var
 | 
					var
 | 
				
			||||||
  tokens, current_token: ^Token
 | 
					  tokens, current_token: ^Token
 | 
				
			||||||
  first_char: Char
 | 
					  first_char: Char
 | 
				
			||||||
@@ -755,6 +762,12 @@ begin
 | 
				
			|||||||
    if is_alpha(first_char) or first_char = '_' then
 | 
					    if is_alpha(first_char) or first_char = '_' then
 | 
				
			||||||
      lex_identifier(@source_code, @token_buffer);
 | 
					      lex_identifier(@source_code, @token_buffer);
 | 
				
			||||||
      current_token^ := categorize_identifier(string_buffer_clear(@token_buffer))
 | 
					      current_token^ := categorize_identifier(string_buffer_clear(@token_buffer))
 | 
				
			||||||
 | 
						elsif first_char = '#' then
 | 
				
			||||||
 | 
						  source_code_advance(@source_code);
 | 
				
			||||||
 | 
						  lex_identifier(@source_code, @token_buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  current_token^.kind := TokenKind.trait;
 | 
				
			||||||
 | 
						  current_token^.value.string := string_dup(string_buffer_clear(@token_buffer))
 | 
				
			||||||
	elsif is_digit(first_char) then
 | 
						elsif is_digit(first_char) then
 | 
				
			||||||
	  lex_number(@source_code, @current_token^.value.int_value);
 | 
						  lex_number(@source_code, @current_token^.value.int_value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -894,6 +907,15 @@ begin
 | 
				
			|||||||
	elsif first_char = '!' then
 | 
						elsif first_char = '!' then
 | 
				
			||||||
	  current_token^.kind := TokenKind.exclamation;
 | 
						  current_token^.kind := TokenKind.exclamation;
 | 
				
			||||||
	  source_code_advance(@source_code)
 | 
						  source_code_advance(@source_code)
 | 
				
			||||||
 | 
						elsif first_char = '&' then
 | 
				
			||||||
 | 
						  current_token^.kind := TokenKind.and;
 | 
				
			||||||
 | 
						  source_code_advance(@source_code)
 | 
				
			||||||
 | 
						elsif first_char = '~' then
 | 
				
			||||||
 | 
						  current_token^.kind := TokenKind.not;
 | 
				
			||||||
 | 
						  source_code_advance(@source_code)
 | 
				
			||||||
 | 
						elsif first_char = '|' then
 | 
				
			||||||
 | 
						  current_token^.kind := TokenKind.pipe;
 | 
				
			||||||
 | 
						  source_code_advance(@source_code)
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
	  current_token^.kind := TokenKind.unknown;
 | 
						  current_token^.kind := TokenKind.unknown;
 | 
				
			||||||
	  source_code_advance(@source_code)
 | 
						  source_code_advance(@source_code)
 | 
				
			||||||
@@ -912,7 +934,11 @@ begin
 | 
				
			|||||||
  return tokens
 | 
					  return tokens
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc parse_command_line*(argc: Int, argv: ^^Char) -> ^CommandLine;
 | 
					(*
 | 
				
			||||||
 | 
					  Command line handling.
 | 
				
			||||||
 | 
					*)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					proc parse_command_line*(argc: Int, argv: ^^Char) -> ^CommandLine
 | 
				
			||||||
var
 | 
					var
 | 
				
			||||||
  parameter: ^^Char
 | 
					  parameter: ^^Char
 | 
				
			||||||
  i: Int
 | 
					  i: Int
 | 
				
			||||||
@@ -920,23 +946,26 @@ var
 | 
				
			|||||||
begin
 | 
					begin
 | 
				
			||||||
  i := 1;
 | 
					  i := 1;
 | 
				
			||||||
  result := cast(malloc(#size(CommandLine)): ^CommandLine);
 | 
					  result := cast(malloc(#size(CommandLine)): ^CommandLine);
 | 
				
			||||||
  result^.tokenize := false;
 | 
					  result^.lex := false;
 | 
				
			||||||
  result^.syntax_tree := false;
 | 
					  result^.parse := false;
 | 
				
			||||||
  result^.input := nil;
 | 
					  result^.input := nil;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  while i < argc do
 | 
					  while i < argc do
 | 
				
			||||||
    parameter := argv + i;
 | 
					    parameter := argv + i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if strcmp(parameter^, "--tokenize\0".ptr) = 0 then
 | 
					    if strcmp(parameter^, "--lex\0".ptr) = 0 then
 | 
				
			||||||
      result^.tokenize := true
 | 
					      result^.lex := true
 | 
				
			||||||
    elsif strcmp(parameter^, "--syntax-tree\0".ptr) = 0 then
 | 
					    elsif strcmp(parameter^, "--parse\0".ptr) = 0 then
 | 
				
			||||||
      result^.syntax_tree := true
 | 
					      result^.parse := true
 | 
				
			||||||
    elsif parameter^^ <> '-' then
 | 
					    elsif parameter^^ <> '-' then
 | 
				
			||||||
 | 
						  if result^.input <> nil then
 | 
				
			||||||
 | 
							write_s("Fatal error: Only one source file can be given.\n");
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						  end;
 | 
				
			||||||
      result^.input := parameter^
 | 
					      result^.input := parameter^
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
      write_s("Fatal error: Unknown command line options:");
 | 
					      write_s("Fatal error: Unknown command line options: ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      write_c(' ');
 | 
					 | 
				
			||||||
      write_z(parameter^);
 | 
					      write_z(parameter^);
 | 
				
			||||||
      write_s(".\n");
 | 
					      write_s(".\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -953,7 +982,11 @@ begin
 | 
				
			|||||||
  return result
 | 
					  return result
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc process(argc: Int, argv: ^^Char) -> Int;
 | 
					(*
 | 
				
			||||||
 | 
					  Compilation entry.
 | 
				
			||||||
 | 
					*)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					proc process(argc: Int, argv: ^^Char) -> Int
 | 
				
			||||||
var
 | 
					var
 | 
				
			||||||
  tokens: ^Token
 | 
					  tokens: ^Token
 | 
				
			||||||
  tokens_size: Word
 | 
					  tokens_size: Word
 | 
				
			||||||
@@ -969,7 +1002,7 @@ begin
 | 
				
			|||||||
  end;
 | 
					  end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if return_code = 0 then
 | 
					  if return_code = 0 then
 | 
				
			||||||
	source_code.position := make_position();
 | 
						source_code.position := Position(1u, 1u);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	source_code.input := cast(read_source(command_line^.input): ^Byte);
 | 
						source_code.input := cast(read_source(command_line^.input): ^Byte);
 | 
				
			||||||
	source_code.empty := source_file_empty;
 | 
						source_code.empty := source_file_empty;
 | 
				
			||||||
@@ -986,7 +1019,7 @@ begin
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    fclose(cast(source_code.input: ^SourceFile)^.handle);
 | 
					    fclose(cast(source_code.input: ^SourceFile)^.handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if command_line^.tokenize then
 | 
					    if command_line^.lex then
 | 
				
			||||||
      print_tokens(tokens, tokens_size)
 | 
					      print_tokens(tokens, tokens_size)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end;
 | 
					  end;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										204
									
								
								tools/init.c
									
									
									
									
									
								
							
							
						
						
									
										204
									
								
								tools/init.c
									
									
									
									
									
								
							@@ -1,204 +0,0 @@
 | 
				
			|||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
#include <dirent.h>
 | 
					 | 
				
			||||||
#include <fcntl.h>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
#include <sys/stat.h>
 | 
					 | 
				
			||||||
#include <sys/wait.h>
 | 
					 | 
				
			||||||
#include <sys/reboot.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define FILENAME_BUFFER_SIZE 256
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
size_t read_command(int descriptor, char *command_buffer)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    ssize_t bytes_read = 0;
 | 
					 | 
				
			||||||
    size_t read_so_far = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    while ((bytes_read = read(descriptor, command_buffer + read_so_far, FILENAME_BUFFER_SIZE - read_so_far - 1)) > 0)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        read_so_far += bytes_read;
 | 
					 | 
				
			||||||
        if (read_so_far >= FILENAME_BUFFER_SIZE - 1)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    command_buffer[read_so_far] = 0;
 | 
					 | 
				
			||||||
    return read_so_far;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum status
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    status_success,
 | 
					 | 
				
			||||||
    status_failure,
 | 
					 | 
				
			||||||
    status_warning,
 | 
					 | 
				
			||||||
    status_fatal
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
unsigned int make_path(char *destination, const char *directory, const char *filename, const char *extension)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    unsigned int i = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (; i < FILENAME_BUFFER_SIZE; i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if (directory[i] == 0)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        destination[i] = directory[i];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    for (int j = 0; i < FILENAME_BUFFER_SIZE; i++, j++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if (filename[j] == 0)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        destination[i] = filename[j];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (extension == NULL)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        goto done;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    for (int j = 0; i < FILENAME_BUFFER_SIZE; i++, j++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if (extension[j] == 0)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        destination[i] = extension[j];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
done:
 | 
					 | 
				
			||||||
    destination[i] = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return i;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum status run_test(const char *file_entry_name)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    printf("Running %s. ", file_entry_name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    char filename[FILENAME_BUFFER_SIZE];
 | 
					 | 
				
			||||||
    char command_buffer[FILENAME_BUFFER_SIZE];
 | 
					 | 
				
			||||||
    char file_buffer[256];
 | 
					 | 
				
			||||||
    int pipe_ends[2];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (pipe(pipe_ends) == -1)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        perror("pipe");
 | 
					 | 
				
			||||||
        return status_fatal;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    make_path(filename, "./tests/", file_entry_name, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int child_pid = fork();
 | 
					 | 
				
			||||||
    if (child_pid == -1)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return status_fatal;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else if (child_pid == 0)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        close(STDIN_FILENO);
 | 
					 | 
				
			||||||
        close(STDERR_FILENO);
 | 
					 | 
				
			||||||
        close(pipe_ends[0]); // Close the read end.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (dup2(pipe_ends[1], STDOUT_FILENO) == -1)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            perror("dup2");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            execl(filename, filename);
 | 
					 | 
				
			||||||
            perror("execl");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        close(STDOUT_FILENO);
 | 
					 | 
				
			||||||
        close(pipe_ends[1]);
 | 
					 | 
				
			||||||
        _exit(1);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        close(pipe_ends[1]); // Close the write end.
 | 
					 | 
				
			||||||
        read_command(pipe_ends[0], command_buffer);
 | 
					 | 
				
			||||||
        close(pipe_ends[0]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        int wait_status = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        make_path(filename, "./expectations/", file_entry_name, ".txt");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        FILE *expectation_descriptor = fopen(filename, "r");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (expectation_descriptor == NULL)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return status_warning;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        size_t read_from_file = fread(file_buffer, 1, sizeof(file_buffer) - 1, expectation_descriptor);
 | 
					 | 
				
			||||||
        fclose(expectation_descriptor);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        file_buffer[read_from_file] = 0;
 | 
					 | 
				
			||||||
        for (unsigned int i = 0; ; ++i)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (command_buffer[i] == 0 && file_buffer[i] == 0)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                fwrite("\n", 1, 1, stdout);
 | 
					 | 
				
			||||||
                return status_success;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (command_buffer[i] != file_buffer[i])
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                printf("Failed. Got:\n%s", command_buffer);
 | 
					 | 
				
			||||||
                return status_failure;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct summary
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    size_t total;
 | 
					 | 
				
			||||||
    size_t failure;
 | 
					 | 
				
			||||||
    size_t success;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void walk()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    DIR *directory_stream = opendir("./tests");
 | 
					 | 
				
			||||||
    struct dirent *file_entry;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    struct summary test_summary = { .total = 0, .failure = 0, .success = 0 };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    while ((file_entry = readdir(directory_stream)) != NULL)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if (file_entry->d_name[0] == '.')
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            continue;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        ++test_summary.total;
 | 
					 | 
				
			||||||
        switch (run_test(file_entry->d_name))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            case status_failure:
 | 
					 | 
				
			||||||
                ++test_summary.failure;
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case status_success:
 | 
					 | 
				
			||||||
                ++test_summary.success;
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case status_warning:
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case status_fatal:
 | 
					 | 
				
			||||||
                goto end_walk;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    printf("Successful: %lu, Failed: %lu, Total: %lu.\n",
 | 
					 | 
				
			||||||
            test_summary.success, test_summary.failure, test_summary.total);
 | 
					 | 
				
			||||||
end_walk:
 | 
					 | 
				
			||||||
    closedir(directory_stream);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int dev_console = open("/dev/console", O_WRONLY);
 | 
					 | 
				
			||||||
    if (dev_console != -1)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        dup2(dev_console, STDOUT_FILENO);
 | 
					 | 
				
			||||||
        walk();
 | 
					 | 
				
			||||||
        close(dev_console);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    sync();
 | 
					 | 
				
			||||||
    reboot(RB_POWER_OFF);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Reference in New Issue
	
	Block a user