home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / jsage / znode3 / tcj / tcj47.tzt / TCJ47.TXT
Encoding:
Text File  |  1993-06-07  |  31.1 KB  |  589 lines

  1.                                Z-System Corner
  2.                                  by Jay Sage
  3.                         The Computer Journal, Issue 47
  4.                           Reproduced with permission
  5.                            of author and publisher
  6.  
  7. Last time I presented an overview of the philosophy behind the design of the
  8. ZMATE macro text editor and wordprocessor. In particular, I described the
  9. approach that allows the user of the program to implement his/her own text
  10. processing functions and to bind them to arbitrary sequences of keystrokes. In
  11. other words, you can design your own wordprocessor!
  12.  
  13. This time I am going to begin a description of the macro command language that
  14. ZMATE uses. For this column we will start with relatively simple macros; in
  15. future columns we'll begin to display some of the fancy things that ZMATE can
  16. do. Even if you don't own or use ZMATE (yet), I hope you will find it
  17. interesting to learn about this approach to the implementation of a text
  18. editor.
  19.  
  20. For those of you who remember my promises from two issues back, I'm afraid
  21. that my computer has still not been restored to full operation since the hard
  22. disk drive gave me problems. I sent the drive out to be repaired, and the
  23. technicians could not find anything wrong with it. Since I did not want any
  24. data to be destroyed, they did not try reformatting it, but they told me that
  25. they had no trouble reading data from the tracks.
  26.  
  27. I just have not had the time to reinstall that drive. For the moment I am
  28. still running on a replacement drive with only the most basic software (and I
  29. mean basic -- I don't even have BGii on it yet!). It may be that my house has
  30. been afflicted by malicious gremlins. My modem failed at about the same time
  31. as the hard disk. I finally negotiated with the manufacturer the terms under
  32. which I could return it for repair. Before doing so, however, I decided to
  33. give it one more try. It worked perfectly! Are there problems that go away
  34. when an instrument is powered down for a week or two that would not go away in
  35. one day?!
  36.  
  37. During the time of these troubles, Murphy really had the upper hand. Although
  38. there were some files on the hard disk that I should have backed up but did
  39. not, there were some very important files related to these TCJ columns that I
  40. had backed up to a floppy. However, when the hard disk failed, the backup
  41. floppy vanished. Now, even after a month, it has still not turned up. If I'm
  42. lucky, the hard disk will work when I reinstall it, and the floppy will then
  43. reappear, in plain sight on my desk where I know I kept it. If all that
  44. happens in the next two months, I hope to have a further installment on my
  45. efforts to patch up MEX-Plus to add some new features and correct some bugs.
  46. Cross your fingers for me!
  47.  
  48. Recapitulation
  49.  
  50. I'd like to start the ZMATE discussion by reminding you of the four ways in
  51. which macro commands can be used, as described in my previous column.
  52.  
  53. The most common way to execute a macro is by pressing one of the so-called
  54. instant-command editing keys, such as the keys that move the cursor left,
  55. right, up, and down by various amounts. These keys are bound to a set of ZMATE
  56. internal functions, most of which are implemented in the macro language. In
  57. the original PMATE editor, from which ZMATE was derived, these functions could
  58. not be changed; in ZMATE the user can patch in new macro functions for the
  59. internal commands. Source code is provided in the file INTMACRO.Z80, and it is
  60. a relatively simple procedure to edit it and patch it into the distribution
  61. version of ZMATE.COM.
  62.  
  63. An additional set of macro functions can be defined in the "permanent macro
  64. area" or PMA. There, macro strings are associated with single-character names.
  65. These macros can be invoked by name using other commands in the macro
  66. language, and those with a specific range of names can be bound to keystroke
  67. sequences.
  68.  
  69. Third, when the editor is in command mode, the user can enter a temporary
  70. macro sequence directly on the command line at the top of the screen. The
  71. user's command line is stored in a special text buffer called the command
  72. buffer.
  73.  
  74. Finally, the contents of any of the ten numbered editing buffers can be
  75. interpreted as a macro sequence and executed. In other words, any of the
  76. auxiliary editing buffers can function like the command buffer.
  77.  
  78. ZMATE Macro Commands
  79.  
  80. Now let's look at some of the macro commands that ZMATE recognizes. We can't
  81. cover all of them this time. We will start with some of the simpler ones and
  82. then will cover a few of the more sophisticated ones. We will then look at
  83. some of ZMATE's built-in functions so you can see how macros are used to
  84. implement them.
  85.  
  86. The ZMATE language is very compact to save space, typing, and time. Most of
  87. the commands use only a single letter; some are two characters; a few are
  88. three-characters long. To the extent possible, the letters for the commands
  89. are chosen to be mnemonic in some way. There is a bit of a learning curve, but
  90. it does not take too long to get the hang of them. I made a two-page crib
  91. sheet that I occasionally consult to remind myself of some of the more obscure
  92. ones.
  93.  
  94. Cursor Motion
  95.  
  96. The most basic commands are those that move the cursor around within the text
  97. in an editing buffer.
  98.  
  99. There are four macros that move the cursor in units: 'M' moves by characters;
  100. 'W', by words; 'P', by paragraphs; and 'L', by lines. It is pretty clear what
  101. a character is. The one thing that might not be obvious is that hard carriage
  102. returns are treated as a character in the text. The cursor can be positioned
  103. on one, and it can be deleted to close up two lines. ZMATE does not generally
  104. use linefeeds. Carriage returns in the editing buffer are converted to
  105. carriage-return/linefeed pairs when the file is written out to disk or
  106. printed.
  107.  
  108. Words are contiguous groups of letters and numbers. Special characters -- such
  109. as periods, quotes, asterisks, dollar signs, etc. -- and control characters --
  110. including spaces, tabs, and carriage returns -- separate words. Paragraphs are
  111. terminated by hard carriage returns. ZMATE supports a mode, called "format
  112. mode," in which lines wrap automatically at the right margin as with
  113. wordprocessors. The apparent carriage returns at the ends of the wrapped lines
  114. are called soft carriage returns. The "P" macro ignores those carriage
  115. returns. When ZMATE is in format mode, the hard returns are visible as '<'
  116. characters in highlighted video.
  117.  
  118. Each of these move-by-unit macros can take a signed numerical prefix. Such a
  119. prefix is one of the two ways arguments are passed to ZMATE commands. For the
  120. cursor-motion commands, if there is no prefix, "1" is assumed; if the prefix
  121. is simply "-", then "-1" is assumed.
  122.  
  123. Positive prefixes move the cursor forward (to the right and down) in the text;
  124. negative prefixes move it back (left and up). For example, "3W" moves the
  125. cursor to the beginning of the third word after the one where the cursor is
  126. now, while "-2W" moves the cursor to the beginning of the second word before
  127. the one in which the cursor is presently located.
  128.  
  129. A '0' prefix moves to the beginning of the current unit. For this purpose,
  130. word separator characters are considered to be a part of the word they follow.
  131. Suppose we have the text
  132.  
  133.     ONE...TWO:;THREE
  134.  
  135. with the cursor sitting on the 'W' in 'TWO'. "-W" will put the cursor on the
  136. 'O' in 'ONE'; "0W" will put it on the 'T' in 'TWO'; and "W" will put it on the
  137. 'T' in 'THREE'. Where would the cursor have ended up if it had started on
  138. either the colon or semicolon between 'TWO' and 'THREE'? Answer: in the same
  139. places. Those word-separator characters after 'TWO' are treated as if they
  140. were a part of the word they follow.
  141.  
  142. What do you think "0M" does? Well, it does nothing to the cursor.
  143. Nevertheless, it is not at all a useless command. You see, the numerical
  144. prefix is not always given as a literal number. Sometimes it is a calculated
  145. quantity, as we will see later. If we compute how far we should move, and the
  146. answer is zero, the macro should work.
  147.  
  148. There are a few absolute (unit-less) cursor motion macro commands. The command
  149. "A" moves the cursor to the first character in the edit buffer, while "Z"
  150. moves it just past the last character, namely to the place where the next
  151. character would be inserted. ZMATE supports virtual memory in its main editing
  152. buffer, called the 'T' or text buffer. Files that are too big to fit in memory
  153. are paged in and out, either manually or automatically, as desired. The macros
  154. "UA" and "UZ" go to the beginning and end of the entire file (think of 'U' as
  155. 'UNLIMITED'). If required, the file will be paged from disk.
  156.  
  157. The "QX" command is one of a whole family of "Q" commands, a couple of which
  158. we will see this time. It takes a numerical prefix and moves the cursor to
  159. that column in the current line. The columns are numbered beginning with '0'.
  160. As is frequently the case, an absent prefix is taken as "1". Not surprisingly,
  161. the prefix must be non-negative. What happens if you violate this restriction?
  162. Does your file get trashed and your whole disk wiped out? No, ZMATE tries to
  163. interpret the number as a positive number, which, of course, is larger than
  164. the maximum column allowed (typically 250). The result is a beep from the
  165. terminal and a strange positioning of the cursor.
  166.  
  167. Perhaps this is a good time for a general comment about numbers in ZMATE.
  168. Numbers are stored as words (two bytes, or 16 bits). Such numbers can be
  169. interpreted either as positive numbers ranging from 0 to 65535 or as signed
  170. numbers with a positive range 0 to 32767 (7FFF hex) and a negative range from
  171. -1 (FFFF hex) to -32768 (8000 hex). Numbers are also used to represent Boolean
  172. logical values. False is represented by '0'; true, by '-1'. When a function
  173. only accepts Boolean values, then any number other than '0' is taken as true.
  174.  
  175. The "Q-" macro determines whether ZMATE will display numbers as signed or
  176. unsigned. Following the Boolean convention, "0Q-" turns off the display of
  177. negative numbers, while "-1Q-" or just "Q-" turns them on. If you enter a
  178. number all by itself as an interactive command line macro, its value in the
  179. current display mode will be shown after the "arg=" status message on the top
  180. line of ZMATE's screen. If you enter
  181.  
  182.         0Q- -1$$
  183.  
  184. you will see "arg=65535" on the status line. If you enter
  185.  
  186.         Q- -1$$
  187.  
  188. you will see "arg=-1".
  189.  
  190. Now lets see how some of ZMATE's built-in functions are defined. Look at Table
  191. 1. Functions 3 and 6 are especially interesting. Macro commands can be
  192. combined by writing them in sequence with or without spaces or tabs between
  193. the individual commands. The spaces in the two examples above were put there
  194. only to make the commands easier for you to read; ZMATE can read them just as
  195. well without any spaces.
  196.  
  197. Function 3 implements what an ordinary person would think of as "move back one
  198. word." If the cursor is currently somewhere other than the beginning of a
  199. word, then the cursor is supposed to move back to the beginning of the current
  200. word. If it is already at the beginning, then it should move back to the
  201. beginning of the previous word. As we noted earlier, "-W" would move back too
  202. far in the former case. Moving back one character and then to the beginning of
  203. the current word does the trick. See if you can figure out why -- and also why
  204. function 6 is implemented as it is.
  205.  
  206. Text Deletion and Insertion
  207.  
  208. There are only two deletion commands: "D" deletes characters; "K" deletes
  209. (kills) lines. They take a numerical prefix with the usual default values.
  210. Deletions to the right -- positive prefixes -- start with the character under
  211. the cursor. Deletions to the left --negative prefixes -- start with the
  212. character to the left of the one under the cursor. Thus, the command "K"
  213. deletes all characters on a line to the right of and including the cursor,
  214. while "0K" deletes all characters on a line to the left of the cursor. "0LK"
  215. deletes the entire current line. Line deletions to the right, by the way,
  216. include the carriage return at the end of the line.
  217.  
  218. The basic insertion command is "I". It can be used in two forms. If it has a
  219. numerical prefix, then the character with that ASCII value is inserted before
  220. the character under the cursor, and the cursor remains on the character it was
  221. on before (i.e., after the new character).
  222.  
  223. The prefix value is interpreted as a positive number modulo 256. This form of
  224. the insert command can be used to insert some characters that cannot be
  225. inserted by typing (e.g., characters with their high bit set) and some that
  226. cannot be inserted using the second form of the insert command that we will
  227. look at shortly (e.g., the escape character).
  228.  
  229. Some character values (e.g., 0 and some special values that ZMATE uses for
  230. specially formatted text) cannot be used. Characters with the high bit set can
  231. be put into a file and can be written out to disk, but when such a file is
  232. read back in, the high bits will be filtered out.
  233.  
  234. The second form of the "I" command illustrates the general syntax for string
  235. arguments in the macro language. These come after the macro command and are
  236. terminated or delimited by escape characters. The command
  237.  
  238.        Istring of text$
  239.  
  240. will insert the string of characters following the 'I' and up to the escape
  241. character, which is indicated here by the dollar sign. Some commands, as we
  242. will see shortly, take more than one string argument.
  243.  
  244. Another type of insertion is replacement, which uses the "R" command. It is
  245. much like the "I" command except that the new characters replace those under
  246. the cursor and to the right. For example, "65R" changes the character under
  247. the cursor to an 'A' (ASCII value 65), and the command "Rtest$" replaces the
  248. character under the cursor with a 't', the next character with an 'e', and so
  249. on. The cursor ends up on the character after the last one replaced.
  250.  
  251. The "\" command converts its numerical prefix into the text representation for
  252. the number and inserts it into the text before the cursor. Leading zeros are
  253. not included.
  254.  
  255. It might be appropriate to mention at this point that ZMATE in not limited to
  256. working in decimal radix. There are macro commands to set a radix to values
  257. between 2 and 16. Decimal is standard and will be assumed in all our examples.
  258. However, the radix in which input numbers, such as command prefixes, are
  259. interpreted and the radix in which output numbers are displayed can be changed
  260. independently.
  261.  
  262. For example, "8QI" sets the input radix to octal. "QI" (no prefix) will always
  263. set the radix back to decimal. This is awfully handy when you don't know what
  264. the current input radix is. After all, "10QI" leaves the radix unchanged. Do
  265. you understand why? "16QO" will set the output radix to hexadecimal, provided
  266. the input radix was decimal when this command was processed. If it was octal,
  267. the output radix would become 14, the octal value of '16'.
  268.  
  269. I recommend a trick for entering constants so that expressions will not be
  270. misinterpreted if the radix is changed. We have been careful to implement all
  271. built-in functions using radix-invariant expressions. The special ZMATE
  272. operator double-quote converts the character following it to its ASCII
  273. numerical value. To set the output radix to hexadecimal, for example, we could
  274. use the command
  275.  
  276.         "^PQO
  277.  
  278. Here we use '^P' to represent control-P. ZMATE allows control characters to be
  279. entered by typing a caret followed by the letter. The older PMATE editor also
  280. displayed control characters this way, but ZMATE shows just the character in
  281. highlighted video. The value of control-P is always 16, no matter what the
  282. input radix is. If you cannot enter a single character with the desired value,
  283. you can use arithmetic to get the value. We could have written the above
  284. command as
  285.  
  286.        ("Q-"A)QO
  287.  
  288. or simply
  289.  
  290.        "Q-"AQO
  291.  
  292. since 'Q' is 16 characters higher than 'A'.
  293.  
  294. Now back to insertion macros. There is one more. "QH" inserts a block of blank
  295. spaces (perhaps the 'H' stands for 'hole') in the text before the cursor. As
  296. usual, it takes a numeric prefix. The three commands below are all equivalent.
  297.  
  298.        10QH
  299.        I          $
  300.        " I" I" I" I" I" I" I" I" I" I
  301.  
  302. Besides being more compact, the "10QH" form will generally be faster. It tells
  303. ZMATE in advance how much space to open up, and the entire insertion, which
  304. may involve moving the text after the cursor, can be done in a single
  305. operation.
  306.  
  307. Search and Search-and-Replace Macros
  308.  
  309. ZMATE's string searching command illustrates a syntax in which a command takes
  310. both a numerical prefix argument and a string argument. The general form of
  311. the search command is "nSstring$". The numerical prefix can be positive or
  312. negative. With a positive value, the search is performed in the forward
  313. direction; with a negative value, the search moves back toward the beginning
  314. of the buffer.
  315.  
  316. The number tells ZMATE the maximum number of lines to search through. The
  317. current line to the left of the cursor is line 0. The current line to the
  318. right of the cursor is line 1. Thus "0Stest$" will search for 'test' in the
  319. part of the current line to the left of the cursor. "-4Stest$" will search in
  320. the current line to the left of the cursor plus the four lines before that.
  321. "1Stest$" will search the remainder of the current line beginning at the
  322. cursor and working to the right.
  323.  
  324. The default prefix values are different with the "S" command from what we have
  325. seen before. If just a sign is given without a number, then the entire
  326. remainder of the text buffer in the given direction will be searched. Thus a
  327. plus sign -- or no prefix at all -- defaults to the largest positive number
  328. (32767); a minus sign alone defaults to the largest negative number (-32768).
  329.  
  330. A variant of the "S" command is "US" (unlimited search). Like the commands
  331. "UA" and "UZ", it will perform scrolling of a file to and from disk in order
  332. to search the entire file. The "US" command does not accept a numerical
  333. prefix; it would not make sense, since it searches the entire file. It does
  334. accept a sign to indicate the direction of the search.
  335.  
  336. The search-and-replace, or change, commands "C" and "UC" are quite similar
  337. except that they take two string arguments. The first is the search target;
  338. the second is the text to replace the search target with. If I executed the
  339. command
  340.  
  341.        -Ctest$examination$
  342.  
  343. at this point in the text, the instance of 'test' three paragraphs back would
  344. be removed and replaced by 'examination'.
  345.  
  346. Some special characters can be used in the search string in the "S" and "C"
  347. commands. A control-E represents any character ('E' as in 'EVERY'). Thus
  348. "Ste^Et$" would find either 'test' or 'text' (or lots of other things). A
  349. control-S ('S' as in 'SPACE') represents any white-space character, namely
  350. space and tab. Control-W represents any word-separation character, so that
  351. "Sa^Wb$" would find 'a-b' or 'a b' or 'a/b' (but not 'axb' or 'a//b', which
  352. has two word-spacing characters between the 'a' and the 'b').
  353.  
  354. A control-N matches any character except the one that follows it ('N' as in
  355. 'NOT'). "Ste^Nst$" will stop on 'text' and 'tent' but not on 'test'. Just in
  356. case you need to search for one of these special characters, control-L ('L' as
  357. in 'LITERAL') causes the character following it to be treated literally. Thus
  358. "S^L^N$" will search for a control-N, and "S^L$$" will search for an escape
  359. character.
  360.  
  361. These special characters do not implement string searching as powerful as that
  362. in Unix GREP or in Bridger Mitchell's Jetfind, but they cover the most common
  363. situations. Other macro capabilities in ZMATE would make it possible to
  364. implement full GREP search rules, but such a macro would not be very fast.
  365.  
  366. Variables
  367.  
  368. A little earlier we alluded to the fact that ZMATE has numerical variables. It
  369. can perform arithmetic operations, bitwise Boolean operations, and logical
  370. comparisons with literal numbers and values of variables.
  371.  
  372. Listing all the variables would take up too much room here, so I will describe
  373. just a few of them to give you some idea of the kind of information available
  374. to a ZMATE macro.
  375.  
  376. Almost all ZMATE variables are represented by an '@' sign followed by a
  377. character that designates the variable name. None of them take any arguments,
  378. except for two that take a string argument.
  379.  
  380. Some variables tell where the cursor is located. "@C" returns the number of
  381. the character (its position in the text) counting from the first character in
  382. the buffer. "@L" gives the absolute line number (i.e., counting from the
  383. beginning of the file, even if some of it has been scrolled out to disk) of
  384. the line containing the cursor. "@X" reports the column number.
  385.  
  386. Some variables give information about the way the page is set up. "@Y" and
  387. "@W" give the left and right margins, respectively. "@Z" gives the column
  388. number of the next tab stop.
  389.  
  390. One of the most important variable commands, if not the most important, is
  391. "@T". It returns the ASCII value of the character under the cursor.  This
  392. information is critical to intelligent text processing.
  393.  
  394. There are also ten user variables numbered from 0 to 9. The "V" macro is used
  395. to set values into them, and the values can be retrieved by '@' followed by
  396. the variable name. Full memory access is provided by the variable "@@", which
  397. returns the contents of memory at the address stored in user variable 9. The
  398. macro "Q!" stores the value passed as a prefix into that address. Thus "@@" is
  399. the PEEK function and "Q!" is the POKE function. "@P" returns the absolute
  400. address where the character under the cursor is presently stored in memory.
  401.  
  402. The macro command "Gprompt$" displays the prompt string on the command line
  403. and waits for the user to enter a keystroke. The macro "@K" ('K' as in
  404. 'KEYSTROKE') then returns the ASCII value of the user's response. This
  405. provides the hook for interactive operation.
  406.  
  407. As you can see, ZMATE gives you the basic tools for doing just about anything.
  408. It may take some effort, but there isn't much that is impossible. There are a
  409. few variables I can think of that are missing. For example, ZMATE can get a
  410. disk directory or ask if a file exists, but it cannot find out how much space
  411. is left on a disk (though it can find out how much memory is free). It also
  412. cannot determine the drive or user number it is logged into or that is
  413. associated with a file it is editing.
  414.  
  415. Flow Control
  416.  
  417. A programming language is pretty much useless if it has no way of making
  418. decisions. That's why the flow control package (FCP) is so important in the Z-
  419. System. We have already shown you the kind of information that is at ZMATE's
  420. disposal. Now we will show you how that information is used to make decisions.
  421.  
  422. In one way or another ZMATE implements all the major flow control forms:
  423. repetition, if-then-else, do-until, and goto. Blocks of macro code are formed
  424. by enclosing them in matching pairs of either square or curly brackets. For
  425. most purposes, the two forms of bracket are equivalent.
  426.  
  427. For the flow control formats, we will use 'n' and 'm' to represent macro
  428. expressions that return numerical values. A numerical value of '0' has a
  429. Boolean value of 'false', while a numerical value of '-1' has a Boolean value
  430. of 'true'. Three dots are used to indicate an arbitrary sequence of macro
  431. commands, which may, themselves, include flow-control constructs (nesting of
  432. flow control is allowed to 15 levels).
  433.  
  434. The general form of the repetition macro is
  435.  
  436.        n[...m]
  437.  
  438. The value 'n' is the repeat count. In general, the macro commands inside the
  439. brackets will be repeated 'n' times. If 'n' is '0' or 'false', they will be
  440. skipped. If 'n' has the special value '-1', it will be interpreted as a
  441. Boolean, and the block will be executed only once. Other negative values will
  442. be interpreted as their corresponding positive values. If the prefix 'n' is
  443. omitted, the block will be repeated indefinitely (well, actually some 65534
  444. times, but who's counting).
  445.  
  446. After each iteration of the block of macro commands and before going back to
  447. the beginning, the value of 'm' is checked. If its Boolean value is 0 (false),
  448. iteration continues; if it is nonzero (true), control passes over the ending
  449. bracket and continues with any following commands. Thus 'm' constitutes the
  450. 'until' test for the DO-UNTIL construct.
  451.  
  452. If the numerical/Boolean expression 'm' is omitted, then the value of the
  453. special ZMATE error flag is used. This flag can also be evaluated explicitly
  454. as "@E". Certain commands set and clear this flag. For example, a search
  455. command ("S") will set the error flag if it could not find the designated
  456. search string. A cursor motion command that tries to take the cursor beyond
  457. the bounds of the text will also set the flag.
  458.  
  459. There are cases where iteration loops seem to terminate prematurely. This is
  460. usually because of the default use of the error flag as the 'until' test. One
  461. way to get around the problem is to end the block with the form '0]'. This
  462. ensures a false 'until' test and continued iteration.
  463.  
  464. The general form above includes basic condition processing. Full if-then-else
  465. processing is implemented by the form
  466.  
  467.        n[...][...]
  468.  
  469. If 'n' is 'false' (i.e., has a value of zero), then the first block will be
  470. skipped and the second block executed. If 'n' is 'true' (in this context,
  471. nonzero), then the first block will be executed and the second block skipped.
  472.  
  473. This form is identified by the touching closing and opening brackets. If you
  474. have two repeat blocks in a row, use '] [' with a space instead of '][' to
  475. prevent ZMATE from interpreting the macro as an IF-THEN-ELSE test.
  476.  
  477. There are several special commands for terminating or moving around within an
  478. iteration block. The 'exit' macro "n_" will immediately exit the loop and
  479. continue after the next closing square bracket. The 'next' macro "n^" will
  480. immediately go back to the closest preceding opening square bracket and start
  481. a new iteration. This is the only case in which the kind of bracket makes a
  482. difference. Because of this difference, it is generally effective to use curly
  483. brackets for if-then-else tests and square brackets for iteration constructs.
  484.  
  485. One extra word of caution. ZMATE is not smart enough to distinguish brackets
  486. in a string expressions from those used in flow control constructs. Be very
  487. careful whenever you have string expressions containing square or curly
  488. brackets; they may confuse flow control macros.
  489.  
  490. ZMATE has a goto function. The syntax is "nJx", where 'x' is a single-
  491. character label (any character can be used). If 'n' is true, ZMATE will scan
  492. the macro from the beginning for a marker of the form ":x".
  493.  
  494. Finally, if 'n' is 'true', the command "n%" will terminate execution of the
  495. entire macro and return control to any macro that called this one as a
  496. subroutine or to the user.
  497.  
  498. Some Final Examples
  499.  
  500. Table 2 shows some more examples of built-in functions. These macros use some
  501. of ZMATE's testing powers. Function 0 moves the cursor to the first character
  502. in the buffer unless it is already there, in which case it moves it to the
  503. bottom of the buffer. The expression "@C=0" performs a logical comparison of
  504. the value of '@C', the number of the character under the cursor, and 0. If the
  505. cursor is on the first character in the buffer (remember, numbering starts at
  506. 0), then this expression will be Boolean 'true' (arithmetic -1), and the first
  507. macro block, "Z", will be performed. Otherwise the second block, "A", will be
  508. carried out.
  509.  
  510. In looking at that macro just now, I realized that it could be shorted
  511. slightly to
  512.  
  513.        @C{A}{Z}
  514.  
  515. Here we treat "@C" as a Boolean value. If it is zero (we are at top of
  516. buffer), it will be interpreted as 'false' and "Z" will be executed. The
  517. version we used is easier to read but costs two extra characters.
  518.  
  519. Function 24 moves the cursor left one character geometrically. The command "-
  520. M" moves the cursor back one character absolute, and will back up to the
  521. previous line if the cursor is presently at the beginning of a line. The
  522. geometric motion macros work on the column number. Function 24 first checks to
  523. see what column the cursor is in presently. If the column number is greater
  524. than 0 ("@X>0"), then the macro computes the column number one to the left
  525. ("@X-1") and passes that value as a prefix argument to the command "QX".
  526.  
  527. Function 38 is still more complicated. It toggles the case of the alphabetic
  528. character under the cursor. The macro has three independent parts, the first
  529. two of which are conditionally executed. The conditionals are complex
  530. expressions involving two parts combined by a Boolean operator.
  531.  
  532. In the first one, @T>"@ tests to see whether the character under the cursor
  533. has an ASCII value greater than that of '@', which is one less than 'A'. If
  534. ZMATE had a greater-than-or-equal-to test, we could have written something
  535. like @T>="A, but this is not allowed. The second part, @T<"[, tests to see if
  536. the character is 'Z' or less. These two tests are combined by the Boolean
  537. 'and' operator '&'. The result will be true if the character is an upper case
  538. letter.
  539.  
  540. If the result is true, the value of the space character (32 decimal, but
  541. radix-invariant when expressed this way) is added to the current value to make
  542. the corresponding lower case character. This value then replaces the existing
  543. character. Finally, "%" is executed to terminate the macro.
  544.  
  545. If the first conditional is false, the macro continues with the second one. It
  546. tests to see if the character is in the range 'a' to 'z'. If it is, 32 is
  547. subtracted from the present value to make the corresponding upper case
  548. character, which then replaces the existing character. Again, the macro is
  549. terminated with "%".
  550.  
  551. If the character is not alphabetic at all, the macro continues with the final
  552. line. This simply moves the cursor to the next character without making any
  553. change.
  554.  
  555. Next time we will continue the discussion of ZMATE's command language, and,
  556. with any luck, I will have recovered my MEX patches and will be able to
  557. present them as well.
  558.  
  559.  
  560. Table 1. Macros used to implement some ZMATE built-in
  561. cursor motion functions. The table lists the function
  562. number and describes what the function does. If the
  563. function has a standard binding, it is shown. A caret
  564. prefix indicates a control character.
  565.  
  566. fn #          description              key       macro
  567. -----   ----------------------------   ---     -----------
  568.   1     to end of buffer                        Z
  569.   2     to previous char                ^G      -M
  570.   3     to previous word                ^O      -M0W
  571.   4     to next character               ^H      M
  572.   5     to next word                    ^P      W
  573.   6     up one line                     ^Y      -M0L
  574.  
  575. Table 2. Macros used to implement some additional and more
  576. complex ZMATE built-in functions.
  577.  
  578. fn #          description                    macro
  579. ----  ----------------------------   ---------------------
  580.   0   toggle top/bottom of buffer    @C=0{Z}{A}
  581.  24   character left geometric       @X>0{@X-1QX}
  582.  38   toggle case of character       @T>"@&(@T<"[)'{@T+" R%}
  583.                                      @T>"`&(@T<"{)'{@T-" R%}
  584.                                      M
  585.  
  586. [This article was originally published in issue 47 of The Computer Journal,
  587. P.O. Box 12, South Plainfield, NJ 07080-0012 and is reproduced with the
  588. permission of the author and the publisher.]
  589.