home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / jsage / znode3 / tcj / tcj46.ws < prev    next >
Encoding:
Text File  |  1994-09-02  |  23.8 KB  |  517 lines

  1. R65
  2. TCJ46.WS
  3.  
  4.                       The ZMATE Text Editor
  5.  
  6.                             Jay Sage
  7.  
  8.  
  9.    Although I have not yet finished the treatment of MEX, I amì
  10. going to start a new subject this time: the ZMATE macro textì
  11. editor.  During the past two months I have been working on aì
  12. number of code patches to MEX-Plus to fix some problems and toì
  13. add some new features that I wanted or needed.  That work is notì
  14. complete, so I have decided to hold off on a MEX update untilì
  15. next time.  As usual, I do have a few miscellaneous items toì
  16. bring to your attention.
  17.  
  18.  
  19.                          Pieces of Eight
  20.  
  21.    First, I would like to put in a plug for the "Pieces of Eight"ì
  22. magazine (POE) from the Connecticut CP/M Users' Group (CCP/M). ì
  23. CCP/M recently decided to begin addressing a national audienceì
  24. and not just their local members.  Even if you cannot attendì
  25. their meetings, the subscription to POE that your $15 annual duesì
  26. brings you is alone worth the price.
  27.  
  28.    POE is a very nice complement to TCJ.  I don't think I willì
  29. offend CCP/M by saying that their magazine is far less seriousì
  30. than this one.  There is some solid technical content, but theì
  31. emphasis is definitely on the human side of computing.  It isì
  32. really fun to read, and not just by us computer nuts but by ourì
  33. entire families as well.
  34.  
  35.    The July, 1990, issue has a feature article on the Trentonì
  36. Computer Festival held in April.  On the cover is a picture takenì
  37. there showing me, Bridger Mitchell, Al Hawley, and Cam Cotrill. ì
  38. (In case you might be questioning my motives, their flattering meì
  39. by putting my picture on the cover provided only a fraction ofì
  40. the inspiration for this plug!)
  41.  
  42.    Inside are more pictures: Rob Friefeld (LSH, SALIAS), Carsonì
  43. Wilson (ZDE, ZSDOS), Hal Bower (ZSDOS), Bruce Morgen (MEX+2Z andì
  44. lots of program patches), Howard Goldstein (our alpha tester andì
  45. bug catcher and fixer extraordinaire), and quite a few others. ì
  46. As you can see, Trenton drew Z-Team members and enthusiasts fromì
  47. all over the country!  If you want to learn more about theì
  48. festival, sign up for POE.  Send dues to Tom Veile, 26 Slaterì
  49. Ave., Norwich, CT 06360.
  50.  
  51.  
  52.                     A Patch for The Word Plus
  53.  
  54.  
  55.    Some time ago I published here a set of ARUNZ aliases forì
  56. automating the use of The Word Plus spell checker.  Well, Richardì
  57. Swift liked them just fine, but it then annoyed him that he stillì
  58. had to hit a carriage return to get past TW's prompt aboutì
  59. whether the configuration was correct.  He wanted TW to get rightì
  60. to work.
  61.  
  62.    At first I didn't really see why he was making such a fussì
  63. about such a little thing.  Then it began to eat at me, too. ì
  64. This one little thing was standing in the way of completeì
  65. automation.
  66.  
  67.    Well, it took a good bit of poking around in the TW.COM code,ì
  68. but in the end it was quite easy to patch around this annoyingì
  69. prompt.  First I located where the code that put up the promptì
  70. began, and then I found where things picked up again after it.  Aì
  71. simple jump instruction at the beginning to skip over it shouldì
  72. do the trick, I thought.
  73.  
  74.    Unfortunately, it was not quite that simple.  As Bruce Morgenì
  75. had described earlier in an issue of his NAOG newsletter, theì
  76. programs in The Word Plus suite perform some simple internalì
  77. checking to make sure the file is not corrupted and has loadedì
  78. successfully.  Nice of those folks, but after I put in my patch,ì
  79. the code looked corrupted.  I could have figured out the newì
  80. checksum value and stuck it into the testing code, but it wasì
  81. easier just to bypass the checking entirely.
  82.  
  83.    At first I put the changes into a patch file that would beì
  84. overlaid onto the original code.  Then, however, I decided thatì
  85. there was no real need to make the change permanently.  Whenì
  86. running TW manually, one would probably want the prompt to appearì
  87. so that one would have the option of changing the setup.  So, myì
  88. solution was the old GET/POKE/GO technique introduced by Bruceì
  89. Morgen (boy does that name keep coming up!).
  90.  
  91.    My original ARUNZ alias had a command of the form
  92.  
  93.     tw:tw <file> <dictionary>
  94.  
  95. I just replaced that by
  96.  
  97.     /TWPAT <file> <dictionary>
  98.  
  99. and wrote the new alias TWPAT with the command lines
  100.  
  101.     get 100 tw:tw.com    load TW.COM
  102.     poke 103 c3 3b 01    patch to jump over code test
  103.     poke 395 c3 2a 04    patch to jump over prompt
  104.     go $*            run the patched code
  105.  
  106. Now I could invoke the patched TW whenever I wanted by using theì
  107. command TWPAT instead.
  108.  
  109.  
  110.                       The ZMATE Text Editor
  111.  
  112.  
  113.    Now for the main topic of this column, the first in a seriesì
  114. of articles on ZMATE.  This one will be just an introduction andì
  115. will cover only its design philosophy and mode of operation. ì
  116. Next time I will start to describe its language in detail.
  117.  
  118.  
  119. Interpreters and Compilers
  120.  
  121.    A casual user would classify ZMATE as an application program,ì
  122. and more precisely as a text editor or wordprocessor.  In itsì
  123. soul, however, it is really a high-level programming language. ì
  124. In some ways it is similar to the familiar BASIC interpreter.
  125.  
  126.    Like almost all the programming languages most people workì
  127. with, BASIC is oriented toward numerical computation.  Forì
  128. example, at the system prompt one can enter a command such as
  129.  
  130.     print ( n1 + n2 ) * n3
  131.  
  132. BASIC will then retrieve the values associated with the variablesì
  133. N1, N2, and N3, substitute them into the mathematical expression,ì
  134. evaluate the expression, and print the result to the screen.
  135.  
  136.    BASIC also allows one to write programs comprising a series ofì
  137. numbered statements such as:
  138.  
  139.     100 n1 = 10
  140.     110 n2 = 5
  141.     120 n3 = 3
  142.     130 print ( n1 + n2 ) * n3
  143.  
  144. When the immediate command "RUN" is entered, the entire sequenceì
  145. of commands is carried out, and the number 45 appears on theì
  146. screen.
  147.  
  148.    One could write a program to do the same thing using assemblyì
  149. language, the native language of a computer.  However, a high¡
  150. level language like BASIC makes it far easier to generate theì
  151. required instructions.  This is especially true when we areì
  152. dealing with floating point numbers, or when we are using arrayì
  153. variables or advanced mathematical (trig and log) functions.
  154.  
  155.    When the BASIC interpreter we described above is told toì
  156. "RUN", it processes the program statements one at a time.  Firstì
  157. it analyzes a statement to determine the procedures required toì
  158. perform the specified function.  Then it calls routines thatì
  159. execute those procedures.  This means that when a BASIC statementì
  160. appears in a loop, the analysis has to be repeated each time theì
  161. statement is executed.
  162.  
  163.    A compiler provides an alternative approach.  The compiler canì
  164. be thought of as an automatic assembly language program writer. ì
  165. You write your program using the commands of the high-levelì
  166. language, and then the compiler converts them into an assemblyì
  167. language program for you.
  168.  
  169.    Some compilers generate actual assembly language source codeì
  170. that you then have to assemble.  The PASCAL Z compiler, forì
  171. example, worked this way.  This approach makes programì
  172. development slower but allows you to fine-tune the code if you soì
  173. desire.  Other compilers, such as Turbo Pascal, generate only theì
  174. machine code (COM) files.  Some compilers, such as BDS C, followì
  175. a two-step process, but the intermediate code is not standardì
  176. assembly code.
  177.  
  178.    A compiler, as you might guess, has the advantage of executionì
  179. speed, since the high-level language statements have to beì
  180. analyzed and converted into machine code only once, even whenì
  181. they are executed repeatedly in a loop.  Also, more complexì
  182. programs that need more working memory can be accommodated, sinceì
  183. the code that figures out how to process the high-level languageì
  184. statements does not have to be in memory when the final programì
  185. is run.
  186.  
  187.    On the other hand, an interpreter offers many advantages thatì
  188. may make it well worth giving up some speed.  Programs are muchì
  189. easier to develop with an interpreter for several reasons. ì
  190. First, you can execute them immediately, without having to goì
  191. through the extra step of compilation (and possibly assembly andì
  192. linkage) before execution.  Second, the programs can be run lineì
  193. by line, and you can watch what is happening and catch errorsì
  194. more easily.
  195.  
  196.    There are also some things that an interpreter can do that aì
  197. compiler generally cannot.  For example, suppose you are workingì
  198. with an array variable (a variable that holds a collection ofì
  199. values, not just a single value).  With a compiler, you wouldì
  200. have to specify the size -- or at least a maximum size -- of theì
  201. array at the time the program is compiled so that the compilerì
  202. can allocate enough memory for it.  With an interpreter, this isì
  203. not necessary.  It does not have to allocate the memory until theì
  204. variable is first referenced.  As a result, it is quiteì
  205. acceptable for its size to be determined by computationsì
  206. performed earlier in the program.
  207.  
  208.  
  209. ZMATE as Interpreter
  210.  
  211.    ZMATE is, in a way, like the BASIC interpreter, except thatì
  212. its intrinsic high-level language functions (we will call theseì
  213. 'primitives') are aimed at text processing rather than numberì
  214. processing.  Just as BASIC has some text-processing primitivesì
  215. (e.g., string variables and functions), so ZMATE has someì
  216. numerical functions, but it is the text-manipulation primitivesì
  217. that are emphasized and richly developed.
  218.  
  219.    If your past experience has been confined to the usualì
  220. programming languages -- BASIC, FORTRAN, PASCAL, C, etc. -- youì
  221. probably have trouble picturing what a text-processing languageì
  222. would look like.  Here are some examples to help convey theì
  223. concept.
  224.  
  225.    While most variables in BASIC contain either single numbers orì
  226. arrays of numbers, ZMATE has 'variables' called buffers thatì
  227. contain pieces of text.  Primitives allow reading disk files intoì
  228. these buffers or writing text from the buffers out to files.
  229.  
  230.    Each buffer has two pointers.  One is called the cursor.  Itì
  231. is where most ZMATE primitives perform their operation.  Theì
  232. other pointer is called a tag, and together with the cursor itì
  233. defines a block of text for some block-operation primitives.
  234.  
  235.    A whole set of ZMATE primitives deals with cursor motion.  Theì
  236. cursor can be moved forward and backward in the buffer by unitsì
  237. of characters, words, paragraphs, or the whole buffer.  Forì
  238. example, you can tell the cursor to back up by three words or goì
  239. forward two paragraphs.
  240.  
  241.    This highlights the difference between a number-processing andì
  242. a text processing language.  BASIC supports string variables thatì
  243. can contain a line of text, but it does not know about words andì
  244. paragraphs.  The user would have to write complex code to dealì
  245. with these text concepts.  As a text-processing language, ZMATEì
  246. provides the code for this as part of the language primitives.
  247.  
  248.    Other ZMATE primitives search for strings and compare stringsì
  249. or characters.  Text can be inserted and deleted.  Blocks of textì
  250. can be moved between buffers for cutting and pasting operations. ì
  251. All the usual control primitives are provided to allow testing,ì
  252. conditional operations, and looping.
  253.  
  254.    There are also special facilities for handling text formattingì
  255. and text input from the keyboard.  Soft carriage returns can beì
  256. placed into text automatically, and various kinds of indentationì
  257. and margin control are provided.  These functions make it easy toì
  258. write a wordprocessor in the ZMATE language.
  259.  
  260.  
  261. How the ZMATE Language is Used
  262.  
  263.    In our examples above, we saw that a BASIC statement can beì
  264. entered for immediate execution.  ZMATE, too, allows this.  Weì
  265. also saw that BASIC programs containing a sequence of statementsì
  266. can be prepared for later execution.  The same is true of ZMATE. ì
  267. In fact, ZMATE can have a number of programs loaded and ready forì
  268. execution at the same time, and one program can call another as aì
  269. subroutine.
  270.  
  271.    ZMATE allows its language to be used in one other very specialì
  272. way.  Programs that are permanently stored in the ZMATE COM fileì
  273. can be bound to a key or sequence of keys.  Then when that keyì
  274. sequence is typed at the keyboard, the program is automaticallyì
  275. executed.  ZMATE commands executed this way are called "instantì
  276. commands."
  277.  
  278.    As an example, suppose we write this little ZMATE program:
  279.  
  280.     100 put the tag where the cursor is now
  281.     110 move the cursor forward one word
  282.     120 delete the block (tag-to-cursor)
  283.     130 stop
  284.  
  285. [I am using a BASIC-like pseudo-language for this example.  Theì
  286. actual ZMATE language, which we will get into next time, is notì
  287. at all like this.]  If we now bind this program to the '^T'ì
  288. (control-T) key, we will have implemented the WordStar delete¡
  289. word function.
  290.  
  291.    This should give you a sense now of how ZMATE can be used toì
  292. implement a text editor or wordprocessor.  Although ZMATE comesì
  293. with some standard programs and key bindings, you can change theì
  294. standard programs, can attach your own new programs, and canì
  295. change the key bindings.  Thus you have extensive control overì
  296. the way ZMATE works and can add any functions you like to it.
  297.  
  298.  
  299. The ZMATE Screen
  300.  
  301.    The normal appearance of the screen while ZMATE is running isì
  302. shown in Fig. 1.  In fact, I captured this screen using the BGiiì
  303. 'screen' command while writing this article.  I have made a fewì
  304. changes to adapt it to the TCJ format.  The real screen is theì
  305. full width of the terminal, usually 80 characters, and the fullì
  306. length, usually 24 lines.  I have reduced both of these sizes.
  307.  
  308. =================================================================
  309. R70
  310.  
  311. /------------------------------------------------------------------\
  312. | TCJ: TCJ:TCJ46.WS,TCJ:TCJ46.$$$   buf=T  arg=0      |col = 18    |
  313. | INSERT MODE                                         |line= 204   |
  314. | ----------------------------------------------------|free= 13454 |
  315. |         100 put the tag where the cursor is now<                 |
  316. |         110 move the cursor to the next word<                    |
  317. |         120 delete the block (tag-to-cursor)<                    |
  318. |         130 stop<                                                |
  319. | <                                                                |
  320. | [I am using a BASIC-like pseudo-language for this example.  The  |
  321. | actual ZMATE language, which we will get to next time, is not at |
  322. | all like this.]  If we now bind this program to the ^T key, we   |
  323. | will have implemented the WordStar delete-word function.<        |
  324. | <                                                                |
  325. | <                                                                |
  326. | The ZMATE Screen<                                                |
  327. | <                                                                |
  328. |    The normal appearance of the screen while ZMATE is running is |
  329. | shown in Fig. 1.  In fact, I captured this screen using the BGii |
  330. | 'screen' command while writing this article.  I have made a few  |
  331. | changes to adapt it to the TCJ format.  The real screen is the   |
  332. \------------------------------------------------------------------/
  333. R65
  334. Fig. 1.  This is a snapshot of the ZMATE screen approximately asì
  335. it appeared while I was writing this column.
  336.  
  337. =================================================================
  338.  
  339.    All but the top three lines are used for the display of text. ì
  340. In the original PMATE, only one buffer could be viewed.  Withì
  341. ZMATE, Bridger Mitchell made it possible to look at two buffersì
  342. or at two sections of one buffer at the same time.  By the way,ì
  343. the '<' characters at the ends of some lines in Fig. 1 indicateì
  344. hard carriage returns.  The other lines end with soft returns. ì
  345. If one changes the margins, the text instantly readjusts.
  346.  
  347.    At the left of the top line, ZMATE shows the currently loggedì
  348. directory, the file that is open for input, and the file that isì
  349. open for output.  In this case, the output file is a temporaryì
  350. file, TCJ:TCJ46.$$$.  When one closes the edit file, the inputì
  351. file will be given a file type of BAK, while the temporary outputì
  352. file name will be changed to the original input file name.
  353.  
  354.    In the center of the top line, two status variables areì
  355. displayed.  The first tells us which buffer is currently beingì
  356. edited (there are 12 of them); the second is a numerical valueì
  357. returned by the last ZMATE command that was performed.  Thatì
  358. value can convey information to the user or can be used forì
  359. testing in a program.
  360.  
  361.    At the right edge of the screen, three other status variablesì
  362. are displayed.  The position of the cursor is given as a columnì
  363. and line number.  The third value tells how much free memory isì
  364. available for additional text.
  365.  
  366.    The second line in Fig. 1 shows the mode status "INSERT MODE". ì
  367. ZMATE can run in three modes: insert, overtype, and command.  Inì
  368. command mode, the second line is where the user enters ZMATEì
  369. program statements for immediate execution.  After a command isì
  370. entered, it is executed by pressing the escape key (ESC).
  371.  
  372.    The most recently entered command remains on the command lineì
  373. and can be executed again by pressing ESC again.  Other instantì
  374. command functions can be executed in between.  This gives ZMATEì
  375. wonderful power.  It is one of the things that the author ofì
  376. Vedit -- which began, I believe, as a PMATE clone -- neverì
  377. understood and is one of the reasons why I have always foundì
  378. Vedit unacceptable as an editor.
  379.  
  380.    Here is an example of how this facility can be used.  Supposeì
  381. we want to change a number of words to upper case.  Assuming thisì
  382. is not already defined as a built-in editor function, we write aì
  383. command line with code that changes all letters of the wordì
  384. containing the cursor to upper case.  Then we press ESC, and theì
  385. current word is converted.  Suppose the next word we want toì
  386. convert is down two lines and over three words from where we areì
  387. now.  Assuming WordStar-like bindings, we could pressì
  388. "^X^X^F^F^F".  Then we can press ESC again to convert that word. ì
  389. In a sense, ZMATE commands typed on the command line become boundì
  390. temporarily as an instant command on the ESC key.
  391.  
  392.    In insert mode, we are effectively running a ZMATE programì
  393. that asks the user to press keys, which are then inserted intoì
  394. the text.  Overtype mode is the same except that the newì
  395. characters replace the ones previously under the cursor.  In bothì
  396. insert and overtype mode, instant commands operate just as inì
  397. command mode.  That is, key sequence binding are still fully inì
  398. effect.
  399.  
  400.  
  401. Key Bindings
  402.  
  403.    This is a good time to make the role of key bindings moreì
  404. explicit.  With ZMATE, one should think of no keys as producingì
  405. direct input to the editor.  All keys have to be bound to someì
  406. function if they are to have any effect at all.
  407.  
  408.    ZMATE has three sources for the functions that are bound toì
  409. the keys.  One of these comprises functions that produce ASCIIì
  410. characters.  Most people would take it for granted that pressingì
  411. the 'A' key would produce an 'A', but this is not necessarily soì
  412. in ZMATE.  This makes it quite easy to implement a non-standardì
  413. keyboard layout, such as the Dvorak layout.
  414.  
  415.    The bindings, moreover, are not one-to-one.  You can have aì
  416. number of different key sequences bound to the same function. ì
  417. So, if you want to have two ESC keys, you can bind a secondì
  418. keyboard key to the "produce-an-ESC-character" function as well. ì
  419. And I want to emphasize that these bindings are of sequences ofì
  420. one or more keys (up to some configurable maximum number) to anyì
  421. single function.
  422.  
  423.    The key bindings are defined in a table with the followingì
  424. structure.  Each entry, except the last, comprises a byte with aì
  425. function number followed by the sequence of ASCII key codes boundì
  426. to that function.  The sequences are all exactly the maximumì
  427. length specified in the configuration.  If the defined sequenceì
  428. is shorter than this, null bytes (value 0) are used as filler. ì
  429. The end of the table is indicated by a value of FF hex in theì
  430. function-number position.
  431.  
  432.    The character-producing functions have numbers from from 1 toì
  433. 127 inclusive.  I am not sure about function 0.  Putting a nullì
  434. into text is generally not allowed, as null is used to separateì
  435. the buffers.  If no explicit binding is specified for a singleì
  436. ASCII character in the range 1 to 127, it is by default bound toì
  437. the function that produces that character.  Thus the key sequenceì
  438. 'A' (a single press of the 'A' key) is bound to the "produce-an¡
  439. A" function if it does not appear in the key binding table.
  440.  
  441.    This direct mapping of ASCII characters is not, as I saidì
  442. above, required.  For example, I use the tilde and back¡
  443. apostrophe as lead-in keys to other sequences (some people wouldì
  444. call these keys 'meta' keys).  In order to be able to enter theseì
  445. two characters easily into text, I bind the sequence "~~" (twoì
  446. tildes in a row) to the "produce-a-tilde" function and "``" toì
  447. the "produce-a-back-apostrophe" function.
  448.  
  449.    The second set of functions, numbered from 128 to 191, isì
  450. implemented in ZMATE's internal code.  However, all but a few ofì
  451. them are in fact performed by macro statements in the standardì
  452. ZMATE language.  In PMATE there was no way to modify these; inì
  453. ZMATE, they have been placed at the end of the code andì
  454. referenced in a way that allows the overlay configuration patchì
  455. to redefine these functions freely.
  456.  
  457.    By my count, of the 64 functions of this type, all but 12 areì
  458. defined by macro program statements.  In some cases it is obviousì
  459. why some are not.  For example, there is a function for setting aì
  460. repeat count that applies to the next command entered.  There isì
  461. also a function that aborts the execution of any macro.  Theseì
  462. functions would not make sense in the macro language itself.
  463.  
  464.    For some functions it is not so clear why they are notì
  465. implemented as macros.  For example, there is a function to popì
  466. from the "garbage stack" the most recently deleted block of text. ì
  467. This is something that cannot presently be done in the commandì
  468. language, but I don't see why it couldn't or shouldn't be.
  469.  
  470.    Then there are several functions for which there exist macroì
  471. commands that perform the function.  Switching to insert,ì
  472. overtype, or command mode are examples.  I don't know why theyì
  473. are implemented directly in code rather than in the macroì
  474. language.
  475.  
  476.    The final set of functions is numbered from 192 to 254.  Aì
  477. hexadecimal FF (255 decimal) is used to mark the end of theì
  478. binding table, so this function number is not allowed.  Theseì
  479. functions are associated with what is called the "permanent macroì
  480. area" or PMA in ZMATE.
  481.  
  482.    The PMA is a text block that is permanently stored along withì
  483. the ZMATE code and can be moved to and from editing buffers.  Itì
  484. contains a series of macro definitions, each one introduced by aì
  485. control-X character followed by the one-character name for theì
  486. macro and then the program.  Functions 192 to 254 correspond toì
  487. macros whose one-character name is 160 less than the functionì
  488. number, i.e., from space (32) to caret (94).  Because the PMA canì
  489. be edited from within ZMATE, these instant-command functions canì
  490. be modified quite easily.  It might even be possible for one ofì
  491. these macros to be modified by another macro!
  492.  
  493.    Permanent macros are not limited to the names that can beì
  494. bound to key sequences.  The maximum number of permanent macrosì
  495. would be 256 (0 to 255).  However, (1) the value 0 is notì
  496. allowed, (2) upper-case and lower-case letters are equivalent,ì
  497. and (3) not all characters with the high bit set are distinctì
  498. from the same character without the high bit set (though some areì
  499. different).  In all, by my count there are 160 possible permanentì
  500. macro names, of which 63, as mentioned earlier, can be bound toì
  501. keys.  The others can be invoked from the command line or fromì
  502. other macros.
  503.  
  504.    Well, this completes the discussion of ZMATE for this time. ì
  505. Next time I will present its command language in detail.
  506. commands.
  507.  
  508. The Word
  509. ========
  510.  
  511. Patch developed for Swift to bypass the prompt.  See TWPAT.Z80 inì
  512. TW:
  513. directory.
  514.  
  515. Plug for POE magazine
  516. =====================
  517.