summaryrefslogtreecommitdiff
path: root/ext/ply/example/BASIC
diff options
context:
space:
mode:
Diffstat (limited to 'ext/ply/example/BASIC')
-rw-r--r--ext/ply/example/BASIC/basic.py9
-rw-r--r--ext/ply/example/BASIC/basiclex.py16
-rw-r--r--ext/ply/example/BASIC/basiclog.py79
-rw-r--r--ext/ply/example/BASIC/basinterp.py125
-rw-r--r--ext/ply/example/BASIC/basparse.py26
5 files changed, 169 insertions, 86 deletions
diff --git a/ext/ply/example/BASIC/basic.py b/ext/ply/example/BASIC/basic.py
index 3a07acdbf..b14483d2d 100644
--- a/ext/ply/example/BASIC/basic.py
+++ b/ext/ply/example/BASIC/basic.py
@@ -4,6 +4,9 @@
import sys
sys.path.insert(0,"../..")
+if sys.version_info[0] >= 3:
+ raw_input = input
+
import basiclex
import basparse
import basinterp
@@ -41,7 +44,7 @@ while 1:
prog = basparse.parse(line)
if not prog: continue
- keys = prog.keys()
+ keys = list(prog)
if keys[0] > 0:
b.add_statements(prog)
else:
@@ -58,8 +61,8 @@ while 1:
elif stat[0] == 'NEW':
b.new()
-
-
+
+
diff --git a/ext/ply/example/BASIC/basiclex.py b/ext/ply/example/BASIC/basiclex.py
index 727383f2b..3d27cdeeb 100644
--- a/ext/ply/example/BASIC/basiclex.py
+++ b/ext/ply/example/BASIC/basiclex.py
@@ -25,7 +25,7 @@ def t_ID(t):
if t.value in keywords:
t.type = t.value
return t
-
+
t_EQUALS = r'='
t_PLUS = r'\+'
t_MINUS = r'-'
@@ -41,7 +41,7 @@ t_GE = r'>='
t_NE = r'<>'
t_COMMA = r'\,'
t_SEMI = r';'
-t_INTEGER = r'\d+'
+t_INTEGER = r'\d+'
t_FLOAT = r'((\d*\.\d+)(E[\+-]?\d+)?|([1-9]\d*E[\+-]?\d+))'
t_STRING = r'\".*?\"'
@@ -51,14 +51,10 @@ def t_NEWLINE(t):
return t
def t_error(t):
- print "Illegal character", t.value[0]
+ print("Illegal character %s" % t.value[0])
t.lexer.skip(1)
-lex.lex()
-
-
-
-
+lex.lex(debug=0)
@@ -66,6 +62,10 @@ lex.lex()
+
+
+
+
diff --git a/ext/ply/example/BASIC/basiclog.py b/ext/ply/example/BASIC/basiclog.py
new file mode 100644
index 000000000..ccfd7b967
--- /dev/null
+++ b/ext/ply/example/BASIC/basiclog.py
@@ -0,0 +1,79 @@
+# An implementation of Dartmouth BASIC (1964)
+#
+
+import sys
+sys.path.insert(0,"../..")
+
+if sys.version_info[0] >= 3:
+ raw_input = input
+
+import logging
+logging.basicConfig(
+ level = logging.INFO,
+ filename = "parselog.txt",
+ filemode = "w"
+)
+log = logging.getLogger()
+
+import basiclex
+import basparse
+import basinterp
+
+# If a filename has been specified, we try to run it.
+# If a runtime error occurs, we bail out and enter
+# interactive mode below
+if len(sys.argv) == 2:
+ data = open(sys.argv[1]).read()
+ prog = basparse.parse(data,debug=log)
+ if not prog: raise SystemExit
+ b = basinterp.BasicInterpreter(prog)
+ try:
+ b.run()
+ raise SystemExit
+ except RuntimeError:
+ pass
+
+else:
+ b = basinterp.BasicInterpreter({})
+
+# Interactive mode. This incrementally adds/deletes statements
+# from the program stored in the BasicInterpreter object. In
+# addition, special commands 'NEW','LIST',and 'RUN' are added.
+# Specifying a line number with no code deletes that line from
+# the program.
+
+while 1:
+ try:
+ line = raw_input("[BASIC] ")
+ except EOFError:
+ raise SystemExit
+ if not line: continue
+ line += "\n"
+ prog = basparse.parse(line,debug=log)
+ if not prog: continue
+
+ keys = list(prog)
+ if keys[0] > 0:
+ b.add_statements(prog)
+ else:
+ stat = prog[keys[0]]
+ if stat[0] == 'RUN':
+ try:
+ b.run()
+ except RuntimeError:
+ pass
+ elif stat[0] == 'LIST':
+ b.list()
+ elif stat[0] == 'BLANK':
+ b.del_line(stat[1])
+ elif stat[0] == 'NEW':
+ b.new()
+
+
+
+
+
+
+
+
+
diff --git a/ext/ply/example/BASIC/basinterp.py b/ext/ply/example/BASIC/basinterp.py
index 5850457cb..3e8a7774a 100644
--- a/ext/ply/example/BASIC/basinterp.py
+++ b/ext/ply/example/BASIC/basinterp.py
@@ -40,10 +40,11 @@ class BasicInterpreter:
if self.prog[lineno][0] == 'END' and not has_end:
has_end = lineno
if not has_end:
- print "NO END INSTRUCTION"
+ print("NO END INSTRUCTION")
self.error = 1
+ return
if has_end != lineno:
- print "END IS NOT LAST"
+ print("END IS NOT LAST")
self.error = 1
# Check loops
@@ -60,9 +61,9 @@ class BasicInterpreter:
self.loopend[pc] = i
break
else:
- print "FOR WITHOUT NEXT AT LINE" % self.stat[pc]
+ print("FOR WITHOUT NEXT AT LINE %s" % self.stat[pc])
self.error = 1
-
+
# Evaluate an expression
def eval(self,expr):
etype = expr[0]
@@ -79,33 +80,33 @@ class BasicInterpreter:
elif etype == 'VAR':
var,dim1,dim2 = expr[1]
if not dim1 and not dim2:
- if self.vars.has_key(var):
+ if var in self.vars:
return self.vars[var]
else:
- print "UNDEFINED VARIABLE", var, "AT LINE", self.stat[self.pc]
+ print("UNDEFINED VARIABLE %s AT LINE %s" % (var, self.stat[self.pc]))
raise RuntimeError
# May be a list lookup or a function evaluation
if dim1 and not dim2:
- if self.functions.has_key(var):
+ if var in self.functions:
# A function
return self.functions[var](dim1)
else:
# A list evaluation
- if self.lists.has_key(var):
+ if var in self.lists:
dim1val = self.eval(dim1)
if dim1val < 1 or dim1val > len(self.lists[var]):
- print "LIST INDEX OUT OF BOUNDS AT LINE", self.stat[self.pc]
+ print("LIST INDEX OUT OF BOUNDS AT LINE %s" % self.stat[self.pc])
raise RuntimeError
return self.lists[var][dim1val-1]
if dim1 and dim2:
- if self.tables.has_key(var):
+ if var in self.tables:
dim1val = self.eval(dim1)
dim2val = self.eval(dim2)
if dim1val < 1 or dim1val > len(self.tables[var]) or dim2val < 1 or dim2val > len(self.tables[var][0]):
- print "TABLE INDEX OUT OUT BOUNDS AT LINE", self.stat[self.pc]
+ print("TABLE INDEX OUT OUT BOUNDS AT LINE %s" % self.stat[self.pc])
raise RuntimeError
return self.tables[var][dim1val-1][dim2val-1]
- print "UNDEFINED VARIABLE", var, "AT LINE", self.stat[self.pc]
+ print("UNDEFINED VARIABLE %s AT LINE %s" % (var, self.stat[self.pc]))
raise RuntimeError
# Evaluate a relational expression
@@ -145,31 +146,31 @@ class BasicInterpreter:
elif dim1 and not dim2:
# List assignment
dim1val = self.eval(dim1)
- if not self.lists.has_key(var):
+ if not var in self.lists:
self.lists[var] = [0]*10
if dim1val > len(self.lists[var]):
- print "DIMENSION TOO LARGE AT LINE", self.stat[self.pc]
+ print ("DIMENSION TOO LARGE AT LINE %s" % self.stat[self.pc])
raise RuntimeError
self.lists[var][dim1val-1] = self.eval(value)
elif dim1 and dim2:
dim1val = self.eval(dim1)
dim2val = self.eval(dim2)
- if not self.tables.has_key(var):
+ if not var in self.tables:
temp = [0]*10
v = []
for i in range(10): v.append(temp[:])
self.tables[var] = v
# Variable already exists
if dim1val > len(self.tables[var]) or dim2val > len(self.tables[var][0]):
- print "DIMENSION TOO LARGE AT LINE", self.stat[self.pc]
+ print("DIMENSION TOO LARGE AT LINE %s" % self.stat[self.pc])
raise RuntimeError
self.tables[var][dim1val-1][dim2val-1] = self.eval(value)
# Change the current line number
def goto(self,linenum):
- if not self.prog.has_key(linenum):
- print "UNDEFINED LINE NUMBER %d AT LINE %d" % (linenum, self.stat[self.pc])
+ if not linenum in self.prog:
+ print("UNDEFINED LINE NUMBER %d AT LINE %d" % (linenum, self.stat[self.pc]))
raise RuntimeError
self.pc = self.stat.index(linenum)
@@ -183,7 +184,7 @@ class BasicInterpreter:
self.gosub = None # Gosub return point (if any)
self.error = 0 # Indicates program error
- self.stat = self.prog.keys() # Ordered list of all line numbers
+ self.stat = list(self.prog) # Ordered list of all line numbers
self.stat.sort()
self.pc = 0 # Current program counter
@@ -198,7 +199,7 @@ class BasicInterpreter:
while 1:
line = self.stat[self.pc]
instr = self.prog[line]
-
+
op = instr[0]
# END and STOP statements
@@ -225,11 +226,11 @@ class BasicInterpreter:
out += str(eval)
sys.stdout.write(out)
end = instr[2]
- if not (end == ',' or end == ';'):
+ if not (end == ',' or end == ';'):
sys.stdout.write("\n")
if end == ',': sys.stdout.write(" "*(15-(len(out) % 15)))
if end == ';': sys.stdout.write(" "*(3-(len(out) % 3)))
-
+
# LET statement
elif op == 'LET':
target = instr[1]
@@ -258,7 +259,7 @@ class BasicInterpreter:
initval = instr[2]
finval = instr[3]
stepval = instr[4]
-
+
# Check to see if this is a new loop
if not self.loops or self.loops[-1][0] != self.pc:
# Looks like a new loop. Make the initial assignment
@@ -284,21 +285,21 @@ class BasicInterpreter:
elif op == 'NEXT':
if not self.loops:
- print "NEXT WITHOUT FOR AT LINE",line
+ print("NEXT WITHOUT FOR AT LINE %s" % line)
return
-
+
nextvar = instr[1]
self.pc = self.loops[-1][0]
loopinst = self.prog[self.stat[self.pc]]
forvar = loopinst[1]
if nextvar != forvar:
- print "NEXT DOESN'T MATCH FOR AT LINE", line
+ print("NEXT DOESN'T MATCH FOR AT LINE %s" % line)
return
continue
elif op == 'GOSUB':
newline = instr[1]
if self.gosub:
- print "ALREADY IN A SUBROUTINE AT LINE", line
+ print("ALREADY IN A SUBROUTINE AT LINE %s" % line)
return
self.gosub = self.stat[self.pc]
self.goto(newline)
@@ -306,7 +307,7 @@ class BasicInterpreter:
elif op == 'RETURN':
if not self.gosub:
- print "RETURN WITHOUT A GOSUB AT LINE",line
+ print("RETURN WITHOUT A GOSUB AT LINE %s" % line)
return
self.goto(self.gosub)
self.gosub = None
@@ -333,7 +334,7 @@ class BasicInterpreter:
v.append(temp[:])
self.tables[vname] = v
- self.pc += 1
+ self.pc += 1
# Utility functions for program listing
def expr_str(self,expr):
@@ -358,74 +359,74 @@ class BasicInterpreter:
# Create a program listing
def list(self):
- stat = self.prog.keys() # Ordered list of all line numbers
+ stat = list(self.prog) # Ordered list of all line numbers
stat.sort()
for line in stat:
instr = self.prog[line]
op = instr[0]
if op in ['END','STOP','RETURN']:
- print line, op
+ print("%s %s" % (line, op))
continue
elif op == 'REM':
- print line, instr[1]
+ print("%s %s" % (line, instr[1]))
elif op == 'PRINT':
- print line, op,
+ _out = "%s %s " % (line, op)
first = 1
for p in instr[1]:
- if not first: print ",",
- if p[0] and p[1]: print '"%s"%s' % (p[0],self.expr_str(p[1])),
- elif p[1]: print self.expr_str(p[1]),
- else: print '"%s"' % (p[0],),
+ if not first: _out += ", "
+ if p[0] and p[1]: _out += '"%s"%s' % (p[0],self.expr_str(p[1]))
+ elif p[1]: _out += self.expr_str(p[1])
+ else: _out += '"%s"' % (p[0],)
first = 0
- if instr[2]: print instr[2]
- else: print
+ if instr[2]: _out += instr[2]
+ print(_out)
elif op == 'LET':
- print line,"LET",self.var_str(instr[1]),"=",self.expr_str(instr[2])
+ print("%s LET %s = %s" % (line,self.var_str(instr[1]),self.expr_str(instr[2])))
elif op == 'READ':
- print line,"READ",
+ _out = "%s READ " % line
first = 1
for r in instr[1]:
- if not first: print ",",
- print self.var_str(r),
+ if not first: _out += ","
+ _out += self.var_str(r)
first = 0
- print ""
+ print(_out)
elif op == 'IF':
- print line,"IF %s THEN %d" % (self.relexpr_str(instr[1]),instr[2])
+ print("%s IF %s THEN %d" % (line,self.relexpr_str(instr[1]),instr[2]))
elif op == 'GOTO' or op == 'GOSUB':
- print line, op, instr[1]
+ print("%s %s %s" % (line, op, instr[1]))
elif op == 'FOR':
- print line,"FOR %s = %s TO %s" % (instr[1],self.expr_str(instr[2]),self.expr_str(instr[3])),
- if instr[4]: print "STEP %s" % (self.expr_str(instr[4])),
- print
+ _out = "%s FOR %s = %s TO %s" % (line,instr[1],self.expr_str(instr[2]),self.expr_str(instr[3]))
+ if instr[4]: _out += " STEP %s" % (self.expr_str(instr[4]))
+ print(_out)
elif op == 'NEXT':
- print line,"NEXT", instr[1]
+ print("%s NEXT %s" % (line, instr[1]))
elif op == 'FUNC':
- print line,"DEF %s(%s) = %s" % (instr[1],instr[2],self.expr_str(instr[3]))
+ print("%s DEF %s(%s) = %s" % (line,instr[1],instr[2],self.expr_str(instr[3])))
elif op == 'DIM':
- print line,"DIM",
+ _out = "%s DIM " % line
first = 1
for vname,x,y in instr[1]:
- if not first: print ",",
+ if not first: _out += ","
first = 0
if y == 0:
- print "%s(%d)" % (vname,x),
+ _out += "%s(%d)" % (vname,x)
else:
- print "%s(%d,%d)" % (vname,x,y),
-
- print
+ _out += "%s(%d,%d)" % (vname,x,y)
+
+ print(_out)
elif op == 'DATA':
- print line,"DATA",
+ _out = "%s DATA " % line
first = 1
for v in instr[1]:
- if not first: print ",",
+ if not first: _out += ","
first = 0
- print v,
- print
+ _out += v
+ print(_out)
# Erase the current program
def new(self):
self.prog = {}
-
+
# Insert statements
def add_statements(self,prog):
for line,stat in prog.items():
diff --git a/ext/ply/example/BASIC/basparse.py b/ext/ply/example/BASIC/basparse.py
index 930af9a22..ccdeb16b6 100644
--- a/ext/ply/example/BASIC/basparse.py
+++ b/ext/ply/example/BASIC/basparse.py
@@ -39,12 +39,12 @@ def p_program_error(p):
p[0] = None
p.parser.error = 1
-#### Format of all BASIC statements.
+#### Format of all BASIC statements.
def p_statement(p):
'''statement : INTEGER command NEWLINE'''
if isinstance(p[2],str):
- print p[2],"AT LINE", p[1]
+ print("%s %s %s" % (p[2],"AT LINE", p[1]))
p[0] = None
p.parser.error = 1
else:
@@ -68,7 +68,7 @@ def p_statement_blank(p):
def p_statement_bad(p):
'''statement : INTEGER error NEWLINE'''
- print "MALFORMED STATEMENT AT LINE", p[1]
+ print("MALFORMED STATEMENT AT LINE %s" % p[1])
p[0] = None
p.parser.error = 1
@@ -121,7 +121,7 @@ def p_command_print_bad(p):
#### Optional ending on PRINT. Either a comma (,) or semicolon (;)
def p_optend(p):
- '''optend : COMMA
+ '''optend : COMMA
| SEMI
|'''
if len(p) == 2:
@@ -188,7 +188,7 @@ def p_optstep(p):
p[0] = None
#### NEXT statement
-
+
def p_command_next(p):
'''command : NEXT ID'''
@@ -392,30 +392,30 @@ def p_item_expr(p):
p[0] = ("",p[1])
#### Empty
-
+
def p_empty(p):
'''empty : '''
#### Catastrophic error handler
def p_error(p):
if not p:
- print "SYNTAX ERROR AT EOF"
+ print("SYNTAX ERROR AT EOF")
bparser = yacc.yacc()
-def parse(data):
+def parse(data,debug=0):
bparser.error = 0
- p = bparser.parse(data)
+ p = bparser.parse(data,debug=debug)
if bparser.error: return None
return p
-
-
-
-
+
+
+
+