home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / TURBO5.ZIP / IF.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1986-12-26  |  10.8 KB  |  270 lines

  1. program IfTest;
  2. {$C-} {$I-}
  3. { Process a command line "IF" statement in to a boolean variable and set the CP/M Plus error codes correspondingly.
  4.   Syntax allows for full operator precedence and parenthesis.  Any file matching a file specification returns true.
  5.   Valid operators are '&' for a logical AND, '|' for a logical OR, and '~' for a logical NOT.  For example, to allow
  6.   the next conditional submit line to execute if there are no *.BAK files but there are either *.ASM or *.MAC files on
  7.   the default drive, use the following line:
  8.          IF ~ *.BAK & (*.ASM | *.MAC)
  9.   Remember that any submit line which is preceeded by a ":" will only be used if the Error Code from the program on the
  10.   previous line of the submit file returned a true value.  Thus if you wish to use PIP to copy the *.PAS files if there
  11.   are no *.BAK files on A:, use the following lines in your submit file:
  12.          IF ~ A:*.BAK
  13.          :PIP C:=A:*.PAS
  14.   This program requires a simple loader to be written in assembly language and tacked in front
  15.   of the resulting command file in order to save the full command line before calling the Turbo Pascal
  16.   program since Turbo destroys part of the command line during execution.  The assembly portion is:
  17.  
  18.          ; Assembly language portion of IF.PAS
  19.          ;
  20.          ; Required so that entire command line tail is saved before entering
  21.          ; Turbo Pascal since Turbo destroys all but very beginning of command
  22.          ; line.
  23.          ;
  24.          ; All that this module does is move the command line to 3E80h and then
  25.          ; moves the Pascal program to 100h and executes it.  It will run only
  26.          ; on a Z80 system.
  27.          ;
  28.  
  29.          ; First, start by move the command line and this program itself up to higher memory.
  30.                  org  100h
  31.                  lxi  b,256
  32.                  lxi  d,3E80h
  33.                  lxi  h,0080h
  34.                  db   0EDh,0B0h
  35.                  jmp  3F20h
  36.  
  37.          ; Now move the Pascal program down to 100h -- Notice that this portion will actually
  38.          ; be executed at 3F20h after being moved by above portion of code.
  39.                  org  120h
  40.                  lxi  b,3D00h
  41.                  lxi  d,0100h
  42.                  lxi  h,0180h
  43.                  db   0EDh,0B0h
  44.                  jmp  100h
  45.                  end
  46.  
  47.   To assemble this fragment of assembly language, pull it into a file of its own called IF1.ASM
  48.   and use MAC to assemble it as follows:
  49.          A>MAC IF1 $PZ SZ
  50.   Then convert the resulting IF1.HEX into IF1.COM by using the HEXCOM utility:
  51.          A>HEXCOM IF1
  52.   Now compile IF.PAS into IF.COM using Turbo Pascal.  Be sure to use the compiler options menu to
  53.   force compilation into a .COM file and use the "E" command to set the end of memory to 3D00.  Setting
  54.   the end of memory lower in this manner will prevent many problems with varying TPA sizes.  Next
  55.   combine the two sections by using PIP as follows:
  56.          A>PIP IF.COM=IF1.COM,IF.COM[O]
  57.   The resulting file IF.COM is the final form of the program.
  58.  
  59.   If you have any questions, feel free to leave a note to me on Compuserve [74206,21] or to
  60.          Scott Bussinger
  61.          Professional Practice Systems
  62.          112 South 131st Street
  63.          Tacoma, WA  98444                                                                                              }
  64.  
  65. type Fyle = file;                      { Your generic untyped file }
  66.      Stack = string[32];               { Stacks are implemented as strings so I can use all of the convenient functions }
  67.      Symbol = (NotExists,Exists,NotOperator,AndOperator,OrOperator,LeftParenthesis,RightParenthesis);
  68.  
  69. const a: array[Symbol] of integer = (0,0,1,2,2,0,0);  { Number of arguments }
  70.       f: array[Symbol] of integer = (7,7,5,3,1,9,0);  { Input precendence }
  71.       g: array[Symbol] of integer = (8,8,6,4,2,0,0);  { Stack precendence }
  72.  
  73. var CPM: boolean;
  74.     CPMPlus: boolean;
  75.     MPM: boolean;
  76.     Buffer: string[127];                      { A one sector buffer }
  77.     CommandLine: string[127] absolute $3E80;  { Get the command line from CP/M -- was moved from $0080 }
  78.     ResultStack: Stack;
  79.     SubFile: File;
  80.  
  81. procedure InitStack(var S: Stack);
  82.   { Initialize the stack to empty }
  83.   { All of the stack routines use a string as the implementation medium }
  84.   begin
  85.   S := ''
  86.   end;
  87.  
  88. procedure Push(Value: Symbol;var S: Stack);
  89.   { Push a value onto the stack -- there is no overflow test }
  90.   begin
  91.   S := chr(ord(Value))+S
  92.   end;
  93.  
  94. function Pop(var S: Stack): Symbol;
  95.   { Pop a value from stack  -- there is no underflow test }
  96.   begin
  97.   Pop := Symbol(S[1]);
  98.   delete(S,1,1)
  99.   end;
  100.  
  101. function TopOfStack(var S: Stack): Symbol;
  102.   { Return the value of the top element in the stack }
  103.   begin
  104.   TopOfStack := Symbol(S[1])
  105.   end;
  106.  
  107. function SizeOfStack(var S: Stack): integer;
  108.   { Return current number of elements in stack }
  109.   begin
  110.   SizeOfStack := length(S)
  111.   end;
  112.  
  113. function CheckDirectory(var Mask: Fyle): boolean;
  114.   { Use an untyped file's name as a mask for a directory check using search first BDOS call }
  115.   begin
  116.   bdos(26,addr(Buffer));                         { Set DMA to point at a temporary sector buffer }
  117.   CheckDirectory := bdos(17,addr(Mask)+12)<>255  { Do a Search-for-First using BDOS call and FCB in file interface block }
  118.   end;                                           { addr(Mask)+12 is address of CP/M FCB in Pascal's FIB }
  119.  
  120. function ParseNext: Symbol;
  121.   { Return the symbol type of next element on command line }
  122.   { If underflow on command line, return a right parenthesis }
  123.   var DirFile: Fyle;
  124.       Filename: string[32];
  125.   begin
  126.   case CommandLine[1] of
  127.     '&': begin
  128.          ParseNext := AndOperator;
  129.          delete(CommandLine,1,1)
  130.          end;
  131.     '|': begin
  132.          ParseNext := OrOperator;
  133.          delete(CommandLine,1,1)
  134.          end;
  135.     '~': begin
  136.          ParseNext := NotOperator;
  137.          delete(CommandLine,1,1)
  138.          end;
  139.     '(': begin
  140.          ParseNext := LeftParenthesis;
  141.          delete(CommandLine,1,1)
  142.          end;
  143.     ')': begin
  144.          ParseNext := RightParenthesis;
  145.          delete(CommandLine,1,1)
  146.          end
  147.     else begin                         { Should be a filename -- possibly with wildcards }
  148.          Filename := '';
  149.          repeat                        { Accumulate filename characters }
  150.            if CommandLine[1]='*'       { Check for a fill-rest-of-field wildcard }
  151.             then
  152.              Filename := Filename+'????????'          { Add enough ?'s to fill either primary name or extension }
  153.             else
  154.              Filename := Filename+CommandLine[1];     { Add next character to file name }
  155.            delete(CommandLine,1,1)
  156.          until (CommandLine[1] in [#8,' ','~','&','|','(',')']) or (CommandLine=''); { Accumulate until delimiter }
  157.          assign(DirFile,Filename);
  158.          if CheckDirectory(DirFile)    { Look in directory for the file }
  159.           then
  160.            ParseNext := Exists
  161.           else
  162.            ParseNext := NotExists
  163.          end
  164.     end;
  165.   while (CommandLine<>'') and (CommandLine[1] in [#8,' ']) do  { Strip off trailing spaces or tabs }
  166.     delete(CommandLine,1,1)
  167.   end;
  168.  
  169. function UseSymbol(Value: Symbol): boolean;
  170.   { Combine the symbol with the result stack }
  171.   { Type conversion uses the fact that ord(false)=0 and ord(true)=1 }
  172.   begin
  173.   if SizeOfStack(ResultStack) < a[Value]  { Make sure there is no stack underflow }
  174.    then
  175.     UseSymbol := true                  { Oops, we don't have enough arguments for that function -- a stack underflow }
  176.    else
  177.     begin
  178.     UseSymbol := false;
  179.     case Value of
  180.       NotExists,Exists: Push(Value,ResultStack);
  181.       AndOperator: Push(Symbol((Pop(ResultStack)=Exists) and (Pop(ResultStack)=Exists)),ResultStack);
  182.       OrOperator: Push(Symbol((Pop(ResultStack)=Exists) or (Pop(ResultStack)=Exists)),ResultStack);
  183.       NotOperator: Push(Symbol(Pop(ResultStack)<>Exists),ResultStack)
  184.       end
  185.     end
  186.   end;
  187.  
  188. function InfixToReverseToBoolean: boolean;
  189.   { Convert the input string into reverse polish notation and calculate the answer }
  190.   label 1,Error;
  191.   var NextSymbol: Symbol;
  192.       ConversionStack: Stack;
  193.       Temp: Symbol;
  194.   begin
  195.   InitStack(ConversionStack);
  196.   Push(LeftParenthesis,ConversionStack);
  197.  
  198.   while CommandLine <> '' do           { Check that CommandLine is not empty }
  199.     begin
  200.     NextSymbol := ParseNext;
  201.     while f[NextSymbol] <= g[TopOfStack(ConversionStack)] do
  202.       begin
  203.       Temp := Pop(ConversionStack);
  204.       if f[NextSymbol] = g[Temp]
  205.        then
  206.         goto 1
  207.        else
  208.         if UseSymbol(Temp) then goto Error
  209.       end;
  210.     Push(NextSymbol,ConversionStack);
  211. 1:  end;
  212.   if (SizeOfStack(ConversionStack)<>0) or (SizeOfStack(ResultStack)<>1)
  213.    then
  214.     begin
  215. Error: writeln('Error in command syntax -- false assumed.');
  216.     InfixToReverseToBoolean := false
  217.     end
  218.    else
  219.     InfixToReverseToBoolean := Pop(ResultStack)=Exists
  220.   end;
  221.  
  222. begin
  223. CPMPlus := (hi(bdoshl(12))=0) and (lo(bdoshl(12))>=$30);  { Check for CP/M Plus version number }
  224. CPM := (hi(bdoshl(12))=0) and not CPMPlus;  { Check for CP/M 2.2 or below }
  225. MPM := hi(bdoshl(12))=1;               { Check for MP/M because this program will NOT run under that system }
  226. if MPM
  227.  then
  228.   writeln('This program will not run under MP/M.')
  229.  else
  230.   begin
  231.   while (CommandLine<>'') and (CommandLine[1] in [#8,' ']) do  { Strip off leading spaces or tabs in CommandLine }
  232.     delete(CommandLine,1,1);
  233.   CommandLine := CommandLine+')';      { Algorithm needs a final right parenthesis to work }
  234.   InitStack(ResultStack);              { Prepare the result stack }
  235.   if InfixToReverseToBoolean           { Convert command line into a boolean value }
  236.    then
  237.     begin
  238.     writeln('true');
  239.     if CPMPlus then                    { If CP/M 2.2 then do nothing if true }
  240.       bdos(108,0)                      { If CP/M Plus then return a true value to CCP }
  241.     end
  242.    else
  243.     begin
  244.     writeln('false');
  245.     if CPMPlus
  246.      then
  247.       bdos(108,$FF00)                  { If CP/M Plus then return a false value }
  248.      else
  249.       begin                            { If CP/M 2.2 then insert a ';' into last record of $$$.SUB to comment it out }
  250.       assign(SubFile,'A:$$$.SUB');
  251.       reset(SubFile);
  252.       if ioresult=0 then
  253.         begin
  254.         seek(SubFile,pred(filesize(SubFile)));  { Move pointer to last record of file -- next line to be submitted }
  255.         blockread(Subfile,Buffer,1);   { Read in record }
  256.         Buffer := ';'+Buffer;          { Comment out the line so that it won't execute }
  257.         blockwrite(Subfile,Buffer,1);  { Save sector again }
  258.         close(SubFile)
  259.         end
  260.       end
  261.     end
  262.   end
  263. end.
  264.    blockwrite(Subfile,Buffer,1);  { Save sector again }
  265.         close(SubFile)
  266.         end
  267.       end
  268.     end
  269.   end
  270. end.