Pointers and references: Difference between revisions

(→‎{{header|PARI/GP}}: now with references!)
Line 1,934:
V:= Ptr(-1); \get item immediately preceding Array(1), i.e. Array(0)
]</lang>
 
=={{header|Z80 Assembly}}==
Pointers can be used in several different ways on the Z80.
As with nearly all assembly languages, the Z80 does not enforce data types (except byte vs word). This means that a 16-bit integer in a register pair can be used as a pointer at any time. A value in <code>HL</code>, <code>BC</code>, <code>DE</code>, <code>IX</code>, or <code>IY</code> can be temporarily treated as a pointer by enclosing it in brackets. In addition, the accumulator can load from or store to a constant pointer.
 
<lang z80>ld a,(&C000) ;load the accumulator with the value from the memory address &C000.
 
ld hl,&D000
ld e,(hl) ;load the E register with the byte at memory address &D000.
 
ld bc,(&E000) ;load the register pair BC from memory address &E000.
; This is the same as:
; ld a,(&E000)
; ld c,a
; ld a,(&E001)
; ld b,a
 
ld IX,&F000
ld a,(IX+3) ;load A with the byte stored at &F003</lang>
 
Keep in mind that <code>HL</code>, <code>IX</code>, and <code>IY</code> are more flexible in the valid addressing modes that can be used.
Below are examples of code that are '''not valid''' and will be rejected by your assembler.
 
<lang z80>ld h,(bc) ;if (bc) or (de) is the operand of a LD command, the other operand must be A.
ld e,(&A000) ;if a constant pointer is the operand of a LD command, the other operand must be A.</lang>
 
 
In addition, <code>(HL)</code>, <code>(IX+n)</code>, and <code>(IY+n)</code> can be used with most commands that work with 8-bit register operands. (n is a signed, constant offset.) Some examples include:
 
<lang z80>inc (HL) ;increment the byte pointed to by HL
rrc (IX+5) ;take the byte pointed to by IX+5 and rotate it right. The value of IX is unchanged.
sub (IY-23) ;subtract the value of the byte that is 23 bytes before IY, from A.
;The value of that byte at that address is unchanged, as is IY.</lang>
 
 
Pointers that point to other pointers are a little tricky to dereference on the Z80. It's very difficult to do this without using a second register pair to hold the pieces temporarily.
 
<lang z80>ld hl,PointerTable
ld e,(hl)
inc hl
ld d,(hl)
; depending on what we need to do next, we might need this new pointer back in HL. There are a few ways to do this:
; ex de,hl
 
; push de
; pop hl
 
; ld L,E
; ld H,D</lang>
 
 
If you're able to use self-modifying code you can get away with using fewer registers, provided you know what the bytecode should look like:
 
<lang z80>ld hl,PointerTable
ld a,(hl)
ld (SMC+1),a ;SMC+1 points to low byte of the operand
 
inc hl ;increment HL so we can fetch the high byte
 
ld a,(hl)
ld (SMC+2),a ;SMC+2 points to high byte of the operand
 
SMC:
ld a,&BEEF ;gets overwritten with the pointer stored in entry 0 of PointerTable.</lang>
 
 
Making a new reference to an existing object is a common practice for when another function needs to use a value you looked up recently.
<lang z80>ld hl,PointerTable
ld a,(index)
add a ;this is a table of 16-bit values so double our index
add L
ld L,a
ld a,H
adc 0
ld H,a ;offset HL by our index
 
 
ld e,(hl)
inc hl
ld d,(hl) ;get the Ath entry of PointerTable and store it into DE.
 
ld (referenceStorage),DE ;store DE into ram for later use as a reference.</lang>
 
=={{header|zkl}}==
1,489

edits