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

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