Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ htmlcov/
build/
venv/
.pypi-token
.coverage.*
15 changes: 12 additions & 3 deletions src/zxbc/zxbc.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import re
import sys
from argparse import Namespace
from io import StringIO

import src.api.optimize
Expand Down Expand Up @@ -61,7 +62,12 @@ def output(memory, ofile=None):
ofile.write("%s\n" % m)


def main(args=None, emitter=None):
def save_config(options: Namespace) -> None:
if not gl.has_errors and options.save_config:
src.api.config.save_config_into_file(options.save_config, src.api.config.ConfigSections.ZXBC)


def main(args=None, emitter=None) -> int:
"""Entry point when executed from command line.
zxbc can be used as python module. If so, bear in mind this function
won't be executed unless explicitly called.
Expand Down Expand Up @@ -124,6 +130,10 @@ def main(args=None, emitter=None):
debug.__DEBUG__("exiting due to errors.")
return 1 # Exit with errors

if options.parse_only:
save_config(options)
return gl.has_errors

# Emits data lines
translator.emit_data_blocks()
# Emits default constant strings
Expand Down Expand Up @@ -216,8 +226,7 @@ def main(args=None, emitter=None):
with open_file(OPTIONS.memory_map, "wt", "utf-8") as f:
f.write(asmparse.MEMORY.memory_map)

if not gl.has_errors and options.save_config:
src.api.config.save_config_into_file(options.save_config, src.api.config.ConfigSections.ZXBC)
save_config(options)

return gl.has_errors # Exit success

Expand Down
22 changes: 18 additions & 4 deletions src/zxbc/zxblex.py
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,8 @@ def t_ID(t):
entry = api.global_.SYMBOL_TABLE.get_entry(t.value) if api.global_.SYMBOL_TABLE is not None else None
if entry:
t.type = callables.get(entry.class_, t.type)
elif is_label(t):
t.type = "LABEL"

if t.type == "BIN":
t.lexer.begin("bin")
Expand Down Expand Up @@ -683,7 +685,7 @@ def find_column(token):
return column


def is_label(token):
def is_label(token) -> bool:
"""Return whether the token is a label (an integer number or id
at the beginning of a line.

Expand All @@ -706,11 +708,23 @@ def is_label(token):
i -= 1

column = c - i
if column != 0:
return False

if token.type == "NUMBER":
return True

i = token.lexpos + len(token.value)
while i < len(input):
if input[i] == ":":
return True

if input[i] not in {" ", "\t"}:
break

if column == 0:
column += 1
i += 1

return column == 1
return False


lexer = lex.lex()
Expand Down
2 changes: 1 addition & 1 deletion src/zxbc/zxbparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -1074,7 +1074,7 @@ def p_statement_call(p):
p[0] = None
elif len(p) == 2:
entry = SYMBOL_TABLE.get_entry(p[1])
if not entry or entry.class_ in (CLASS.label, CLASS.unknown):
if entry is not None and entry.class_ in (CLASS.label, CLASS.unknown):
p[0] = make_label(p[1], p.lineno(1))
else:
p[0] = make_sub_call(p[1], p.lineno(1), make_arg_list(None))
Expand Down
26 changes: 26 additions & 0 deletions tests/functional/arch/zx48k/label_decl0.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
org 32768
.core.__START_PROGRAM:
di
push ix
push iy
exx
push hl
exx
ld hl, 0
add hl, sp
ld (.core.__CALL_BACK__), hl
ei
jp .core.__MAIN_PROGRAM__
.core.__CALL_BACK__:
DEFW 0
.core.ZXBASIC_USER_DATA:
; Defines USER DATA Length in bytes
.core.ZXBASIC_USER_DATA_LEN EQU .core.ZXBASIC_USER_DATA_END - .core.ZXBASIC_USER_DATA
.core.__LABEL__.ZXBASIC_USER_DATA_LEN EQU .core.ZXBASIC_USER_DATA_LEN
.core.__LABEL__.ZXBASIC_USER_DATA EQU .core.ZXBASIC_USER_DATA
.core.ZXBASIC_USER_DATA_END:
.core.__MAIN_PROGRAM__:
.LABEL._MYLABEL:
jp .LABEL._MYLABEL
;; --- end of user code ---
END
6 changes: 6 additions & 0 deletions tests/functional/arch/zx48k/label_decl0.bas
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

REM labels needs to be declared at the beginning of line
REM with a trailing colon

MYLABEL:
GOTO MYLABEL
5 changes: 5 additions & 0 deletions tests/functional/arch/zx48k/label_decl1.bas
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

REM Will fail because it lacks a trailing COLON

WRONG_LABEL
GOTO WRONG_LABEL
5 changes: 5 additions & 0 deletions tests/functional/arch/zx48k/label_decl2.bas
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

REM will fail because labels must be declared
REM at the begining of the line

IF a > 10 THEN MYLABEL
89 changes: 89 additions & 0 deletions tests/functional/arch/zx48k/label_decl3.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
org 32768
.core.__START_PROGRAM:
di
push ix
push iy
exx
push hl
exx
ld hl, 0
add hl, sp
ld (.core.__CALL_BACK__), hl
ei
jp .core.__MAIN_PROGRAM__
.core.__CALL_BACK__:
DEFW 0
.core.ZXBASIC_USER_DATA:
; Defines USER DATA Length in bytes
.core.ZXBASIC_USER_DATA_LEN EQU .core.ZXBASIC_USER_DATA_END - .core.ZXBASIC_USER_DATA
.core.__LABEL__.ZXBASIC_USER_DATA_LEN EQU .core.ZXBASIC_USER_DATA_LEN
.core.__LABEL__.ZXBASIC_USER_DATA EQU .core.ZXBASIC_USER_DATA
_a:
DEFB 00
.core.ZXBASIC_USER_DATA_END:
.core.__MAIN_PROGRAM__:
ld a, 1
ld hl, (_a - 1)
cp h
jp c, .LABEL._BREAK
.LABEL.__LABEL1:
ld a, 8
call .core.__STOP
ld hl, 0
ld b, h
ld c, l
.core.__END_PROGRAM:
di
ld hl, (.core.__CALL_BACK__)
ld sp, hl
exx
pop hl
exx
pop iy
pop ix
ei
ret
.LABEL._BREAK:
ld hl, _a
inc (hl)
ld hl, 0
ld b, h
ld c, l
jp .core.__END_PROGRAM
;; --- end of user code ---
#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm"
; Simple error control routines
; vim:ts=4:et:
push namespace core
ERR_NR EQU 23610 ; Error code system variable
; Error code definitions (as in ZX spectrum manual)
; Set error code with:
; ld a, ERROR_CODE
; ld (ERR_NR), a
ERROR_Ok EQU -1
ERROR_SubscriptWrong EQU 2
ERROR_OutOfMemory EQU 3
ERROR_OutOfScreen EQU 4
ERROR_NumberTooBig EQU 5
ERROR_InvalidArg EQU 9
ERROR_IntOutOfRange EQU 10
ERROR_NonsenseInBasic EQU 11
ERROR_InvalidFileName EQU 14
ERROR_InvalidColour EQU 19
ERROR_BreakIntoProgram EQU 20
ERROR_TapeLoadingErr EQU 26
; Raises error using RST #8
__ERROR:
ld (__ERROR_CODE), a
rst 8
__ERROR_CODE:
nop
ret
; Sets the error system variable, but keeps running.
; Usually this instruction if followed by the END intermediate instruction.
__STOP:
ld (ERR_NR), a
ret
pop namespace
#line 31 "label_decl3.bas"
END
7 changes: 7 additions & 0 deletions tests/functional/arch/zx48k/label_decl3.bas
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

DIM a As UByte

IF a > 1 THEN GOTO BREAK
STOP

BREAK: LET a = a + 1
Loading