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;