23 January 2004 A tiny compiler, part 4 I had to make a few changes to my keyboard-loop code to get it ready to pass words on to the actual compiler code. Code changes The updated code works as follows (changes are in boldface): The code sets up the segment registers and stack, clears the text screen, and enters the loop. Changes to the key loop The loop starts by setting the attribute (color) of the next two character slots on the screen, so that the next characters typed are consistent with the value in attrib. Next, I get a key. If the key is not F1, F2, F3, or F4, I branch ahead. I check this by subtracting the scan code for F1 from the scan code I received. If the unsigned result is greater than four, I branch ahead. Otherwise, I save the result in mode so that I can use it later as an offset into the modes table when it comes time to process the word. Then I use the result as an offset into the attribs table so I can store the current attribute byte in attrib. Finally, I return to the top of the loop. sub ah, 0x3B cmp ah, 4 jnb .2 mov [mode], ah ; <-- CHANGE xor bh, bh mov bl, ah mov ah, [attribs+ax] mov [attrib], ah jmp short .4 If the key was not a function key, I test the ASCII code. If it is 33 or greater, then the character is printable and can be part of a word; otherwise, I go back for another key. If the keypress produced a visible character, I save the character into the newword buffer. I preserve the character already there by moving it into the other slot in the buffer. Note that the consequence of storing new characters in this way is that the word is stored backwards — if you type "ab", newword will contain "ba". This is a consequence of the fact that the second character's ASCII code arrives in AL and of my realization that writing code to correct this was unnecessary. cmp al, 33 jb .1 mov ah, [newword] ; <-- CHANGE mov [newword], ax ; <-- CHANGE The new character is printed to the screen, and the cursor is moved forward by one character. If the character just typed was the first of the two characters in the current word, then I go back to get the next key. If the character was the second of the two, I call the routine to process the word — I grab mode, use it as an offset into the modes table, and call the address I find there. The routine sets the carry flag on an error, in which case I print a question mark after the word on the screen; otherwise I print a space. ; SIX LINES ADDED: mov bx, [mode] shl bx, 1 mov bx, [modes+bx] call bx mov ax, (0xE * 0x100) + '?' jc .3 mov ax, (0xE * 0x100) + ' ' .3: xor bh, bh ; <-- LOCAL LABEL ADDED int 0x10 I then print another space (to bring the number of characters devoted to this word to four) and return to the top of the loop. Other changes The code requires the addition of two variables, a table of four two-byte addresses, and four compiler-mode routines. The compiler-mode routines are currently dummy routines that just set or clear the carry flag to test how well the calling code works: The code must print a question mark after the current word if the carry is set; otherwise it must print a space. ; ------ Compiler-mode routines. define: stc ret compile: clc ret execute: stc ret hex: clc ret ; ------ Variables. c: db 0 attrib: dw 0x04 ; facilitates "mov bx, [attrib]" attribs: db 0x04 ; red on black (define) db 0x02 ; green on black (compile) db 0x0E ; yellow on black (execute) db 0x05 ; magenta on black (hex) mode: dw 0 ; facilitates "mov bx, [mode]" modes: dw define, compile, execute, hex newword: db "c," Results
The code and data take up only 160 out of 510 bytes, so apparently I have plenty of room to add every feature I want. The code should work in the same way as the original keyboard-loop code, except that you'll see a question mark after every red word and every yellow word, but not after any green or magenta words. It works as advertised on my laptop. Some advice
If you're writing in assembly language and are trying to read an address from a table into a register so you can CALL the address via the register, make sure you don't type call [bx] when you really need call bx. I just spent two hours trying to figure out why my computer was crashing when I ran my code before I figured out that using call [bx] was the wrong thing to do here. Sigh. Check the index for other entries. |