diff --git a/apps/README.md b/apps/README.md index c85b5c9..6be1999 100644 --- a/apps/README.md +++ b/apps/README.md @@ -104,3 +104,8 @@ Symbols have a different meaning depending on the application. In zasm, it's labels and constants. In basic, it's variables. Expressions can't contain spaces. + +Expressions can have an empty left operand. It will then be considered as 0. +This allows signed integers, for example, `-42` to be expressed as expected. +That form doesn't work well everywhere and is mostly supported for BASIC. In +zasm, you're safer with `0-42`. diff --git a/apps/basic/README.md b/apps/basic/README.md index c3f092a..3848591 100644 --- a/apps/basic/README.md +++ b/apps/basic/README.md @@ -47,10 +47,12 @@ by typing a whitespace. ### Numbers, expressions and variables -Only 16-bit integers (unsigned for now) are supported in this BASIC. When -printed, they're printed in decimal form. When expressing number literals, you -can do so either in multiple forms. . See "Number literals" in `apps/README.md` -for details. +Numbers are stored in memory as 16-bit integers (little endian) and numbers +being represented by BASIC are expressed as signed integers, in decimal form. +Line numbers, however, are expressed and treated as unsigned integers: You can, +if you want, put something on line "-1", but it will be the equivalent of line +65535. When expressing number literals, you can do so either in multiple forms. +See "Number literals" in `apps/README.md` for details. Expressions are accepted wherever a number is expected. For example, `print 2+3` will print `5`. See "Expressions" in `apps/README.md`. diff --git a/apps/basic/main.asm b/apps/basic/main.asm index 1ef9537..800e88b 100644 --- a/apps/basic/main.asm +++ b/apps/basic/main.asm @@ -192,7 +192,7 @@ basPRINT: jr nz, .parseError push ix \ pop de ld hl, SCRATCHPAD - call fmtDecimal + call fmtDecimalS call printstr pop hl ; <-- lvl 1 .chkAnother: diff --git a/apps/lib/expr.asm b/apps/lib/expr.asm index 53d941d..57eb33d 100644 --- a/apps/lib/expr.asm +++ b/apps/lib/expr.asm @@ -97,8 +97,16 @@ _findAndSplit: ; parse expression on the left (HL) and the right (DE) and put the results in ; HL (left) and DE (right) _resolveLeftAndRight: + ; special case: is (HL) zero? If yes, it means that our left operand + ; is empty. consider it as 0 + ld ix, 0 ; pre-set to 0 + ld a, (hl) + or a + jr z, .skip + ; Parse left operand in (HL) call parseExpr ret nz ; return immediately if error +.skip: ; Now we have parsed everything to the left and we have its result in ; IX. What we need to do now is the same thing on (DE) and then apply ; the + operator. Let's save IX somewhere and parse this. diff --git a/apps/lib/fmt.asm b/apps/lib/fmt.asm index 25e62b9..74236ed 100644 --- a/apps/lib/fmt.asm +++ b/apps/lib/fmt.asm @@ -1,4 +1,25 @@ +; Same as fmtDecimal, but DE is considered a signed number +fmtDecimalS: + bit 7, d + jr z, fmtDecimal ; unset, not negative + ; Invert DE. spit '-', unset bit, then call fmtDecimal + push de + ld a, '-' + ld (hl), a + inc hl + ld a, d + cpl + ld d, a + ld a, e + cpl + ld e, a + inc de + call fmtDecimal + dec hl + pop de + ret + ; Format the number in DE into the string at (HL) in a decimal form. ; Null-terminated. DE is considered an unsigned number. fmtDecimal: diff --git a/tools/tests/unit/test_expr.asm b/tools/tests/unit/test_expr.asm index b4cdc1c..e52ab25 100644 --- a/tools/tests/unit/test_expr.asm +++ b/tools/tests/unit/test_expr.asm @@ -149,6 +149,8 @@ testParseExpr: call .testEQ ld iy, .t7 call .testEQ + ld iy, .t8 + call .testEQ ret .testEQ: @@ -186,6 +188,9 @@ testParseExpr: .t7: .dw 0xcfb8 .db "0x99f7{3", 0 +.t8: + .dw 0xffff + .db "-1", 0 nexttest: ld a, (testNum) diff --git a/tools/tests/unit/test_lib_fmt.asm b/tools/tests/unit/test_lib_fmt.asm index 049717f..54a05ff 100644 --- a/tools/tests/unit/test_lib_fmt.asm +++ b/tools/tests/unit/test_lib_fmt.asm @@ -11,6 +11,7 @@ test: ld sp, 0xffff call testFmtDecimal + call testFmtDecimalS ; success xor a @@ -55,6 +56,30 @@ testFmtDecimal: .dw 0xffff .db "65535", 0 +testFmtDecimalS: + ld ix, .t1 + call .test + ld ix, .t2 + call .test + ret +.test: + ld e, (ix) + ld d, (ix+1) + ld hl, sandbox + call fmtDecimalS + ld hl, sandbox + push ix \ pop de + inc de \ inc de + call strcmp + jp nz, fail + jp nexttest +.t1: + .dw 1234 + .db "1234", 0 +.t2: + .dw 0-1234 + .db "-1234", 0 + nexttest: ld a, (testNum) inc a