Mercurial > repo
view interps/linguine/linguine.py @ 12514:500486b20e41 draft default tip
<int-e> slwd fungot//s/ds/d s/
author | HackEso <hackeso@esolangs.org> |
---|---|
date | Fri, 27 Sep 2024 20:43:06 +0100 |
parents | 859f9b4339e6 |
children |
line wrap: on
line source
#! /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()