Parse and transpile unary operations

This commit is contained in:
Eugen Wissner 2025-06-06 18:25:53 +02:00
parent 3ca8491f64
commit 8d52410be9
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
6 changed files with 297 additions and 29 deletions

View File

@ -18,7 +18,7 @@ var
parsed: BOOLEAN; parsed: BOOLEAN;
begin begin
i := 1; i := 1;
ALLOCATE(result, TSIZE(CommandLine)); NEW(result);
result^.lex := false; result^.lex := false;
result^.parse := false; result^.parse := false;
MemZero(ADR(result^.input), 256); MemZero(ADR(result^.input), 256);

View File

@ -2,7 +2,7 @@ DEFINITION MODULE Lexer;
FROM FIO IMPORT File; FROM FIO IMPORT File;
FROM Common IMPORT Identifier; FROM Common IMPORT Identifier, ShortString;
TYPE TYPE
PLexerBuffer = POINTER TO CHAR; PLexerBuffer = POINTER TO CHAR;
@ -41,7 +41,7 @@ TYPE
lexerKindNull, lexerKindNull,
lexerKindAnd, lexerKindAnd,
lexerKindOr, lexerKindOr,
lexerKindNot, lexerKindTilde,
lexerKindReturn, lexerKindReturn,
lexerKindDefinition, lexerKindDefinition,
lexerKindRange, lexerKindRange,
@ -84,7 +84,8 @@ TYPE
CASE kind: LexerKind OF CASE kind: LexerKind OF
lexerKindBoolean: booleanKind: BOOLEAN | lexerKindBoolean: booleanKind: BOOLEAN |
lexerKindIdentifier: identifierKind: Identifier | lexerKindIdentifier: identifierKind: Identifier |
lexerKindInteger: integerKind: INTEGER lexerKindInteger: integerKind: INTEGER |
lexerKindString: stringKind: ShortString
END END
END; END;
PLexerToken = POINTER TO LexerToken; PLexerToken = POINTER TO LexerToken;

View File

@ -301,6 +301,8 @@ end;
(* Delimited string action. *) (* Delimited string action. *)
proc transition_action_delimited(lexer: PLexer, token: PLexerToken); proc transition_action_delimited(lexer: PLexer, token: PLexerToken);
var
text_length: CARDINAL;
begin begin
if lexer^.Start^ = '(' then if lexer^.Start^ = '(' then
token^.kind := lexerKindComment token^.kind := lexerKindComment
@ -309,6 +311,10 @@ begin
token^.kind := lexerKindCharacter token^.kind := lexerKindCharacter
end; end;
if lexer^.Start^ = "'" then if lexer^.Start^ = "'" then
text_length := lexer^.Current - lexer^.Start;
MemZero(ADR(token^.stringKind), TSIZE(ShortString));
MemCopy(lexer^.Start, text_length, ADR(token^.stringKind));
token^.kind := lexerKindString token^.kind := lexerKindString
end; end;
INC(lexer^.Current) INC(lexer^.Current)
@ -432,8 +438,8 @@ begin
if lexer^.Current^ = ',' then if lexer^.Current^ = ',' then
token^.kind := lexerKindComma token^.kind := lexerKindComma
end; end;
if lexer^.Current^ = ',' then if lexer^.Current^ = '~' then
token^.kind := lexerKindComma token^.kind := lexerKindTilde
end; end;
if lexer^.Current^ = ')' then if lexer^.Current^ = ')' then
token^.kind := lexerKindRightParen token^.kind := lexerKindRightParen

View File

@ -1,9 +1,55 @@
DEFINITION MODULE Parser; DEFINITION MODULE Parser;
FROM Common IMPORT Identifier, PIdentifier; FROM Common IMPORT Identifier, PIdentifier, ShortString;
FROM Lexer IMPORT PLexer; FROM Lexer IMPORT PLexer;
TYPE TYPE
AstLiteralKind = (
astLiteralKindInteger,
astLiteralKindString,
astLiteralKindNull
);
AstLiteral = RECORD
CASE kind: AstLiteralKind OF
astLiteralKindInteger: integer: INTEGER |
astLiteralKindString: string: ShortString |
astLiteralKindNull:
END
END;
PAstLiteral = POINTER TO AstLiteral;
AstUnaryOperator = (
astUnaryOperatorNot,
astUnaryOperatorMinus
);
AstExpressionKind = (
astExpressionKindLiteral,
astExpressionKindIdentifier,
astExpressionKindArrayAccess,
astExpressionKindDereference,
astExpressionKindFieldAccess,
astExpressionKindUnary
);
AstExpression = RECORD
CASE kind: AstExpressionKind OF
astExpressionKindLiteral: literal: PAstLiteral |
astExpressionKindIdentifier: identifier: Identifier |
astExpressionKindDereference: reference: PAstExpression |
astExpressionKindArrayAccess:
array: PAstExpression;
index: PAstExpression |
astExpressionKindFieldAccess:
aggregate: PAstExpression;
field: Identifier |
astExpressionKindUnary:
unary_operator: AstUnaryOperator;
unary_operand: PAstExpression
END
END;
PAstExpression = POINTER TO AstExpression;
PPAstExpression = POINTER TO PAstExpression;
AstImportStatement = RECORD AstImportStatement = RECORD
package: Identifier; package: Identifier;
symbols: PIdentifier symbols: PIdentifier
@ -74,5 +120,6 @@ PROCEDURE parse_type_part(lexer: PLexer): PPAstTypeDeclaration;
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;
END Parser. END Parser.

View File

@ -60,7 +60,7 @@ proc parse_record_type(lexer: PLexer) -> PAstTypeExpression;
var var
result: PAstTypeExpression; result: PAstTypeExpression;
begin begin
ALLOCATE(result, TSIZE(AstTypeExpression)); NEW(result);
result^.kind := astTypeExpressionKindRecord; result^.kind := astTypeExpressionKindRecord;
result^.fields := parse_type_fields(lexer); result^.fields := parse_type_fields(lexer);
@ -72,7 +72,7 @@ var
token: LexerToken; token: LexerToken;
result: PAstTypeExpression; result: PAstTypeExpression;
begin begin
ALLOCATE(result, TSIZE(AstTypeExpression)); NEW(result);
result^.kind := astTypeExpressionKindPointer; result^.kind := astTypeExpressionKindPointer;
token := lexer_current(lexer); token := lexer_current(lexer);
@ -92,7 +92,7 @@ var
buffer: [20]CHAR; buffer: [20]CHAR;
result: PAstTypeExpression; result: PAstTypeExpression;
begin begin
ALLOCATE(result, TSIZE(AstTypeExpression)); NEW(result);
result^.kind := astTypeExpressionKindArray; result^.kind := astTypeExpressionKindArray;
result^.length := 0; result^.length := 0;
@ -121,7 +121,7 @@ var
current_case: PIdentifier; current_case: PIdentifier;
case_count: CARDINAL; case_count: CARDINAL;
begin begin
ALLOCATE(result, TSIZE(AstTypeExpression)); NEW(result);
result^.kind := astTypeExpressionKindEnumeration; result^.kind := astTypeExpressionKindEnumeration;
case_count := 1; case_count := 1;
@ -153,10 +153,9 @@ proc parse_named_type(lexer: PLexer) -> PAstTypeExpression;
var var
token: LexerToken; token: LexerToken;
result: PAstTypeExpression; result: PAstTypeExpression;
written_bytes: CARDINAL;
begin begin
token := lexer_current(lexer); token := lexer_current(lexer);
ALLOCATE(result, TSIZE(AstTypeExpression)); NEW(result);
result^.kind := astTypeExpressionKindNamed; result^.kind := astTypeExpressionKindNamed;
result^.name := token.identifierKind; result^.name := token.identifierKind;
@ -172,7 +171,7 @@ var
parameter_count: CARDINAL; parameter_count: CARDINAL;
begin begin
parameter_count := 0; parameter_count := 0;
ALLOCATE(result, TSIZE(AstTypeExpression)); NEW(result);
result^.kind := astTypeExpressionKindProcedure; result^.kind := astTypeExpressionKindProcedure;
ALLOCATE(result^.parameters, 1); ALLOCATE(result^.parameters, 1);
@ -236,7 +235,7 @@ var
begin begin
token := lexer_current(lexer); token := lexer_current(lexer);
ALLOCATE(result, TSIZE(AstTypeDeclaration)); NEW(result);
result^.identifier := token.identifierKind; result^.identifier := token.identifierKind;
token := transpiler_lex(lexer); token := transpiler_lex(lexer);
@ -288,7 +287,7 @@ var
token: LexerToken; token: LexerToken;
result: PAstVariableDeclaration; result: PAstVariableDeclaration;
begin begin
ALLOCATE(result, TSIZE(AstVariableDeclaration)); NEW(result);
token := lexer_current(lexer); token := lexer_current(lexer);
result^.variable_name := token.identifierKind; result^.variable_name := token.identifierKind;
@ -342,7 +341,7 @@ var
token: LexerToken; token: LexerToken;
result: PAstConstantDeclaration; result: PAstConstantDeclaration;
begin begin
ALLOCATE(result, TSIZE(AstConstantDeclaration)); NEW(result);
token := lexer_current(lexer); token := lexer_current(lexer);
result^.constant_name := token.identifierKind; result^.constant_name := token.identifierKind;
@ -399,7 +398,7 @@ var
symbol_count: CARDINAL; symbol_count: CARDINAL;
current_symbol: PIdentifier; current_symbol: PIdentifier;
begin begin
ALLOCATE(result, TSIZE(AstImportStatement)); NEW(result);
symbol_count := 1; symbol_count := 1;
token := transpiler_lex(lexer); token := transpiler_lex(lexer);
@ -463,4 +462,132 @@ begin
return result return result
end; end;
proc parse_literal(lexer: PLexer) -> PAstLiteral;
var
literal: PAstLiteral;
token: LexerToken;
begin
literal := nil;
token := lexer_current(lexer);
if token.kind = lexerKindInteger then
NEW(literal);
literal^.kind := astLiteralKindInteger;
literal^.integer := token.integerKind;
end;
if token.kind = lexerKindCharacter then
NEW(literal);
literal^.kind := astLiteralKindString;
literal^.string := token.stringKind;
end;
if token.kind = lexerKindNull then
NEW(literal);
literal^.kind := astLiteralKindNull;
end;
if literal <> nil then
token := transpiler_lex(lexer)
end;
return literal
end;
proc parse_factor(lexer: PLexer) -> PAstExpression;
var
next_token: LexerToken;
result: PAstExpression;
literal: PAstLiteral;
begin
result := nil;
next_token := lexer_current(lexer);
literal := parse_literal(lexer);
if (result = nil) & (literal <> nil) then
NEW(result);
result^.kind := astExpressionKindLiteral;
result^.literal := literal;
end;
if (result = nil) & (next_token.kind = lexerKindMinus) then
NEW(result);
next_token := transpiler_lex(lexer);
result^.kind := astExpressionKindUnary;
result^.unary_operator := astUnaryOperatorMinus;
result^.unary_operand := parse_factor(lexer)
end;
if (result = nil) & (next_token.kind = lexerKindTilde) then
NEW(result);
next_token := transpiler_lex(lexer);
result^.kind := astExpressionKindUnary;
result^.unary_operator := astUnaryOperatorNot;
result^.unary_operand := parse_factor(lexer)
end;
if (result = nil) & (next_token.kind = lexerKindIdentifier) then
NEW(result);
result^.kind := astExpressionKindIdentifier;
result^.identifier := next_token.identifierKind;
next_token := transpiler_lex(lexer)
end;
return result
end;
proc parse_designator(lexer: PLexer) -> PAstExpression;
var
next_token: LexerToken;
inner_expression: PAstExpression;
designator: PAstExpression;
handled: BOOLEAN;
begin
designator := parse_factor(lexer);
handled := designator <> nil;
next_token := lexer_current(lexer);
while handled do
inner_expression := designator;
handled := false;
if ~handled & (next_token.kind = lexerKindHat) then
NEW(designator);
designator^.kind := astExpressionKindDereference;
designator^.reference := inner_expression;
next_token := transpiler_lex(lexer);
handled := true
end;
if ~handled & (next_token.kind = lexerKindLeftSquare) then
NEW(designator);
next_token := transpiler_lex(lexer);
designator^.kind := astExpressionKindArrayAccess;
designator^.array := inner_expression;
designator^.index := parse_designator(lexer);
next_token := transpiler_lex(lexer);
handled := true
end;
if ~handled & (next_token.kind = lexerKindDot) then
NEW(designator);
next_token := transpiler_lex(lexer);
designator^.kind := astExpressionKindFieldAccess;
designator^.aggregate := inner_expression;
designator^.field := next_token.identifierKind;
next_token := transpiler_lex(lexer);
handled := true
end
end;
return designator
end;
end. end.

View File

@ -1,6 +1,6 @@
module; module;
from FIO import WriteNBytes, WriteLine, WriteChar, WriteString; from FIO import StdErr, WriteNBytes, WriteLine, WriteChar, WriteString;
from SYSTEM import ADR, ADDRESS, TSIZE; from SYSTEM import ADR, ADDRESS, TSIZE;
from NumberIO import IntToStr; from NumberIO import IntToStr;
@ -9,12 +9,14 @@ 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 AstModule, PAstModule, AstTypeExpressionKind, from Parser import AstTypeExpressionKind, AstExpressionKind, AstLiteralKind, AstUnaryOperator,
AstModule, PAstModule, AstExpression, PAstExpression, PAstLiteral,
PAstConstantDeclaration, PPAstConstantDeclaration, PAstConstantDeclaration, PPAstConstantDeclaration,
AstTypeDeclaration, PAstTypeDeclaration, PPAstTypeDeclaration, AstTypeDeclaration, PAstTypeDeclaration, PPAstTypeDeclaration,
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_type_expression, parse_variable_part, parse_type_part, parse_constant_part, parse_import_part,
parse_designator;
(* Calls lexer_lex() but skips the comments. *) (* Calls lexer_lex() but skips the comments. *)
proc transpiler_lex(lexer: PLexer) -> LexerToken; proc transpiler_lex(lexer: PLexer) -> LexerToken;
@ -117,7 +119,7 @@ var
token: LexerToken; token: LexerToken;
result: PAstModule; result: PAstModule;
begin begin
ALLOCATE(result, TSIZE(AstModule)); NEW(result);
token := transpiler_lex(context^.lexer); token := transpiler_lex(context^.lexer);
if token.kind = lexerKindModule then if token.kind = lexerKindModule then
@ -404,12 +406,12 @@ begin
return result return result
end; end;
proc transpile_expression(context: PTranspilerContext, trailing_token: LexerKind); proc transpile_unchanged(context: PTranspilerContext, trailing_token: LexerKind);
var var
token: LexerToken; token: LexerToken;
written_bytes: CARDINAL; written_bytes: CARDINAL;
begin begin
token := transpiler_lex(context^.lexer); token := lexer_current(context^.lexer);
while (token.kind <> trailing_token) & (token.kind <> lexerKindEnd) do while (token.kind <> trailing_token) & (token.kind <> lexerKindEnd) do
written_bytes := 0; written_bytes := 0;
@ -433,7 +435,7 @@ begin
WriteString(context^.output, 'AND '); WriteString(context^.output, 'AND ');
written_bytes := 1 written_bytes := 1
end; end;
if token.kind = lexerKindNot then if token.kind = lexerKindTilde then
WriteString(context^.output, 'NOT '); WriteString(context^.output, 'NOT ');
written_bytes := 1 written_bytes := 1
end; end;
@ -445,12 +447,92 @@ begin
end end
end; end;
proc parse_expression(lexer: PLexer) -> PAstExpression;
var
next_token: LexerToken;
result: PAstExpression;
written_bytes: CARDINAL;
begin
result := parse_designator(lexer);
written_bytes := WriteNBytes(StdErr, ADDRESS(lexer^.Current - lexer^.Start), lexer^.Start);
WriteLine(StdErr);
return result
end;
proc transpile_unary_operator(context: PTranspilerContext, operator: AstUnaryOperator);
begin
if operator = astUnaryOperatorMinus then
WriteChar(context^.output, '-')
end;
if operator = astUnaryOperatorNot then
WriteChar(context^.output, '~')
end
end;
proc transpile_expression(context: PTranspilerContext, expression: PAstExpression);
var
literal: PAstLiteral;
buffer: [20]CHAR;
written_bytes: CARDINAL;
begin
if expression^.kind = astExpressionKindLiteral then
literal := expression^.literal;
if literal^.kind = astLiteralKindInteger then
IntToStr(literal^.integer, 0, buffer);
WriteString(context^.output, buffer);
end;
if literal^.kind = astLiteralKindString then
WriteString(context^.output, literal^.string)
end
end;
if expression^.kind = astExpressionKindIdentifier then
written_bytes := WriteNBytes(context^.output, ORD(expression^.identifier[1]), ADR(expression^.identifier[2]))
end;
if expression^.kind = astExpressionKindDereference then
transpile_expression(context, expression^.reference);
WriteChar(context^.output, '^')
end;
if expression^.kind = astExpressionKindArrayAccess then
transpile_expression(context, expression^.array);
WriteChar(context^.output, '[');
transpile_expression(context, expression^.index);
WriteChar(context^.output, ']')
end;
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]));
end;
if expression^.kind = astExpressionKindUnary then
transpile_unary_operator(context, expression^.unary_operator);
transpile_expression(context, expression^.unary_operand)
end
end;
proc transpile_if_statement(context: PTranspilerContext); proc transpile_if_statement(context: PTranspilerContext);
var var
token: LexerToken; token: LexerToken;
expression: PAstExpression;
lexer: Lexer;
begin begin
WriteString(context^.output, ' IF '); WriteString(context^.output, ' IF ');
transpile_expression(context, lexerKindThen);
lexer := context^.lexer^;
token := transpiler_lex(ADR(lexer));
expression := parse_expression(ADR(lexer));
if expression <> nil then
context^.lexer^ := lexer;
transpile_expression(context, expression);
WriteChar(context^.output, ' ')
end;
if expression = nil then
token := transpiler_lex(context^.lexer)
end;
transpile_unchanged(context, lexerKindThen);
WriteString(context^.output, 'THEN'); WriteString(context^.output, 'THEN');
WriteLine(context^.output); WriteLine(context^.output);
@ -464,7 +546,8 @@ var
token: LexerToken; token: LexerToken;
begin begin
WriteString(context^.output, ' WHILE '); WriteString(context^.output, ' WHILE ');
transpile_expression(context, lexerKindDo); token := transpiler_lex(context^.lexer);
transpile_unchanged(context, lexerKindDo);
WriteString(context^.output, 'DO'); WriteString(context^.output, 'DO');
WriteLine(context^.output); WriteLine(context^.output);
@ -474,9 +557,12 @@ begin
end; end;
proc transpile_assignment_statement(context: PTranspilerContext); proc transpile_assignment_statement(context: PTranspilerContext);
var
token: LexerToken;
begin begin
WriteString(context^.output, ' := '); WriteString(context^.output, ' := ');
transpile_expression(context, lexerKindSemicolon); token := transpiler_lex(context^.lexer);
transpile_unchanged(context, lexerKindSemicolon);
end; end;
proc transpile_call_statement(context: PTranspilerContext); proc transpile_call_statement(context: PTranspilerContext);
@ -541,7 +627,8 @@ var
token: LexerToken; token: LexerToken;
begin begin
WriteString(context^.output, ' RETURN '); WriteString(context^.output, ' RETURN ');
transpile_expression(context, lexerKindSemicolon) token := transpiler_lex(context^.lexer);
transpile_unchanged(context, lexerKindSemicolon)
end; end;
proc transpile_statement(context: PTranspilerContext); proc transpile_statement(context: PTranspilerContext);