{ Copyright (c) 1998-2002 by Peter Vreman This unit implements the parsing of the switches like $I- 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 switches; {$i fpcdefs.inc} interface uses systems,globtype; procedure HandleSwitch(switch,state:char); function CheckSwitch(switch,state:char):boolean; procedure recordpendingverbosityswitch(sw: char; state: char); procedure recordpendingmessagestate(msg: longint; state: tmsgstate); procedure recordpendinglocalswitch(sw: tlocalswitch; state: char); procedure recordpendinglocalfullswitch(const switches: tlocalswitches); procedure recordpendingverbosityfullswitch(verbosity: longint); procedure recordpendingcallingswitch(const str: shortstring); procedure recordpendingalignmentfullswitch(const alignment : talignmentinfo); procedure recordpendingsetalloc(alloc:shortint); procedure recordpendingpackenum(size:shortint); procedure recordpendingpackrecords(size:shortint); procedure flushpendingswitchesstate; implementation uses cpuinfo, {$ifdef llvm} { override optimizer switches } llvminfo, {$endif llvm} globals,verbose,comphook,dirparse, fmodule; {**************************************************************************** Main Switches Parsing ****************************************************************************} type TSwitchType=(ignoredsw,localsw,modulesw,globalsw,illegalsw,unsupportedsw,alignsw,optimizersw,packenumsw,pentiumfdivsw,targetsw); SwitchRec=record typesw : TSwitchType; setsw : byte; end; SwitchRecTable = array['A'..'Z'] of SwitchRec; const turboSwitchTable: SwitchRecTable =( {A} (typesw:alignsw; setsw:ord(cs_localnone)), {B} (typesw:localsw; setsw:ord(cs_full_boolean_eval)), {C} (typesw:localsw; setsw:ord(cs_do_assertion)), {D} (typesw:modulesw; setsw:ord(cs_debuginfo)), {E} (typesw:modulesw; setsw:ord(cs_fp_emulation)), {$ifdef i8086} {F} (typesw:localsw; setsw:ord(cs_force_far_calls)), {$else i8086} {F} (typesw:ignoredsw; setsw:ord(cs_localnone)), {$endif i8086} {G} (typesw:localsw; setsw:ord(cs_imported_data)), {H} (typesw:localsw; setsw:ord(cs_refcountedstrings)), {I} (typesw:localsw; setsw:ord(cs_check_io)), {J} (typesw:localsw; setsw:ord(cs_typed_const_writable)), {$ifdef i8086} {K} (typesw:modulesw; setsw:ord(cs_win16_smartcallbacks)), {$else i8086} {K} (typesw:unsupportedsw; setsw:ord(cs_localnone)), {$endif i8086} {L} (typesw:unsupportedsw; setsw:ord(cs_localnone)), {M} (typesw:localsw; setsw:ord(cs_generate_rtti)), {N} (typesw:unsupportedsw; setsw:ord(cs_localnone)), {O} (typesw:optimizersw; setsw:ord(cs_opt_none)), {P} (typesw:modulesw; setsw:ord(cs_openstring)), {Q} (typesw:localsw; setsw:ord(cs_check_overflow)), {R} (typesw:localsw; setsw:ord(cs_check_range)), {S} (typesw:localsw; setsw:ord(cs_check_stack)), {T} (typesw:localsw; setsw:ord(cs_typed_addresses)), {U} (typesw:pentiumfdivsw; setsw:ord(cs_localnone)), {V} (typesw:localsw; setsw:ord(cs_strict_var_strings)), {$ifdef i8086} {W} (typesw:targetsw; setsw:ord(ts_x86_far_procs_push_odd_bp)), {$else i8086} {W} (typesw:localsw; setsw:ord(cs_generate_stackframes)), {$endif i8086} {X} (typesw:modulesw; setsw:ord(cs_extsyntax)), {Y} (typesw:unsupportedsw; setsw:ord(cs_localnone)), {Z} (typesw:packenumsw; setsw:ord(cs_localnone)) ); macSwitchTable: SwitchRecTable =( {A} (typesw:unsupportedsw; setsw:ord(cs_localnone)), {B} (typesw:localsw; setsw:ord(cs_full_boolean_eval)), {C} (typesw:localsw; setsw:ord(cs_do_assertion)), {D} (typesw:modulesw; setsw:ord(cs_debuginfo)), {E} (typesw:modulesw; setsw:ord(cs_fp_emulation)), {$ifdef i8086} {F} (typesw:localsw; setsw:ord(cs_force_far_calls)), {$else i8086} {F} (typesw:ignoredsw; setsw:ord(cs_localnone)), {$endif i8086} {G} (typesw:ignoredsw; setsw:ord(cs_localnone)), {H} (typesw:localsw; setsw:ord(cs_refcountedstrings)), {I} (typesw:localsw; setsw:ord(cs_check_io)), {J} (typesw:localsw; setsw:ord(cs_external_var)), {$ifdef i8086} {K} (typesw:modulesw; setsw:ord(cs_win16_smartcallbacks)), {$else i8086} {K} (typesw:unsupportedsw; setsw:ord(cs_localnone)), {$endif i8086} {L} (typesw:unsupportedsw; setsw:ord(cs_localnone)), {M} (typesw:localsw; setsw:ord(cs_generate_rtti)), {N} (typesw:unsupportedsw; setsw:ord(cs_localnone)), {O} (typesw:optimizersw; setsw:ord(cs_opt_none)), {P} (typesw:modulesw; setsw:ord(cs_openstring)), {Q} (typesw:localsw; setsw:ord(cs_check_overflow)), {R} (typesw:localsw; setsw:ord(cs_check_range)), {S} (typesw:localsw; setsw:ord(cs_check_stack)), {T} (typesw:localsw; setsw:ord(cs_typed_addresses)), {U} (typesw:illegalsw; setsw:ord(cs_localnone)), {V} (typesw:localsw; setsw:ord(cs_strict_var_strings)), {$ifdef i8086} {W} (typesw:targetsw; setsw:ord(ts_x86_far_procs_push_odd_bp)), {$else i8086} {W} (typesw:localsw; setsw:ord(cs_generate_stackframes)), {$endif i8086} {X} (typesw:modulesw; setsw:ord(cs_extsyntax)), {Y} (typesw:unsupportedsw; setsw:ord(cs_localnone)), {Z} (typesw:localsw; setsw:ord(cs_externally_visible)) ); procedure HandleSwitch(switch,state:char); var switchTablePtr: ^SwitchRecTable; begin switch:=upcase(switch); { Is the Switch in the letters ? } if not ((switch in ['A'..'Z']) and (state in ['-','+'])) then begin Message(scan_w_illegal_switch); exit; end; { Select switch table } if m_mac in current_settings.modeswitches then switchTablePtr:= @macSwitchTable else switchTablePtr:= @turboSwitchTable; { Handle the switch } with switchTablePtr^[switch] do begin case typesw of alignsw: if state='+' then current_settings.packrecords:=4 else current_settings.packrecords:=1; optimizersw : begin if state='+' then current_settings.optimizerswitches:=level2optimizerswitches else current_settings.optimizerswitches:=[]; end; ignoredsw : Message1(scan_n_ignored_switch,'$'+switch); illegalsw : Message1(scan_w_illegal_switch,'$'+switch); unsupportedsw : Message1(scan_w_unsupported_switch,'$'+switch); localsw : recordpendinglocalswitch(tlocalswitch(setsw),state); modulesw : begin if current_module.in_global then begin {$ifndef cpufpemu} if tmoduleswitch(setsw)=cs_fp_emulation then begin Message1(scan_w_unsupported_switch_by_target,'$'+switch); end else {$endif cpufpemu} begin if state='+' then include(current_settings.moduleswitches,tmoduleswitch(setsw)) else begin { Turning off debuginfo when lineinfo is requested is not possible } if not((cs_use_lineinfo in current_settings.globalswitches) and (tmoduleswitch(setsw)=cs_debuginfo)) then exclude(current_settings.moduleswitches,tmoduleswitch(setsw)); end; end; end else Message(scan_w_switch_is_global); end; globalsw : begin if current_module.in_global and (current_module=main_module) then begin if state='+' then include(current_settings.globalswitches,tglobalswitch(setsw)) else exclude(current_settings.globalswitches,tglobalswitch(setsw)); end else Message(scan_w_switch_is_global); end; packenumsw: begin if state='-' then current_settings.packenum:=1 else current_settings.packenum:=4; end; pentiumfdivsw: begin { Switch u- means pentium-safe fdiv off -> fpc default. We don't } { support u+ } if state='+' then Message1(scan_w_unsupported_switch,'$'+switch); end; targetsw: UpdateTargetSwitchStr(TargetSwitchStr[ttargetswitch(setsw)].name+state,current_settings.targetswitches,current_module.in_global); end; end; end; function CheckSwitch(switch,state:char):boolean; var found : boolean; switchTablePtr: ^SwitchRecTable; begin switch:=upcase(switch); { Is the Switch in the letters ? } if not ((switch in ['A'..'Z']) and (state in ['-','+'])) then begin Message(scan_w_illegal_switch); CheckSwitch:=false; exit; end; { Select switch table } if m_mac in current_settings.modeswitches then switchTablePtr:= @macSwitchTable else switchTablePtr:= @turboSwitchTable; { Check the switch } with switchTablePtr^[switch] do begin case typesw of localsw : found:=(tlocalswitch(setsw) in current_settings.localswitches); modulesw : found:=(tmoduleswitch(setsw) in current_settings.moduleswitches); globalsw : found:=(tglobalswitch(setsw) in current_settings.globalswitches); packenumsw : found := (current_settings.packenum = 4); else found:=false; end; if state='-' then found:=not found; CheckSwitch:=found; end; end; procedure recordpendingverbosityswitch(sw: char; state: char); begin pendingstate.nextverbositystr:=pendingstate.nextverbositystr+sw+state; end; procedure recordpendingmessagestate(msg: longint; state: tmsgstate); var pstate : pmessagestaterecord; begin new(pstate); pstate^.next:=pendingstate.nextmessagerecord; pstate^.value:=msg; pstate^.state:=state; pendingstate.nextmessagerecord:=pstate; end; procedure recordpendinglocalswitch(sw: tlocalswitch; state: char); begin if not (psf_local_switches_changed in pendingstate.flags) then pendingstate.nextlocalswitches:=current_settings.localswitches; if state='-' then exclude(pendingstate.nextlocalswitches,sw) else if state='+' then include(pendingstate.nextlocalswitches,sw) else { state = '*' } begin if sw in init_settings.localswitches then include(pendingstate.nextlocalswitches,sw) else exclude(pendingstate.nextlocalswitches,sw); end; include(pendingstate.flags,psf_local_switches_changed); end; procedure recordpendingalignmentfullswitch(const alignment : talignmentinfo); begin pendingstate.nextalignment:=alignment; include(pendingstate.flags,psf_alignment_changed); end; procedure recordpendinglocalfullswitch(const switches: tlocalswitches); begin pendingstate.nextlocalswitches:=switches; include(pendingstate.flags,psf_local_switches_changed); end; procedure recordpendingverbosityfullswitch(verbosity: longint); begin pendingstate.nextverbositystr:=''; pendingstate.nextverbosityfullswitch:=verbosity; include(pendingstate.flags,psf_verbosity_full_switched); end; procedure recordpendingcallingswitch(const str: shortstring); begin pendingstate.nextcallingstr:=str; end; procedure recordpendingsetalloc(alloc:shortint); begin pendingstate.nextsetalloc:=alloc; include(pendingstate.flags,psf_setalloc_changed); end; procedure recordpendingpackenum(size:shortint); begin pendingstate.nextpackenum:=size; include(pendingstate.flags,psf_packenum_changed); end; procedure recordpendingpackrecords(size:shortint); begin pendingstate.nextpackrecords:=size; include(pendingstate.flags,psf_packrecords_changed); end; procedure flushpendingswitchesstate; var tmpproccal: tproccalloption; fstate, pstate : pmessagestaterecord; begin { process pending localswitches (range checking, etc) } if psf_local_switches_changed in pendingstate.flags then begin current_settings.localswitches:=pendingstate.nextlocalswitches; exclude(pendingstate.flags,psf_local_switches_changed); end; { process pending verbosity changes (warnings on, etc) } if psf_verbosity_full_switched in pendingstate.flags then begin status.verbosity:=pendingstate.nextverbosityfullswitch; exclude(pendingstate.flags,psf_verbosity_full_switched); end; if psf_alignment_changed in pendingstate.flags then begin current_settings.alignment:=pendingstate.nextalignment; exclude(pendingstate.flags,psf_alignment_changed); end; if psf_packenum_changed in pendingstate.flags then begin current_settings.packenum:=pendingstate.nextpackenum; exclude(pendingstate.flags,psf_packenum_changed); end; if psf_packrecords_changed in pendingstate.flags then begin current_settings.packrecords:=pendingstate.nextpackrecords; exclude(pendingstate.flags,psf_packrecords_changed); end; if psf_setalloc_changed in pendingstate.flags then begin current_settings.setalloc:=pendingstate.nextsetalloc; exclude(pendingstate.flags,psf_setalloc_changed); end; { process pending verbosity changes (warnings on, etc) } if pendingstate.nextverbositystr<>'' then begin setverbosity(pendingstate.nextverbositystr); pendingstate.nextverbositystr:=''; end; fstate:=pendingstate.nextmessagerecord; pstate:=pendingstate.nextmessagerecord; while assigned(pstate) do begin pendingstate.nextmessagerecord:=pstate^.next; SetMessageVerbosity(pstate^.value,pstate^.state); if not assigned(pstate^.next) then begin pstate^.next:=current_settings.pmessage; current_settings.pmessage:=fstate; pstate:=nil; end else pstate:=pstate^.next; pendingstate.nextmessagerecord:=nil; end; { process pending calling convention changes (calling x) } if pendingstate.nextcallingstr<>'' then begin if not SetAktProcCall(pendingstate.nextcallingstr,tmpproccal) then Message1(parser_w_unknown_proc_directive_ignored,pendingstate.nextcallingstr) else if not(tmpproccal in supported_calling_conventions) then Message1(parser_e_illegal_calling_convention,pendingstate.nextcallingstr) else current_settings.defproccall:=tmpproccal; pendingstate.nextcallingstr:=''; end; end; end.