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;