Press enter to see results or esc to cancel.

Searching For Identifiers

This function checks for identifier that should be already declared. If Token is Token_Identifier it checks if identifier is declared under current scope. If not the error is reported. Token variable is set to the identifier’s actual token and current identifier data variables are set to the current identifier’s data. It first calls FindCurrentIdentifier to find the identifier. Then it checks if this is actually a unit name. If it is, the function expects period and identifier in this unit.

Procedure CheckForDeclaredIdentifier;
Var IdentifierToken: TToken;
    IdentifierData: Pointer;
    UnitIdData: PUnitIdentifierData absolute IdentifierData;
    IdentifierOffset: Word;
begin
  If Token <> Token_Identifier then Exit;
  If not FindCurrentIdentifier (IdentifierToken, IdentifierOffset, IdentifierData) then Error (UnknownIdentifier);
  If IdentifierToken = Token_UnitIdentifier then
    begin
      GetNextToken;
      ExpectTokenAndGetNext (Token_Period);
      ExpectIdentifier;
      If not FindIdentifierInUnit (Ptr (UnitIdData^.UnitSegment, 0), IdentifierToken, IdentifierOffset, IdentifierData)
        then Error (UnknownIdentifier);
    end;
  Token := IdentifierToken;
  CurrentIdentifierOffset  := IdentifierOffset;
  CurrentIdentifierDataPtr := IdentifierData;
end;

This function searches for identifiers under current scope according to Pascal programming language rules:

  • First records and objects are checked if the identifier is declared as a field or method inside With statement (they are stored in a linked list).
  • Next, procedures and functions are checked if the identifier is declared inside them (as a local variable).
  • Finally, units are searched in reverse order of declaration.
Function FindCurrentIdentifier (Var TempToken: TToken; Var IdentifierOffset: Word; Var IdentifierData: Pointer): Boolean;
Var UnitHeader: PUnitHeader;
    UnitHeaderRec: PtrRec absolute UnitHeader;
    UnitIdentifier: PIdentifier;
    UnitIdentifierRec: PtrRec absolute UnitIdentifier;
    UnitIdData: PUnitIdentifierData;
    ProcedureIdentifier: PIdentifier;
    ProcedureIdentifierOfs: Word absolute ProcedureIdentifier;
    ProcedureIdentifierData: PProcedureIdentifierData absolute ProcedureIdentifier;
    WithRecord: PWithRecord;
    WithRecordOfs: Word absolute WithRecord;
begin
  WithRecord := Ptr (SSeg, LastWithRecord);
  CurrentWithRecord := LastWithRecord;
  FindCurrentIdentifier := True;
  While WithRecordOfs <> 0 do
    begin
      If IsCurrentIdentifierDeclaredAsMemberInRecordOrObject (WithRecord^.RecordTypeDefinition,
                                                              PVariableIdentifierData (IdentifierData),
                                                              TempToken, IdentifierOffset) then Exit;
      WithRecordOfs := WithRecord^.PreviousWithRecord;
      CurrentWithRecord := WithRecordOfs;
    end;
  ProcedureIdentifier := Ptr (MainSymbolTable.Segment, CurrentProcedureIdentifier);
  While ProcedureIdentifierOfs <> 0 do
    begin
      Inc (ProcedureIdentifierOfs, ProcedureIdentifier^.Name.Len + 4);
      If IsCurrentIdentifierDeclaredInProcedure (ProcedureIdentifierData, IdentifierData,
                                                 TempToken, IdentifierOffset) then Exit;
      If pfMethod in ProcedureIdentifierData^.Flags then Break;
      ProcedureIdentifierOfs := ProcedureIdentifierData^.OuterBlockProcedureIdentifier;
    end;
  UnitHeader := Ptr (MainSymbolTable.Segment, 0);
  UnitIdentifier := Ptr (MainSymbolTable.Segment, UnitHeader^.UnitNameIdentifierOffset);
  Repeat
    UnitIdData := PUnitIdentifierData (PChar (UnitIdentifier) + UnitIdentifier^.Name.Len + 4);
    If FindIdentifierInUnit (Ptr (UnitIdData^.UnitSegment, 0), TempToken, IdentifierOffset, IdentifierData) then Exit;
    UnitIdentifierRec.Ofs := UnitIdData^.CurrentUsedUnitIdentifier;
  until UnitIdentifierRec.Ofs = 0;
  FindCurrentIdentifier := False;
end;

This function searches for identifiers in records and objects.

Function IsCurrentIdentifierDeclaredAsMemberInRecordOrObject (RecordTypeDefinition: PRecordTypeDefinition; Var IdentifierDataPtr: PVariableIdentifierData; Var TokenFound: TToken; Var IdentifierOfs: Word): Boolean;
Var ObjectTypeDefinition: PObjectTypeDefinition absolute RecordTypeDefinition;
begin
  CurrentRecordTypeDef := RecordTypeDefinition;
  IsCurrentIdentifierDeclaredAsMemberInRecordOrObject := False;
  Repeat
    If IsIdentifierInSymbolTable (Ptr (Seg (RecordTypeDefinition^), RecordTypeDefinition^.FieldsListOffset), TokenFound,
                                                                              Pointer (IdentifierDataPtr), IdentifierOfs) then
      begin
        IsCurrentIdentifierDeclaredAsMemberInRecordOrObject := True;
        Exit;
      end;
    If ObjectTypeDefinition^.BaseType <> btObject then Exit;
    If ObjectTypeDefinition^.AncestorTypeOffset.UnitIdentifierData = 0 then Exit;
    ObjectTypeDefinition := PointerFromOffsets (ObjectTypeDefinition^.AncestorTypeOffset);
  until False;
end;

This function searches for identifiers in functions and procedures.

Function IsCurrentIdentifierDeclaredInProcedure (ProcedureIdentifierData: PProcedureIdentifierData;
                                                 Var IdentifierDataPtr: Pointer;
                                                 Var TokenFound: TToken; Var IdentifierOfs: Word): Boolean;
begin
  IsCurrentIdentifierDeclaredInProcedure := True;
  If IsIdentifierInSymbolTable (Ptr (Seg (ProcedureIdentifierData^),
                                ProcedureIdentifierData^.LocalIdentifiersList),
                                TokenFound,
                                IdentifierDataPtr,
                                IdentifierOfs) then Exit;
  IsCurrentIdentifierDeclaredInProcedure := False;
  If not (pfMethod in ProcedureIdentifierData^.Flags) then Exit;
  IsCurrentIdentifierDeclaredInProcedure :=
    IsCurrentIdentifierDeclaredAsMemberInRecordOrObject (Ptr (Seg (ProcedureIdentifierData^),
                                                                ProcedureIdentifierData^.OuterBlockProcedureIdentifier),
                                                         PVariableIdentifierData (IdentifierDataPtr),
                                                         TokenFound,
                                                         IdentifierOfs);
end;

This function searches for identifiers in units.

Function FindIdentifierInUnit (UnitPointer: PUnitHeader; Var IdentifierToken: TToken; Var IdentifierOffset: Word; Var IdentifierDataPtr: Pointer): Boolean;
Var IdentifierList: Word;
begin
  IdentifierList := UnitPointer^.PublicIdentifiersListOffset;
  If Seg (UnitPointer^) = MainSymbolTable.Segment then IdentifierList := UnitPointer^.PrivateIdentifiersListOffset;
  FindIdentifierInUnit := IsIdentifierInSymbolTable (Ptr (Seg (UnitPointer^), IdentifierList),
                                              IdentifierToken, IdentifierDataPtr, IdentifierOffset);
end;