[Index] [Previous] [Next]

1.4 Utility Functions

Some useful functions.

GetFlowPtr

Sets HL to point to the appropriate flow struct on the stack. On entry, if this was called by the NEXT keyword handler then DE is pointing to the variable following the NEXT keyword.

The first four bytes on the stack are (or rather, should be) two return addresses. We're not interested in them, so the first thing to do is set HL to point to SP+4.
0192 210400 GetFlowPtr LXI H,0004 HL=SP+4 (ie get word
0195 39 DAD SP just past return addr)
Get the keyword ID, the byte that precedes the flow struct. Then we increment HL so it points to (what should be) the flow struct, and return if the keyword ID is not 'FOR'.
0196 7E MOV A,M
0197 23 INX H
0198 FE81 CPI 81 'FOR'?
019A C0 RNZ Return if not 'FOR'
Special treatment for FOR flow structs. Here we check that we've got the right one, ie the one required by the NEXT statement which called us. When we're called by NEXT, it sets DE to point to the variable in the NEXT statement. So here we get the first word of the FOR flow struct which is the address of the FOR variable, and compare it to the one we've been given in DE. If they match, then we've found the flow struct wanted and we can safely return. If not then we jump 13 bytes up the stack - 13 bytes is the size of the FOR flow struct - and loop back to try again.
019B F7 RST PushNextWord PUSH (HL)
019C E3 XTHL POP HL (ie HL=(HL))
019D E7 RST CompareHLDE HL==DE?
019E 010D00 LXI B,000D
01A1 E1 POP H Restore HL
01A2 C8 RZ Return if var ptrs match.
01A3 09 DAD B HL+=000D
01A4 C39601 JMP GetFlowPtr+4 Loop

 

CopyMemoryUp

Copies a block of memory from BC to HL. Copying is done backwards, down to and including the point where BC==DE. It goes backwards because this function is used to move blocks of memory forward by as little as a couple of bytes. If it copied forwards then the block of memory would overwrite itself.

01A7 CDC301 CopyMemoryUp CALL CheckEnoughMem
Exchange BC with HL, so HL now points to the source and BC points to destination.
01AA C5 PUSH B Exchange BC with HL.
01AB E3 XTHL
01AC C1 POP B
01AD E7 CopyMemLoop RST CompareHLDE HL==DE?
01AE 7E MOV A,M
01AF 02 STAX B
01B0 C8 RZ Exit if DE reached.
01B1 0B DCX B
01B2 2B DCX H
01B3 C3AD01 JMP CopyMemLoop

 

CheckEnoughVarSpace

Checks that there is enough room for C*4 bytes on top of (VAR_TOP) before it intrudes on the stack. Probably varspace.

01B6 E5 CheckEnoughVarSpace PUSH H
01B7 2A6B01 LHLD VAR_TOP
01BA 0600 MVI B,00 BC=C*4
01BC 09 DAD B
01BD 09 DAD B
01BE CDC301 CALL CheckEnoughMem
01C1 E1 POP H
01C2 C9 RET

 

CheckEnoughMem

Checks that HL is more than 32 bytes away from the stack pointer. If HL is within 32 bytes of the stack pointer then this function falls into OutOfMemory.

01C3 D5 CheckEnoughMem PUSH D
01C4 EB XCHG
01C5 21DEFF LXI H,FFDE HL=-34 (extra 2 bytes for return address)
01C8 39 DAD SP
01C9 E7 RST CompareHLDE
01CA EB XCHG
01CB D1 POP D
01CC D0 RNC

 

Three common errors.

Notice use of LXI trick.

01CD 1E0C OutOfMemory MVI E,0C
01CF 01.... LXI B,....
     
01D0 1E02 SyntaxError MVI E,02
01D2 01.... LXI B,....
     
01D3 1E14 DivideByZero MVI E,14
     
     

 

Error

Resets the stack, prints an error code (offset into error codes table is given in E), and stops program execution.

01D5 CDB502 Error CALL ResetStack
01D8 CD8A05 CALL NewLine
01DB 21FA00 LXI H,ERROR_CODES
01DE 57 MOV D,A
01DF 3E3F MVI A,'?' Print '?'
01E1 DF RST OutChar
01E2 19 DAD D HL points to error code.
01E3 7E MOV A,M
01E4 DF RST OutChar Print first char of code.
01E5 D7 RST NextChar
01E6 DF RST OutChar Print second char of code.
01E7 218101 LXI H,szError Print " ERROR".
01EA CDA305 CALL PrintString
01ED 2A6101 LHLD CURRENT_LINE
01F0 7C MOV A,H
01F1 A5 ANA L
01F2 3C INR A
01F3 C42F0B CNZ PrintIN
01F6 01.... LXI B,.... LXI over Stop and fall into Main

 


[Index] [Previous] [Next]