Press enter to see results or esc to cancel.

Loading Variables

This procedure loads variable data from symbol table and sets all expression fields accordingly. Variables declared outside procedures and functions are called global variables, and they reside in the data segment. Variables declared within procedures and functions are called local variables, and they reside in the stack segment. Absolute variables are loaded from the target variable which is in memory and for record or object fields base address is loaded.

Procedure TExpression.LoadVariable;
Var IdentifierDataPtr: PVariableIdentifierData;
begin
  GetNextToken;
  IdentifierDataPtr := CurrentVariableIdentifierData;
  TypeDefPtr := PointerFromOffsets (IdentifierDataPtr^.UnitTypeOffsets);
  DataType := TypeDefPtr^.DataType;
  Location := elMemory;
  UsedRegisters := [];
  IdentifierDataPtr := CurrentVariableIdentifierData;
  While vfAbsoluteVar in IdentifierDataPtr^.Flags do
    IdentifierDataPtr := PVariableIdentifierData (PointerFromOffsets (IdentifierDataPtr^.AbsoluteVarDataOffsets));
  If Field in IdentifierDataPtr^.Flags then
    begin
      LoadSelfAddress;
      Inc (Value.VarOffset, IdentifierDataPtr^.W1.Ofs);
      Exit;
    end;
  Value.VarOffset := IdentifierDataPtr^.W1.Ofs;
  If IdentifierDataPtr^.Flags * VariableTypeMask = GlobalVariable then
    begin
      LocationData.Flags := [segDS];
      Value.VarSegment := IdentifierDataPtr^.W1.Seg;
      Value.W14 := Seg (IdentifierDataPtr^);
    end else If IdentifierDataPtr^.Flags * VariableTypeMask = TypedConstant then
               begin
                 LocationData.Flags := [efTypedConstant, segDS];
                 Value.VarSegment := IdentifierDataPtr^.W1.Seg;
                 Value.W14 := Seg (IdentifierDataPtr^);
               end else If IdentifierDataPtr^.Flags * VariableTypeMask = LocalStackVariable then
                          begin
                            Value.IdentifierDataPointer := IdentifierDataPtr;
                            LoadAddressOfLocalVariable (IdentifierDataPtr^.Flags, IdentifierDataPtr^.W1.Seg);
                          end else begin
                                     Value.VarSegment := IdentifierDataPtr^.W1.Seg;
                                     LocationData.Flags := [];
                                   end;
  If vfConst in IdentifierDataPtr^.Flags then Include (LocationData.Flags, efReadOnly);
  EndIntermediateCodeSubroutine;
end;

This procedure generates code to load the address of local variable (on stack).

Procedure TExpression.LoadAddressOfLocalVariable (Flags: TVarFlagsSet; ProcIdentifier: Word);
begin
  If Flags * [vfOpenParameter, vfVar] <> [] then
    begin
      LocationData.Flags := [ofsDI, segES];
      Load_ES_DI (ProcIdentifier, Value.Offset, 0);
      Value.Offset := 0;
    end else begin
               LocationData.Flags := [ofsBP, segSS];
               If ProcIdentifier <> CurrentProcedureIdentifier then
                 begin
                   LocationData.Flags := [ofsDI, segSS];
                   Load_ES_DI (ProcIdentifier, 0, 0);
                 end;
             end;
end;

This procedure loads the address of Record or Object field variable.

Procedure TExpression.LoadSelfAddress;
Var MethodIdentifier: PIdentifier;
    MethodIdentifierData: PProcedureIdentifierData;
    WithRecord: PWithRecord;
begin
  Case CurrentWithRecord = 0 of
    True: begin
            FindCurrentMethod (MethodIdentifier, MethodIdentifierData);
            Load_ES_DI (Ofs (MethodIdentifier^), 6, 0);
            LocationData.Flags := [ofsDI, segES];
            Value.Word := 0;
          end;
    else begin
           WithRecord := Ptr (SSeg, CurrentWithRecord);
           Location := elMemory;
           LocationData.Flags := WithRecord^.ExpressionFlags;
           Case WithRecord^.RecordType of
             1: begin
                  Value.Offset      := WithRecord^.AddressOffset;
                  Value.BlockRecord := WithRecord^.BlockRecord;
                  Value.Segment     := WithRecord^.AddressSegment;
                end;
             2: begin      { Save Address }
                  Load_ES_DI (CurrentProcedureIdentifier, WithRecord^.AddressOffset, WithRecord^.BlockRecord);
                  Value.Word := 0;
                end;
           end;
         end;
  end;
  EndIntermediateCodeSubroutine;
end;

This procedure finds the current method. It jumps out of nested procedures until it finds a method. If method is found it returns True and method’s identifier and data address, otherwise it returns False.

Function FindCurrentMethod (Var MethodIdentifier: PIdentifier; Var MethodIdentifierData: PProcedureIdentifierData): Boolean;
Var MethodIdentifierOfs: Word absolute MethodIdentifier;
    MethodIdentifierDataOfs: Word absolute MethodIdentifierData;
begin
  MethodIdentifier := Ptr (MainSymbolTable.Segment, CurrentProcedureIdentifier);
  MethodIdentifierData := Ptr (MainSymbolTable.Segment, CurrentProcedureIdentifier);
  FindCurrentMethod := True;
  While MethodIdentifierOfs <> 0 do
    begin
      MethodIdentifierDataOfs := MethodIdentifierOfs + MethodIdentifier^.Name.Len + 4;
      If pfMethod in MethodIdentifierData^.Flags then Exit;
      MethodIdentifierOfs := MethodIdentifierData^.OuterBlockProcedureIdentifier;
    end;
  FindCurrentMethod := False;
end;