Implement data_types.py and STR, VAL() functions
authorNick Downing <nick@ndcode.org>
Mon, 16 May 2022 13:18:36 +0000 (23:18 +1000)
committerNick Downing <nick@ndcode.org>
Mon, 16 May 2022 13:24:52 +0000 (23:24 +1000)
applesoft_basic.t
applesoft_basic.y
data_types.py [new file with mode: 0644]
test.bas

index 1d15ca0..555df61 100644 (file)
@@ -18,8 +18,8 @@
 
 %{
   import apple_io
+  import data_types
   import element
-  import math
 %}
 
 %%
@@ -93,6 +93,8 @@ class NodeExpressionIntLiteral: NodeExpression;
 class NodeExpressionFloatLiteral: NodeExpression;
 class NodeExpressionStrLiteral: NodeExpression;
 class NodeExpressionVariable: NodeExpression;
+class NodeExpressionStrDollar: NodeExpression;
+class NodeExpressionVal: NodeExpression;
 
 %%
 
@@ -225,77 +227,20 @@ def execute(self, context):
       raise Exception(
         f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
       )
-  elif name[-1] == '%':
-    if not isinstance(value, float):
-      raise Exception(
-        f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
-      )
-    value = ((int(math.floor(value)) + 0x8000) & 0xffff) - 0x8000
   else:
     if not isinstance(value, float):
       raise Exception(
         f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
       )
+    if name[-1] == '%':
+      value = data_types.cint(value)
   context.variables[name] = value
 @method(NodeStatementPrint)
 def execute(self, context):
   for i in self.children:
     value = i.evaluate(context)
     if isinstance(value, float):
-      sign = ''
-      if value < 0.:
-        sign = '-'
-        value = -value
-
-      if value == 0.:
-        value = '0.'
-        exponent = ''
-      else:
-        exponent = int(math.floor(math.log10(value)))
-        if exponent < -99:
-          value = '0.'
-          exponent = ''
-        else:
-          if exponent >= 100:
-            raise Exception(
-              f'?OVERFLOW ERROR IN {context.line_number():d}'
-            )
-          value *= 10. ** (8 - exponent)
-
-          int_value = int(round(value))
-          assert int_value >= 100000000
-          if int_value >= 1000000000:
-            value /= 10.
-            exponent += 1
-            if exponent >= 100:
-              raise Exception(
-                f'?OVERFLOW ERROR IN {context.line_number():d}'
-              )
-            int_value = int(round(value))
-            assert int_value >= 100000000 and int_value < 1000000000
-
-          value = str(int_value)
-          if exponent >= -2 and exponent < 9:
-            exponent += 1
-            if exponent < 0:
-              value = '0' * -exponent + value
-              exponent = 0
-            value = value[:exponent] + '.' + value[exponent:]
-            exponent = ''
-          else:
-            value = value[:1] + '.' + value[1:]
-            exponent_sign = '+'
-            if exponent < 0:
-              exponent_sign = '-'
-              exponent = -exponent
-            exponent = 'E' + exponent_sign + ('0' + str(exponent))[-2:]
-
-      i = len(value) - 1
-      while value[i] == '0':
-        i -= 1
-      if value[i] != '.':
-        i += 1
-      value = sign + value[:i] + exponent
+      value = data_types.str_dollar(value)
     apple_io._print(value)
   if not self.semicolon:
     apple_io.cr() # really writes \r\n
@@ -416,16 +361,6 @@ def execute(self, context):
         f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
       )
     value = item.text[0]
-  elif name[-1] == '%':
-    if isinstance(item, NodeTextIntLiteral):
-      value = item.int_value
-    elif isinstance(item, NodeFloatLiteral):
-      value = int(math.floor(item.float_value))
-    else:
-      raise Exception(
-        f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
-      )
-    value = ((value + 0x8000) & 0xffff) - 0x8000
   else:
     if isinstance(item, NodeTextIntLiteral):
       value = float(item.int_value)
@@ -435,6 +370,8 @@ def execute(self, context):
       raise Exception(
         f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
       )
+    if name[-1] == '%':
+      value = data_types.cint(value)
   context.variables[name] = value
 @method(NodeStatementRestore)
 def execute(self, context):
@@ -467,7 +404,7 @@ def execute(self, context):
     raise Exception(
       f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
     )
-  apple_io.htab(int(math.floor(value)))
+  apple_io.htab(data_types.cint(value))
 @method(NodeStatementVTab)
 def execute(self, context):
   value = self.children[0].evaluate(context)
@@ -475,7 +412,7 @@ def execute(self, context):
     raise Exception(
       f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
     )
-  apple_io.vtab(int(math.floor(value)))
+  apple_io.vtab(data_types.cint(value))
 @method(NodeStatementGet)
 def execute(self, context):
   name = self.children[0].str_value
@@ -495,9 +432,9 @@ def execute(self, context):
   name = self.children[-1].str_value
   value = apple_io.input()
   if name[-1] != '$':
-    value = float(value)
+    value = data_types.val(value)
     if name[-1] == '%':
-      value = ((int(math.floor(value)) + 0x8000) & 0xffff) - 0x8000
+      value = data_types.cint(value)
   context.variables[name] = value
 del execute
 
@@ -677,4 +614,20 @@ def evaluate(self, context):
   else:
     value = context.variables.get(name, 0.)
   return value
+@method(NodeExpressionStrDollar)
+def evaluate(self, context):
+  value = self.children[0].evaluate(context)
+  if not isinstance(value, float):
+    raise Exception(
+      f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
+    )
+  return data_types.str_dollar(value)
+@method(NodeExpressionVal)
+def evaluate(self, context):
+  value = self.children[0].evaluate(context)
+  if not isinstance(value, str):
+    raise Exception(
+      f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
+    )
+  return data_types.val(value)
 del evaluate
index 4f00db7..5e04f93 100644 (file)
@@ -225,6 +225,8 @@ expression
   | %space (?E{t_def.NodeExpressionFloatLiteral}FLOAT_LITERAL)
   | %space (?E{t_def.NodeExpressionStrLiteral}STR_LITERAL)
   | %space (?E{t_def.NodeExpressionVariable}VARIABLE)
+  | %space (?E{t_def.NodeExpressionStrDollar}KEYWORD_STR_DOLLAR '(' expression ')')
+  | %space (?E{t_def.NodeExpressionVal}KEYWORD_VAL '(' expression ')')
   ;
 %%
 
diff --git a/data_types.py b/data_types.py
new file mode 100644 (file)
index 0000000..09f637a
--- /dev/null
@@ -0,0 +1,67 @@
+import math
+
+def cint(value):
+  assert isinstance(value, float)
+  return ((int(math.floor(value)) + 0x8000) & 0xffff) - 0x8000
+
+def str_dollar(value):
+  assert isinstance(value, float)
+  sign = ''
+  if value < 0.:
+    sign = '-'
+    value = -value
+
+  if value == 0.:
+    value = '0.'
+    exponent = ''
+  else:
+    exponent = int(math.floor(math.log10(value)))
+    if exponent < -99:
+      value = '0.'
+      exponent = ''
+    else:
+      if exponent >= 100:
+        raise Exception(
+          f'?OVERFLOW ERROR IN {context.line_number():d}'
+        )
+      value *= 10. ** (8 - exponent)
+
+      int_value = int(round(value))
+      assert int_value >= 100000000
+      if int_value >= 1000000000:
+        value /= 10.
+        exponent += 1
+        if exponent >= 100:
+          raise Exception(
+            f'?OVERFLOW ERROR IN {context.line_number():d}'
+          )
+        int_value = int(round(value))
+        assert int_value >= 100000000 and int_value < 1000000000
+
+      value = str(int_value)
+      if exponent >= -2 and exponent < 9:
+        exponent += 1
+        if exponent < 0:
+          value = '0' * -exponent + value
+          exponent = 0
+        value = value[:exponent] + '.' + value[exponent:]
+        exponent = ''
+      else:
+        value = value[:1] + '.' + value[1:]
+        exponent_sign = '+'
+        if exponent < 0:
+          exponent_sign = '-'
+          exponent = -exponent
+        exponent = 'E' + exponent_sign + ('0' + str(exponent))[-2:]
+
+  i = len(value) - 1
+  while value[i] == '0':
+    i -= 1
+  if value[i] != '.':
+    i += 1
+  return sign + value[:i] + exponent
+
+def val(value):
+  # make this more sophisticated later
+  assert isinstance(value, str)
+  return float(value)
index b1b4762..8c992df 100644 (file)
--- a/test.bas
+++ b/test.bas
@@ -10,7 +10,9 @@
 90 RESTORE 2010
 100 READ K
 110 PRINT "K"K
-120 END
+120 PRINT STR$(3.14159)
+130 PRINT VAL("3.1515926")
+140 END
 1000 I%=I%+1
 1010 RETURN
 2000 DATA 20,30,40.5,50,60