Locomotive Shell 1.0 - Extending & Modifying Locomotive BASIC

Started by zhulien, 20:11, 24 January 22

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

zhulien

new_commands.asm for new LUT lookups
newcommand_DIR: jp command_CAT


; command_GRAPHICS_PAPER__GRAPHICS_PEN_and_set_graphics_draw_mode:;{{Addr=$c59a Code Calls/jump count: 0 Data use count: 1}}
        ; cp      $ba              ;{{c59a:feba}}  token for "PAPER"
        ; jr      z,eval_and_set_graphics_paper;{{c59c:2813}}  set graphics paper
     
        ; call    next_token_if_equals_inline_data_byte;{{c59e:cd25de}}
        ; defb $bb                  ; token for "PEN"
        ; cp      $2c              ;{{c5a2:fe2c}}  ','
        ; call    nz,validate_and_set_graphics_pen;{{c5a4:c4bac5}}  set graphics pen


newcommand_MCP:
;ret nz
push af
push bc
push de
push hl

push af
ld a, 0
ld ($be80), a
pop af

        ;cp $0d                  ;CR
;jr z, newcommand_MCPOnly

        cp $00                  ;zero
jr z, newcommand_MCPOnly

; check overloaded tokens that are not extensions before we read the next token
        cp $a7                  ;extension token to test "LIST"
jr z, newcommand_MCPLIST

; do we have extensions?
        cp $e9                  ;extension indicator token
jr nz, newcommand_MCPEnd

; read the next token
call get_next_token_skipping_space

        cp $80                  ;extension token to test "STATUS"
jr z, newcommand_MCPSTATUS

newcommand_MCPEnd:
ld ($be80), a
pop hl
pop de
pop bc
pop af
;jr newcommand_MCPOnly
ret

newcommand_MCPOnly:
;ld a, 1
ld ($be80), a
ld hl, mcp_message
call output_ASCIIZ_string

pop hl
pop de
pop bc
pop af
        ret

newcommand_MCPLIST:
;ld a, 2
ld ($be80), a
ld hl, mcp_list_message
call output_ASCIIZ_string

pop hl
pop de
pop bc
pop af
;xor a
        ret

newcommand_MCPSTATUS:
;ld a, 3
ld ($be80), a
ld hl, mcp_status_message
call output_ASCIIZ_string

pop hl
pop de
pop bc
pop af
;xor a
        ret

mcp_message:
defb "MCP",10,13,0  ; base mcp

mcp_list_message:
defb "MCP LIST",10,13,0  ; base mcp and overloaded list

mcp_status_message:
defb "MCP STATUS",10,13,0  ; base mcp, but extended status

; commands made of more than 1 word seemed previously to always have two variants implemented
; for example: symbol after.  symbol is a command that checks for a subsequent after, but after is also a valid command on it's own.
; similar for graphics pen, graphics paper, line input
; ultimately we get dual use of the 2nd keyword if it makes sense
; note: the overloaded second keyword must have the same token as the original use keyword
;
; for example, below is status, but above is also mcp status separately
newcommand_STATUS:
;ret nz
push af
push bc
push de
push hl

ld a, 4
ld ($be80), a
ld hl, status_message
call output_ASCIIZ_string

pop hl
pop de
pop bc
pop af
;xor a
        ret

status_message:
defb "STATUS",10,13,0 

; does nothing as we already have a list command, however we are using this token for extended list commands
newcommand_LIST:
ret

;; get extension table for letter
;; A = initial letter of BASIC extension
get_extension_table_for_letter:
        push    hl
        sub    $41              ;{initial letter - 'A'
                                  ; number in range 0->27
        add    a,a              ; x2 (two bytes per table entry)
                                  ; A = offset into table

        ;add    a,(extension_table_per_letter) and $ff;table starts at Low byte of keyword table address
        ;ld      l,a
        ;adc    a,(extension_table_per_letter >> 8);high byte of keyword table address
        ;sub    l
        ;ld      h,a

push bc
ld b, 0
ld c, a
ld hl, extension_table_per_letter
add hl, bc
pop bc

        ld      e,(hl)            ;get address of keyword list from table
        inc    hl
        ld      d,(hl)
        pop    hl
        ret

extension_to_code_address_LUT:
                                 
defw newcommand_STATUS ;STATUS $80
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;
defw doNothing ;

extension_to_code_address_LUTEnd:

extension_table_per_letter:

        defw extension_table_A      ;
        defw extension_table_B      ;
        defw extension_table_C      ;
        defw extension_table_D      ;
        defw extension_table_E      ;
        defw extension_table_F      ;
        defw extension_table_G      ;
        defw extension_table_H      ;
        defw extension_table_I      ;
        defw extension_table_J      ;
        defw extension_table_K      ;
        defw extension_table_L      ;
        defw extension_table_M      ;
        defw extension_table_N      ;
        defw extension_table_O      ;
        defw extension_table_P      ;
        defw extension_table_Q      ;
        defw extension_table_R      ;
        defw extension_table_S      ; STATUS
        defw extension_table_T      ;
        defw extension_table_U      ;
        defw extension_table_V      ;
        defw extension_table_W      ;
        defw extension_table_X      ;
        defw extension_table_Y      ;
        defw extension_table_Z      ;

defb "EXTENSION_TABLE:"
;;======================================================================
;; Extension table
;; list of extension as text followed by extension byte (token?)
;; end of list signalled with a 0 byte
;;
;; - BASIC extension stored excluding initial letter

;;=extension table Z
extension_table_Z:
                                 
        defb 0                   

;;=extension table Y
extension_table_Y:
                                 
        defb 0                   

;;=extension table X
extension_table_X:
                                 
        defb 0                   

;;=extension table W
extension_table_W:
                                 
        defb 0                   

;;=extension table V
extension_table_V:
                                 
        defb 0                   

;;=extension table U
extension_table_U:
                                 
        defb 0                   

;;=extension table T
extension_table_T:
                                 
        defb 0                   

;;=extension table S
extension_table_S:
                                 
        defb "TATU","S"+$80,$80    ; STATUS
        defb 0                   

;;=extension table R
extension_table_R:
                                 
        defb 0                   

;;=extension table Q
extension_table_Q:
                                 
        defb 0                   

;;=extension table P
extension_table_P:
                                 
        defb 0                   

;;=extension table O
extension_table_O:
                                 
        defb 0                   

;;=extension table N
extension_table_N:
                                 
        defb 0                   

;;=extension table M
extension_table_M:
                                 
        defb 0                   

;;=extension table L
extension_table_L:
                                 
        defb 0                   

;;=extension table K
extension_table_K:
                                 
        defb 0                   

;;=extension table J
extension_table_J:
                                 
        defb 0                   

;;=extension table I
extension_table_I:
                                 
        defb 0                   

;;=extension table H
extension_table_H:
                                 
        defb 0                   

;;=extension table G
extension_table_G:
                                 
        defb 0                   

;;=extension table F
extension_table_F:
                                 
        defb 0                   

;;=extension table E
extension_table_E:
                                 
        defb 0                   

;;=extension table D
extension_table_D:
                                 
        defb 0                   

;;=extension table C
extension_table_C:
                                 
        defb 0                   

;;=extension table B
extension_table_B:
                                 
        defb 0                   

;;=extension table A
extension_table_A:
                                 
        defb 0                   

defb "EXTENSION_END:"


Bread80

I hadn't thought before about how extra tokens would affect the keyword lookups.

It looks like your creating a whole second set of keyword tables. But you'll need to know which keyword (ASCII) you have in order to know which table to look in, and you won't know which table to look in until you've done the lookup.

My suggestions would be to take the current lookup tables and add a second byte (after the existing token byte) to specify the table. The ASCII to token mapping would need to skip over (or return) the extra byte.

For token to keyword mapping you could retain the existing subroutine for original code to use, but updating it to check the second token byte and create a separate routine for the new table, which would be a near copy except for the second byte checking.

(Or you could do this in one routine which checks both bytes. That would depend on how easy it is to adapt the calling code, and the availability of registers both for the call and the code itself).

zhulien

Actually the keywords string together to form sentences, that how how it is by default, currently up to 3 words I think (on error goto blah).  what is intersting, is that each keyword can be functional by itself, or with 2, or with 3 etc and each keyword that is strung together takes up a token, the only way to get more tokens is to sacrifice existing or as I have done, create a new lookup of tokens triggered by an extension token.  To make matters worst, for expressions, they use the same token space as the non-expression tokens, effectively overloaded so we don't want to mess that up too.

To keep changes to a minimum, the extension token $e9, if present does go lookup a 2nd table for which we can have all new keywords or use existing tokens as extension, eg.

extension tokens:

MCP
STATUS

standard tokens:

LIST - lists a basic program usually

combinations:

LIST - as usual
MCP STATUS - extension token followed by another extension token
MCP LIST - list behaviour specific to the MCP, perhaps list tasks, using extension token followed by standard token

I didn't want to complicate the existing code too much, but even to introduce a new list or keywords, we need to take space from somewhere.

We can do that by either somehow splitting the existing 16kb ROM into 2 ROMS trying to make the code organised with a minimal number of jumps - I started looking at this and it is very very difficult because almost all the logic for keywords, errors, etc seems to be needed from everywhere.  The only way to do this with a bit of effort would be to put the actual implementations of the keywords into a 2nd ROM, but then we are swapping ROMs for every invokation - might be a bit slow (compared to usual)?

I thought it is easier with the extension lookup because, we can essentially move that to the 2nd ROM (duplicating only the 1st keyword lookup table in the 2nd ROM purely for lookups) if we want to continue stringing words together.

The most logical way to extend it would be to introduce keywords that string together related subsystems of commands.

like 

GRAPHICS PEN, GRAPHICS PAPER
which have 3 keywords involved: GRAPHICS, PEN, PAPER (note PEN & PAPER can be used by themselves too).

So, we could introduce new GRAPHICS commands, new AUDIO commands, new TASK (or MCP) commands, new RAM access commands etc.

Sadly, having to sacrifice existing keywords from the ROM to make the job easier to get any space to even pass control to a 2nd ROM for the 2nd lookup table, that is why I thought to create Locomotive Shell.  Already proven that we can launch different flavours of BASIC via their RSXs, |BASIC, or |SHELL or |BASICPLUS, and they all co-exist nicely and RSXs seem to work perfectly in all.  Just be sure to choose the default one you like to have in the upper half of the system ROM.

Bread80

So, if I understand you, certain keywords cause the system to switch to an alternate keyword table for the tokens/keywords which follow them. That's actually quite neat.

I was tempted to mention that any new keywords will cause any old code using that word as a variable name will fail, but using a separate table, presumably, means no such problems.

As for splitting the ROM in two, I have that in my future plans, but plenty of other projects to do first. I'll need to create some tools to parse the code and find links to see what to put in each ROM (or both), and then to replace any links between ROMs with the appropriate system call.

TotO

I can imagine that people using a shell instead of the BASIC to run programs expect to only replace the ROM 0.
"You make one mistake in your life and the internet will never let you live it down" (Keith Goodyer)

Powered by SMFPacks Menu Editor Mod