home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / image144.sit / Macros1.p < prev    next >
Encoding:
Text File  |  1992-03-30  |  76.6 KB  |  3,646 lines

  1. unit Macros1;
  2. {This unit contains the recursive descent parser/}
  3. {interpreter for Image's Pascal-like macro language.}
  4.  
  5. {References:}
  6. {  "Pascal User Manual and Report", Kathleen Jensen and Niklaus Wirth, Springer-Verlag}
  7. {  "Building Your Own C Interpreter", Dr. Dobb's Journal, August 1989}
  8.  
  9.  
  10. interface
  11.  
  12.     uses
  13.         QuickDraw, Palettes, PrintTraps, globals, Utilities, Graphics, edit, Analysis, Camera, file1, file2, functions, macros2, Stacks, Lut;
  14.  
  15.  
  16.     procedure LoadMacros (fname: str255; RefNum: integer);
  17.     procedure RunMacro (nMacro: integer);
  18.     procedure RunKeyMacro (ch: char; KeyCode: integer);
  19.  
  20.  
  21. implementation
  22.  
  23.  
  24.     const
  25.         DivideByZero = 'Divide by zero';
  26.         DoExpected = '"do" expected';
  27.         StackOverflow = 'Stack overflow';
  28.         RightParenExpected = '")" expected';
  29.         MaxArgs = 25;
  30.         BlankSymbol = '            ';
  31.  
  32.     var
  33.         EndMacros, pcStart, TopOfStack, CurrentX, CurrentY, nSaves: integer;
  34.         nProcedures, TokenLoc, TokenStackLoc, SavePC, nGlobals: integer;
  35.         MacroStart: array[1..MaxMacros] of integer;
  36.         MacroKey: packed array[1..MaxMacros] of char;
  37.         pc: integer; {"program counter" used by macro interpreter}
  38.         Token, SaveToken: TokenType;
  39.         TokenStr: string[100];
  40.         TokenSymbol, ProcName: SymbolType;
  41.         TokenValue: extended;
  42.         DoOption: boolean;
  43.         SaveForeground, SaveBackground, SavePicWidth, SavePicHeight: integer;
  44.         SaveMethod: rsMethodType;
  45.         SaveCreate, SaveInvertY: boolean;
  46.         SaveAngle, SaveH, SaveV: real;
  47.         MacroOpPending: boolean;
  48.  
  49.  
  50.     function GetExpression: extended;
  51.     forward;
  52.     procedure DoStatement;
  53.     forward;
  54.     procedure DoFor;
  55.     forward;
  56.  
  57.  
  58.     function LineNumber: integer;
  59.         var
  60.             i, n: integer;
  61.     begin
  62.         n := 1;
  63.         with MacrosP^ do
  64.             for i := pcStart to pc do
  65.                 if macros[i] = cr then
  66.                     n := n + 1;
  67.         LineNumber := n;
  68.     end;
  69.  
  70. {$PUSH}
  71. {$D-}
  72.  
  73.     function PreScan: boolean;
  74.    {Convert to lowercase and remove comments to speed up parsing.}
  75.         var
  76.             inString, inComment: boolean;
  77.             c: char;
  78.             i, StartComment: integer;
  79.     begin
  80.         with MacrosP^ do begin
  81.                 PreScan := false;
  82.                 inString := false;
  83.                 inComment := false;
  84.                 pcStart := 0;
  85.                 for i := 0 to EndMacros do begin
  86.                         c := macros[i];
  87.                         if inString and (c = cr) then begin
  88.                                 pc := i;
  89.                                 PutMessage(concat('The quoted string in line ', long2str(LineNumber), ' is not terminated.'));
  90.                                 exit(PreScan);
  91.                             end;
  92.                         if (not InString) and (c = '{') then begin
  93.                                 InComment := true;
  94.                                 StartComment := i;
  95.                             end;
  96.                         if inComment then begin
  97.                                 if (c = '{') and (i <> StartComment) then begin
  98.                                         PutMessage('Comments cannot be nested.');
  99.                                         exit(PreScan);
  100.                                     end;
  101.                                 if c = '}' then
  102.                                     inComment := false;
  103.                                 macros[i] := ' ';
  104.                             end
  105.                         else begin
  106.                                 if c = '''' then
  107.                                     inString := not inString;
  108.                                 if (c >= 'A') and (c <= 'Z') and not inString then
  109.                                     macros[i] := chr(ord(c) + 32);
  110.                             end;
  111.                     end;
  112.                 if inComment then begin
  113.                         pc := StartComment;
  114.                         PutMessage(concat('The comment starting in line ', long2str(LineNumber), ' is not terminated.'))
  115.                     end
  116.                 else
  117.                     PreScan := true;
  118.             end; {with}
  119.     end;
  120.  
  121.  
  122.     function match (str: str255): boolean;
  123.         var
  124.             i, loc: integer;
  125.     begin
  126.         loc := pc - 1;
  127.         match := false;
  128.         with MacrosP^ do
  129.             for i := 1 to length(str) do
  130.                 if macros[loc + i] <> str[i] then
  131.                     exit(match);
  132.         match := true;
  133.     end;
  134.  
  135.  
  136.     procedure TrimString (var str: str255);
  137.     begin
  138.         if length(str) > 0 then begin
  139.                 while (length(str) > 1) and (str[1] = ' ') do
  140.                     delete(str, 1, 1);
  141.                 while (length(str) > 1) and ((str[length(str)] = ' ') or (str[length(str)] = ';')) do
  142.                     delete(str, length(str), 1);
  143.             end;
  144.     end;
  145.  
  146.  
  147.     procedure MacroError (str: str255);
  148.         var
  149.             cLine, str2: str255;
  150.             i, count: integer;
  151.     begin
  152.         with MacrosP^ do begin
  153.                 if token = DoneT then
  154.                     exit(MacroError);
  155.                 i := pc - 1;
  156.                 while (i > 0) and (macros[i] <> cr) do {Find start of line}
  157.                     i := i - 1;
  158.                 count := 0;
  159.                 cLine := '';
  160.                 repeat
  161.                     i := i + 1;
  162.                     count := count + 1;
  163.                     if macros[i] <> cr then
  164.                         cLine := concat(cLine, macros[i]);
  165.                 until (i >= EndMacros) or (macros[i] = cr) or (count > 60);
  166.                 TrimString(cLine);
  167.                 if ProcName <> BlankSymbol then begin {Are we in a procedure?}
  168.                         str2 := ProcName;
  169.                         TrimString(str2);
  170.                         str2 := concat(' of procedure ', str2)
  171.                     end
  172.                 else
  173.                     str2 := ' of macro';
  174.                 PutMessage(concat(str, ' in line ', long2str(LineNumber), str2, '.', cr, cr, '"', cLine, '"'));
  175.                 Token := DoneT;
  176.             end; {with}
  177.     end;
  178.  
  179.  
  180.     procedure LookupIdentifier;
  181.   {Binary search routine from "Data Structures with Abstract}
  182.   {Data Types and Pascal" by Stubbs and Webre.}
  183.         var
  184.             low, high, mid: integer;
  185.     begin
  186.         with MacrosP^ do begin
  187.                 low := 1;
  188.                 high := nSymbols;
  189.                 while low < high do begin
  190.                         mid := (low + high + 1) div 2;
  191.                         if TokenSymbol < SymbolTable[mid].symbol then
  192.                             high := mid - 1
  193.                         else
  194.                             low := mid;
  195.                     end;
  196.                 with SymbolTable[high] do
  197.                     if (high <> 0) and (TokenSymbol = symbol) then begin
  198.                             token := tType;
  199.                             MacroCommand := cType;
  200.                             TokenLoc := loc;
  201.                         end
  202.                     else
  203.                         token := UnknownIdentifier;
  204.             end;
  205.     end;
  206.  
  207.  
  208.     procedure LookupVariable;
  209.         var
  210.             VarFound: boolean;
  211.             i: integer;
  212.     begin
  213.         with MacrosP^ do begin
  214.                 VarFound := false;
  215.                 i := TopOfStack + 1;
  216.                 repeat
  217.                     i := i - 1;
  218.                     VarFound := TokenSymbol = Stack[i].symbol
  219.                 until VarFound or (i = 1);
  220.                 if VarFound then
  221.                     with stack[i] do begin
  222.                             token := Variable;
  223.                             TokenValue := value;
  224.                             TokenStackLoc := i;
  225.                         end;
  226.             end; {with}
  227.     end;
  228.  
  229.  
  230.     procedure GetToken;
  231.         var
  232.             c: char;
  233.             SymbolLength: integer;
  234.     begin
  235.         with MacrosP^ do begin
  236.                 if token = DoneT then
  237.                     exit(GetToken);
  238.                 SavePC := PC;
  239.                 SaveToken := token;
  240.                 while not (macros[pc] in ['a'..'z', '0'..'9', '(', ')', ',', '''', '+', '-', '*', '/', ':', ';', '=', '.', '>', '<', '[', ']']) do begin  {skip white space}
  241.                         pc := pc + 1;
  242.                         if pc > EndMacros then begin
  243.                                 Token := DoneT;
  244.                                 exit(GetToken);
  245.                             end;
  246.                     end;
  247.                 c := macros[pc];
  248.                 case c of
  249.                     'a'..'z':  begin
  250.                             TokenSymbol := BlankSymbol;
  251.                             SymbolLength := 0;
  252.                             while macros[pc] in ['a'..'z', '0'..'9'] do begin
  253.                                     SymbolLength := SymbolLength + 1;
  254.                                     if SymbolLength <= SymbolSize then
  255.                                         TokenSymbol[SymbolLength] := macros[pc];
  256.                                     pc := pc + 1;
  257.                                     if pc > EndMacros then begin
  258.                                             Token := DoneT;
  259.                                             exit(GetToken);
  260.                                         end;
  261.                                 end;
  262.                             Token := identifier;
  263.                             LookupIdentifier;
  264.                             if (token = UnknownIdentifier) and (TopOfStack > 0) then
  265.                                 LookupVariable;
  266.                             exit(GetToken);
  267.                         end;
  268.                     '0'..'9', '.':  begin
  269.                             TokenStr := '';
  270.                             while macros[pc] in ['0'..'9', '.'] do begin
  271.                                     TokenStr := concat(TokenStr, c);
  272.                                     pc := pc + 1;
  273.                                     c := macros[pc];
  274.                                     if pc > EndMacros then begin
  275.                                             Token := DoneT;
  276.                                             exit(GetToken);
  277.                                         end;
  278.                                 end;
  279.                             Token := NumericLiteral;
  280.                             if macros[pc] in ['a'..'z'] then
  281.                                 MacroError('Operator expected');
  282.                             exit(GetToken);
  283.                         end;
  284.                     '(':  begin
  285.                             Token := LeftParen;
  286.                             pc := pc + 1;
  287.                         end;
  288.                     ')':  begin
  289.                             Token := RightParen;
  290.                             pc := pc + 1;
  291.                         end;
  292.                     '[':  begin
  293.                             Token := LeftBracket;
  294.                             pc := pc + 1;
  295.                         end;
  296.                     ']':  begin
  297.                             Token := RightBracket;
  298.                             pc := pc + 1;
  299.                         end;
  300.                     ',':  begin
  301.                             Token := comma;
  302.                             pc := pc + 1;
  303.                         end;
  304.                     ':': 
  305.                         if macros[pc + 1] = '=' then begin
  306.                                 Token := AssignOp;
  307.                                 pc := pc + 2;
  308.                             end
  309.                         else begin
  310.                                 Token := colon;
  311.                                 pc := pc + 1;
  312.                             end;
  313.                     ';':  begin
  314.                             Token := SemiColon;
  315.                             pc := pc + 1;
  316.                         end;
  317.                     '+':  begin
  318.                             Token := PlusOp;
  319.                             pc := pc + 1;
  320.                         end;
  321.                     '-':  begin
  322.                             Token := MinusOp;
  323.                             pc := pc + 1;
  324.                         end;
  325.                     '*':  begin
  326.                             Token := MulOp;
  327.                             pc := pc + 1;
  328.                         end;
  329.                     '/':  begin
  330.                             Token := DivOp;
  331.                             pc := pc + 1;
  332.                         end;
  333.                     '''':  begin
  334.                             TokenStr := '';
  335.                             pc := pc + 1;
  336.                             while macros[pc] <> '''' do begin
  337.                                     TokenStr := concat(TokenStr, macros[pc]);
  338.                                     pc := pc + 1;
  339.                                     if pc > EndMacros then begin
  340.                                             Token := DoneT;
  341.                                             exit(GetToken);
  342.                                         end;
  343.                                 end;
  344.                             pc := pc + 1;
  345.                             Token := stringT;
  346.                         end;
  347.                     '=':  begin
  348.                             Token := eqOp;
  349.                             pc := pc + 1;
  350.                         end;
  351.                     '<':  begin
  352.                             pc := pc + 1;
  353.                             if macros[pc] = '>' then begin
  354.                                     token := neOp;
  355.                                     pc := pc + 1;
  356.                                 end
  357.                             else if macros[pc] = '=' then begin
  358.                                     token := leOp;
  359.                                     pc := pc + 1;
  360.                                 end
  361.                             else
  362.                                 token := ltOp;
  363.                         end;
  364.                     '>':  begin
  365.                             pc := pc + 1;
  366.                             if macros[pc] = '=' then begin
  367.                                     token := geOp;
  368.                                     pc := pc + 1;
  369.                                 end
  370.                             else
  371.                                 token := gtOp;
  372.                         end;
  373.                     otherwise begin
  374.                             token := NullT;
  375.                             beep;
  376.                         end;
  377.                 end; {case}
  378.             end; {with}
  379.     end;
  380.  
  381.  
  382.     procedure AddMenuItem;
  383.         var
  384.             i, fkey: integer;
  385.             str: str255;
  386.             c, key: char;
  387.     begin
  388.         with MacrosP^ do begin
  389.                 if pc > 1 then
  390.                     if macros[pc - 1] in ['a'..'z', '0'..'9'] then
  391.                         exit(AddMenuItem);
  392.                 if macros[pc + 5] in ['a'..'z', '0'..'9'] then
  393.                     exit(AddMenuItem);
  394.                 pc := pc + 4;
  395.                 repeat
  396.                     pc := pc + 1;
  397.                     c := macros[pc];
  398.                 until (c = '''') or (c = cr) or (pc = EndMacros);
  399.                 if (c = cr) or (pc = EndMacros) then begin
  400.                         MacroError('Menu entry for macro not found.');
  401.                         exit(AddMenuItem);
  402.                     end;
  403.                 pc := pc + 1;
  404.                 str := '';
  405.                 repeat
  406.                     str := concat(str, macros[pc]);
  407.                     pc := pc + 1;
  408.                 until (macros[pc] = '''') or (pc = EndMacros);
  409.                 if pc = EndMacros then
  410.                     PutMessage('Ending quote('') missing.')
  411.                 else
  412.                     pc := pc + 1;
  413.                 AppendMenu(SpecialMenuH, str);
  414.                 if nMacros < MaxMacros then
  415.                     nMacros := nMacros + 1
  416.                 else
  417.                     beep;
  418.                 if macros[pc] = ';' then
  419.                     pc := pc + 1;
  420.                 MacroStart[nMacros] := pc;
  421.                 i := pos('[', str);
  422.                 if i > 0 then begin {Assign a key to macro?}
  423.                         i := i + 1;
  424.                         key := str[i];
  425.                         if (key >= 'A') and (key <= 'Z') then
  426.                             key := chr(ord(key) + 32);
  427.                         MacroKey[nMacros] := key;
  428.                         if (key = 'f') and (str[i + 1] in ['1'..'9']) then begin {Function Key?}
  429.                                 fkey := ord(str[i + 1]) - ord('0');
  430.                                 if str[i + 2] in ['0'..'5'] then
  431.                                     fkey := fkey * 10 + ord(str[i + 2]) - ord('0');
  432.                                 if (fkey >= 1) and (fkey <= 15) then
  433.                                     MacroKey[nMacros] := chr(ord('A') + fkey - 1);
  434.                             end; {Function key?}
  435.                     end;
  436.             end; {with}
  437.     end;
  438.  
  439.  
  440.     procedure AddProcedure;
  441.     begin
  442.         pc := pc + 9;
  443.         GetToken;
  444.         if token <> UnknownIdentifier then begin
  445.                 MacroError('Procedure name missing or previously defined');
  446.                 exit(AddProcedure);
  447.             end;
  448.         if nSymBols >= MaxSymbols then begin
  449.                 MacroError('Too many procedures');
  450.                 exit(AddProcedure);
  451.             end;
  452.         nSymbols := nSymbols + 1;
  453.         nProcedures := nProcedures + 1;
  454.         with MacrosP^, MacrosP^.SymbolTable[nSymbols] do begin
  455.                 symbol := TokenSymbol;
  456.                 tType := procedureT;
  457.                 cType := NullC;
  458.                 if macros[pc] = ';' then
  459.                     pc := pc + 1;
  460.                 loc := pc;
  461.             end;
  462.     end;
  463.  
  464.  
  465.     procedure CheckForReservedWord;
  466.         var
  467.             str: str255;
  468.     begin
  469.         if token in [CommandT, FunctionT, endT, VarT, ForT, ToT, DoT, IfT, ThenT, whileT, repeatT, untilT, IntDivOp, modOp, andOp, NotOp, ProcedureT, MacroT, ArrayT] then begin
  470.                 str := TokenSymbol;
  471.                 TrimString(str);
  472.                 MacroError(concat('"', str, '" is a reserved identifier'));
  473.             end;
  474.     end;
  475.  
  476.  
  477.     procedure DoDeclaration (global: boolean);
  478.         var
  479.             SaveStackLoc, StackLoc: integer;
  480.     begin
  481.         SaveStackLoc := TopOfStack;
  482.         while (token = UnknownIdentifier) or (token = Variable) or (token = comma) do begin
  483.                 TopOfStack := TopOfStack + 1;
  484.                 if global then
  485.                     nGlobals := nGlobals + 1;
  486.                 if TopOfStack > MaxStackSize then begin
  487.                         MacroError(StackOverflow);
  488.                         exit(DoDeclaration);
  489.                     end;
  490.                 with MacrosP^.stack[TopOfStack] do begin
  491.                         Symbol := TokenSymbol;
  492.                         value := 0.0;
  493.                     end;
  494.                 GetToken;
  495.                 if token = comma then
  496.                     GetToken;
  497.             end; {while}
  498.         CheckForReservedWord;
  499.         if token <> colon then
  500.             MacroError('":" expected');
  501.         GetToken;
  502.         if (token <> IntegerT) and (token <> RealT) and (token <> BooleanT) then
  503.             MacroError('"integer", "real", or "boolean" expected');
  504.         for StackLoc := SaveStackLoc + 1 to TopOfStack do
  505.             with macrosP^.stack[StackLoc] do
  506.                 case token of
  507.                     IntegerT: 
  508.                         vType := IntVar;
  509.                     RealT: 
  510.                         vType := RealVar;
  511.                     BooleanT: 
  512.                         vType := BooleanVar;
  513.                     otherwise
  514.                 end;
  515.         GetToken;
  516.         if Token = SemiColon then
  517.             GetToken;
  518.     end;
  519.  
  520.  
  521.     procedure PutTokenBack;
  522.     begin
  523.         if token <> DoneT then begin
  524.                 pc := SavePC;
  525.                 token := SaveToken;
  526.             end;
  527.     end;
  528.  
  529.  
  530.     procedure DoGlobalDeclarations;
  531.     begin
  532.         pc := pc + 3;
  533.         GetToken;
  534.         CheckForReservedWord;
  535.         while (token = UnknownIdentifier) and (Token <> DoneT) do
  536.             DoDeclaration(true);
  537.         PutTokenBack;
  538.     end;
  539.  
  540.  
  541.     procedure PreScan2;
  542.         var
  543.             i: integer;
  544.             inString: boolean;
  545.             c: char;
  546.     begin
  547.         Token := NullT;
  548.         with MacrosP^ do begin
  549.                 if nMacros > 0 then
  550.                     for i := 1 to nMacros do begin
  551.                             DelMenuItem(SpecialMenuH, FirstMacroItem);
  552.                             MacroKey[i] := chr(0);
  553.                         end;
  554.                 nMacros := 0;
  555.                 nProcedures := 0;
  556.                 nGlobals := 0;
  557.                 TopOfStack := 0;
  558.                 ProcName := BlankSymbol;
  559.                 pc := 0;
  560.                 inString := false;
  561.                 while pc <= (EndMacros - 10) do begin
  562.                         c := macros[pc];
  563.                         if c = '''' then
  564.                             inString := not inString;
  565.                         if not InString then
  566.                             case c of
  567.                                 'm': 
  568.                                     if match('macro') then begin
  569.                                             AddMenuItem;
  570.                                             if token = DoneT then
  571.                                                 exit(PreScan2);
  572.                                         end;
  573.                                 'p': 
  574.                                     if match('procedure') then begin
  575.                                             AddProcedure;
  576.                                             if token = DoneT then
  577.                                                 exit(PreScan2);
  578.                                         end;
  579.                                 'v': 
  580.                                     if (nMacros = 0) and (nProcedures = 0) then
  581.                                         if match('var') then begin
  582.                                                 DoGlobalDeclarations;
  583.                                                 if token = DoneT then
  584.                                                     exit(PreScan2);
  585.                                             end;
  586.                                 otherwise
  587.                             end;
  588.                         pc := pc + 1;
  589.                     end; {while}
  590.                 if nMacros = 0 then
  591.                     PutMessage('No macros found in this file.');
  592.             end; {with}
  593.     end;
  594.  
  595.  
  596.     procedure SortSymbolTable;
  597.   {Selection sort routine from "Algorithms" by Robert Sedgewick.}
  598.         var
  599.             i, j, min: integer;
  600.             t: SymTabRec;
  601.     begin
  602.         with MacrosP^ do
  603.             for i := 1 to nSymbols do begin
  604.                     min := i;
  605.                     for j := i + 1 to nSymbols do
  606.                         if SymbolTable[j].symbol < SymbolTable[min].symbol then
  607.                             min := j;
  608.                     t := SymbolTable[min];
  609.                     SymbolTable[min] := SymbolTable[i];
  610.                     SymbolTable[i] := t;
  611.                 end;
  612.     end;
  613.  
  614.  
  615.     procedure LoadMacros (fname: str255; RefNum: integer);
  616.         var
  617.             err: OSErr;
  618.             FileSize: LongInt;
  619.             f: integer;
  620.     begin
  621.         err := FSOpen(fname, RefNum, f);
  622.         err := GetEOF(f, FileSize);
  623.         if FileSize > MaxMacroSize then begin
  624.                 err := fsclose(f);
  625.                 PutMessage('Macro file is too large.');
  626.                 exit(LoadMacros);
  627.             end;
  628.         err := SetFPos(f, fsFromStart, 0);
  629.         err := fsRead(f, FileSize, @MacrosP^.macros);
  630.         EndMacros := FileSize - 1;
  631.         err := fsclose(f);
  632.         ShowWatch;
  633.         if not PreScan then
  634.             exit(LoadMacros);
  635.         InitSymbolTable;
  636.         UnloadSeg(@InitSymbolTable);
  637.         SortSymbolTable;
  638.         PreScan2;
  639.         if nProcedures > 0 then
  640.             SortSymbolTable;
  641.         CurrentX := 20;
  642.         CurrentY := 20;
  643.         SaveForeground := -1;
  644.     end;
  645.  
  646.  
  647.     procedure GetLeftParen;
  648.     begin
  649.         GetToken;
  650.         if token <> LeftParen then
  651.             MacroError('"(" expected');
  652.     end;
  653.  
  654.  
  655.     procedure GetRightParen;
  656.     begin
  657.         GetToken;
  658.         if token <> RightParen then
  659.             MacroError(RightParenExpected);
  660.     end;
  661.  
  662.  
  663.     procedure GetComma;
  664.     begin
  665.         GetToken;
  666.         if token <> comma then
  667.             MacroError('"," expected');
  668.     end;
  669.  
  670.  
  671.     function GetString: str255;
  672.     begin
  673.         GetToken;
  674.         if token = stringT then
  675.             GetString := TokenStr
  676.         else begin
  677.                 MacroError('String expected');
  678.                 GetString := '';
  679.             end;
  680.     end;
  681.  
  682.  
  683.     function GetInteger: LongInt;
  684.         var
  685.             n: LongInt;
  686.             r: extended;
  687.     begin
  688.         r := GetExpression;
  689.         if token = DoneT then begin
  690.                 GetInteger := 0;
  691.                 exit(GetInteger);
  692.             end;
  693.         GetInteger := round(r);
  694.     end;
  695.  
  696.  
  697.     procedure GetArguments (var str: str255);
  698.         var
  699.             width, fwidth: integer;
  700.             i: LongInt;
  701.             isExpression, ZeroFill, noArgs: boolean;
  702.             n: real;
  703.             str2: str255;
  704.     begin
  705.         if MacroCommand = WritelnC then begin {Check for Writeln with no arguments}
  706.                 GetToken;
  707.                 noArgs := token <> LeftParen;
  708.                 PutTokenBack;
  709.                 if NoArgs then begin
  710.                         str := '';
  711.                         exit(GetArguments);
  712.                     end;
  713.             end;
  714.         ZeroFill := not (MacroCommand in [DrawTextC, WriteC, WritelnC, PutMsgC, ShowMsgC]);
  715.         width := 4;
  716.         fwidth := 0;
  717.         str := '';
  718.         GetLeftParen;
  719.         GetToken;
  720.         repeat
  721.             isExpression := token in [Variable, NumericLiteral, FunctionT, TrueT, FalseT, ArrayT];
  722.             PutTokenBack;
  723.             if isExpression then
  724.                 n := GetExpression
  725.             else
  726.                 str2 := GetString;
  727.             GetToken;
  728.             if token = colon then begin
  729.                     width := GetInteger;
  730.                     if width < 0 then
  731.                         width := 0;
  732.                     if width > 100 then
  733.                         width := 100;
  734.                     GetToken;
  735.                     if token = colon then begin
  736.                             fwidth := GetInteger;
  737.                             if fwidth < 0 then
  738.                                 width := 0;
  739.                             if fwidth > 12 then
  740.                                 width := 12;
  741.                             GetToken;
  742.                         end;
  743.                 end;
  744.             if token = comma then
  745.                 GetToken;
  746.             if isExpression then begin
  747.                     RealToString(n, width, fwidth, str2);
  748.                     if ZeroFill then
  749.                         for i := 1 to width do
  750.                             if str2[i] = ' ' then
  751.                                 str2[i] := '0';
  752.                 end;
  753.             str := concat(str, str2);
  754.         until (token = RightParen) or (token = DoneT);
  755.     end;
  756.  
  757.  
  758.     procedure CheckBoolean (b: extended);
  759.     begin
  760.         if (b <> ord(true)) and (b <> ord(false)) then
  761.             MacroError('Boolean expression expected');
  762.     end;
  763.  
  764.  
  765.     function GetBoolean: boolean;
  766.         var
  767.             value: extended;
  768.     begin
  769.         value := GetExpression;
  770.         CheckBoolean(value);
  771.         GetBoolean := value = ord(true);
  772.     end;
  773.  
  774.  
  775.     function GetBooleanArg: boolean;
  776.     begin
  777.         GetLeftParen;
  778.         GetBooleanArg := GetBoolean;
  779.         GetRightParen;
  780.     end;
  781.  
  782.  
  783.     function GetStringArg: str255;
  784.     begin
  785.         GetLeftParen;
  786.         GetStringArg := GetString;
  787.         GetRightParen;
  788.     end;
  789.  
  790.  
  791.     procedure DoConvolve;
  792.         var
  793.             err: OSErr;
  794.             f: integer;
  795.             FileFound: boolean;
  796.             fname: str255;
  797.     begin
  798.         fname := GetStringArg;
  799.         err := fsopen(fname, KernelsRefNum, f);
  800.         FileFound := err = NoErr;
  801.         err := fsclose(f);
  802.         if FileFound then
  803.             convolve(fname, KernelsRefNum)
  804.         else
  805.             convolve('', 0);
  806.     end;
  807.  
  808.  
  809.     function GetNumber: extended; {(prompt:str255; default:extended)}
  810.         var
  811.             prompt: str255;
  812.             default, n: extended;
  813.             Canceled: boolean;
  814.     begin
  815.         GetLeftParen;
  816.         prompt := GetString;
  817.         GetComma;
  818.         default := GetExpression;
  819.         GetRightParen;
  820.         n := 0.0;
  821.         if Token <> DoneT then begin
  822.                 n := GetReal(prompt, default, Canceled);
  823.                 if Canceled then begin
  824.                         n := default;
  825.                         token := DoneT;
  826.                     end;
  827.             end;
  828.         GetNumber := n;
  829.     end;
  830.  
  831.  
  832.     function DoGetPixel: extended; {(hloc,vloc:integer)}
  833.         var
  834.             hloc, vloc: integer;
  835.     begin
  836.         GetLeftParen;
  837.         hloc := GetInteger;
  838.         GetComma;
  839.         vloc := GetInteger;
  840.         GetRightParen;
  841.         if (Token <> DoneT) and (info <> NoInfo) then
  842.             DoGetPixel := MyGetPixel(hloc, vloc)
  843.         else
  844.             DoGetPixel := 0.0;
  845.     end;
  846.  
  847.  
  848.     function DoFunction (c: CommandType): extended;
  849.         var
  850.             n: extended;
  851.             SaveCommand: CommandType;
  852.     begin
  853.         SaveCommand := MacroCommand;
  854.         GetLeftParen;
  855.         n := GetExpression;
  856.         GetRightParen;
  857.         if Token <> DoneT then
  858.             case SaveCommand of
  859.                 truncC: 
  860.                     DoFunction := trunc(n);
  861.                 roundC: 
  862.                     DoFunction := round(n);
  863.                 oddC: 
  864.                     if odd(trunc(n)) then
  865.                         DoFunction := ord(true)
  866.                     else
  867.                         DoFunction := ord(false);
  868.                 absC: 
  869.                     DoFunction := abs(n);
  870.                 sqrtC: 
  871.                     if n < 0.0 then
  872.                         MacroError('Sqrt Error')
  873.                     else
  874.                         DoFunction := sqrt(n);
  875.                 sqrC: 
  876.                     DoFunction := sqr(n);
  877.                 sinC: 
  878.                     DoFunction := sin(n);
  879.                 cosC: 
  880.                     DoFunction := cos(n);
  881.                 expC: 
  882.                     DoFunction := exp(n);
  883.                 lnC: 
  884.                     if n <= 0.0 then
  885.                         MacroError('Log Error')
  886.                     else
  887.                         DoFunction := ln(n);
  888.                 arctanC: 
  889.                     DoFunction := arctan(n);
  890.             end
  891.         else
  892.             DoFunction := 0.0;
  893.     end;
  894.  
  895.  
  896.     procedure RangeCheck (i: LongInt);
  897.     begin
  898.         if (i < 0) or (i > 255) then
  899.             MacroError('Argument is less than 0 or greater than 255');
  900.     end;
  901.  
  902.  
  903.     function CalibrateValue: extended;
  904.         var
  905.             i: integer;
  906.     begin
  907.         GetLeftParen;
  908.         i := GetInteger;
  909.         GetRightParen;
  910.         RangeCheck(i);
  911.         if Token <> DoneT then begin
  912.                 CalibrateValue := cvalue[i];
  913.             end;
  914.     end;
  915.  
  916.  
  917.     function ExecuteFunction: extended;
  918.     begin
  919.         case MacroCommand of
  920.             TruncC, RoundC, oddC, absC, sqrtC, sqrC, sinC, cosC, expC, lnC, arctanC: 
  921.                 ExecuteFunction := DoFunction(MacroCommand);
  922.             GetNumC: 
  923.                 ExecuteFunction := GetNumber;
  924.             RandomC: 
  925.                 ExecuteFunction := (random + 32767.0) / 65534.0;
  926.             GetPixelC: 
  927.                 ExecuteFunction := DoGetPixel;
  928.             ButtonC:  begin
  929.                     ExecuteFunction := ord(Button);
  930.                     FlushEvents(EveryEvent, 0);
  931.                 end;
  932.             nPicsC: 
  933.                 ExecuteFunction := nPics;
  934.             PicNumC: 
  935.                 ExecuteFunction := info^.PicNum;
  936.             SameSizeC: 
  937.                 ExecuteFunction := ord(AllSameSize);
  938.             cValueC: 
  939.                 ExecuteFunction := CalibrateValue;
  940.             CalibratedC: 
  941.                 ExecuteFunction := ord(info^.DensityCalibrated);
  942.             rCountC: 
  943.                 ExecuteFunction := mCount;
  944.             GetSliceC: 
  945.                 with info^ do
  946.                     if StackInfo = nil then
  947.                         ExecuteFunction := 0
  948.                     else
  949.                         ExecuteFunction := Info^.StackInfo^.CurrentSlice;
  950.             nSlicesC: 
  951.                 with info^ do
  952.                     if StackInfo = nil then
  953.                         ExecuteFunction := 0
  954.                     else
  955.                         ExecuteFunction := Info^.StackInfo^.nSlices;
  956.             GetSpacingC: 
  957.                 with info^ do
  958.                     if StackInfo = nil then
  959.                         MacroError('No stack')
  960.                     else
  961.                         ExecuteFunction := Info^.StackInfo^.SliceSpacing;
  962.             GetPlotCountC: 
  963.                 ExecuteFunction := PlotCount;
  964.         end; {case}
  965.     end;
  966.  
  967.  
  968.     procedure CheckIndex (index: LongInt; min, max: extended);
  969.     begin
  970.         if (index < min) or (index > max) then
  971.             MacroError('Array index out of range');
  972.     end;
  973.  
  974.  
  975.     function GetArrayValue: extended;
  976.         var
  977.             SaveCommand: CommandType;
  978.             Index: LongInt;
  979.     begin
  980.         SaveCommand := MacroCommand;
  981.         GetToken;
  982.         if token <> LeftBracket then
  983.             MacroError('"[" expected');
  984.         Index := GetInteger;
  985.         GetToken;
  986.         if token <> RightBracket then
  987.             MacroError('"]" expected');
  988.         case SaveCommand of
  989.             HistogramC:  begin
  990.                     CheckIndex(Index, 0, 255);
  991.                     GetArrayValue := histogram[Index];
  992.                 end;
  993.             rAreaC:  begin
  994.                     CheckIndex(Index, 1, MaxRegions);
  995.                     GetArrayValue := mArea^[Index];
  996.                 end;
  997.             rMeanC:  begin
  998.                     CheckIndex(Index, 1, MaxRegions);
  999.                     GetArrayValue := mean^[Index];
  1000.                 end;
  1001.             rStdDevC:  begin
  1002.                     CheckIndex(Index, 1, MaxRegions);
  1003.                     GetArrayValue := sd^[Index];
  1004.                 end;
  1005.             rXC:  begin
  1006.                     CheckIndex(Index, 1, MaxRegions);
  1007.                     GetArrayValue := xcenter^[Index];
  1008.                 end;
  1009.             rYC:  begin
  1010.                     CheckIndex(Index, 1, MaxRegions);
  1011.                     GetArrayValue := ycenter^[Index];
  1012.                 end;
  1013.             rLengthC:  begin
  1014.                     CheckIndex(Index, 1, MaxRegions);
  1015.                     GetArrayValue := pLength^[Index];
  1016.                 end;
  1017.             rMinC:  begin
  1018.                     CheckIndex(Index, 1, MaxRegions);
  1019.                     GetArrayValue := mMin^[Index];
  1020.                 end;
  1021.             rMaxC:  begin
  1022.                     CheckIndex(Index, 1, MaxRegions);
  1023.                     GetArrayValue := mMax^[Index];
  1024.                 end;
  1025.             rMajorC:  begin
  1026.                     CheckIndex(Index, 1, MaxRegions);
  1027.                     GetArrayValue := MajorAxis^[Index];
  1028.                 end;
  1029.             rMinorC:  begin
  1030.                     CheckIndex(Index, 1, MaxRegions);
  1031.                     GetArrayValue := MinorAxis^[Index];
  1032.                 end;
  1033.             rAngleC:  begin
  1034.                     CheckIndex(Index, 1, MaxRegions);
  1035.                     GetArrayValue := orientation^[Index];
  1036.                 end;
  1037.             rUser1C:  begin
  1038.                     CheckIndex(Index, 1, MaxRegions);
  1039.                     GetArrayValue := User1^[Index];
  1040.                 end;
  1041.             rUser2C:  begin
  1042.                     CheckIndex(Index, 1, MaxRegions);
  1043.                     GetArrayValue := User2^[Index];
  1044.                 end;
  1045.             RedLutC, GreenLutC, BlueLutC:  begin
  1046.                     CheckIndex(Index, 0, 255);
  1047.                     if Token <> DoneT then
  1048.                         with cScreenPort^.portPixMap^^.pmTable^^.ctTable[index].rgb do
  1049.                             case SaveCommand of
  1050.                                 RedLutC: 
  1051.                                     GetArrayValue := band(bsr(red, 8), 255);
  1052.                                 GreenLutC: 
  1053.                                     GetArrayValue := band(bsr(green, 8), 255);
  1054.                                 BlueLutC: 
  1055.                                     GetArrayValue := band(bsr(blue, 8), 255);
  1056.                             end; {case}
  1057.                 end;
  1058.             BufferC:  begin
  1059.                     CheckIndex(Index, 0, MaxLine - 1);
  1060.                     if Token <> DoneT then
  1061.                         GetArrayValue := MacrosP^.aLine[index];
  1062.                 end;
  1063.             PlotDataC:  begin
  1064.                     CheckIndex(Index, 0, MaxLine - 1);
  1065.                     if Token <> DoneT then
  1066.                         GetArrayValue := PlotData^[index];
  1067.                 end;
  1068.         end; {case}
  1069.     end;
  1070.  
  1071.  
  1072.     function GetValue: extended;
  1073.     begin
  1074.         case token of
  1075.             Variable: 
  1076.                 GetValue := TokenValue;
  1077.             NumericLiteral: 
  1078.                 GetValue := StringToReal(TokenStr);
  1079.             FunctionT: 
  1080.                 GetValue := ExecuteFunction;
  1081.             TrueT: 
  1082.                 GetValue := ord(true);
  1083.             FalseT: 
  1084.                 GetValue := ord(false);
  1085.             ArrayT: 
  1086.                 GetValue := GetArrayValue;
  1087.             otherwise begin
  1088.                     MacroError('Number expected');
  1089.                     GetValue := 0.0;
  1090.                     exit(GetValue);
  1091.                 end;
  1092.         end; {case}
  1093.     end;
  1094.  
  1095.  
  1096.     function GetFactor: extended;
  1097.         var
  1098.             fValue: extended;
  1099.             isUnaryMinus, isNot: boolean;
  1100.     begin
  1101.         GetToken;
  1102.         isUnaryMinus := token = MinusOp;
  1103.         isNot := token = NotOp;
  1104.         if isUnaryMinus or isNot then
  1105.             GetToken;
  1106.         case token of
  1107.             Variable, NumericLiteral, FunctionT, TrueT, FalseT, ArrayT: 
  1108.                 fValue := GetValue;
  1109.             LeftParen:  begin
  1110.                     fValue := GetExpression;
  1111.                     GetRightParen;
  1112.                 end;
  1113.             otherwise begin
  1114.                     macroError('Undefined identifier');
  1115.                     fvalue := 0.0
  1116.                 end;
  1117.         end;
  1118.         GetToken;
  1119.         if isUnaryMinus then
  1120.             fValue := -fValue;
  1121.         if isNot then
  1122.             if fValue = ord(true) then
  1123.                 fValue := ord(false)
  1124.             else
  1125.                 fValue := ord(true);
  1126.         GetFactor := fValue;
  1127.     end;
  1128.  
  1129.  
  1130.     function GetTerm: extended;
  1131.         var
  1132.             tValue, fValue: extended;
  1133.             op: TokenType;
  1134.     begin
  1135.         tValue := GetFactor;
  1136.         while token in [MulOp, IntDivOp, ModOp, DivOp, AndOp] do begin
  1137.                 op := token;
  1138.                 fValue := GetFactor;
  1139.                 case op of
  1140.                     MulOp: 
  1141.                         tValue := tValue * fValue;
  1142.                     IntDivOp: 
  1143.                         if fValue <> 0.0 then
  1144.                             tValue := trunc(tValue) div trunc(fValue)
  1145.                         else
  1146.                             MacroError(DivideByZero);
  1147.                     ModOp: 
  1148.                         if fValue <> 0.0 then
  1149.                             tValue := trunc(tValue) mod trunc(fValue)
  1150.                         else
  1151.                             MacroError(DivideByZero);
  1152.                     DivOp: 
  1153.                         if fValue <> 0.0 then
  1154.                             tValue := tValue / fValue
  1155.                         else
  1156.                             MacroError(DivideByZero);
  1157.                     AndOp:  begin
  1158.                             CheckBoolean(tValue);
  1159.                             CheckBoolean(fValue);
  1160.                             tValue := ord((tValue = ord(true)) and (fValue = ord(true)));
  1161.                         end;
  1162.                 end; {case}
  1163.             end; {while}
  1164.         GetTerm := tValue;
  1165.     end;
  1166.  
  1167.  
  1168.     function GetSimpleExpression: extended;
  1169.         var
  1170.             seValue, tValue: extended;
  1171.             op: TokenType;
  1172.     begin
  1173.         seValue := GetTerm;
  1174.         while token in [PlusOp, MinusOp, OrOp] do begin
  1175.                 op := token;
  1176.                 tValue := GetTerm;
  1177.                 case op of
  1178.                     PlusOp: 
  1179.                         seValue := seValue + tValue;
  1180.                     MinusOp: 
  1181.                         seValue := seValue - tValue;
  1182.                     orOp:  begin
  1183.                             CheckBoolean(seValue);
  1184.                             CheckBoolean(tValue);
  1185.                             seValue := ord((seValue = ord(true)) or (tValue = ord(true)));
  1186.                         end;
  1187.                 end;
  1188.             end;
  1189.         GetSimpleExpression := seValue;
  1190.     end;
  1191.  
  1192.  
  1193.     function GetExpression: extended;
  1194.         var
  1195.             eValue, seValue: extended;
  1196.             op: TokenType;
  1197.     begin
  1198.         eValue := GetSimpleExpression;
  1199.         while token in [eqOp, ltOp, gtOp, neOp, leOp, geOp] do begin
  1200.                 op := token;
  1201.                 seValue := GetSimpleExpression;
  1202.                 case op of
  1203.                     eqOp: 
  1204.                         eValue := ord(eValue = seValue);
  1205.                     ltOp: 
  1206.                         eValue := ord(eValue < seValue);
  1207.                     gtOp: 
  1208.                         eValue := ord(eValue > seValue);
  1209.                     neOp: 
  1210.                         eValue := ord(eValue <> seValue);
  1211.                     leOp: 
  1212.                         eValue := ord(eValue <= seValue);
  1213.                     geOp: 
  1214.                         eValue := ord(eValue >= seValue);
  1215.                 end;
  1216.             end;
  1217.         GetExpression := eValue;
  1218.         PutTokenBack;
  1219.         ;
  1220.     end;
  1221.  
  1222.  
  1223.     procedure DoCapture;
  1224.     begin
  1225.         CaptureAndDisplayQCFrame;
  1226.         if ContinuousHistogram then
  1227.             ShowContinuousHistogram;
  1228.     end;
  1229.  
  1230.  
  1231.     procedure DoWait;
  1232.         var
  1233.             seconds: extended;
  1234.             SaveTicks: LongInt;
  1235.             str: str255;
  1236.     begin
  1237.         GetLeftParen;
  1238.         seconds := GetExpression;
  1239.         GetRightParen;
  1240.         if Token <> DoneT then begin
  1241.                 SaveTicks := TickCount + round(seconds * 60.0);
  1242.                 repeat
  1243.                     if Digitizing then
  1244.                         DoCapture;
  1245.                 until (TickCount > SaveTicks) or CommandPeriod;
  1246.             end;
  1247.     end;
  1248.  
  1249.  
  1250.     procedure SetDensitySlice; {LowerLevel,UpperLevel:integer}
  1251.         var
  1252.             sStart, sEnd: integer;
  1253.     begin
  1254.         GetLeftParen;
  1255.         sStart := GetInteger;
  1256.         RangeCheck(sStart);
  1257.         GetComma;
  1258.         sEnd := GetInteger;
  1259.         RangeCheck(sEnd);
  1260.         GetRightParen;
  1261.         if Token <> DoneT then begin
  1262.                 DisableDensitySlice;
  1263.                 if (sEnd < sStart) or ((sStart = 0) and (sEnd = 0)) then
  1264.                     exit(SetDensitySlice);
  1265.                 if not ((sStart = 255) and (sEnd = 255)) then begin
  1266.                         SliceStart := sStart;
  1267.                         SliceEnd := sEnd;
  1268.                     end;
  1269.                 if thresholding then
  1270.                     ResetGrayMap;
  1271.                 EnableDensitySlice;
  1272.             end;
  1273.     end;
  1274.  
  1275.  
  1276.     procedure SetColor;
  1277.         var
  1278.             index: integer;
  1279.             SaveCommand: CommandType;
  1280.     begin
  1281.         SaveCommand := MacroCommand;
  1282.         GetLeftParen;
  1283.         index := GetInteger;
  1284.         GetRightParen;
  1285.         RangeCheck(index);
  1286.         if Token <> DoneT then begin
  1287.                 if SaveCommand = SetForeC then
  1288.                     SetForegroundColor(index)
  1289.                 else
  1290.                     SetBackgroundColor(index);
  1291.             end;
  1292.     end;
  1293.  
  1294.  
  1295.     procedure DoConstantArithmetic;
  1296.         var
  1297.             constant: extended;
  1298.             SaveCommand: CommandType;
  1299.     begin
  1300.         SaveCommand := MacroCommand;
  1301.         GetLeftParen;
  1302.         constant := GetExpression;
  1303.         GetRightParen;
  1304.         if token <> DoneT then
  1305.             case SaveCommand of
  1306.                 AddConstC: 
  1307.                     DoArithmetic(AddItem, constant);
  1308.                 MulConstC: 
  1309.                     DoArithmetic(MultiplyItem, constant);
  1310.             end;
  1311.     end;
  1312.  
  1313.  
  1314.     procedure GetNextWindow;
  1315.         var
  1316.             n: integer;
  1317.     begin
  1318.         n := info^.PicNum + 1;
  1319.         if n > nPics then
  1320.             n := 1;
  1321.         KillRoi;
  1322.         Info := pointer(WindowPeek(PicWindow[n])^.RefCon);
  1323.         SetPort(info^.wptr);
  1324.         IsInsertionPoint := false;
  1325.         WhatToUndo := NothingToUndo;
  1326.         UndoFromClip := false;
  1327.     end;
  1328.  
  1329.  
  1330.     procedure DoRevert;
  1331.     begin
  1332.         if info^.revertable then begin
  1333.                 RevertToSaved;
  1334.                 UpdatePicWindow;
  1335.             end
  1336.         else
  1337.             MacroError('Unable to revert');
  1338.     end;
  1339.  
  1340.  
  1341.     procedure MakeRoi;
  1342.         var
  1343.             Left, Top, Width, Height: integer;
  1344.             SaveCommand: CommandType;
  1345.     begin
  1346.         SaveCommand := MacroCommand;
  1347.         GetLeftParen;
  1348.         left := GetInteger;
  1349.         GetComma;
  1350.         top := GetInteger;
  1351.         GetComma;
  1352.         width := GetInteger;
  1353.         GetComma;
  1354.         height := GetInteger;
  1355.         GetRightParen;
  1356.         KillRoi;
  1357.         if token <> DoneT then
  1358.             with Info^ do begin
  1359.                     StopDigitizing;
  1360.                     if SaveCommand = MakeOvalC then
  1361.                         RoiType := OvalRoi
  1362.                     else
  1363.                         RoiType := RectRoi;
  1364.                     SetRect(RoiRect, left, top, left + width, top + height);
  1365.                     MakeRegion;
  1366.                     SetupUndo;
  1367.                     RoiShowing := true;
  1368.                 end;
  1369.     end;
  1370.  
  1371.  
  1372.     procedure MoveRoi;
  1373.         var
  1374.             DeltaH, DeltaV: integer;
  1375.     begin
  1376.         GetLeftParen;
  1377.         DeltaH := GetInteger;
  1378.         GetComma;
  1379.         DeltaV := GetInteger;
  1380.         GetRightParen;
  1381.         with info^ do begin
  1382.                 if not RoiShowing then begin
  1383.                         MacroError('No Selection');
  1384.                         exit(MoveRoi);
  1385.                     end;
  1386.                 OffsetRgn(roiRgn, DeltaH, DeltaV);
  1387.                 RoiRect := roiRgn^^.rgnBBox;
  1388.                 RoiUpdateTime := 0;
  1389.                 MacroOpPending := true;
  1390.             end;
  1391.     end;
  1392.  
  1393.  
  1394.     procedure InsetRoi;
  1395.         var
  1396.             delta: integer;
  1397.     begin
  1398.         GetLeftParen;
  1399.         delta := GetInteger;
  1400.         GetRightParen;
  1401.         with info^ do begin
  1402.                 if not RoiShowing then begin
  1403.                         MacroError('No Selection');
  1404.                         exit(InsetRoi);
  1405.                     end;
  1406.                 InsetRgn(roiRgn, delta, delta);
  1407.                 RoiRect := roiRgn^^.rgnBBox;
  1408.                 RoiUpdateTime := 0;
  1409.                 MacroOpPending := true;
  1410.             end;
  1411.     end;
  1412.  
  1413.  
  1414.     procedure DoMoveTo; {(x,y:integer)}
  1415.     begin
  1416.         GetLeftParen;
  1417.         CurrentX := GetInteger;
  1418.         GetComma;
  1419.         CurrentY := GetInteger;
  1420.         GetRightParen;
  1421.         InsertionPoint.h := CurrentX;
  1422.         InsertionPoint.v := CurrentY + 4;
  1423.     end;
  1424.  
  1425.  
  1426.     procedure DoDrawtext (str: str255; EndOfLine: boolean);
  1427.     begin
  1428.         KillRoi;
  1429.         DrawTextString(str, InsertionPoint, TextJust);
  1430.         if EndOfLine then begin
  1431.                 CurrentY := CurrentY + CurrentSize;
  1432.                 InsertionPoint.h := CurrentX;
  1433.                 InsertionPoint.v := CurrentY + 4;
  1434.             end;
  1435.     end;
  1436.  
  1437.  
  1438.     procedure DrawNumber;
  1439.         var
  1440.             n: extended;
  1441.             str: str255;
  1442.             fwidth: integer;
  1443.     begin
  1444.         GetLeftParen;
  1445.         n := GetExpression;
  1446.         GetRightParen;
  1447.         if token <> DoneT then begin
  1448.                 if n = trunc(n) then
  1449.                     fwidth := 0
  1450.                 else
  1451.                     fwidth := precision;
  1452.                 RealToString(n, 1, fwidth, str);
  1453.                 DoDrawText(str, true);
  1454.             end;
  1455.     end;
  1456.  
  1457.  
  1458.     procedure MakeLowerCase (var str: str255);
  1459.         var
  1460.             i: integer;
  1461.             c: char;
  1462.     begin
  1463.         for i := 1 to length(str) do begin
  1464.                 c := str[i];
  1465.                 if (c >= 'A') and (c <= 'Z') then
  1466.                     str[i] := chr(ord(c) + 32);
  1467.             end;
  1468.     end;
  1469.  
  1470.  
  1471.     procedure SetFont;
  1472.         var
  1473.             FontName: str255;
  1474.             id: integer;
  1475.     begin
  1476.         FontName := GetStringArg;
  1477.         if Token <> DoneT then begin
  1478.                 GetFNum(FontName, id);
  1479.                 if id = 0 then
  1480.                     MacroError('Font not available')
  1481.                 else
  1482.                     CurrentFontID := id;
  1483.             end;
  1484.     end;
  1485.  
  1486.  
  1487.     procedure SetFontSize;
  1488.         var
  1489.             size: integer;
  1490.     begin
  1491.         GetLeftParen;
  1492.         Size := GetInteger;
  1493.         GetRightParen;
  1494.         if Token <> DoneT then
  1495.             CurrentSize := size;
  1496.     end;
  1497.  
  1498.  
  1499.     procedure SetText;
  1500.         var
  1501.             Attributes: str255;
  1502.     begin
  1503.         Attributes := GetStringArg;
  1504.         if Token <> DoneT then begin
  1505.                 MakeLowerCase(Attributes);
  1506.                 if pos('with', Attributes) <> 0 then
  1507.                     TextBack := WithBack;
  1508.                 if pos('no', Attributes) <> 0 then
  1509.                     TextBack := NoBack;
  1510.                 if pos('left', Attributes) <> 0 then
  1511.                     TextJust := teJustLeft;
  1512.                 if pos('center', Attributes) <> 0 then
  1513.                     TextJust := teJustCenter;
  1514.                 if pos('right', Attributes) <> 0 then
  1515.                     TextJust := teJustRight;
  1516.                 CurrentStyle := [];
  1517.                 if pos('bold', Attributes) <> 0 then
  1518.                     CurrentStyle := CurrentStyle + [Bold];
  1519.                 if pos('italic', Attributes) <> 0 then
  1520.                     CurrentStyle := CurrentStyle + [Italic];
  1521.                 if pos('underline', Attributes) <> 0 then
  1522.                     CurrentStyle := CurrentStyle + [Underline];
  1523.                 if pos('outline', Attributes) <> 0 then
  1524.                     CurrentStyle := CurrentStyle + [Outline];
  1525.                 if pos('shadow', Attributes) <> 0 then
  1526.                     CurrentStyle := CurrentStyle + [Shadow];
  1527.             end;
  1528.     end;
  1529.  
  1530.  
  1531.     procedure DoPutMessage;
  1532.         var
  1533.             str: str255;
  1534.     begin
  1535.         GetArguments(str);
  1536.         if Token <> DoneT then
  1537.             PutMessage(str)
  1538.     end;
  1539.  
  1540.  
  1541.     function GetVar: integer;
  1542.     begin
  1543.         GetVar := 0;
  1544.         GetToken;
  1545.         if token <> Variable then
  1546.             MacroError('Variable expected')
  1547.         else
  1548.             GetVar := TokenStackLoc;
  1549.     end;
  1550.  
  1551.  
  1552.     procedure GetPicSize;  {(width,height)}
  1553.         var
  1554.             loc1, loc2: integer;
  1555.     begin
  1556.         GetLeftParen;
  1557.         loc1 := GetVar;
  1558.         GetComma;
  1559.         loc2 := GetVar;
  1560.         GetRightParen;
  1561.         if Token <> DoneT then
  1562.             with MacrosP^ do
  1563.                 if info = NoInfo then begin
  1564.                         stack[loc1].value := 0.0;
  1565.                         stack[loc2].value := 0.0;
  1566.                     end
  1567.                 else
  1568.                     with info^ do begin
  1569.                             stack[loc1].value := PixelsPerLine;
  1570.                             stack[loc2].value := nLines;
  1571.                         end;
  1572.     end;
  1573.  
  1574.  
  1575.  
  1576.     procedure GetRoi;  {(hloc,vloc,width,height)}
  1577.         var
  1578.             loc1, loc2, loc3, loc4: integer;
  1579.     begin
  1580.         GetLeftParen;
  1581.         loc1 := GetVar;
  1582.         GetComma;
  1583.         loc2 := GetVar;
  1584.         GetComma;
  1585.         loc3 := GetVar;
  1586.         GetComma;
  1587.         loc4 := GetVar;
  1588.         GetRightParen;
  1589.         if Token <> DoneT then
  1590.             with MacrosP^, Info^ do
  1591.                 if RoiShowing then
  1592.                     with RoiRect do begin
  1593.                             stack[loc1].value := left;
  1594.                             stack[loc2].value := top;
  1595.                             stack[loc3].value := right - left;
  1596.                             stack[loc4].value := bottom - top;
  1597.                         end
  1598.                 else begin
  1599.                         stack[loc1].value := 0.0;
  1600.                         stack[loc2].value := 0.0;
  1601.                         stack[loc3].value := 0.0;
  1602.                         stack[loc4].value := 0.0;
  1603.                     end;
  1604.     end;
  1605.  
  1606.  
  1607.     procedure CaptureOneFrame;
  1608.     begin
  1609.         if FrameGrabber <> QuickCapture then
  1610.             MacroError('DT2255 frame grabber not installed')
  1611.         else begin
  1612.                 StartDigitizing;
  1613.                 CaptureAndDisplayQCFrame;
  1614.                 StopDigitizing;
  1615.             end;
  1616.     end;
  1617.  
  1618.  
  1619.     procedure DoMakeNewWindow; {(name:str255)}
  1620.         var
  1621.             name: str255;
  1622.     begin
  1623.         GetArguments(name);
  1624.         if token <> DoneT then
  1625.             if (LongInt(NewPicWidth) * NewPicHeight) > UndoBufSize then
  1626.                 MacroError('New window larger than Undo buffer')
  1627.             else if not NewPicWindow(name, NewPicWidth, NewPicHeight) then
  1628.                 MacroError('Out of memory');
  1629.     end;
  1630.  
  1631.  
  1632.     procedure DoSetPalette;
  1633.         var
  1634.             PaletteType: str255;
  1635.             ok: boolean;
  1636.     begin
  1637.         PaletteType := GetStringArg;
  1638.         if token <> DoneT then begin
  1639.                 MakeLowerCase(PaletteType);
  1640.                 if pos('gray', PaletteType) <> 0 then
  1641.                     ResetGrayMap
  1642.                 else if pos('pseudo', PaletteType) <> 0 then
  1643.                     SwitchColorTables(Pseudo20Item, true)
  1644.                 else if pos('system', PaletteType) <> 0 then
  1645.                     SwitchColorTables(SystemPaletteItem, true)
  1646.                 else if pos('rainbow', PaletteType) <> 0 then
  1647.                     SwitchColorTables(RainbowItem, true)
  1648.                 else if pos('spectrum', PaletteType) <> 0 then
  1649.                     SwitchColorTables(SpectrumItem, true)
  1650.             end;
  1651.     end;
  1652.  
  1653.  
  1654.     procedure DoOpenImage;
  1655.         var
  1656.             err: OSErr;
  1657.             f: integer;
  1658.             FileFound, result: boolean;
  1659.             fname: str255;
  1660.             SaveCommand: CommandType;
  1661.     begin
  1662.         SaveCommand := MacroCommand;
  1663.         GetArguments(fname);
  1664.         if token <> DoneT then begin
  1665.                 if fname = '' then
  1666.                     fname := DefaultFileName;
  1667.                 err := fsopen(fname, DefaultRefNum, f);
  1668.                 FileFound := err = NoErr;
  1669.                 err := fsclose(f);
  1670.                 if FileFound then
  1671.                     case SaveCommand of
  1672.                         OpenC: 
  1673.                             result := DoOpen(fname, DefaultRefNum);
  1674.                         ImportC: 
  1675.                             result := ImportFile(fname, DefaultRefNum);
  1676.                     end
  1677.                 else
  1678.                     case SaveCommand of
  1679.                         OpenC: 
  1680.                             result := DoOpen('', 0);
  1681.                         ImportC: 
  1682.                             result := ImportFile('', 0);
  1683.                     end;
  1684.                 if not result then
  1685.                     token := DoneT;
  1686.             end;
  1687.     end;
  1688.  
  1689.  
  1690.     procedure SetImportAttributes;
  1691.         var
  1692.             Attributes: str255;
  1693.     begin
  1694.         Attributes := GetStringArg;
  1695.         if Token <> DoneT then begin
  1696.                 MakeLowerCase(Attributes);
  1697.                 WhatToImport := ImportTIFF;
  1698.                 ImportCustomDepth := EightBits;
  1699.                 ImportSwapBytes := false;
  1700.                 ImportCalibrate := false;
  1701.                 ImportAll := false;
  1702.                 ImportAutoScale := true;
  1703.                 if pos('mcid', Attributes) <> 0 then
  1704.                     WhatToImport := ImportMCID;
  1705.                 if pos('look', Attributes) <> 0 then
  1706.                     WhatToImport := ImportLUT;
  1707.                 if pos('palette', Attributes) <> 0 then
  1708.                     WhatToImport := ImportLUT;
  1709.                 if pos('text', Attributes) <> 0 then
  1710.                     WhatToImport := ImportText;
  1711.                 if pos('custom', Attributes) <> 0 then
  1712.                     WhatToImport := ImportCustom;
  1713.                 if (pos('8', Attributes) <> 0) or (pos('eight', Attributes) <> 0) then begin
  1714.                         ImportCustomDepth := EightBits;
  1715.                         WhatToImport := ImportCustom;
  1716.                     end;
  1717.                 if (pos('signed', Attributes) <> 0) then begin
  1718.                         ImportCustomDepth := SixteenBitsSigned;
  1719.                         WhatToImport := ImportCustom;
  1720.                     end;
  1721.                 if (pos('unsigned', Attributes) <> 0) then begin
  1722.                         ImportCustomDepth := SixteenBitsUnsigned;
  1723.                         WhatToImport := ImportCustom;
  1724.                     end;
  1725.                 if (pos('swap', Attributes) <> 0) then
  1726.                     ImportSwapBytes := true;
  1727.                 if (pos('calibrate', Attributes) <> 0) then
  1728.                     ImportCalibrate := true;
  1729.                 if (pos('fixed', Attributes) <> 0) then
  1730.                     ImportAutoScale := false;
  1731.                 if (pos('all', Attributes) <> 0) then
  1732.                     ImportAll := true;
  1733.             end;
  1734.     end;
  1735.  
  1736.  
  1737.     procedure SetImportMinMax; {(min,max:integer)}
  1738.         var
  1739.             TempMin, TempMax: extended;
  1740.     begin
  1741.         GetLeftParen;
  1742.         TempMin := GetExpression;
  1743.         GetComma;
  1744.         TempMax := GetExpression;
  1745.         GetRightParen;
  1746.         if Token <> DoneT then begin
  1747.                 ImportAutoScale := false;
  1748.                 ImportMin := TempMin;
  1749.                 ImportMax := TempMax;
  1750.             end;
  1751.     end;
  1752.  
  1753.  
  1754.     procedure SetCustomImport; {(width,height,offset:integer)}
  1755.         var
  1756.             width, height: integer;
  1757.             offset: LongInt;
  1758.     begin
  1759.         GetLeftParen;
  1760.         width := GetInteger;
  1761.         GetComma;
  1762.         height := GetInteger;
  1763.         GetComma;
  1764.         offset := GetInteger;
  1765.         GetRightParen;
  1766.         if (width < 0) or (width > MaxPicSize) or (height < 0) or (offset < 0) then
  1767.             MacroError('Argument out of range');
  1768.         if Token <> DoneT then begin
  1769.                 ImportCustomWidth := width;
  1770.                 ImportCustomHeight := height;
  1771.                 ImportCustomOffset := offset;
  1772.                 WhatToImport := ImportCustom;
  1773.             end;
  1774.     end;
  1775.  
  1776.  
  1777.     procedure SelectPic; {(WindowID:integer)}
  1778.         var
  1779.             WindowID: integer;
  1780.             SaveCommand: CommandType;
  1781.     begin
  1782.         SaveCommand := MacroCommand;
  1783.         GetLeftParen;
  1784.         WindowID := GetInteger;
  1785.         if (WindowID < 1) or (WindowID > nPICS) then
  1786.             MacroError('Invalid window ID');
  1787.         GetRightParen;
  1788.         if Token <> DoneT then begin
  1789.                 if SaveCommand = SelectPicC then begin
  1790.                         StopDigitizing;
  1791.                         SaveRoi;
  1792.                         DisableDensitySlice;
  1793.                         SelectWindow(PicWindow[WindowID]);
  1794.                         Info := pointer(WindowPeek(PicWindow[WindowID])^.RefCon);
  1795.                         ActivateWindow;
  1796.                     end
  1797.                 else
  1798.                     Info := pointer(WindowPeek(PicWindow[WindowID])^.RefCon);
  1799.             end;
  1800.     end;
  1801.  
  1802.  
  1803.     procedure SetPicName;  {(name:string)}
  1804.         var
  1805.             n, i: LongInt;
  1806.             isInteger: boolean;
  1807.             name: str255;
  1808.     begin
  1809.         GetArguments(name);
  1810.         if Token <> DoneT then begin
  1811.                 with info^ do begin
  1812.                         title := name;
  1813.                         if PictureType <> QuickCaptureType then
  1814.                             PictureType := NewPicture;
  1815.                         UpdateWindowsMenuItem(ImageSize, title, PicNum);
  1816.                         UpdateTitleBar;
  1817.                     end;
  1818.             end;
  1819.     end;
  1820.  
  1821.  
  1822.     procedure SetNewSize; {(width,height:integer)}
  1823.         var
  1824.             TempWidth, TempHeight: integer;
  1825.     begin
  1826.         GetLeftParen;
  1827.         TempWidth := GetInteger;
  1828.         GetComma;
  1829.         TempHeight := GetInteger;
  1830.         GetRightParen;
  1831.         if Token <> DoneT then begin
  1832.                 NewPicWidth := TempWidth;
  1833.                 NewPicHeight := TempHeight;
  1834.                 if odd(NewPicWidth) then
  1835.                     NewPicWidth := NewPicWidth + 1;
  1836.                 if NewPicWidth > MaxPicSize then
  1837.                     NewPicWidth := MaxPicSize;
  1838.                 if NewPicWidth < 8 then
  1839.                     NewPicWidth := 8;
  1840.                 if NewPicHeight < 8 then
  1841.                     NewPicHeight := 8;
  1842.                 if NewPicHeight > MaxPicSize then
  1843.                     NewPicHeight := MaxPicSize;
  1844.             end;
  1845.     end;
  1846.  
  1847.  
  1848.     procedure DoSaveAs;
  1849.         var
  1850.             name: str255;
  1851.             RefNum: integer;
  1852.             HasArgs: boolean;
  1853.     begin
  1854.         name := info^.title;
  1855.         if (name = 'Untitled') or (name = 'Camera') then
  1856.             name := '';
  1857.         GetToken;
  1858.         HasArgs := token = LeftParen;
  1859.         PutTokenBack;
  1860.         if HasArgs then
  1861.             GetArguments(name);
  1862.         if token <> DoneT then begin
  1863.                 StopDigitizing;
  1864.                 if nSaves = 0 then
  1865.                     RefNum := 0
  1866.                 else
  1867.                     RefNum := DefaultRefNum;
  1868.                 SaveAs(name, RefNum);
  1869.                 nSaves := nSaves + 1;
  1870.             end;
  1871.     end;
  1872.  
  1873.  
  1874.     procedure DoExport;
  1875.         var
  1876.             name: str255;
  1877.             RefNum: integer;
  1878.     begin
  1879.         StopDigitizing;
  1880.         name := info^.title;
  1881.         if (name = 'Untitled') or (name = 'Camera') then
  1882.             name := '';
  1883.         if nSaves = 0 then
  1884.             RefNum := 0
  1885.         else
  1886.             RefNum := DefaultRefNum;
  1887.         UpdateFileMenu;
  1888.         Export(name, RefNum);
  1889.         nSaves := nSaves + 1;
  1890.     end;
  1891.  
  1892.  
  1893.     procedure DoCopyResults;
  1894.         var
  1895.             IgnoreResult: boolean;
  1896.     begin
  1897.         if mCount < 1 then
  1898.             MacroError('Copy Results failed')
  1899.         else begin
  1900.                 CopyResults;
  1901.                 IgnoreResult := SystemEdit(3); {Fake Copy needed for MultiFinder}
  1902.             end;
  1903.     end;
  1904.  
  1905.  
  1906.     procedure DisposeAll;
  1907.         var
  1908.             i, ignore: integer;
  1909.     begin
  1910.         StopDigitizing;
  1911.         for i := nPics downto 1 do begin
  1912.                 Info := pointer(WindowPeek(PicWindow[i])^.RefCon);
  1913.                 ignore := CloseAWindow(info^.wptr);
  1914.             end;
  1915.     end;
  1916.  
  1917.  
  1918.     procedure DoDuplicate;
  1919.         var
  1920.             str: str255;
  1921.     begin
  1922.         GetArguments(str);
  1923.         if token <> DoneT then
  1924.             if not Duplicate(str, false) then
  1925.                 token := DoneT
  1926.             else
  1927.                 UpdatePicWindow;
  1928.     end;
  1929.  
  1930.  
  1931.     procedure DoLineTo; {(x,y:integer)}
  1932.         var
  1933.             x, y: integer;
  1934.             p1, p2: point;
  1935.     begin
  1936.         GetLeftParen;
  1937.         p2.h := GetInteger;
  1938.         GetComma;
  1939.         p2.v := GetInteger;
  1940.         GetRightParen;
  1941.         if token <> DoneT then begin
  1942.                 p1.h := CurrentX;
  1943.                 p1.v := CurrentY;
  1944.                 CurrentX := p2.h;
  1945.                 CurrentY := p2.v;
  1946.                 OffscreenToScreen(p1);
  1947.                 OffscreenToScreen(p2);
  1948.                 DrawObject(LineObj, p1, p2);
  1949.             end;
  1950.     end;
  1951.  
  1952.  
  1953.     procedure DoGetLine;  {(var x1,y1,x2,y2:real; LineWidth:integer)}
  1954.         var
  1955.             loc1, loc2, loc3, loc4, loc5: integer;
  1956.             x1, y1, x2, y2: real;
  1957.     begin
  1958.         GetLeftParen;
  1959.         loc1 := GetVar;
  1960.         GetComma;
  1961.         loc2 := GetVar;
  1962.         GetComma;
  1963.         loc3 := GetVar;
  1964.         GetComma;
  1965.         loc4 := GetVar;
  1966.         GetComma;
  1967.         loc5 := GetVar;
  1968.         GetRightParen;
  1969.         if Token <> DoneT then
  1970.             with MacrosP^, info^ do begin
  1971.                     GetLoi(x1, y1, x2, y2);
  1972.                     if RoiShowing and (RoiType = LineRoi) then
  1973.                         stack[loc1].value := x1
  1974.                     else
  1975.                         stack[loc1].value := -1;
  1976.                     stack[loc2].value := y1;
  1977.                     stack[loc3].value := x2;
  1978.                     stack[loc4].value := y2;
  1979.                     stack[loc5].value := LineWidth;
  1980.                 end;
  1981.     end;
  1982.  
  1983.  
  1984.     procedure SetChannel; {(channel:integer)}
  1985.         var
  1986.             channel: integer;
  1987.     begin
  1988.         GetLeftParen;
  1989.         channel := GetInteger;
  1990.         GetRightParen;
  1991.         if (channel < 0) or (channel > 3) then
  1992.             MacroError('Bad channel number')
  1993.         else
  1994.             VideoChannel := channel;
  1995.     end;
  1996.  
  1997.  
  1998.     procedure DoScaleAndRotate; {(hscale,vscale,angle:real)}
  1999.         var
  2000.             SaveCommand: CommandType;
  2001.     begin
  2002.         SaveCommand := MacroCommand;
  2003.         GetLeftParen;
  2004.         rsHScale := GetExpression;
  2005.         GetComma;
  2006.         rsVScale := GetExpression;
  2007.         if SaveCommand <> ScaleSelectionC then begin
  2008.                 GetComma;
  2009.                 rsAngle := GetExpression;
  2010.             end;
  2011.         GetRightParen;
  2012.         if token <> DoneT then begin
  2013.                 if SaveCommand = ScaleSelectionC then begin
  2014.                         rsMethod := NearestNeighbor;
  2015.                         rsCreateNewWindow := false;
  2016.                         rsAngle := 0.0;
  2017.                     end;
  2018.                 ScaleAndRotate;
  2019.             end;
  2020.     end;
  2021.  
  2022.  
  2023.     procedure SetPlotScale; {(min,max:integer)}
  2024.         var
  2025.             min, max: extended;
  2026.     begin
  2027.         GetLeftParen;
  2028.         min := GetExpression;
  2029.         GetComma;
  2030.         max := GetExpression;
  2031.         GetRightParen;
  2032.         if not info^.DensityCalibrated then begin
  2033.                 RangeCheck(trunc(min));
  2034.                 RangeCheck(trunc(max));
  2035.             end;
  2036.         if token <> DoneT then begin
  2037.                 AutoScalePlots := (min = 0.0) and (max = 0.0);
  2038.                 ProfilePlotMin := min;
  2039.                 ProfilePlotMax := max;
  2040.             end;
  2041.     end;
  2042.  
  2043.  
  2044.     procedure SetPlotDimensions; {(width,height:integer)}
  2045.         var
  2046.             width, height: integer;
  2047.     begin
  2048.         GetLeftParen;
  2049.         width := GetInteger;
  2050.         GetComma;
  2051.         height := GetInteger;
  2052.         GetRightParen;
  2053.         if token <> DoneT then begin
  2054.                 FixedSizePlot := not ((width = 0) and (height = 0));
  2055.                 ProfilePlotWidth := width;
  2056.                 ProfilePlotHeight := height;
  2057.             end;
  2058.     end;
  2059.  
  2060.  
  2061.     procedure GetResults;  {(var n,mean,mode,min,max:real)}
  2062.         var
  2063.             loc1, loc2, loc3, loc4, loc5: integer;
  2064.     begin
  2065.         GetLeftParen;
  2066.         loc1 := GetVar;
  2067.         GetComma;
  2068.         loc2 := GetVar;
  2069.         GetComma;
  2070.         loc3 := GetVar;
  2071.         GetComma;
  2072.         loc4 := GetVar;
  2073.         GetComma;
  2074.         loc5 := GetVar;
  2075.         GetRightParen;
  2076.         if mCount = 0 then
  2077.             MacroError('No results');
  2078.         if Token <> DoneT then
  2079.             with MacrosP^, results do begin
  2080.                     stack[loc1].value := PixelCount^[mCount];
  2081.                     stack[loc2].value := imean;
  2082.                     stack[loc3].value := imode;
  2083.                     stack[loc4].value := MinIndex;
  2084.                     stack[loc5].value := MaxIndex;
  2085.                 end;
  2086.     end;
  2087.  
  2088.  
  2089.     procedure DoPasteOperation;
  2090.     begin
  2091.         if not (OpPending and (CurrentOp = PasteOp)) then begin
  2092.                 MacroError('Not pasting');
  2093.                 exit(DoPasteOperation);
  2094.             end;
  2095.         if MacroCommand in [AddC, SubC, MulC, DivC] then begin
  2096.                 case MacroCommand of
  2097.                     AddC: 
  2098.                         CurrentOp := AddOp;
  2099.                     SubC: 
  2100.                         CurrentOp := SubtractOp;
  2101.                     MulC: 
  2102.                         CurrentOp := MultiplyOp;
  2103.                     DivC: 
  2104.                         CurrentOp := DivideOp;
  2105.                 end;
  2106.                 DoMath;
  2107.                 exit(DoPasteOperation);
  2108.             end;
  2109.         case MacroCommand of
  2110.             CopyModeC: 
  2111.                 SetPasteMode(CopyModeItem);
  2112.             AndC: 
  2113.                 SetPasteMode(AndItem);
  2114.             OrC: 
  2115.                 SetPasteMode(OrItem);
  2116.             XorC: 
  2117.                 SetPasteMode(XorItem);
  2118.             ReplaceC: 
  2119.                 SetPasteMode(ReplaceItem);
  2120.             BlendC: 
  2121.                 SetPasteMode(BlendItem);
  2122.         end;
  2123.         if OptionKeyWasDown then begin
  2124.                 if PasteControl <> nil then
  2125.                     DrawPasteControl;
  2126.             end
  2127.         else
  2128.             KillRoi;
  2129.     end;
  2130.  
  2131.  
  2132.     procedure SetLineWidth; {(width:integer)}
  2133.         var
  2134.             width: integer;
  2135.     begin
  2136.         GetLeftParen;
  2137.         width := GetInteger;
  2138.         GetRightParen;
  2139.         if (Token <> DoneT) and (width > 0) then begin
  2140.                 LineWidth := width;
  2141.                 ShowLIneWidth;
  2142.             end;
  2143.     end;
  2144.  
  2145.  
  2146.     function GetMType (index: integer): MeasurementTypes;
  2147.     begin
  2148.         case index of
  2149.             0: 
  2150.                 GetMType := AreaM;
  2151.             1: 
  2152.                 GetMType := MeanM;
  2153.             2: 
  2154.                 GetMType := StdDevM;
  2155.             3: 
  2156.                 GetMType := xyLocM;
  2157.             4: 
  2158.                 GetMType := ModeM;
  2159.             5: 
  2160.                 GetMType := LengthM;
  2161.             6: 
  2162.                 GetMType := MajorAxisM;
  2163.             7: 
  2164.                 GetMType := MinorAxisM;
  2165.             8: 
  2166.                 GetMType := AngleM;
  2167.             9: 
  2168.                 GetMType := IntDenM;
  2169.             10: 
  2170.                 GetMType := MinMaxM;
  2171.             11: 
  2172.                 GetMType := User1M;
  2173.             12: 
  2174.                 GetMType := User2M;
  2175.         end;
  2176.     end;
  2177.  
  2178.  
  2179.     procedure SetMeasurements;
  2180.         var
  2181.             index: integer;
  2182.             mtype: MeasurementTypes;
  2183.     begin
  2184.         index := ord(MacroCommand) - ord(AreaC);
  2185.         mtype := GetMType(index);
  2186.         if GetBooleanArg then
  2187.             measurements := measurements + [mtype]
  2188.         else
  2189.             measurements := measurements - [mtype];
  2190.         UpdateFitEllipse;
  2191.     end;
  2192.  
  2193.  
  2194.     procedure SetPrecision; {(DigitsRightofDecimalPoint:integer)}
  2195.         var
  2196.             digits: LongInt;
  2197.     begin
  2198.         GetLeftParen;
  2199.         digits := GetInteger;
  2200.         GetRightParen;
  2201.         if (Token <> DoneT) and (digits >= 0) and (digits <= 12) then
  2202.             precision := digits;
  2203.     end;
  2204.  
  2205.  
  2206.     procedure SetParticleSize; {(min,max:LongInt)}
  2207.         var
  2208.             min, max: LongInt;
  2209.     begin
  2210.         GetLeftParen;
  2211.         min := GetInteger;
  2212.         GetComma;
  2213.         max := GetInteger;
  2214.         GetRightParen;
  2215.         if Token <> DoneT then begin
  2216.                 MinParticleSize := min;
  2217.                 MaxParticleSize := max;
  2218.             end;
  2219.     end;
  2220.  
  2221.  
  2222.     procedure SetThreshold; {(level:integer)}
  2223.         var
  2224.             level: LongInt;
  2225.     begin
  2226.         GetLeftParen;
  2227.         level := GetInteger;
  2228.         GetRightParen;
  2229.         if level = -1 then begin
  2230.                 ResetGrayMap;
  2231.                 exit(SetThreshold);
  2232.             end;
  2233.         RangeCheck(level);
  2234.         if Token <> DoneT then
  2235.             EnableThresholding(level);
  2236.     end;
  2237.  
  2238.  
  2239.     procedure DoPutPixel; {(hloc,vloc, value:integer)}
  2240.         var
  2241.             hloc, vloc, value: integer;
  2242.             MaskRect: rect;
  2243.     begin
  2244.         GetLeftParen;
  2245.         hloc := GetInteger;
  2246.         GetComma;
  2247.         vloc := GetInteger;
  2248.         GetComma;
  2249.         value := GetInteger;
  2250.         GetRightParen;
  2251.         if (Token <> DoneT) and (info <> NoInfo) then begin
  2252.                 PutPixel(hloc, vloc, value);
  2253.                 SetRect(MaskRect, hloc, vloc, hloc + 1, vloc + 1);
  2254.                 UpdateScreen(MaskRect);
  2255.             end;
  2256.     end;
  2257.  
  2258.  
  2259.     procedure ClosePicWindow;
  2260.         var
  2261.             OldPicNum, NewPicNum, ignore: integer;
  2262.     begin
  2263.         StopDigitizing;
  2264.         SaveRoi;
  2265.         with info^ do begin
  2266.                 OldPicNum := PicNum;
  2267.                 ignore := CloseAWindow(wptr);
  2268.             end;
  2269.         if nPics >= 1 then begin
  2270.                 NewPicNum := OldPicNum - 1;
  2271.                 if NewPicNum < 1 then
  2272.                     NewPicNum := 1;
  2273.                 Info := pointer(WindowPeek(PicWindow[NewPicNum])^.RefCon);
  2274.             end;
  2275.     end;
  2276.  
  2277.  
  2278.     procedure SetScaling;
  2279.         var
  2280.             ScalingOptions: str255;
  2281.             ok: boolean;
  2282.     begin
  2283.         ScalingOptions := GetStringArg;
  2284.         if token <> DoneT then begin
  2285.                 MakeLowerCase(ScalingOptions);
  2286.                 rsInteractive := false;
  2287.                 if pos('bilinear', ScalingOptions) <> 0 then
  2288.                     rsMethod := Bilinear;
  2289.                 if pos('nearest', ScalingOptions) <> 0 then
  2290.                     rsMethod := NearestNeighbor;
  2291.                 if pos('new', ScalingOptions) <> 0 then
  2292.                     rsCreateNewWindow := true;
  2293.                 if pos('same', ScalingOptions) <> 0 then
  2294.                     rsCreateNewWindow := false;
  2295.                 if pos('interactive', ScalingOptions) <> 0 then
  2296.                     rsInteractive := true;
  2297.             end;
  2298.     end;
  2299.  
  2300.  
  2301.     procedure DoChangeValues; {(v1,v2,v3:integer)}
  2302.         var
  2303.             v1, v2, v3: integer;
  2304.     begin
  2305.         GetLeftParen;
  2306.         v1 := GetInteger;
  2307.         GetComma;
  2308.         v2 := GetInteger;
  2309.         GetComma;
  2310.         v3 := GetInteger;
  2311.         GetRightParen;
  2312.         RangeCheck(v1);
  2313.         RangeCheck(v2);
  2314.         RangeCheck(v3);
  2315.         if Token <> DoneT then
  2316.             ChangeValues(v1, v2, v3);
  2317.     end;
  2318.  
  2319.  
  2320.     procedure DoGetMouse;  {(var x,y:integer)}
  2321.         var
  2322.             loc1, loc2, sh, sv: integer;
  2323.             loc: point;
  2324.     begin
  2325.         GetLeftParen;
  2326.         loc1 := GetVar;
  2327.         GetComma;
  2328.         loc2 := GetVar;
  2329.         GetRightParen;
  2330.         if Token <> DoneT then
  2331.             with MacrosP^ do begin
  2332.                     SetPort(info^.wptr);
  2333.                     GetMouse(loc);
  2334.                     with loc do begin
  2335.                             sh := h;
  2336.                             sv := v;
  2337.                             ScreenToOffscreen(loc);
  2338.                             if sh < 0 then
  2339.                                 h := sh;
  2340.                             if sv < 0 then
  2341.                                 v := sv;
  2342.                             stack[loc1].value := h;
  2343.                             stack[loc2].value := v;
  2344.                         end;
  2345.                 end;
  2346.     end;
  2347.  
  2348.  
  2349.     procedure DoRotate (cmd: CommandType);
  2350.         var
  2351.             NoBoolean, NewWindow: boolean;
  2352.     begin
  2353.         GetToken;
  2354.         noBoolean := token <> LeftParen;
  2355.         PutTokenBack;
  2356.         if NoBoolean then
  2357.             NewWindow := false
  2358.         else
  2359.             NewWindow := GetBooleanArg;
  2360.         if NewWindow then begin
  2361.                 case cmd of
  2362.                     RotateRC: 
  2363.                         RotateToNewWindow(RotateRight);
  2364.                     RotateLC: 
  2365.                         RotateToNewWindow(RotateLeft)
  2366.                 end;
  2367.                 if not macro then
  2368.                     MacroError('Rotate failed')
  2369.             end
  2370.         else
  2371.             case cmd of
  2372.                 RotateRC: 
  2373.                     FlipOrRotate(RotateRight);
  2374.                 RotateLC: 
  2375.                     FlipOrRotate(RotateLeft)
  2376.             end;
  2377.     end;
  2378.  
  2379.  
  2380.     procedure DoSelectSlice; {(SliceNumber:integer)}
  2381.         var
  2382.             SliceNumber: LongInt;
  2383.             isRoi: boolean;
  2384.             SaveCommand: CommandType;
  2385.     begin
  2386.         SaveCommand := MacroCommand;
  2387.         GetLeftParen;
  2388.         SliceNumber := GetInteger;
  2389.         GetRightParen;
  2390.         with info^, info^.StackInfo^ do begin
  2391.                 if (SliceNumber < 1) or (SliceNumber > nSlices) then
  2392.                     MacroError('Illegal slice number');
  2393.                 if Token <> DoneT then begin
  2394.                         isRoi := RoiShowing;
  2395.                         if isRoi then
  2396.                             KillRoi;
  2397.                         CurrentSlice := SliceNumber;
  2398.                         SelectSlice(CurrentSlice);
  2399.                         if SaveCommand = SelectSliceC then begin
  2400.                                 UpdatePicWindow;
  2401.                                 UpdateTitleBar;
  2402.                             end;
  2403.                         if isRoi then
  2404.                             RestoreRoi;
  2405.                     end;
  2406.             end;
  2407.     end;
  2408.  
  2409.  
  2410.     procedure MakeNewStack; {(name:str255)}
  2411.         var
  2412.             name: str255;
  2413.             aok: boolean;
  2414.     begin
  2415.         GetArguments(name);
  2416.         if token <> DoneT then
  2417.             if (LongInt(NewPicWidth) * NewPicHeight) > UndoBufSize then
  2418.                 MacroError('Stack too large')
  2419.             else if NewPicWindow(name, NewPicWidth, NewPicHeight) then
  2420.                 if not MakeStackFromWindow then
  2421.                     MacroError('Out of memory');
  2422.     end;
  2423.  
  2424.  
  2425.     procedure MakeLineRoi; {(x1,y1,x2,y2:integer)}
  2426.         var
  2427.             x1, y1, x2, y2: LongInt;
  2428.     begin
  2429.         GetLeftParen;
  2430.         x1 := GetInteger;
  2431.         GetComma;
  2432.         y1 := GetInteger;
  2433.         GetComma;
  2434.         x2 := GetInteger;
  2435.         GetComma;
  2436.         y2 := GetInteger;
  2437.         GetRightParen;
  2438.         if token <> DoneT then
  2439.             with Info^ do begin
  2440.                     KillRoi;
  2441.                     StopDigitizing;
  2442.                     LX1 := x1;
  2443.                     LY1 := y1;
  2444.                     LX2 := x2;
  2445.                     LY2 := y2;
  2446.                     RoiType := LineRoi;
  2447.                     MakeRegion;
  2448.                     SetupUndo;
  2449.                     RoiShowing := true;
  2450.                 end;
  2451.     end;
  2452.  
  2453.  
  2454.     procedure DoGetTime;
  2455.         var
  2456.             date: DateTimeRec;
  2457.             loc1, loc2, loc3, loc4, loc5, loc6, loc7: integer;
  2458.     begin
  2459.         GetLeftParen;
  2460.         loc1 := GetVar;
  2461.         GetComma;
  2462.         loc2 := GetVar;
  2463.         GetComma;
  2464.         loc3 := GetVar;
  2465.         GetComma;
  2466.         loc4 := GetVar;
  2467.         GetComma;
  2468.         loc5 := GetVar;
  2469.         GetComma;
  2470.         loc6 := GetVar;
  2471.         GetComma;
  2472.         loc7 := GetVar;
  2473.         GetRightParen;
  2474.         if Token <> DoneT then
  2475.             with MacrosP^, info^ do begin
  2476.                     GetTime(date);
  2477.                     with date do begin
  2478.                             stack[loc1].value := year;
  2479.                             stack[loc2].value := month;
  2480.                             stack[loc3].value := day;
  2481.                             stack[loc4].value := hour;
  2482.                             stack[loc5].value := minute;
  2483.                             stack[loc6].value := second;
  2484.                             stack[loc7].value := DayOfWeek;
  2485.                         end;
  2486.                 end;
  2487.     end;
  2488.  
  2489.  
  2490.     procedure DoSetScale; {(scale:real; units:string)}
  2491.         var
  2492.             id: integer;
  2493.             scale: extended;
  2494.             str: str255;
  2495.     begin
  2496.         GetLeftParen;
  2497.         scale := GetExpression;
  2498.         GetComma;
  2499.         str := GetString;
  2500.         GetRightParen;
  2501.         if token <> DoneT then
  2502.             with info^ do begin
  2503.                     if str = '' then begin
  2504.                             SetScale;
  2505.                             exit(DoSetScale);
  2506.                         end;
  2507.                     if scale < 0.0 then begin
  2508.                             MacroError('Scale<0');
  2509.                             exit(DoSetScale);
  2510.                         end;
  2511.                     MakeLowerCase(str);
  2512.                     if pos('nm', str) <> 0 then
  2513.                         id := 5
  2514.                     else if pos('â•¡m', str) <> 0 then
  2515.                         id := 6
  2516.                     else if pos('mm', str) <> 0 then
  2517.                         id := 7
  2518.                     else if pos('cm', str) <> 0 then
  2519.                         id := 8
  2520.                     else if pos('me', str) <> 0 then
  2521.                         id := 9
  2522.                     else if pos('km', str) <> 0 then
  2523.                         id := 10
  2524.                     else if pos('in', str) <> 0 then
  2525.                         id := 11
  2526.                     else if pos('ft', str) <> 0 then
  2527.                         id := 12
  2528.                     else if pos('mi', str) <> 0 then
  2529.                         id := 13
  2530.                     else
  2531.                         id := 14; {pixels}
  2532.                     RawSpatialScale := scale;
  2533.                     xSpatialScale := scale;
  2534.                     ySpatialScale := scale;
  2535.                     PixelAspectRatio := 1.0;
  2536.                     ScaleMagnification := 1.0;
  2537.                     SpatiallyCalibrated := xSpatialScale <> 0.0;
  2538.                     GetUnits(id);
  2539.                 end;
  2540.     end;
  2541.  
  2542.  
  2543.     procedure SaveState;
  2544.     begin
  2545.         SaveForeground := ForegroundIndex;
  2546.         SaveBackground := BackgroundIndex;
  2547.         SavePicWidth := NewPicWidth;
  2548.         SavePicHeight := NewPicHeight;
  2549.         SaveMethod := rsMethod;
  2550.         SaveCreate := rsCreateNewWindow;
  2551.         SaveAngle := rsAngle;
  2552.         SaveH := rsHScale;
  2553.         SaveV := rsVScale;
  2554.         SaveInvertY := InvertYCoordinates;
  2555.     end;
  2556.  
  2557.  
  2558.     procedure RestoreState;
  2559.     begin
  2560.         if SaveForeground = -1 then
  2561.             MacroError('State not saved')
  2562.         else begin
  2563.                 SetForegroundColor(SaveForeground);
  2564.                 SetBackgroundColor(SaveBackground);
  2565.                 NewPicWidth := SavePicWidth;
  2566.                 NewPicHeight := SavePicHeight;
  2567.                 rsMethod := SaveMethod;
  2568.                 rsCreateNewWindow := SaveCreate;
  2569.                 rsAngle := SaveAngle;
  2570.                 rsHScale := SaveH;
  2571.                 rsVScale := SaveV;
  2572.                 InvertYCoordinates := SaveInvertY;
  2573.             end;
  2574.     end;
  2575.  
  2576.  
  2577.     procedure DoPrint;
  2578.     begin
  2579.         FindWhatToPrint;
  2580.         if WhatToPrint <> NothingToPrint then
  2581.             Print(false)
  2582.         else
  2583.             MacroError('NothingToPrint');
  2584.     end;
  2585.  
  2586.  
  2587.     procedure SetCounter; {(n:integer)}
  2588.         var
  2589.             N, i: LongInt;
  2590.     begin
  2591.         GetLeftParen;
  2592.         N := GetInteger;
  2593.         GetRightParen;
  2594.         if (N < 0) or (N > MaxRegions) then
  2595.             MacroError('Argument out of range');
  2596.         if Token <> DoneT then begin
  2597.                 if N = 0 then
  2598.                     ResetCounter;
  2599.                 for i := mCount + 1 to N do
  2600.                     ClearResults(i);
  2601.                 mCount := N;
  2602.                 UpdateList;
  2603.                 ShowValues;
  2604.             end;
  2605.     end;
  2606.  
  2607.  
  2608.     procedure OutputText;
  2609.         var
  2610.             NewLine: boolean;
  2611.             str: str255;
  2612.             i: integer;
  2613.             SaveCommand: CommandType;
  2614.     begin
  2615.         NewLine := MacroCommand <> WriteC;
  2616.         SaveCommand := MacroCommand;
  2617.         GetArguments(str);
  2618.         if token <> DoneT then begin
  2619.                 if SaveCommand = ShowMsgC then begin
  2620.                         for i := 1 to length(str) do
  2621.                             if str[i] = '\' then
  2622.                                 str[i] := cr;
  2623.                         ValuesMessage := str;
  2624.                         ShowValues;
  2625.                     end
  2626.                 else
  2627.                     DoDrawText(str, NewLine);
  2628.             end;
  2629.     end;
  2630.  
  2631.  
  2632.     procedure SetErosionDilationCount; {(n:integer)}
  2633.         var
  2634.             n: LongInt;
  2635.     begin
  2636.         GetLeftParen;
  2637.         n := GetInteger;
  2638.         GetRightParen;
  2639.         if (n < 1) or (n > 8) then
  2640.             MacroError('Argument out of range');
  2641.         if Token <> DoneT then begin
  2642.                 BinaryCount := n;
  2643.                 BinaryThreshold := BinaryCount * 255;
  2644.             end;
  2645.     end;
  2646.  
  2647.  
  2648.     procedure SetSliceSpacing; {(n:real)}
  2649.         var
  2650.             n: real;
  2651.     begin
  2652.         GetLeftParen;
  2653.         n := GetExpression;
  2654.         GetRightParen;
  2655.         if (n <= 0.0) or (n > 100.0) then
  2656.             MacroError('Spacing must be >0 and <100');
  2657.         if info^.StackInfo = nil then
  2658.             MacroError('No stack');
  2659.         if Token <> DoneT then
  2660.             info^.StackInfo^.SliceSpacing := n;
  2661.     end;
  2662.  
  2663.  
  2664. {$POP}
  2665.  
  2666.  
  2667.     procedure GetOrPutLineOrColumn;  {(x,y,count:integer:integer)}
  2668.         var
  2669.             x, y, count, i: integer;
  2670.             MaskRect: rect;
  2671.             aLine2: LineType;
  2672.     begin
  2673.         GetLeftParen;
  2674.         x := GetInteger;
  2675.         GetComma;
  2676.         y := GetInteger;
  2677.         GetComma;
  2678.         count := GetInteger;
  2679.         GetRightParen;
  2680.         if (Token <> DoneT) and (count <= MaxLine) then
  2681.             with MacrosP^ do
  2682.                 case MacroCommand of
  2683.                     GetRowC: 
  2684.                         GetLine(x, y, count, aLine);
  2685.                     PutRowC:  begin
  2686.                             PutLine(x, y, count, aLine);
  2687.                             SetRect(MaskRect, x, y, x + count, y + 1);
  2688.                             UpdateScreen(MaskRect);
  2689.                         end;
  2690.                     GetColumnC: 
  2691.                         GetColumn(x, y, count, aLine);
  2692.                     PutColumnC:  begin
  2693.                             PutColumn(x, y, count, aLine);
  2694.                             SetRect(MaskRect, x, y, x + 1, y + count);
  2695.                             UpdateScreen(MaskRect);
  2696.                         end;
  2697.                 end;
  2698.     end;
  2699.  
  2700.  
  2701.     procedure CheckVersion; {(RequiredVersion:real)}
  2702.         var
  2703.             RequiredVersion: real;
  2704.             str: str255;
  2705.     begin
  2706.         GetLeftParen;
  2707.         RequiredVersion := GetExpression;
  2708.         GetRightParen;
  2709.         if (Token <> DoneT) then
  2710.             if (RequiredVersion * 100.0) > version then begin
  2711.                     RealToString(RequiredVersion, 1, 2, str);
  2712.                     PutMessage(concat('This macro requires version ', str, ' or later of Image.'));
  2713.                     Token := DoneT;
  2714.                 end;
  2715.     end;
  2716.  
  2717.  
  2718.     procedure SetOptions; {(Options:string)}
  2719.         var
  2720.             options: str255;
  2721.             mtype: MeasurementTypes;
  2722.             i, LastOption: integer;
  2723.             SaveMeasurements: set of MeasurementTypes;
  2724.     begin
  2725.         GetLeftParen;
  2726.         Options := GetString;
  2727.         GetRightParen;
  2728.         if (Token <> DoneT) then begin
  2729.                 SaveMeasurements := measurements;
  2730.                 MakeLowerCase(options);
  2731.                 Measurements := [];
  2732.                 if pos('area', options) <> 0 then
  2733.                     Measurements := Measurements + [AreaM];
  2734.                 if pos('mean', options) <> 0 then
  2735.                     Measurements := Measurements + [MeanM];
  2736.                 if pos('st', options) <> 0 then
  2737.                     Measurements := Measurements + [StdDevM];
  2738.                 if pos('center', options) <> 0 then
  2739.                     Measurements := Measurements + [xyLocM];
  2740.                 if pos('mode', options) <> 0 then
  2741.                     Measurements := Measurements + [ModeM];
  2742.                 if (pos('per', options) <> 0) or (pos('length', options) <> 0) then
  2743.                     Measurements := Measurements + [LengthM];
  2744.                 if pos('major', options) <> 0 then
  2745.                     Measurements := Measurements + [MajorAxisM];
  2746.                 if pos('minor', options) <> 0 then
  2747.                     Measurements := Measurements + [MinorAxisM];
  2748.                 if pos('angle', options) <> 0 then
  2749.                     Measurements := Measurements + [AngleM];
  2750.                 if pos('int', options) <> 0 then
  2751.                     Measurements := Measurements + [IntDenM];
  2752.                 if pos('max', options) <> 0 then
  2753.                     Measurements := Measurements + [MinMaxM];
  2754.                 if pos('1', options) <> 0 then
  2755.                     Measurements := Measurements + [User1M];
  2756.                 if pos('2', options) <> 0 then
  2757.                     Measurements := Measurements + [User2M];
  2758.                 UpdateFitEllipse;
  2759.                 if Measurements <> SaveMeasurements then
  2760.                     UpdateList;
  2761.             end;
  2762.     end;
  2763.  
  2764.  
  2765.     procedure SetLabel;
  2766.         var
  2767.             SaveCommand: CommandType;
  2768.             str, SaveLabel: str255;
  2769.     begin
  2770.         SaveCommand := MacroCommand;
  2771.         GetArguments(str);
  2772.         case SaveCommand of
  2773.             SetMajorC:  begin
  2774.                     SaveLabel := MajorLabel;
  2775.                     MajorLabel := str;
  2776.                     Measurements := Measurements + [MajorAxisM];
  2777.                 end;
  2778.             SetMinorC:  begin
  2779.                     SaveLabel := MinorLabel;
  2780.                     MinorLabel := str;
  2781.                     Measurements := Measurements + [MinorAxisM];
  2782.                 end;
  2783.             SetUser1C:  begin
  2784.                     SaveLabel := User1Label;
  2785.                     User1Label := str;
  2786.                     Measurements := Measurements + [User1M];
  2787.                 end;
  2788.             SetUser2C:  begin
  2789.                     SaveLabel := User2Label;
  2790.                     User2Label := str;
  2791.                     Measurements := Measurements + [User2M];
  2792.                 end;
  2793.         end; {case}
  2794.         ShowValues;
  2795.         if str <> SaveLabel then
  2796.             UpdateList;
  2797.     end;
  2798.  
  2799.  
  2800.     procedure ExecuteCommand;
  2801.         var
  2802.             AutoSelectAll: boolean;
  2803.             t: FateTable;  {Needed for MakeSkeleton}
  2804.             str: str255;
  2805.             aok: boolean;
  2806.     begin
  2807.         if (Info = NoInfo) and not (MacroCommand in [StartC, ShowResultsC, GetPicSizeC, PutMsgC, ExitC, CaptureC, MoveToC, BeepC, MakeNewC, SetPaletteC, SetBackC, GetRoiC, OpenC, ImportC, SetImportC, SetMinMaxC, SetCustomC, nPicsC, WaitC, SetSizeC, AreaC, DensityC, StdC, XyC, ModeC, PerimeterC, MajorC, MinorC, AngleC, IntDensityC, TriggerC, AverageFramesC, SaveStateC, RestoreStateC, SetCounterC, MakeStackC, ShowMsgC]) then begin
  2808.                 MacroError('No image window active');
  2809.                 exit(ExecuteCommand);
  2810.             end;
  2811.         if DoOption then begin
  2812.                 OptionKeyWasDown := true;
  2813.                 DoOption := false;
  2814.             end;
  2815.         if OpPending then
  2816.             if not (MacroCommand in [CopyModeC, AndC, OrC, XorC, BlendC, ReplaceC, AddC, SubC, MulC, DivC, SetOptionC]) then
  2817.                 KillRoi; {Terminate any pending paste operation.}
  2818.         MacroOpPending := false;
  2819.         case MacroCommand of
  2820.             RotateRC, RotateLC: 
  2821.                 DoRotate(MacroCommand);
  2822.             FlipVC: 
  2823.                 FlipOrRotate(FlipVertical);
  2824.             FlipHC: 
  2825.                 FlipOrRotate(FlipHorizontal);
  2826.             CopyC:  begin
  2827.                     FindWhatToCopy;
  2828.                     if WhatToCopy = NothingToCopy then
  2829.                         MacroError('Copy failed')
  2830.                     else
  2831.                         DoCopy;
  2832.                 end;
  2833.             SelectC:  begin
  2834.                     StopDigitizing;
  2835.                     SelectAll(true);
  2836.                 end;
  2837.             PasteC: 
  2838.                 DoPaste;
  2839.             ClearC, FillC, InvertC, FrameC: 
  2840.                 with info^ do begin
  2841.                         AutoSelectAll := not RoiShowing;
  2842.                         if AutoSelectAll then
  2843.                             SelectAll(true);
  2844.                         case MacroCommand of
  2845.                             ClearC: 
  2846.                                 DoOperation(EraseOp);
  2847.                             FillC: 
  2848.                                 DoOperation(PaintOp);
  2849.                             InvertC: 
  2850.                                 DoOperation(InvertOp);
  2851.                             FrameC: 
  2852.                                 DoOperation(FrameOp);
  2853.                         end;
  2854.                         UpdateScreen(RoiRect);
  2855.                         if AutoSelectAll then
  2856.                             KillRoi
  2857.                         else
  2858.                             MacroOpPending := true;
  2859.                     end;
  2860.             KillC: 
  2861.                 KillRoi;
  2862.             RestoreC: 
  2863.                 if NoInfo^.RoiType <> NoRoi then
  2864.                     RestoreRoi;
  2865.             AnalyzeC: 
  2866.                 AnalyzeParticles;
  2867.             ConvolveC: 
  2868.                 DoConvolve;
  2869.             NextC: 
  2870.                 GetNextWindow;
  2871.             MarkC: 
  2872.                 MarkSelection(mCount);
  2873.             MeasureC: 
  2874.                 Measure;
  2875.             MakeBinC: 
  2876.                 MakeBinary;
  2877.             DitherC: 
  2878.                 Filter(Dither, 0, t);
  2879.             SmoothC: 
  2880.                 if OptionKeyWasDown then
  2881.                     Filter(UnweightedAvg, 0, t)
  2882.                 else
  2883.                     Filter(WeightedAvg, 0, t);
  2884.             SharpenC: 
  2885.                 Filter(fsharpen, 0, t);
  2886.             ShadowC: 
  2887.                 Filter(fshadow, 0, t);
  2888.             TraceC: 
  2889.                 Filter(EdgeDetect, 0, t);
  2890.             ReduceC: 
  2891.                 Filter(ReduceNoise, 0, t);
  2892.             RedirectC: 
  2893.                 RedirectSampling := GetBooleanArg;
  2894.             ThresholdC: 
  2895.                 SetThreshold;
  2896.             ResetgmC: 
  2897.                 ResetGrayMap;
  2898.             WaitC: 
  2899.                 DoWait;
  2900.             ResetmC: 
  2901.                 ResetCounter;
  2902.             SetSliceC: 
  2903.                 SetDensitySlice;
  2904.             UndoC: 
  2905.                 DoUndo;
  2906.             SetForeC, SetBackC: 
  2907.                 SetColor;
  2908.             HistoC:  begin
  2909.                     DoHistogram;
  2910.                     DrawHistogram;
  2911.                 end;
  2912.             EnhanceC: 
  2913.                 EnhanceContrast;
  2914.             EqualizeC: 
  2915.                 EqualizeHistogram;
  2916.             ErodeC: 
  2917.                 DoErosion;
  2918.             DilateC: 
  2919.                 DoDilation;
  2920.             OutlineC: 
  2921.                 filter(OutlineFilter, 0, t);
  2922.             ThinC: 
  2923.                 MakeSkeleton;
  2924.             AddConstC, MulConstC: 
  2925.                 DoConstantArithmetic;
  2926.             RevertC: 
  2927.                 DoRevert;
  2928.             BeepC: 
  2929.                 Beep;
  2930.             NopC: 
  2931.                 ;
  2932.             MakeC, MakeOvalC: 
  2933.                 MakeRoi;
  2934.             MoveC: 
  2935.                 MoveRoi;
  2936.             InsetC: 
  2937.                 InsetRoi;
  2938.             MoveToC: 
  2939.                 DoMoveTo;
  2940.             DrawTextC, WriteC, WritelnC, ShowMsgC: 
  2941.                 OutputText;
  2942.             SetFontC: 
  2943.                 SetFont;
  2944.             SetFontSizeC: 
  2945.                 SetFontSize;
  2946.             SetTextC: 
  2947.                 SetText;
  2948.             DrawNumC: 
  2949.                 DrawNumber;
  2950.             ExitC: 
  2951.                 token := DoneT;
  2952.             GetPicSizeC: 
  2953.                 GetPicSize;
  2954.             PutMsgC: 
  2955.                 DoPutMessage;
  2956.             GetRoiC: 
  2957.                 GetRoi;
  2958.             MakeNewC: 
  2959.                 DoMakeNewWindow;
  2960.             DrawScaleC: 
  2961.                 if info^.RoiShowing then begin
  2962.                         DrawScale;
  2963.                         UpdatePicWindow
  2964.                     end
  2965.                 else
  2966.                     MacroError('No Selection');
  2967.             SetPaletteC: 
  2968.                 DoSetPalette;
  2969.             OpenC, ImportC: 
  2970.                 DoOpenImage;
  2971.             SetImportC: 
  2972.                 SetImportAttributes;
  2973.             SetMinMaxC: 
  2974.                 SetImportMinMax;
  2975.             SetCustomC: 
  2976.                 SetCustomImport;
  2977.             SelectPicC, ChoosePicC: 
  2978.                 SelectPic;
  2979.             SetPicNameC: 
  2980.                 SetPicName;
  2981.             ApplyLutC: 
  2982.                 ApplyLookupTable;
  2983.             SetSizeC: 
  2984.                 SetNewSize;
  2985.             SaveC:  begin
  2986.                     StopDigitizing;
  2987.                     with info^ do
  2988.                         if (PictureType = TiffFile) or (PictureType = PictFile) then
  2989.                             SaveFile
  2990.                         else
  2991.                             DoSaveAs;
  2992.                 end;
  2993.             SaveAllC: 
  2994.                 SaveAll;
  2995.             SaveAsC: 
  2996.                 DoSaveAs;
  2997.             CopyResultsC: 
  2998.                 DoCopyResults;
  2999.             CloseC, DisposeC: 
  3000.                 ClosePicWindow;
  3001.             DisposeAllC: 
  3002.                 DisposeAll;
  3003.             DupC: 
  3004.                 DoDuplicate;
  3005.             GetInfoC: 
  3006.                 GetInfo;
  3007.             PrintC: 
  3008.                 DoPrint;
  3009.             LineToC: 
  3010.                 DoLineTo;
  3011.             GetLineC: 
  3012.                 DoGetLine;
  3013.             ShowPasteC: 
  3014.                 if PasteControl = nil then
  3015.                     ShowPasteControl
  3016.                 else
  3017.                     BringToFront(PasteControl);
  3018.             ChannelC: 
  3019.                 SetChannel;
  3020.             ColumnC, PlotProfileC:  begin
  3021.                     PlotDensityProfile;
  3022.                     if PlotWindow <> nil then
  3023.                         UpdatePlotWindow;
  3024.                 end;
  3025.             ScaleC, ScaleSelectionC: 
  3026.                 DoScaleAndRotate;
  3027.             SetOptionC: 
  3028.                 DoOption := true;
  3029.             SetLabelsC: 
  3030.                 DrawPlotLabels := GetBooleanArg;
  3031.             SetPlotScaleC: 
  3032.                 SetPlotScale;
  3033.             SetDimC: 
  3034.                 SetPlotDimensions;
  3035.             GetResultsC: 
  3036.                 GetResults;
  3037.             CopyModeC, AndC, OrC, XorC, BlendC, ReplaceC, AddC, SubC, MulC, DivC: 
  3038.                 DoPasteOperation;
  3039.             ScaleMathC: 
  3040.                 ScaleArithmetic := GetBooleanArg;
  3041.             InvertYC: 
  3042.                 InvertYCoordinates := GetBooleanArg;
  3043.             SetWidthC: 
  3044.                 SetLineWidth;
  3045.             ShowResultsC:  begin
  3046.                     ShowResults;
  3047.                     UpdateList
  3048.                 end;
  3049.             StartC: 
  3050.                 StartDigitizing;
  3051.             StopC: 
  3052.                 StopDigitizing;
  3053.             CaptureC: 
  3054.                 CaptureOneFrame;
  3055.             GetRowC, PutRowC, GetColumnC, PutColumnC: 
  3056.                 GetOrPutLineOrColumn;
  3057.             PlotXYZC: 
  3058.                 PlotXYZ;
  3059.             IncludeC: 
  3060.                 IncludeHoles := GetBooleanArg;
  3061.             AutoC: 
  3062.                 WandAutoMeasure := GetBooleanArg;
  3063.             AreaC, DensityC, StdC, XyC, ModeC, PerimeterC, MajorC, MinorC, AngleC, IntDensityC, MinMaxC: 
  3064.                 SetMeasurements;
  3065.             LabelC: 
  3066.                 LabelParticles := GetBooleanArg;
  3067.             OutlineParticlesC: 
  3068.                 OutlineParticles := GetBooleanArg;
  3069.             IgnoreC: 
  3070.                 IgnoreParticlesTouchingEdge := GetBooleanArg;
  3071.             AdjustC: 
  3072.                 WandAdjustAreas := GetBooleanArg;
  3073.             SetParticleSizeC: 
  3074.                 SetParticleSize;
  3075.             SetPrecisionC: 
  3076.                 SetPrecision;
  3077.             PutPixelC: 
  3078.                 DoPutPixel;
  3079.             ScalingOptionsC: 
  3080.                 SetScaling;
  3081.             ExportC: 
  3082.                 DoExport;
  3083.             ChangeC: 
  3084.                 DoChangeValues;
  3085.             UpdateResultsC:  begin
  3086.                     ShowValues;
  3087.                     DeleteLines(mCount, mCount);
  3088.                     AppendResults;
  3089.                 end;
  3090.             TileC: 
  3091.                 TileWindows;
  3092.             SetMajorC, SetMinorC, SetUser1C, SetUser2C: 
  3093.                 SetLabel;
  3094.             GetMouseC: 
  3095.                 DoGetMouse;
  3096.             SelectSliceC, ChooseSliceC, AddSliceC, DeleteSliceC, ResliceC:  begin
  3097.                     if info^.StackInfo = nil then
  3098.                         MacroError('No stack');
  3099.                     if token <> DoneT then
  3100.                         case MacroCommand of
  3101.                             SelectSliceC, ChooseSliceC: 
  3102.                                 DoSelectSlice;
  3103.                             AddSliceC: 
  3104.                                 aok := AddSlice(true);
  3105.                             DeleteSliceC: 
  3106.                                 DeleteSlice;
  3107.                             ResliceC: 
  3108.                                 Reslice;
  3109.                         end;
  3110.                 end;
  3111.             MakeStackC: 
  3112.                 MakeNewStack;
  3113.             AverageFramesC: 
  3114.                 AverageFrames;
  3115.             TriggerC: 
  3116.                 WaitForTrigger;
  3117.             MakeLineC: 
  3118.                 MakeLineRoi;
  3119.             GetTimeC: 
  3120.                 DoGetTime;
  3121.             SetScaleC: 
  3122.                 DoSetScale;
  3123.             SaveStateC: 
  3124.                 SaveState;
  3125.             RestoreStateC: 
  3126.                 RestoreState;
  3127.             SetCounterC: 
  3128.                 SetCounter;
  3129.             UpdateLutC: 
  3130.                 LoadLUT(info^.ctable);
  3131.             SetCountC: 
  3132.                 SetErosionDilationCount;
  3133.             PropagateLutC: 
  3134.                 DoPropagate(1);
  3135.             PropagateSpatialC: 
  3136.                 DoPropagate(2);
  3137.             PropagateDensityC: 
  3138.                 DoPropagate(3);
  3139.             SetSpacingC: 
  3140.                 SetSliceSpacing;
  3141.             RequiresC: 
  3142.                 CheckVersion;
  3143.             SetOptionsC: 
  3144.                 SetOptions;
  3145.         end; {case}
  3146.         OptionKeyWasDown := false;
  3147.     end;
  3148.  
  3149.  
  3150.     procedure DoCompoundStatement;
  3151.     begin
  3152.         if token <> BeginT then
  3153.             MacroError('"begin" expected');
  3154.         GetToken;
  3155.         while (token <> endT) and (token <> DoneT) do begin
  3156.                 DoStatement;
  3157.                 GetToken;
  3158.                 if Token = SemiColon then
  3159.                     GetToken;
  3160.             end;
  3161.     end;
  3162.  
  3163.  
  3164.     procedure DoDeclarations;
  3165.     begin
  3166.         if token = SemiColon then
  3167.             GetToken;
  3168.         if token = VarT then begin
  3169.                 GetToken;
  3170.                 while ((token = UnknownIdentifier) or (token = Variable)) and (Token <> DoneT) do
  3171.                     DoDeclaration(false);
  3172.                 CheckForReservedWord;
  3173.             end;
  3174.     end;
  3175.  
  3176.  
  3177.     procedure SkipStatement (Statement: TokenType);
  3178.         var
  3179.             count: integer;
  3180.     begin
  3181.         GetToken;
  3182.         if token = beginT then begin
  3183.                 count := 1;
  3184.                 repeat
  3185.                     GetToken;
  3186.                     case token of
  3187.                         beginT: 
  3188.                             count := count + 1;
  3189.                         endT: 
  3190.                             count := count - 1;
  3191.                         DoneT:  begin
  3192.                                 MacroError('"end" expected');
  3193.                                 exit(SkipStatement);
  3194.                             end;
  3195.                         otherwise
  3196.                     end; {case}
  3197.                 until count = 0;
  3198.             end
  3199.         else begin
  3200.                 while (token <> SemiColon) and (token <> endT) and not ((Statement = IfT) and (token = ElseT)) do begin
  3201.                         GetToken;
  3202.                         if token = DoneT then begin
  3203.                                 MacroError('";"  or "end" expected');
  3204.                                 exit(SkipStatement);
  3205.                             end;
  3206.                     end; {while}
  3207.                 PutTokenBack;
  3208.             end;
  3209.     end;
  3210.  
  3211.  
  3212.     procedure DoFor;
  3213.         var
  3214.             SavePC, StackLoc: integer;
  3215.             StartValue, EndValue, i: LongInt;
  3216.     begin
  3217.         StackLoc := GetVar;
  3218.         GetToken;
  3219.         if token <> AssignOp then begin
  3220.                 MacroError('":=" expected');
  3221.                 exit(DoFor);
  3222.             end;
  3223.         StartValue := GetInteger;
  3224.         if token = DoneT then
  3225.             exit(DoFor);
  3226.         GetToken;
  3227.         if token <> ToT then begin
  3228.                 MacroError('"to" expected');
  3229.                 exit(DoFor);
  3230.             end;
  3231.         EndValue := GetInteger;
  3232.         if token = DoneT then
  3233.             exit(DoFor);
  3234.         GetToken;
  3235.         if token <> DoT then begin
  3236.                 MacroError(DoExpected);
  3237.                 exit(DoFor);
  3238.             end;
  3239.         SavePC := pc;
  3240.         if StartValue > EndValue then
  3241.             SkipStatement(ForT)
  3242.         else
  3243.             for i := StartValue to EndValue do
  3244.                 with MacrosP^ do begin
  3245.                         Stack[StackLoc].value := i;
  3246.                         pc := SavePC;
  3247.                         GetToken;
  3248.                         DoStatement;
  3249.                         if Token = DoneT then
  3250.                             leave;
  3251.                         if Digitizing then
  3252.                             DoCapture;
  3253.                     end;
  3254.     end;
  3255.  
  3256.  
  3257.     procedure DoAssignment;
  3258.         var
  3259.             SaveStackLoc: integer;
  3260.     begin
  3261.         SaveStackLoc := TokenStackLoc;
  3262.         GetToken;
  3263.         if token <> AssignOp then begin
  3264.                 MacroError('":=" expected');
  3265.                 exit(DoAssignment);
  3266.             end;
  3267.         MacrosP^.stack[SaveStackLoc].value := GetExpression;
  3268.     end;
  3269.  
  3270.  
  3271.     procedure DoIf;
  3272.         var
  3273.             isTrue: boolean;
  3274.     begin
  3275.         isTrue := GetBoolean;
  3276.         GetToken;
  3277.         if token <> ThenT then
  3278.             MacroError('"then" expected');
  3279.         if isTrue then begin
  3280.                 GetToken;
  3281.                 DoStatement
  3282.             end
  3283.         else
  3284.             SkipStatement(IfT);
  3285.         GetToken;
  3286.         if token = elseT then begin
  3287.                 if isTrue then
  3288.                     SkipStatement(NullT)
  3289.                 else begin
  3290.                         GetToken;
  3291.                         DoStatement;
  3292.                     end;
  3293.             end
  3294.         else
  3295.             PutTokenBack;
  3296.     end;
  3297.  
  3298.  
  3299.     procedure DoWhile;
  3300.         var
  3301.             isTrue: boolean;
  3302.             SavePC: integer;
  3303.     begin
  3304.         SavePC := pc;
  3305.         repeat
  3306.             pc := SavePC;
  3307.             isTrue := GetBoolean;
  3308.             GetToken;
  3309.             if token <> doT then
  3310.                 MacroError(DoExpected);
  3311.             if isTrue then begin
  3312.                     GetToken;
  3313.                     DoStatement
  3314.                 end
  3315.             else
  3316.                 SkipStatement(WhileT);
  3317.             if Digitizing then
  3318.                 DoCapture;
  3319.         until not isTrue or (Token = DoneT);
  3320.     end;
  3321.  
  3322.  
  3323.     procedure DoRepeat;
  3324.         var
  3325.             isTrue: boolean;
  3326.             SavePC: integer;
  3327.     begin
  3328.         SavePC := pc;
  3329.         isTrue := true;
  3330.         repeat
  3331.             pc := SavePC;
  3332.             GetToken;
  3333.             while (token <> untilT) and (token <> DoneT) do begin
  3334.                     DoStatement;
  3335.                     GetToken;
  3336.                     if Token = SemiColon then
  3337.                         GetToken;
  3338.                 end;
  3339.             if token <> untilT then
  3340.                 MacroError('"until" expected');
  3341.             isTrue := GetBoolean;
  3342.             if Digitizing then
  3343.                 DoCapture;
  3344.         until isTrue or (Token = DoneT);
  3345.     end;
  3346.  
  3347.  
  3348.     procedure PushArguments (var nArgs: integer);
  3349.         var
  3350.             arg: array[1..MaxArgs] of extended;
  3351.             i: integer;
  3352.             TempName: SymbolType;
  3353.     begin
  3354.         nArgs := 1;
  3355.         Arg[nArgs] := GetExpression;
  3356.         GetToken;
  3357.         while token = comma do begin
  3358.                 if nArgs < MaxArgs then
  3359.                     nArgs := nArgs + 1
  3360.                 else
  3361.                     MacroError('Too many arguments');
  3362.                 arg[nArgs] := GetExpression;
  3363.                 GetToken;
  3364.             end;
  3365.         if token <> RightParen then
  3366.             MacroError(RightParenExpected);
  3367.         for i := 1 to nArgs do begin
  3368.                 if TopOfStack < MaxStackSize then
  3369.                     TopOfStack := TopOfStack + 1
  3370.                 else
  3371.                     MacroError(StackOverflow);
  3372.                 with MacrosP^.stack[TopOfStack] do begin
  3373.                         vType := RealVar;
  3374.                         value := arg[i];
  3375.                     end;
  3376.             end;
  3377.     end;
  3378.  
  3379.  
  3380.     procedure DoProcedure;
  3381.         var
  3382.             SavePC, SavePCStart, SaveStackLoc, nArgs, i: integer;
  3383.             SaveProcName: SymbolType;
  3384.     begin
  3385.         SavePCStart := PCStart;
  3386.         PCStart := TokenLoc;
  3387.         SaveProcName := ProcName;
  3388.         ProcName := TokenSymbol;
  3389.         SaveStackLoc := TopOfStack;
  3390.         GetToken;
  3391.         if token = LeftParen then
  3392.             PushArguments(nArgs)
  3393.         else begin
  3394.                 nArgs := 0;
  3395.                 PutTokenBack;
  3396.             end;
  3397.         SavePC := pc;
  3398.         pc := pcStart;
  3399.         if nArgs > 0 then begin
  3400.                 GetLeftParen;
  3401.                 i := 0;
  3402.                 GetToken;
  3403.                 while token in [UnknownIdentifier, Variable, comma, colon, SemiColon, RealT, IntegerT, BooleanT] do begin
  3404.                         if (token = UnknownIdentifier) or (token = Variable) then begin
  3405.                                 if i < nArgs then
  3406.                                     i := i + 1
  3407.                                 else
  3408.                                     MacroError('Too many arguments');
  3409.                                 MacrosP^.stack[SaveStackLoc + i].symbol := TokenSymbol;
  3410.                             end;
  3411.                         GetToken;
  3412.                     end;
  3413.                 if Token = VarT then
  3414.                     MacroError('VAR parameters not supported');
  3415.                 if i < nArgs then
  3416.                     MacroError('Too few arguments');
  3417.                 if token <> RightParen then
  3418.                     MacroError(RightParenExpected);
  3419.             end;
  3420.         GetToken;
  3421.         if (token = LeftParen) and (nArgs = 0) then
  3422.             MacroError('Arguments not expected');
  3423.         DoDeclarations;
  3424.         DoCompoundStatement;
  3425.         pc := SavePC;
  3426.         TopOfStack := SaveStackLoc;
  3427.         pcStart := SavePCStart;
  3428.         ProcName := SaveProcName;
  3429.     end;
  3430.  
  3431.  
  3432.     procedure DoArrayAssignment;
  3433.         var
  3434.             SaveCommand: CommandType;
  3435.             index, LutValue, PixelValue: LongInt;
  3436.     begin
  3437.         SaveCommand := MacroCommand;
  3438.         GetToken;
  3439.         if token <> LeftBracket then
  3440.             MacroError('"[" expected');
  3441.         Index := GetInteger;
  3442.         GetToken;
  3443.         if token <> RightBracket then
  3444.             MacroError('"]" expected');
  3445.         GetToken;
  3446.         if token <> AssignOp then
  3447.             MacroError('":=" expected');
  3448.         if SaveCommand = BufferC then begin
  3449.                 CheckIndex(index, 0, MaxLine - 1);
  3450.                 PixelValue := GetInteger;
  3451.                 RangeCheck(PixelValue);
  3452.                 if token <> DoneT then
  3453.                     MacrosP^.aLine[index] := PixelValue;
  3454.                 exit(DoArrayAssignment);
  3455.             end;
  3456.         if SaveCommand in [RedLutC, BlueLutC, GreenLutC] then begin
  3457.                 CheckIndex(index, 0, 255);
  3458.                 LutValue := GetInteger;
  3459.                 RangeCheck(LutValue);
  3460.                 if token <> DoneT then
  3461.                     with info^.cTable[index].rgb do
  3462.                         case SaveCommand of
  3463.                             RedLutC: 
  3464.                                 red := bsl(LutValue, 8);
  3465.                             GreenLutC: 
  3466.                                 green := bsl(LutValue, 8);
  3467.                             BlueLutC: 
  3468.                                 blue := bsl(LutValue, 8);
  3469.                         end;
  3470.                 exit(DoArrayAssignment);
  3471.             end;
  3472.         CheckIndex(index, 1, MaxRegions);
  3473.         if token <> DoneT then
  3474.             case SaveCommand of
  3475.                 rAreaC: 
  3476.                     mArea^[Index] := GetInteger;
  3477.                 rMeanC: 
  3478.                     mean^[Index] := GetExpression;
  3479.                 rStdDevC: 
  3480.                     sd^[Index] := GetExpression;
  3481.                 rXC: 
  3482.                     xcenter^[Index] := GetExpression;
  3483.                 rYC: 
  3484.                     ycenter^[Index] := GetExpression;
  3485.                 rLengthC: 
  3486.                     plength^[Index] := GetExpression;
  3487.                 rMinC: 
  3488.                     mMin^[Index] := GetExpression;
  3489.                 rMaxC: 
  3490.                     mMax^[Index] := GetExpression;
  3491.                 rMajorC: 
  3492.                     MajorAxis^[Index] := GetExpression;
  3493.                 rMinorC: 
  3494.                     MinorAxis^[Index] := GetExpression;
  3495.                 rAngleC: 
  3496.                     orientation^[Index] := GetExpression;
  3497.                 rUser1C: 
  3498.                     User1^[Index] := GetExpression;
  3499.                 rUser2C: 
  3500.                     User2^[Index] := GetExpression;
  3501.                 otherwise
  3502.                     MacroError('Read-only array');
  3503.             end; {case}
  3504.     end;
  3505.  
  3506.  
  3507.     procedure DoStatement;
  3508.     begin
  3509.         case token of
  3510.             BeginT: 
  3511.                 DoCompoundStatement;
  3512.             CommandT: 
  3513.                 ExecuteCommand;
  3514.             ForT: 
  3515.                 DoFor;
  3516.             IfT: 
  3517.                 DoIf;
  3518.             WhileT: 
  3519.                 DoWhile;
  3520.             RepeatT: 
  3521.                 DoRepeat;
  3522.             UnknownIdentifier: 
  3523.                 MacroError('Undefined identifier');
  3524.             Variable: 
  3525.                 DoAssignment;
  3526.             ArrayT: 
  3527.                 DoArrayAssignment;
  3528.             ProcedureT: 
  3529.                 DoProcedure;
  3530.             ElseT: 
  3531.                 MacroError('Statement expected');
  3532.             otherwise
  3533.         end;
  3534.         if CommandPeriod or not macro then begin
  3535.                 Token := DoneT;
  3536.                 KillRoi;
  3537.                 if macro then
  3538.                     beep;
  3539.             end;
  3540.     end;
  3541.  
  3542.  
  3543.     procedure RunMacro (nMacro: integer);
  3544.         var
  3545.             count: integer;
  3546.             str: str255;
  3547.             SaveInfo: InfoPtr;
  3548.     begin
  3549.         if nPics > 0 then
  3550.             with info^ do {Activate image window so Copy won't fail.}
  3551.                 if FrontWindow <> wptr then
  3552.                     if wptr <> nil then
  3553.                         SelectWindow(wptr);
  3554.         DefaultFileName := '';
  3555.         str := '';
  3556.         nSaves := 0;
  3557.         DefaultRefNum := 0;
  3558.         count := 0;
  3559.         pcStart := MacroStart[nMacro];
  3560.         pc := pcStart;
  3561.         SavePC := pcStart;
  3562.         token := NullT;
  3563.         macro := true;
  3564.         if OpPending then begin
  3565.                 KillRoi;
  3566.                 RestoreRoi;
  3567.             end;
  3568.         MacroOpPending := false;
  3569.         DoOption := false;
  3570.         SaveInfo := info;
  3571.         TopOfStack := nGlobals;
  3572.         ProcName := BlankSymbol;
  3573.         GetToken;
  3574.         DoDeclarations;
  3575.         DoCompoundStatement;
  3576.         if (info <> SaveInfo) and (info <> NoInfo) then
  3577.             SelectWindow(info^.wptr);
  3578.         with info^, RoiRect do begin
  3579.                 if ((right - left) <= 0) or ((bottom - top) <= 0) then
  3580.                     KillRoi;
  3581.             end;
  3582.         if info^.RoiShowing then begin
  3583.                 if MacroOpPending then begin
  3584.                         KillRoi;
  3585.                         RestoreRoi;
  3586.                     end
  3587.                 else
  3588.                     UpdatePicWindow;
  3589.             end;
  3590.         macro := false;
  3591.     end;
  3592.  
  3593.  
  3594.     procedure RunKeyMacro (ch: char; KeyCode: integer);
  3595.         const
  3596.             FunctionKey = 16;
  3597.         var
  3598.             i: integer;
  3599.     begin
  3600.         if (ord(ch) = 0) then
  3601.             exit(RunKeyMacro);
  3602.         if (ch >= 'A') and (ch <= 'Z') then
  3603.             ch := chr(ord(ch) + 32); {Convert to lower case}
  3604.         if ord(ch) = FunctionKey then
  3605.             case KeyCode of
  3606.                 122: 
  3607.                     ch := 'A';
  3608.                 120: 
  3609.                     ch := 'B';
  3610.                 99: 
  3611.                     ch := 'C';
  3612.                 118: 
  3613.                     ch := 'D';
  3614.                 96: 
  3615.                     ch := 'E';
  3616.                 97: 
  3617.                     ch := 'F';
  3618.                 98: 
  3619.                     ch := 'G';
  3620.                 100: 
  3621.                     ch := 'H';
  3622.                 101: 
  3623.                     ch := 'I';
  3624.                 109: 
  3625.                     ch := 'J';
  3626.                 103: 
  3627.                     ch := 'K';
  3628.                 111: 
  3629.                     ch := 'L';
  3630.                 105: 
  3631.                     ch := 'M';
  3632.                 107: 
  3633.                     ch := 'N';
  3634.                 113: 
  3635.                     ch := 'O';
  3636.                 otherwise
  3637.             end;
  3638.         for i := 1 to nMacros do
  3639.             if ch = MacroKey[i] then begin
  3640.                     RunMacro(i);
  3641.                     leave;
  3642.                 end;
  3643.     end;
  3644.  
  3645.  
  3646. end.