Mercurial > repo
comparison interps/linguine/linguine.py @ 996:859f9b4339e6
<Gregor> tar xf egobot.tar.xz
author | HackBot |
---|---|
date | Sun, 09 Dec 2012 19:30:08 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
995:6883f5911eb7 | 996:859f9b4339e6 |
---|---|
1 #! /usr/bin/env python | |
2 | |
3 """ | |
4 Linguine programming language interpreter | |
5 Copyright (c) 2005 by Jeffry Johnston | |
6 | |
7 This program is free software; you can redistribute it and/or | |
8 modify it under the terms of the GNU General Public License as | |
9 published by the Free Software Foundation. See the file LICENSE | |
10 for more details. | |
11 | |
12 Version History: | |
13 1.00 November 24, 2005 Initial version | |
14 1.10 November 25, 2005 Added jump dereferencing | |
15 1.20 November 26, 2005 Added `>' instruction | |
16 1.21 November 26, 2005 Fix negative y on `>' bug | |
17 1.22 November 26, 2005 Fix >> big number bug | |
18 1.30 November 27, 2005 Added `^' instruction | |
19 """ | |
20 | |
21 import sys | |
22 import time | |
23 from optparse import OptionParser | |
24 | |
25 VERSION = "1.10" | |
26 glo_memory = {} | |
27 | |
28 | |
29 | |
30 | |
31 def read(filename): | |
32 """ | |
33 Reads and parses the program, checking for errors. | |
34 Returns: | |
35 (firstline, program) | |
36 firstline = line number of first program line | |
37 program = {linenum: (command_list, goto, deref_goto), ...} | |
38 linenum = line number | |
39 command_list = [(instr, x, deref_x, y, deref_y, ifjump, deref_if), ...] | |
40 instr = instruction, one of: =, +, -, |, ?, $, #, <, ~ | |
41 x = x value | |
42 deref_x = number of times x value should be deref'd, or 0 | |
43 y = y value | |
44 deref_y = number of times y value should be deref'd, or 0 | |
45 ifjump = ifjump line number | |
46 deref_if = number of times ifjump value should be deref'd, or 0 | |
47 goto = jump line number | |
48 deref_goto = number of times goto value should be deref'd, or 0 | |
49 """ | |
50 fileline = 0 | |
51 program = {} | |
52 firstline = None | |
53 goto_list = [] | |
54 try: | |
55 infile = open(filename) | |
56 while True: | |
57 # read line | |
58 line = infile.readline() | |
59 fileline += 1 | |
60 if line == "": | |
61 break | |
62 | |
63 # strip comments | |
64 i = line.find("'") | |
65 if i >= 0: | |
66 line = line[0:i] | |
67 line = line.strip() | |
68 | |
69 # ignore blank lines | |
70 if len(line) < 1: | |
71 continue | |
72 | |
73 # get line number | |
74 i = line.find("[") | |
75 if i < 0: | |
76 print >> sys.stderr, "Error [line " + str(fileline) + "]: missing `['" | |
77 sys.exit(1) | |
78 try: | |
79 linenum = int(line[0:i].strip()) | |
80 linenum = int(linenum) | |
81 if linenum == 0: | |
82 raise ValueError | |
83 if firstline == None or linenum < firstline: | |
84 firstline = linenum | |
85 except ValueError: | |
86 print >> sys.stderr, "Error [line " + str(fileline) + "]: bad or missing line number `" + str(linenum) + "'" | |
87 sys.exit(1) | |
88 | |
89 # get command | |
90 line = line[i:] | |
91 i = line.find("]") | |
92 if i < 0: | |
93 print >> sys.stderr, "Error [line " + str(fileline) + "]: missing `]'" | |
94 sys.exit(1) | |
95 command = line[1:i].strip() | |
96 if len(command) < 2: | |
97 print >> sys.stderr, "Error [line " + str(fileline) + "]: missing or invalid command" | |
98 sys.exit(1) | |
99 goto = line[i + 1:].strip() | |
100 | |
101 # parse commands | |
102 command_list = [] | |
103 commands = command.split(",") | |
104 for command in commands: | |
105 command = command.strip() | |
106 | |
107 # get x deref | |
108 deref_x = 0 | |
109 while len(command) > 0 and command[0] == "*": | |
110 deref_x += 1 | |
111 command = command[1:].strip() | |
112 | |
113 # find instruction | |
114 for c in "=+|>?^#$<~-": | |
115 i = command.find(c, 1) | |
116 if i >= 0: | |
117 instr = c | |
118 break | |
119 else: | |
120 print >> sys.stderr, "Error [line " + str(fileline) + "]: unrecognized command `" + command + "'" | |
121 sys.exit(1) | |
122 | |
123 # get x | |
124 x = command[0:i].strip() | |
125 command = command[i + 1:].strip() | |
126 try: | |
127 x = int(x) | |
128 except ValueError: | |
129 print >> sys.stderr, "Error [line " + str(fileline) + "]: bad x value `" + str(x) + "'" | |
130 sys.exit(1) | |
131 | |
132 # get y deref | |
133 deref_y = 0 | |
134 while len(command) > 0 and command[0] == "*": | |
135 deref_y += 1 | |
136 command = command[1:].strip() | |
137 | |
138 # get if jump | |
139 deref_if = 0 | |
140 if instr[0] == "<" or instr[0] == "~": | |
141 i = command.find(":") | |
142 if i < 0: | |
143 print >> sys.stderr, "Error [line " + str(fileline) + "]: missing if jump line number" | |
144 sys.exit(1) | |
145 ifjump = command[i + 1:].strip() | |
146 | |
147 # get ifjump deref | |
148 while len(ifjump) > 0 and ifjump[0] == "*": | |
149 deref_if += 1 | |
150 ifjump = ifjump[1:].strip() | |
151 | |
152 command = command[0:i].strip() | |
153 try: | |
154 ifjump = int(ifjump) | |
155 except ValueError: | |
156 print >> sys.stderr, "Error [line " + str(fileline) + "]: bad if jump line number `" + str(ifjump) + "'" | |
157 sys.exit(1) | |
158 if deref_if == 0: | |
159 goto_list += [(ifjump, fileline)] | |
160 else: | |
161 ifjump = None | |
162 | |
163 # get y | |
164 if instr[0] != "?" and instr[0] != "^" and instr[0] != "#" and instr[0] != "$": | |
165 y = command.strip() | |
166 try: | |
167 y = int(y) | |
168 except ValueError: | |
169 print >> sys.stderr, "Error [line " + str(fileline) + "]: bad y value `" + str(y) + "'" | |
170 sys.exit(1) | |
171 else: | |
172 y = None | |
173 if deref_y: | |
174 print >> sys.stderr, "Error [line " + str(fileline) + "]: bad dereference" | |
175 sys.exit(1) | |
176 | |
177 # add command to command list | |
178 command_list += [(instr, x, deref_x, y, deref_y, ifjump, deref_if)] | |
179 | |
180 # get goto line number | |
181 deref_goto = 0 | |
182 while len(goto) > 0 and goto[0] == "*": | |
183 deref_goto += 1 | |
184 goto = goto[1:].strip() | |
185 if len(goto) < 1: | |
186 print >> sys.stderr, "Error [line " + str(fileline) + "]: missing jump line number" | |
187 sys.exit(1) | |
188 try: | |
189 goto = int(goto) | |
190 except ValueError: | |
191 print >> sys.stderr, "Error [line " + str(fileline) + "]: bad jump line number `" + str(goto) + "'" | |
192 sys.exit(1) | |
193 if deref_goto == 0: | |
194 goto_list += [(goto, fileline)] | |
195 | |
196 # add line to program dictionary | |
197 try: | |
198 program[linenum] | |
199 print >> sys.stderr, "Error [line " + str(fileline) + "]: duplicate line number `" + str(linenum) + "'" | |
200 sys.exit(1) | |
201 except KeyError: | |
202 program[linenum] = (command_list, goto, deref_goto) | |
203 | |
204 infile.close() | |
205 except IOError, e: | |
206 print >> sys.stderr, "Error reading program: " + str(e) | |
207 sys.exit(1) | |
208 | |
209 # check that there was at least one program line | |
210 if firstline == None: | |
211 print >> sys.stderr, "Error: Program must have at least one command" | |
212 sys.exit(1) | |
213 | |
214 # check that all jumps are to valid line numbers | |
215 for goto, fileline in goto_list: | |
216 if goto != 0 and not program.has_key(goto): | |
217 print >> sys.stderr, "Error [line " + str(fileline) + "]: jump to undefined line number `" + str(goto) + "'" | |
218 sys.exit(1) | |
219 goto_list = None | |
220 | |
221 return (firstline, program) | |
222 | |
223 | |
224 | |
225 | |
226 def get_cell(index): | |
227 """ | |
228 Returns the cell value at the specified index, or 0 if the cell is | |
229 unused. | |
230 """ | |
231 if glo_memory.has_key(index): | |
232 return glo_memory[index] | |
233 else: | |
234 return 0 | |
235 | |
236 | |
237 | |
238 | |
239 def set_cell(index, value): | |
240 """ | |
241 Sets the value of the cell at the specified index. | |
242 """ | |
243 glo_memory[index] = value | |
244 | |
245 | |
246 | |
247 | |
248 def interpret((firstline, program)): | |
249 """ | |
250 Interprets the given Linguine program | |
251 """ | |
252 line = firstline | |
253 index = 0 | |
254 while line > 0: | |
255 # get the current command | |
256 commands = program[line][0] | |
257 command = commands[index] | |
258 instr = command[0] | |
259 x = command[1] | |
260 for i in xrange(command[2]): | |
261 x = get_cell(x) | |
262 y = command[3] | |
263 for i in xrange(command[4]): | |
264 y = get_cell(y) | |
265 ifjump = command[5] | |
266 for i in xrange(command[6]): | |
267 ifjump = get_cell(ifjump) | |
268 if ifjump != None and ifjump != 0 and not program.has_key(ifjump): | |
269 print >> sys.stderr, "Runtime error [line number " + str(line) + "]: bad ifjump line number `" + str(ifjump) + "'" | |
270 sys.exit(1) | |
271 if index + 1 >= len(commands): | |
272 goto = program[line][1] | |
273 for i in xrange(program[line][2]): | |
274 goto = get_cell(goto) | |
275 if goto != 0 and not program.has_key(goto): | |
276 print >> sys.stderr, "Runtime error [line number " + str(line) + "]: bad jump line number `" + str(goto) + "'" | |
277 sys.exit(1) | |
278 line = goto | |
279 index = 0 | |
280 else: | |
281 index += 1 | |
282 | |
283 # execute instruction | |
284 if instr == "=": | |
285 set_cell(x, y) | |
286 elif instr == "+": | |
287 set_cell(x, get_cell(x) + y) | |
288 elif instr == "-": | |
289 set_cell(x, get_cell(x) - y) | |
290 elif instr == "|": | |
291 set_cell(x, ~(get_cell(x) & y)) | |
292 elif instr == ">": | |
293 if y < 0: | |
294 set_cell(x, get_cell(x) * (2**(-y))) | |
295 else: | |
296 set_cell(x, get_cell(x) >> y) | |
297 elif instr == "?": | |
298 ch = sys.stdin.read(1) | |
299 if len(ch) < 1: | |
300 ch = -1 | |
301 else: | |
302 ch = ord(ch) | |
303 set_cell(x, ch) | |
304 elif instr == "^": | |
305 set_cell(x, int(time.time())) | |
306 elif instr == "$": | |
307 sys.stdout.write(chr(get_cell(x) & 255)) | |
308 sys.stdout.flush() | |
309 elif instr == "#": | |
310 sys.stdout.write(str(get_cell(x))) | |
311 sys.stdout.flush() | |
312 elif instr == "<" and get_cell(x) < y: | |
313 line = ifjump | |
314 index = 0 | |
315 elif instr == "~" and get_cell(x) == y: | |
316 line = ifjump | |
317 index = 0 | |
318 | |
319 | |
320 | |
321 | |
322 def main(): | |
323 """ | |
324 Processes the command line, reads the program, and starts the Linguine | |
325 interpreter. | |
326 """ | |
327 (options, args) = OptionParser(usage="linguine.py [options] program", \ | |
328 version=VERSION, \ | |
329 description="Interprets the specified Linguine program.").parse_args() | |
330 if len(args) < 1: | |
331 print >> sys.stderr, "Missing program filename." | |
332 sys.exit(1) | |
333 elif len(args) > 1: | |
334 print >> sys.stderr, "Too many filenames given." | |
335 sys.exit(1) | |
336 interpret(read(args[0])) | |
337 | |
338 | |
339 | |
340 | |
341 if __name__ == "__main__": | |
342 main() | |
343 |