LocalLabelsLully

This doc describes upcoming local label feature, and how to code it!
In this doc I may use label/symbol interchangeably.

Documentation

A local label starts with ‘.’. It can be repeated so you don’t have to invent fresh names each time. That is especially useful when embedded in a MACRO or a repetition bloc.

Exemple:

next_line_hl
    ld a,8:add h:jr nc,ok_msb
    ld a,r1*2::add l:ld l,a
    ld a,&c8:adc h
.ok_msb
   ld h,a

[...]

next_line_de
    ld a,8:add d:jr nc,ok_msb
    ld a,r1*2:add e:ld e,a
    ld a,&c8:adc d
.ok_msb
    ld d,a 

 4 ** [
    ...
    bit 7,h
    jr z,bit7off
.bit7on
    ...
    jr endBit7
.bit7off
    ...
.endBit7
    ...
    ]

Each local label is attached to the current scope. A new scope is introduced:

  • At each global label (next_line_hl and next_line_de in the example).
  • At the beginning of a repetition bloc
  • At MACRO invocation

Some differences with rasm:

  • No distinction is done between “proximity labels” and “local label”.
  • When they isn’t any global label with the same name, you don’t have to prefix it by ‘.’ at usage site (see the example: jr nc,ok_msb works as well as jr nc,.ok_msb).
  • No external access plained yet (e.g. next_line_hl.ok_msb).

Implementation

Existing state

Structure

The symbols table use 4 bytes per entry:

  • 1 byte: Flags (defined, used, type)
  • 3 bytes: Value (e.g. address, MACRO Id).

Assemblage

Each type of symbol is encoder differently in the source and triggers a different routine:

  • ass_equ: Assign the value of the expression.
  • ass_lab: Assign the current PC ($)
  • ass_macro: Register MACRO (store current pointeur in source then skip the body of the MACRO).

Potential issues

CTRL-ENTER

Jumping to the right label in the editor (CTRL-ENTER) becomes complicated, because we would need additional information from the assembler. It cannot be resolved purely textually.
This point isn’t addressed (hu) yet.

Design choice

Ids for local labels

Currently, each name is associated with an unique id. So there are two options to handle duplicate local labels.

Option 1: Use a fresh id (Rejected)

For each declaration we would use a new id.

Pro:

  • Minimal changes in structure.
  • Would allow to track the proper instance in the editor (CTRL-ENTER).

Con:

  • Less efficient memory-wise.

One big flaw: at usage sites, how would we pick the right one? It cannot be done at parsing time, since each line is encoded independently, without information about the surrounding (which might not exist yet!).
At assembly time, it would requires a slow

Option 2: Share the id (chosen)

All instances share the same id, and discrimination occurs at assemblage.
Pro:

  • Only the assembler can discriminate anyway.
  • That actually leads to an efficient implementation (see below)

Each declaration instance of a local label is associated with different attributes (current PC, current scope). Since the same ID is shared for those instances, how to store the attributes in the symbols table?

Option 1: More space for each entry (rejected)

Con:

  • Not scalable
  • Not efficient (unused space for all other kind of labels)

Option 2: Pointer to external list (chosen)

Each list can be stored in an auxiliary pool, emptied before assemblage.
Perfect!

Algorithm

Pre-assemblage: Reset pool_local,

Assemblage phase 1.

The main concern is to be able to identify each distinct scope. For instance “2nd invocation of MY_MACRO()”. To do so, we register the kind of scope (global, macro, repeat), the id and an additional counter. (**)

  • For each global label (ass_lab, both phases):
    • Set va_scope to tag LABEL + ID of this global label.
  • For each macro invocation (ass_macro_use, both phases):
    • Set va_scope to tag MACRO + ID of the macro + CNT (*)
  • For each repetition start (ass_repeat_start, both phases):
    • Set va_scope to tag REPEAT + $
  • For each local label(ass_local to be created):
    • If ID first met: reset associated list (RAZ pointeur).
    • In any case, append current pc and scope (va_scope). See list_append.

(*) The counter could either be:
1/ The invocation index for the particular macro/loop (0 for first invocation, 1 the next, etc).
Con: no pro.
2/ A global invocation index (across macros/loops)
Pro: Simpler

(**) Everything could fit on 3 bytes.

Assemblage phase 2

Here, where a local label is used, we must find the state associated with the current scope. To do so, the current scope (va_phase) must be updated as in phase1. Then:

  • For each local label use (is asseva.o):
    • Lookup the scope == va_scope, and get corresponding $.

One observation to speed up the lookup is that we never go backward (refer to a scope ahead of the current one). So we only need to search from the current position in the auxiliary list.

Routines

reset_pool

list_append

ass_local

eva_local

Sauf mention contraire, le contenu de cette page est protégé par la licence Creative Commons Attribution-ShareAlike 3.0 License