{$optimize 7}
{---------------------------------------------------------------}
{								}
{  Header							}
{								}
{  Handles saving and reading precompiled headers.		}
{								}
{---------------------------------------------------------------}

unit Header;

interface

{$LibPrefix '0/obj/'}

uses CCommon, MM, Scanner, Symbol, CGI;

{$segment 'HEADER'}

const
   symFileVersion = 45;                 {version number of .sym file format}

var
   inhibitHeader: boolean;		{should .sym includes be blocked?}


procedure EndInclude (chPtr: ptr);

{ Saves symbols created by the include file			}
{								}
{ Parameters:							}
{    chPtr - chPtr when the file returned			}
{								}
{ Notes:							}
{    1. Call this subroutine right after processing an		}
{       include file.						}
{    2. Declared externally in Symbol.pas			}


procedure FlagPragmas (pragma: pragmas);

{ record the effects of a pragma				}
{								}
{ parameters:							}
{    pragma - pragma to record					}
{								}
{ Notes:							}
{    1. Defined as extern in Scanner.pas			}
{    2. For the purposes of this unit, the segment statement is	}
{	treated as a pragma.					}


procedure InitHeader (var fName: gsosOutString);

{ look for a header file, reading it if it exists		}
{								}
{ parameters:							}
{    fName - source file name (var for efficiency)		}


procedure TermHeader;

{ Stop processing the header file				}
{								}
{ Note: This is called when the first code-generating		}
{    subroutine is found, and again when the compile ends.  It	}
{    closes any open symbol file, and should take no action if	}
{    called twice.						}


procedure StartInclude (name: gsosOutStringPtr);

{ Marks the start of an include file				}
{								}
{ Notes:							}
{    1. Call this subroutine right after opening an include	}
{       file.							}
{    2. Defined externally in Scanner.pas			}

{---------------------------------------------------------------}

implementation

const
   symFiletype = $5E;			{symbol file type}
   symAuxtype = $008008;

					{file buffer}
                                        {-----------}
   bufSize = 1024;			{size of output buffer}

type                   
   closeOSDCB = record
      pcount: integer;
      refNum: integer;
      end;

   createOSDCB = record
      pcount: integer;
      pathName: gsosInStringPtr;
      access: integer;
      fileType: integer;
      auxType: longint;
      storageType: integer;
      dataEOF: longint;
      resourceEOF: longint;
      end;

   destroyOSDCB = record
      pcount: integer;
      pathName: gsosInStringPtr;
      end;

   getFileInfoOSDCB = record
      pcount: integer;
      pathName: gsosInStringPtr;
      access: integer;
      fileType: integer;
      auxType: longint;
      storageType: integer;
      createDateTime: timeField;
      modDateTime: timeField;
      optionList: optionListPtr;
      dataEOF: longint;
      blocksUsed: longint;
      resourceEOF: longint;
      resourceBlocks: longint;
      end;

   getMarkOSDCB = record
      pcount: integer;
      refNum: integer;
      displacement: longint;
      end;

   openOSDCB = record
      pcount: integer;
      refNum: integer;
      pathName: gsosInStringPtr;
      requestAccess: integer;
      resourceNumber: integer;
      access: integer;
      fileType: integer;
      auxType: longint;
      storageType: integer;
      createDateTime: timeField;
      modDateTime: timeField;
      optionList: optionListPtr;
      dataEOF: longint;
      blocksUsed: longint;
      resourceEOF: longint;
      resourceBlocks: longint;
      end;

   readWriteOSDCB = record
      pcount: integer;
      refNum: integer;
      dataBuffer: ptr;
      requestCount: longint;
      transferCount: longint;
      cachePriority: integer;
      end;

   setMarkOSDCB = record
      pcount: integer;
      refNum: integer;
      base: integer;
      displacement: longint;
      end;

					{file buffer}
                                        {-----------}
   bufferType = array[0..bufSize] of byte; {output buffer}

var
   codeStarted: boolean;		{has code generation started?}
   includeLevel: 0..maxint;		{nested include level}
   includeMark: boolean;		{has the mark field been written?}
   savePragmas: set of pragmas;		{pragmas to record}
   saveSource: boolean;			{save source streams?}
   symChPtr: ptr;			{chPtr at start of current source sequence}
   symEndPtr: ptr;			{points to first byte past end of file}
   symMark: longint;			{start of current block}
   symName: gsosOutString;		{symbol file name}
   symStartPtr: ptr;			{first byte in the symbol file}
   symPtr: ptr;				{next byte in the symbol file}
   symRefnum: integer;			{symName reference number}
   tokenMark: longint;			{start of last token list}

					{file buffer}
                                        {-----------}
   buffer: ^bufferType;			{output buffer}
   bufPtr: ^byte;			{next available byte}
   bufLen: 0..bufSize;			{bytes left in buffer}

{---------------------------------------------------------------}

procedure BlockMove (sourcPtr, destPtr: ptr; count: longint); tool ($02, $2B);

procedure CloseGS (var parms: closeOSDCB); prodos ($2014);

procedure CreateGS (var parms: createOSDCB); prodos ($2001);

procedure DestroyGS (var parms: destroyOSDCB); prodos ($2002);

procedure GetFileInfoGS (var parms: getFileInfoOSDCB); prodos ($2006);

procedure GetMarkGS (var parms: getMarkOSDCB); prodos ($2017);

procedure OpenGS (var parms: openOSDCB); prodos ($2010);

procedure SetEOFGS (var parms: setMarkOSDCB); prodos ($2018);

procedure SetMarkGS (var parms: setMarkOSDCB); prodos ($2016);

procedure WriteGS (var parms: readWriteOSDCB); prodos ($2013);

{---------------------------------------------------------------}

procedure DestroySymbolFile;

{ Delete any existing symbol file				}

var
   dsRec: destroyOSDCB;			{DestroyGS record}
   giRec: getFileInfoOSDCB;		{GetFileInfoGS record}

begin {DestroySymbolFile}
giRec.pCount := 4;
giRec.pathname := @symName.theString;
GetFileInfoGS(giRec);
if (giRec.filetype = symFiletype) and (giRec.auxtype = symAuxtype) then begin
   dsRec.pCount := 1;			
   dsRec.pathname := @symName.theString;
   DestroyGS(dsRec);
   end; {if}
end; {DestroySymbolFile}


procedure Purge;

{ Purge the output buffer					}

var
   clRec: closeOSDCB;			{CloseGS record}
   wrRec: readWriteOSDCB;		{WriteGS record}

begin {Purge}
wrRec.pcount := 4;
wrRec.refnum := symRefnum;
wrRec.dataBuffer := pointer(buffer);
wrRec.requestCount := (bufSize - bufLen);
WriteGS(wrRec);
if ToolError <> 0 then begin
   clRec.pCount := 1;
   clRec.refnum := symRefnum;
   CloseGS(clRec);
   DestroySymbolFile;
   saveSource := false;
   end; {if}
bufLen := bufSize;
bufPtr := pointer(buffer);
end; {Purge}


procedure CloseSymbols;

{ Close the symbol file						}

var
   clRec: closeOSDCB;			{CloseGS record}

begin {CloseSymbols}
Purge;
clRec.pCount := 1;
clRec.refnum := symRefnum;
CloseGS(clRec);
if numErrors <> 0 then
   DestroySymbolFile;
end; {CloseSymbols}


function ReadExtended: extended;

{ Read an extended precision real from the symbol file		}
{								}
{ Returns: value read						}

type
   extendedptr = ^extended;

begin {ReadExtended}
ReadExtended := extendedptr(symPtr)^;
symPtr := pointer(ord4(symPtr)+10);
end; {ReadExtended}


function ReadLong: longint;

{ Read a long word from the symbol file				}
{								}
{ Returns: long word read					}

type
   longptr = ^longint;

begin {ReadLong}
ReadLong := longptr(symPtr)^;
symPtr := pointer(ord4(symPtr)+4);
end; {ReadLong}


function ReadLongString: longStringPtr;

{ Read a long string from the symbol file			}
{								}
{ Returns: string read						}

var
   len: 0..maxint;			{string buffer length}
   sp1, sp2: longStringPtr;		{work pointers}

begin {ReadLongString}
sp1 := longStringPtr(symPtr);
len := sp1^.length + 2;
symPtr := pointer(ord4(symPtr) + len);
sp2 := pointer(GMalloc(len));
BlockMove(sp1, sp2, len);
ReadLongString := sp2;
end; {ReadLongString}


function ReadString: stringPtr;

{ Read a string from the symbol file				}
{								}
{ Returns: string read						}

var
   len: 0..255;				{string buffer length}
   sp1, sp2: stringPtr;			{work pointers}

begin {ReadString}
sp1 := stringptr(symPtr);
len := length(sp1^) + 1;
symPtr := pointer(ord4(symPtr) + len);
sp2 := pointer(GMalloc(len));
BlockMove(sp1, sp2, len);
ReadString := sp2;
end; {ReadString}


function ReadByte: integer;

{ Read a byte from the symbol file				}
{								}
{ Returns: byte read						}

type
   intptr = ^integer;

begin {ReadByte}
ReadByte := (intptr(symPtr)^) & $00FF;
symPtr := pointer(ord4(symPtr)+1);
end; {ReadByte}


function ReadWord: integer;

{ Read a word from the symbol file				}
{								}
{ Returns: word read						}

type
   intptr = ^integer;

begin {ReadWord}
ReadWord := intptr(symPtr)^;
symPtr := pointer(ord4(symPtr)+2);
end; {ReadWord}


procedure ReadChars (var p1, p2: ptr);

{ Read a character stream from the file				}
{								}
{ parameters:							}
{    p1 - (output) pointer to first char in stream		}
{    p2 - (output) points one past last char in stream		}

var
   len: integer;			{length of the stream}

begin {ReadChars}
len := ReadWord;
p1 := pointer(GMalloc(len));
p2 := pointer(ord4(p1) + len);
BlockMove(symPtr, p1, len);
symPtr := pointer(ord4(symPtr) + len);
end; {ReadChars}


procedure WriteExtended (e: extended);

{ Write an extended constant to the symbol file			}
{								}
{ parameters:							}
{    e - constant to write					}

var
   ePtr: ^extended;			{work pointer}

begin {WriteExtended}
if bufLen < 10 then
   Purge;
ePtr := pointer(bufPtr);
ePtr^ := e;
bufPtr := pointer(ord4(bufPtr) + 10);
bufLen := bufLen - 10;
end; {WriteExtended}


procedure WriteLong (i: longint);

{ Write a long word to the symbol file				}
{								}
{ parameters:							}
{    i - long word to write					}

var
   lPtr: ^longint;			{work pointer}

begin {WriteLong}
if bufLen < 4 then
   Purge;
lPtr := pointer(bufPtr);
lPtr^ := i;
bufPtr := pointer(ord4(bufPtr) + 4);
bufLen := bufLen - 4;
end; {WriteLong}


procedure WriteByte (i: integer);

{ Write a byte to the symbol file				}
{								}
{ parameters:							}
{    i - byte to write						}

var
   iPtr: ^byte;				{work pointer}
    
begin {WriteByte}
if bufLen = 0 then
   Purge;
iPtr := pointer(bufPtr);
iPtr^ := i;
bufPtr := pointer(ord4(bufPtr) + 1);
bufLen := bufLen - 1;
end; {WriteByte}


procedure WriteWord (i: integer);

{ Write a word to the symbol file				}
{								}
{ parameters:							}
{    i - word to write						}

var
   iPtr: ^integer;			{work pointer}
    
begin {WriteWord}
if bufLen < 2 then
   Purge;
iPtr := pointer(bufPtr);
iPtr^ := i;
bufPtr := pointer(ord4(bufPtr) + 2);
bufLen := bufLen - 2;
end; {WriteWord}


procedure WriteLongString (s: longStringPtr);

{ Write a long string to the symbol file			}
{								}
{ parameters:							}
{    s - pointer to the string to write				}

var
   i: 0..maxint;			{loop/index variables}
   len: 0..maxint;			{string length}
   wrRec: readWriteOSDCB;		{WriteGS record}
     
begin {WriteLongString}
len := s^.length;
if bufLen < len+2 then
   Purge;
if bufLen < len+2 then begin
   wrRec.pcount := 4;
   wrRec.refnum := symRefnum;
   wrRec.dataBuffer := pointer(s);
   wrRec.requestCount := s^.length + 2;
   WriteGS(wrRec);
   if ToolError <> 0 then begin
      CloseSymbols;
      DestroySymbolFile;
      saveSource := false;
      end; {if}
   end {if}
else begin
   WriteWord(len);
   for i := 1 to len do begin
      bufPtr^ := ord(s^.str[i]);
      bufPtr := pointer(ord4(bufPtr) + 1);
      end; {for}
   bufLen := bufLen - len;
   end; {else}
end; {WriteLongString}


procedure WriteChars (p1, p2: ptr);

{ Write a stream of chars as a longString			}
{								}
{ parameters:							}
{    p1 - points to the first char to write			}
{    p2 - points to the byte following the last char		}

var
   i: 0..maxint;			{loop/index variables}
   len: 0..maxint;			{char length}
   wrRec: readWriteOSDCB;		{WriteGS record}

begin {WriteChars}
len := ord(ord4(p2) - ord4(p1));
WriteWord(len);
if bufLen < len then
   Purge;
if bufLen < len then begin
   if saveSource then begin
      wrRec.pcount := 4;
      wrRec.refnum := symRefnum;
      wrRec.dataBuffer := pointer(p1);
      wrRec.requestCount := ord4(p2) - ord4(p1);
      WriteGS(wrRec);
      if ToolError <> 0 then begin
	 CloseSymbols;
	 DestroySymbolFile;
	 saveSource := false;
	 end; {if}
      end; {if}
   end {if}
else begin
   for i := 1 to len do begin
      bufPtr^ := p1^;
      bufPtr := pointer(ord4(bufPtr)+1);
      p1 := pointer(ord4(p1)+1);
      end; {for}
   bufLen := bufLen - len;
   end; {else}
end; {WriteChars}


procedure WriteString (s: stringPtr);

{ Write a string to the symbol file				}
{								}
{ parameters:							}
{    s - pointer to the string to write				}

var
   i: 0..255;				{loop/index variable}
   len: 0..255;				{length of the string}

begin {WriteString}
len := length(s^);
if bufLen < len+1 then
   Purge;
for i := 0 to len do begin
   bufPtr^ := ord(s^[i]);
   bufPtr := pointer(ord4(bufPtr)+1);
   end; {for}
bufLen := bufLen - (len + 1);
end; {WriteString}


procedure MarkBlock;

{ Mark the length of the current block				}

var
   l: longint;				{block length}
   smRec: setMarkOSDCB;			{SetMarkGS record}
   gmRec: getMarkOSDCB;			{GetMarkGS record}
   wrRec: readWriteOSDCB;		{WriteGS record}
      
begin {MarkBlock}
Purge;					{purge the buffer}
gmRec.pCount := 2;			{get the current EOF}
gmRec.refnum := symRefnum;
GetMarkGS(gmRec);
if ToolError = 0 then begin
   smRec.pcount := 3;			{set the mark to the block length field}
   smRec.refnum := symRefnum;
   smRec.base := 0;
   smRec.displacement := symMark;
   SetMarkGS(smRec);
   if ToolError = 0 then begin
      l := gmRec.displacement - smRec.displacement - 4;
      wrRec.pcount := 4;
      wrRec.refnum := symRefnum;
      wrRec.dataBuffer := @l;
      wrRec.requestCount := 4;
      WriteGS(wrRec);
      if ToolError <> 0 then begin
	 CloseSymbols;
	 DestroySymbolFile;
	 saveSource := false;
	 end; {if}
      smRec.displacement := gmRec.displacement;
      SetMarkGS(smRec);
      end; {if}
   end; {if}
if ToolError <> 0 then begin		{for errors, delete the symbol file}
   CloseSymbols;
   DestroySymbolFile;
   saveSource := false;
   end; {if}
end; {MarkBlock}


function GetMark: longint;

{ Find the current file mark					}
{								}
{ Returns: file mark						}

var
   gmRec: getMarkOSDCB;			{GetMarkGS record}

begin {GetMark}
gmRec.pCount := 2;
gmRec.refnum := symRefnum;
GetMarkGS(gmRec);
GetMark := gmRec.displacement + (bufSize - bufLen);
if ToolError <> 0 then begin
   CloseSymbols;
   DestroySymbolFile;
   saveSource := false;
   end; {else}
end; {GetMark}


procedure SetMark;

{ Mark the start of a block					}

begin {SetMark}
symMark := GetMark;
WriteLong(0);
end; {SetMark}

{---------------------------------------------------------------}

procedure EndInclude {chPtr: ptr};

{ Saves symbols created by the include file			}
{								}
{ Parameters:							}
{    chPtr - chPtr when the file returned			}
{								}
{ Notes:							}
{    1. Call this subroutine right after processing an		}
{       include file.						}
{    2. Declared externally in Scanner.pas			}


   procedure SaveMacroTable;

   { Save macros to the symbol file				}


      procedure SaveMacros;

      { Write the macros to the symbol file			}

      var
         i: 0..hashSize;		{loop/index variable}
         mp: macroRecordPtr;		{used to trace macro lists}
         tp: tokenListRecordPtr;	{used to trace token lists}


	 procedure WriteToken (var token: tokenType);

	 { Write a token in the header file				}
	 {								}
	 { parameters:							}
	 {    token - token to write					}

	 begin {WriteToken}
	 WriteByte(ord(token.kind));
	 WriteByte(ord(token.class));
         if token.numstring = nil then
            WriteByte(0)
         else begin
            WriteByte(1);
            WriteString(token.numstring);
            end; {else}
	 case token.class of
	    identifier:		WriteString(token.name);
	    intConstant:	WriteWord(token.ival);
	    longConstant:	WriteLong(token.lval);
	    longlongConstant:	begin
                		WriteLong(token.qval.lo);
                		WriteLong(token.qval.hi);
                		end;
	    realConstant:	WriteExtended(token.rval);
	    stringConstant:	begin
				WriteLongString(token.sval);
                		WriteByte(ord(token.ispstring));
                		WriteByte(ord(token.prefix));
                		end;
            otherCharacter:	WriteByte(ord(token.ch));
            preprocessingNumber:WriteWord(token.errCode);
            macroParameter:	WriteWord(token.pnum);
            reservedSymbol:	if token.kind in [lbracech,rbracech,lbrackch,
                                   rbrackch,poundch,poundpoundop] then 
                                   WriteByte(ord(token.isDigraph));
	    otherwise:	;
	    end; {case}
	 end; {WriteToken}


      begin {SaveMacros}
      for i := 0 to hashSize do begin	{loop over hash buckets}
         mp := macros^[i];		{loop over macro records in hash bucket}
         while mp <> nil do begin
            if not mp^.saved then begin
               mp^.saved := true;	{mark this one as saved}
               WriteString(mp^.name);	{write the macroRecord}
               WriteByte(mp^.parameters);
               WriteByte(ord(mp^.isVarargs));
               WriteByte(ord(mp^.readOnly));
               WriteByte(mp^.algorithm);
               tp := mp^.tokens;	{loop over token list}
               while tp <> nil do begin
		  WriteByte(1);		{write tokenListRecord}
        	  WriteToken(tp^.token);
        	  WriteByte(ord(tp^.expandEnabled));
        	  WriteChars(tp^.tokenStart, tp^.tokenEnd);
        	  tp := tp^.next;
        	  end; {while}
               WriteByte(0);		{mark end of token list}
               end; {if}
            mp := mp^.next;
            end; {while}
         end; {for}
      end; {SaveMacros}


   begin {SaveMacroTable}
   SetMark;				{set the macro table length mark}
   if saveSource then			{write the macro table}
      SaveMacros;
   if saveSource then			{mark the length of the table}
      MarkBlock;
   end; {SaveMacroTable}


   procedure SavePragmaEffects;

   { Save the variables effected by any pragmas encountered	}

   var
      count: 0..maxint;			{number of path names}
      i: 1..10;				{loop/index variable}
      p: pragmas;			{loop variable}
      pp: pathRecordPtr;		{used to trace pathname list}

   begin {SavePragmaEffects}
   SetMark;
   if saveSource then
      for p := succ(p_startofenum) to pred(p_endofenum) do
         if p in savePragmas then
            if saveSource then begin
               WriteByte(ord(p));
               case p of
                  p_cda: begin
                     WriteString(@menuLine);
                     WriteString(openName);
                     WriteString(closeName);
                     end;

                  p_cdev: WriteString(openName);

                  p_float: begin
                     WriteWord(floatCard);
                     WriteWord(floatSlot);
                     end;

                  p_keep: WriteLongString(@pragmaKeepFile^.theString);

                  p_line: begin
                     WriteLong(lineNumber);
                     WriteLongString(@sourceFileGS.theString);
                     end;

                  p_nda: begin
                     WriteString(openName);
                     WriteString(closeName);
                     WriteString(actionName);
                     WriteString(initName);
                     WriteWord(refreshPeriod);
                     WriteWord(eventMask);
                     WriteString(@menuLine);
                     end;

                  p_nba:
                     WriteString(openName);

                  p_xcmd:
                     WriteString(openName);

                  p_debug:
                     WriteWord(ord(rangeCheck)
                        | (ord(debugFlag) << 1)
                        | (ord(profileFlag) << 2)
                        | (ord(traceBack) << 3)
                        | (ord(checkStack) << 4)
                        | (ord(checkNullPointers) << 5)
                        | (ord(debugStrFlag) << 15));

                  p_lint: begin
                     WriteWord(lint);
                     WriteByte(ord(lintIsError));
                     end;

                  p_memorymodel: WriteByte(ord(smallMemoryModel));

                  p_expand: WriteByte(ord(printMacroExpansions));

                  p_optimize:
                     WriteByte(ord(peepHole)
                        | (ord(npeepHole) << 1)
                        | (ord(registers) << 2)
                        | (ord(saveStack) << 3)
                        | (ord(commonSubexpression) << 4)
                        | (ord(loopOptimizations) << 5)
                        | (ord(strictVararg) << 6)
                        | (ord(fastMath) << 7));

                  p_stacksize: WriteWord(stackSize);

                  p_toolparms: WriteByte(ord(toolParms));

                  p_databank: WriteByte(ord(dataBank));

                  p_rtl: ;

                  p_noroot: ;

                  p_path: begin
                     pp := pathList;
                     count := 0;
                     while pp <> nil do begin
                        count := count+1;
                        pp := pp^.next;
                        end; {while}
                     WriteWord(count);
                     pp := pathList;
                     while pp <> nil do begin
                        WriteString(pp^.path);
                        pp := pp^.next;
                        end; {while}
                     end; {p_path}

                  p_ignore:
                     WriteByte(ord(skipIllegalTokens)
                        | (ord(allowLongIntChar) << 1)
                        | (ord(allowTokensAfterEndif) << 2)
                        | (ord(allowSlashSlashComments) << 3)
                        | (ord(allowMixedDeclarations) << 4)
                        | (ord(looseTypeChecks) << 5));

                  p_segment: begin
                     for i := 1 to 10 do begin
                        WriteByte(defaultSegment[i]);
                        WriteByte(currentSegment[i]);
                        end; {for}
                     WriteWord(segmentKind);
                     WriteWord(defaultSegmentKind);
                     end;

                  p_unix: WriteByte(ord(unix_1));
                  
                  p_fenv_access: WriteByte(ord(fenvAccess));
                  
                  p_extensions:
                     WriteByte(ord(extendedKeywords)
                        | (ord(extendedParameters) << 1));

                  end; {case}
               end; {if}
   if saveSource then
      MarkBlock;
   savePragmas := [];
   end; {SavePragmaEffects}


   procedure SaveSourceStream;

   { Save the source stream for later compares			}

   var
      wrRec: readWriteOSDCB;		{WriteGS record}

   begin {SaveSourceStream}
   WriteLong(ord4(chPtr) - ord4(symChPtr));
   Purge;
   wrRec.pcount := 4;
   wrRec.refnum := symRefnum;
   wrRec.dataBuffer := pointer(symChPtr);
   wrRec.requestCount := ord4(chPtr) - ord4(symChPtr);
   WriteGS(wrRec);
   symChPtr := chPtr;
   if ToolError <> 0 then begin
      CloseSymbols;
      DestroySymbolFile;
      saveSource := false;
      end; {if}
   end; {SaveSourceStream}


   procedure SaveSymbolTable;

   { Save symbols to the symbol file				}


      procedure SaveSymbol;

      { Write the symbols to the symbol file			}

      var
         abort: boolean;		{abort due to initialized var?}
         efRec: setMarkOSDCB;		{SetEOFGS record}
         i: 0..hashSize;		{loop/index variable}
         sp: identPtr;			{used to trace symbol lists}


         procedure WriteIdent (ip: identPtr);

         { write a symbol to the symbol file				}
         {								}
         { parameters:							}
         {    ip - pointer to symbol entry				}


            procedure WriteType (tp: typePtr);

            { write a type entry to the symbol file			}
            {								}
            { parameters:						}
            {    tp - pointer to type entry				}

            var
               ip: identPtr;			{for tracing field list}


               procedure WriteParm (pp: parameterPtr);

               { write a parameter list to the symbol file		}
               {							}
               { parameters:						}
               {    pp - parameter pointer				}

               begin {WriteParm}
               while pp <> nil do begin
                  WriteByte(1);
                  WriteType(pp^.parameterType);
                  pp := pp^.next;
                  end; {while}
               WriteByte(0);
               end; {WriteParm}


            begin {WriteType}
            if tp = sCharPtr then
               WriteByte(2)
            else if tp = charPtr then
               WriteByte(3)
            else if tp = intPtr then
               WriteByte(4)
            else if tp = uIntPtr then
               WriteByte(5)
            else if tp = longPtr then
               WriteByte(6)
            else if tp = uLongPtr then
               WriteByte(7)
            else if tp = floatPtr then
               WriteByte(8)
            else if tp = doublePtr then
               WriteByte(9)
            else if tp = extendedPtr then
               WriteByte(10)
            else if tp = stringTypePtr then
               WriteByte(11)
            else if tp = voidPtr then
               WriteByte(12)
            else if tp = voidPtrPtr then
               WriteByte(13)
            else if tp = defaultStruct then
               WriteByte(14)
            else if tp = uCharPtr then
               WriteByte(15)
            else if tp = shortPtr then
               WriteByte(16)
            else if tp = uShortPtr then
               WriteByte(17)
            else if tp = utf16StringTypePtr then
               WriteByte(18)
            else if tp = utf32StringTypePtr then
               WriteByte(19)
            else if tp^.saveDisp <> 0 then begin
               WriteByte(1);
               WriteLong(tp^.saveDisp);
               end {if}
            else begin
               WriteByte(0);
               tp^.saveDisp := GetMark;
               WriteLong(tp^.size);
               WriteByte(ord(tqConst in tp^.qualifiers)
                  | (ord(tqVolatile in tp^.qualifiers) << 1)
                  | (ord(tqRestrict in tp^.qualifiers) << 2));
               WriteByte(ord(tp^.kind));
               case tp^.kind of
        	  scalarType: begin
        	     WriteByte(ord(tp^.baseType));
        	     WriteByte(ord(tp^.cType));
        	     end;

        	  arrayType: begin
        	     WriteLong(tp^.elements);
        	     WriteType(tp^.aType);
        	     end;

        	  pointerType:
        	     WriteType(tp^.pType);

        	  functionType: begin
        	     WriteByte((ord(tp^.varargs) << 2)
                        | (ord(tp^.prototyped) << 1) | ord(tp^.isPascal));
        	     WriteWord(tp^.toolnum);
        	     WriteLong(tp^.dispatcher);
        	     WriteType(tp^.fType);
        	     WriteParm(tp^.parameterList);
        	     end;

        	  enumConst:
        	     WriteWord(tp^.eval);

        	  definedType:
        	     WriteType(tp^.dType);

        	  structType, unionType: begin
        	     ip := tp^.fieldList;
        	     while ip <> nil do begin
                	WriteByte(1);
                	WriteIdent(ip);
                	ip := ip^.next;
                	end; {while}
        	     WriteByte(0);
        	     WriteByte(ord(tp^.constMember));
        	     WriteByte(ord(tp^.flexibleArrayMember));
        	     end;

		  otherwise: ;
               
        	  end; {case}
               end; {else}
            end; {WriteType}


	 begin {WriteIdent}
         WriteString(ip^.name);	
         WriteType(ip^.itype);
         if (ip^.disp = 0) and (ip^.bitDisp = 0) and (ip^.bitSize = 0) then
            WriteByte(0)
         else if (ip^.bitSize = 0) and (ip^.bitDisp = 0) then begin
            if ip^.disp < maxint then begin
               WriteByte(1);
               WriteWord(ord(ip^.disp));
               end {if}
            else begin
               WriteByte(2);
               WriteLong(ip^.disp);
               end; {else}
            end {else if}
         else begin
            WriteByte(3);
            WriteLong(ip^.disp);
            WriteByte(ip^.bitDisp);
            WriteByte(ip^.bitSize);
            end; {else}
         if ip^.iPtr <> nil then
            abort := true;
         WriteByte(ord(ip^.state));
         WriteByte(ord(ip^.isForwardDeclared));
         WriteByte(ord(ip^.class));
         WriteByte(ord(ip^.storage));
         if ip^.storage = external then
            WriteByte(ord(ip^.inlineDefinition));
         {if ip^.storage = none then ip^.anonMemberField must be false}
	 end; {WriteIdent}
         

      begin {SaveSymbol}
      abort := false;			{no reason to abort, yet}
      for i := 0 to hashSize2 do begin	{loop over hash buckets}
         sp := globalTable^.buckets[i];	{loop over symbol records in hash bucket}
         while sp <> nil do begin
            if not sp^.saved then begin
               sp^.saved := true;	{mark this one as saved}
               WriteWord(i);		{save the symbol}
               WriteIdent(sp);
               end; {if}
            sp := sp^.next;
            end; {while}
         end; {for}
      if abort then begin
         Purge;
	 efRec.pcount := 3;
	 efRec.refnum := symRefnum;
	 efRec.base := 0;
	 efRec.displacement := tokenMark;
	 SetEOFGS(efRec);
	 if ToolError <> 0 then begin
	    CloseSymbols;
	    DestroySymbolFile;
	    end; {if}
         saveSource := false;
         end; {if}
      end; {SaveSymbol}


   begin {SaveSymbolTable}
   SetMark;				{set the symbol table length mark}
   if saveSource then			{write the symbol table}
      if globalTable <> nil then
         SaveSymbol;
   if saveSource then			{mark the length of the table}
      MarkBlock;
   end; {SaveSymbolTable}


begin {EndInclude}
if not ignoreSymbols then begin
   includeLevel := includeLevel-1;
   if includeLevel = 0 then
      if saveSource then begin
	 MarkBlock;			{set the include name mark}
	 SaveSourceStream;		{save the source stream}
	 SaveMacroTable;		{save the macro table}
	 SaveSymbolTable;		{save the symbol table}
	 SavePragmaEffects;		{save the effects of pragmas}
	 tokenMark := GetMark;		{record mark for early exit}
	 includeMark := false;		{no include mark, yet}
	 end; {if}
   end; {if}
end; {EndInclude}                


procedure FlagPragmas {pragma: pragmas};

{ record the effects of a pragma				}
{								}
{ parameters:							}
{    pragma - pragma to record					}
{								}
{ Notes:							}
{    1. Defined as extern in Scanner.pas			}
{    2. For the purposes of this unit, the segment statement	}
{	and #line directive are treated as pragmas.		}

begin {FlagPragmas}
savePragmas := savePragmas + [pragma];
end; {FlagPragmas}


procedure InitHeader {var fName: gsosOutString};

{ look for a header file, reading it if it exists		}
{								}
{ parameters:							}
{    fName - source file name (var for efficiency)		}

type
   typeDispPtr = ^typeDispRecord;	{type displacement/pointer table}
   typeDispRecord = record
      next: typeDispPtr;
      saveDisp: longint;
      tPtr: typePtr;
      end;

var
   done: boolean;			{for loop termination test}
   typeDispList: typeDispPtr;		{type displacement/pointer table}
   includesPtr: ptr;			{ptr to includes section from sym file}
   i: 1..maxint;			{loop/index variable}


   procedure DisposeTypeDispList;

   { Dispose of the type displacement list			}

   var
      tp: typeDispPtr;			{work pointer}

   begin {DisposeTypeDispList}
   while typeDispList <> nil do begin
      tp := typeDispList;
      typeDispList := tp^.next;
      dispose(tp);
      end; {while}
   end; {DisposeTypeDispList}


   function EndOfSymbols: boolean;

   { See if we're at the end of the symbol file			}
   {								}
   { Returns: True if at the end, else false			}

   begin {EndOfSymbols}
   EndOfSymbols := ord4(symPtr) >= ord4(symEndPtr);
   end; {EndOfSymbols}


   function OpenSymbols: boolean;

   { open and initialize the symbol file			}
   {								}
   { Returns: True if successful, else false			}

   var
      crRec: createOSDCB;		{CreateGS record}
      opRec: openOSDCB;			{OpenGS record}

   begin {OpenSymbols}
   OpenSymbols := false;		{assume we will fail}
   DestroySymbolFile;			{destroy any existing file}
   crRec.pCount := 5;			{create a symbol file}
   crRec.pathName := @symName.theString;
   crRec.access := $C3;
   crRec.fileType := symFiletype;
   crRec.auxType := symAuxtype;
   crRec.storageType := 1;
   CreateGS(crRec);
   if ToolError = 0 then begin
      opRec.pCount := 3;
      opRec.pathname := @symName.theString;
      opRec.requestAccess := 3;
      OpenGS(opRec);
      if ToolError = 0 then begin           
         symRefnum := opRec.refnum;
         OpenSymbols := true;
         WriteWord(symFileVersion);
         WriteLongString(pointer(@infoStringGS.theString));
         tokenMark := GetMark;
         includeMark := false;
         end; {if}
      end; {if}
   end; {OpenSymbols}


   procedure PurgeSymbols;

   { Purge the symbol input file				}

   var
      ffDCBGS: fastFileDCBGS;		{fast file DCB}
   
   begin {PurgeSymbols}
   with ffDCBGS do begin		{purge the file}
      pCount := 5;
      action := 7;
      pathName := @symName.theString;
      end; {with}
   FastFileGS(ffDCBGS);
   end; {PurgeSymbols}                                      


   function DatesMatch: boolean;

   { Make sure the create/mod dates have not changed		}

   var
      giRec: getFileInfoOSDCB;		{GetFileInfoGS record}
      i: 1..maxint;			{loop/index variable}
      len: longint;			{length of names}
      match: boolean;			{do the dates match?}

   begin {DatesMatch}
   match := true;
   len := ReadLong;
   while len > 0 do begin
      giRec.pCount := 7;
      giRec.pathname := pointer(ReadLongString);
      len := len - (giRec.pathname^.size + 18);
      GetFileInfoGS(giRec);
      if ToolError = 0 then begin
	 for i := 1 to 8 do
	    match := match and (giRec.createDateTime[i] = ReadByte);
	 for i := 1 to 8 do
	    match := match and (giRec.modDateTime[i] = ReadByte);
         end {if}
      else begin
         match := false;
         len := 0;
         end; {else}
      end; {while}
   DatesMatch := match;
   end; {DatesMatch}


   procedure PrintIncludes;

   { Print "Including ..." lines for the headers		}

   type
      longptr = ^longint;

   var
      dataPtr: ptr;                     {pointer to data from sym file}
      endPtr: ptr;                      {pointer to end of includes section}
      i: 1..maxint;			{loop/index variable}
      includeNamePtr: gsosInStringPtr;  {pointer to an include file name}

   begin {PrintIncludes}
   dataPtr := includesPtr;
   endPtr := pointer(ord4(dataPtr) + longptr(dataPtr)^ + 4);
   dataPtr := pointer(ord4(dataPtr) + 4);
   while dataPtr <> endPtr do begin
      includeNamePtr := gsosInStringPtr(dataPtr);
      write('Including ');
      for i := 1 to includeNamePtr^.size do
         write(includeNamePtr^.theString[i]);
      writeln;
      dataPtr := pointer(ord4(dataPtr) + includeNamePtr^.size + 18);
      end; {while}
   end; {PrintIncludes}


   procedure ReadMacroTable;

   { Read macros from the symbol file				}

   var
      bp: ^macroRecordPtr;		{pointer to head of hash bucket}
      ep: tokenListRecordPtr;		{last token record}
      mePtr: ptr;			{end of macro table}
      mp: macroRecordPtr;		{new macro record}
      tlen: integer;			{length of the token name}
      tp: tokenListRecordPtr;		{new token record}
        

      procedure ReadToken (var token: tokenType);

      { read a token						}
      {								}
      { parameters:						}
      {    token - (output) token read)				}

      begin {ReadToken}
      token.kind := tokenEnum(ReadByte);
      token.class := tokenClass(ReadByte);
      if ReadByte = 0 then
         token.numString := nil
      else
         token.numstring := ReadString;
      case token.class of 
	 identifier:		token.name := ReadString;
	 intConstant:		token.ival := ReadWord;
	 longConstant:		token.lval := ReadLong;
	 longlongConstant:	begin
			        token.qval.lo := ReadLong;
                	        token.qval.hi := ReadLong;
                	        end;
	 realConstant:		token.rval := ReadExtended;
	 stringConstant:	begin
			        token.sval := ReadLongString;
                	        token.ispstring := ReadByte <> 0;
                	        token.prefix := charStrPrefixEnum(ReadByte);
                	        end;
         otherCharacter:	token.ch := chr(ReadByte);
         preprocessingNumber:   token.errCode := ReadWord;
         macroParameter:	token.pnum := ReadWord;
         reservedSymbol:	if token.kind in [lbracech,rbracech,lbrackch,
                                   rbrackch,poundch,poundpoundop] then 
                                   token.isDigraph := boolean(ReadByte);
	 otherwise:		;
	 end; {case}
      end; {ReadToken}


   begin {ReadMacroTable}
   mePtr := symPtr;			{read the block length}
   mePtr := pointer(ord4(mePtr) + ReadLong + 4);
   while ord4(symPtr) < ord4(mePtr) do	{process the macros}
      begin
      Spin;
      mp := pointer(GMalloc(sizeof(macroRecord)));
      mp^.saved := false;
      mp^.name := ReadString;
      bp := pointer(ord4(macros) + Hash(mp^.name));
      mp^.next := bp^;
      bp^ := mp;
      mp^.parameters := ReadByte;
      if mp^.parameters & $0080 <> 0 then
         mp^.parameters := mp^.parameters | $FF00;
      mp^.isVarargs := boolean(ReadByte);
      mp^.readOnly := boolean(ReadByte);
      mp^.algorithm := ReadByte;
      mp^.tokens := nil;
      ep := nil;
      while ReadByte <> 0 do begin
         tp := pointer(GMalloc(sizeof(tokenListRecord)));
         tp^.next := nil;
         ReadToken(tp^.token);
         tp^.expandEnabled := boolean(ReadByte);
         ReadChars(tp^.tokenStart, tp^.tokenEnd);
         if ep = nil then
            mp^.tokens := tp
         else
            ep^.next := tp;
         ep := tp;
         end; {while}
      end; {while}
   symPtr := mePtr;
   end; {ReadMacroTable}


   procedure ReadPragmas;

   { Read pragma effects					}

   var
      i: 0..maxint;			{loop/index variable}
      lsPtr: longStringPtr;		{work pointer}
      p: pragmas;			{kind of pragma being processed}
      pePtr: ptr;			{end of pragma table}
      pp, ppe: pathRecordPtr;		{used to create a path name list}
      sPtr: stringPtr;			{work pointer}
      val: integer;			{temp value}
      
   begin {ReadPragmas}
   pePtr := symPtr;			{read the block length}
   pePtr := pointer(ord4(pePtr) + ReadLong + 4);
   while ord4(symPtr) < ord4(pePtr) do	{process the pragmas}
      begin
      Spin;
      p := pragmas(ReadByte);
      case p of
         p_cda: begin
            isClassicDeskAcc := true;
            sPtr := ReadString;
            menuLine := sPtr^;
            openName := ReadString;
            closeName := ReadString;
            end;

         p_cdev: begin
            isCDev := true;
            openName := ReadString;
            end;

         p_float: begin
            floatCard := ReadWord;
            floatSlot := ReadWord;
            end;

         p_keep: begin
            lsPtr := ReadLongString;
            if liDCBGS.kFlag = 0 then begin
               liDCBGS.kFlag := 1;
               outFileGS.theString.size := lsPtr^.length;
               for i := 1 to outFileGS.theString.size do
                  outFileGS.theString.theString[i] := lsPtr^.str[i];
               end; {if}
            end;

         p_line: begin
            lineNumber := ReadLong - 1;
            lsPtr := ReadLongString;
            sourceFileGS.theString.size := lsPtr^.length;
            for i := 1 to sourceFileGS.theString.size do
               sourceFileGS.theString.theString[i] := lsPtr^.str[i];
            end;

         p_nda: begin
            isNewDeskAcc := true;
            openName := ReadString;
            closeName := ReadString;
            actionName := ReadString;
            initName := ReadString;
            refreshPeriod := ReadWord;
            eventMask := ReadWord;
            sPtr := ReadString;
            menuLine := sPtr^;
            end;

         p_nba: begin
            isNBA := true;
            openName := ReadString;
            end;

         p_xcmd: begin
            isXCMD := true;
            openName := ReadString;
            end;

         p_debug: begin
            val := ReadWord;
            rangeCheck := odd(val);
            debugFlag := odd(val >> 1);
            profileFlag := odd(val >> 2);
            traceback := odd(val >> 3);
            checkStack := odd(val >> 4);
            checkNullPointers := odd(val >> 5);
            debugStrFlag := odd(val >> 15);
            end;

         p_lint: begin
            lint := ReadWord;
            lintIsError := boolean(ReadByte);
            end;

         p_memorymodel: smallMemoryModel := boolean(ReadByte);

         p_expand: printMacroExpansions := boolean(ReadByte);

         p_optimize: begin
            val := ReadByte;
            peepHole := odd(val);
            npeepHole := odd(val >> 1);
            registers := odd(val >> 2);
            saveStack := odd(val >> 3);
            commonSubexpression := odd(val >> 4);
            loopOptimizations := odd(val >> 5);
            strictVararg := odd(val >> 6);
            fastMath := odd(val >> 7);
            end;

         p_stacksize: stackSize := ReadWord;

         p_toolparms: toolParms := boolean(ReadByte);

         p_databank: dataBank := boolean(ReadByte);

         p_rtl: rtl := true;

         p_noroot: noroot := true;

         p_path: begin
            i := ReadWord;
            pathList := nil;
            ppe := nil;
            while i <> 0 do begin
               pp := pathRecordPtr(GMalloc(sizeof(pathRecord)));
               pp^.path := ReadString;
               pp^.next := nil;
               if pathList = nil then
                  pathList := pp
               else
                  ppe^.next := pp;
               ppe := pp;
               i := i-1;
               end; {while}
            end; {p_path}

         p_ignore: begin
            i := ReadByte;
            skipIllegalTokens := odd(i);
            allowLongIntChar := odd(i >> 1);
            allowTokensAfterEndif := odd(i >> 2);
            allowSlashSlashComments := odd(i >> 3);
            allowMixedDeclarations := odd(i >> 4);
            c99Scope := allowMixedDeclarations;
            looseTypeChecks := odd(i >> 5);
            end;
         
         p_segment: begin
            for i := 1 to 10 do begin
               defaultSegment[i] := chr(ReadByte);
               currentSegment[i] := chr(ReadByte);
               end; {for}
            segmentKind := ReadWord;
            defaultSegmentKind := ReadWord;
            end;

         p_unix: unix_1 := boolean(ReadByte);
         
         p_fenv_access: fenvAccess := boolean(ReadByte);
         
         p_extensions: begin
            i := ReadByte;
            extendedKeywords := odd(i);
            extendedParameters := odd(i >> 1);
            end;

         otherwise: begin
            PurgeSymbols;
            DestroySymbolFile;
            TermError(12);
            end;
         end; {case}
      end; {while}
   symPtr := pePtr;
   end; {ReadPragmas}


   procedure ReadSymbolTable;

   { Read symbols from the symbol file				}

   var
      hashPtr: ^identPtr;		{pointer to hash bucket in symbol table}
      sePtr: ptr;			{end of symbol table}
      sp: identPtr;			{identifier being constructed}


      function ReadIdent: identPtr;

      { Read an identifier from the file			}
      {								}
      { Returns: Pointer to the new identifier			}

      var
         format: 0..3;			{storage format}
	 sp: identPtr;			{identifier being constructed}


	 procedure ReadType (var tp: typePtr);

	 { read a type from the symbol file				}
	 {								}
	 { parameters:							}
	 {    tp - (output) type entry					}

	 var
            disp: longint;			{disp read from symbol file}
            ep: identPtr;			{end of list of field names}
            ip: identPtr;			{for tracing field list}
            tdisp: typeDispPtr;			{used to trace, add to typeDispList}
            val: integer;			{temp word}


            procedure ReadParm (var pp: parameterPtr);

            { read a parameter list from the symbol file		}
            {								}
            { parameters:						}
            {    pp - (output) parameter pointer			}

            var
               ep: parameterPtr;		{last parameter in list}
               np: parameterPtr;		{new parameter}

            begin {ReadParm}
            pp := nil;
            ep := nil;
            while ReadByte = 1 do begin
               np := parameterPtr(GMalloc(sizeof(parameterRecord)));
               np^.next := nil;
               np^.parameter := nil;
               ReadType(np^.parameterType);
               if ep = nil then
                  pp := np
               else
                  ep^.next := np;
               ep := np;
               end; {while}
            end; {ReadParm}


	 begin {ReadType}
         case ReadByte of
            0: begin			{read a new type}
	       tp := typePtr(GMalloc(sizeof(typeRecord)));
               new(tdisp);
               tdisp^.next := typeDispList;
               typeDispList := tdisp;
               tdisp^.saveDisp := ord4(symPtr) - ord4(symStartPtr);
               tdisp^.tPtr := tp;
	       tp^.size := ReadLong;
               tp^.saveDisp := 0;
	       val := ReadByte;
	       if odd(val) then
	          tp^.qualifiers := [tqConst]
	       else
	          tp^.qualifiers := [];
	       if odd(val >> 1) then begin
	          tp^.qualifiers := tp^.qualifiers + [tqVolatile];
	          volatile := true;
	          end; {if}
	       if odd(val >> 2) then
	          tp^.qualifiers := tp^.qualifiers + [tqRestrict];
	       tp^.kind := typeKind(ReadByte);
	       case tp^.kind of
        	  scalarType: begin
        	     tp^.baseType := baseTypeEnum(ReadByte);
        	     tp^.cType := cTypeEnum(ReadByte);
        	     end;

        	  arrayType: begin
        	     tp^.elements := ReadLong;
        	     ReadType(tp^.aType);
        	     end;

        	  pointerType: 
        	     ReadType(tp^.pType);

        	  functionType: begin
        	     val := ReadByte;
        	     tp^.varargs := odd(val >> 2);
        	     tp^.prototyped := odd(val >> 1);
        	     tp^.isPascal := odd(val);
        	     tp^.toolnum := ReadWord;
        	     tp^.dispatcher := ReadLong;
        	     ReadType(tp^.fType);
        	     ReadParm(tp^.parameterList);
        	     end;

        	  enumConst:
        	     tp^.eval := ReadWord;

        	  definedType:
        	     ReadType(tp^.dType);

        	  structType, unionType: begin
        	     tp^.fieldList := nil;
        	     ep := nil;
        	     while ReadByte = 1 do begin
        		ip := ReadIdent;
        		if ep = nil then
                	   tp^.fieldList := ip
        		else
                	   ep^.next := ip;
        		ep := ip;
        		end; {while}
        	     tp^.constMember := boolean(ReadByte);
        	     tp^.flexibleArrayMember := boolean(ReadByte);
        	     end;

        	  enumType: ;

        	  otherwise: begin
        	     PurgeSymbols;
        	     DestroySymbolFile;
        	     TermError(12);
        	     end;

        	  end; {case}
               end; {case 0}

            1: begin			{read a type displacement}
               tdisp := typeDispList;
               disp := ReadLong;
               tp := nil;
               while tdisp <> nil do
        	  if tdisp^.saveDisp = disp then begin
                     tp := tdisp^.tPtr;
                     tdisp := nil;
                     end {if}
        	  else 
                     tdisp := tdisp^.next;
               if tp = nil then begin
                  PurgeSymbols;
                  DestroySymbolFile;
                  TermError(12);
                  end; {if}
               end; {case 1}

            2: tp := sCharPtr;
            3: tp := charPtr;
            4: tp := intPtr;
            5: tp := uIntPtr;
            6: tp := longPtr;
            7: tp := uLongPtr;
            8: tp := floatPtr;
            9: tp := doublePtr;
            10: tp := extendedPtr;
            11: tp := stringTypePtr;
            12: tp := voidPtr;
            13: tp := voidPtrPtr;
            14: tp := defaultStruct;
            15: tp := uCharPtr;
            16: tp := shortPtr;
            17: tp := uShortPtr;
            18: tp := utf16StringTypePtr;
            19: tp := utf32StringTypePtr;

            otherwise: begin
               PurgeSymbols;
               DestroySymbolFile;
               TermError(12);
               end;
            end; {case}
	 end; {ReadType}


      begin {ReadIdent}
      sp := pointer(GMalloc(sizeof(identRecord)));
      sp^.next := nil;
      sp^.saved := false;
      sp^.name := ReadString;
      ReadType(sp^.itype);
      format := ReadByte;
      if format = 0 then begin
         sp^.disp := 0;
         sp^.bitDisp := 0;
         sp^.bitSize := 0;
         end {if}
      else if format = 1 then begin
         sp^.disp := ReadWord;
         sp^.bitDisp := 0;
         sp^.bitSize := 0;
         end {else if}
      else if format = 2 then begin
         sp^.disp := ReadLong;
         sp^.bitDisp := 0;
         sp^.bitSize := 0;
         end {else if}
      else begin
	 sp^.disp := ReadLong;
	 sp^.bitDisp := ReadByte;
	 sp^.bitSize := ReadByte;
         end; {else}
      sp^.iPtr := nil;
      sp^.state := stateKind(ReadByte);
      sp^.isForwardDeclared := boolean(ReadByte);
      sp^.class := tokenEnum(ReadByte);
      sp^.storage := storageType(ReadByte);
      sp^.used := false;
      if sp^.storage = none then
         sp^.anonMemberField := false
      else if sp^.storage = external then
         sp^.inlineDefinition := boolean(ReadByte);
      ReadIdent := sp;
      end; {ReadIdent}


   begin {ReadSymbolTable}
   sePtr := symPtr;			{read the block length}
   sePtr := pointer(ord4(sePtr) + ReadLong + 4);
   while ord4(symPtr) < ord4(sePtr) do	{process the symbols}
      begin
      Spin;
      hashPtr := pointer(ord4(globalTable) + ReadWord*4);
      sp := ReadIdent;
      sp^.next := hashPtr^;
      hashPtr^ := sp;
      end; {while}
   symPtr := sePtr;
   end; {ReadSymbolTable}


   function OpenSymbolFile (var fName: gsosOutString): boolean;

   { Look for and open a symbol file				}
   {								}
   { parameters:						}
   {    fName - source file name (var for efficiency)		}
   {								}
   { Returns: True if the file was found and opened, else false	}
   {								}
   { Notes: As a side effect, this subroutine creates the	}
   {    pathname for the symbol file (symName).			}

   var
      ffDCBGS: fastFileDCBGS;		{fast file DCB}
      i: integer;			{loop/index variable}

   begin {OpenSymbolFile}
   symName := fName;			{create the symbol file name}
   i := symName.theString.size - 1;
   while not (symName.theString.theString[i] in [':', '/', '.']) do
      i := i-1;
   if symName.theString.theString[i] <> '.' then
      i := symName.theString.size;
   if i > maxPath-5 then
      i := maxPath-5;
   symName.theString.theString[i] := '.';
   symName.theString.theString[i+1] := 's';
   symName.theString.theString[i+2] := 'y';
   symName.theString.theString[i+3] := 'm';
   symName.theString.theString[i+4] := chr(0);
   symName.theString.size := i+3;
   if rebuildSymbols then begin		{rebuild any existing symbol file}
      DestroySymbolFile;
      OpenSymbolFile := false;
      end {if}
   else begin
      with ffDCBGS do begin		{read the symbol file}
	 pCount := 14;
	 action := 0;
	 flags := $C000;
	 pathName := @symName.theString;
	 end; {with}
      FastFileGS(ffDCBGS);
      if ToolError = 0 then begin
	 if (ffDCBGS.filetype = symFiletype) and (ffDCBGS.auxtype = symAuxtype) then
            OpenSymbolFile := true
	 else begin
            OpenSymbolFile := false;
            PurgeSymbols;
            end; {else}
	 symPtr := ffDCBGS.fileHandle^;
	 symStartPtr := symPtr;
	 symEndPtr := pointer(ord4(symPtr) + ffDCBGS.fileLength);
	 end {if}
      else
	 OpenSymbolFile := false;
      end; {else}
   end; {OpenSymbolFile}


   function SymbolFileIsUsable: boolean;

   { Read the symbol file header to check if it is usable	}
   {								}
   { Returns: True if the symbol file is usable, false if not	}

   label 1;

   var
      ccPtr: longStringPtr;             {cc= string recorded in symbol file}
      i: integer;                       {loop counter}

   begin {SymbolFileIsUsable}
   SymbolFileIsUsable := false;
   if ReadWord = symFileVersion then begin
      ccPtr := ReadLongString;
      if ccPtr^.length = infoStringGS.theString.size then begin
         for i := 1 to infoStringGS.theString.size do
            if ccPtr^.str[i] <> infoStringGS.theString.theString[i] then
               goto 1;
         SymbolFileIsUsable := true;
         end; {if}
      end; {if}
1:
   end; {SymbolFileIsUsable}


   function SourceMatches: boolean;

   { Make sure the token streams match up to the next include	}

   type
      intPtr = ^integer;		{for faster compares}

   var
      len, len2: longint;		{size of stream to compare}
      match: boolean;			{result flag}
      p1, p2: ptr;			{work pointers}

   begin {SourceMatches}
   match := true;
   len := ReadLong;
   len2 := len;
   p1 := symPtr;
   p2 := chPtr;
   while len > 1 do
      if intPtr(p1)^ <> intPtr(p2)^ then begin
         match := false;
         len := 0;
         end {if}
      else begin
	 len := len-2;
	 p1 := pointer(ord4(p1)+2);
	 p2 := pointer(ord4(p2)+2);
         end; {else}
   if len = 1 then
      if p1^ <> p2^ then
         match := false;
   if match then begin
      symPtr := pointer(ord4(symPtr)+len2);
      symChPtr := pointer(ord4(chPtr)+len2);
      while chPtr <> symChPtr do
         NextCh;
      end; {if}
   SourceMatches := match;
   end; {SourceMatches}


begin {InitHeader}
inhibitHeader := false;			{don't block .sym files}
if not ignoreSymbols then begin
   codeStarted := false;		{code generation has not started}
   new(buffer);				{allocate an output buffer}
   bufPtr := pointer(buffer);
   bufLen := bufSize;
   includeLevel := 0;			{no nested includes}
   symChPtr := chPtr;			{record initial source location}
   if OpenSymbolFile(fName) then begin	{check for symbol file}
      if SymbolFileIsUsable then begin
	 done := EndOfSymbols;		{valid file found - process it}
	 if done then
            PurgeSymbols;
	 typeDispList := nil;
	 while not done do begin
            includesPtr := symPtr;
            if DatesMatch then begin
               if SourceMatches then begin
                  if progress then
                     PrintIncludes;
        	  ReadMacroTable;
        	  ReadSymbolTable;
        	  ReadPragmas;
        	  if EndOfSymbols then begin
        	     done := true;
        	     PurgeSymbols;
        	     end; {if}
        	  end {if}
               else begin
        	  PurgeSymbols;
        	  DestroySymbolFile;
        	  done := true;
        	  end; {else}
               end {if}
            else begin
               PurgeSymbols;
               DestroySymbolFile;
               done := true;
               end; {else}
            end; {while}
	 DisposeTypeDispList;
	 saveSource := false;
         if ord4(symPtr) > ord4(symEndPtr) then begin
            PurgeSymbols;
            DestroySymbolFile;
            TermError(12);
            end; {if}
	 end {if}
      else begin
	 PurgeSymbols;			{no file found}
	 saveSource := true;
	 end; {else}
      end {if}
   else 
      saveSource := true;
   if saveSource then begin		{start saving source}
      saveSource := OpenSymbols;
      savePragmas := [];
      DoDefaultsDotH;
      end; {if}
   end {if}
else
   DoDefaultsDotH;
end; {InitHeader}


procedure StartInclude {name: gsosOutStringPtr};

{ Marks the start of an include file				}
{								}
{ Notes:							}
{    1. Call this subroutine right after opening an include	}
{       file.							}
{    2. Defined externally in Scanner.pas			}

var
   giRec: getFileInfoOSDCB;		{GetFileInfoGS record}
   i: 1..8;				{loop/index counter}

begin {StartInclude}
if inhibitHeader then   
   TermHeader;
if not ignoreSymbols then begin
   includeLevel := includeLevel+1;
   if saveSource then begin
      if not includeMark then begin
	 includeMark := true;
	 SetMark;
	 end; {if}
      giRec.pCount := 7;
      giRec.pathname := pointer(ord4(name)+2);
      GetFileInfoGS(giRec);
      WriteLongString(pointer(giRec.pathname));
      for i := 1 to 8 do
	 WriteByte(giRec.createDateTime[i]);
      for i := 1 to 8 do
	 WriteByte(giRec.modDateTime[i]);
      end {if}
   else if not codeStarted then
      DestroySymbolFile;
   end; {if}
end; {StartInclude}


procedure TermHeader;

{ Stop processing the header file				}
{								}
{ Note: This is called when the first code-generating		}
{    subroutine is found, and again when the compile ends.  It	}
{    closes any open symbol file, and should take no action if	}
{    called twice.						}

begin {TermHeader}
if not ignoreSymbols then begin
   codeStarted := true;
   if saveSource then begin
      CloseSymbols;
      saveSource := false;
      dispose(buffer);
      end; {if}
   end; {if}
end; {TermHeader}

end.
