Press enter to see results or esc to cancel.

Processing Program Block

This is where the main compilation routines are called. This procedure resets many compiler flags and variables, initializes intermediate code, saves source line number, resets compiler switches, and processes statements between begin and end tokes (or asm and end for assembler procedures). After the compilation, module entry and exit code is added. Of course, for interrupts different code is generated. Finally, the target code is generated. Because of the possibility to use subroutines in intermediate code, there is no need to generate linear code as it needs to be at the end. Turbo Compiler generates code by cleverly joining smaller pieces into one big code. Code generator takes care to generate code in the right order.

Function ProcessProgramBlock: Word;
Var SavedMainSymbolTableUsedSize: Word;
    SavedModuleCompilerSwitches: TCompilerSwitchesSet;
    BlockEntryCode, BlockExitCode, ProgramBlockStartLineNumber: Word;
    ProgramBlockCode: TStatement;
    ProgramBlockEndLineNumber, ResultUnitIdData: Word;
    ProcedureIdentifierData: PProcedureIdentifierData;
    ProcedureIdentifierDataRec: PtrRec absolute ProcedureIdentifierData;
    ResultTypeDef: PTypeDefinition;
    ResultTypeDefRec: PtrRec absolute ResultTypeDef;

begin
  SavedMainSymbolTableUsedSize := SymbolTable [stMain].UsedSize;
  ProgramBlockCompilation := True;
  LastIntermediateCodeSubroutine := 2;
  IncreaseSymbolTable (stIntermediateCode, 2);
  StatementMaxStackFrameOffset := ProgramBlockMaxStackFrameOffset;
  NumberOfLocalParameters := 0;
  LastJumpToProgramBlockExit := 0;
  LastJumpToFail := 0;
  Last_GOTO_Record := 0;
  LastJumpOutOfBlock := $FFFF;
  LastJumpToNextBlockIteration := $FFFF;
  With CurrentSourceFile^ do
    begin
      FirstProgramBlocktSourceLineNumber := CurrentLineNumber;
      LastProgramBlockSourceLineNumber := CurrentLineNumber;
    end;
  ProgramBlockStartLineNumber := GetCurrentProgramBlockSourceLineNumber;
  SavedModuleCompilerSwitches := ModuleCompilerSwitches;
  ProcedureIdentifierData := Ptr (SymbolTable [stMain].Segment, ProcedureIdentifierDataOffset);
  If (ProcedureIdentifierDataOffset <> 0) and (pfAssembler in ProcedureIdentifierData^.Flags) then
    ProgramBlockCode.Process_ASM_END_Block else ProgramBlockCode.ProcessStatementsBetweenTokens (Token_BEGIN, Token_END);
  StatementCompilerSwitches := SavedModuleCompilerSwitches;
  ProgramBlockEndLineNumber := GetCurrentProgramBlockSourceLineNumber;
  PlaceLabelRecordsTo_GOTO_Records;
  ProgramBlockMaxStackFrameOffset := ProgramBlockMaxStackFrameOffset and $FFFE;
  If ProcedureIdentifierDataOffset = 0 then
    begin
      BlockEntryCode := GenerateModuleEntryCode;
      BlockExitCode := GenerateModuleExitCode;
    end else
      begin
        ProcedureIdentifierData := Ptr (SymbolTable [stMain].Segment, ProcedureIdentifierDataOffset);
        If pfInterrupt in ProcedureIdentifierData^.Flags then
          begin
            Exclude (StatementCompilerSwitches, StackChecking);
            BlockEntryCode := GenerateInterruptEntryCode;
            BlockExitCode := GenerateInterruptExitCode;
          end else
            begin
              If (pfAssembler in ProcedureIdentifierData^.Flags) and
                 (PushedParametersSize or ProgramBlockMaxStackFrameOffset = 0) then
                begin
                  ResultUnitIdData := ProcedureIdentifierData^.ProcedureTypeDefinition.ResultTypeOffset.UnitIdentifierData;
                  If ResultUnitIdData <> 0 then
                    begin
                      ResultTypeDefRec.Seg :=
                        PUnitIdentifierData (Ptr (Seg (ProcedureIdentifierData^), ResultUnitIdData))^.UnitSegment;
                      ResultTypeDefRec.Ofs := ProcedureIdentifierData^.ProcedureTypeDefinition.ResultTypeOffset.TypeOffset;
                      If ResultTypeDef^.BaseType = btString then Include (ProcedureIdentifierData^.Flags, pfStackFrame);
                    end;
                end else Include (ProcedureIdentifierData^.Flags, pfStackFrame);
              BlockEntryCode := GenerateProcedureEntryCode;
              BlockExitCode := GenerateProcedureExitCode;
            end;
      end;
  MarkSourceLineNumber (ProgramBlockStartLineNumber);
  StoreCode_icGoSub (BlockEntryCode);
  StoreCode_icGoSub (ProgramBlockCode.StatementCode);
  If LastJumpToFail <> 0 then
    begin
      GenerateCodeForNearJump (LastJumpToProgramBlockExit, JMP_ShortDirect);
      GenerateLabelAndSetJumpsToIt (LastJumpToFail);
      ProcedureIdentifierData := Ptr (SymbolTable [stMain].Segment, ProcedureIdentifierDataOffset);
      ProcedureIdentifierDataRec.Ofs := ProcedureIdentifierData^.OuterBlockProcedureIdentifier;
      GenerateInstruction_MOV_16BitReg_Immediate (rDI,
        ProcedureIdentifierData^.ProcedureTypeDefinition.ResultTypeOffset.UnitIdentifierData);
      GenerateInstruction_CALL_FAR (SysProc_Destruct);
    end;
  GenerateLabelAndSetJumpsToIt (LastJumpToProgramBlockExit);
  MarkSourceLineNumber (ProgramBlockEndLineNumber);
  StoreCode_icGoSub (BlockExitCode);
  ProcessProgramBlock := SymbolTable [stCode].UsedSize - LastProgramBlockCodeSize;
  GenerateCode;
  SymbolTable [stIntermediateCode].UsedSize := 0;
  LastIntermediateCodeSubroutine := 0;
  ProgramBlockCompilation := False;
  SymbolTable [stMain].UsedSize := SavedMainSymbolTableUsedSize;
end;

This procedure takes care for the main program block.

Procedure ProcessMainProgramBlock;
Var MainProgramBlockSizeOfConstants: Word;
begin
  ProgramBlockMaxStackFrameOffset := 0;
  ProcedureStartLineNumber := 1;
  MainProgramBlockSizeOfConstants := ProcessProgramBlock;

{ SymbolTable [stProcedures].Segment might change in ProcessProgramBlock }

  With PProceduresBlockRecord (Ptr (SymbolTable [stProcedures].Segment, 0))^ do
    begin
      SizeOfConstants              := MainProgramBlockSizeOfConstants;
      ProgramCodeBlockRecordOffset := SymbolTable [stCodeBlocks].NextRecordOffset;
    end;
  CreateProgramCodeBlockRecord;
  CreateTypedConstantsBlockRecord;
end;