fpc/compiler/globstat.pas
2024-03-05 07:56:14 +00:00

261 lines
6.4 KiB
ObjectPascal

{
Copyright (c) 2012 by the FPC development team
Contains functionality to save/restore the global compiler state when
switching between the compilation of different units.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
unit globstat;
{$i fpcdefs.inc}
interface
uses
globtype,tokens,globals,
aasmdata,
dbgbase,
symbase,symsym,
fmodule,
scanner,scandir,
procinfo;
type
tglobalstate = class
{ scanner }
oldidtoken,
oldtoken : ttoken;
oldtokenpos : tfileposinfo;
oldc : char;
oldpattern,
oldorgpattern : string;
old_block_type : tblock_type;
{ symtable }
oldsymtablestack,
oldmacrosymtablestack : TSymtablestack;
oldaktprocsym : tprocsym;
{ cg }
oldparse_only : boolean;
{ akt.. things }
oldcurrent_filepos : tfileposinfo;
old_current_module : tmodule;
oldcurrent_procinfo : tprocinfo;
old_settings : tsettings;
old_switchesstatestack : tswitchesstatestack;
old_switchesstatestackpos : Integer;
old_verbosity : longint;
{ only saved/restored if "full" is true }
old_asmdata : tasmdata;
old_debuginfo : tdebuginfo;
old_scanner : tscannerfile;
old_parser_file : string;
constructor create(savefull : boolean);
destructor destroy; override;
procedure clearscanner;
class procedure remove_scanner_from_states(scanner : tscannerfile); static;
procedure save(full : boolean);
procedure restore(full : boolean);
end;
procedure save_global_state(state:tglobalstate;full:boolean);
procedure restore_global_state(state:tglobalstate;full:boolean);
implementation
uses
switches, verbose, pbase,comphook;
var
states : array of tglobalstate;
statecount : integer = 0;
class procedure tglobalstate.remove_scanner_from_states(scanner : tscannerfile);
var
i : integer;
begin
for I:=0 to statecount-1 do
if (states[i].old_scanner=scanner) then
states[i].clearscanner;
end;
procedure addstate(astate : tglobalstate);
var
l : integer;
begin
l:=length(states);
if l=statecount then
setlength(states,l+10);
states[statecount]:=astate;
inc(statecount);
end;
procedure removestate(astate : tglobalstate);
var
l : integer;
begin
l:=statecount-1;
While (l>=0) and (states[l]<>astate) do
dec(l);
if l<0 then
exit;
if l<>statecount-1 then
states[l]:=states[statecount-1];
states[statecount-1]:=Nil;
Dec(Statecount);
end;
procedure save_global_state(state:tglobalstate;full:boolean);
begin
state.save(full);
end;
procedure restore_global_state(state:tglobalstate;full:boolean);
begin
state.restore(full);
end;
procedure tglobalstate.save(full: boolean);
begin
old_current_module:=current_module;
{ save symtable state }
oldsymtablestack:=symtablestack;
oldmacrosymtablestack:=macrosymtablestack;
oldcurrent_procinfo:=current_procinfo;
{ save scanner state }
oldc:=c;
oldpattern:=pattern;
oldorgpattern:=orgpattern;
oldtoken:=token;
oldidtoken:=idtoken;
old_block_type:=block_type;
oldtokenpos:=current_tokenpos;
{
consuming the semicolon after a uses clause can add to the
pending state if the first directives change warning state.
So we must flush before context switch. See for example:
ppcgen/cgppc.pas
line 144 has a WARN 6018 OFF...
}
flushpendingswitchesstate;
old_switchesstatestack:=switchesstatestack;
old_switchesstatestackpos:=switchesstatestackpos;
{ save cg }
oldparse_only:=parse_only;
{ save akt... state }
{ handle the postponed case first }
oldcurrent_filepos:=current_filepos;
old_settings:=current_settings;
old_verbosity:=status.verbosity;
if full then
begin
old_asmdata:=current_asmdata;
old_debuginfo:=current_debuginfo;
old_parser_file:=parser_current_file;
old_scanner:=current_scanner;
end;
end;
procedure tglobalstate.restore(full: boolean);
begin
{ restore scanner }
c:=oldc;
pattern:=oldpattern;
orgpattern:=oldorgpattern;
token:=oldtoken;
idtoken:=oldidtoken;
current_tokenpos:=oldtokenpos;
block_type:=old_block_type;
switchesstatestack:=old_switchesstatestack;
switchesstatestackpos:=old_switchesstatestackpos;
{ restore cg }
parse_only:=oldparse_only;
{ restore symtable state }
symtablestack:=oldsymtablestack;
macrosymtablestack:=oldmacrosymtablestack;
current_procinfo:=oldcurrent_procinfo;
current_filepos:=oldcurrent_filepos;
current_settings:=old_settings;
status.verbosity:=old_verbosity;
{ restore message settings which were recorded prior to unit switch }
RestoreLocalVerbosity(current_settings.pmessage);
if full then
begin
set_current_module(old_current_module);
// These can be different
current_asmdata:=old_asmdata;
current_debuginfo:=old_debuginfo;
end;
end;
constructor tglobalstate.create(savefull: boolean);
begin
addstate(self);
save(savefull);
end;
destructor tglobalstate.destroy;
begin
removestate(self);
inherited destroy;
end;
procedure tglobalstate.clearscanner;
begin
old_scanner:=nil;
oldidtoken:=NOTOKEN;
oldtoken:=NOTOKEN;
oldtokenpos:=Default(tfileposinfo);
oldc:=#0;
oldpattern:='';
oldorgpattern:='';
old_block_type:=bt_none;
end;
initialization
onfreescanner:=@tglobalstate.remove_scanner_from_states;
finalization
onfreescanner:=Nil;
end.