Processing Expressions
These routines provide basic expression processing. Each expression is divided into simpler elements according to the operator precedence: Expression, Simple Expression, Term and Factor. Once the operation and operands are determined, the mathematical operation can be performed.
Procedure TExpression.ProcessExpression;
Var RightSimpleExpression: TExpression;
Operation: TCalcOperation;
begin
ProcessSimpleExpression;
Case Token of
Token_Equal: Operation := Calc_IsEqual;
Token_NotEqual: Operation := Calc_IsNotEqual;
Token_Greater: Operation := Calc_IsGreater;
Token_Lower: Operation := Calc_IsLower;
Token_GreaterOrEqual: Operation := Calc_IsGreaterOrEqual;
Token_LowerOrEqual: Operation := Calc_IsLowerOrEqual;
Token_IN: Operation := Calc_IN;
else begin
Exit;
end;
end;
GetNextToken;
RightSimpleExpression.ProcessSimpleExpression;
If Operation = Calc_IN then GenerateCodeForOperator_IN (Self, RightSimpleExpression)
else CalculateOperation (Operation, Self, RightSimpleExpression);
end;
Procedure TExpression.ProcessSimpleExpression;
Var RightTerm: TExpression;
Operation: TCalcOperation;
begin
ProcessTerm;
Repeat
Case Token of
Token_Plus: Operation := Calc_Add;
Token_Minus: Operation := Calc_Subtract;
Token_OR: Operation := Calc_OR;
Token_XOR: Operation := Calc_XOR;
else Exit;
end;
GetNextToken;
RightTerm.ProcessTerm;
CalculateOperation (Operation, Self, RightTerm);
until False;
end;
Procedure TExpression.ProcessTerm;
Var RightFactor: TExpression;
Operation: TCalcOperation;
begin
ProcessFactor;
Repeat
Case Token of
Token_Asterisk: Operation := Calc_Multiply;
Token_Slash: Operation := Calc_Divide;
Token_DIV: Operation := Calc_DIV;
Token_MOD: Operation := Calc_MOD;
Token_AND: Operation := Calc_AND;
Token_SHL: Operation := Calc_SHL;
Token_SHR: Operation := Calc_SHR;
else Exit;
end;
GetNextToken;
RightFactor.ProcessFactor;
CalculateOperation (Operation, Self, RightFactor);
until False;
end;
Factor is the smallest element of any Turbo Pascal expression. It can be a variable, constant, system function, special operator or another expression in parenthesis.
Procedure TExpression.ProcessFactor;
Var ProcedureIdentifierData: PProcedureIdentifierData;
begin
CheckForStringConstantWithControlCharacter;
CheckForDeclaredIdentifier;
Case Token of
Token_VariableIdentifier: LoadVariable;
Token_Constant,
Token_ConstantIdentifier: LoadConstant;
Token_ProcedureIdentifier: ProcessProcedureIdentifier;
Token_LeftParenthesis: ProcessLeftParenthesis;
Token_Minus,
Token_Plus: ProcessUnaryMinus_Plus;
Token_NOT: Process_NOT;
Token_NIL: LoadNilPointer;
Token_TypeIdentifier,
Token_STRING,
Token_FILE: ProcessValueTypecastOrMethodCall;
Token_INHERITED: Process_INHERITED;
Token_LeftBracket: ProcessSetConstant;
Token_SystemFunction,
Token_SystemFunctionOrProcedure: Process_SystemFunction;
Token_At: Process_At;
Token_Mem: Process_Mem;
Token_Port: Process_Port;
else Error (ErrorInExpression);
end;
Repeat
If TypeDefPtr^.BaseType = btFunctionProcedure then
Case PProcedureTypeDefinition (TypeDefPtr)^.ResultTypeOffset.TypeOffset = 0 of
True: begin
If Location <> elProcedure then Error (InvalidProcedureOrFunctionReference);
ProcedureIdentifierData := PProcedureIdentifierData (PChar (TypeDefPtr) - 10);
If not (pfConstructor in ProcedureIdentifierData^.Flags) then Error (InvalidProcedureOrFunctionReference);
CallProcedure;
Calculate;
GenerateInstruction_TwoBytes ($09, $D0); { OR AX, DX }
EndIntermediateCodeSubroutine;
UsedRegisters := [urSP, urDX, urAX];
SetExpressionToBooleanJump (JNE);
Exit;
end;
else begin
CallProcedure;
SetExpressionToFunctionResult;
end;
end;
until not ProcessQualifiers;
end;
This procedure sets expression data for functions according to the result type. For String result it first reserves space in the stack frame.
Procedure TExpression.SetExpressionToFunctionResult;
begin
TypeDefPtr := PointerFromOffsets (PProcedureTypeDefinition (TypeDefPtr)^.ResultTypeOffset);
UsedRegisters := [urBX, urDX, urCX, urAX];
Case TypeDefPtr^.BaseType of
btPointer,
btReal,
btInteger..btEnumeration: begin
Location := elRegister;
DataType := TypeDefPtr^.DataType;
LocationData.Register := rDX_AX;
end;
btExtended: begin
Location := elStackFrame;
DataType := [fpExtended];
end;
else begin
CreateSpaceInStackFrameAndPushAddressToIt ($0100);
Calculate;
EndIntermediateCodeSubroutine;
end;
end;
end;
Different order of expression processing can be achieved with parentheses. Simple recursive call solves the problem.
Procedure TExpression.ProcessLeftParenthesis;
begin
ExpectTokenAndGetNext (Token_LeftParenthesis);
ProcessExpression;
ExpectTokenAndGetNext (Token_RightParenthesis);
end;
Nil
pointer is a simple constant that generates no code.
Procedure LoadNilPointer;
begin
GetNextToken;
Location := elConstant;
IntermediateCodeOffset := 0;
DataType := [it32Bit, it16Bit, itSigned];
UsedRegisters := [];
Value.Pointer := nil;
TypeDefPtr := Ptr (SystemUnitSegment, Pointer_TypeOffset);
end;
For Procedures
and Functions
the location is set and for methods Self address is loaded. The procedure or function will be called later at the factor processing procedure.
Procedure TExpression.ProcessProcedureIdentifier;
begin
IntermediateCodeOffset := 0;
UsedRegisters := [];
If pfMethod in PProcedureIdentifierData (CurrentIdentifierDataPtr)^.Flags then LoadSelfAddress;
TypeDefPtr := @PProcedureIdentifierData (CurrentIdentifierDataPtr)^.ProcedureTypeDefinition;
Location := elProcedure;
DataType := [];
Value.W16 := Ofs (CurrentRecordTypeDef^);
Value.W18 := Seg (CurrentRecordTypeDef^);
GetNextToken;
end;
This procedure processes call to inherited method.
Procedure TExpression.Process_INHERITED;
Var MethodIdentifier: PIdentifier;
MethodIdentifierData: PProcedureIdentifierData;
UnitTypeOffsets: PUnitOffsets;
TypeDef: PTypeDefinition;
begin
If not FindCurrentMethod (MethodIdentifier, MethodIdentifierData) then Error (NoInheritedMethodsAreAccessibleHere);
UnitTypeOffsets := Ptr (Seg (MethodIdentifierData^), MethodIdentifierData^.OuterBlockProcedureIdentifier + 12);
If UnitTypeOffsets^.UnitIdentifierData = 0 then Error (NoInheritedMethodsAreAccessibleHere);
TypeDef := PointerFromOffsets (UnitTypeOffsets^);
GetNextToken;
IntermediateCodeOffset := 0;
UsedRegisters := [];
FindAndProcessMethodCall (TypeDef, [pfMethod], [mcStatic], MethodIdentifierExpected);
end;
This procedure processes system function.
Procedure TExpression.Process_SystemFunction;
Var Func: Word;
begin
Func := (PSystemProcedureIdentifierData (CurrentIdentifierDataPtr)^.ProcData and $3FFF) shr 2;
GetNextToken;
ProcessFunction (Func, Self);
end;
This procedure processes the @
character and creates pointer to variable reference.
Procedure TExpression.Process_At;
begin
GetNextToken;
ExpectVariableReference;
CreatePointerToVariableReference;
end;