--- /dev/null
+__pycache__
+/element.py
+/lex_yy.py
+/t_def.py
+/y_tab.py
--- /dev/null
+all: element.py lex_yy.py t_def.py y_tab.py
+
+element.py:
+ pitree --install-element
+
+lex_yy.py: applesoft_basic.l
+ pilex --element --groups --python $<
+
+t_def.py: applesoft_basic.t
+ pitree --python $<
+
+y_tab.py: applesoft_basic.y
+ piyacc --element --python $<
+
+clean:
+ rm -f element.py lex_yy.py t_def.py y_tab.py
--- /dev/null
+/*
+ * Copyright (C) 2018 Nick Downing <nick@ndcode.org>
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+%{
+ import element
+ import t_def
+ import y_tab
+%}
+
+%option nodefault
+
+%%
+
+[ ]
+X\ *P\ *L\ *O\ *T/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_XPLOT
+}
+X\ *D\ *R\ *A\ *W/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_XDRAW
+}
+W\ *A\ *I\ *T/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_WAIT
+}
+V\ *T\ *A\ *B/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_VTAB
+}
+V\ *L\ *I\ *N/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_VLIN
+}
+V\ *A\ *L/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_VAL
+}
+U\ *S\ *R/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_USR
+}
+T\ *R\ *A\ *C\ *E/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_TRACE
+}
+T\ *O/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_TO
+}
+T\ *H\ *E\ *N/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_THEN
+}
+T\ *E\ *X\ *T/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_TEXT
+}
+T\ *A\ *N/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_TAN
+}
+T\ *A\ *B\ *\( {
+ return y_tab.KEYWORD_TAB_LPAREN
+}
+S\ *T\ *R\ *\$ {
+ return y_tab.KEYWORD_STR_DOLLAR
+}
+S\ *T\ *O\ *R\ *E/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_STORE
+}
+S\ *T\ *O\ *P/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_STOP
+}
+S\ *T\ *E\ *P/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_STEP
+}
+S\ *Q\ *R/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_SQR
+}
+S\ *P\ *E\ *E\ *D\ *= {
+ return y_tab.KEYWORD_SPEED_EQUAL
+}
+S\ *P\ *C\ *\( {
+ return y_tab.KEYWORD_SPC_LPAREN
+}
+S\ *I\ *N/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_SIN
+}
+S\ *H\ *L\ *O\ *A\ *D/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_SHLOAD
+}
+S\ *G\ *N/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_SGN
+}
+S\ *C\ *R\ *N\ *\( {
+ return y_tab.KEYWORD_SCRN_LPAREN
+}
+S\ *C\ *A\ *L\ *E\ *= {
+ return y_tab.KEYWORD_SCALE_EQUAL
+}
+S\ *A\ *V\ *E/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_SAVE
+}
+R\ *I\ *G\ *H\ *T\ *\$ {
+ return y_tab.KEYWORD_RIGHT_DOLLAR
+}
+R\ *E\ *T\ *U\ *R\ *N/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_RETURN
+}
+R\ *E\ *S\ *U\ *M\ *E/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_RESUME
+}
+R\ *E\ *S\ *T\ *O\ *R\ *E/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_RESTORE
+}
+R\ *E\ *M/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_REM
+}
+R\ *E\ *C\ *A\ *L\ *L/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_RECALL
+}
+R\ *E\ *A\ *D/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_READ
+}
+P\ *R\ *I\ *N\ *T/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_PRINT
+}
+P\ *R\ *# {
+ return y_tab.KEYWORD_PR_FLOAT_LITERAL
+}
+P\ *O\ *S/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_POS
+}
+P\ *O\ *P/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_POP
+}
+P\ *O\ *K\ *E/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_POKE
+}
+P\ *L\ *O\ *T/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_PLOT
+}
+P\ *E\ *E\ *K/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_PEEK
+}
+P\ *D\ *L/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_PDL
+}
+O\ *R/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_OR
+}
+O\ *N\ *E\ *R\ *R/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_ONERR
+}
+O\ *N/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_ON
+}
+N\ *O\ *T\ *R\ *A\ *C\ *E/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_NOTRACE
+}
+N\ *O\ *T/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_NOT
+}
+N\ *O\ *R\ *M\ *A\ *L/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_NORMAL
+}
+N\ *E\ *X\ *T/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_NEXT
+}
+N\ *E\ *W/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_NEW
+}
+M\ *I\ *D\ *\$ {
+ return y_tab.KEYWORD_MID_DOLLAR
+}
+L\ *O\ *M\ *E\ *M\ *: {
+ return y_tab.KEYWORD_LOMEM_COLON
+}
+L\ *O\ *G/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_LOG
+}
+L\ *O\ *A\ *D/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_LOAD
+}
+L\ *I\ *S\ *T/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_LIST
+}
+L\ *E\ *T/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_LET
+}
+L\ *E\ *N/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_LEN
+}
+L\ *E\ *F\ *T\ *\$ {
+ return y_tab.KEYWORD_LEFT_DOLLAR
+}
+I\ *N\ *V\ *E\ *R\ *S\ *E/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_INVERSE
+}
+I\ *N\ *T/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_INT
+}
+I\ *N\ *P\ *U\ *T/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_INPUT
+}
+I\ *N\ *# {
+ return y_tab.KEYWORD_IN_FLOAT_LITERAL
+}
+I\ *F/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_IF
+}
+H\ *T\ *A\ *B/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_HTAB
+}
+H\ *P\ *L\ *O\ *T/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_HPLOT
+}
+H\ *O\ *M\ *E/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_HOME
+}
+H\ *L\ *I\ *N/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_HLIN
+}
+H\ *I\ *M\ *E\ *M\ *: {
+ return y_tab.KEYWORD_HIMEM_COLON
+}
+H\ *G\ *R\ *2/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_HGR2
+}
+H\ *G\ *R/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_HGR
+}
+H\ *C\ *O\ *L\ *O\ *R\ *= {
+ return y_tab.KEYWORD_HCOLOR_EQUAL
+}
+G\ *R/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_GR
+}
+G\ *O\ *T\ *O/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_GOTO
+}
+G\ *O/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_GO
+}
+G\ *E\ *T/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_GET
+}
+F\ *R\ *E/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_FRE
+}
+F\ *O\ *R/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_FOR
+}
+F\ *N/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_FN
+}
+F\ *L\ *A\ *S\ *H/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_FLASH
+}
+E\ *X\ *P/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_EXP
+}
+E\ *N\ *D/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_END
+}
+D\ *R\ *A\ *W/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_DRAW
+}
+D\ *I\ *M/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_DIM
+}
+D\ *E\ *L/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_DEL
+}
+D\ *E\ *F/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_DEF
+}
+D\ *A\ *T\ *A/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_DATA
+}
+C\ *O\ *S/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_COS
+}
+C\ *O\ *N\ *T/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_CONT
+}
+C\ *O\ *L\ *O\ *R\ *= {
+ return y_tab.KEYWORD_COLOR_EQUAL
+}
+C\ *L\ *E\ *A\ *R/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_CLEAR
+}
+C\ *H\ *R\ *\$ {
+ return y_tab.KEYWORD_CHR_DOLLAR
+}
+C\ *A\ *L\ *L/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_CALL
+}
+A\ *T\ *N/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_ATN
+}
+A\ *T/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_AT
+}
+A\ *S\ *C/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_ASC
+}
+A\ *N\ *D/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_AND
+}
+A\ *B\ *S/(\ *[A-Z0-9])*(\ *[$%])? {
+ return y_tab.KEYWORD_ABS
+}
+(?E{t_def.NodeTextIntLiteral}(?E{t_def.NodeText.Char}[0-9])(\ *(?E{t_def.NodeText.Char}[0-9]))*) {
+ return y_tab.INT_LITERAL
+}
+(?E{t_def.NodeTextVariable}(?E{t_def.NodeText.Char}[A-Z])(\ *(?E{t_def.NodeText.Char}[A-Z0-9])(\ *[A-Z0-9])*)?(\ *(?E{t_def.NodeText.Char}[$%]))?) {
+ return y_tab.VARIABLE
+}
+(?E{t_def.NodeTextIntLiteral}(?E{t_def.NodeText.Char}[0-9])(\ *(?E{t_def.NodeText.Char}[0-9]))*) {
+ return y_tab.INT_LITERAL
+}
+(?E{t_def.NodeFloatLiteral}((?E{t_def.NodeFloatLiteral.NodeTextInteger}(?E{t_def.NodeText.Char}[0-9])(\ *(?E{t_def.NodeText.Char}[0-9]))*)|(?E{t_def.NodeFloatLiteral.NodeTextInteger}((?E{t_def.NodeText.Char}[0-9])\ *)*)(?E{t_def.NodeFloatLiteral.NodeTextFraction}\.(\ *(?E{t_def.NodeText.Char}[0-9]))*))(?E{t_def.NodeFloatLiteral.Exponent}\ *E(?E{t_def.NodeFloatLiteral.NodeTextSign}(\ *(?E{t_def.NodeText.Char}[+-]))?)(?E{t_def.NodeFloatLiteral.NodeTextInteger}(\ *(?E{t_def.NodeText.Char}[0-9]))*))?) {
+ return y_tab.FLOAT_LITERAL
+}
+\"(?E{t_def.NodeStrLiteral}[^"\n]*)\" {
+ return y_tab.STR_LITERAL
+}
+\>\ *=|=\ *\> {
+ return y_tab.OPERATOR_GE
+}
+\<\ *=|=\ *\< {
+ return y_tab.OPERATOR_LE
+}
+\<\ *\>|\>\ *\< {
+ return y_tab.OPERATOR_NE
+}
+. {
+ return ord(yytext[0])
+}
+\n {
+ return ord('\n')
+}
--- /dev/null
+#!/usr/bin/env python3
+
+# Copyright (C) 2018 Nick Downing <nick@ndcode.org>
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+import t_def
+import element
+import sys
+import y_tab
+
+print('y_tab.yyparse()')
+program = y_tab.yyparse(t_def.NodeProgram)
+
+print('program.post_process()')
+program.post_process(program)
+
+print('element.serialize()')
+element.serialize(program, sys.stdout)
+
+print('context.execute()')
+context = t_def.Context(program)
+context.execute()
--- /dev/null
+/*
+ * Copyright (C) 2019 Nick Downing <nick@ndcode.org>
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+%{
+ import element
+ import math
+%}
+
+%%
+
+/* generic */
+class Node;
+class NodeText: Node {
+ class Char;
+ str str_value = '';
+};
+
+/* lexical tokens */
+class NodeTextIntLiteral: NodeText {
+ int int_value = 0;
+};
+class NodeFloatLiteral: Node {
+ class NodeTextSign: NodeText;
+ class NodeTextInteger: NodeText;
+ class NodeTextFraction: NodeText;
+ class NodeExponent: Node;
+ float float_value = 0.;
+};
+class NodeStrLiteral: Node;
+class NodeTextVariable: NodeText;
+
+/* grammar productions */
+class NodeProgram: Node;
+class NodeLine: Node;
+class NodeStatement: Node;
+class NodeStatementLet: NodeStatement;
+class NodeStatementPrint: NodeStatement {
+ bool semicolon;
+};
+class NodeStatementGoto: NodeStatement;
+class NodeExpression: Node;
+class NodeExpressionOr: NodeExpression;
+class NodeExpressionAnd: NodeExpression;
+class NodeExpressionLT: NodeExpression;
+class NodeExpressionEqual: NodeExpression;
+class NodeExpressionGT: NodeExpression;
+class NodeExpressionGE: NodeExpression;
+class NodeExpressionLE: NodeExpression;
+class NodeExpressionNE: NodeExpression;
+class NodeExpressionAdd: NodeExpression;
+class NodeExpressionSubtract: NodeExpression;
+class NodeExpressionMultiply: NodeExpression;
+class NodeExpressionDivide: NodeExpression;
+class NodeExpressionPower: NodeExpression;
+class NodeExpressionSign: NodeExpression {
+ int sign;
+};
+class NodeExpressionNot: NodeExpression;
+class NodeExpressionIntLiteral: NodeExpression;
+class NodeExpressionFloatLiteral: NodeExpression;
+class NodeExpressionStrLiteral: NodeExpression;
+class NodeExpressionVariable: NodeExpression;
+
+%%
+
+# Copyright (C) 2018 Nick Downing <nick@ndcode.org>
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+class Context:
+ def __init__(self, program = None, variables = None, i = 0, j = 1):
+ self.program = program if program is not None else NodeProgram()
+ self.variables = variables if variables is not None else {}
+ self.i = i
+ self.j = j
+
+ def line_number(self):
+ assert self.i < len(self.program.children)
+ return self.program.children[self.i].children[0].int_value
+
+ def execute(self):
+ while self.i < len(self.program.children):
+ line = self.program.children[self.i]
+ if self.j < len(line.children):
+ statement = line.children[self.j]
+ self.j += 1
+ statement.execute(self)
+ else:
+ self.i += 1
+ self.j = 1
+
+def factory(tag, *args, **kwargs):
+ return tag_to_class[tag](*args, **kwargs)
+
+@method(Node)
+def post_process(self, program):
+ for i in self.children:
+ i.post_process(program)
+@method(NodeText)
+def post_process(self, program):
+ self.str_value = ''.join([i.text[0] for i in self.children])
+@method(NodeTextIntLiteral)
+def post_process(self, program):
+ NodeText.post_process(self, program)
+ self.int_value = int(self.str_value)
+del post_process
+@method(NodeFloatLiteral)
+def post_process(self, program):
+ Node.post_process(self, program)
+ exponent = 0
+ if len(self.children) >= 4:
+ exponent = int(self.children[3].str_value)
+ if self.children[2].str_value == '-':
+ exponent = -exponent
+ value = (
+ int(self.children[0].str_value + self.children[1].str_value) *
+ 10. ** (exponent - len(self.children[1].str_value))
+ )
+ self.float_value = value
+del post_process
+
+@method(NodeStatement)
+def execute(self, context):
+ raise NotImplementedError()
+@method(NodeStatementLet)
+def execute(self, context):
+ name = self.children[0].str_value
+ value = self.children[1].evaluate(context)
+ if name[-1] == '$':
+ if not isinstance(value, str):
+ 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}')
+ 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 >= .01 and value < 999999999.2:
+ if value >= 100000000.:
+ value = f'{value:.0f}.'
+ elif value >= 10000000.:
+ value = f'{value:.1f}'
+ elif value >= 1000000.:
+ value = f'{value:.2f}'
+ elif value >= 100000.:
+ value = f'{value:.3f}'
+ elif value >= 10000.:
+ value = f'{value:.4f}'
+ elif value >= 1000.:
+ value = f'{value:.5f}'
+ elif value >= 100.:
+ value = f'{value:.6f}'
+ elif value >= 10.:
+ value = f'{value:.7f}'
+ elif value >= 1.:
+ value = f'{value:.8f}'
+ elif value >= .1:
+ value = f'{value:.9f}'
+ else:
+ value = f'{value:.10f}'
+ exponent = ''
+ else:
+ value = f'{value:10.8e}'
+ assert value[-4] == 'e'
+ exponent = 'E' + value[-3:]
+ value = value[:-4]
+ while value[-1] == '0':
+ value = value[:-1]
+ if value[-1] == '.':
+ value = value[:-1]
+ value = sign + value + exponent
+ assert isinstance(value, str)
+ print(value, end = '')
+ if not self.semicolon:
+ print()
+@method(NodeStatementGoto)
+def execute(self, context):
+ target = self.children[0].int_value
+ for i in range(len(context.program.children)):
+ if target == context.program.children[i].children[0].int_value:
+ context.i = i
+ context.j = 1
+ break
+ else:
+ raise Exception(f'?UNDEF\'D STATEMENT ERROR IN {context.line_number():d}')
+del execute
+
+@method(NodeExpression)
+def evaluate(self, context):
+ raise NotImplementedError()
+@method(NodeExpressionOr)
+def evaluate(self, context):
+ return float(
+ self.children[0].evaluate(context) != 0. or
+ self.children[1].evaluate(context) != 0.
+ )
+@method(NodeExpressionAnd)
+def evaluate(self, context):
+ return float(
+ self.children[0].evaluate(context) != 0. and
+ self.children[1].evaluate(context) != 0.
+ )
+@method(NodeExpressionLT)
+def evaluate(self, context):
+ return float(
+ self.children[0].evaluate(context) <
+ self.children[1].evaluate(context)
+ )
+@method(NodeExpressionEqual)
+def evaluate(self, context):
+ return float(
+ self.children[0].evaluate(context) ==
+ self.children[1].evaluate(context)
+ )
+@method(NodeExpressionGT)
+def evaluate(self, context):
+ return float(
+ self.children[0].evaluate(context) >
+ self.children[1].evaluate(context)
+ )
+@method(NodeExpressionGE)
+def evaluate(self, context):
+ return float(
+ self.children[0].evaluate(context) >=
+ self.children[1].evaluate(context)
+ )
+@method(NodeExpressionLE)
+def evaluate(self, context):
+ return float(
+ self.children[0].evaluate(context) <=
+ self.children[1].evaluate(context)
+ )
+@method(NodeExpressionNE)
+def evaluate(self, context):
+ return float(
+ self.children[0].evaluate(context) !=
+ self.children[1].evaluate(context)
+ )
+@method(NodeExpressionAdd)
+def evaluate(self, context):
+ return (
+ self.children[0].evaluate(context) +
+ self.children[1].evaluate(context)
+ )
+@method(NodeExpressionSubtract)
+def evaluate(self, context):
+ return (
+ self.children[0].evaluate(context) -
+ self.children[1].evaluate(context)
+ )
+@method(NodeExpressionMultiply)
+def evaluate(self, context):
+ return (
+ self.children[0].evaluate(context) *
+ self.children[1].evaluate(context)
+ )
+@method(NodeExpressionDivide)
+def evaluate(self, context):
+ return (
+ self.children[0].evaluate(context) /
+ self.children[1].evaluate(context)
+ )
+@method(NodeExpressionPower)
+def evaluate(self, context):
+ return (
+ self.children[0].evaluate(context) **
+ self.children[1].evaluate(context)
+ )
+@method(NodeExpressionSign)
+def evaluate(self, context):
+ return self.sign * self.children[0].evaluate(context)
+@method(NodeExpressionNot)
+def evaluate(self, context):
+ return float(
+ self.children[0].evaluate(context) == 0.
+ )
+@method(NodeExpressionIntLiteral)
+def evaluate(self, context):
+ return float(self.children[0].int_value)
+@method(NodeExpressionFloatLiteral)
+def evaluate(self, context):
+ return self.children[0].float_value
+@method(NodeExpressionStrLiteral)
+def evaluate(self, context):
+ return self.children[0].text[0]
+@method(NodeExpressionVariable)
+def evaluate(self, context):
+ name = self.children[0].str_value
+ if name[-1] == '$':
+ value = context.variables.get(name, '')
+ elif name[-1] == '%':
+ value = float(context.variables.get(name, 0))
+ else:
+ value = context.variables.get(name, 0.)
+ return value
+del evaluate
--- /dev/null
+/*
+ * Copyright (C) 2018 Nick Downing <nick@ndcode.org>
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+%{
+ import t_def
+ import sys
+%}
+
+%locations
+
+%token KEYWORD_ABS
+%token KEYWORD_AND
+%token KEYWORD_ASC
+%token KEYWORD_AT
+%token KEYWORD_ATN
+%token KEYWORD_CALL
+%token KEYWORD_CHR_DOLLAR
+%token KEYWORD_CLEAR
+%token KEYWORD_COLOR_EQUAL
+%token KEYWORD_CONT
+%token KEYWORD_COS
+%token KEYWORD_DATA
+%token KEYWORD_DEF
+%token KEYWORD_DEL
+%token KEYWORD_DIM
+%token KEYWORD_DRAW
+%token KEYWORD_END
+%token KEYWORD_EXP
+%token KEYWORD_FLASH
+%token KEYWORD_FN
+%token KEYWORD_FOR
+%token KEYWORD_FRE
+%token KEYWORD_GET
+%token KEYWORD_GO
+%token KEYWORD_GOTO
+%token KEYWORD_GR
+%token KEYWORD_HCOLOR_EQUAL
+%token KEYWORD_HGR
+%token KEYWORD_HGR2
+%token KEYWORD_HIMEM_COLON
+%token KEYWORD_HLIN
+%token KEYWORD_HOME
+%token KEYWORD_HPLOT
+%token KEYWORD_HTAB
+%token KEYWORD_IF
+%token KEYWORD_IN_FLOAT_LITERAL
+%token KEYWORD_INPUT
+%token KEYWORD_INT
+%token KEYWORD_INVERSE
+%token KEYWORD_LEFT_DOLLAR
+%token KEYWORD_LEN
+%token KEYWORD_LET
+%token KEYWORD_LIST
+%token KEYWORD_LOAD
+%token KEYWORD_LOG
+%token KEYWORD_LOMEM_COLON
+%token KEYWORD_MID_DOLLAR
+%token KEYWORD_NEW
+%token KEYWORD_NEXT
+%token KEYWORD_NORMAL
+%token KEYWORD_NOT
+%token KEYWORD_NOTRACE
+%token KEYWORD_ON
+%token KEYWORD_ONERR
+%token KEYWORD_OR
+%token KEYWORD_PDL
+%token KEYWORD_PEEK
+%token KEYWORD_PLOT
+%token KEYWORD_POKE
+%token KEYWORD_POP
+%token KEYWORD_POS
+%token KEYWORD_PR_FLOAT_LITERAL
+%token KEYWORD_PRINT
+%token KEYWORD_READ
+%token KEYWORD_RECALL
+%token KEYWORD_REM
+%token KEYWORD_RESTORE
+%token KEYWORD_RESUME
+%token KEYWORD_RETURN
+%token KEYWORD_RIGHT_DOLLAR
+%token KEYWORD_SAVE
+%token KEYWORD_SCALE_EQUAL
+%token KEYWORD_SCRN_LPAREN
+%token KEYWORD_SGN
+%token KEYWORD_SHLOAD
+%token KEYWORD_SIN
+%token KEYWORD_SPC_LPAREN
+%token KEYWORD_SPEED_EQUAL
+%token KEYWORD_SQR
+%token KEYWORD_STEP
+%token KEYWORD_STOP
+%token KEYWORD_STORE
+%token KEYWORD_STR_DOLLAR
+%token KEYWORD_TAB_LPAREN
+%token KEYWORD_TAN
+%token KEYWORD_TEXT
+%token KEYWORD_THEN
+%token KEYWORD_TO
+%token KEYWORD_TRACE
+%token KEYWORD_USR
+%token KEYWORD_VAL
+%token KEYWORD_VLIN
+%token KEYWORD_VTAB
+%token KEYWORD_WAIT
+%token KEYWORD_XDRAW
+%token KEYWORD_XPLOT
+%token INT_LITERAL
+%token FLOAT_LITERAL
+%token OPERATOR_GE
+%token OPERATOR_LE
+%token OPERATOR_NE
+%token STR_LITERAL
+%token VARIABLE
+
+%left KEYWORD_OR
+%left KEYWORD_AND
+%left '<' '=' '>' OPERATOR_GE OPERATOR_LE OPERATOR_NE
+%left '+' '-'
+%left '*' '/'
+%left '^'
+%right UNARY KEYWORD_NOT
+
+%%
+
+program
+ :
+ | program %space (?E{t_def.NodeLine}INT_LITERAL statement_list) '\n'
+ | error '\n' {
+ yyerror('Syntax error\n')
+ yyerrok()
+ }
+ ;
+
+statement_list
+ : statement_opt
+ | statement_list ':' statement_opt
+ ;
+
+statement_opt
+ :
+ | %space (?E{t_def.NodeStatementLet}VARIABLE '=' expression)
+ | %space (?E{t_def.NodeStatementLet}KEYWORD_LET VARIABLE '=' expression)
+ | %space (?E{t_def.NodeStatementPrint, semicolon = False}KEYWORD_PRINT print_expression_list0)
+ | %space (?E{t_def.NodeStatementPrint, semicolon = True}KEYWORD_PRINT print_expression_list1)
+ | %space (?E{t_def.NodeStatementGoto}KEYWORD_GOTO INT_LITERAL)
+ ;
+
+print_expression_list0
+ :
+ | print_expression_list0 expression
+ | print_expression_list1 expression
+ ;
+
+print_expression_list1
+ : print_expression_list0 ';'
+ | print_expression_list1 ';'
+ ;
+
+expression
+ : %space (?E{t_def.NodeExpressionOr}expression KEYWORD_OR expression)
+ | %space (?E{t_def.NodeExpressionAnd}expression KEYWORD_AND expression)
+ | %space (?E{t_def.NodeExpressionLT}expression '<' expression)
+ | %space (?E{t_def.NodeExpressionEqual}expression '=' expression)
+ | %space (?E{t_def.NodeExpressionGT}expression '>' expression)
+ | %space (?E{t_def.NodeExpressionGE}expression OPERATOR_GE expression)
+ | %space (?E{t_def.NodeExpressionLE}expression OPERATOR_LE expression)
+ | %space (?E{t_def.NodeExpressionNE}expression OPERATOR_NE expression)
+ | %space (?E{t_def.NodeExpressionAdd}expression '+' expression)
+ | %space (?E{t_def.NodeExpressionSubtract}expression '-' expression)
+ | %space (?E{t_def.NodeExpressionMultiply}expression '*' expression)
+ | %space (?E{t_def.NodeExpressionDivide}expression '/' expression)
+ | %space (?E{t_def.NodeExpressionPower}expression '^' expression)
+ | %space (?E{t_def.NodeExpressionSign, sign = -1}'-' expression) %prec UNARY
+ | %space (?E{t_def.NodeExpressionSign, sign = 1}'+' expression) %prec UNARY
+ | %space (?E{t_def.NodeExpressionNot}KEYWORD_NOT expression)
+ | '(' expression ')'
+ | %space (?E{t_def.NodeExpressionIntLiteral}INT_LITERAL)
+ | %space (?E{t_def.NodeExpressionFloatLiteral}FLOAT_LITERAL)
+ | %space (?E{t_def.NodeExpressionStrLiteral}STR_LITERAL)
+ | %space (?E{t_def.NodeExpressionVariable}VARIABLE)
+ ;
+%%
+
+def yyerror(s):
+ sys.stdout.write('{0:s}\n'.format(s))
+ sys.exit(1)
--- /dev/null
+10 I$="PI":I%=-3.141:I=3.141
+20 PRINT I$" "I%" "I
+30 I%=I%+1
+40 GOTO 20