!#if  ~(d!e)(=false)
{  #report One of d or e must be set}
!#fi
!#if  (d&e)(=false)
{  #report Only one of d or e may be set}
!#fi
!#if  x(=false)
{#report Debugging code added}
!#fi
!#if  d(=false)
{!DEIMOS declerations}
{%systemroutinespec exit(%integer fault)}
{%externalstring(255)%mapspec cli param}
{%conststring(8) date="00/00/00"}
{%conststring(8) time="00:00:00"}
!#fi
!#if  e(=true)
!#else(=false)
{  #report Preparing DEIMOS version of PREP}
!#fi
!#if  e(=true)
!Emas declerations
%EXTERNALSTRINGFUNCTIONSPEC date %ALIAS "S#DATE"
%EXTERNALSTRINGFUNCTIONSPEC time %ALIAS "S#TIME"
%EXTERNALROUTINESPEC set return code %ALIAS "S#SETRETURNCODE"(%INTEGER n)
%ROUTINE define(%STRING (255) s)
   %EXTERNALROUTINESPEC emas3(%STRINGNAME command,params, %INTEGERNAME flag)
   %INTEGER flag
   emas3("DEFINE",s,flag)
%END;                                    ! Of %ROUTINE define.
%ROUTINE destroy(%STRING (255) s)
   %EXTERNALROUTINESPEC emas3(%STRINGNAME command,params, %INTEGERNAME flag)
   %INTEGER flag
   emas3("DESTROY",s,flag)
%END;                                    ! Of %ROUTINE destroy.
%EXTERNALINTEGERFUNCTIONSPEC exist %ALIAS "S#EXIST"(%STRING (255) file)
!%EXTERNALINTEGERFNSPEC iocp %ALIAS "S#IOCP" (%INTEGER ep, parm)
!#fi

%OWNSTRING (255) expression
%OWNSTRING (255) initstr
%OWNINTEGER expindex,expchar,errflag,line no,hash present
%OWNBYTEINTEGERARRAY vars(0:25)=0(26)
%OWNINTEGER cleanflag;                   !non zero => don't print unwanted code
!#if  e(=true)
%CONSTINTEGER report=0,input=10,output=11
!#fi
!#if  d(=false)
{%constinteger report=0,input=1,output=1}
!#fi


%INTEGERFN to lc(%INTEGER i)
!---------------------------
!
!Convert UC character to lower case

   %IF 'A'<=i<='Z' %THENRESULT = i+'a'-'A' %ELSERESULT = i

%END
%STRING (255) %FN subs(%INTEGER i, %STRING (255) %NAME s)
!---------------------------------------------------
!
!Returns substring of s starting at position i
   %INTEGER n
   %STRING (255) x

   x = ""
   %RESULT = "" %IF length(s)<i
   %FOR n = i,1,length(s) %CYCLE
      x = x.tostring(charno(s,n))
   %REPEAT
   %RESULT = x
%END

%INTEGERFN starts(%STRING (255) %NAME s, %STRING (255) ss)
!-------------------------------------------
!return 1 if s starts with ss
   %INTEGER i,l
   %RESULT = 0 %IF length(s)<2
   l = 1
   l = l+1 %WHILE charno(s,l)=' ' %AND l+length(ss)<=length(s)
   l = l-1

   %IF length(ss)+l>length(s) %THENRESULT = 0
   %FOR i = 1,1,length(ss) %CYCLE
      %IF to lc(charno(s,i+l))#charno(ss,i) %THENRESULT = 0
   %REPEAT
   %RESULT = length(ss)+l+1
%END

%ROUTINE getline(%STRING (255) %NAME s, %INTEGER skipping)
!--------------------------------------
   %STRING (255) mess
   %INTEGER a
!#if  ~e(=false)
   %INTEGER c
x: s = ""
   readsymbol(c)
   %WHILE c#nl %CYCLE
      s = s.to string(c)
      readsymbol(c)
   %REPEAT
!#else(=true)
!x: s=string(iocp(6,0))
!   %IF length(s)>0 %THEN length(s)=length(s)-1
!#fi
   line no = line no+1
   %RETURNIF skipping=0
                                         ! code to speed up prep
   hash present = 0
   %IF s#"" %START
      %CYCLE a = 1,1,length(s)
         %IF charno(s,a)='#' %THEN hash present = 1 %ANDEXIT
      %REPEAT
   %FINISH
   %RETURNIF hash present=0;             ! no '#' in line


!#if  d(=false)
   {   %if starts(s,"#datestring")#0 %or starts(s,"#timestring")#0 %start}
   {      select output(report)}
   {      printstring("Date/Time can not be set correctly from DEIMOS version")}
   {      newline}
   {      select output(output)}
   {   %finish}
!#fi
   %IF starts(s,"#datestring")#0 %THEN %C
      s = "%conststring (8) datestring=""".date.""""
   %IF starts(s,"#timestring")#0 %THEN %C
      s = "%conststring (8) timestring=""".time.""""
   %IF starts(s,"#options")#0 %START
      s = "! Options used:".initstr
   %FINISH
   %IF starts(s,"#report")#0 %START
      mess = subs(starts(s,"#report"),s)
      select output(report)
      printstring(mess)
      newline
      select output(output)
      ->x
   %FINISH
   %IF starts(s,"#abort")#0 %THENSIGNAL 1
%END

%ROUTINE error
!-------------
   %IF errflag=1 %THENRETURN
   expchar = -1;                         !force termination of expression
   selectoutput(0)
   printstring("line"); write(line no,4)
   printstring("error in :-".expression)
   newline
   selectoutput(11)
   errflag = 1
%END

%ROUTINE getchar
!---------------
   %CYCLE
      %IF expindex>=length(expression) %THEN expchar = -1 %ANDRETURN
      expindex = expindex+1
      expchar = charno(expression,expindex)
   %REPEATUNTIL expchar#' '
   %IF 'a'<=expchar<='z' %THEN expchar = expchar-'a'+'A'
%END

%INTEGERFNSPEC operand

%INTEGERFN evaluate
!------------------
   %INTEGER x
   x = operand
   %WHILE expchar='&' %OR expchar='!' %CYCLE
      %IF expchar='&' %START
         getchar
         x = x&operand
      %FINISHELSESTART
         getchar
         x = x!operand
      %FINISH
   %REPEAT
   %RESULT = x
%END

%INTEGERFN operand
!-----------------
   %INTEGER x
   %IF expchar<0 %THENRESULT = 0
   %IF expchar='(' %START
      getchar
      x = evaluate
      %IF expchar#')' %THEN error %ANDRESULT = 0
      getchar
      %RESULT = x
   %FINISH
   %IF 'A'<=expchar<='Z' %START
      x = vars(expchar-'A')
      getchar
      %RESULT = x
   %FINISH
   %IF expchar='~' %START
      getchar
      %RESULT = 1-operand
   %FINISH
   error
   %RESULT = 0
%END

%ROUTINE put(%INTEGER x)
!-----------------------
   %IF x=0 %THEN printstring("(=false)") %ELSE printstring("(=true)")
%END

%ROUTINE commentout(%STRING (*) %NAME s)
!---------------------------------------
   %IF cleanflag#0 %THENRETURN
   printstring("{".s."}")
   newline
%END

%ROUTINE skip fi
!--------------
   %STRING (255) text
   %CYCLE
      getline(text,0)
      commentout(text)
      %IF starts(text,"#if")#0 %THEN skipfi
   %REPEATUNTIL starts(text,"#fi")#0
%END

%ROUTINE putout(%STRING (255) %NAME s)
!-------------------------------------
!print string unless ERCC type comment {xyz}
   %INTEGER val,i,c
   %IF s="" %THEN newline %ANDRETURN
   %IF charno(s,1)='{' %START
      val = 0;                           !line not wanted
      i = 2
      %CYCLE
         %IF i>length(s) %THEN val = 1 %ANDEXIT
         c = charno(s,i); i = i+1
         %IF c='}' %THENEXIT;            !valid ERCC type comment
         %IF 'a'<=c<='z' %THEN c = c-'a'+'A'
         %IF 'A'<=c<='Z' %THEN val = val!vars(c-'A') %ELSE val = 1 %ANDEXIT
      %REPEAT
      %IF val=0 %START;                  !line not wanted
         %IF cleanflag#0 %THENRETURN
         charno(s,1) = '!'
         charno(s,i-1) = '!'
      %FINISH
   %FINISH
   printstring(s);
   newline

%END

%ROUTINE do if(%STRING (255) %NAME s)
!------------------------------------
   %INTEGER val
   %STRING (255) text
   expression = subs(starts(s,"#if"),s)
   expindex = 0; errflag = 0; getchar
   val = evaluate
   %IF errflag#0 %THEN val = 0;          !error
   %IF cleanflag=0 %START
      printstring("!#if ".expression)
      put(val); newline
   %FINISH
   %CYCLE
      getline(text,val)
      %IF starts(text,"#else")#0 %START
         val = 1-val
         %IF cleanflag=0 %START
            printstring("!".text)
            put(val)
            newline
         %FINISH
      %FINISHELSEIF starts(text,"#fi")#0 %START
         %IF cleanflag=0 %START
            printstring("!".text)
            newline
         %FINISH
         %EXIT
      %FINISHELSESTART
         %IF val=0 %START
            commentout(text)
            %IF starts(text,"#if")#0 %THEN skip fi
         %FINISHELSESTART
            %IF starts(text,"#if")#0 %THEN do if(text) %ELSE putout(text)
         %FINISH
      %FINISH
   %REPEAT
%END

%ROUTINE param(%STRING (255) %NAME s)
!------------------------------------
   %INTEGER c
!#if  x(=false)
   {   printstring("Param: ")}
   {   printstring(s)}
   {   newline}
!#fi
   %IF s="" %THENRETURN
   %IF s="CLEAN" %THEN cleanflag = 1 %ANDRETURN
   c = charno(s,1)
   %IF 'a'<=c<='z' %THEN c = c-'a'+'A'
   %IF 'A'<=c<='Z' %START
      vars(c-'A') = 1
   %FINISHELSESTART
      printstring("Illegal parameters, use: infile,outfile,letter,letter...")
      %STOP
   %FINISH
%END

!#if  e(=true)
%EXTERNALROUTINE prep(%STRING (255) s)
!#else(=false)
   {%begin}
   {%string(255) s}
!#fi
!this routine is a pre-processor for imp11 programs, it provides a
!conditional compilation facility. The first parameter is the source
!file name, the second parameter is the output file. If the output
!file is not specified <input file>#p is used. The remaining
!parameters are taken to be booleans (all true) to control the
!generation of the text. Booleans not in the parameter list are taken
!to be false. The conditional generation is controlled by lines
!begining with # i.e.
!#if <boolean exp>
!#else
!#fi
!#datestring      this is changed to a conststring declaration
!                 containing the date   %CONSTSTRING(9) datestring='.....'
!#timestring      similarily returns a time declaration
!
!The #if construct can be nested but this only is evaluated in the 'true'
!case. The boolean operators are &, ! and ~.
!the precedence is ~ first then & and ! (left to right) brackets
!may be used. Null operands evaluate to false.
!
!
!for example    PREP(infile,outfile,k,r)      the booleans k and r are true
!Within the file expressions such as
!    #if (k!x) & r
!may be used
!
!
   %STRING (255) t,infile,outfile,text

   %ONEVENT 1,9 %START
!#if  e(=true)
      %IF event inf>>8=1 %START
         select output(0)
         printstring("Run aborted after ")
         write(line no-1,3)
         printstring(" lines")
         newline
         set return code(1)
         %STOP
      %FINISH
      select output(0)
      close stream(output)
!#fi
!#if  d(=false)
      {   %if event_event=1 %start}
      {      select output(0)}
      {      printstring("Run aborted after ")}
      {      write(line no-1,3)}
      {      printstring(" lines")}
      {      exit(1)}
      {   %finish}
      {   close output}
      {   select output(0)}
!#fi
      write(line no-1,3); printstring(" lines processed"); newline
      %STOP
   %FINISH


   printstring("Prep version 3.0")
   newline
!#if  e(=true)
   initstr = s;                          ! keep for later
   infile = s
   outfile = ""
   %IF infile->infile.(",").outfile %START
      %IF outfile->outfile.(",").s %START
         %WHILE s->t.(",").s %CYCLE
            param(t)
         %REPEAT
         param(s)
      %FINISH
   %FINISH
   %IF infile="" %THEN printstring("No input!!") %ANDSTOP
   %IF charno(infile,1)#'.' %AND exist(infile)=0 %START
      printstring(infile." not there")
      newline
      %STOP
   %FINISH
   %IF outfile="" %START
      %IF charno(infile,1)='.' %THEN printstring("No output!!") %ANDSTOP
      outfile = infile."#P"
      printstring("Output file=".outfile)
      newline
   %FINISH
   %IF exist(outfile)#0 %THEN destroy(outfile)
   define("10,".infile)
   define("11,".outfile)
!#fi
!#if  d(=false)
   {   s=cli param}
   {   initstr = s}
   {#if x}
   {   printstring("Input command :")}
   {   printstring(s)}
   {   newline}
   {#fi}
   {  s="" %unless s->(":").s}
   {   %while s->t.(",").s %cycle}
   {     param(t)}
   {   %repeat}
   {   param(s)}
!#fi
   selectinput(input)
   selectoutput(output)

   line no = 0
   %CYCLE
      getline(text,1)
      %IF hash present#0 %AND starts(text,"#if")#0 %THEN do if(text) %ELSE %C
         putout(text)
      %EXITIF text="%endofprogram"
   %REPEAT

%END

%ENDOFFILE