summaryrefslogtreecommitdiff
path: root/compiler/parser.pas
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/parser.pas')
-rw-r--r--compiler/parser.pas613
1 files changed, 613 insertions, 0 deletions
diff --git a/compiler/parser.pas b/compiler/parser.pas
new file mode 100644
index 0000000000..8d5a6d06fb
--- /dev/null
+++ b/compiler/parser.pas
@@ -0,0 +1,613 @@
+{
+ Copyright (c) 1998-2002 by Florian Klaempfl
+
+ This unit does the parsing process
+
+ 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 parser;
+
+{$i fpcdefs.inc}
+
+interface
+
+{$ifdef PREPROCWRITE}
+ procedure preprocess(const filename:string);
+{$endif PREPROCWRITE}
+ procedure compile(const filename:string);
+ procedure initparser;
+ procedure doneparser;
+
+implementation
+
+ uses
+{$IFNDEF MACOS_USE_FAKE_SYSUTILS}
+ sysutils,
+{$ENDIF MACOS_USE_FAKE_SYSUTILS}
+ cutils,cclasses,
+ globtype,version,tokens,systems,globals,verbose,
+ symbase,symtable,symsym,
+ finput,fmodule,fppu,
+ aasmbase,aasmtai,
+ cgbase,
+ script,gendef,
+{$ifdef BrowserCol}
+ browcol,
+{$endif BrowserCol}
+{$ifdef BrowserLog}
+ browlog,
+{$endif BrowserLog}
+ comphook,
+ scanner,scandir,
+ pbase,ptype,psystem,pmodules,psub,
+ cresstr,cpuinfo,procinfo;
+
+
+ procedure initparser;
+ begin
+ { ^M means a string or a char, because we don't parse a }
+ { type declaration }
+ ignore_equal:=false;
+
+ { we didn't parse a object or class declaration }
+ { and no function header }
+ testcurobject:=0;
+
+ { Current compiled module/proc }
+ objectlibrary:=nil;
+ current_module:=nil;
+ compiled_module:=nil;
+ current_procinfo:=nil;
+ SetCompileModule(nil);
+
+ loaded_units:=TLinkedList.Create;
+
+ usedunits:=TLinkedList.Create;
+
+ { global switches }
+ aktglobalswitches:=initglobalswitches;
+
+ aktsourcecodepage:=initsourcecodepage;
+
+ { initialize scanner }
+ InitScanner;
+ InitScannerDirectives;
+
+ { scanner }
+ c:=#0;
+ pattern:='';
+ orgpattern:='';
+ current_scanner:=nil;
+
+ { register all nodes and tais }
+ registernodes;
+ registertais;
+
+ { memory sizes }
+ if stacksize=0 then
+ stacksize:=target_info.stacksize;
+
+ { open assembler response }
+ if cs_link_on_target in aktglobalswitches then
+ GenerateAsmRes(outputexedir+inputfile+'_ppas')
+ else
+ GenerateAsmRes(outputexedir+'ppas');
+
+ { open deffile }
+ DefFile:=TDefFile.Create(outputexedir+inputfile+target_info.defext);
+
+ { list of generated .o files, so the linker can remove them }
+ SmartLinkOFiles:=TStringList.Create;
+
+ { codegen }
+ if paraprintnodetree<>0 then
+ printnode_reset;
+
+ { target specific stuff }
+ case target_info.system of
+ system_powerpc_morphos:
+ include(supported_calling_conventions,pocall_syscall);
+ system_m68k_amiga:
+ include(supported_calling_conventions,pocall_syscall);
+ end;
+ end;
+
+
+ procedure doneparser;
+ begin
+ { Reset current compiling info, so destroy routines can't
+ reference the data that might already be destroyed }
+ objectlibrary:=nil;
+ current_module:=nil;
+ compiled_module:=nil;
+ current_procinfo:=nil;
+ SetCompileModule(nil);
+
+ { unload units }
+ loaded_units.free;
+ usedunits.free;
+
+ { if there was an error in the scanner, the scanner is
+ still assinged }
+ if assigned(current_scanner) then
+ begin
+ current_scanner.free;
+ current_scanner:=nil;
+ end;
+
+ { close scanner }
+ DoneScanner;
+
+ { close ppas,deffile }
+ asmres.free;
+ deffile.free;
+
+ { free list of .o files }
+ SmartLinkOFiles.Free;
+ end;
+
+
+
+
+{$ifdef PREPROCWRITE}
+ procedure preprocess(const filename:string);
+ var
+ i : longint;
+ begin
+ new(preprocfile,init('pre'));
+ { initialize a module }
+ current_module:=new(pmodule,init(filename,false));
+
+ macrosymtablestack:= initialmacrosymtable;
+ current_module.localmacrosymtable:= tmacrosymtable.create(false);
+ current_module.localmacrosymtable.next:= initialmacrosymtable;
+ macrosymtablestack:= current_module.localmacrosymtable;
+ ConsolidateMode;
+
+ main_module:=current_module;
+ { startup scanner, and save in current_module }
+ current_scanner:=new(pscannerfile,Init(filename));
+ current_module.scanner:=current_scanner;
+ { loop until EOF is found }
+ repeat
+ current_scanner^.readtoken;
+ preprocfile^.AddSpace;
+ case token of
+ _ID :
+ begin
+ preprocfile^.Add(orgpattern);
+ end;
+ _REALNUMBER,
+ _INTCONST :
+ preprocfile^.Add(pattern);
+ _CSTRING :
+ begin
+ i:=0;
+ while (i<length(pattern)) do
+ begin
+ inc(i);
+ if pattern[i]='''' then
+ begin
+ insert('''',pattern,i);
+ inc(i);
+ end;
+ end;
+ preprocfile^.Add(''''+pattern+'''');
+ end;
+ _CCHAR :
+ begin
+ case pattern[1] of
+ #39 :
+ pattern:='''''''';
+ #0..#31,
+ #128..#255 :
+ begin
+ str(ord(pattern[1]),pattern);
+ pattern:='#'+pattern;
+ end;
+ else
+ pattern:=''''+pattern[1]+'''';
+ end;
+ preprocfile^.Add(pattern);
+ end;
+ _EOF :
+ break;
+ else
+ preprocfile^.Add(tokeninfo^[token].str)
+ end;
+ until false;
+ { free scanner }
+ dispose(current_scanner,done);
+ current_scanner:=nil;
+ { close }
+ dispose(preprocfile,done);
+ end;
+{$endif PREPROCWRITE}
+
+
+{*****************************************************************************
+ Create information for a new module
+*****************************************************************************}
+
+ procedure init_module;
+ var
+ i : Tasmlist;
+ begin
+ exprasmlist:=taasmoutput.create;
+ for i:=low(Tasmlist) to high(Tasmlist) do
+ asmlist[i]:=Taasmoutput.create;
+
+ { PIC data }
+{$ifdef powerpc}
+ if target_info.system=system_powerpc_darwin then
+ asmlist[al_picdata].concat(tai_directive.create(asd_non_lazy_symbol_pointer,''));
+{$endif powerpc}
+
+ { Resource strings }
+ cresstr.resourcestrings:=Tresourcestrings.Create;
+
+ { use the librarydata from current_module }
+ objectlibrary:=current_module.librarydata;
+ end;
+
+
+ procedure done_module;
+ var
+{$ifdef MEMDEBUG}
+ d : tmemdebug;
+{$endif}
+ i:Tasmlist;
+ begin
+{$ifdef MEMDEBUG}
+ d:=tmemdebug.create(current_module.modulename^+' - asmlists');
+{$endif}
+ for i:=low(Tasmlist) to high(Tasmlist) do
+ if asmlist[i]<>nil then
+ asmlist[i].free;
+{$ifdef MEMDEBUG}
+ d.free;
+{$endif}
+ { resource strings }
+ cresstr.resourcestrings.free;
+ objectlibrary:=nil;
+ end;
+
+
+{*****************************************************************************
+ Compile a source file
+*****************************************************************************}
+
+ procedure compile(const filename:string);
+ type
+ polddata=^tolddata;
+ tolddata=record
+ { scanner }
+ oldidtoken,
+ oldtoken : ttoken;
+ oldtokenpos : tfileposinfo;
+ oldc : char;
+ oldpattern,
+ oldorgpattern : string;
+ old_block_type : tblock_type;
+ { symtable }
+ oldrefsymtable,
+ olddefaultsymtablestack,
+ oldsymtablestack : tsymtable;
+ olddefaultmacrosymtablestack,
+ oldmacrosymtablestack : tsymtable;
+ oldaktprocsym : tprocsym;
+ { cg }
+ oldparse_only : boolean;
+ { asmlists }
+ oldexprasmlist:Taasmoutput;
+ oldasmlist:array[Tasmlist] of Taasmoutput;
+ oldobjectlibrary : tasmlibrarydata;
+ { al_resourcestrings }
+ Oldresourcestrings : tresourcestrings;
+ { akt.. things }
+ oldaktlocalswitches : tlocalswitches;
+ oldaktmoduleswitches : tmoduleswitches;
+ oldaktfilepos : tfileposinfo;
+ oldaktpackrecords,
+ oldaktpackenum : shortint;
+ oldaktmaxfpuregisters : longint;
+ oldaktalignment : talignmentinfo;
+ oldaktspecificoptprocessor,
+ oldaktoptprocessor : tprocessors;
+ oldaktfputype : tfputype;
+ oldaktasmmode : tasmmode;
+ oldaktinterfacetype: tinterfacetypes;
+ oldaktmodeswitches : tmodeswitches;
+ old_compiled_module : tmodule;
+ oldcurrent_procinfo : tprocinfo;
+ oldaktdefproccall : tproccalloption;
+ oldsourcecodepage : tcodepagestring;
+ end;
+
+ var
+ olddata : polddata;
+ begin
+ inc(compile_level);
+ parser_current_file:=filename;
+ { Uses heap memory instead of placing everything on the
+ stack. This is needed because compile() can be called
+ recursively }
+ new(olddata);
+ with olddata^ do
+ begin
+ old_compiled_module:=compiled_module;
+ { save symtable state }
+ oldsymtablestack:=symtablestack;
+ oldmacrosymtablestack:=macrosymtablestack;
+ olddefaultsymtablestack:=defaultsymtablestack;
+ olddefaultmacrosymtablestack:=defaultmacrosymtablestack;
+ oldrefsymtable:=refsymtable;
+ oldcurrent_procinfo:=current_procinfo;
+ oldaktdefproccall:=aktdefproccall;
+ { save scanner state }
+ oldc:=c;
+ oldpattern:=pattern;
+ oldorgpattern:=orgpattern;
+ oldtoken:=token;
+ oldidtoken:=idtoken;
+ old_block_type:=block_type;
+ oldtokenpos:=akttokenpos;
+ oldsourcecodepage:=aktsourcecodepage;
+ { save cg }
+ oldparse_only:=parse_only;
+ { save assembler lists }
+ oldasmlist:=asmlist;
+ oldexprasmlist:=exprasmlist;
+ oldobjectlibrary:=objectlibrary;
+ Oldresourcestrings:=resourcestrings;
+ { save akt... state }
+ { handle the postponed case first }
+ if localswitcheschanged then
+ begin
+ aktlocalswitches:=nextaktlocalswitches;
+ localswitcheschanged:=false;
+ end;
+ oldaktlocalswitches:=aktlocalswitches;
+ oldaktmoduleswitches:=aktmoduleswitches;
+ oldaktalignment:=aktalignment;
+ oldaktpackenum:=aktpackenum;
+ oldaktpackrecords:=aktpackrecords;
+ oldaktfputype:=aktfputype;
+ oldaktmaxfpuregisters:=aktmaxfpuregisters;
+ oldaktoptprocessor:=aktoptprocessor;
+ oldaktspecificoptprocessor:=aktspecificoptprocessor;
+ oldaktasmmode:=aktasmmode;
+ oldaktinterfacetype:=aktinterfacetype;
+ oldaktfilepos:=aktfilepos;
+ oldaktmodeswitches:=aktmodeswitches;
+ end;
+ { show info }
+ Message1(parser_i_compiling,filename);
+
+ { reset symtable }
+ symtablestack:=nil;
+ macrosymtablestack:=nil;
+ defaultsymtablestack:=nil;
+ defaultmacrosymtablestack:=nil;
+ systemunit:=nil;
+ refsymtable:=nil;
+ aktdefproccall:=initdefproccall;
+ registerdef:=true;
+ aktexceptblock:=0;
+ exceptblockcounter:=0;
+ aktmaxfpuregisters:=-1;
+ { reset the unit or create a new program }
+ { a unit compiled at command line must be inside the loaded_unit list }
+ if (compile_level=1) then
+ begin
+ if assigned(current_module) then
+ internalerror(200501158);
+ current_module:=tppumodule.create(nil,filename,'',false);
+ addloadedunit(current_module);
+ main_module:=current_module;
+ current_module.state:=ms_compile;
+ end;
+ if not(assigned(current_module) and
+ (current_module.state in [ms_compile,ms_second_compile])) then
+ internalerror(200212281);
+
+ { Set the module to use for verbose }
+ compiled_module:=current_module;
+ SetCompileModule(current_module);
+ Fillchar(aktfilepos,0,sizeof(aktfilepos));
+
+ { Load current state from the init values }
+ aktlocalswitches:=initlocalswitches;
+ aktmoduleswitches:=initmoduleswitches;
+ aktmodeswitches:=initmodeswitches;
+ {$IFDEF Testvarsets}
+ aktsetalloc:=initsetalloc;
+ {$ENDIF}
+ aktalignment:=initalignment;
+ aktfputype:=initfputype;
+ aktpackenum:=initpackenum;
+ aktpackrecords:=0;
+ aktoptprocessor:=initoptprocessor;
+ aktspecificoptprocessor:=initspecificoptprocessor;
+ aktasmmode:=initasmmode;
+ aktinterfacetype:=initinterfacetype;
+
+ { startup scanner and load the first file }
+ current_scanner:=tscannerfile.Create(filename);
+ current_scanner.firstfile;
+ current_module.scanner:=current_scanner;
+
+ { init macros before anything in the file is parsed.}
+ macrosymtablestack:= initialmacrosymtable;
+ current_module.localmacrosymtable:= tmacrosymtable.create(false);
+ current_module.localmacrosymtable.next:= initialmacrosymtable;
+ macrosymtablestack:= current_module.localmacrosymtable;
+
+ { read the first token }
+ current_scanner.readtoken;
+
+ { init code generator for a new module }
+ init_module;
+
+ { If the compile level > 1 we get a nice "unit expected" error
+ message if we are trying to use a program as unit.}
+ try
+ try
+ if (token=_UNIT) or (compile_level>1) then
+ begin
+ current_module.is_unit:=true;
+ proc_unit;
+ end
+ else
+ proc_program(token=_LIBRARY);
+ except
+ on ECompilerAbort do
+ raise;
+ on Exception do
+ begin
+ { Increase errorcounter to prevent some
+ checks during cleanup }
+ inc(status.errorcount);
+ raise;
+ end;
+ end;
+ finally
+ { restore old state }
+ done_module;
+
+ if assigned(current_module) then
+ begin
+ { module is now compiled }
+ tppumodule(current_module).state:=ms_compiled;
+
+ { free ppu }
+ if assigned(tppumodule(current_module).ppufile) then
+ begin
+ tppumodule(current_module).ppufile.free;
+ tppumodule(current_module).ppufile:=nil;
+ end;
+
+ { free scanner }
+ if assigned(current_module.scanner) then
+ begin
+ if current_scanner=tscannerfile(current_module.scanner) then
+ current_scanner:=nil;
+ tscannerfile(current_module.scanner).free;
+ current_module.scanner:=nil;
+ end;
+ end;
+
+ if (compile_level>1) then
+ begin
+ with olddata^ do
+ begin
+ { restore scanner }
+ c:=oldc;
+ pattern:=oldpattern;
+ orgpattern:=oldorgpattern;
+ token:=oldtoken;
+ idtoken:=oldidtoken;
+ akttokenpos:=oldtokenpos;
+ block_type:=old_block_type;
+ { restore cg }
+ parse_only:=oldparse_only;
+ { restore asmlists }
+ exprasmlist:=oldexprasmlist;
+ asmlist:=oldasmlist;
+ { object data }
+ resourcestrings:=oldresourcestrings;
+ objectlibrary:=oldobjectlibrary;
+ { restore previous scanner }
+ if assigned(old_compiled_module) then
+ current_scanner:=tscannerfile(old_compiled_module.scanner)
+ else
+ current_scanner:=nil;
+ if assigned(current_scanner) then
+ parser_current_file:=current_scanner.inputfile.name^;
+ { restore symtable state }
+ refsymtable:=oldrefsymtable;
+ symtablestack:=oldsymtablestack;
+ macrosymtablestack:=oldmacrosymtablestack;
+ defaultsymtablestack:=olddefaultsymtablestack;
+ defaultmacrosymtablestack:=olddefaultmacrosymtablestack;
+ aktdefproccall:=oldaktdefproccall;
+ current_procinfo:=oldcurrent_procinfo;
+ aktsourcecodepage:=oldsourcecodepage;
+ aktlocalswitches:=oldaktlocalswitches;
+ aktmoduleswitches:=oldaktmoduleswitches;
+ aktalignment:=oldaktalignment;
+ aktpackenum:=oldaktpackenum;
+ aktpackrecords:=oldaktpackrecords;
+ aktmaxfpuregisters:=oldaktmaxfpuregisters;
+ aktoptprocessor:=oldaktoptprocessor;
+ aktspecificoptprocessor:=oldaktspecificoptprocessor;
+ aktfputype:=oldaktfputype;
+ aktasmmode:=oldaktasmmode;
+ aktinterfacetype:=oldaktinterfacetype;
+ aktfilepos:=oldaktfilepos;
+ aktmodeswitches:=oldaktmodeswitches;
+ aktexceptblock:=0;
+ exceptblockcounter:=0;
+ end;
+ end
+ else
+ begin
+ { Shut down things when the last file is compiled succesfull }
+ if (compile_level=1) and
+ (status.errorcount=0) then
+ begin
+ parser_current_file:='';
+ { Close script }
+ if (not AsmRes.Empty) then
+ begin
+ Message1(exec_i_closing_script,AsmRes.Fn);
+ AsmRes.WriteToDisk;
+ end;
+
+ { do not create browsers on errors !! }
+ if status.errorcount=0 then
+ begin
+{$ifdef BrowserLog}
+ { Write Browser Log }
+ if (cs_browser_log in aktglobalswitches) and
+ (cs_browser in aktmoduleswitches) then
+ begin
+ if browserlog.elements_to_list.empty then
+ begin
+ Message1(parser_i_writing_browser_log,browserlog.Fname);
+ WriteBrowserLog;
+ end
+ else
+ browserlog.list_elements;
+ end;
+{$endif BrowserLog}
+ { Write Browser Collections, also used by the TextMode IDE to
+ retrieve a list of sourcefiles }
+ do_extractsymbolinfo{$ifdef FPC}(){$endif};
+ end;
+ end;
+ end;
+
+ dec(compile_level);
+ compiled_module:=olddata^.old_compiled_module;
+ SetCompileModule(compiled_module);
+
+ dispose(olddata);
+ end;
+ end;
+
+end.