Skip to content
This repository has been archived by the owner on May 21, 2024. It is now read-only.

Commit

Permalink
Merge pull request boriel-basic#664 from boriel/bugfix/Cannot_declare…
Browse files Browse the repository at this point in the history
…_CONST_strings

fix: allow CONST strings
  • Loading branch information
boriel committed Aug 27, 2023
2 parents db6d5ac + 5567233 commit b0e1e50
Show file tree
Hide file tree
Showing 7 changed files with 815 additions and 31 deletions.
4 changes: 4 additions & 0 deletions src/api/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,10 @@ def is_number(*p):
return all(i.token in ("NUMBER", "CONST") for i in p)


def is_static_str(*p):
return all(i.token == "STRING" for i in p)


def is_var(*p):
"""Returns True if ALL the arguments are AST nodes
containing ID
Expand Down
3 changes: 2 additions & 1 deletion src/arch/z80/backend/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from src.api import global_, tmp_labels
from src.api.exception import TempAlreadyFreedError
from src.symbols.symbol_ import Symbol

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

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

self.quad = args
self.op = args[0]
Expand Down
42 changes: 18 additions & 24 deletions src/arch/z80/translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def visit_LABEL(self, node):
self.ic_label(node.mangled)

def visit_CONST(self, node):
yield node.t
yield node.symbol

def visit_VAR(self, node):
__DEBUG__(
Expand Down Expand Up @@ -977,7 +977,7 @@ def loop_cont_label(self, loop_type):
raise InvalidLoopError(loop_type)

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

val = Translator.traverse_const(expr)
if type_.size == 1: # U/byte
if expr.type_.size != 1:
return ["#({0}) & 0xFF".format(val)]
return [f"#({val}) & 0xFF"]
else:
return ["#{0}".format(val)]
return [f"#{val}"]

if type_.size == 2: # U/integer
if expr.type_.size != 2:
return ["##({0}) & 0xFFFF".format(val)]
return [f"##({val}) & 0xFFFF"]
else:
return ["##{0}".format(val)]
return [f"##{val}"]

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

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

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

DE = DE[:-1] # Remove 'h' suffix
if len(DE) > 4:
DE = DE[-4:]
elif len(DE) < 3:
DE = "00" + DE
DE = ("00" + DE)[-4:]

HL = HL[:-1] # Remove 'h' suffix
if len(HL) > 4:
HL = HL[-4:]
elif len(HL) < 3:
HL = "00" + HL
HL = ("00" + HL)[-4:]

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

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

result = [value, value >> 8, value >> 16, value >> 24]
result = ["%02X" % (v & 0xFF) for v in result]
values = [value, value >> 8, value >> 16, value >> 24]
result = ["%02X" % (v & 0xFF) for v in values]
return result[: type_.size]

@staticmethod
Expand Down Expand Up @@ -1459,7 +1452,10 @@ def visit_FUNCTION(self, node):
if node.convention == CONVENTION.stdcall:
for local_var in node.local_symbol_table.values():
scope = local_var.scope
if local_var.type_ == self.TYPE(TYPE.string): # Only if it's string we free it
if local_var.type_ == self.TYPE(TYPE.string):
if local_var.class_ == CLASS.const:
continue
# Only if it's string we free it
if local_var.class_ != CLASS.array: # Ok just free it
if scope == SCOPE.local or (scope == SCOPE.parameter and not local_var.byref):
if not preserve_hl:
Expand All @@ -1469,8 +1465,6 @@ def visit_FUNCTION(self, node):
offset = -local_var.offset if scope == SCOPE.local else local_var.offset
self.ic_fpload(TYPE.string, local_var.t, offset)
self.runtime_call(RuntimeLabel.MEM_FREE, 0)
elif local_var.class_ == CLASS.const:
continue
else: # This is an array of strings, we must free it unless it's a by_ref array
if scope == SCOPE.local or (scope == SCOPE.parameter and not local_var.byref):
if not preserve_hl:
Expand Down
8 changes: 6 additions & 2 deletions src/symbols/id_/ref/constref.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class ConstRef(SymbolRef):

def __init__(self, parent: SymbolID, default_value: Symbol):
super().__init__(parent)
assert default_value.token in ("CONSTEXPR", "NUMBER", "CONST")
assert default_value.token in ("CONSTEXPR", "NUMBER", "CONST", "STRING")
self._value = default_value

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

@property
def value(self):
if self._value.token in ("NUMBER", "CONST"):
if self._value.token in ("NUMBER", "CONST", "STRING"):
return self._value.value

return self.t

@property
def symbol(self) -> Symbol:
return self._value
12 changes: 8 additions & 4 deletions src/zxbc/zxbparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
is_number,
is_numeric,
is_static,
is_static_str,
is_string,
is_unsigned,
)
Expand Down Expand Up @@ -365,8 +366,8 @@ def make_call(id_: str, lineno: int, args: sym.ARGLIST):
A "call" is just an ID followed by a list of arguments.
E.g. a(4)
- a(4) can be a function call if 'a' is a function
- a(4) can be a string slice if a is a string variable: a$(4)
- a(4) can be an access to an array if a is an array
- a(4) can be a string slice if 'a' is a string variable: a$(4)
- a(4) can be an access to an array if 'a' is an array
This function will inspect the id_. If it is undeclared then
id_ will be taken as a forwarded function.
Expand Down Expand Up @@ -705,8 +706,11 @@ def p_var_decl_ini(p):
else:
# keyword == "CONST"
if defval is None:
errmsg.syntax_error_not_constant(p.lineno(4))
return
if not is_static_str(value):
errmsg.syntax_error_not_constant(p.lineno(4))
return
else:
defval = value

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

Expand Down

0 comments on commit b0e1e50

Please sign in to comment.