Press enter to see results or esc to cancel.

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;