I've written a "simple" interpreter for a programming language in Python, called Tellurium (named after the element of the same name). So far, it's working pretty well, but there are some things I'd like to fix/remove.
Tellurium is a tape-based language, so it uses a tape to store data.
import string, sys, random, time, codecs
tape = [0] * 25500
funcs = {}
variables = {}
readingStr = False
readingLoopAmount = False
readingLoopCode = False
readingRand = False
readingRand2 = False
readingFName = False
readingFCode = False
readingName = False
readingVName = False
readingFileName = False
readingVText = False
readingVName2 = False
appendToFront = False
appendToBack = False
loopInf = False
loopRand = False
string = False
isChar = False
fileName = []
vName = []
vText = []
vName2 = []
tempText = []
tempName = []
fName = []
fCode = []
text = []
rand = []
rand2 = []
loopCode = []
loopAmount = []
selected = 0
def prompt():
cmd = input("> ")
return cmd
def read(cmd):
if "!K" in cmd:
cmd = cmd.replace("!K", "1000")
if "!H" in cmd:
cmd = cmd.replace("!H", "100")
commands = len(cmd)
tokens = list(cmd)
for i in range(0, commands):
parse(tokens[i])
def parse(cmd):
# Sorry for all these globals...
global tape
global funcs
global variables
global readingStr
global readingFileName
global readingLoopAmount
global readingLoopCode
global readingRand
global readingRand2
global readingFName
global readingFCode
global readingName
global readingVName
global readingVText
global readingVName2
global appendToFront
global appendToBack
global loopInf
global loopRand
global vName, vText, vName2
global fileName
global string
global isChar
global tempName
global tempText
global fName
global fCode
global text
global rand
global rand2
global loopCode
global loopAmount
global selected
if readingFileName == True:
if cmd == "]":
readingFileName = False
f = open(''.join(fileName), 'r')
code = f.read()
f.close()
read(code)
fileName = []
else:
fileName.append(cmd)
elif readingVName2 == True:
if cmd == ".":
readingVName2 = False
tape[selected] = variables[''.join(vName2)]
vName2 = []
else:
vName2.append(cmd)
elif readingVName == True:
if cmd == "|":
readingVText = True
readingVName = False
else:
vName.append(cmd)
elif readingVText == True:
if cmd == "]":
readingVText = False
name = ''.join(vName)
val = ''.join(vText)
variables[name] = val
vName = []
vText = []
else:
vText.append(cmd)
elif readingName == True:
if cmd == ".":
readingName = False
name = ''.join(tempName)
read(funcs[name])
tempName = []
else:
tempName.append(cmd)
elif readingFName == True:
if cmd == "|":
readingFName = False
readingFCode = True
else:
fName.append(cmd)
elif readingFCode == True:
if cmd == "`":
readingFCode = False
name = ''.join(fName)
code = ''.join(fCode)
funcs[name] = code
fName = []
fCode = []
else:
fCode.append(cmd)
elif readingRand == True:
if cmd == "|":
readingRand = False
else:
rand.append(cmd)
elif readingRand2 == True:
if cmd == "|":
readingRand2 = False
else:
rand2.append(cmd)
elif string == True:
if appendToFront == True:
if cmd == "~":
tape[selected] = str(tape[selected]) + ''.join(tempText)
tempText = []
appendToFront = False
elif cmd == "$":
tape[selected] = str(tape[selected]) + str(tape[selected-1])
appendToFront = False
tempText = []
else:
tempText.append(cmd)
elif appendToBack == True:
if cmd == "~":
tape[selected] = ''.join(tempText) + str(tape[selected])
tempText = []
appendToBack = False
elif cmd == "$":
tape[selected] = str(tape[selected-1]) + str(tape[selected])
appendToFront = False
tempText = []
else:
tempText.append(cmd)
elif cmd == "r":
tape[selected] = tape[selected].reverse()
elif cmd == "u":
tape[selected] = tape[selected].upper()
elif cmd == "l":
tape[selected] = tape[selected].lower()
elif cmd == "a":
appendToFront = True
elif cmd == "b":
appendToBack = True
elif cmd == ".":
string = False
elif readingLoopAmount == True:
if cmd == "|":
readingLoopAmount = False
readingLoopCode = True
elif cmd == "i":
loopInf = True
elif cmd == "r":
loopRand = True
else:
loopAmount.append(cmd)
elif readingLoopCode == True:
if cmd == "]":
readingLoopCode = False
if loopInf == True:
while 1:
read(loopCode)
if loopRand == True:
if rand and rand2 == []:
for i in range(0, random.randint(0, 100)):
read(loopCode)
else:
if rand2 == []:
for i in range(0, random.randint(0, int(''.join(rand)))):
read(loopCode)
elif rand == []:
for i in range(0, random.randint(int(''.join(rand2)), 100)):
read(loopCode)
else:
for i in range(0, random.randint(int(''.join(rand2)), int(''.join(rand)))):
read(loopCode)
else:
for i in range(0, int(''.join(loopAmount))):
read(loopCode)
loopCode = []
loopAmount = []
else:
loopCode.append(cmd)
elif readingStr == True:
if cmd == "~":
readingStr = False
text = ''.join(text).replace("µ", "")
tape[selected] = text
text = []
else:
text.append(cmd)
elif cmd == "+":
tape[selected] += 1
elif cmd == "-":
tape[selected] -= 1
elif cmd == ">":
selected += 1
elif cmd == "<":
selected -= 1
elif cmd == "*":
print(selected)
elif cmd == "^":
print(tape[selected])
elif cmd == "!":
if isinstance(tape[selected], str):
print(tape[selected])
else:
print(chr(tape[selected]))
elif cmd == "%":
tape[selected] = ord(tape[selected])
elif cmd == "#":
tape[selected] = 0
elif cmd == "$":
selected = 0
elif cmd == "/":
tape[selected] += 10
elif cmd == "\\":
tape[selected] -= 10
elif cmd == "{":
selected += 10
elif cmd == "}":
selected -= 10
elif cmd == '"':
tape[selected] += 100
elif cmd == "'":
tape[selected] -= 100
elif cmd == "-":
selected += 100
elif cmd == "_":
selected -= 100
elif cmd == "i":
tape[selected] = input(">> ")
elif cmd == "n":
tape[selected] = int(tape[selected])
elif cmd == "a":
tape[selected] = int(tape[selected]) + int(tape[selected+1])
elif cmd == "s":
tape[selected] = int(tape[selected]) - int(tape[selected+1])
elif cmd == "m":
tape[selected] = int(tape[selected]) * int(tape[selected+1])
elif cmd == "d":
tape[selected] = int(tape[selected]) / int(tape[selected+1])
elif cmd == "(":
readingNum = True
elif cmd == "z":
tape[selected] = tape[selected+1]
elif cmd == "x":
tape[selected] = tape[selected-1]
elif cmd == "µ":
readingStr = True
elif cmd == "[":
readingLoopAmount = True
elif cmd == "p":
return
elif cmd == ".":
exit
elif cmd == "&":
string = True
elif cmd == "→":
if rand != []:
rand = []
readingRand = True
elif cmd == "←":
if rand2 != []:
rand2 = []
readingRand2 = True
elif cmd == "t":
tape[selected] = str(time.ctime())
elif cmd == "¨":
time.sleep(1)
elif cmd == "r":
tape[selected] = codecs.encode(str(tape[selected]), 'rot_13')
elif cmd == "n":
tape[selected] = int(tape[selected])
elif cmd == "@":
readingFName = True
elif cmd == "=":
readingName = True
elif cmd == "¤":
readingVName = True
elif cmd == ";":
readingVName2 = True
elif cmd == "0":
readingFileName = True
elif cmd == "f":
tape[selected] = float(tape[selected])
while 1:
read(prompt())
Example programs
Hello, world! -
µHello, world!~^
Explanation: everything after
µ
and before~
will be read and stored in the tape's currently selected cell.^
outputs whatever is in the selected cell, which in the program isHello, world!
.Cat program -
i^
Explanation:
i
reads input and stores it in the selected cell.^
outputs whatever is in the cell.Navigating cells -
+>++>+++<<^>^>^
Explanation:
+
adds one to the selected cell's value.>
goes forward one cell in the tape.<
goes back, and^
outputs whatever is in the selected cell. So, the output is123
, separated by newlines.Math (addition) -
+>+<a^
Explanation: If you read the above example, you'll know what the
+
,>
and<
commands do. Thea
command is the addition command. It takes the values of the selected cell and the next one up, and adds them together. The result is stored in the selected cell. The other math commands ares
(subtraction),m
(multiplication) andd
(division).Loop -
[5|^]
Explanation: The syntax of a for loop in Tellurium is
[times|code]
. So, this outputs the selected cell's value 5 times.Clock -
[i|t^¨]
Explanation:
t
stores the current time and date in the selected cell.¨
waits one second before continuing the code.i
makes a loop run forever. The code will keep printing the current time and date every second.Countdown -
/[10|-^¨]
Explanation:
/
adds ten to the selected cell's value. The loop after that runs the code-^¨
ten times.-
subtracts one from the cell's value.`Functions -
@a|^^^^]
Explanation: this program creates a function called
a
, which outputs the selected cell's value four times.Calling functions -
=a.
Explanation: this calls a function called
a
. (The.
is needed, otherwise it won't work)Appending to strings -
µHello,
&aworld!~.^`Explanation: this sets the value of the selected cell to
Hello,
.&
starts string manipulation mode. While in string mode, you can use thea
command to append to the end of a string. In this example, it appendsworld!
to the end of the selected cell.
.` exits string manipulation mode.
The reason I posted this here is because the code is messy and quite unreadable. I'm looking for some tips to clean it up, remove the unneeded things, etc. Also, I'd like to remove the big list of variables and global statements, if possible. They're limiting the flexibility of the language. For example, I can't implement conditional statements until I've removed the globals. I've tried, but it hasn't worked.