Split the parser from the code generator

This commit is contained in:
2025-06-11 22:36:05 +02:00
parent 6cfeb46dbf
commit 90aa5a0030
6 changed files with 392 additions and 222 deletions

View File

@@ -7,6 +7,7 @@ FROM M2RTS IMPORT HALT, ExitOnHalt;
FROM Lexer IMPORT Lexer, lexer_destroy, lexer_initialize; FROM Lexer IMPORT Lexer, lexer_destroy, lexer_initialize;
FROM Transpiler IMPORT transpile; FROM Transpiler IMPORT transpile;
FROM CommandLineInterface IMPORT PCommandLine, parse_command_line; FROM CommandLineInterface IMPORT PCommandLine, parse_command_line;
FROM Parser IMPORT PAstModule, parse_module;
VAR VAR
command_line: PCommandLine; command_line: PCommandLine;
@@ -15,6 +16,7 @@ PROCEDURE compile_from_stream();
VAR VAR
lexer: Lexer; lexer: Lexer;
source_input: File; source_input: File;
ast_module: PAstModule;
BEGIN BEGIN
source_input := OpenToRead(command_line^.input); source_input := OpenToRead(command_line^.input);
@@ -29,7 +31,8 @@ BEGIN
IF IsNoError(source_input) THEN IF IsNoError(source_input) THEN
lexer_initialize(ADR(lexer), source_input); lexer_initialize(ADR(lexer), source_input);
transpile(ADR(lexer), StdOut, command_line^.input); ast_module := parse_module(ADR(lexer));
transpile(ast_module, StdOut, command_line^.input);
lexer_destroy(ADR(lexer)); lexer_destroy(ADR(lexer));

View File

@@ -11,7 +11,7 @@ FROM MemUtils IMPORT MemCopy, MemZero;
FROM StrCase IMPORT Lower; FROM StrCase IMPORT Lower;
CONST CONST
CHUNK_SIZE = 65536; CHUNK_SIZE = 85536;
TYPE TYPE
(* (*
@@ -308,8 +308,8 @@ BEGIN
END; END;
IF lexer^.start^ = '"' THEN IF lexer^.start^ = '"' THEN
text_length := lexer^.current; text_length := lexer^.current;
DEC(text_length, lexer^.start); DEC(text_length, lexer^.start);
INC(text_length); INC(text_length);
MemZero(ADR(token^.stringKind), TSIZE(ShortString)); MemZero(ADR(token^.stringKind), TSIZE(ShortString));
MemCopy(lexer^.start, text_length, ADR(token^.stringKind)); MemCopy(lexer^.start, text_length, ADR(token^.stringKind));
@@ -318,8 +318,8 @@ BEGIN
END; END;
IF lexer^.start^ = "'" THEN IF lexer^.start^ = "'" THEN
text_length := lexer^.current; text_length := lexer^.current;
DEC(text_length, lexer^.start); DEC(text_length, lexer^.start);
INC(text_length); INC(text_length);
MemZero(ADR(token^.stringKind), TSIZE(ShortString)); MemZero(ADR(token^.stringKind), TSIZE(ShortString));
MemCopy(lexer^.start, text_length, ADR(token^.stringKind)); MemCopy(lexer^.start, text_length, ADR(token^.stringKind));

View File

@@ -153,12 +153,12 @@ TYPE
PAstTypeExpression = POINTER TO AstTypeExpression; PAstTypeExpression = POINTER TO AstTypeExpression;
PPAstTypeExpression = POINTER TO PAstTypeExpression; PPAstTypeExpression = POINTER TO PAstTypeExpression;
AstTypeDeclaration = RECORD AstTypedDeclaration = RECORD
identifier: Identifier; identifier: Identifier;
type_expression: PAstTypeExpression type_expression: PAstTypeExpression
END; END;
PAstTypeDeclaration = POINTER TO AstTypeDeclaration; PAstTypedDeclaration = POINTER TO AstTypedDeclaration;
PPAstTypeDeclaration = POINTER TO PAstTypeDeclaration; PPAstTypedDeclaration = POINTER TO PAstTypedDeclaration;
AstVariableDeclaration = RECORD AstVariableDeclaration = RECORD
variable_name: Identifier; variable_name: Identifier;
@@ -167,23 +167,38 @@ TYPE
PAstVariableDeclaration = POINTER TO AstVariableDeclaration; PAstVariableDeclaration = POINTER TO AstVariableDeclaration;
PPAstVariableDeclaration = POINTER TO PAstVariableDeclaration; PPAstVariableDeclaration = POINTER TO PAstVariableDeclaration;
AstProcedureDeclaration = RECORD
name: Identifier;
parameter_count: CARDINAL;
parameters: PAstTypedDeclaration;
return_type: PAstTypeExpression;
constants: PPAstConstantDeclaration;
variables: PPAstVariableDeclaration;
statements: AstCompoundStatement
END;
PAstProcedureDeclaration = POINTER TO AstProcedureDeclaration;
PPAstProcedureDeclaration = POINTER TO PAstProcedureDeclaration;
AstModule = RECORD AstModule = RECORD
main: BOOLEAN;
imports: PPAstImportStatement; imports: PPAstImportStatement;
constants: PPAstConstantDeclaration; constants: PPAstConstantDeclaration;
types: PPAstTypeDeclaration; types: PPAstTypedDeclaration;
variables: PPAstVariableDeclaration variables: PPAstVariableDeclaration;
procedures: PPAstProcedureDeclaration;
statements: AstCompoundStatement
END; END;
PAstModule = POINTER TO AstModule; PAstModule = POINTER TO AstModule;
PROCEDURE parse_type_expression(lexer: PLexer): PAstTypeExpression; PROCEDURE parse_type_expression(lexer: PLexer): PAstTypeExpression;
PROCEDURE parse_type_part(lexer: PLexer): PPAstTypeDeclaration; PROCEDURE parse_type_part(lexer: PLexer): PPAstTypedDeclaration;
PROCEDURE parse_variable_part(lexer: PLexer): PPAstVariableDeclaration; PROCEDURE parse_variable_part(lexer: PLexer): PPAstVariableDeclaration;
PROCEDURE parse_constant_part(lexer: PLexer): PPAstConstantDeclaration; PROCEDURE parse_constant_part(lexer: PLexer): PPAstConstantDeclaration;
PROCEDURE parse_import_part(lexer: PLexer): PPAstImportStatement; PROCEDURE parse_import_part(lexer: PLexer): PPAstImportStatement;
PROCEDURE parse_designator(lexer: PLexer): PAstExpression; PROCEDURE parse_designator(lexer: PLexer): PAstExpression;
PROCEDURE parse_expression(lexer: PLexer): PAstExpression; PROCEDURE parse_expression(lexer: PLexer): PAstExpression;
PROCEDURE parse_return_statement(lexer: PLexer): PAstStatement; PROCEDURE parse_statement_part(lexer: PLexer): AstCompoundStatement;
PROCEDURE parse_assignment_statement(lexer: PLexer; assignee: PAstExpression): PAstStatement; PROCEDURE parse_procedure_part(lexer: PLexer): PPAstProcedureDeclaration;
PROCEDURE parse_call_statement(lexer: PLexer; call: PAstExpression): PAstStatement; PROCEDURE parse_module(lexer: PLexer): PAstModule;
END Parser. END Parser.

View File

@@ -34,9 +34,9 @@ BEGIN
WHILE token.kind <> lexerKindEnd DO WHILE token.kind <> lexerKindEnd DO
INC(field_count); INC(field_count);
INC(field_count); INC(field_count);
REALLOCATE(field_declarations, TSIZE(AstFieldDeclaration) * field_count); REALLOCATE(field_declarations, TSIZE(AstFieldDeclaration) * field_count);
DEC(field_count); DEC(field_count);
current_field := field_declarations; current_field := field_declarations;
INC(current_field , TSIZE(AstFieldDeclaration) * (field_count - 1)); INC(current_field , TSIZE(AstFieldDeclaration) * (field_count - 1));
@@ -105,7 +105,7 @@ BEGIN
result^.length := token.integerKind; result^.length := token.integerKind;
token := transpiler_lex(lexer); token := transpiler_lex(lexer)
END; END;
token := transpiler_lex(lexer); token := transpiler_lex(lexer);
result^.base := parse_type_expression(lexer); result^.base := parse_type_expression(lexer);
@@ -138,8 +138,8 @@ BEGIN
REALLOCATE(result^.cases, TSIZE(Identifier) * case_count); REALLOCATE(result^.cases, TSIZE(Identifier) * case_count);
DEC(case_count); DEC(case_count);
current_case := result^.cases; current_case := result^.cases;
INC(current_case, TSIZE(Identifier) * (case_count - 1)); INC(current_case, TSIZE(Identifier) * (case_count - 1));
current_case^ := token.identifierKind; current_case^ := token.identifierKind;
token := transpiler_lex(lexer) token := transpiler_lex(lexer)
END; END;
@@ -183,7 +183,7 @@ BEGIN
REALLOCATE(result^.parameters, TSIZE(PAstTypeExpression) * parameter_count); REALLOCATE(result^.parameters, TSIZE(PAstTypeExpression) * parameter_count);
DEC(parameter_count); DEC(parameter_count);
current_parameter := result^.parameters; current_parameter := result^.parameters;
INC(current_parameter, TSIZE(PAstTypeExpression) * (parameter_count - 1)); INC(current_parameter, TSIZE(PAstTypeExpression) * (parameter_count - 1));
current_parameter^ := parse_type_expression(lexer); current_parameter^ := parse_type_expression(lexer);
@@ -226,10 +226,10 @@ BEGIN
END; END;
RETURN result RETURN result
END parse_type_expression; END parse_type_expression;
PROCEDURE parse_type_declaration(lexer: PLexer): PAstTypeDeclaration; PROCEDURE parse_type_declaration(lexer: PLexer): PAstTypedDeclaration;
VAR VAR
token: LexerToken; token: LexerToken;
result: PAstTypeDeclaration; result: PAstTypedDeclaration;
BEGIN BEGIN
token := lexer_current(lexer); token := lexer_current(lexer);
@@ -244,16 +244,16 @@ BEGIN
RETURN result RETURN result
END parse_type_declaration; END parse_type_declaration;
PROCEDURE parse_type_part(lexer: PLexer): PPAstTypeDeclaration; PROCEDURE parse_type_part(lexer: PLexer): PPAstTypedDeclaration;
VAR VAR
token: LexerToken; token: LexerToken;
result: PPAstTypeDeclaration; result: PPAstTypedDeclaration;
current_declaration: PPAstTypeDeclaration; current_declaration: PPAstTypedDeclaration;
declaration_count: CARDINAL; declaration_count: CARDINAL;
BEGIN BEGIN
token := lexer_current(lexer); token := lexer_current(lexer);
ALLOCATE(result, TSIZE(PAstTypeDeclaration)); ALLOCATE(result, TSIZE(PAstTypedDeclaration));
current_declaration := result; current_declaration := result;
declaration_count := 0; declaration_count := 0;
@@ -263,16 +263,16 @@ BEGIN
WHILE token.kind = lexerKindIdentifier DO WHILE token.kind = lexerKindIdentifier DO
INC(declaration_count); INC(declaration_count);
REALLOCATE(result, TSIZE(PAstTypeDeclaration) * (declaration_count + 1)); REALLOCATE(result, TSIZE(PAstTypedDeclaration) * (declaration_count + 1));
current_declaration := result; current_declaration := result;
INC(current_declaration, TSIZE(PAstTypeDeclaration) * (declaration_count - 1)); INC(current_declaration, TSIZE(PAstTypedDeclaration) * (declaration_count - 1));
current_declaration^ := parse_type_declaration(lexer); current_declaration^ := parse_type_declaration(lexer);
token := transpiler_lex(lexer) token := transpiler_lex(lexer)
END END
END; END;
IF declaration_count <> 0 THEN IF declaration_count <> 0 THEN
INC(current_declaration, TSIZE(PAstTypeDeclaration)) INC(current_declaration, TSIZE(PAstTypedDeclaration))
END; END;
current_declaration^ := NIL; current_declaration^ := NIL;
@@ -411,7 +411,7 @@ BEGIN
REALLOCATE(result^.symbols, TSIZE(Identifier) * (symbol_count + 1)); REALLOCATE(result^.symbols, TSIZE(Identifier) * (symbol_count + 1));
current_symbol := result^.symbols; current_symbol := result^.symbols;
INC(current_symbol, TSIZE(Identifier) * (symbol_count - 1)); INC(current_symbol, TSIZE(Identifier) * (symbol_count - 1));
current_symbol^ := token.identifierKind; current_symbol^ := token.identifierKind;
token := transpiler_lex(lexer) token := transpiler_lex(lexer)
@@ -464,18 +464,18 @@ BEGIN
NEW(literal); NEW(literal);
literal^.kind := astLiteralKindInteger; literal^.kind := astLiteralKindInteger;
literal^.integer := token.integerKind; literal^.integer := token.integerKind
END; END;
IF (token.kind = lexerKindCharacter) OR (token.kind = lexerKindString) THEN IF (token.kind = lexerKindCharacter) OR (token.kind = lexerKindString) THEN
NEW(literal); NEW(literal);
literal^.kind := astLiteralKindString; literal^.kind := astLiteralKindString;
literal^.string := token.stringKind; literal^.string := token.stringKind
END; END;
IF token.kind = lexerKindNull THEN IF token.kind = lexerKindNull THEN
NEW(literal); NEW(literal);
literal^.kind := astLiteralKindNull; literal^.kind := astLiteralKindNull
END; END;
IF token.kind = lexerKindBoolean THEN IF token.kind = lexerKindBoolean THEN
NEW(literal); NEW(literal);
@@ -504,7 +504,7 @@ BEGIN
NEW(result); NEW(result);
result^.kind := astExpressionKindLiteral; result^.kind := astExpressionKindLiteral;
result^.literal := literal; result^.literal := literal
END; END;
IF (result = NIL) AND (next_token.kind = lexerKindMinus) THEN IF (result = NIL) AND (next_token.kind = lexerKindMinus) THEN
NEW(result); NEW(result);
@@ -638,7 +638,7 @@ BEGIN
result^.kind := astExpressionKindBinary; result^.kind := astExpressionKindBinary;
result^.binary_operator := operator; result^.binary_operator := operator;
result^.lhs := left; result^.lhs := left;
result^.rhs := right; result^.rhs := right
END; END;
RETURN result RETURN result
@@ -732,4 +732,234 @@ BEGIN
RETURN result RETURN result
END parse_call_statement; END parse_call_statement;
PROCEDURE parse_compound_statement(lexer: PLexer): AstCompoundStatement;
VAR
result: AstCompoundStatement;
token: LexerToken;
current_statement: PPAstStatement;
old_count: CARDINAL;
BEGIN
result.count := 0;
result.statements := NIL;
token := lexer_current(lexer);
WHILE token.kind <> lexerKindEnd DO
old_count := result.count;
INC(result.count);
REALLOCATE(result.statements, TSIZE(PAstStatement) * result.count);
current_statement := result.statements;
INC(current_statement, TSIZE(PAstStatement) * old_count);
current_statement^ := parse_statement(lexer);
token := lexer_current(lexer)
END;
RETURN result
END parse_compound_statement;
PROCEDURE parse_statement(lexer: PLexer): PAstStatement;
VAR
token: LexerToken;
statement: PAstStatement;
designator: PAstExpression;
BEGIN
statement := NIL;
token := transpiler_lex(lexer);
IF token.kind = lexerKindIf THEN
statement := parse_if_statement(lexer)
END;
IF token.kind = lexerKindWhile THEN
statement := parse_while_statement(lexer)
END;
IF token.kind = lexerKindReturn THEN
statement := parse_return_statement(lexer)
END;
IF token.kind = lexerKindIdentifier THEN
designator := parse_designator(lexer);
token := lexer_current(lexer);
IF token.kind = lexerKindAssignment THEN
statement := parse_assignment_statement(lexer, designator)
END;
IF token.kind <> lexerKindAssignment THEN
statement := parse_call_statement(lexer, designator)
END
END;
RETURN statement
END parse_statement;
PROCEDURE parse_if_statement(lexer: PLexer): PAstStatement;
VAR
token: LexerToken;
result: PAstStatement;
BEGIN
NEW(result);
result^.kind := astStatementKindIf;
token := transpiler_lex(lexer);
result^.if_condition := parse_expression(lexer);
result^.if_branch := parse_compound_statement(lexer);
token := transpiler_lex(lexer);
RETURN result
END parse_if_statement;
PROCEDURE parse_while_statement(lexer: PLexer): PAstStatement;
VAR
token: LexerToken;
result: PAstStatement;
BEGIN
NEW(result);
result^.kind := astStatementKindWhile;
token := transpiler_lex(lexer);
result^.while_condition := parse_expression(lexer);
result^.while_body := parse_compound_statement(lexer);
token := transpiler_lex(lexer);
RETURN result
END parse_while_statement;
PROCEDURE parse_statement_part(lexer: PLexer): AstCompoundStatement;
VAR
token: LexerToken;
compound: AstCompoundStatement;
BEGIN
compound.count := 0;
compound.statements := NIL;
token := lexer_current(lexer);
IF token.kind = lexerKindBegin THEN
compound := parse_compound_statement(lexer)
END;
RETURN compound
END parse_statement_part;
PROCEDURE parse_procedure_heading(lexer: PLexer): PAstProcedureDeclaration;
VAR
token: LexerToken;
declaration: PAstProcedureDeclaration;
parameter_index: CARDINAL;
current_parameter: PAstTypedDeclaration;
BEGIN
NEW(declaration);
token := transpiler_lex(lexer);
declaration^.name := token.identifierKind;
token := transpiler_lex(lexer);
declaration^.parameters := NIL;
declaration^.parameter_count := 0;
token := transpiler_lex(lexer);
WHILE token.kind <> lexerKindRightParen DO
parameter_index := declaration^.parameter_count;
INC(declaration^.parameter_count);
REALLOCATE(declaration^.parameters, TSIZE(AstTypedDeclaration) * declaration^.parameter_count);
current_parameter := declaration^.parameters;
INC(current_parameter, TSIZE(AstTypedDeclaration) * parameter_index);
current_parameter^.identifier := token.identifierKind;
token := transpiler_lex(lexer);
token := transpiler_lex(lexer);
current_parameter^.type_expression := parse_type_expression(lexer);
token := transpiler_lex(lexer);
IF token.kind = lexerKindComma THEN
token := transpiler_lex(lexer)
END
END;
token := transpiler_lex(lexer);
declaration^.return_type := NIL;
(* Check for the return type and write it. *)
IF token.kind = lexerKindArrow THEN
token := transpiler_lex(lexer);
declaration^.return_type := parse_type_expression(lexer);
token := transpiler_lex(lexer)
END;
token := transpiler_lex(lexer);
RETURN declaration
END parse_procedure_heading;
PROCEDURE parse_procedure_declaration(lexer: PLexer): PAstProcedureDeclaration;
VAR
token: LexerToken;
declaration: PAstProcedureDeclaration;
BEGIN
declaration := parse_procedure_heading(lexer);
declaration^.constants := parse_constant_part(lexer);
declaration^.variables := parse_variable_part(lexer);
declaration^.statements := parse_statement_part(lexer);
token := transpiler_lex(lexer);
token := transpiler_lex(lexer);
RETURN declaration
END parse_procedure_declaration;
PROCEDURE parse_procedure_part(lexer: PLexer): PPAstProcedureDeclaration;
VAR
token: LexerToken;
current_declaration: PPAstProcedureDeclaration;
result: PPAstProcedureDeclaration;
declaration_count: CARDINAL;
declaration_index: CARDINAL;
BEGIN
token := lexer_current(lexer);
declaration_count := 0;
declaration_index := 0;
ALLOCATE(result, TSIZE(PAstProcedureDeclaration));
WHILE token.kind = lexerKindProc DO
INC(declaration_count);
REALLOCATE(result, TSIZE(PAstProcedureDeclaration) * (declaration_count + 1));
current_declaration := result;
INC(current_declaration, TSIZE(PAstProcedureDeclaration) * declaration_index);
current_declaration^ := parse_procedure_declaration(lexer);
token := lexer_current(lexer);
declaration_index := declaration_count
END;
current_declaration := result;
INC(current_declaration, TSIZE(PAstProcedureDeclaration) * declaration_index);
current_declaration^ := NIL;
RETURN result
END parse_procedure_part;
PROCEDURE parse_module(lexer: PLexer): PAstModule;
VAR
token: LexerToken;
result: PAstModule;
BEGIN
NEW(result);
token := transpiler_lex(lexer);
result^.main := TRUE;
IF token.kind = lexerKindModule THEN
result^.main := FALSE
END;
token := transpiler_lex(lexer);
(* Write the module body. *)
token := transpiler_lex(lexer);
result^.imports := parse_import_part(lexer);
result^.constants := parse_constant_part(lexer);
result^.types := parse_type_part(lexer);
result^.variables := parse_variable_part(lexer);
result^.procedures := parse_procedure_part(lexer);
result^.statements := parse_statement_part(lexer);
token := transpiler_lex(lexer);
token := transpiler_lex(lexer);
RETURN result
END parse_module;
END Parser. END Parser.

View File

@@ -4,15 +4,15 @@ FROM FIO IMPORT File;
FROM Common IMPORT ShortString; FROM Common IMPORT ShortString;
FROM Lexer IMPORT PLexer, Lexer; FROM Lexer IMPORT PLexer, Lexer;
FROM Parser IMPORT PAstModule;
TYPE TYPE
TranspilerContext = RECORD TranspilerContext = RECORD
input_name: ShortString; input_name: ShortString;
output: File; output: File
lexer: PLexer
END; END;
PTranspilerContext = POINTER TO TranspilerContext; PTranspilerContext = POINTER TO TranspilerContext;
PROCEDURE transpile(lexer: PLexer; output: File; input_name: ShortString); PROCEDURE transpile(ast_module: PAstModule; output: File; input_name: ShortString);
END Transpiler. END Transpiler.

View File

@@ -1,6 +1,6 @@
IMPLEMENTATION MODULE Transpiler; IMPLEMENTATION MODULE Transpiler;
FROM FIO IMPORT StdErr, WriteNBytes, WriteLine, WriteChar, WriteString; FROM FIO IMPORT WriteNBytes, WriteLine, WriteChar, WriteString;
FROM SYSTEM IMPORT ADR, ADDRESS, TSIZE; FROM SYSTEM IMPORT ADR, ADDRESS, TSIZE;
FROM NumberIO IMPORT IntToStr; FROM NumberIO IMPORT IntToStr;
@@ -10,13 +10,11 @@ FROM MemUtils IMPORT MemCopy, MemZero;
FROM Common IMPORT Identifier, PIdentifier, ShortString; FROM Common IMPORT Identifier, PIdentifier, ShortString;
FROM Lexer IMPORT Lexer, LexerToken, lexer_current, lexer_lex, LexerKind; FROM Lexer IMPORT Lexer, LexerToken, lexer_current, lexer_lex, LexerKind;
FROM Parser IMPORT AstTypeExpressionKind, AstExpressionKind, AstLiteralKind, AstUnaryOperator, AstBinaryOperator, FROM Parser IMPORT AstTypeExpressionKind, AstExpressionKind, AstLiteralKind, AstUnaryOperator, AstBinaryOperator,
AstModule, PAstModule, AstExpression, PPAstExpression, PAstExpression, PAstLiteral, AstModule, PAstModule, AstExpression, PPAstExpression, PAstExpression, PAstLiteral, PPAstProcedureDeclaration,
PAstConstantDeclaration, PPAstConstantDeclaration, PAstStatement, AstStatementKind, PAstConstantDeclaration, PPAstConstantDeclaration, PPAstStatement, PAstStatement, AstStatementKind,
AstTypeDeclaration, PAstTypeDeclaration, PPAstTypeDeclaration, AstTypedDeclaration, PAstTypedDeclaration, PPAstTypedDeclaration, AstCompoundStatement, PAstProcedureDeclaration,
PAstVariableDeclaration, PPAstVariableDeclaration, PAstImportStatement, PPAstImportStatement, PAstVariableDeclaration, PPAstVariableDeclaration, PAstImportStatement, PPAstImportStatement,
PAstTypeExpression, PPAstTypeExpression, AstFieldDeclaration, PAstFieldDeclaration, PAstTypeExpression, PPAstTypeExpression, AstFieldDeclaration, PAstFieldDeclaration;
parse_type_expression, parse_variable_part, parse_type_part, parse_constant_part, parse_import_part,
parse_designator, parse_expression, parse_return_statement, parse_assignment_statement, parse_call_statement;
(* Calls lexer_lex() but skips the comments. *) (* Calls lexer_lex() but skips the comments. *)
PROCEDURE transpiler_lex(lexer: PLexer): LexerToken; PROCEDURE transpiler_lex(lexer: PLexer): LexerToken;
@@ -111,15 +109,11 @@ BEGIN
WriteLine(context^.output) WriteLine(context^.output)
END END
END transpile_constant_part; END transpile_constant_part;
PROCEDURE transpile_module(context: PTranspilerContext): PAstModule; PROCEDURE transpile_module(context: PTranspilerContext; result: PAstModule);
VAR VAR
token: LexerToken; token: LexerToken;
result: PAstModule;
BEGIN BEGIN
NEW(result); IF result^.main = FALSE THEN
token := transpiler_lex(context^.lexer);
IF token.kind = lexerKindModule THEN
WriteString(context^.output, 'IMPLEMENTATION ') WriteString(context^.output, 'IMPLEMENTATION ')
END; END;
WriteString(context^.output, 'MODULE '); WriteString(context^.output, 'MODULE ');
@@ -127,37 +121,23 @@ BEGIN
(* Write the module name and end the line with a semicolon and newline. *) (* Write the module name and end the line with a semicolon and newline. *)
transpile_module_name(context); transpile_module_name(context);
token := transpiler_lex(context^.lexer);
write_semicolon(context^.output); write_semicolon(context^.output);
WriteLine(context^.output); WriteLine(context^.output);
(* Write the module body. *) (* Write the module body. *)
token := transpiler_lex(context^.lexer);
result^.imports := parse_import_part(context^.lexer);
transpile_import_part(context, result^.imports); transpile_import_part(context, result^.imports);
result^.constants := parse_constant_part(context^.lexer);
transpile_constant_part(context, result^.constants); transpile_constant_part(context, result^.constants);
result^.types := parse_type_part(context^.lexer);
transpile_type_part(context, result^.types); transpile_type_part(context, result^.types);
result^.variables := parse_variable_part(context^.lexer);
transpile_variable_part(context, result^.variables); transpile_variable_part(context, result^.variables);
transpile_procedure_part(context, result^.procedures);
transpile_procedure_part(context); transpile_statement_part(context, result^.statements);
transpile_statement_part(context);
WriteString(context^.output, 'END '); WriteString(context^.output, 'END ');
transpile_module_name(context); transpile_module_name(context);
token := transpiler_lex(context^.lexer);
WriteChar(context^.output, '.'); WriteChar(context^.output, '.');
WriteLine(context^.output)
token := transpiler_lex(context^.lexer);
WriteLine(context^.output);
RETURN result
END transpile_module; END transpile_module;
PROCEDURE transpile_type_fields(context: PTranspilerContext; fields: PAstFieldDeclaration); PROCEDURE transpile_type_fields(context: PTranspilerContext; fields: PAstFieldDeclaration);
VAR VAR
@@ -206,7 +186,7 @@ BEGIN
WriteString(context^.output, '[1..'); WriteString(context^.output, '[1..');
IntToStr(type_expression^.length, 0, buffer); IntToStr(type_expression^.length, 0, buffer);
WriteString(context^.output, buffer); WriteString(context^.output, buffer);
WriteChar(context^.output, ']') WriteChar(context^.output, ']')
END; END;
@@ -256,7 +236,7 @@ BEGIN
WHILE current_parameter^ <> NIL DO WHILE current_parameter^ <> NIL DO
transpile_type_expression(context, current_parameter^); transpile_type_expression(context, current_parameter^);
INC(current_parameter, TSIZE(PAstTypeExpression)); INC(current_parameter, TSIZE(PAstTypeExpression));
IF current_parameter^ <> NIL THEN IF current_parameter^ <> NIL THEN
WriteString(context^.output, ', ') WriteString(context^.output, ', ')
@@ -285,7 +265,7 @@ BEGIN
transpile_named_type(context, type_expression) transpile_named_type(context, type_expression)
END END
END transpile_type_expression; END transpile_type_expression;
PROCEDURE transpile_type_declaration(context: PTranspilerContext; declaration: PAstTypeDeclaration); PROCEDURE transpile_type_declaration(context: PTranspilerContext; declaration: PAstTypedDeclaration);
VAR VAR
written_bytes: CARDINAL; written_bytes: CARDINAL;
BEGIN BEGIN
@@ -297,9 +277,9 @@ BEGIN
transpile_type_expression(context, declaration^.type_expression); transpile_type_expression(context, declaration^.type_expression);
write_semicolon(context^.output) write_semicolon(context^.output)
END transpile_type_declaration; END transpile_type_declaration;
PROCEDURE transpile_type_part(context: PTranspilerContext; declarations: PPAstTypeDeclaration); PROCEDURE transpile_type_part(context: PTranspilerContext; declarations: PPAstTypedDeclaration);
VAR VAR
current_declaration: PPAstTypeDeclaration; current_declaration: PPAstTypedDeclaration;
BEGIN BEGIN
IF declarations^ <> NIL THEN IF declarations^ <> NIL THEN
WriteString(context^.output, 'TYPE'); WriteString(context^.output, 'TYPE');
@@ -309,7 +289,7 @@ BEGIN
WHILE current_declaration^ <> NIL DO WHILE current_declaration^ <> NIL DO
transpile_type_declaration(context, current_declaration^); transpile_type_declaration(context, current_declaration^);
INC(current_declaration, TSIZE(PAstTypeDeclaration)) INC(current_declaration, TSIZE(PAstTypedDeclaration))
END; END;
WriteLine(context^.output) WriteLine(context^.output)
END END
@@ -343,51 +323,41 @@ BEGIN
WriteLine(context^.output) WriteLine(context^.output)
END END
END transpile_variable_part; END transpile_variable_part;
PROCEDURE transpile_procedure_heading(context: PTranspilerContext): LexerToken; PROCEDURE transpile_procedure_heading(context: PTranspilerContext; declaration: PAstProcedureDeclaration);
VAR VAR
token: LexerToken; token: LexerToken;
result: LexerToken; written_bytes: CARDINAL;
type_expression: PAstTypeExpression; parameter_index: CARDINAL;
current_parameter: PAstTypedDeclaration;
BEGIN BEGIN
WriteString(context^.output, 'PROCEDURE '); WriteString(context^.output, 'PROCEDURE ');
written_bytes := WriteNBytes(context^.output, ORD(declaration^.name[1]), ADR(declaration^.name[2]));
result := transpiler_lex(context^.lexer);
write_current(context^.lexer, context^.output);
token := transpiler_lex(context^.lexer);
WriteChar(context^.output, '('); WriteChar(context^.output, '(');
token := transpiler_lex(context^.lexer); parameter_index := 0;
WHILE token.kind <> lexerKindRightParen DO current_parameter := declaration^.parameters;
write_current(context^.lexer, context^.output);
token := transpiler_lex(context^.lexer); WHILE parameter_index < declaration^.parameter_count DO
written_bytes := WriteNBytes(context^.output, ORD(current_parameter^.identifier[1]), ADR(current_parameter^.identifier[2]));
WriteString(context^.output, ': '); WriteString(context^.output, ': ');
token := transpiler_lex(context^.lexer); transpile_type_expression(context, current_parameter^.type_expression);
type_expression := parse_type_expression(context^.lexer); INC(parameter_index);
transpile_type_expression(context, type_expression); INC(current_parameter, TSIZE(AstTypedDeclaration));
token := transpiler_lex(context^.lexer); IF parameter_index <> declaration^.parameter_count THEN
IF (token.kind = lexerKindSemicolon) OR (token.kind = lexerKindComma) THEN WriteString(context^.output, '; ')
WriteString(context^.output, '; ');
token := transpiler_lex(context^.lexer)
END END
END; END;
WriteString(context^.output, ')'); WriteString(context^.output, ')');
token := transpiler_lex(context^.lexer);
(* Check for the return type and write it. *) (* Check for the return type and write it. *)
IF token.kind = lexerKindArrow THEN IF declaration^.return_type <> NIL THEN
WriteString(context^.output, ': '); WriteString(context^.output, ': ');
token := transpiler_lex(context^.lexer); transpile_type_expression(context, declaration^.return_type)
write_current(context^.lexer, context^.output);
token := transpiler_lex(context^.lexer)
END; END;
token := transpiler_lex(context^.lexer); write_semicolon(context^.output)
write_semicolon(context^.output);
RETURN result
END transpile_procedure_heading; END transpile_procedure_heading;
PROCEDURE transpile_unary_operator(context: PTranspilerContext; operator: AstUnaryOperator); PROCEDURE transpile_unary_operator(context: PTranspilerContext; operator: AstUnaryOperator);
BEGIN BEGIN
@@ -447,20 +417,20 @@ BEGIN
IF literal^.kind = astLiteralKindInteger THEN IF literal^.kind = astLiteralKindInteger THEN
IntToStr(literal^.integer, 0, buffer); IntToStr(literal^.integer, 0, buffer);
WriteString(context^.output, buffer); WriteString(context^.output, buffer)
END; END;
IF literal^.kind = astLiteralKindString THEN IF literal^.kind = astLiteralKindString THEN
WriteString(context^.output, literal^.string) WriteString(context^.output, literal^.string)
END; END;
IF literal^.kind = astLiteralKindNull THEN IF literal^.kind = astLiteralKindNull THEN
WriteString(context^.output, 'NIL') WriteString(context^.output, 'NIL')
END; END;
IF (literal^.kind = astLiteralKindBoolean) AND literal^.boolean THEN IF (literal^.kind = astLiteralKindBoolean) AND literal^.boolean THEN
WriteString(context^.output, 'TRUE') WriteString(context^.output, 'TRUE')
END; END;
IF (literal^.kind = astLiteralKindBoolean) AND (literal^.boolean = FALSE) THEN IF (literal^.kind = astLiteralKindBoolean) AND (literal^.boolean = FALSE) THEN
WriteString(context^.output, 'FALSE') WriteString(context^.output, 'FALSE')
END END
END; END;
IF expression^.kind = astExpressionKindIdentifier THEN IF expression^.kind = astExpressionKindIdentifier THEN
written_bytes := WriteNBytes(context^.output, ORD(expression^.identifier[1]), ADR(expression^.identifier[2])) written_bytes := WriteNBytes(context^.output, ORD(expression^.identifier[1]), ADR(expression^.identifier[2]))
@@ -478,7 +448,7 @@ BEGIN
IF expression^.kind = astExpressionKindFieldAccess THEN IF expression^.kind = astExpressionKindFieldAccess THEN
transpile_expression(context, expression^.aggregate); transpile_expression(context, expression^.aggregate);
WriteChar(context^.output, '.'); WriteChar(context^.output, '.');
written_bytes := WriteNBytes(context^.output, ORD(expression^.field[1]), ADR(expression^.field[2])); written_bytes := WriteNBytes(context^.output, ORD(expression^.field[1]), ADR(expression^.field[2]))
END; END;
IF expression^.kind = astExpressionKindUnary THEN IF expression^.kind = astExpressionKindUnary THEN
transpile_unary_operator(context, expression^.unary_operator); transpile_unary_operator(context, expression^.unary_operator);
@@ -516,51 +486,33 @@ BEGIN
WriteChar(context^.output, ')') WriteChar(context^.output, ')')
END END
END transpile_expression; END transpile_expression;
PROCEDURE transpile_if_statement(context: PTranspilerContext): PAstStatement; PROCEDURE transpile_if_statement(context: PTranspilerContext; statement: PAstStatement);
VAR VAR
token: LexerToken; token: LexerToken;
result: PAstStatement;
BEGIN BEGIN
NEW(result); IF statement <> NIL THEN
result^.kind := astStatementKindIf; WriteString(context^.output, ' IF ');
WriteString(context^.output, ' IF '); transpile_expression(context, statement^.if_condition);
token := transpiler_lex(context^.lexer); WriteString(context^.output, ' THEN');
result^.if_condition := parse_expression(context^.lexer); WriteLine(context^.output);
transpile_expression(context, result^.if_condition); transpile_compound_statement(context, statement^.if_branch);
token := lexer_current(context^.lexer); WriteString(context^.output, ' END')
END
WriteString(context^.output, ' THEN');
WriteLine(context^.output);
transpile_statements(context);
WriteString(context^.output, ' END');
token := transpiler_lex(context^.lexer);
RETURN result
END transpile_if_statement; END transpile_if_statement;
PROCEDURE transpile_while_statement(context: PTranspilerContext): PAstStatement; PROCEDURE transpile_while_statement(context: PTranspilerContext; statement: PAstStatement);
VAR VAR
token: LexerToken; token: LexerToken;
result: PAstStatement;
BEGIN BEGIN
NEW(result);
result^.kind := astStatementKindWhile;
WriteString(context^.output, ' WHILE '); WriteString(context^.output, ' WHILE ');
transpile_expression(context, statement^.while_condition);
token := transpiler_lex(context^.lexer);
result^.while_condition := parse_expression(context^.lexer);
transpile_expression(context, result^.while_condition);
token := lexer_current(context^.lexer);
WriteString(context^.output, ' DO'); WriteString(context^.output, ' DO');
WriteLine(context^.output); WriteLine(context^.output);
transpile_statements(context);
WriteString(context^.output, ' END');
token := transpiler_lex(context^.lexer);
RETURN result transpile_compound_statement(context, statement^.while_body);
WriteString(context^.output, ' END')
END transpile_while_statement; END transpile_while_statement;
PROCEDURE transpile_assignment_statement(context: PTranspilerContext; statement: PAstStatement); PROCEDURE transpile_assignment_statement(context: PTranspilerContext; statement: PAstStatement);
BEGIN BEGIN
@@ -572,103 +524,76 @@ PROCEDURE transpile_return_statement(context: PTranspilerContext; statement: PAs
BEGIN BEGIN
WriteString(context^.output, ' RETURN '); WriteString(context^.output, ' RETURN ');
transpile_expression(context, statement^.returned); transpile_expression(context, statement^.returned)
END transpile_return_statement; END transpile_return_statement;
PROCEDURE transpile_statement(context: PTranspilerContext); PROCEDURE transpile_compound_statement(context: PTranspilerContext; statement: AstCompoundStatement);
VAR VAR
token: LexerToken; current_statement: PPAstStatement;
written_bytes: CARDINAL; index: CARDINAL;
statement: PAstStatement;
designator: PAstExpression;
BEGIN BEGIN
token := transpiler_lex(context^.lexer); index := 0;
current_statement := statement.statements;
IF token.kind = lexerKindIf THEN WHILE index < statement.count DO
statement := transpile_if_statement(context) transpile_statement(context, current_statement^);
END;
IF token.kind = lexerKindWhile THEN
statement := transpile_while_statement(context)
END;
IF token.kind = lexerKindReturn THEN
statement := parse_return_statement(context^.lexer);
transpile_return_statement(context, statement)
END;
IF token.kind = lexerKindIdentifier THEN
designator := parse_designator(context^.lexer);
token := lexer_current(context^.lexer);
IF token.kind = lexerKindAssignment THEN INC(current_statement, TSIZE(PAstStatement));
statement := parse_assignment_statement(context^.lexer, designator); INC(index);
transpile_assignment_statement(context, statement)
END;
IF token.kind <> lexerKindAssignment THEN
statement := parse_call_statement(context^.lexer, designator);
transpile_expression(context, designator);
written_bytes := WriteNBytes(StdErr, 5, context^.lexer^.start); IF index <> statement.count THEN
WriteLine(StdErr);
END
END
END transpile_statement;
PROCEDURE transpile_statements(context: PTranspilerContext);
VAR
token: LexerToken;
BEGIN
token := lexer_current(context^.lexer);
WHILE token.kind <> lexerKindEnd DO
transpile_statement(context);
token := lexer_current(context^.lexer);
IF token.kind = lexerKindSemicolon THEN
WriteChar(context^.output, ';') WriteChar(context^.output, ';')
END; END;
WriteLine(context^.output) WriteLine(context^.output)
END END
END transpile_statements; END transpile_compound_statement;
PROCEDURE transpile_statement_part(context: PTranspilerContext); PROCEDURE transpile_statement(context: PTranspilerContext; statement: PAstStatement);
VAR
token: LexerToken;
BEGIN BEGIN
token := lexer_current(context^.lexer); IF statement^.kind = astStatementKindIf THEN
IF token.kind = lexerKindBegin THEN transpile_if_statement(context, statement)
END;
IF statement^.kind = astStatementKindWhile THEN
transpile_while_statement(context, statement)
END;
IF statement^.kind = astStatementKindReturn THEN
transpile_return_statement(context, statement)
END;
IF statement^.kind = astStatementKindAssignment THEN
transpile_assignment_statement(context, statement)
END;
IF statement^.kind = astStatementKindCall THEN
transpile_expression(context, statement^.call)
END
END transpile_statement;
PROCEDURE transpile_statement_part(context: PTranspilerContext; compound: AstCompoundStatement);
BEGIN
IF compound.count > 0 THEN
WriteString(context^.output, 'BEGIN'); WriteString(context^.output, 'BEGIN');
WriteLine(context^.output); WriteLine(context^.output);
transpile_statements(context) transpile_compound_statement(context, compound)
END END
END transpile_statement_part; END transpile_statement_part;
PROCEDURE transpile_procedure_declaration(context: PTranspilerContext); PROCEDURE transpile_procedure_declaration(context: PTranspilerContext; declaration: PAstProcedureDeclaration);
VAR VAR
token: LexerToken;
seen_variables: PPAstVariableDeclaration;
written_bytes: CARDINAL; written_bytes: CARDINAL;
seen_constants: PPAstConstantDeclaration;
BEGIN BEGIN
token := transpile_procedure_heading(context); transpile_procedure_heading(context, declaration);
seen_constants := parse_constant_part(context^.lexer);
transpile_constant_part(context, seen_constants);
seen_variables := parse_variable_part(context^.lexer); transpile_constant_part(context, declaration^.constants);
transpile_variable_part(context, seen_variables); transpile_variable_part(context, declaration^.variables);
transpile_statement_part(context); transpile_statement_part(context, declaration^.statements);
WriteString(context^.output, 'END '); WriteString(context^.output, 'END ');
written_bytes := WriteNBytes(context^.output, ORD(token.identifierKind[1]), ADR(token.identifierKind[2])); written_bytes := WriteNBytes(context^.output, ORD(declaration^.name[1]), ADR(declaration^.name[2]));
token := transpiler_lex(context^.lexer); write_semicolon(context^.output)
write_semicolon(context^.output);
token := transpiler_lex(context^.lexer)
END transpile_procedure_declaration; END transpile_procedure_declaration;
PROCEDURE transpile_procedure_part(context: PTranspilerContext); PROCEDURE transpile_procedure_part(context: PTranspilerContext; declaration: PPAstProcedureDeclaration);
VAR
token: LexerToken;
BEGIN BEGIN
token := lexer_current(context^.lexer); WHILE declaration^ <> NIL DO
transpile_procedure_declaration(context, declaration^);
WriteLine(context^.output);
WHILE token.kind = lexerKindProc DO INC(declaration, TSIZE(PAstProcedureDeclaration))
transpile_procedure_declaration(context);
token := lexer_current(context^.lexer);
WriteLine(context^.output)
END END
END transpile_procedure_part; END transpile_procedure_part;
PROCEDURE transpile_module_name(context: PTranspilerContext); PROCEDURE transpile_module_name(context: PTranspilerContext);
@@ -683,7 +608,7 @@ BEGIN
IF context^.input_name[counter] = '/' THEN IF context^.input_name[counter] = '/' THEN
last_slash := counter last_slash := counter
END; END;
INC(counter) INC(counter)
END; END;
IF last_slash = 0 THEN IF last_slash = 0 THEN
@@ -694,19 +619,16 @@ BEGIN
END; END;
WHILE (context^.input_name[counter] <> '.') AND (ORD(context^.input_name[counter]) <> 0) DO WHILE (context^.input_name[counter] <> '.') AND (ORD(context^.input_name[counter]) <> 0) DO
WriteChar(context^.output, context^.input_name[counter]); WriteChar(context^.output, context^.input_name[counter]);
INC(counter) INC(counter)
END; END
END transpile_module_name; END transpile_module_name;
PROCEDURE transpile(lexer: PLexer; output: File; input_name: ShortString); PROCEDURE transpile(ast_module: PAstModule; output: File; input_name: ShortString);
VAR VAR
token: LexerToken;
context: TranspilerContext; context: TranspilerContext;
ast_module: PAstModule;
BEGIN BEGIN
context.input_name := input_name; context.input_name := input_name;
context.output := output; context.output := output;
context.lexer := lexer;
ast_module := transpile_module(ADR(context)) transpile_module(ADR(context), ast_module)
END transpile; END transpile;
END Transpiler. END Transpiler.