From fccea0f93831f96d3f8ba6fa9ef54e827e16379e Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Sun, 18 May 2025 22:35:49 +0200 Subject: [PATCH] Remove semicolons after field declarations --- Rakefile | 4 +- boot/parser.yy | 4 +- gcc/elna-generic.cc | 2 +- source.elna | 761 +++++++++++++++++++++++--------------------- 4 files changed, 412 insertions(+), 359 deletions(-) diff --git a/Rakefile b/Rakefile index d270857..8f20428 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,6 @@ # This Source Code Form is subject to the terms of the Mozilla Public License, # v. 2.0. If a copy of the MPL was not distributed with this file, You can -# obtain one at https://mozilla.org/MPL/2.0/. -} +# obtain one at https://mozilla.org/MPL/2.0/. require 'pathname' require 'open3' @@ -21,7 +21,7 @@ directory HOST_GCC directory HOST_INSTALL task default: [TMP + 'elna'] do - sh (TMP + 'elna').to_path, '--lex', 'source.elna' + sh (TMP + 'elna').to_path, '--parse', 'source.elna' end namespace :boot do diff --git a/boot/parser.yy b/boot/parser.yy index 575d752..28c5df9 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -454,9 +454,9 @@ optional_statements: field_declaration: IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); } required_fields: - field_declaration ";" required_fields + field_declaration required_fields { - std::swap($$, $3); + std::swap($$, $2); $$.emplace($$.cbegin(), $1); } | field_declaration { $$.emplace_back($1); } diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index c96e28f..b6b2354 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -620,7 +620,7 @@ namespace elna::gcc else { error_at(expression_location, - "invalid operands of type '%s' and '%s' for operator %s", + "Invalid operands of type '%s' and '%s' for operator %s", print_type(left_type).c_str(), print_type(right_type).c_str(), elna::boot::print_binary_operator(expression->operation())); return error_mark_node; diff --git a/source.elna b/source.elna index 822f6b7..7fbe0aa 100644 --- a/source.elna +++ b/source.elna @@ -1,3 +1,6 @@ +(* This Source Code Form is subject to the terms of the Mozilla Public License, + v. 2.0. If a copy of the MPL was not distributed with this file, You can + obtain one at https://mozilla.org/MPL/2.0/. *) program import dummy @@ -78,48 +81,52 @@ type _import ) Position* = record - line: Word; + line: Word column: Word end Location* = record - first: Position; + first: Position last: Position end SourceFile* = record - buffer: [1024]Char; - handle: ^FILE; - size: Word; + buffer: [1024]Char + handle: ^FILE + size: Word index: Word end FILE* = record end StringBuffer* = record - data: ^Byte; - size: Word; + data: ^Byte + size: Word capacity: Word end SourceCode = record - position: Position; + position: Position - input: ^Byte; - empty: proc(^Byte) -> Bool; - advance: proc(^Byte); + input: ^Byte + empty: proc(^Byte) -> Bool + advance: proc(^Byte) head: proc(^Byte) -> Char end Token* = record - kind: TokenKind; + kind: TokenKind value: union - int_value: Int; - string: String; - boolean_value: Bool; + int_value: Int + string: String + boolean_value: Bool char_value: Char - end; + end location: Location end CommandLine* = record - input: ^Char; - lex: Bool; + input: ^Char + lex: Bool parse: Bool end + Lexer* = record + length: Word + data: ^Token + end (* External procedures. @@ -359,7 +366,7 @@ end Token procedures. *) -proc escape_char(escape: Char, result: ^Char) -> Bool; +proc lexer_escape(escape: Char, result: ^Char) -> Bool; var successful: Bool begin @@ -405,7 +412,8 @@ begin return successful end -proc skip_spaces(source_code: ^SourceCode); +(* Skip spaces. *) +proc lexer_spaces(source_code: ^SourceCode); var current: Char begin @@ -419,21 +427,22 @@ begin end end -proc is_ident(char: Char) -> Bool; +(* Checker whether the character is allowed in an identificator. *) +proc lexer_is_ident(char: Char) -> Bool; return is_alnum(char) or char = '_' end -proc lex_identifier(source_code: ^SourceCode, token_content: ^StringBuffer); +proc lexer_identifier(source_code: ^SourceCode, token_content: ^StringBuffer); var content_length: Word begin - while ~source_code_empty(source_code) & is_ident(source_code_head(source_code^)) do + while ~source_code_empty(source_code) & lexer_is_ident(source_code_head(source_code^)) do string_buffer_push(token_content, source_code_head(source_code^)); source_code_advance(source_code) end end -proc lex_comment(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool; +proc lexer_comment(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool; var trailing: Word begin @@ -456,7 +465,7 @@ begin return trailing = 2u end -proc lex_character(source_code: ^SourceCode, token_content: ^Char) -> Bool; +proc lexer_character(source_code: ^SourceCode, token_content: ^Char) -> Bool; var successful: Bool begin @@ -466,7 +475,7 @@ begin if source_code_head(source_code^) = '\\' then source_code_advance(source_code); - successful := ~source_code_empty(source_code) & escape_char(source_code_head(source_code^), token_content) + successful := ~source_code_empty(source_code) & lexer_escape(source_code_head(source_code^), token_content) else token_content^ := source_code_head(source_code^); successful := true @@ -478,7 +487,7 @@ begin return successful end -proc lex_string(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool; +proc lexer_string(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool; var token_end, constructed_string: ^Char token_length: Word @@ -488,7 +497,7 @@ begin is_valid := true; while is_valid & ~source_code_empty(source_code) & source_code_head(source_code^) <> '"' do - is_valid := lex_character(source_code, @next_char); + is_valid := lexer_character(source_code, @next_char); if is_valid then string_buffer_push(token_content, next_char) @@ -503,7 +512,7 @@ begin return is_valid end -proc lex_number(source_code: ^SourceCode, token_content: ^Int); +proc lexer_number(source_code: ^SourceCode, token_content: ^Int); begin token_content^ := 0; @@ -514,7 +523,342 @@ begin end end -proc print_tokens(tokens: ^Token, tokens_size: Word); +(* Categorize an identifier. *) +proc lexer_categorize(token_content: String) -> Token; +var + current_token: Token +begin + if token_content = "if" then + current_token.kind := TokenKind._if + elsif token_content = "then" then + current_token.kind := TokenKind._then + elsif token_content = "else" then + current_token.kind := TokenKind._else + elsif token_content = "elsif" then + current_token.kind := TokenKind._elsif + elsif token_content = "while" then + current_token.kind := TokenKind._while + elsif token_content = "do" then + current_token.kind := TokenKind._do + elsif token_content = "proc" then + current_token.kind := TokenKind._proc + elsif token_content = "begin" then + current_token.kind := TokenKind._begin + elsif token_content = "end" then + current_token.kind := TokenKind._end + elsif token_content = "extern" then + current_token.kind := TokenKind._extern + elsif token_content = "const" then + current_token.kind := TokenKind._const + elsif token_content = "var" then + current_token.kind := TokenKind._var + elsif token_content = "case" then + current_token.kind := TokenKind._case + elsif token_content = "of" then + current_token.kind := TokenKind._of + elsif token_content = "type" then + current_token.kind := TokenKind._type + elsif token_content = "record" then + current_token.kind := TokenKind._record + elsif token_content = "union" then + current_token.kind := TokenKind._union + elsif token_content = "true" then + current_token.kind := TokenKind.boolean; + current_token.value.boolean_value := true + elsif token_content = "false" then + current_token.kind := TokenKind.boolean; + current_token.value.boolean_value := false + elsif token_content = "nil" then + current_token.kind := TokenKind.null + elsif token_content = "or" then + current_token.kind := TokenKind._or + elsif token_content = "return" then + current_token.kind := TokenKind._return + elsif token_content = "cast" then + current_token.kind := TokenKind._cast + elsif token_content = "defer" then + current_token.kind := TokenKind._defer + elsif token_content = "program" then + current_token.kind := TokenKind._program + elsif token_content = "module" then + current_token.kind := TokenKind._module + elsif token_content = "import" then + current_token.kind := TokenKind._import + else + current_token.kind := TokenKind.identifier; + current_token.value.string := string_dup(token_content) + end; + + return current_token +end + +proc lexer_add_token(lexer: ^Lexer, token: Token); +var + new_length: Word +begin + new_length := lexer^.length + 1u; + lexer^.data := cast(reallocarray(cast(lexer^.data: ^Byte), new_length, #size(Token)): ^Token); + (lexer^.data + lexer^.length)^ := token; + lexer^.length := new_length +end + +(* Read the next token from the input. *) +proc lexer_next(source_code: SourceCode, token_buffer: ^StringBuffer) -> Token; +var + current_token: Token + first_char: Char +begin + current_token.kind := TokenKind.unknown; + + first_char := source_code_head(source_code); + + if is_alpha(first_char) or first_char = '_' then + lexer_identifier(@source_code, token_buffer); + current_token := lexer_categorize(string_buffer_clear(token_buffer)) + elsif first_char = '#' then + source_code_advance(@source_code); + lexer_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 + lexer_number(@source_code, @current_token.value.int_value); + + if source_code_expect(@source_code, 'u') then + current_token.kind := TokenKind.word; + source_code_advance(@source_code) + else + current_token.kind := TokenKind.integer + end + elsif first_char = '(' then + source_code_advance(@source_code); + + if source_code_empty(@source_code) then + current_token.kind := TokenKind.left_paren + elsif source_code_head(source_code) = '*' then + source_code_advance(@source_code); + + if lexer_comment(@source_code, token_buffer) then + current_token.value.string := string_dup(string_buffer_clear(token_buffer)); + current_token.kind := TokenKind.comment + else + current_token.kind := TokenKind.unknown + end + else + current_token.kind := TokenKind.left_paren + end + elsif first_char = ')' then + current_token.kind := TokenKind.right_paren; + source_code_advance(@source_code) + elsif first_char = '\'' then + source_code_advance(@source_code); + + if lexer_character(@source_code, @current_token.value.char_value) & source_code_expect(@source_code, '\'') then + current_token.kind := TokenKind.character; + source_code_advance(@source_code) + else + current_token.kind := TokenKind.unknown + end + elsif first_char = '"' then + source_code_advance(@source_code); + + if lexer_string(@source_code, token_buffer) then + current_token.kind := TokenKind.string; + current_token.value.string := string_dup(string_buffer_clear(token_buffer)) + else + current_token.kind := TokenKind.unknown + end + elsif first_char = '[' then + current_token.kind := TokenKind.left_square; + source_code_advance(@source_code) + elsif first_char = ']' then + current_token.kind := TokenKind.right_square; + source_code_advance(@source_code) + elsif first_char = '>' then + source_code_advance(@source_code); + + if source_code_empty(@source_code) then + current_token.kind := TokenKind.greater_than + elsif source_code_head(source_code) = '=' then + current_token.kind := TokenKind.greater_equal; + source_code_advance(@source_code) + elsif source_code_head(source_code) = '>' then + current_token.kind := TokenKind.shift_right; + source_code_advance(@source_code) + else + current_token.kind := TokenKind.greater_than + end + elsif first_char = '<' then + source_code_advance(@source_code); + + if source_code_empty(@source_code) then + current_token.kind := TokenKind.less_than + elsif source_code_head(source_code) = '=' then + current_token.kind := TokenKind.less_equal; + source_code_advance(@source_code) + elsif source_code_head(source_code) = '<' then + current_token.kind := TokenKind.shift_left; + source_code_advance(@source_code) + elsif source_code_head(source_code) = '>' then + current_token.kind := TokenKind.not_equal; + source_code_advance(@source_code) + else + current_token.kind := TokenKind.less_than + end + elsif first_char = '=' then + current_token.kind := TokenKind.equal; + source_code_advance(@source_code) + elsif first_char = ';' then + current_token.kind := TokenKind.semicolon; + source_code_advance(@source_code) + elsif first_char = '.' then + current_token.kind := TokenKind.dot; + source_code_advance(@source_code) + elsif first_char = ',' then + current_token.kind := TokenKind.comma; + source_code_advance(@source_code) + elsif first_char = '+' then + current_token.kind := TokenKind.plus; + source_code_advance(@source_code) + elsif first_char = '-' then + source_code_advance(@source_code); + + if source_code_empty(@source_code) then + current_token.kind := TokenKind.minus + elsif source_code_head(source_code) = '>' then + current_token.kind := TokenKind.arrow; + source_code_advance(@source_code) + else + current_token.kind := TokenKind.minus + end + elsif first_char = '*' then + current_token.kind := TokenKind.multiplication; + source_code_advance(@source_code) + elsif first_char = '/' then + current_token.kind := TokenKind.division; + source_code_advance(@source_code) + elsif first_char = '%' then + current_token.kind := TokenKind.remainder; + source_code_advance(@source_code) + elsif first_char = ':' then + source_code_advance(@source_code); + + if source_code_empty(@source_code) then + current_token.kind := TokenKind.colon + elsif source_code_head(source_code) = '=' then + current_token.kind := TokenKind.assignment; + source_code_advance(@source_code) + else + current_token.kind := TokenKind.colon + end + elsif first_char = '^' then + current_token.kind := TokenKind.hat; + source_code_advance(@source_code) + elsif first_char = '@' then + current_token.kind := TokenKind.at; + source_code_advance(@source_code) + elsif first_char = '!' then + current_token.kind := TokenKind.exclamation; + 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 + current_token.kind := TokenKind.unknown; + source_code_advance(@source_code) + end; + + return current_token +end + +(* Split the source text into tokens. *) +proc lexer_text(source_code: SourceCode) -> Lexer; +var + current_token: Token + token_buffer: StringBuffer + lexer: Lexer +begin + lexer := Lexer(0u, nil); + token_buffer := string_buffer_new(); + + lexer_spaces(@source_code); + + while ~source_code_empty(@source_code) do + current_token := lexer_next(source_code, @token_buffer); + + if current_token.kind <> TokenKind.unknown then + lexer_add_token(@lexer, current_token); + lexer_spaces(@source_code) + else + write_s("Lexical analysis error on \""); + write_c(source_code_head(source_code)); + write_s("\".\n") + end + end; + + return lexer +end + +(* + Command line handling. +*) + +proc parse_command_line*(argc: Int, argv: ^^Char) -> ^CommandLine; +var + parameter: ^^Char + i: Int + result: ^CommandLine +begin + i := 1; + result := cast(malloc(#size(CommandLine)): ^CommandLine); + result^.lex := false; + result^.parse := false; + result^.input := nil; + + while i < argc & result <> nil do + parameter := argv + i; + + if strcmp(parameter^, "--lex\0".ptr) = 0 then + result^.lex := true + elsif strcmp(parameter^, "--parse\0".ptr) = 0 then + result^.parse := true + elsif parameter^^ <> '-' then + if result^.input <> nil then + write_s("Fatal error: Only one source file can be given.\n"); + result := nil + else + result^.input := parameter^ + end + else + write_s("Fatal error: Unknown command line options: "); + + write_z(parameter^); + write_s(".\n"); + + result := nil + end; + + i := i + 1 + end; + if result <> nil & result^.input = nil then + write_s("Fatal error: no input files.\n"); + result := nil + end; + + return result +end + +(* + Parser. +*) + +proc parse(tokens: ^Token, tokens_size: Word); var current_token: ^Token i: Word @@ -673,319 +1017,27 @@ begin write_c('\n') end -proc categorize_identifier(token_content: String) -> Token; -var - current_token: Token -begin - if token_content = "if" then - current_token.kind := TokenKind._if - elsif token_content = "then" then - current_token.kind := TokenKind._then - elsif token_content = "else" then - current_token.kind := TokenKind._else - elsif token_content = "elsif" then - current_token.kind := TokenKind._elsif - elsif token_content = "while" then - current_token.kind := TokenKind._while - elsif token_content = "do" then - current_token.kind := TokenKind._do - elsif token_content = "proc" then - current_token.kind := TokenKind._proc - elsif token_content = "begin" then - current_token.kind := TokenKind._begin - elsif token_content = "end" then - current_token.kind := TokenKind._end - elsif token_content = "extern" then - current_token.kind := TokenKind._extern - elsif token_content = "const" then - current_token.kind := TokenKind._const - elsif token_content = "var" then - current_token.kind := TokenKind._var - elsif token_content = "case" then - current_token.kind := TokenKind._case - elsif token_content = "of" then - current_token.kind := TokenKind._of - elsif token_content = "type" then - current_token.kind := TokenKind._type - elsif token_content = "record" then - current_token.kind := TokenKind._record - elsif token_content = "union" then - current_token.kind := TokenKind._union - elsif token_content = "true" then - current_token.kind := TokenKind.boolean; - current_token.value.boolean_value := true - elsif token_content = "false" then - current_token.kind := TokenKind.boolean; - current_token.value.boolean_value := false - elsif token_content = "nil" then - current_token.kind := TokenKind.null - elsif token_content = "or" then - current_token.kind := TokenKind._or - elsif token_content = "return" then - current_token.kind := TokenKind._return - elsif token_content = "cast" then - current_token.kind := TokenKind._cast - elsif token_content = "defer" then - current_token.kind := TokenKind._defer - elsif token_content = "program" then - current_token.kind := TokenKind._program - elsif token_content = "module" then - current_token.kind := TokenKind._module - elsif token_content = "import" then - current_token.kind := TokenKind._import - else - current_token.kind := TokenKind.identifier; - current_token.value.string := string_dup(token_content) - end; - - return current_token -end - -proc tokenize(source_code: SourceCode, tokens_size: ^Word) -> ^Token; -var - tokens, current_token: ^Token - first_char: Char - token_buffer: StringBuffer -begin - tokens_size^ := 0u; - tokens := nil; - token_buffer := string_buffer_new(); - - skip_spaces(@source_code); - - while ~source_code_empty(@source_code) do - tokens := cast(reallocarray(cast(tokens: ^Byte), tokens_size^ + 1u, #size(Token)): ^Token); - current_token := tokens + tokens_size^; - first_char := source_code_head(source_code); - - if is_alpha(first_char) or first_char = '_' then - lex_identifier(@source_code, @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 - lex_number(@source_code, @current_token^.value.int_value); - - if source_code_expect(@source_code, 'u') then - current_token^.kind := TokenKind.word; - source_code_advance(@source_code) - else - current_token^.kind := TokenKind.integer - end - elsif first_char = '(' then - source_code_advance(@source_code); - - if source_code_empty(@source_code) then - current_token^.kind := TokenKind.left_paren - elsif source_code_head(source_code) = '*' then - source_code_advance(@source_code); - - if lex_comment(@source_code, @token_buffer) then - current_token^.value.string := string_dup(string_buffer_clear(@token_buffer)); - current_token^.kind := TokenKind.comment - else - current_token^.kind := TokenKind.unknown - end - else - current_token^.kind := TokenKind.left_paren - end - elsif first_char = ')' then - current_token^.kind := TokenKind.right_paren; - source_code_advance(@source_code) - elsif first_char = '\'' then - source_code_advance(@source_code); - - if lex_character(@source_code, @current_token^.value.char_value) & source_code_expect(@source_code, '\'') then - current_token^.kind := TokenKind.character; - source_code_advance(@source_code) - else - current_token^.kind := TokenKind.unknown - end - elsif first_char = '"' then - source_code_advance(@source_code); - - if lex_string(@source_code, @token_buffer) then - current_token^.kind := TokenKind.string; - current_token^.value.string := string_dup(string_buffer_clear(@token_buffer)) - else - current_token^.kind := TokenKind.unknown - end - elsif first_char = '[' then - current_token^.kind := TokenKind.left_square; - source_code_advance(@source_code) - elsif first_char = ']' then - current_token^.kind := TokenKind.right_square; - source_code_advance(@source_code) - elsif first_char = '>' then - source_code_advance(@source_code); - - if source_code_empty(@source_code) then - current_token^.kind := TokenKind.greater_than - elsif source_code_head(source_code) = '=' then - current_token^.kind := TokenKind.greater_equal; - source_code_advance(@source_code) - elsif source_code_head(source_code) = '>' then - current_token^.kind := TokenKind.shift_right; - source_code_advance(@source_code) - else - current_token^.kind := TokenKind.greater_than - end - elsif first_char = '<' then - source_code_advance(@source_code); - - if source_code_empty(@source_code) then - current_token^.kind := TokenKind.less_than - elsif source_code_head(source_code) = '=' then - current_token^.kind := TokenKind.less_equal; - source_code_advance(@source_code) - elsif source_code_head(source_code) = '<' then - current_token^.kind := TokenKind.shift_left; - source_code_advance(@source_code) - elsif source_code_head(source_code) = '>' then - current_token^.kind := TokenKind.not_equal; - source_code_advance(@source_code) - else - current_token^.kind := TokenKind.less_than - end - elsif first_char = '=' then - current_token^.kind := TokenKind.equal; - source_code_advance(@source_code) - elsif first_char = ';' then - current_token^.kind := TokenKind.semicolon; - source_code_advance(@source_code) - elsif first_char = '.' then - current_token^.kind := TokenKind.dot; - source_code_advance(@source_code) - elsif first_char = ',' then - current_token^.kind := TokenKind.comma; - source_code_advance(@source_code) - elsif first_char = '+' then - current_token^.kind := TokenKind.plus; - source_code_advance(@source_code) - elsif first_char = '-' then - source_code_advance(@source_code); - - if source_code_empty(@source_code) then - current_token^.kind := TokenKind.minus - elsif source_code_head(source_code) = '>' then - current_token^.kind := TokenKind.arrow; - source_code_advance(@source_code) - else - current_token^.kind := TokenKind.minus - end - elsif first_char = '*' then - current_token^.kind := TokenKind.multiplication; - source_code_advance(@source_code) - elsif first_char = '/' then - current_token^.kind := TokenKind.division; - source_code_advance(@source_code) - elsif first_char = '%' then - current_token^.kind := TokenKind.remainder; - source_code_advance(@source_code) - elsif first_char = ':' then - source_code_advance(@source_code); - - if source_code_empty(@source_code) then - current_token^.kind := TokenKind.colon - elsif source_code_head(source_code) = '=' then - current_token^.kind := TokenKind.assignment; - source_code_advance(@source_code) - else - current_token^.kind := TokenKind.colon - end - elsif first_char = '^' then - current_token^.kind := TokenKind.hat; - source_code_advance(@source_code) - elsif first_char = '@' then - current_token^.kind := TokenKind.at; - source_code_advance(@source_code) - elsif first_char = '!' then - current_token^.kind := TokenKind.exclamation; - 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 - current_token^.kind := TokenKind.unknown; - source_code_advance(@source_code) - end; - - if current_token^.kind <> TokenKind.unknown then - tokens_size^ := tokens_size^ + 1u; - skip_spaces(@source_code) - else - write_s("Lexical analysis error on \""); - write_c(first_char); - write_s("\".\n") - end - end; - - return tokens -end - -(* - Command line handling. -*) - -proc parse_command_line*(argc: Int, argv: ^^Char) -> ^CommandLine; -var - parameter: ^^Char - i: Int - result: ^CommandLine -begin - i := 1; - result := cast(malloc(#size(CommandLine)): ^CommandLine); - result^.lex := false; - result^.parse := false; - result^.input := nil; - - while i < argc & result <> nil do - parameter := argv + i; - - if strcmp(parameter^, "--lex\0".ptr) = 0 then - result^.lex := true - elsif strcmp(parameter^, "--parse\0".ptr) = 0 then - result^.parse := true - elsif parameter^^ <> '-' then - if result^.input <> nil then - write_s("Fatal error: Only one source file can be given.\n"); - result := nil - else - result^.input := parameter^ - end - else - write_s("Fatal error: Unknown command line options: "); - - write_z(parameter^); - write_s(".\n"); - - result := nil - end; - - i := i + 1 - end; - if result <> nil & result^.input = nil then - write_s("Fatal error: no input files.\n"); - result := nil - end; - - return result -end - (* Compilation entry. *) +proc compile_in_stages(command_line: ^CommandLine, source_code: SourceCode) -> Int; +var + return_code: Int + lexer: Lexer +begin + return_code := 0; + + if command_line^.lex or command_line^.parse then + lexer := lexer_text(source_code) + end; + if command_line^.parse then + parse(lexer.data, lexer.length) + end; + + return return_code +end + proc process(argc: Int, argv: ^^Char) -> Int; var tokens: ^Token @@ -993,6 +1045,7 @@ var source_code: SourceCode command_line: ^CommandLine return_code: Int + source_file: ^SourceFile begin return_code := 0; @@ -1002,26 +1055,26 @@ begin end; if return_code = 0 then - source_code.position := Position(1u, 1u); + source_file := read_source(command_line^.input); - source_code.input := cast(read_source(command_line^.input): ^Byte); + if source_file = nil then + perror(command_line^.input); + return_code := 3 + end + end; + + if return_code = 0 then + defer + fclose(source_file^.handle) + end; + + source_code.position := Position(1u, 1u); + source_code.input := cast(source_file: ^Byte); source_code.empty := source_file_empty; source_code.head := source_file_head; source_code.advance := source_file_advance; - if source_code.input = nil then - perror(command_line^.input); - return_code := 3 - end - end; - if return_code = 0 then - tokens := tokenize(source_code, @tokens_size); - - fclose(cast(source_code.input: ^SourceFile)^.handle); - - if command_line^.lex then - print_tokens(tokens, tokens_size) - end + return_code := compile_in_stages(command_line, source_code) end; return return_code end