home *** CD-ROM | disk | FTP | other *** search
- R65
- TCJ46.WS
-
- The ZMATE Text Editor
-
- Jay Sage
-
-
- Although I have not yet finished the treatment of MEX, I amì
- going to start a new subject this time: the ZMATE macro textì
- editor. During the past two months I have been working on aì
- number of code patches to MEX-Plus to fix some problems and toì
- add some new features that I wanted or needed. That work is notì
- complete, so I have decided to hold off on a MEX update untilì
- next time. As usual, I do have a few miscellaneous items toì
- bring to your attention.
-
-
- Pieces of Eight
-
- First, I would like to put in a plug for the "Pieces of Eight"ì
- magazine (POE) from the Connecticut CP/M Users' Group (CCP/M). ì
- CCP/M recently decided to begin addressing a national audienceì
- and not just their local members. Even if you cannot attendì
- their meetings, the subscription to POE that your $15 annual duesì
- brings you is alone worth the price.
-
- POE is a very nice complement to TCJ. I don't think I willì
- offend CCP/M by saying that their magazine is far less seriousì
- than this one. There is some solid technical content, but theì
- emphasis is definitely on the human side of computing. It isì
- really fun to read, and not just by us computer nuts but by ourì
- entire families as well.
-
- The July, 1990, issue has a feature article on the Trentonì
- Computer Festival held in April. On the cover is a picture takenì
- there showing me, Bridger Mitchell, Al Hawley, and Cam Cotrill. ì
- (In case you might be questioning my motives, their flattering meì
- by putting my picture on the cover provided only a fraction ofì
- the inspiration for this plug!)
-
- Inside are more pictures: Rob Friefeld (LSH, SALIAS), Carsonì
- Wilson (ZDE, ZSDOS), Hal Bower (ZSDOS), Bruce Morgen (MEX+2Z andì
- lots of program patches), Howard Goldstein (our alpha tester andì
- bug catcher and fixer extraordinaire), and quite a few others. ì
- As you can see, Trenton drew Z-Team members and enthusiasts fromì
- all over the country! If you want to learn more about theì
- festival, sign up for POE. Send dues to Tom Veile, 26 Slaterì
- Ave., Norwich, CT 06360.
-
-
- A Patch for The Word Plus
-
-
- Some time ago I published here a set of ARUNZ aliases forì
- automating the use of The Word Plus spell checker. Well, Richardì
- Swift liked them just fine, but it then annoyed him that he stillì
- had to hit a carriage return to get past TW's prompt aboutì
- whether the configuration was correct. He wanted TW to get rightì
- to work.
-
- At first I didn't really see why he was making such a fussì
- about such a little thing. Then it began to eat at me, too. ì
- This one little thing was standing in the way of completeì
- automation.
-
- Well, it took a good bit of poking around in the TW.COM code,ì
- but in the end it was quite easy to patch around this annoyingì
- prompt. First I located where the code that put up the promptì
- began, and then I found where things picked up again after it. Aì
- simple jump instruction at the beginning to skip over it shouldì
- do the trick, I thought.
-
- Unfortunately, it was not quite that simple. As Bruce Morgenì
- had described earlier in an issue of his NAOG newsletter, theì
- programs in The Word Plus suite perform some simple internalì
- checking to make sure the file is not corrupted and has loadedì
- successfully. Nice of those folks, but after I put in my patch,ì
- the code looked corrupted. I could have figured out the newì
- checksum value and stuck it into the testing code, but it wasì
- easier just to bypass the checking entirely.
-
- At first I put the changes into a patch file that would beì
- overlaid onto the original code. Then, however, I decided thatì
- there was no real need to make the change permanently. Whenì
- running TW manually, one would probably want the prompt to appearì
- so that one would have the option of changing the setup. So, myì
- solution was the old GET/POKE/GO technique introduced by Bruceì
- Morgen (boy does that name keep coming up!).
-
- My original ARUNZ alias had a command of the form
-
- tw:tw <file> <dictionary>
-
- I just replaced that by
-
- /TWPAT <file> <dictionary>
-
- and wrote the new alias TWPAT with the command lines
-
- get 100 tw:tw.com load TW.COM
- poke 103 c3 3b 01 patch to jump over code test
- poke 395 c3 2a 04 patch to jump over prompt
- go $* run the patched code
-
- Now I could invoke the patched TW whenever I wanted by using theì
- command TWPAT instead.
-
-
- The ZMATE Text Editor
-
-
- Now for the main topic of this column, the first in a seriesì
- of articles on ZMATE. This one will be just an introduction andì
- will cover only its design philosophy and mode of operation. ì
- Next time I will start to describe its language in detail.
-
-
- Interpreters and Compilers
-
- A casual user would classify ZMATE as an application program,ì
- and more precisely as a text editor or wordprocessor. In itsì
- soul, however, it is really a high-level programming language. ì
- In some ways it is similar to the familiar BASIC interpreter.
-
- Like almost all the programming languages most people workì
- with, BASIC is oriented toward numerical computation. Forì
- example, at the system prompt one can enter a command such as
-
- print ( n1 + n2 ) * n3
-
- BASIC will then retrieve the values associated with the variablesì
- N1, N2, and N3, substitute them into the mathematical expression,ì
- evaluate the expression, and print the result to the screen.
-
- BASIC also allows one to write programs comprising a series ofì
- numbered statements such as:
-
- 100 n1 = 10
- 110 n2 = 5
- 120 n3 = 3
- 130 print ( n1 + n2 ) * n3
-
- When the immediate command "RUN" is entered, the entire sequenceì
- of commands is carried out, and the number 45 appears on theì
- screen.
-
- One could write a program to do the same thing using assemblyì
- language, the native language of a computer. However, a high¡
- level language like BASIC makes it far easier to generate theì
- required instructions. This is especially true when we areì
- dealing with floating point numbers, or when we are using arrayì
- variables or advanced mathematical (trig and log) functions.
-
- When the BASIC interpreter we described above is told toì
- "RUN", it processes the program statements one at a time. Firstì
- it analyzes a statement to determine the procedures required toì
- perform the specified function. Then it calls routines thatì
- execute those procedures. This means that when a BASIC statementì
- appears in a loop, the analysis has to be repeated each time theì
- statement is executed.
-
- A compiler provides an alternative approach. The compiler canì
- be thought of as an automatic assembly language program writer. ì
- You write your program using the commands of the high-levelì
- language, and then the compiler converts them into an assemblyì
- language program for you.
-
- Some compilers generate actual assembly language source codeì
- that you then have to assemble. The PASCAL Z compiler, forì
- example, worked this way. This approach makes programì
- development slower but allows you to fine-tune the code if you soì
- desire. Other compilers, such as Turbo Pascal, generate only theì
- machine code (COM) files. Some compilers, such as BDS C, followì
- a two-step process, but the intermediate code is not standardì
- assembly code.
-
- A compiler, as you might guess, has the advantage of executionì
- speed, since the high-level language statements have to beì
- analyzed and converted into machine code only once, even whenì
- they are executed repeatedly in a loop. Also, more complexì
- programs that need more working memory can be accommodated, sinceì
- the code that figures out how to process the high-level languageì
- statements does not have to be in memory when the final programì
- is run.
-
- On the other hand, an interpreter offers many advantages thatì
- may make it well worth giving up some speed. Programs are muchì
- easier to develop with an interpreter for several reasons. ì
- First, you can execute them immediately, without having to goì
- through the extra step of compilation (and possibly assembly andì
- linkage) before execution. Second, the programs can be run lineì
- by line, and you can watch what is happening and catch errorsì
- more easily.
-
- There are also some things that an interpreter can do that aì
- compiler generally cannot. For example, suppose you are workingì
- with an array variable (a variable that holds a collection ofì
- values, not just a single value). With a compiler, you wouldì
- have to specify the size -- or at least a maximum size -- of theì
- array at the time the program is compiled so that the compilerì
- can allocate enough memory for it. With an interpreter, this isì
- not necessary. It does not have to allocate the memory until theì
- variable is first referenced. As a result, it is quiteì
- acceptable for its size to be determined by computationsì
- performed earlier in the program.
-
-
- ZMATE as Interpreter
-
- ZMATE is, in a way, like the BASIC interpreter, except thatì
- its intrinsic high-level language functions (we will call theseì
- 'primitives') are aimed at text processing rather than numberì
- processing. Just as BASIC has some text-processing primitivesì
- (e.g., string variables and functions), so ZMATE has someì
- numerical functions, but it is the text-manipulation primitivesì
- that are emphasized and richly developed.
-
- If your past experience has been confined to the usualì
- programming languages -- BASIC, FORTRAN, PASCAL, C, etc. -- youì
- probably have trouble picturing what a text-processing languageì
- would look like. Here are some examples to help convey theì
- concept.
-
- While most variables in BASIC contain either single numbers orì
- arrays of numbers, ZMATE has 'variables' called buffers thatì
- contain pieces of text. Primitives allow reading disk files intoì
- these buffers or writing text from the buffers out to files.
-
- Each buffer has two pointers. One is called the cursor. Itì
- is where most ZMATE primitives perform their operation. Theì
- other pointer is called a tag, and together with the cursor itì
- defines a block of text for some block-operation primitives.
-
- A whole set of ZMATE primitives deals with cursor motion. Theì
- cursor can be moved forward and backward in the buffer by unitsì
- of characters, words, paragraphs, or the whole buffer. Forì
- example, you can tell the cursor to back up by three words or goì
- forward two paragraphs.
-
- This highlights the difference between a number-processing andì
- a text processing language. BASIC supports string variables thatì
- can contain a line of text, but it does not know about words andì
- paragraphs. The user would have to write complex code to dealì
- with these text concepts. As a text-processing language, ZMATEì
- provides the code for this as part of the language primitives.
-
- Other ZMATE primitives search for strings and compare stringsì
- or characters. Text can be inserted and deleted. Blocks of textì
- can be moved between buffers for cutting and pasting operations. ì
- All the usual control primitives are provided to allow testing,ì
- conditional operations, and looping.
-
- There are also special facilities for handling text formattingì
- and text input from the keyboard. Soft carriage returns can beì
- placed into text automatically, and various kinds of indentationì
- and margin control are provided. These functions make it easy toì
- write a wordprocessor in the ZMATE language.
-
-
- How the ZMATE Language is Used
-
- In our examples above, we saw that a BASIC statement can beì
- entered for immediate execution. ZMATE, too, allows this. Weì
- also saw that BASIC programs containing a sequence of statementsì
- can be prepared for later execution. The same is true of ZMATE. ì
- In fact, ZMATE can have a number of programs loaded and ready forì
- execution at the same time, and one program can call another as aì
- subroutine.
-
- ZMATE allows its language to be used in one other very specialì
- way. Programs that are permanently stored in the ZMATE COM fileì
- can be bound to a key or sequence of keys. Then when that keyì
- sequence is typed at the keyboard, the program is automaticallyì
- executed. ZMATE commands executed this way are called "instantì
- commands."
-
- As an example, suppose we write this little ZMATE program:
-
- 100 put the tag where the cursor is now
- 110 move the cursor forward one word
- 120 delete the block (tag-to-cursor)
- 130 stop
-
- [I am using a BASIC-like pseudo-language for this example. Theì
- actual ZMATE language, which we will get into next time, is notì
- at all like this.] If we now bind this program to the '^T'ì
- (control-T) key, we will have implemented the WordStar delete¡
- word function.
-
- This should give you a sense now of how ZMATE can be used toì
- implement a text editor or wordprocessor. Although ZMATE comesì
- with some standard programs and key bindings, you can change theì
- standard programs, can attach your own new programs, and canì
- change the key bindings. Thus you have extensive control overì
- the way ZMATE works and can add any functions you like to it.
-
-
- The ZMATE Screen
-
- The normal appearance of the screen while ZMATE is running isì
- shown in Fig. 1. In fact, I captured this screen using the BGiiì
- 'screen' command while writing this article. I have made a fewì
- changes to adapt it to the TCJ format. The real screen is theì
- full width of the terminal, usually 80 characters, and the fullì
- length, usually 24 lines. I have reduced both of these sizes.
-
- =================================================================
- R70
-
- /------------------------------------------------------------------\
- | TCJ: TCJ:TCJ46.WS,TCJ:TCJ46.$$$ buf=T arg=0 |col = 18 |
- | INSERT MODE |line= 204 |
- | ----------------------------------------------------|free= 13454 |
- | 100 put the tag where the cursor is now< |
- | 110 move the cursor to the next word< |
- | 120 delete the block (tag-to-cursor)< |
- | 130 stop< |
- | < |
- | [I am using a BASIC-like pseudo-language for this example. The |
- | actual ZMATE language, which we will get to next time, is not at |
- | all like this.] If we now bind this program to the ^T key, we |
- | will have implemented the WordStar delete-word function.< |
- | < |
- | < |
- | The ZMATE Screen< |
- | < |
- | The normal appearance of the screen while ZMATE is running is |
- | shown in Fig. 1. In fact, I captured this screen using the BGii |
- | 'screen' command while writing this article. I have made a few |
- | changes to adapt it to the TCJ format. The real screen is the |
- \------------------------------------------------------------------/
- R65
- Fig. 1. This is a snapshot of the ZMATE screen approximately asì
- it appeared while I was writing this column.
-
- =================================================================
-
- All but the top three lines are used for the display of text. ì
- In the original PMATE, only one buffer could be viewed. Withì
- ZMATE, Bridger Mitchell made it possible to look at two buffersì
- or at two sections of one buffer at the same time. By the way,ì
- the '<' characters at the ends of some lines in Fig. 1 indicateì
- hard carriage returns. The other lines end with soft returns. ì
- If one changes the margins, the text instantly readjusts.
-
- At the left of the top line, ZMATE shows the currently loggedì
- directory, the file that is open for input, and the file that isì
- open for output. In this case, the output file is a temporaryì
- file, TCJ:TCJ46.$$$. When one closes the edit file, the inputì
- file will be given a file type of BAK, while the temporary outputì
- file name will be changed to the original input file name.
-
- In the center of the top line, two status variables areì
- displayed. The first tells us which buffer is currently beingì
- edited (there are 12 of them); the second is a numerical valueì
- returned by the last ZMATE command that was performed. Thatì
- value can convey information to the user or can be used forì
- testing in a program.
-
- At the right edge of the screen, three other status variablesì
- are displayed. The position of the cursor is given as a columnì
- and line number. The third value tells how much free memory isì
- available for additional text.
-
- The second line in Fig. 1 shows the mode status "INSERT MODE". ì
- ZMATE can run in three modes: insert, overtype, and command. Inì
- command mode, the second line is where the user enters ZMATEì
- program statements for immediate execution. After a command isì
- entered, it is executed by pressing the escape key (ESC).
-
- The most recently entered command remains on the command lineì
- and can be executed again by pressing ESC again. Other instantì
- command functions can be executed in between. This gives ZMATEì
- wonderful power. It is one of the things that the author ofì
- Vedit -- which began, I believe, as a PMATE clone -- neverì
- understood and is one of the reasons why I have always foundì
- Vedit unacceptable as an editor.
-
- Here is an example of how this facility can be used. Supposeì
- we want to change a number of words to upper case. Assuming thisì
- is not already defined as a built-in editor function, we write aì
- command line with code that changes all letters of the wordì
- containing the cursor to upper case. Then we press ESC, and theì
- current word is converted. Suppose the next word we want toì
- convert is down two lines and over three words from where we areì
- now. Assuming WordStar-like bindings, we could pressì
- "^X^X^F^F^F". Then we can press ESC again to convert that word. ì
- In a sense, ZMATE commands typed on the command line become boundì
- temporarily as an instant command on the ESC key.
-
- In insert mode, we are effectively running a ZMATE programì
- that asks the user to press keys, which are then inserted intoì
- the text. Overtype mode is the same except that the newì
- characters replace the ones previously under the cursor. In bothì
- insert and overtype mode, instant commands operate just as inì
- command mode. That is, key sequence binding are still fully inì
- effect.
-
-
- Key Bindings
-
- This is a good time to make the role of key bindings moreì
- explicit. With ZMATE, one should think of no keys as producingì
- direct input to the editor. All keys have to be bound to someì
- function if they are to have any effect at all.
-
- ZMATE has three sources for the functions that are bound toì
- the keys. One of these comprises functions that produce ASCIIì
- characters. Most people would take it for granted that pressingì
- the 'A' key would produce an 'A', but this is not necessarily soì
- in ZMATE. This makes it quite easy to implement a non-standardì
- keyboard layout, such as the Dvorak layout.
-
- The bindings, moreover, are not one-to-one. You can have aì
- number of different key sequences bound to the same function. ì
- So, if you want to have two ESC keys, you can bind a secondì
- keyboard key to the "produce-an-ESC-character" function as well. ì
- And I want to emphasize that these bindings are of sequences ofì
- one or more keys (up to some configurable maximum number) to anyì
- single function.
-
- The key bindings are defined in a table with the followingì
- structure. Each entry, except the last, comprises a byte with aì
- function number followed by the sequence of ASCII key codes boundì
- to that function. The sequences are all exactly the maximumì
- length specified in the configuration. If the defined sequenceì
- is shorter than this, null bytes (value 0) are used as filler. ì
- The end of the table is indicated by a value of FF hex in theì
- function-number position.
-
- The character-producing functions have numbers from from 1 toì
- 127 inclusive. I am not sure about function 0. Putting a nullì
- into text is generally not allowed, as null is used to separateì
- the buffers. If no explicit binding is specified for a singleì
- ASCII character in the range 1 to 127, it is by default bound toì
- the function that produces that character. Thus the key sequenceì
- 'A' (a single press of the 'A' key) is bound to the "produce-an¡
- A" function if it does not appear in the key binding table.
-
- This direct mapping of ASCII characters is not, as I saidì
- above, required. For example, I use the tilde and back¡
- apostrophe as lead-in keys to other sequences (some people wouldì
- call these keys 'meta' keys). In order to be able to enter theseì
- two characters easily into text, I bind the sequence "~~" (twoì
- tildes in a row) to the "produce-a-tilde" function and "``" toì
- the "produce-a-back-apostrophe" function.
-
- The second set of functions, numbered from 128 to 191, isì
- implemented in ZMATE's internal code. However, all but a few ofì
- them are in fact performed by macro statements in the standardì
- ZMATE language. In PMATE there was no way to modify these; inì
- ZMATE, they have been placed at the end of the code andì
- referenced in a way that allows the overlay configuration patchì
- to redefine these functions freely.
-
- By my count, of the 64 functions of this type, all but 12 areì
- defined by macro program statements. In some cases it is obviousì
- why some are not. For example, there is a function for setting aì
- repeat count that applies to the next command entered. There isì
- also a function that aborts the execution of any macro. Theseì
- functions would not make sense in the macro language itself.
-
- For some functions it is not so clear why they are notì
- implemented as macros. For example, there is a function to popì
- from the "garbage stack" the most recently deleted block of text. ì
- This is something that cannot presently be done in the commandì
- language, but I don't see why it couldn't or shouldn't be.
-
- Then there are several functions for which there exist macroì
- commands that perform the function. Switching to insert,ì
- overtype, or command mode are examples. I don't know why theyì
- are implemented directly in code rather than in the macroì
- language.
-
- The final set of functions is numbered from 192 to 254. Aì
- hexadecimal FF (255 decimal) is used to mark the end of theì
- binding table, so this function number is not allowed. Theseì
- functions are associated with what is called the "permanent macroì
- area" or PMA in ZMATE.
-
- The PMA is a text block that is permanently stored along withì
- the ZMATE code and can be moved to and from editing buffers. Itì
- contains a series of macro definitions, each one introduced by aì
- control-X character followed by the one-character name for theì
- macro and then the program. Functions 192 to 254 correspond toì
- macros whose one-character name is 160 less than the functionì
- number, i.e., from space (32) to caret (94). Because the PMA canì
- be edited from within ZMATE, these instant-command functions canì
- be modified quite easily. It might even be possible for one ofì
- these macros to be modified by another macro!
-
- Permanent macros are not limited to the names that can beì
- bound to key sequences. The maximum number of permanent macrosì
- would be 256 (0 to 255). However, (1) the value 0 is notì
- allowed, (2) upper-case and lower-case letters are equivalent,ì
- and (3) not all characters with the high bit set are distinctì
- from the same character without the high bit set (though some areì
- different). In all, by my count there are 160 possible permanentì
- macro names, of which 63, as mentioned earlier, can be bound toì
- keys. The others can be invoked from the command line or fromì
- other macros.
-
- Well, this completes the discussion of ZMATE for this time. ì
- Next time I will present its command language in detail.
- commands.
-
- The Word
- ========
-
- Patch developed for Swift to bypass the prompt. See TWPAT.Z80 inì
- TW:
- directory.
-
- Plug for POE magazine
- =====================
-