|
1 | | -#! /usr/bin/python |
2 | | - |
3 | | -# SPDX-License-Identifier: GPL-3.0-or-later |
4 | | -# |
5 | | -# This program is free software: you can redistribute it and/or modify |
6 | | -# it under the terms of the GNU General Public License as published by |
7 | | -# the Free Software Foundation, either version 3 of the License, or |
8 | | -# (at your option) any later version. |
9 | | -# |
10 | | -# This program is distributed in the hope that it will be useful, |
11 | | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | -# GNU General Public License for more details. |
14 | | -# |
15 | | -# You should have received a copy of the GNU General Public License |
16 | | -# along with this program. If not, see <https://www.gnu.org/licenses/>. |
17 | | - |
18 | | -"""This class implements a BASIC interpreter that |
19 | | -presents a prompt to the user. The user may input |
20 | | -program statements, list them and run the program. |
21 | | -The program may also be saved to disk and loaded |
22 | | -again. |
23 | | -
|
24 | | -""" |
25 | | - |
26 | | -from basictoken import BASICToken as Token |
27 | | -from lexer import Lexer |
28 | | -from program import Program |
29 | | -from sys import stderr,implementation |
30 | | -from os import listdir,rename,remove |
31 | | -import gc |
32 | | -try: |
33 | | - from pydos_ui import input |
34 | | -except: |
35 | | - pass |
36 | | - |
37 | | -if implementation.name.upper() == 'MICROPYTHON': |
38 | | - from sys import print_exception |
39 | | - |
40 | | -gc.collect() |
41 | | -if 'threshold' in dir(gc): |
42 | | - gc.threshold(gc.mem_free() // 4 + gc.mem_alloc()) |
43 | | - |
44 | | -def main(passedIn=""): |
45 | | - |
46 | | - banner = ( |
47 | | -""" |
48 | | - PPPP Y Y BBBB AAA SSSS I CCC |
49 | | - P P Y Y B B A A S I C |
50 | | - P P Y Y B B A A S I C |
51 | | - PPPP Y BBBB AAAAA SSSS I C |
52 | | -u u P Y B B A A S I C |
53 | | -u u P Y B B A A S I C |
54 | | -uuuu P Y BBBB A A SSSS I CCC |
55 | | - microPyBasic |
56 | | -""") |
57 | | - |
58 | | - print(banner) |
59 | | - |
60 | | - lexer = Lexer() |
61 | | - program = Program() |
62 | | - |
63 | | - fOpened = False |
64 | | - #initialize and open temporary file |
65 | | - tmpfile = open('_pybTmp.tmp','w+') |
66 | | - infile = tmpfile |
67 | | - |
68 | | - #Attempting memory pre-allocation to prepare for large Basic programs |
69 | | - if implementation.name.upper() in ['MICROPYTHON','CIRCUITPYTHON']: |
70 | | - gc.collect() |
71 | | - for i in range(1600): |
72 | | - if i % 100 == 0: |
73 | | - print(".",end="") |
74 | | - try: |
75 | | - program.__program[i] = i |
76 | | - except: |
77 | | - print("\nMemory pre-allocation limit reached at ",i) |
78 | | - break |
79 | | - print() |
80 | | - program.__program.clear() |
81 | | - |
82 | | - if passedIn != "": |
83 | | - infile = program.load(passedIn,tmpfile) |
84 | | - program.execute(infile,tmpfile) |
85 | | - |
86 | | - # Continuously accept user input and act on it until |
87 | | - # the user enters 'EXIT' |
88 | | - while True: |
89 | | - |
90 | | - # kfw stmt = input_keyboard(': ') |
91 | | - stmt = input(': ') |
92 | | - |
93 | | - try: |
94 | | - #if True: |
95 | | - tokenlist = lexer.tokenize(stmt) |
96 | | - |
97 | | - # Execute commands directly, otherwise |
98 | | - # add program statements to the stored |
99 | | - # BASIC program |
100 | | - |
101 | | - if len(tokenlist) > 0: |
102 | | - |
103 | | - # remove blank tokens |
104 | | - i = 0 |
105 | | - iend = len(tokenlist) |
106 | | - for _ in range(iend): |
107 | | - if i>0 and tokenlist[i].lexeme.strip() == "" and tokenlist[i].category != Token.STRING: |
108 | | - tokenlist.pop(i) |
109 | | - else: |
110 | | - i+=1 |
111 | | - |
112 | | - # Exit the interpreter |
113 | | - if tokenlist[0].category == Token.EXIT: |
114 | | - if fOpened: |
115 | | - infile.close() |
116 | | - tmpfile.close() |
117 | | - remove('_pybTmp.tmp') |
118 | | - break |
119 | | - |
120 | | - # Add a new program statement |
121 | | - elif tokenlist[0].category == Token.UNSIGNEDINT\ |
122 | | - and len(tokenlist) > 1: |
123 | | - program.add_stmt(tokenlist,-1,tmpfile) |
124 | | - |
125 | | - # Delete a statement from the program |
126 | | - elif tokenlist[0].category == Token.UNSIGNEDINT \ |
127 | | - and len(tokenlist) == 1: |
128 | | - program.delete_statement(int(tokenlist[0].lexeme)) |
129 | | - |
130 | | - # Execute the program |
131 | | - elif tokenlist[0].category == Token.RUN: |
132 | | - try: |
133 | | - program.execute(infile,tmpfile) |
134 | | - |
135 | | - except KeyboardInterrupt: |
136 | | - print("Program terminated") |
137 | | - |
138 | | - # List the program |
139 | | - elif tokenlist[0].category == Token.LIST: |
140 | | - if len(tokenlist) == 2: |
141 | | - program.list(int(tokenlist[1].lexeme),int(tokenlist[1].lexeme),infile,tmpfile) |
142 | | - elif len(tokenlist) == 3: |
143 | | - program.list(int(tokenlist[1].lexeme),int(tokenlist[2].lexeme),infile,tmpfile) |
144 | | - elif len(tokenlist) == 4: |
145 | | - program.list(int(tokenlist[1].lexeme),int(tokenlist[3].lexeme),infile,tmpfile) |
146 | | - else: |
147 | | - program.list(-1,-1,infile,tmpfile) |
148 | | - |
149 | | - # Save the program to disk |
150 | | - elif tokenlist[0].category == Token.SAVE: |
151 | | - if len(tokenlist) <= 1: |
152 | | - print("No filename specified") |
153 | | - elif "/" in tokenlist[1].lexeme or "\\" in tokenlist[1].lexeme or ":" in tokenlist[1].lexeme: |
154 | | - print("Can only save to current directory") |
155 | | - else: |
156 | | - if tokenlist[1].lexeme.split(".")[-1].upper() == "PGM": |
157 | | - filename = tokenlist[1].lexeme+".BAS" |
158 | | - if filename in listdir(): |
159 | | - remove(filename) |
160 | | - else: |
161 | | - filename = tokenlist[1].lexeme |
162 | | - |
163 | | - if program.save(filename,infile,tmpfile): |
164 | | - # Since we are running the program from the disk file "in place" |
165 | | - # the current program listing is contained only on disk in the |
166 | | - # loaded file (if one has been loaded) and the _pYbTmp.tmp working file |
167 | | - # the program.save function has to save the file to a temporary filename |
168 | | - # and we now have to replace the specified output filename with that |
169 | | - # temporary file. Finally we need to reload the saved file to initialize |
170 | | - # the in place files and index |
171 | | - # |
172 | | - # PGM files are worse since we use the internal file index keys we have to |
173 | | - # first save as a normal BAS file and reaload to eliminate all code from |
174 | | - # the temporary file |
175 | | - program.delete() |
176 | | - if fOpened: |
177 | | - infile.close() |
178 | | - |
179 | | - if filename in listdir(): |
180 | | - remove(filename) |
181 | | - |
182 | | - rename(filename+".pYb",filename) |
183 | | - |
184 | | - tmpfile.close() |
185 | | - tmpfile = open('_pybTmp.tmp','w+') |
186 | | - infile = program.load(filename,tmpfile) |
187 | | - if infile != None: |
188 | | - |
189 | | - if tokenlist[1].lexeme.split(".")[-1].upper() == "PGM": |
190 | | - |
191 | | - filename = tokenlist[1].lexeme |
192 | | - if program.save(filename,infile,tmpfile): |
193 | | - |
194 | | - if filename in listdir(): |
195 | | - remove(filename) |
196 | | - |
197 | | - rename(filename+".pYb",filename) |
198 | | - |
199 | | - #.PGM.BAS file now being used, need to close .PGM.BAS and reload .pgm file |
200 | | - program.delete() |
201 | | - infile.close() |
202 | | - infile = program.load(filename,tmpfile) |
203 | | - if infile != None: |
204 | | - remove(filename+".BAS") |
205 | | - fOpened = True |
206 | | - print("Program written to file") |
207 | | - else: |
208 | | - # This should never happen, but just in case... |
209 | | - fOpened = False |
210 | | - print("Program saved but lost from active memory, ",end="") |
211 | | - print("enter load command to re-load saved work") |
212 | | - else: |
213 | | - fOpened = True |
214 | | - print("Program written to file") |
215 | | - else: |
216 | | - # This should never happen, but just in case... |
217 | | - fOpened = False |
218 | | - if tokenlist[1].lexeme.split(".")[-1].upper() == "PGM": |
219 | | - rename(filename,tokenlist[1].lexeme+".BAS") |
220 | | - print("Texed program saved as "+tokenlist[1].lexeme+".BAS but lost from active memory, ",end="") |
221 | | - else: |
222 | | - print("Program saved but lost from active memory, ",end="") |
223 | | - print("enter load command to re-load saved work") |
224 | | - |
225 | | - |
226 | | - # Load the program from disk and/or delete the program from memory |
227 | | - elif tokenlist[0].category == Token.LOAD or tokenlist[0].category == Token.NEW: |
228 | | - program.delete() |
229 | | - if fOpened: |
230 | | - infile.close() |
231 | | - fOpened = False |
232 | | - |
233 | | - tmpfile.close() |
234 | | - tmpfile = open('_pybTmp.tmp','w+') |
235 | | - |
236 | | - if tokenlist[0].category == Token.LOAD: |
237 | | - |
238 | | - if len(tokenlist) > 1: |
239 | | - infile = program.load(tokenlist[1].lexeme,tmpfile) |
240 | | - if infile != None: |
241 | | - fOpened = True |
242 | | - print("Program read from file") |
243 | | - else: |
244 | | - fOpened = False |
245 | | - else: |
246 | | - print("Program file not found") |
247 | | - |
248 | | - else: |
249 | | - print("Unrecognized input") |
250 | | - for token in tokenlist: |
251 | | - token.print_lexeme() |
252 | | - print("") |
253 | | - |
254 | | - # Trap all exceptions so that interpreter keeps running |
255 | | - except Exception as e: |
256 | | - if implementation.name.upper() == 'MICROPYTHON': |
257 | | - print_exception(e) |
258 | | - else: |
259 | | - print(e) |
260 | | - |
261 | | -if __name__ == "PyDOS": |
262 | | - main(passedIn) |
263 | | -else: |
264 | | - print("Enter 'PyBasic.main()' in the REPL to run.") |
| 1 | +import interpreter |
| 2 | +if __name__ != "PyDOS": |
| 3 | + passedIn = "" |
| 4 | +interpreter.main(passedIn) |
0 commit comments