Mercurial > repo
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/interps/linguine/linguine.py Sun Dec 09 19:30:08 2012 +0000 @@ -0,0 +1,343 @@ +#! /usr/bin/env python + +""" +Linguine programming language interpreter +Copyright (c) 2005 by Jeffry Johnston + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as +published by the Free Software Foundation. See the file LICENSE +for more details. + +Version History: +1.00 November 24, 2005 Initial version +1.10 November 25, 2005 Added jump dereferencing +1.20 November 26, 2005 Added `>' instruction +1.21 November 26, 2005 Fix negative y on `>' bug +1.22 November 26, 2005 Fix >> big number bug +1.30 November 27, 2005 Added `^' instruction +""" + +import sys +import time +from optparse import OptionParser + +VERSION = "1.10" +glo_memory = {} + + + + +def read(filename): + """ + Reads and parses the program, checking for errors. + Returns: + (firstline, program) + firstline = line number of first program line + program = {linenum: (command_list, goto, deref_goto), ...} + linenum = line number + command_list = [(instr, x, deref_x, y, deref_y, ifjump, deref_if), ...] + instr = instruction, one of: =, +, -, |, ?, $, #, <, ~ + x = x value + deref_x = number of times x value should be deref'd, or 0 + y = y value + deref_y = number of times y value should be deref'd, or 0 + ifjump = ifjump line number + deref_if = number of times ifjump value should be deref'd, or 0 + goto = jump line number + deref_goto = number of times goto value should be deref'd, or 0 + """ + fileline = 0 + program = {} + firstline = None + goto_list = [] + try: + infile = open(filename) + while True: + # read line + line = infile.readline() + fileline += 1 + if line == "": + break + + # strip comments + i = line.find("'") + if i >= 0: + line = line[0:i] + line = line.strip() + + # ignore blank lines + if len(line) < 1: + continue + + # get line number + i = line.find("[") + if i < 0: + print >> sys.stderr, "Error [line " + str(fileline) + "]: missing `['" + sys.exit(1) + try: + linenum = int(line[0:i].strip()) + linenum = int(linenum) + if linenum == 0: + raise ValueError + if firstline == None or linenum < firstline: + firstline = linenum + except ValueError: + print >> sys.stderr, "Error [line " + str(fileline) + "]: bad or missing line number `" + str(linenum) + "'" + sys.exit(1) + + # get command + line = line[i:] + i = line.find("]") + if i < 0: + print >> sys.stderr, "Error [line " + str(fileline) + "]: missing `]'" + sys.exit(1) + command = line[1:i].strip() + if len(command) < 2: + print >> sys.stderr, "Error [line " + str(fileline) + "]: missing or invalid command" + sys.exit(1) + goto = line[i + 1:].strip() + + # parse commands + command_list = [] + commands = command.split(",") + for command in commands: + command = command.strip() + + # get x deref + deref_x = 0 + while len(command) > 0 and command[0] == "*": + deref_x += 1 + command = command[1:].strip() + + # find instruction + for c in "=+|>?^#$<~-": + i = command.find(c, 1) + if i >= 0: + instr = c + break + else: + print >> sys.stderr, "Error [line " + str(fileline) + "]: unrecognized command `" + command + "'" + sys.exit(1) + + # get x + x = command[0:i].strip() + command = command[i + 1:].strip() + try: + x = int(x) + except ValueError: + print >> sys.stderr, "Error [line " + str(fileline) + "]: bad x value `" + str(x) + "'" + sys.exit(1) + + # get y deref + deref_y = 0 + while len(command) > 0 and command[0] == "*": + deref_y += 1 + command = command[1:].strip() + + # get if jump + deref_if = 0 + if instr[0] == "<" or instr[0] == "~": + i = command.find(":") + if i < 0: + print >> sys.stderr, "Error [line " + str(fileline) + "]: missing if jump line number" + sys.exit(1) + ifjump = command[i + 1:].strip() + + # get ifjump deref + while len(ifjump) > 0 and ifjump[0] == "*": + deref_if += 1 + ifjump = ifjump[1:].strip() + + command = command[0:i].strip() + try: + ifjump = int(ifjump) + except ValueError: + print >> sys.stderr, "Error [line " + str(fileline) + "]: bad if jump line number `" + str(ifjump) + "'" + sys.exit(1) + if deref_if == 0: + goto_list += [(ifjump, fileline)] + else: + ifjump = None + + # get y + if instr[0] != "?" and instr[0] != "^" and instr[0] != "#" and instr[0] != "$": + y = command.strip() + try: + y = int(y) + except ValueError: + print >> sys.stderr, "Error [line " + str(fileline) + "]: bad y value `" + str(y) + "'" + sys.exit(1) + else: + y = None + if deref_y: + print >> sys.stderr, "Error [line " + str(fileline) + "]: bad dereference" + sys.exit(1) + + # add command to command list + command_list += [(instr, x, deref_x, y, deref_y, ifjump, deref_if)] + + # get goto line number + deref_goto = 0 + while len(goto) > 0 and goto[0] == "*": + deref_goto += 1 + goto = goto[1:].strip() + if len(goto) < 1: + print >> sys.stderr, "Error [line " + str(fileline) + "]: missing jump line number" + sys.exit(1) + try: + goto = int(goto) + except ValueError: + print >> sys.stderr, "Error [line " + str(fileline) + "]: bad jump line number `" + str(goto) + "'" + sys.exit(1) + if deref_goto == 0: + goto_list += [(goto, fileline)] + + # add line to program dictionary + try: + program[linenum] + print >> sys.stderr, "Error [line " + str(fileline) + "]: duplicate line number `" + str(linenum) + "'" + sys.exit(1) + except KeyError: + program[linenum] = (command_list, goto, deref_goto) + + infile.close() + except IOError, e: + print >> sys.stderr, "Error reading program: " + str(e) + sys.exit(1) + + # check that there was at least one program line + if firstline == None: + print >> sys.stderr, "Error: Program must have at least one command" + sys.exit(1) + + # check that all jumps are to valid line numbers + for goto, fileline in goto_list: + if goto != 0 and not program.has_key(goto): + print >> sys.stderr, "Error [line " + str(fileline) + "]: jump to undefined line number `" + str(goto) + "'" + sys.exit(1) + goto_list = None + + return (firstline, program) + + + + +def get_cell(index): + """ + Returns the cell value at the specified index, or 0 if the cell is + unused. + """ + if glo_memory.has_key(index): + return glo_memory[index] + else: + return 0 + + + + +def set_cell(index, value): + """ + Sets the value of the cell at the specified index. + """ + glo_memory[index] = value + + + + +def interpret((firstline, program)): + """ + Interprets the given Linguine program + """ + line = firstline + index = 0 + while line > 0: + # get the current command + commands = program[line][0] + command = commands[index] + instr = command[0] + x = command[1] + for i in xrange(command[2]): + x = get_cell(x) + y = command[3] + for i in xrange(command[4]): + y = get_cell(y) + ifjump = command[5] + for i in xrange(command[6]): + ifjump = get_cell(ifjump) + if ifjump != None and ifjump != 0 and not program.has_key(ifjump): + print >> sys.stderr, "Runtime error [line number " + str(line) + "]: bad ifjump line number `" + str(ifjump) + "'" + sys.exit(1) + if index + 1 >= len(commands): + goto = program[line][1] + for i in xrange(program[line][2]): + goto = get_cell(goto) + if goto != 0 and not program.has_key(goto): + print >> sys.stderr, "Runtime error [line number " + str(line) + "]: bad jump line number `" + str(goto) + "'" + sys.exit(1) + line = goto + index = 0 + else: + index += 1 + + # execute instruction + if instr == "=": + set_cell(x, y) + elif instr == "+": + set_cell(x, get_cell(x) + y) + elif instr == "-": + set_cell(x, get_cell(x) - y) + elif instr == "|": + set_cell(x, ~(get_cell(x) & y)) + elif instr == ">": + if y < 0: + set_cell(x, get_cell(x) * (2**(-y))) + else: + set_cell(x, get_cell(x) >> y) + elif instr == "?": + ch = sys.stdin.read(1) + if len(ch) < 1: + ch = -1 + else: + ch = ord(ch) + set_cell(x, ch) + elif instr == "^": + set_cell(x, int(time.time())) + elif instr == "$": + sys.stdout.write(chr(get_cell(x) & 255)) + sys.stdout.flush() + elif instr == "#": + sys.stdout.write(str(get_cell(x))) + sys.stdout.flush() + elif instr == "<" and get_cell(x) < y: + line = ifjump + index = 0 + elif instr == "~" and get_cell(x) == y: + line = ifjump + index = 0 + + + + +def main(): + """ + Processes the command line, reads the program, and starts the Linguine + interpreter. + """ + (options, args) = OptionParser(usage="linguine.py [options] program", \ + version=VERSION, \ + description="Interprets the specified Linguine program.").parse_args() + if len(args) < 1: + print >> sys.stderr, "Missing program filename." + sys.exit(1) + elif len(args) > 1: + print >> sys.stderr, "Too many filenames given." + sys.exit(1) + interpret(read(args[0])) + + + + +if __name__ == "__main__": + main() +