Add apple_io module and HOME, NORMAL, INVERSE, FLASH, HTAB, VTAB statements
authorNick Downing <nick@ndcode.org>
Mon, 16 May 2022 10:08:16 +0000 (20:08 +1000)
committerNick Downing <nick@ndcode.org>
Mon, 16 May 2022 10:08:16 +0000 (20:08 +1000)
apple_io.py [new file with mode: 0755]
applesoft_basic.py
applesoft_basic.t
applesoft_basic.y
test_io.bas [new file with mode: 0644]

diff --git a/apple_io.py b/apple_io.py
new file mode 100755 (executable)
index 0000000..c49b30e
--- /dev/null
@@ -0,0 +1,70 @@
+#!/usr/bin/env python3
+
+import atexit
+import os
+import select
+import sys
+import termios
+import tty
+
+attr = None
+def init():
+  global attr
+  if attr is None and os.isatty(sys.stdin.fileno()):
+    attr = termios.tcgetattr(sys.stdin.fileno())
+    atexit.register(deinit)
+    tty.setraw(sys.stdin)
+def deinit():
+  global attr
+  if attr is not None:
+    termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, attr)
+    attr = None
+    atexit.unregister(deinit)
+
+def read(n):
+  return str(os.read(sys.stdin.fileno(), n), 'ascii')
+
+def write(str):
+  os.write(sys.stdout.fileno(), bytes(str, 'ascii'))
+
+poll_stdin = select.poll()
+poll_stdin.register(sys.stdin.fileno(), select.POLLIN)
+def read_ready():
+  return len(poll_stdin.poll(1)) != 0
+
+def htab(x):
+  write(f'\x1b[{x:d}G')
+
+def vtab(y):
+  write(f'\x1b[{y:d}d')
+
+def clreop():
+  write('\x1b[J')
+
+def home():
+  write('\x1b[H\x1b[2J')
+
+def normal():
+  write('\x1b[0m')
+
+def inverse():
+  write('\x1b[0;7m')
+
+def flash():
+  write('\x1b[0;7;5m')
+
+def tone(freq, dur): # Hz, ms
+  # doesn't seem to work on any linux console on my laptop
+  write(f'\x1b7\x1b[10;{freq:d}]\x1b[11;{dur:d}]\x07\x1b8')
+
+if __name__ == '__main__':
+  init()
+  while True:
+    while not read_ready():
+      pass
+    k = ord(read(1))
+    write(f'k {k:02x}\r\n')
+    if k == 0x1b:
+      break
+  for i in range(12):
+    tone(int(round(220 * 2 ** (i / 12.))), 250)
index 5dbe72f..6662c3d 100755 (executable)
@@ -16,6 +16,7 @@
 # this program; if not, write to the Free Software Foundation, Inc., 51
 # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 
+import apple_io
 import t_def
 import element
 import sys
@@ -26,18 +27,24 @@ import y_tab
 #print('yytext', f'"{lex_yy.yytext:s}"')
 #assert False
 
-print('y_tab.yyparse()')
+#print('y_tab.yyparse()')
 program = y_tab.yyparse(t_def.NodeProgram)
 
-print('element.serialize()')
-element.serialize(program, sys.stdout)
+#print('element.serialize()')
+#element.serialize(program, sys.stdout)
 
-print('program.post_process()')
+#print('program.post_process()')
 program.post_process(program)
 
-print('element.serialize()')
-element.serialize(program, sys.stdout)
+#print('element.serialize()')
+#element.serialize(program, sys.stdout)
 
-print('context.run()')
+#print('apple_io.init()')
+apple_io.init()
+
+#print('context.run()')
 context = t_def.Context(program)
 context.run()
+
+#print('apple_io.deinit()')
+apple_io.deinit()
index dcb0a0f..a09e72e 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 %{
+  import apple_io
   import element
   import math
 %}
@@ -62,6 +63,12 @@ class NodeStatementNext: NodeStatement;
 class NodeStatementRead: NodeStatement;
 class NodeStatementRestore: NodeStatement;
 class NodeStatementData: NodeStatement;
+class NodeStatementHome: NodeStatement;
+class NodeStatementNormal: NodeStatement;
+class NodeStatementInverse: NodeStatement;
+class NodeStatementFlash: NodeStatement;
+class NodeStatementHTab: NodeStatement;
+class NodeStatementVTab: NodeStatement;
 class NodeExpression: Node;
 class NodeExpressionOr: NodeExpression;
 class NodeExpressionAnd: NodeExpression;
@@ -439,6 +446,34 @@ def execute(self, context):
 @method(NodeStatementData)
 def execute(self, context):
   pass
+@method(NodeStatementHome)
+def execute(self, context):
+  apple_io.home()
+@method(NodeStatementNormal)
+def execute(self, context):
+  apple_io.normal()
+@method(NodeStatementInverse)
+def execute(self, context):
+  apple_io.inverse()
+@method(NodeStatementFlash)
+def execute(self, context):
+  apple_io.flash()
+@method(NodeStatementHTab)
+def execute(self, context):
+  value = self.children[0].evaluate(context)
+  if not isinstance(value, float):
+    raise Exception(
+      f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
+    )
+  apple_io.htab(int(math.floor(value)))
+@method(NodeStatementVTab)
+def execute(self, context):
+  value = self.children[0].evaluate(context)
+  if not isinstance(value, float):
+    raise Exception(
+      f'?TYPE MISMATCH ERROR IN {context.line_number():d}'
+    )
+  apple_io.vtab(int(math.floor(value)))
 del execute
 
 @method(NodeExpression)
index c052194..9e764da 100644 (file)
@@ -170,6 +170,12 @@ statement_opt
   | %space (?E{t_def.NodeStatementRead}KEYWORD_READ VARIABLE)
   | %space (?E{t_def.NodeStatementRestore}KEYWORD_RESTORE INT_LITERAL)
   | %space (?E{t_def.NodeStatementData}KEYWORD_DATA data_item_list)
+  | %space (?E{t_def.NodeStatementHome}KEYWORD_HOME)
+  | %space (?E{t_def.NodeStatementNormal}KEYWORD_NORMAL)
+  | %space (?E{t_def.NodeStatementInverse}KEYWORD_INVERSE)
+  | %space (?E{t_def.NodeStatementFlash}KEYWORD_FLASH)
+  | %space (?E{t_def.NodeStatementHTab}KEYWORD_HTAB expression)
+  | %space (?E{t_def.NodeStatementVTab}KEYWORD_VTAB expression)
   ;
 
 print_expression_list0
diff --git a/test_io.bas b/test_io.bas
new file mode 100644 (file)
index 0000000..2087f5e
--- /dev/null
@@ -0,0 +1,7 @@
+10 HOME
+20 HTAB 10
+30 PRINT "MY PROGRAM"
+40 VTAB 5
+50 FLASH
+60 PRINT "GOODBYE"
+70 NORMAL