Skip to content

Commit 5567233

Browse files
committed
fix: allow CONST strings
1 parent db6d5ac commit 5567233

7 files changed

Lines changed: 815 additions & 31 deletions

File tree

src/api/check.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,10 @@ def is_number(*p):
320320
return all(i.token in ("NUMBER", "CONST") for i in p)
321321

322322

323+
def is_static_str(*p):
324+
return all(i.token == "STRING" for i in p)
325+
326+
323327
def is_var(*p):
324328
"""Returns True if ALL the arguments are AST nodes
325329
containing ID

src/arch/z80/backend/common.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from src.api import global_, tmp_labels
1010
from src.api.exception import TempAlreadyFreedError
11+
from src.symbols.symbol_ import Symbol
1112

1213
from . import exception
1314
from .exception import InvalidICError as InvalidIC
@@ -110,7 +111,7 @@ def __init__(self, *args):
110111
if len(args) - 1 != QUADS[args[0]].nargs:
111112
exception.throw_invalid_quad_params(args[0], len(args) - 1, QUADS[args[0]].nargs)
112113

113-
args = tuple([str(x) for x in args]) # Convert it to strings
114+
args = tuple([str(x.t if isinstance(x, Symbol) else x) for x in args]) # Convert it to strings
114115

115116
self.quad = args
116117
self.op = args[0]

src/arch/z80/translator.py

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def visit_LABEL(self, node):
9494
self.ic_label(node.mangled)
9595

9696
def visit_CONST(self, node):
97-
yield node.t
97+
yield node.symbol
9898

9999
def visit_VAR(self, node):
100100
__DEBUG__(
@@ -977,7 +977,7 @@ def loop_cont_label(self, loop_type):
977977
raise InvalidLoopError(loop_type)
978978

979979
@classmethod
980-
def default_value(cls, type_, expr): # TODO: This function must be moved to api.xx
980+
def default_value(cls, type_: symbols.TYPE, expr) -> list[str]: # TODO: This function must be moved to api.xx
981981
"""Returns a list of bytes (as hexadecimal 2 char string)"""
982982
assert isinstance(type_, symbols.TYPE)
983983
assert type_.is_basic
@@ -986,44 +986,37 @@ def default_value(cls, type_, expr): # TODO: This function must be moved to api
986986
if expr.token in ("CONSTEXPR", "CONST"): # a constant expression like @label + 1
987987
if type_ in (cls.TYPE(TYPE.float), cls.TYPE(TYPE.string)):
988988
error(expr.lineno, f"Can't convert non-numeric value to {type_.name} at compile time")
989-
return ["<ERROR>"]
989+
return ["<ERROR>"] # dummy placeholder so the compilation continues
990990

991991
val = Translator.traverse_const(expr)
992992
if type_.size == 1: # U/byte
993993
if expr.type_.size != 1:
994-
return ["#({0}) & 0xFF".format(val)]
994+
return [f"#({val}) & 0xFF"]
995995
else:
996-
return ["#{0}".format(val)]
996+
return [f"#{val}"]
997997

998998
if type_.size == 2: # U/integer
999999
if expr.type_.size != 2:
1000-
return ["##({0}) & 0xFFFF".format(val)]
1000+
return [f"##({val}) & 0xFFFF"]
10011001
else:
1002-
return ["##{0}".format(val)]
1002+
return [f"##{val}"]
10031003

10041004
if type_ == cls.TYPE(TYPE.fixed):
1005-
return ["0000", "##({0}) & 0xFFFF".format(val)]
1005+
return ["0000", f"##({val}) & 0xFFFF"]
10061006

10071007
# U/Long
1008-
return ["##({0}) & 0xFFFF".format(val), "##(({0}) >> 16) & 0xFFFF".format(val)]
1008+
return [f"##({val}) & 0xFFFF", f"##(({val}) >> 16) & 0xFFFF"]
10091009

10101010
if type_ == cls.TYPE(TYPE.float):
10111011
C, DE, HL = _float(expr.value)
10121012
C = C[:-1] # Remove 'h' suffix
1013-
if len(C) > 2:
1014-
C = C[-2:]
1013+
C = C[-2:]
10151014

10161015
DE = DE[:-1] # Remove 'h' suffix
1017-
if len(DE) > 4:
1018-
DE = DE[-4:]
1019-
elif len(DE) < 3:
1020-
DE = "00" + DE
1016+
DE = ("00" + DE)[-4:]
10211017

10221018
HL = HL[:-1] # Remove 'h' suffix
1023-
if len(HL) > 4:
1024-
HL = HL[-4:]
1025-
elif len(HL) < 3:
1026-
HL = "00" + HL
1019+
HL = ("00" + HL)[-4:]
10271020

10281021
return [C, DE[-2:], DE[:-2], HL[-2:], HL[:-2]]
10291022

@@ -1032,8 +1025,8 @@ def default_value(cls, type_, expr): # TODO: This function must be moved to api
10321025
else:
10331026
value = int(expr.value)
10341027

1035-
result = [value, value >> 8, value >> 16, value >> 24]
1036-
result = ["%02X" % (v & 0xFF) for v in result]
1028+
values = [value, value >> 8, value >> 16, value >> 24]
1029+
result = ["%02X" % (v & 0xFF) for v in values]
10371030
return result[: type_.size]
10381031

10391032
@staticmethod
@@ -1459,7 +1452,10 @@ def visit_FUNCTION(self, node):
14591452
if node.convention == CONVENTION.stdcall:
14601453
for local_var in node.local_symbol_table.values():
14611454
scope = local_var.scope
1462-
if local_var.type_ == self.TYPE(TYPE.string): # Only if it's string we free it
1455+
if local_var.type_ == self.TYPE(TYPE.string):
1456+
if local_var.class_ == CLASS.const:
1457+
continue
1458+
# Only if it's string we free it
14631459
if local_var.class_ != CLASS.array: # Ok just free it
14641460
if scope == SCOPE.local or (scope == SCOPE.parameter and not local_var.byref):
14651461
if not preserve_hl:
@@ -1469,8 +1465,6 @@ def visit_FUNCTION(self, node):
14691465
offset = -local_var.offset if scope == SCOPE.local else local_var.offset
14701466
self.ic_fpload(TYPE.string, local_var.t, offset)
14711467
self.runtime_call(RuntimeLabel.MEM_FREE, 0)
1472-
elif local_var.class_ == CLASS.const:
1473-
continue
14741468
else: # This is an array of strings, we must free it unless it's a by_ref array
14751469
if scope == SCOPE.local or (scope == SCOPE.parameter and not local_var.byref):
14761470
if not preserve_hl:

src/symbols/id_/ref/constref.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class ConstRef(SymbolRef):
99

1010
def __init__(self, parent: SymbolID, default_value: Symbol):
1111
super().__init__(parent)
12-
assert default_value.token in ("CONSTEXPR", "NUMBER", "CONST")
12+
assert default_value.token in ("CONSTEXPR", "NUMBER", "CONST", "STRING")
1313
self._value = default_value
1414

1515
@property
@@ -26,7 +26,11 @@ def t(self) -> str:
2626

2727
@property
2828
def value(self):
29-
if self._value.token in ("NUMBER", "CONST"):
29+
if self._value.token in ("NUMBER", "CONST", "STRING"):
3030
return self._value.value
3131

3232
return self.t
33+
34+
@property
35+
def symbol(self) -> Symbol:
36+
return self._value

src/zxbc/zxbparser.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
is_number,
3939
is_numeric,
4040
is_static,
41+
is_static_str,
4142
is_string,
4243
is_unsigned,
4344
)
@@ -365,8 +366,8 @@ def make_call(id_: str, lineno: int, args: sym.ARGLIST):
365366
A "call" is just an ID followed by a list of arguments.
366367
E.g. a(4)
367368
- a(4) can be a function call if 'a' is a function
368-
- a(4) can be a string slice if a is a string variable: a$(4)
369-
- a(4) can be an access to an array if a is an array
369+
- a(4) can be a string slice if 'a' is a string variable: a$(4)
370+
- a(4) can be an access to an array if 'a' is an array
370371
371372
This function will inspect the id_. If it is undeclared then
372373
id_ will be taken as a forwarded function.
@@ -705,8 +706,11 @@ def p_var_decl_ini(p):
705706
else:
706707
# keyword == "CONST"
707708
if defval is None:
708-
errmsg.syntax_error_not_constant(p.lineno(4))
709-
return
709+
if not is_static_str(value):
710+
errmsg.syntax_error_not_constant(p.lineno(4))
711+
return
712+
else:
713+
defval = value
710714

711715
SYMBOL_TABLE.declare_const(idlist[0].name, idlist[0].lineno, typedef, default_value=defval)
712716

0 commit comments

Comments
 (0)