home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / JSAGE / ZSUS / TCJ / TCJ47.TXT < prev    next >
Text File  |  2000-06-30  |  32KB  |  580 lines

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