[Index] [Previous] [Next]

1.11 Jumping to Program Lines

LineNumberFromStr

Gets a line number from a string pointer. The string pointer is passed in in HL, and the integer result is returned in DE. Leading spaces are skipped over, and it returns on finding the first non-digit. The largest possible line number is 65529 - it syntax errors out if the value of the first four digits is more then 6552.

One interesting feature of this function is that it returns with Z set if it found a valid number (or the string was empty), or NZ if the string didn't lead with a number.

Decrement string ptr (so we're pointing at preceding character) and initialise result to 0.
049D 2B LineNumberFromStr DCX H
049E 110000 LXI D,0000
Get next character and exit if it's not alphanumeric.
04A1 D7 NextLineNumChar RST NextChar
04A2 D0 RNC
04A3 E5 PUSH H
04A4 F5 PUSH PSW Preserve flags
Syntax Error out if line number is already > 6552. This is really erroring out of the line number is >65529, since the next digit has not been counted in yet.
04A5 219819 LXI H,1998 Decimal 6552
04A8 E7 RST CompareHLDE
04A9 DAD001 JC SyntaxError
Multiply result by 10.
04AC 62 MOV H,D
04AD 6B MOV L,E
04AE 19 DAD D
04AF 29 DAD H
04B0 19 DAD D
04B1 29 DAD H
04B2 F1 POP PSW
Add this digit's value to the result and jump back.
04B3 D630 SUI '0'
04B5 5F MOV E,A
04B6 1600 MVI D,00
04B8 19 DAD D
04B9 EB XCHG
04BA E1 POP H
04BB C3A104 JMP NextLineNumChar

 

Gosub

Gosub sets up a flow struct on the stack and then falls into Goto. The flow struct is KWID_GOSUB, preceded by the line number of the gosub statement, in turn preceded by prog ptr to just after the gosub statement.

Check we've got at least 12 bytes of memory spare.
04BE 0E03 Gosub MVI C,03
04C0 CDB601 CALL CheckEnoughVarSpace
Preserve return address in BC.
04C3 C1 POP B
Push prog ptr.
04C4 E5 PUSH H
Push the current line number on the stack so we can RETURN to it later.
04C5 E5 PUSH H
04C6 2A6101 LHLD CURRENT_LINE
04C9 E3 XTHL
Push keyword ID of 'GOSUB' onto stack. Note we only push the single byte.
04CA 168C MVI D,KWID_GOSUB
04CC D5 PUSH D
04CD 33 INX SP
Push return address preserved in BC, and fall into GOTO.
04CE C5 PUSH B

 

Goto

Sets program execution to continue from the line number argument.

Get line number argument in DE and return NZ indicating syntax error if the argument was a non-number .
04CF CD9D04 Goto CALL LineNumberFromStr
04D2 C0 RNZ
Look up the address of the program line with the provided number, put that into HL, and return if the program line was found (ie it exists).
04D3 CD7D02 CALL FindProgramLine
04D6 60 MOV H,B
04D7 69 MOV L,C
04D8 2B DCX H
04D9 D8 RC
Carry flag was not set by FindProgramLine so Undefined Subroutine (US) error.
04DA 1E0E MVI E,0E
04DC C3D501 JMP Error

 

Return

Returns program execution to the statement following the last GOSUB. Information about where to return to is kept on the stack in a flow struct (see notes).

No arguments allowed.
04DF C0 Return RNZ
Get pointer to flow struct on stack
04E0 16FF MVI D,FF
04E2 CD9201 CALL GetFlowPtr
04E5 F9 SPHL
If the first byte of the flow struct is not KWID_GOSUB (as placed there by the Gosub handler) then the gosub can't have happened so exit to a Return without Gosub (RG) error.
04E6 FE8C CPI KWID_GOSUB
04E8 1E04 MVI E,04
04EA C2D501 JNZ Error
Get line number of Gosub statement from flow struct into CURRENT_LINE.
04ED E1 POP H
04EE 226101 SHLD CURRENT_LINE
Set return address to ExecNext and pop the prog ptr to just after the Gosub statement into HL.
04F1 212104 LXI H,ExecNext
04F4 E3 XTHL

Safe to fall into FindNextStatement, since we're already at the end of the line!...

 

FindNextStatement

Finds the end of the statement or the end of the program line.

BUG: There is an interesting bug in this block, although it's harmless as by luck it's impossible to see it. The byte at 04F7 is 0x10, an illegal instruction, which is in turn followed by a NOP. This illegal instruction is almost certainly supposed to be 0x0E, so as to become the two-byte instruction MOV C,00. If this were the case it would make perfect sense as the loop reads ahead until it finds a null byte terminating the line or whatever the C register is loaded with.

04F7 is jumped to in two places - it is the REM handler, and also when an IF statement's condition evals to false and the rest of the line needs to be skipped. Luckily in both these cases, C just happens to be loaded with a byte that cannot occur in the program so the null byte marking the end of the line is found as expected.

Load C with the statement seperator character, a colon ':', and also LXI over the illegal instruction (which is a bug - see above).
04F5 013A.. FindNextStatement LXI B,..3A
04F7 10 Rem ???
04F8 00 NOP
04F9 7E FindNextStatementLoop MOV A,M
04FA B7 ORA A
04FB C8 RZ
04FC B9 CMP C
04FD C8 RZ
04FE 23 INX H
04FF C3F904 JMP FindNextStatementLoop

 


[Index] [Previous] [Next]