From 72e545225b3fb04c06e5c93193ff5f8f037049a8 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Sat, 31 May 2025 11:27:23 +0200 Subject: [PATCH] Add A command line parsing procedure --- source/CommandLine.def | 3 + source/CommandLine.mod | 3 + source/CommandLineInterface.def | 15 + source/CommandLineInterface.mod | 74 +++++ source/Common.def | 6 + source/Common.mod | 3 + source/Compiler.mod | 42 ++- source/Parser.def | 3 + source/Parser.mod | 3 + source/Transpiler.def | 12 +- source/Transpiler.mod | 467 ++++++++++++++++---------------- 11 files changed, 386 insertions(+), 245 deletions(-) create mode 100644 source/CommandLine.def create mode 100644 source/CommandLine.mod create mode 100644 source/CommandLineInterface.def create mode 100644 source/CommandLineInterface.mod create mode 100644 source/Common.def create mode 100644 source/Common.mod create mode 100644 source/Parser.def create mode 100644 source/Parser.mod diff --git a/source/CommandLine.def b/source/CommandLine.def new file mode 100644 index 0000000..37fd7fa --- /dev/null +++ b/source/CommandLine.def @@ -0,0 +1,3 @@ +DEFINITION MODULE CommandLine; + +END CommandLine. diff --git a/source/CommandLine.mod b/source/CommandLine.mod new file mode 100644 index 0000000..215f7c3 --- /dev/null +++ b/source/CommandLine.mod @@ -0,0 +1,3 @@ +MODULE CommandLine; + +END CommandLine. diff --git a/source/CommandLineInterface.def b/source/CommandLineInterface.def new file mode 100644 index 0000000..85be324 --- /dev/null +++ b/source/CommandLineInterface.def @@ -0,0 +1,15 @@ +DEFINITION MODULE CommandLineInterface; + +FROM Common IMPORT ShortString; + +TYPE + CommandLine = RECORD + input: ShortString; + lex: BOOLEAN; + parse: BOOLEAN + END; + PCommandLine = POINTER TO CommandLine; + +PROCEDURE parse_command_line(): PCommandLine; + +END CommandLineInterface. diff --git a/source/CommandLineInterface.mod b/source/CommandLineInterface.mod new file mode 100644 index 0000000..2b33668 --- /dev/null +++ b/source/CommandLineInterface.mod @@ -0,0 +1,74 @@ +IMPLEMENTATION MODULE CommandLineInterface; + +FROM SYSTEM IMPORT ADR, TSIZE; + +FROM Args IMPORT GetArg, Narg; +FROM FIO IMPORT WriteString, WriteChar, WriteLine, StdErr; +FROM Storage IMPORT ALLOCATE; +FROM Strings IMPORT CompareStr, Length; +FROM MemUtils IMPORT MemZero; + +FROM Common IMPORT ShortString; + +PROCEDURE parse_command_line(): PCommandLine; +VAR + parameter: ShortString; + i: CARDINAL; + result: PCommandLine; + parsed: BOOLEAN; +BEGIN + i := 1; + ALLOCATE(result, TSIZE(CommandLine)); + result^.lex := FALSE; + result^.parse := FALSE; + MemZero(ADR(result^.input), 256); + + WHILE (i < Narg()) AND (result <> NIL) DO + parsed := GetArg(parameter, i); + parsed := FALSE; + + IF CompareStr(parameter, '--lex') = 0 THEN + parsed := TRUE; + result^.lex := TRUE + END; + IF CompareStr(parameter, '--parse') = 0 THEN + parsed := TRUE; + result^.parse := TRUE + END; + IF parameter[0] <> '-' THEN + parsed := TRUE; + + IF Length(result^.input) > 0 THEN + WriteString(StdErr, 'Fatal error: only one source file can be compiled at once. First given "'); + WriteString(StdErr, result^.input); + WriteString(StdErr, '", then "'); + WriteString(StdErr, parameter); + WriteString(StdErr, '".'); + WriteLine(StdErr); + result := NIL + END; + IF result <> NIL THEN + result^.input := parameter + END + END; + IF parsed = FALSE THEN + WriteString(StdErr, 'Fatal error: unknown command line options: '); + + WriteString(StdErr, parameter); + WriteChar(StdErr, '.'); + WriteLine(StdErr); + + result := NIL + END; + + i := i + 1 + END; + IF (result <> NIL) AND (Length(result^.input) = 0) THEN + WriteString(StdErr, 'Fatal error: no input files.'); + WriteLine(StdErr); + result := NIL + END; + + RETURN result +END parse_command_line; +END CommandLineInterface. diff --git a/source/Common.def b/source/Common.def new file mode 100644 index 0000000..5925cbf --- /dev/null +++ b/source/Common.def @@ -0,0 +1,6 @@ +DEFINITION MODULE Common; + +TYPE + ShortString = ARRAY[0..255] OF CHAR; + +END Common. diff --git a/source/Common.mod b/source/Common.mod new file mode 100644 index 0000000..135d3a9 --- /dev/null +++ b/source/Common.mod @@ -0,0 +1,3 @@ +IMPLEMENTATION MODULE Common; + +END Common. diff --git a/source/Compiler.mod b/source/Compiler.mod index c6b3e09..9971a76 100644 --- a/source/Compiler.mod +++ b/source/Compiler.mod @@ -1,18 +1,50 @@ MODULE Compiler; -FROM FIO IMPORT StdIn; +FROM FIO IMPORT Close, IsNoError, File, OpenToRead, StdErr, WriteLine, WriteString; FROM SYSTEM IMPORT ADR; +FROM M2RTS IMPORT HALT, ExitOnHalt; FROM Lexer IMPORT Lexer, lexer_destroy, lexer_initialize; FROM Transpiler IMPORT transpile; +FROM CommandLineInterface IMPORT PCommandLine, parse_command_line; +VAR + command_line: PCommandLine; + +PROCEDURE compile_from_stream(); VAR lexer: Lexer; - + source_input: File; BEGIN - lexer_initialize(ADR(lexer), StdIn); + source_input := OpenToRead(command_line^.input); - transpile(ADR(lexer)); + IF IsNoError(source_input) = FALSE THEN + WriteString(StdErr, 'Fatal error: failed to read the input file "'); + WriteString(StdErr, command_line^.input); + WriteString(StdErr, '".'); + WriteLine(StdErr); - lexer_destroy(ADR(lexer)) + ExitOnHalt(2) + END; + IF IsNoError(source_input) THEN + lexer_initialize(ADR(lexer), source_input); + + transpile(ADR(lexer)); + + lexer_destroy(ADR(lexer)); + + Close(source_input) + END +END compile_from_stream; +BEGIN + ExitOnHalt(0); + command_line := parse_command_line(); + + IF command_line <> NIL THEN + compile_from_stream() + END; + IF command_line = NIL THEN + ExitOnHalt(1) + END; + HALT() END Compiler. diff --git a/source/Parser.def b/source/Parser.def new file mode 100644 index 0000000..5b016de --- /dev/null +++ b/source/Parser.def @@ -0,0 +1,3 @@ +DEFINITION MODULE Parser; + +END Parser. diff --git a/source/Parser.mod b/source/Parser.mod new file mode 100644 index 0000000..bf39cc7 --- /dev/null +++ b/source/Parser.mod @@ -0,0 +1,3 @@ +MODULE Parser; + +END Parser. diff --git a/source/Transpiler.def b/source/Transpiler.def index c3cd8a7..d9a65cf 100644 --- a/source/Transpiler.def +++ b/source/Transpiler.def @@ -1,6 +1,16 @@ DEFINITION MODULE Transpiler; -FROM Lexer IMPORT PLexer; +FROM FIO IMPORT File; + +FROM Lexer IMPORT PLexer, Lexer; + +TYPE + TranspilerContext = RECORD + indentation: CARDINAL; + output: File; + lexer: PLexer + END; + PTranspilerContext = POINTER TO TranspilerContext; PROCEDURE transpile(ALexer: PLexer); diff --git a/source/Transpiler.mod b/source/Transpiler.mod index 63ce824..b0a5377 100644 --- a/source/Transpiler.mod +++ b/source/Transpiler.mod @@ -1,17 +1,11 @@ IMPLEMENTATION MODULE Transpiler; -FROM FIO IMPORT WriteNBytes, StdOut; +FROM FIO IMPORT WriteNBytes, StdOut, WriteLine, WriteChar; FROM SYSTEM IMPORT ADR, ADDRESS; FROM Terminal IMPORT Write, WriteLn, WriteString; FROM Lexer IMPORT Lexer, LexerToken, lexer_current, lexer_lex, LexerKind; -TYPE - PTranspilerContext = POINTER TO TranspilerContext; - TranspilerContext = RECORD - Indentation: CARDINAL - END; - (* Calls lexer_lex() but skips the comments. *) PROCEDURE transpiler_lex(lexer: PLexer): LexerToken; VAR @@ -26,394 +20,383 @@ BEGIN RETURN result END transpiler_lex; (* Write a semicolon followed by a newline. *) -PROCEDURE write_semicolon(); +PROCEDURE write_semicolon(output: File); BEGIN - WriteString(';'); - WriteLn() + WriteChar(output, ';'); + WriteLine(output) END write_semicolon; -PROCEDURE transpile_import(context: PTranspilerContext; lexer: PLexer); +PROCEDURE write_current(lexer: PLexer); VAR - token: LexerToken; written_bytes: CARDINAL; BEGIN - WriteString('FROM '); - token := transpiler_lex(lexer); - - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); - - token := transpiler_lex(lexer); - WriteString(' IMPORT '); - - token := transpiler_lex(lexer); - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); - - token := transpiler_lex(lexer); - WHILE token.kind <> lexerKindSemicolon DO - WriteString(', '); - token := transpiler_lex(lexer); - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); - token := transpiler_lex(lexer) - END; - write_semicolon(); - token := transpiler_lex(lexer) -END transpile_import; -PROCEDURE transpile_import_part(context: PTranspilerContext; lexer: PLexer); + written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start) +END write_current; +PROCEDURE transpile_import(context: PTranspilerContext); VAR token: LexerToken; BEGIN - token := lexer_current(lexer); + WriteString('FROM '); + token := transpiler_lex(context^.lexer); + + write_current(context^.lexer); + token := transpiler_lex(context^.lexer); + WriteString(' IMPORT '); + + token := transpiler_lex(context^.lexer); + write_current(context^.lexer); + + token := transpiler_lex(context^.lexer); + WHILE token.kind <> lexerKindSemicolon DO + WriteString(', '); + token := transpiler_lex(context^.lexer); + write_current(context^.lexer); + token := transpiler_lex(context^.lexer) + END; + write_semicolon(context^.output); + token := transpiler_lex(context^.lexer) +END transpile_import; +PROCEDURE transpile_import_part(context: PTranspilerContext); +VAR + token: LexerToken; +BEGIN + token := lexer_current(context^.lexer); WHILE token.kind = lexerKindFrom DO - transpile_import(context, lexer); - token := lexer_current(lexer) + transpile_import(context); + token := lexer_current(context^.lexer) END; WriteLn() END transpile_import_part; -PROCEDURE transpile_constant(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_constant(context: PTranspilerContext); VAR token: LexerToken; - written_bytes: CARDINAL; BEGIN WriteString(' '); - token := lexer_current(lexer); - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); + token := lexer_current(context^.lexer); + write_current(context^.lexer); - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); WriteString(' = '); - token := transpiler_lex(lexer); - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); + token := transpiler_lex(context^.lexer); + write_current(context^.lexer); - token := transpiler_lex(lexer); - write_semicolon() + token := transpiler_lex(context^.lexer); + write_semicolon(context^.output) END transpile_constant; -PROCEDURE transpile_constant_part(context: PTranspilerContext; lexer: PLexer): BOOLEAN; +PROCEDURE transpile_constant_part(context: PTranspilerContext): BOOLEAN; VAR token: LexerToken; result: BOOLEAN; BEGIN - token := lexer_current(lexer); + token := lexer_current(context^.lexer); result := token.kind = lexerKindConst; IF result THEN WriteString('CONST'); WriteLn(); - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); WHILE token.kind = lexerKindIdentifier DO - transpile_constant(context, lexer); - token := transpiler_lex(lexer) + transpile_constant(context); + token := transpiler_lex(context^.lexer) END END; RETURN result END transpile_constant_part; -PROCEDURE transpile_module(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_module(context: PTranspilerContext); VAR token: LexerToken; - written_bytes: CARDINAL; BEGIN - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); IF token.kind = lexerKindDefinition THEN WriteString('DEFINITION '); - token := transpiler_lex(lexer) + token := transpiler_lex(context^.lexer) END; IF token.kind = lexerKindImplementation THEN WriteString('IMPLEMENTATION '); - token := transpiler_lex(lexer) + token := transpiler_lex(context^.lexer) END; WriteString('MODULE '); (* Write the module name and end the line with a semicolon and newline. *) - token := transpiler_lex(lexer); - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); + token := transpiler_lex(context^.lexer); + write_current(context^.lexer); - token := transpiler_lex(lexer); - write_semicolon(); + token := transpiler_lex(context^.lexer); + write_semicolon(context^.output); WriteLn(); (* Write the module body. *) - token := transpiler_lex(lexer); - transpile_import_part(context, lexer); - IF transpile_constant_part(context, lexer) THEN + token := transpiler_lex(context^.lexer); + transpile_import_part(context); + IF transpile_constant_part(context) THEN WriteLn() END; - transpile_type_part(context, lexer); - IF transpile_variable_part(context, lexer) THEN + transpile_type_part(context); + IF transpile_variable_part(context) THEN WriteLn() END; - transpile_procedure_part(context, lexer); - transpile_statement_part(context, lexer); + transpile_procedure_part(context); + transpile_statement_part(context); WriteString('END '); - token := transpiler_lex(lexer); - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); + token := transpiler_lex(context^.lexer); + write_current(context^.lexer); - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); Write('.'); - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); WriteLn() END transpile_module; -PROCEDURE transpile_type_fields(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_type_fields(context: PTranspilerContext); VAR token: LexerToken; - written_bytes: CARDINAL; BEGIN - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); WHILE token.kind <> lexerKindEnd DO WriteString(' '); - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); - token := transpiler_lex(lexer); + write_current(context^.lexer); + token := transpiler_lex(context^.lexer); WriteString(': '); - transpile_type_expression(context, lexer); - token := transpiler_lex(lexer); + transpile_type_expression(context); + token := transpiler_lex(context^.lexer); IF token.kind = lexerKindSemicolon THEN - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); Write(';') END; WriteLn() END END transpile_type_fields; -PROCEDURE transpile_record_type(context: PTranspilerContext; lexer: PLexer); -VAR - token: LexerToken; +PROCEDURE transpile_record_type(context: PTranspilerContext); BEGIN WriteString('RECORD'); WriteLn(); - transpile_type_fields(context, lexer); + transpile_type_fields(context); WriteString(' END') END transpile_record_type; -PROCEDURE transpile_pointer_type(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_pointer_type(context: PTranspilerContext); VAR token: LexerToken; - written_bytes: CARDINAL; BEGIN - token := lexer_current(lexer); + token := lexer_current(context^.lexer); WriteString('POINTER TO '); IF token.kind = lexerKindPointer THEN - token := transpiler_lex(lexer) + token := transpiler_lex(context^.lexer) END; - transpile_type_expression(context, lexer) + transpile_type_expression(context) END transpile_pointer_type; -PROCEDURE transpile_array_type(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_array_type(context: PTranspilerContext); VAR token: LexerToken; - written_bytes: CARDINAL; BEGIN WriteString('ARRAY'); - token := lexer_current(lexer); + token := lexer_current(context^.lexer); IF token.kind = lexerKindArray THEN - token := transpiler_lex(lexer) + token := transpiler_lex(context^.lexer) END; IF token.kind <> lexerKindOf THEN WriteString('[1..'); - token := transpiler_lex(lexer); - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); + write_current(context^.lexer); + token := transpiler_lex(context^.lexer); Write(']') END; WriteString(' OF '); - transpile_type_expression(context, lexer) + transpile_type_expression(context) END transpile_array_type; -PROCEDURE transpile_enumeration_type(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_enumeration_type(context: PTranspilerContext); VAR token: LexerToken; - written_bytes: CARDINAL; BEGIN WriteString('('); WriteLn(); WriteString(' '); - token := transpiler_lex(lexer); - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); + token := transpiler_lex(context^.lexer); + write_current(context^.lexer); - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); WHILE token.kind = lexerKindComma DO Write(','); WriteLn(); WriteString(' '); - token := transpiler_lex(lexer); - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); + token := transpiler_lex(context^.lexer); + write_current(context^.lexer); - token := transpiler_lex(lexer) + token := transpiler_lex(context^.lexer) END; WriteLn(); WriteString(' )') END transpile_enumeration_type; -PROCEDURE transpile_union_type(context: PTranspilerContext; lexer: PLexer); -VAR - token: LexerToken; +PROCEDURE transpile_union_type(context: PTranspilerContext); END transpile_union_type; -PROCEDURE transpile_procedure_type(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_procedure_type(context: PTranspilerContext); VAR token: LexerToken; - written_bytes: CARDINAL; BEGIN - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); WriteString('PROCEDURE('); - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); WHILE token.kind <> lexerKindRightParen DO - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); + write_current(context^.lexer); - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); IF token.kind = lexerKindComma THEN - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); WriteString(', ') END END; Write(')') END transpile_procedure_type; -PROCEDURE transpile_type_expression(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_type_expression(context: PTranspilerContext); VAR token: LexerToken; - written_bytes: CARDINAL; BEGIN - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); IF token.kind = lexerKindRecord THEN - transpile_record_type(context, lexer) + transpile_record_type(context) END; IF token.kind = lexerKindLeftParen THEN - transpile_enumeration_type(context, lexer) + transpile_enumeration_type(context) END; IF (token.kind = lexerKindArray) OR (token.kind = lexerKindLeftSquare) THEN - transpile_array_type(context, lexer) + transpile_array_type(context) END; IF token.kind = lexerKindHat THEN - transpile_pointer_type(context, lexer) + transpile_pointer_type(context) END; IF token.kind = lexerKindProc THEN - transpile_procedure_type(context, lexer) + transpile_procedure_type(context) END; IF token.kind = lexerKindIdentifier THEN - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start) + write_current(context^.lexer) END END transpile_type_expression; -PROCEDURE transpile_type_declaration(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_type_declaration(context: PTranspilerContext); VAR token: LexerToken; - written_bytes: CARDINAL; BEGIN WriteString(' '); - token := lexer_current(lexer); - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); + token := lexer_current(context^.lexer); + write_current(context^.lexer); - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); WriteString(' = '); - transpile_type_expression(context, lexer); - token := transpiler_lex(lexer); - write_semicolon(); + transpile_type_expression(context); + token := transpiler_lex(context^.lexer); + write_semicolon(context^.output); END transpile_type_declaration; -PROCEDURE transpile_type_part(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_type_part(context: PTranspilerContext); VAR token: LexerToken; BEGIN - token := lexer_current(lexer); + token := lexer_current(context^.lexer); IF token.kind = lexerKindType THEN WriteString('TYPE'); WriteLn(); - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); WHILE token.kind = lexerKindIdentifier DO - transpile_type_declaration(context, lexer); - token := transpiler_lex(lexer) + transpile_type_declaration(context); + token := transpiler_lex(context^.lexer) END; WriteLn() END END transpile_type_part; -PROCEDURE transpile_variable_declaration(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_variable_declaration(context: PTranspilerContext); VAR token: LexerToken; - written_bytes: CARDINAL; BEGIN WriteString(' '); - token := lexer_current(lexer); - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); + token := lexer_current(context^.lexer); + write_current(context^.lexer); - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); WriteString(': '); - transpile_type_expression(context, lexer); - token := transpiler_lex(lexer); - write_semicolon() + transpile_type_expression(context); + token := transpiler_lex(context^.lexer); + write_semicolon(context^.output) END transpile_variable_declaration; -PROCEDURE transpile_variable_part(context: PTranspilerContext; lexer: PLexer): BOOLEAN; +PROCEDURE transpile_variable_part(context: PTranspilerContext): BOOLEAN; VAR token: LexerToken; result: BOOLEAN; BEGIN - token := lexer_current(lexer); + token := lexer_current(context^.lexer); result := token.kind = lexerKindVar; IF result THEN WriteString('VAR'); WriteLn(); - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); WHILE token.kind = lexerKindIdentifier DO - transpile_variable_declaration(context, lexer); - token := transpiler_lex(lexer) + transpile_variable_declaration(context); + token := transpiler_lex(context^.lexer) END END; RETURN result END transpile_variable_part; -PROCEDURE transpile_procedure_heading(context: PTranspilerContext; lexer: PLexer): LexerToken; +PROCEDURE transpile_procedure_heading(context: PTranspilerContext): LexerToken; VAR token: LexerToken; result: LexerToken; - written_bytes: CARDINAL; BEGIN WriteString('PROCEDURE '); - result := transpiler_lex(lexer); - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); + result := transpiler_lex(context^.lexer); + write_current(context^.lexer); - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); Write('('); - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); WHILE token.kind <> lexerKindRightParen DO - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); + write_current(context^.lexer); - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); WriteString(': '); - transpile_type_expression(context, lexer); + transpile_type_expression(context); - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); IF (token.kind = lexerKindSemicolon) OR (token.kind = lexerKindComma) THEN WriteString('; '); - token := transpiler_lex(lexer) + token := transpiler_lex(context^.lexer) END END; WriteString(')'); - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); (* Check for the return type and write it. *) IF token.kind = lexerKindArrow THEN WriteString(': '); - token := transpiler_lex(lexer); - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); - token := transpiler_lex(lexer) + token := transpiler_lex(context^.lexer); + write_current(context^.lexer); + token := transpiler_lex(context^.lexer) END; - token := transpiler_lex(lexer); - write_semicolon(); + token := transpiler_lex(context^.lexer); + write_semicolon(context^.output); RETURN result END transpile_procedure_heading; -PROCEDURE transpile_expression(context: PTranspilerContext; lexer: PLexer; trailing_token: LexerKind); +PROCEDURE transpile_expression(context: PTranspilerContext; trailing_token: LexerKind); VAR token: LexerToken; written_bytes: CARDINAL; BEGIN - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); WHILE (token.kind <> trailing_token) AND (token.kind <> lexerKindEnd) DO written_bytes := 0; @@ -421,6 +404,14 @@ BEGIN WriteString('NIL '); written_bytes := 1 END; + IF (token.kind = lexerKindBoolean) AND token.booleanKind THEN + WriteString('TRUE '); + written_bytes := 1 + END; + IF (token.kind = lexerKindBoolean) AND (~token.booleanKind) THEN + WriteString('FALSE '); + written_bytes := 1 + END; IF token.kind = lexerKindOr THEN WriteString('OR '); written_bytes := 1 @@ -434,149 +425,143 @@ BEGIN written_bytes := 1 END; IF written_bytes = 0 THEN - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); + write_current(context^.lexer); Write(' ') END; - token := transpiler_lex(lexer) + token := transpiler_lex(context^.lexer) END END transpile_expression; -PROCEDURE transpile_if_statement(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_if_statement(context: PTranspilerContext); VAR token: LexerToken; - written_bytes: CARDINAL; BEGIN WriteString(' IF '); - transpile_expression(context, lexer, lexerKindThen); + transpile_expression(context, lexerKindThen); WriteString('THEN'); WriteLn(); - transpile_statements(context, lexer); + transpile_statements(context); WriteString(' END'); - token := transpiler_lex(lexer) + token := transpiler_lex(context^.lexer) END transpile_if_statement; -PROCEDURE transpile_while_statement(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_while_statement(context: PTranspilerContext); VAR token: LexerToken; - written_bytes: CARDINAL; BEGIN WriteString(' WHILE '); - transpile_expression(context, lexer, lexerKindDo); + transpile_expression(context, lexerKindDo); WriteString('DO'); WriteLn(); - transpile_statements(context, lexer); + transpile_statements(context); WriteString(' END'); - token := transpiler_lex(lexer) + token := transpiler_lex(context^.lexer) END transpile_while_statement; -PROCEDURE transpile_assignment_statement(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_assignment_statement(context: PTranspilerContext); BEGIN WriteString(' := '); - transpile_expression(context, lexer, lexerKindSemicolon); + transpile_expression(context, lexerKindSemicolon); END transpile_assignment_statement; -PROCEDURE transpile_call_statement(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_call_statement(context: PTranspilerContext); VAR token: LexerToken; - written_bytes: CARDINAL; BEGIN WriteString('('); - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); WHILE (token.kind <> lexerKindSemicolon) AND (token.kind <> lexerKindEnd) DO - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); - token := transpiler_lex(lexer) + write_current(context^.lexer); + token := transpiler_lex(context^.lexer) END END transpile_call_statement; -PROCEDURE transpile_designator_expression(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_designator_expression(context: PTranspilerContext); VAR token: LexerToken; - written_bytes: CARDINAL; BEGIN WriteString(' '); - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); - token := transpiler_lex(lexer); + write_current(context^.lexer); + token := transpiler_lex(context^.lexer); WHILE token.kind = lexerKindLeftSquare DO Write('['); - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); WHILE token.kind <> lexerKindRightSquare DO - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); - token := transpiler_lex(lexer) + write_current(context^.lexer); + token := transpiler_lex(context^.lexer) END; Write(']'); - token := transpiler_lex(lexer) + token := transpiler_lex(context^.lexer) END; IF token.kind = lexerKindHat THEN Write('^'); - token := transpiler_lex(lexer) + token := transpiler_lex(context^.lexer) END; IF token.kind = lexerKindDot THEN Write('.'); - token := transpiler_lex(lexer); - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); - token := transpiler_lex(lexer) + token := transpiler_lex(context^.lexer); + write_current(context^.lexer); + token := transpiler_lex(context^.lexer) END; IF token.kind = lexerKindHat THEN Write('^'); - token := transpiler_lex(lexer) + token := transpiler_lex(context^.lexer) END; WHILE token.kind = lexerKindLeftSquare DO Write('['); - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); WHILE token.kind <> lexerKindRightSquare DO - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); - token := transpiler_lex(lexer) + write_current(context^.lexer); + token := transpiler_lex(context^.lexer) END; Write(']'); - token := transpiler_lex(lexer) + token := transpiler_lex(context^.lexer) END END transpile_designator_expression; -PROCEDURE transpile_return_statement(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_return_statement(context: PTranspilerContext); VAR token: LexerToken; - written_bytes: CARDINAL; BEGIN WriteString(' RETURN '); - token := transpiler_lex(lexer); - written_bytes := WriteNBytes(StdOut, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start); - token := transpiler_lex(lexer) + token := transpiler_lex(context^.lexer); + write_current(context^.lexer); + token := transpiler_lex(context^.lexer) END transpile_return_statement; -PROCEDURE transpile_statement(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_statement(context: PTranspilerContext); VAR token: LexerToken; - written_bytes: CARDINAL; BEGIN - token := transpiler_lex(lexer); + token := transpiler_lex(context^.lexer); IF token.kind = lexerKindIf THEN - transpile_if_statement(context, lexer) + transpile_if_statement(context) END; IF token.kind = lexerKindWhile THEN - transpile_while_statement(context, lexer) + transpile_while_statement(context) END; IF token.kind = lexerKindReturn THEN - transpile_return_statement(context, lexer) + transpile_return_statement(context) END; IF token.kind = lexerKindIdentifier THEN - transpile_designator_expression(context, lexer); - token := lexer_current(lexer); + transpile_designator_expression(context); + token := lexer_current(context^.lexer); IF token.kind = lexerKindAssignment THEN - transpile_assignment_statement(context, lexer) + transpile_assignment_statement(context) END; IF token.kind = lexerKindLeftParen THEN - transpile_call_statement(context, lexer) + transpile_call_statement(context) END END END transpile_statement; -PROCEDURE transpile_statements(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_statements(context: PTranspilerContext); VAR token: LexerToken; BEGIN - token := lexer_current(lexer); + token := lexer_current(context^.lexer); WHILE token.kind <> lexerKindEnd DO - transpile_statement(context, lexer); - token := lexer_current(lexer); + transpile_statement(context); + token := lexer_current(context^.lexer); IF token.kind = lexerKindSemicolon THEN Write(';') @@ -584,44 +569,44 @@ BEGIN WriteLn() END END transpile_statements; -PROCEDURE transpile_statement_part(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_statement_part(context: PTranspilerContext); VAR token: LexerToken; BEGIN - token := lexer_current(lexer); + token := lexer_current(context^.lexer); IF token.kind = lexerKindBegin THEN WriteString('BEGIN'); WriteLn(); - transpile_statements(context, lexer) + transpile_statements(context) END END transpile_statement_part; -PROCEDURE transpile_procedure_declaration(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_procedure_declaration(context: PTranspilerContext); VAR token: LexerToken; seen_part: BOOLEAN; written_bytes: CARDINAL; BEGIN - token := transpile_procedure_heading(context, lexer); - seen_part := transpile_constant_part(context, lexer); - seen_part := transpile_variable_part(context, lexer); - transpile_statement_part(context, lexer); + token := transpile_procedure_heading(context); + seen_part := transpile_constant_part(context); + seen_part := transpile_variable_part(context); + transpile_statement_part(context); WriteString('END '); written_bytes := WriteNBytes(StdOut, ORD(token.identifierKind[1]), ADR(token.identifierKind[2])); - token := transpiler_lex(lexer); - write_semicolon(); - token := transpiler_lex(lexer) + token := transpiler_lex(context^.lexer); + write_semicolon(context^.output); + token := transpiler_lex(context^.lexer) END transpile_procedure_declaration; -PROCEDURE transpile_procedure_part(context: PTranspilerContext; lexer: PLexer); +PROCEDURE transpile_procedure_part(context: PTranspilerContext); VAR token: LexerToken; BEGIN - token := lexer_current(lexer); + token := lexer_current(context^.lexer); WHILE token.kind = lexerKindProc DO - transpile_procedure_declaration(context, lexer); - token := lexer_current(lexer); + transpile_procedure_declaration(context); + token := lexer_current(context^.lexer); WriteLn() END END transpile_procedure_part; @@ -631,6 +616,10 @@ VAR written_bytes: CARDINAL; context: TranspilerContext; BEGIN - transpile_module(ADR(context), lexer) + context.indentation := 0; + context.output := StdOut; + context.lexer := lexer; + + transpile_module(ADR(context)) END transpile; END Transpiler.