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