teletype-simulator 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ Metadata-Version: 2.4
2
+ Name: teletype-simulator
3
+ Version: 0.1.0
4
+ Summary: A simple teletype and BASIC interpreter simulator
5
+ Requires-Python: >=3.10
@@ -0,0 +1,12 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "teletype-simulator"
7
+ version = "0.1.0"
8
+ description = "A simple teletype and BASIC interpreter simulator"
9
+ requires-python = ">=3.10"
10
+
11
+ [project.scripts]
12
+ teletype-sim = "teletype_simulator.main:main"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,53 @@
1
+ from teletype_simulator.teletype import Teletype
2
+ from teletype_simulator.interpreter import BASIC_Interpreter
3
+ import sys
4
+
5
+ class Computer():
6
+ def __init__(self):
7
+ self.teletype = Teletype()
8
+ """Instance of the Teletype object in Computer"""
9
+
10
+ self.interpreter = BASIC_Interpreter(self.teletype)
11
+ """Instance of the interpreter in Computer"""
12
+
13
+ self.script_name = None
14
+ """Stores the name of BASIC scripts being ran/created"""
15
+
16
+ self.script = None
17
+ """Stores the actual BASIC script once it's loaded by open_program. HAS .txt APPENDED TO IT AT THE END AT INPUT"""
18
+
19
+ def configure(self):
20
+ self.teletype.output_from_teletype("Configuring BASIC Interpreter...")
21
+ #just a rizzy little thing I guess
22
+
23
+ def get_input(self):
24
+ option = self.teletype.input_to_teletype(0)
25
+ #Option runs from 1 - 3, 1 being create new program and 2 being opening a program; 3 is exit and is dealt with in Teletype
26
+ #This determines which function of the computer we're going to use
27
+
28
+ self.script_name = self.teletype.input_to_teletype(option)
29
+ #This gets the name of the script being created/opened from the user
30
+
31
+ if option == 1: #creates a new program and exits
32
+ self.new_program()
33
+ self.teletype.output_from_teletype("The program will now exit; you can work on the new script.")
34
+ sys.exit(0)
35
+
36
+ elif option == 2: #parses the script into self.script to be interpreted
37
+ self.open_program()
38
+ self.interpreter.interpret(self.script)
39
+
40
+ def new_program(self):
41
+ """Opens a new .txt file for the user to write their BASIC scripts in."""
42
+ with open(f"user_scripts/{self.script_name}", "w") as file:
43
+ file.write("New script!\n")
44
+
45
+ def open_program(self):
46
+ """Opens an existing .txt file for the interpreter to execute."""
47
+ try:
48
+ with open(f"user_scripts/{self.script_name}") as file:
49
+ self.script = file.read()
50
+ except FileNotFoundError:
51
+ print("File not found")
52
+ sys.exit(1)
53
+
@@ -0,0 +1,7 @@
1
+ import csv
2
+
3
+ def read_csv(file_name):
4
+ with open(file_name, "r") as file:
5
+ reader = csv.DictReader(file)
6
+ rows = list(reader)
7
+ return rows
@@ -0,0 +1,200 @@
1
+ import sys
2
+
3
+ class BASIC_Interpreter():
4
+ def __init__(self, teletype):
5
+ self.teletype = teletype
6
+ """Dependency injection to allow easier outputting"""
7
+
8
+ self.script = None
9
+ """Stores the actual BASIC script passed into the interpreter; line_number, command, argument"""
10
+
11
+ self.interpreted_script = None
12
+ """Stores a parsed version of the script separated into keywords; a list of dicts"""
13
+
14
+ self.script_variables = dict()
15
+ """Stores the variables in the script: {"variable name": x, "value": y}"""
16
+
17
+ self.loop_data = dict()
18
+ """Stores data for loops"""
19
+
20
+ def interpret(self, script):
21
+ """Interprets lines, separating them into line number, command, and argument for running"""
22
+ self.script = script
23
+ self.interpreted_script = list()
24
+
25
+ for line in self.script.splitlines():
26
+ line = line.split(maxsplit=2)
27
+ if len(line) != 3:
28
+ argument = None
29
+ else:
30
+ argument = line[2].strip()
31
+ interpreted_line = {
32
+ "line_number": int(line[0]),
33
+ "command": line[1].upper(),
34
+ "argument": argument
35
+ }
36
+ self.interpreted_script.append(interpreted_line)
37
+
38
+ self.run_program()
39
+
40
+ def run_program(self):
41
+ """Continously runs the program and keeps track of the line index"""
42
+ index = 0
43
+ while index < len(self.interpreted_script):
44
+ #Continously runs the program
45
+ current_line = self.interpreted_script[index]
46
+ command = current_line["command"]
47
+ argument = current_line["argument"]
48
+
49
+ new_index = self.execute(index, command, argument)
50
+ if new_index is not None:
51
+ index = new_index
52
+ else:
53
+ index += 1
54
+
55
+ def execute(self, index, command, argument):
56
+ """Executes each line of the program, matching commands to functions"""
57
+ if command == "PRINT":
58
+ self.print_method(argument)
59
+ return None
60
+
61
+ elif command == "LET":
62
+ self.let_method(argument)
63
+ return None
64
+
65
+ elif command == "GOTO":
66
+ return self.goto_method(argument)
67
+
68
+ elif command == "IF":
69
+ action = self.booleans(argument)
70
+ if action:
71
+ return self.execute(index, *(action.split(maxsplit=1)))
72
+ return None
73
+
74
+ elif command == "INPUT":
75
+ self.input_method(argument)
76
+ return None
77
+
78
+ elif command == "FOR":
79
+ self.for_loop(index, argument)
80
+
81
+ elif command == "NEXT":
82
+ new_index = self.next_method(argument)
83
+ if new_index is not None:
84
+ return new_index
85
+
86
+ elif command == "END":
87
+ sys.exit(0)
88
+
89
+ else:
90
+ print("FATAL ERROR")
91
+ sys.exit(1)
92
+
93
+ def print_method(self, argument):
94
+ """prints variables"""
95
+ printed_thing = None
96
+ if argument in self.script_variables:
97
+ printed_thing = self.script_variables[argument]
98
+ else:
99
+ printed_thing = argument
100
+
101
+ self.teletype.output_from_teletype(str(printed_thing).strip('"'))
102
+
103
+ def let_method(self, argument):
104
+ """assigns a value to data"""
105
+ argument = argument.split("=")
106
+ argument[0] = argument[0].strip()
107
+ argument[1] = argument[1].strip()
108
+
109
+ for operator in ["+", "-", "*", "/"]:
110
+ if operator in argument[1]:
111
+ argument[1] = self.evaluate_expression(argument[1])
112
+ break
113
+
114
+ self.script_variables[argument[0]] = argument[1]
115
+
116
+ def goto_method(self, line_number):
117
+ """goes from one line to another line, skipping lines in between"""
118
+ for index, line in enumerate(self.interpreted_script):
119
+ if line["line_number"] == int(line_number):
120
+ return index
121
+
122
+ def evaluate_expression(self, expression):
123
+ """Does basic mathematical calculations; Compares two numbers with operators"""
124
+ expression = expression.split()
125
+
126
+ left = expression[0].strip()
127
+ right = expression[2].strip()
128
+ if not left.isnumeric():
129
+ left = int(self.script_variables[left])
130
+ else:
131
+ left = int(left)
132
+ if not right.isnumeric():
133
+ right = int(self.script_variables[right])
134
+ else:
135
+ right = int(right)
136
+
137
+ operator = expression[1].strip()
138
+ if operator == "+":
139
+ return left + right
140
+ elif operator == "-":
141
+ return left - right
142
+ elif operator == "*":
143
+ return left * right
144
+ elif operator == "/":
145
+ return left / right
146
+ elif operator == ">":
147
+ return True if left > right else False
148
+ elif operator == ">=":
149
+ return True if left >= right else False
150
+ elif operator == "==":
151
+ return True if left == right else False
152
+ elif operator == "<":
153
+ return True if left < right else False
154
+ elif operator == "<=":
155
+ return True if left <= right else False
156
+
157
+ def input_method(self, argument):
158
+ """asks for an input and stores it in a variable"""
159
+ prompt, variable = argument.split(";")
160
+ prompt = prompt.strip()
161
+ variable = variable.strip()
162
+
163
+ self.print_method(prompt)
164
+ user_input = self.teletype.input_to_teletype(3)
165
+
166
+ self.let_method(f"{variable} = {user_input}")
167
+
168
+ def booleans(self, expression):
169
+ """Evaluates boolean expressions"""
170
+ condition, action = expression.split("THEN")
171
+ condition = condition.strip()
172
+ action = action.strip()
173
+
174
+ if self.evaluate_expression(condition):
175
+ return action
176
+ return None
177
+
178
+ def for_loop(self, index, argument):
179
+ """For loop"""
180
+ variable, bound = argument.split("=")
181
+ start, end = bound.split("TO")
182
+ variable = variable.strip()
183
+ start = int(start.strip())
184
+ end = int(end.strip())
185
+
186
+ self.script_variables[variable] = start
187
+ self.loop_data[variable] = {"end": end, "start_index": index + 1}
188
+
189
+ def next_method(self, loop_variable_name):
190
+ """Advances a for loop and see if it should continue"""
191
+ loop_variable_name = loop_variable_name.strip()
192
+ self.script_variables[loop_variable_name] += 1
193
+
194
+ loop_variable_value = self.script_variables[loop_variable_name]
195
+ loop_data = self.loop_data[loop_variable_name]
196
+
197
+ if loop_variable_value <= loop_data["end"]:
198
+ return loop_data["start_index"]
199
+
200
+ return None
@@ -0,0 +1,12 @@
1
+ from teletype_simulator.computer import Computer
2
+
3
+ def main():
4
+ computer = Computer()
5
+ computer.configure()
6
+ running = True
7
+ while running:
8
+ computer.get_input()
9
+
10
+ if __name__ == "__main__":
11
+ main()
12
+
@@ -0,0 +1,58 @@
1
+ import sys, time
2
+
3
+ OUTPUT_SPEED = 0
4
+ """A teletype returns about 10 characters per second according to research; the output speed is also hardwired to this in this program."""
5
+
6
+ class Teletype():
7
+ def __init__(self):
8
+ self.script_name = None
9
+
10
+ def input_to_teletype(self, log_in: int):
11
+ if log_in == 0:
12
+ try:
13
+ self.output_from_teletype("Enter 1 to create a new script, 2 to run an existing one, 3 to exit, \"commands\" for command menu: ")
14
+ option = input("\nINPUT > ")
15
+ if option not in ["1", "2", "3", "commands"]:
16
+ raise ValueError
17
+
18
+ if option == "commands":
19
+ self.commands()
20
+ print()
21
+ sys.exit(0)
22
+ option = int(option)
23
+
24
+ except ValueError,:
25
+ #Exits if none of the three numeric options are picked
26
+ print("Invalid input")
27
+ sys.exit(1)
28
+ if option == 3:
29
+ sys.exit(0)
30
+ return option
31
+
32
+ elif log_in == 1 or log_in == 2: #called by Computer to get a script name
33
+ if log_in == 1:
34
+ self.output_from_teletype("New script name: ") #For new scripts
35
+ else:
36
+ self.output_from_teletype("Name of the script you want to run: ") #For existing scripts
37
+
38
+ self.script_name = input("\nINPUT > ")
39
+ self.script_name += ".txt" #.txt extension is ADDED TO THE FILE NAME HERE
40
+ return self.script_name
41
+
42
+ elif log_in == 3: #Called by INPUT in interpreter to get an input from the user
43
+ return input("\nINPUT > ")
44
+
45
+ def output_from_teletype(self, message: str):
46
+ print("\nOUTPUT > ", end="")
47
+ for character in message:
48
+ print(character, end="", flush=True)
49
+ time.sleep(OUTPUT_SPEED)
50
+ #it outputs character by characteron a line
51
+
52
+ def commands(self):
53
+ """Displays command menu for help"""
54
+ with open("commands.txt", "r") as file:
55
+ commands = file.read()
56
+
57
+ for line in commands.splitlines():
58
+ self.output_from_teletype(line)
@@ -0,0 +1,5 @@
1
+ Metadata-Version: 2.4
2
+ Name: teletype-simulator
3
+ Version: 0.1.0
4
+ Summary: A simple teletype and BASIC interpreter simulator
5
+ Requires-Python: >=3.10
@@ -0,0 +1,12 @@
1
+ pyproject.toml
2
+ teletype_simulator/__init__.py
3
+ teletype_simulator/computer.py
4
+ teletype_simulator/csv_reader.py
5
+ teletype_simulator/interpreter.py
6
+ teletype_simulator/main.py
7
+ teletype_simulator/teletype.py
8
+ teletype_simulator.egg-info/PKG-INFO
9
+ teletype_simulator.egg-info/SOURCES.txt
10
+ teletype_simulator.egg-info/dependency_links.txt
11
+ teletype_simulator.egg-info/entry_points.txt
12
+ teletype_simulator.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ teletype-sim = teletype_simulator.main:main
@@ -0,0 +1 @@
1
+ teletype_simulator