Press enter to see results or esc to cancel.

Storing Identifiers Into Symbol Table

Storing identifiers into symbol table is simple because of the way how Turbo Pascal organizes symbol tables.

StoreCurrentIdentifierToSymbolTable increases main symbol table, adds the identifier at the end of appropriate list and clears identifier data.

Function StoreCurrentIdentifierToSymbolTable (IdentifierList: PIdentifierList; IdentifierDataSize: Word;
                                Var NewIdentifier: PIdentifier): Pointer;
Var DataStart: PChar;
    LastIdentifier: PIdentifier;
    ListEntry: Byte;

begin
  NewIdentifier := IncreaseSymbolTable (stMain, 3 + Length (CurrentIdentifier) + 1 + IdentifierDataSize);
  ListEntry := (CurrentIdentifierHash and IdentifierList^.Mask) shr 1;
  LastIdentifier := Ptr (Seg (IdentifierList^), IdentifierList^.Offset [ListEntry]);
  IdentifierList^.Offset [ListEntry] := Ofs (NewIdentifier^);
  NewIdentifier^.Next := Ofs (LastIdentifier^);
  NewIdentifier^.Token := Token_EndOfLine;
  NewIdentifier^.Name.Str := CurrentIdentifier;
  DataStart := PChar (NewIdentifier) + 3 + 1 + Length (CurrentIdentifier);
  StoreCurrentIdentifierToSymbolTable := DataStart;
  FillChar (DataStart^, IdentifierDataSize, 0);
end;

StoreNewIdentifierToSymbolTable first checks if the identifier is already defined in the current scope. If it is found you get the famous Duplicate Identifier error.

Function StoreNewIdentifierToSymbolTable (NewIdentifierDataSize: Word; Var NewIdentifier: PIdentifier): Pointer;
Var IdentifierDataPtr: Pointer;
    IdentifierOffset: Word;
    IdToken: TToken;
begin
  If CurrentIdentifierDeclaredInCurrentScope (IdentifierOffset, IdentifierDataPtr, IdToken) then
    CurrentIdentifierError (DuplicateIdentifier);
  StoreNewIdentifierToSymbolTable := StoreCurrentIdentifierToSymbolTable (CurrentScopeIdentifierTableAddress, NewIdentifierDataSize, NewIdentifier);
end;

This function finds the symbol table according to the current scope.

Function CurrentScopeIdentifierTableAddress: PIdentifierList;
Var UnitHeader: PUnitHeader;
    ListPtr: PtrRec absolute UnitHeader;
begin
  UnitHeader := Ptr (MainSymbolTable.Segment, 0);
  If CurrentRecordOrObjectTypeDefinitionOffset <> 0 then
    ListPtr.Ofs := PRecordTypeDefinition (Ptr (MainSymbolTable.Segment,
                                               CurrentRecordOrObjectTypeDefinitionOffset))^.FieldsListOffset else
      If ProcedureIdentifierDataOffset <> 0 then
        ListPtr.Ofs := PProcedureIdentifierData (Ptr (MainSymbolTable.Segment,
                                                      ProcedureIdentifierDataOffset))^.LocalIdentifiersList else
          ListPtr.Ofs := UnitHeader^.PrivateIdentifiersListOffset;
  CurrentScopeIdentifierTableAddress := ListPtr.Ptr;
end;

StoreCommaSeparatedIdentifiers simply stores one or more identifiers separated with comma. This procedure is used for storing declared variables and fields in records and objects.

Procedure StoreCommaSeparatedIdentifiers;
Var IdData: Pointer;
begin
  FirstDeclaredVariableIdentifierOffset := SymbolTable [stMain].UsedSize;
  NumberOfDeclaredVariableIdentifiers := 0;
  Repeat
    ExpectAndStoreIdentifier (SizeOf (TVariableIdentifierData), IdData);
    Inc (NumberOfDeclaredVariableIdentifiers);
  until not CheckAndGetNextToken (Token_Comma);
end;

Procedure ExpectIdentifier;
begin
  If Token <> Token_Identifier then Error (IdentifierExpected);
end;

ExpectAndStoreIdentifier checks if the current token is identifier and if it is, it is stored in the main symbol table.

Function ExpectAndStoreIdentifier (DataSize: Word; Var IdentifierData: Pointer): PIdentifier;
Var NewIdentifier: PIdentifier;
begin
  ExpectIdentifier;
  IdentifierData := StoreNewIdentifierToSymbolTable (DataSize, NewIdentifier);
  GetNextToken;
  ExpectAndStoreIdentifier := NewIdentifier;
end;