Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!mailrus!iuvax!cica!ctrsol!lll-winken!ubvax!ardent!peck!rap From: rap@peck.ardent.com (Rob Peck) Newsgroups: comp.sys.amiga.tech Subject: Re: Solution for EXECUTE: No K Directive (long) Message-ID: <7686@ardent.UUCP> Date: 1 Aug 89 17:33:11 GMT References: <3020@blake.acs.washington.edu> <696@jc3b21.UUCP> Sender: news@ardent.UUCP Reply-To: rap@peck.ardent.com (Rob Peck) Organization: Ardent Computer Corp., Sunnyvale, CA Lines: 302 In article <696@jc3b21.UUCP> fgd3@jc3b21.UUCP (Fabbian G. Dufoe) writes: >From article <3020@blake.acs.washington.edu>, by dlarson@blake.acs.washington.edu (Dale Larson): >> importantly, why could I find no reference whatsoever to this error message >> in any description of EXECUTE or on any page listed under "error" in the >> index of any Amiga documentation? (Maybe I forgot to put on my glasses :-) It was suggested in an earlier answer that just using the .bra and .ket as the first two lines of your file would make the "No K directive" error go away. For some reason, this did not work for me, and I finally put a ".key dummy" as the very first line. This got rid of the error. AmigaDOS seemed to be telling me that if I was doing ANY variable substitution (in a test script, I was using the {$$} stuff, similar to that described below) but no OTHER variable substitution in a much smaller script, and I still got the error. The AmigaDOS manual says that if you want to do any variable substitution, that the first line of the script must start with a ".", so the use of .bra { and .ket } should have been enough. But it was not. I dont have the machine here, but I THINK this is all I was doing: .bra { .ket } echo "The CLI Process that is running me is: {$$}" and IT generated this error (NO K Directive), so I added .key dummy as the first line and it went away. Hmmm. Ah well, thats MY solution. If you want a tutorial approach writing of scripts that can be EXECUTEd, I put a whole chapter on that topic into the Amiga Companion, and even included an explanation of the startup-sequence, in English so to speak. Anyone who has tried to decipher the example for "EVAL" in the 1.3 enhancer docs will also appreciate the new explanation that is in the Second Edition of the Companion. I found that the example itself is very clever and contains a couple of useful tricks, but with no documentation to support it, it took a while to figure it out. For those who have not seen the Companion yet, here is what I tell folks about EVAL (starts on page 161 and runs to page 165 of the second edition) Note that this is the "UNEDITED" version of the material. It is as submitted to Amiga World as the "Please insert this material into the first edition of the Companion to create the second edition." So they may have trimmed a few words but told me that the concepts and examples have remained intact. ======================== Using EVAL To Aid Decision Making The EVAL command has been added to 1.3 to let you do simple arithmetic. EVAL is like IF, but where IF compares strings, EVAL compares strings-as-numbers. The command template for EVAL is: VALUE1/A,OP,VALUE2,TO,LFORMAT/K: which means that you MUST provide at least one parameter If no operation or other parameter is specified, the answer evaluates to that of the first parameter. 1> EVAL 695 695 1> EVAL works with integer values (whole numbers) only, and you can specify an operation to perform on two integer values. You specify the operation by using a particular symbol, as contained in the table below. Eval accepts the symbol either by its expected position (between the two values, as with normal arithmetic) or by the keyword method (common to most if not all AmigaDOS commands). 1> EVAL 4 * 6 24 1> EVAL VALUE1 4 VALUE2 6 OP * 24 1> Here are all of the available operations that EVAL can perform, along with the "operator" that EVAL recognizes for this operation: Operation Operator Result ========= ======== ========================= Addition + Value1 + Value2 Subtraction - Value1 - Value2 Multiplication * Value1 * Value2 Division / Value1 / Value2 Modulo mod Remainder after Value1/Value2 AND & Bits in both Value1 and Value2 OR | Bits in either Value1 or Value2 NOT ~ Zero bits become one bits and VV. Left Shift << Shift the Value1 bits left by Value2 bit positions Right Shift >> Shift the Value1 bits right by Value2 bit positions Negation - Placed before any value, that value is treated as negative (unary minus) Exclusive OR xor Exclusive-OR function Bitwise Equivalence eqv Equivalence function Many of these operations are performed by programmers. If you want more information about the operations other than the simple arithmetic, I'd suggest you look into a book on logic programming or programming in C. The TO keyword lets you redirect the output of the EVAL command to a file. This can be quite useful in command scripts because the contents of the file can be read later and used to make operating decisions. An example: 1> EVAL 12 mod 7 TO ENV:remainder 1> GETENV remainder 5 1> The other keyword, LFORMAT, lets you tell EVAL how to output its answer. You provide a format string, and EVAL will put the answer out using that format. For example the number can be formatted as decimal (specify %N somewhere in the output string), or in hexadecimal (specify %X), or in octal (specify %O). When using other than decimal, you can also tell EVAL how many digits to output by specifying the number of digits following the specification. For example, to use 8 hexadecimal digits, specify %X8. There is also a special character sequence that EVAL recognizes (*N) to place a newline into your output string: 1> EVAL 256 LFORMAT "256 decimal = %X8 hexadecimal*N" 256 decimal = 00000100 hexadecimal 1> Without the *N in there, it has the same effect as the NOLINE switch to the ECHO command. The next output simply appears on the same line, in the next available character position. The default input integer values are decimal, but if you tell EVAL that a number is hexadecimal (by prepending "0x" or "#x" to it), or octal (by prepending a leading zero or a #-sign to it), EVAL correctly interprets the value: 1> EVAL 127 + 1 128 1> EVAL 0x7F + 1 ;hexadecimal 128 1> EVAL 0177 + 1 ;octal 128 1> EVAL #x7f + 1 ;hex again 128 1> EVAL #177 + 1 ;octal 128 1> Now that you know what EVAL can do, lets look, line by line, at an example command script that was provided with the AmigaDOS 1.3 Enhancer kit. What you'll see here is a slight revision of the original script. The script file that uses EVAL to form a loop. I commented each line but you can leave out the comments if you try it. Remember that at least the .key statement and any other dot-statement should start in column 1: .key command/a,howmany/a ; Both parameters are needed .bra { .ket } ; Allow left/right arrows for redirection ; so give EXECUTE an alternate for enclosing ; its parameters (alternate BRA(c)KET(s)) ECHO >ENV:loop {howmany} ; Incoming loop value stored in environment ; variable so that we can read it later and ; test its value. ; LAB BEGIN ; ; The start of a loop ; Execute command NOW, assumes at least ONE pass. ; ECHO "This is loop number " NOLINE GETENV loop ; ; Now we are going to modify the loop value by using ; EVAL to do it. Get the value, change it (subtract ; one), then put it back and loop to BEGIN if the ; value still has not reached zero. ; EVAL NIL: TO T:junk{$$} VALUE2 1 OP - ? ; ; This one is just a little tough to explain, but ; here goes: ; ; 1. The specification "NIL:" is a command to redirect ; the output of the command to a file instead of ; to the screen. This prevents the command template ; from being printed to the screen. ; ; 4. The parameter spec "TO T:junk{$$}" says to take ; the real output (the answer) of EVAL, and put it ; into a file and that file should have a unique ; name. If running from CLI 1, then the file name ; will be T:junk1; if running from CLI 2, the file ; name will be T:junk2 and so on. ; ; 5. Finally positional parameters are used to tell ; EVAL what it is supposed to do. We establish ; VALUE2=1 and OP=-, in other words, whatever we ; read from ENV:loop will have 1 subtracted from ; it and the result goes into a uniquely named ; temporary file. ; ; This complicated method had to be used because ; EVAL does not know how to read environment ; variable values (IF knows how) directly, so we ; have to take advantage of the "?" capability to ; fool EVAL into reading the value from the file. ; TYPE >ENV:loop T:junk{$$} ; ; Why not say: ; COPY FROM T:junk{$$} TO ENV:loop ; ; Well, TYPE always puts a newline character as the ; final character output, but COPY copies only what ; is there. EVAL may or may not (depending on whether ; LFORMAT is used). So this is a just-in-case so ; that we can guarantee that there will be at least ; one newline in the file for EVAL to read on the ; next loop around. ; IF val $loop GT 0 ; ; Test the present value of loop counter, may exit. ; SKIP BEGIN BACK ; ; If the test is true, go back and restart script. ; ENDIF ; DELETE T:temp{$$} T:temp2{$$} T:doit{$$} ECHO "Done" Bug Alert (SKIP Command) --------- If one command script calls the EXECUTE function from within the script, the SKIP command, even though told to skip BACK, can no longer find the target label for the SKIP. (This deficiency is actually built into EXECUTE.) So if your command file needs to use the BACK option of switch, do not call EXECUTE from within the script. If you need to call EXECUTE, then follow the menu script example instead, and make the script call itself as it exits. ========================== I don't know who at CATS actually supplied the example for the use of EVAL in the 1.3 enhancer docs, but I really DO think it is clever and its one of those things that is a "forehead slapper" when you realize "hey, that's a real neat way to do it", specifically EVAL