diff --git a/apps/zasm/io.asm b/apps/zasm/io.asm index c9bee13..3fa0da0 100644 --- a/apps/zasm/io.asm +++ b/apps/zasm/io.asm @@ -7,6 +7,11 @@ ; This unit also has the responsibility of counting the number of written bytes, ; maintaining IO_PC and of properly disabling output on first pass. ; +; On top of that, this unit has the responsibility of keeping track of the +; current lineno. Whenever GetC is called, we check if the fetched char is a +; newline. If it is, we increase our lineno. This unit is the best place to +; keep track of this because we have to handle ioRecallPos. +; ; zasm doesn't buffers its reads during tokenization, which simplifies its ; process. However, it also means that it needs, in certain cases, a "putback" ; mechanism, that is, a way to say "you see that character I've just read? that @@ -50,8 +55,12 @@ ; see ioPutBack below .equ IO_PUTBACK_BUF IO_INCLUDE_HDL+FS_HANDLE_SIZE .equ IO_IN_INCLUDE IO_PUTBACK_BUF+1 -.equ IO_PC IO_IN_INCLUDE+1 -.equ IO_RAMEND IO_PC+2 +.equ IO_PC IO_IN_INCLUDE+1 +; Current lineno in top-level file +.equ IO_LINENO IO_PC+2 +; Line number (can be top-level or include) when ioSavePos was last called. +.equ IO_SAVED_LINENO IO_LINENO+2 +.equ IO_RAMEND IO_SAVED_LINENO+2 ; *** Code *** @@ -59,7 +68,7 @@ ioInit: xor a ld (IO_PUTBACK_BUF), a ld (IO_IN_INCLUDE), a - jp ioResetPC + jp ioResetCounters ioGetC: ld a, (IO_PUTBACK_BUF) @@ -89,7 +98,17 @@ ioGetC: .normalmode: ; normal mode, read from IN stream ld ix, (IO_IN_GETC) - jp (ix) + call _callIX + cp 0x0a ; newline + ret nz ; not newline? return + ; inc current lineno + push hl + ld hl, IO_LINENO + inc (hl) + pop hl + cp a ; ensure Z + ret + .getback: push af xor a @@ -97,6 +116,10 @@ ioGetC: pop af ret +_callIX: + jp (ix) + ret + ; Put back non-zero character A into the "ioGetC stack". The next ioGetC call, ; instead of reading from IO_IN_GETC, will return that character. That's the ; easiest way I found to handle the readWord/gotoNextLine problem. @@ -121,21 +144,27 @@ ioPutC: ret ioSavePos: + ld hl, (IO_LINENO) + ld (IO_SAVED_LINENO), hl call _ioTell ld (IO_SAVED_POS), hl ret ioRecallPos: + ld hl, (IO_SAVED_LINENO) + ld (IO_LINENO), hl ld hl, (IO_SAVED_POS) jr _ioSeek ioRewind: - ld hl, 0 + call ioResetCounters ; sets HL to 0 jr _ioSeek -ioResetPC: +ioResetCounters: ld hl, 0 ld (IO_PC), hl + ld (IO_LINENO), hl + ld (IO_SAVED_LINENO), hl ret ; always in absolute mode (A = 0) @@ -186,3 +215,7 @@ ioOpenInclude: cp a ; ensure Z ret +; Return current lineno in HL +ioLineNo: + ld hl, (IO_LINENO) + ret diff --git a/apps/zasm/main.asm b/apps/zasm/main.asm index 34684be..02f2763 100644 --- a/apps/zasm/main.asm +++ b/apps/zasm/main.asm @@ -16,7 +16,8 @@ .equ ZASM_RAMEND ZASM_ORG+2 ; Read file through blockdev ID in H and outputs its upcodes through blockdev -; ID in L. +; ID in L. HL is set to the last lineno to be read. +; Sets Z on success, unset on error. On error, A contains an error code (ERR_*) zasmMain: ; Init I/O ld a, h @@ -38,13 +39,13 @@ zasmMain: ld a, 1 ld (ZASM_FIRST_PASS), a call zasmParseFile - ret nz + jr nz, .end ; Second pass - call ioRewind xor a ld (ZASM_FIRST_PASS), a call zasmParseFile - ret +.end: + jp ioLineNo ; --> HL, returns ; Sets Z according to whether we're in first pass. zasmIsFirstPass: @@ -76,7 +77,7 @@ zasmGetPC: ; IO. Z is set on success, unset on error. DE contains the last line number to ; be read (first line is 1). zasmParseFile: - call ioResetPC + call ioRewind .loop: call parseLine ret nz ; error diff --git a/tools/emul/zasm/zasm.bin b/tools/emul/zasm/zasm.bin index b7b0c76..d0d68a3 100644 Binary files a/tools/emul/zasm/zasm.bin and b/tools/emul/zasm/zasm.bin differ diff --git a/tools/emul/zasm/zasm.c b/tools/emul/zasm/zasm.c index f3bc0fb..10508f0 100644 --- a/tools/emul/zasm/zasm.c +++ b/tools/emul/zasm/zasm.c @@ -190,7 +190,8 @@ int main() fflush(stdout); int res = cpu.R1.br.A; if (res != 0) { - fprintf(stderr, "Error %d\n", res); + int lineno = cpu.R1.wr.HL; + fprintf(stderr, "Error %d on line %d\n", res, lineno); } return res; }