diff --git a/apps/zasm/main.asm b/apps/zasm/main.asm index af5e285..6ecdfec 100644 --- a/apps/zasm/main.asm +++ b/apps/zasm/main.asm @@ -56,12 +56,16 @@ jp zasmMain ; Read file through blockdev ID in H and outputs its upcodes through blockdev ; ID in L. zasmMain: + ; Init I/O ld a, h ld de, IO_IN_GETC call JUMP_BLKSEL ld a, l ld de, IO_OUT_GETC call JUMP_BLKSEL + ; Init modules + call symInit + ; First pass ld a, 1 ld (ZASM_FIRST_PASS), a @@ -155,14 +159,25 @@ parseLine: djnz .loopDirec jr .success .label: - call zasmIsFirstPass - jr nz, .success ; not in first pass? nothing to do ; The string in (scratchpad) is a label with its trailing ':' removed. ld hl, scratchpad + call zasmIsFirstPass + jr z, .registerLabel ; When we encounter a label in the first + ; pass, we register it in the symbol + ; list + ; When we're not in the first pass, we set the context (if label is not + ; local) to that label. + call symIsLabelLocal + jr z, .success ; local? nothing to do. + call symSetContext + jr z, .success + ; NZ? this means that (HL) couldn't be found in symbol list. Weird + jr .error +.registerLabel: ld de, (curOutputOffset) call symRegister - - jr .success + jr nz, .error + ; continue to .success .success: xor a ; ensure Z jr .end diff --git a/apps/zasm/symbol.asm b/apps/zasm/symbol.asm index 534618a..87f739e 100644 --- a/apps/zasm/symbol.asm +++ b/apps/zasm/symbol.asm @@ -29,7 +29,14 @@ ; index of the name, then go get the value at that index in SYM_VALUES. .equ SYM_NAMES SYM_VALUES+(SYM_MAXCOUNT*2) -.equ SYM_RAMEND SYM_NAMES+SYM_BUFSIZE +; Index of the symbol found during the last symSetContext call +.equ SYM_CONTEXT_IDX SYM_NAMES+SYM_BUFSIZE + +; Pointer, in the SYM_NAMES buffer, of the string found during the last +; symSetContext call +.equ SYM_CONTEXT_PTR SYM_CONTEXT_IDX+1 + +.equ SYM_RAMEND SYM_CONTEXT_PTR+2 ; *** Code *** @@ -52,6 +59,20 @@ _symNext: cp a ; ensure Z ret +symInit: + xor a + ld (SYM_NAMES), a + ld (SYM_CONTEXT_IDX), a + ld hl, SYM_CONTEXT_PTR + ld (SYM_CONTEXT_PTR), hl + ret + +; Sets Z according to whether label in (HL) is local (starts with a dot) +symIsLabelLocal: + ld a, '.' + cp (hl) + ret + ; Place HL at the end of SYM_NAMES end (that is, at the point where we have two ; consecutive null chars. We return the index of that new name in A. ; If we're within bounds, Z is set, otherwise unset. @@ -148,6 +169,12 @@ symRegister: ; If we find something, Z is set, otherwise unset. symFind: push hl + call _symFind + pop hl + ret + +; Same as symFind, but leaks HL +_symFind: push bc push de @@ -155,10 +182,21 @@ symFind: call strlen ld c, a ; let's save that + call symIsLabelLocal ; save Z for after the 3 next lines, which + ; doesn't touch flags. We need to call this now + ; before we lose HL. ex hl, de ; it's easier if HL is haystack and DE is ; needle. ld b, 0 ld hl, SYM_NAMES + jr nz, .loop ; not local? jump right to loop + ; local? then we need to adjust B and HL + ld hl, (SYM_CONTEXT_PTR) + ld a, (SYM_CONTEXT_IDX) + ld b, a + xor a + sub b + ld b, a .loop: ld a, c ; recall strlen call JUMP_STRNCMP @@ -179,7 +217,6 @@ symFind: .end: pop de pop bc - pop hl ret ; Return value associated with symbol index A into DE @@ -194,3 +231,18 @@ symGetVal: ld d, (hl) pop hl ret + +; Find symbol name (HL) in the symbol list and set SYM_CONTEXT_* accordingly. +; When symFind will be called with a symbol name starting with a '.', the search +; will begin at that context instead of the beginning of the register. +; Sets Z if symbol is found, unsets it if not. +symSetContext: + push hl + call _symFind + jr nz, .end ; Z already unset + ld (SYM_CONTEXT_IDX), a + ld (SYM_CONTEXT_PTR), hl + ; Z already set +.end: + pop hl + ret diff --git a/apps/zasm/tests/test3.asm b/apps/zasm/tests/test3.asm new file mode 100644 index 0000000..141b16f --- /dev/null +++ b/apps/zasm/tests/test3.asm @@ -0,0 +1,20 @@ +; test local labels +addDE: + push af + add a, e + jr nc, .end ; no carry? skip inc + inc d +.end: + ld e, a + pop af + ret + +addHL: + push af + add a, l + jr nc, .end ; no carry? skip inc + inc h +.end: + ld l, a + pop af + ret