{ MODULE 3 Option Handling A number of features of the Static Checker can be controlled as a set of options modelled by the type OptionType. The set of options for this implementation is relatively small, being concerned only with language level, source input margin setting, listing genera- tion, directive recognition, secondary source input, runtime check generation and postmortem dump generation. Values of the type OptionType are sub-classified into options which, by being essentially 'on' or 'off', are Boolean by nature, and options which by possessing an associated integer-value, are integer by nature. These two sub-groups are represented by subranges BoolOptionType and IntOptionType. Boolean-valued options are held as the set variables Requested and LocallyRequested. The former represents global option values which must remain fixed throughout analysis, and the latter represents the current values of those options which may vary from one part of the program to another. The value associated with each integer option is stored in the array variable OptionValue. In this ver- sion of the Static Checker, Boolean options are available to con- trol generation of the listing output file, runtime checks and postmortem dumps, and two integer options are available to control source-line scanning and language conformance level. Initial option values and the values of variables LocallyRequested and Requested are set by the procedure InitOptions. The initial setting may be overridden by supplying an option-list in the text file OptionFile. The syntax of the option-list is given by the rules: optionlist = option ... ',' option ... option = integer-option|boolean-option. integer-option = optionname '=' option-value. option-name = 'MARGIN' | 'LEVEL'. option-value = unsigned-integer. boolean-option = ('LIST'|'DIRECTIVES'|'IMPORTS'| 'CHECKS'|'PMD') ('+'|'-'). where: LEVEL=n sets the language conformance level to n. Only 0, 1, 2, or 3 are recognised as valid option-values in this context. 0 and 1 indicate ISO Standard Confor- mance Levels 0 and 1, 2 indicates ISO + ICL exten- sions, and 3 indicates ISO + ICL + 'in-house' extensions. MARGIN=n informs the source-input handler to scan only the first n characters of the source-line. This option is ignored in this implementation, and lines of unlimited length can be read. LIST+ enables generation of the listing output file. LIST- disables generation of the listing output file. DIRECTIVES+ enables recognition of embedded ICL source direc- tives, and UNIX pre-processor directives flagged by #. DIRECTIVES- suppresses recognition of embedded source direc- tives. IMPORTS+ enables listing of external source text. IMPORTS- suppresses listing of external source text. CHECKS+ enables generation of runtime checking code. CHECKS- disables generation of runtime checking code. PMD+ enables generation of a postmortem dump after pro- gram execution. PMD- disables generation of a postmortem dump after pro- gram execution. For example: LIST+,IMPORTS+,DIRECTIVES+,LEVEL=2 initializes the global options so that listing of both primary and secondary source input is enabled, embedded directives are recog- nised, and language conformance level is set to 2 for ICL exten- sions. An invalid option value or inappropriate option setting causes a warning message to be placed in the variable Warning, and the boolean flag WarningsToReport to be set true. Errors in the global option settings are reported by inserting the warning mes- sage into the initial banner heading at the start of the listing file. The default settings for each of the options is equivalent to:- LIST+,IMPORTS-,DIRECTIVES+,LEVEL=2 The Boolean options LIST and IMPORTS may also be reset during analysis by the ICL embedded directive ***LIST. In particular, LIST(SHORT) sets LIST-,IMPORTS- LIST(SHORTLIST) " LIST-,IMPORTS- LIST(NORMAL) " LIST+,IMPORTS- LIST(LIST) " LIST+,IMPORTS- LIST(FULL) " LIST+,IMPORTS+ Note that SHORT is a synonym for SHORTLIST, and NORMAL is a synonym for LIST. Any attempt to reset other options in this way is ignored. } program OptionHandler; #include "globals.x" #include "fileio.pf" #include "source.pf" #include "main.pf" procedure SetOptions(Mode: OptionContext); procedure ListOfOptions(var OptionSet: SetOfOptions; Available: SetOfOptions); label 13; procedure OptionError(OptionCode: Scalar); var i: Scalar; begin Terminate(Arg4); reset(ErrorFile, Arg4); if eof(ErrorFile) then OptionWarning := FileWarning else begin for i := 1 to (OptionBase + OptionCode - 1) * LinesPerText do readln(ErrorFile); for i := 1 to BannerTitleSize do begin OptionWarning[i] := ErrorFile^; if not eoln(ErrorFile) then get(ErrorFile) end end; AnyWarningsToReport := true; goto 13 end { optionerror }; procedure NextOpCh; begin if Mode = Locally then begin NextCh; OptionCh := Ch end else if eof(OptionFile) then OptionError(1) else begin get(OptionFile); if not eof(OptionFile) then OptionCh := OptionFile^ end end { nextopch }; procedure OpSelection(Option: OptionType; Selected: Boolean); begin if not (Option in [Listing..PMDump]) then OptionError(2) else if not (Option in Available) then OptionError(3) else if Selected then OptionSet := OptionSet + [Option] else OptionSet := OptionSet - [Option] end { opselection }; procedure OpValue(Option: OptionType); var Velue, DigitCount: integer; begin if not (Option in [Level..Margin]) then OptionError(4) else begin Velue := 0; DigitCount := 0; while OptionCh in ['0'..'9'] do begin DigitCount := DigitCount + 1; Velue := Velue * 10 + ord(OptionCh) - ord('0'); NextOpCh end; if DigitCount = 0 then OptionError(5) else case Option of Level : if Velue > Level3 then OptionError(7); Margin : if Velue > LineMax then OptionError(8) end; OptionValue[Option] := Velue end end { opvalue }; procedure NextOption; var Index: OptionType; i: 0..OptionSize; OptionName: OptionString; procedure NextOrBlank; var CharsLeft: Boolean; begin CharsLeft := true; while (OptionCh = ' ') and CharsLeft do begin CharsLeft := not eof(OptionFile); if CharsLeft then NextOpCh end end { nextorblank }; begin OptionName := UnknownOption; i := 0; NextOrBlank; while (i < OptionSize) and (OptionCh in ['A'..'Z']) do begin i := i + 1; OptionName[i] := OptionCh; NextOpCh end; OptionMap[Other].Name := OptionName; Index := Listing; while OptionMap[Index].Name <> OptionName do Index := succ(Index); with OptionMap[Index] do if Option = Other then OptionError(9) else begin if OptionCh in ['+', '-', '='] then begin case OptionCh of '+', '-' : begin OpSelection(Option, OptionCh = '+'); NextOpCh end; '=' : begin NextOpCh; OpValue(Option) end end; NextOrBlank end else OptionError(10) end end { nextoption }; begin { listofoptions } while true do begin NextOption; if OptionCh <> ',' then goto 13; NextOpCh end; 13 : end { listofoptions }; begin { setoptions } if Mode = Globally then ListOfOptions(Requested, [Listing..Margin]) else ListOfOptions(LocallyRequested, [Listing]) end { setoptions }; procedure SetGlobalOptions; begin Requested := [Listing,Directives]; Terminate(Arg3); reset(OptionFile, Arg3); if not eof(OptionFile) then begin OptionCh := OptionFile^; SetOptions(Globally) end; close(OptionFile) end { setglobaloptions }; procedure SetLocalOptions(NewOptions: SetOfOptions); visible; begin LocallyRequested := NewOptions end { setlocaloptions }; procedure InitOptions; visible; var i: ArgIndex; procedure InitBlankString; var i: ArgIndex; begin for i := 1 to MaxArgString do BlankString[i] := ' '; end { InitBlankString }; procedure argv(ArgNum: Scalar; var Argument: ArgString); var c: char; begin Argument := BlankString; i := 1; c := pargv^[ArgNum]^[i]; while c <> chr(Null) do begin Argument[i] := c; i := i + 1; c := pargv^[ArgNum]^[i] end end { argv }; procedure EnterOpNames; var OpClass: OptionClass; procedure Enter(OpName: AlfaHead; OpType: OptionType); begin with OptionMap[OpType] do begin Name := OpName; Option := OpType; Class := OpClass end end { enter }; begin { enteropnames } OpClass := BoolClass; Enter('LIST ', Listing); Enter('DIRECTIVES ', Directives); Enter('IMPORTS ', Imports); Enter('CHECKS ', Checks); Enter('PMD ', PMDump); OpClass := IntClass; Enter('LEVEL ', Level); Enter('MARGIN ', Margin); Enter(' ', Other) end { enteropnames }; procedure EnterOpValues; begin OptionValue[Level] := Level2; OptionValue[Margin] := LineMax end { enteropvalues }; procedure EnterDirNames; var Flag: DirectiveString; i: 1..3; Ch: char; procedure Enter(Name: DirectiveString; Directive: ICLDirectives); var i: 4..12; ThisName: DirectiveString; begin ThisName := Flag; for i := 4 to 12 do ThisName[i] := Name[i-3]; DirName[Directive] := ThisName end { Enter }; begin DirName[DoInclude] := '#include '; Flag := ' '; DirChars := ['A'..'Z', 'a'..'z', '#']; for i := 1 to 3 do begin Ch := Arg5[i+2]; if Ch = ' ' then Ch := '*'; DirChars := DirChars + [Ch]; Flag[i] := Ch end; Enter('READ ', DoRead); Enter('PAGE ', DoPage); Enter('LINES ', DoLines); Enter('HEADING ', DoHeading); Enter('LIST ', DoList); Enter(' ', DoNothing) end { EnterDirNames }; begin { initoptions } InitBlankString; argv(1, Arg1); { source file name } argv(2, Arg2); { listing file name } argv(3, Arg3); { option file name } argv(4, Arg4); { error file name } argv(5, Arg5); { directive flag } argv(6, Arg6); { listing heading } AnyWarningsToReport := false; EnterOpNames; EnterOpValues; EnterDirNames; SetGlobalOptions; ICLPascal := OptionValue[Level] >= Level2; InHousePascal := OptionValue[Level] >= Level3; LocallyRequested := Requested - (Requested - [Listing, Imports]) end { initoptions }; begin { end of module } end.