Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #################
- # arborealis.py #
- #################
- ## Interpreter written by Maharba for the Esolang wiki
- ## 14 Jun 2011 - 15 Jun 2011
- ###
- # For the Arborealis language specification, see
- # http://esoteric.voxelperfect.net/wiki/Arborealis
- #
- # The Arborealis language was designed by DocHerrings
- ###
- ###
- # Command line usage:
- # python arborealis.py program.arb
- ###
- import sys
- class ArborealisError(Exception):
- """For errors processing or running Arborealis code.
- """
- pass
- # Global variables `current` and `root`
- # for the current and root nodes of the tree
- current = root = None
- # Now a placeholder to be initialized in the `run` function
- class Node(object):
- r"""A node of the binary tree.
- Can be initialized with a given `parent`, otherwise
- it is the root node and its own parent.
- Has an integer `val` and `Node` children `leftc` and `rightc`.
- The `val` starts at `0` and both children at `None`.
- Supports the following methods:
- Internal Name Character Command Name
- `newlchild` / Left Child Create
- `newrchild` \ Right Child Create
- `movel` < Move to Left Child
- `mover` > Move to Right Child
- `condl` ! Conditional Left Move
- `condr` ? Conditional Right Move
- `incr` + Increment
- `decr` - Decrement
- `toroot` ~ Go to Root
- `lparadox` ( Left Paradox
- `rparadox` ) Right Paradox
- `checkl` { Check for Left Child
- `checkr` } Check for Right Child
- `outp` . Output
- `inpu` , Input
- See their individual docstrings or the Arborealis spec for descriptions.
- Also has the method `getval` which returns current node value.
- """
- def __init__(self, parent=None):
- """Create the node.
- If no `parent` is given, becomes the root node.
- """
- if not parent: parent = self
- self.val, self.parent, self.leftc, self.rightc = 0, parent, None, None
- def newlchild(self):
- """Create a new left child node if it does not exist.
- """
- if not self.leftc:
- self.leftc = Node(self)
- def newrchild(self):
- """Create a new right child node if it does not exist.
- """
- if not self.rightc:
- self.rightc = Node(self)
- def movel(self):
- """Move to the left child if it exists.
- Sets the global `current` variable to the left child.
- """
- global current
- if self.leftc:
- current = self.leftc
- def mover(self):
- """Move to the right child if it exists.
- Sets the global `current variable to the right child.
- """
- global current
- if self.rightc:
- current = self.rightc
- def condl(self):
- """Conditional left move.
- Tries the following actions in order until one succeeds:
- If the left child does not exist, create and move to it.
- If the current value is 0, move to the left child.
- If the right child does not exist, create and move to it.
- If the current value is not 0, move to the right child.
- """
- if not self.leftc:
- self.newlchild()
- self.movel()
- elif not self.val:
- self.movel()
- elif not self.rightc:
- self.newrchild()
- self.mover()
- elif self.val:
- self.mover()
- def condr(self):
- """Conditional right move.
- Tries the following actions in order until one succeeds:
- If the right child does not exist, create and move to it.
- If the current value is 0, move to the right child.
- If the left child does not exist, create and move to it.
- If the current value is not 0, move to the left child.
- """
- if not self.rightc:
- self.newrchild()
- self.mover()
- elif not self.val:
- self.mover()
- elif not self.leftc:
- self.newlchild()
- self.movel()
- elif self.val:
- self.movel()
- def incr(self):
- """Increment the current value.
- Wraps around at 256 to 0.
- """
- self.val += 1
- self.val %= 256
- def decr(self):
- """Decrement the current value.
- Wraps around at -1 to 255.
- """
- self.val -= 1
- self.val %= 256
- def toroot(self):
- """Moves to the root node.
- Sets the global `current` to the global `root`.
- This is not node-specific, but easier to implement as a node method.
- """
- global current
- current = root
- def lparadox(self):
- """Left paradox creation.
- If the left child does not exist,
- sets it to the parent of the current node.
- This is not a copy: moving to the left child is equivalent
- to moving to the parent.
- """
- if not self.leftc:
- self.leftc = self.parent
- def rparadox(self):
- """"Right paradox creation.
- If the right child does not exist,
- sets it to the parent of the current node.
- This is not a copy: moving to the right child is equivalent
- to moving to the parent.
- """
- if not self.rightc:
- self.rightc = self.parent
- def checkl(self):
- """Check for left child.
- Sets the current value to 1 if the left child exists, 0 otherwise.
- """
- self.val = int(bool(self.leftc))
- def checkr(self):
- """Check for right child.
- Sets the current value to 1 if the right child exists, 0 otherwise.
- """
- self.val = int(bool(self.rightc))
- def outp(self):
- """Outputs the current value as an ASCII character.
- Writes to stdout.
- """
- sys.stdout.write(chr(self.val))
- def inpu(self):
- """Inputs a character into the current value.
- Reads from stdin.
- Returns 0 on EOF.
- """
- i = sys.stdin.read(1)
- if i:
- self.val = ord(i) % 256
- else:
- self.val = 0
- def getval(self):
- """Utility method to get current value.
- Not an Arborealis command.
- """
- return self.val
- # The standard Arborealis commands,
- # mapped to their internal names.
- cmds = {'>': 'mover', '<': 'movel', '(': 'lparadox', ')': 'rparadox',
- '/': 'newlchild', '\\': 'newrchild', '{': 'checkl', '}': 'checkr',
- '+': 'incr', '-': 'decr', '!': 'condl', '?': 'condr', '~': 'toroot',
- '.': 'outp', ',': 'inpu'}
- # The Arborealis commands for beginnning and ending loops.
- loop_begin, loop_end = '[', ']'
- def parse(code, _top=True):
- """Parse Arborealis code into a list of commands.
- Loops are represented as nested lists.
- The `_top` argument is private and should not be set.
- """
- l = []
- if _top: code = list(code)
- while True:
- try:
- c = code.pop(0)
- except IndexError:
- break
- if c == loop_end:
- if _top:
- raise ArborealisError('Unmatched looping.')
- else:
- return l
- if c == loop_begin:
- l.append(parse(code, _top=False))
- continue
- if c not in cmds:
- continue
- l.append(c)
- if _top:
- return l
- else:
- raise ArborealisError('Unmatched looping.')
- def do_parsed(code):
- """Execute parsed Arborealis commands.
- """
- global current
- for cmd in code:
- if not isinstance(cmd, list):
- getattr(current, cmds[cmd])()
- else:
- while current.getval():
- do_parsed(cmd)
- def _flushinp():
- """Flush standard input.
- Clears any unread characters in sys.stdin.
- """
- sys.stdin.seek(0)
- def run(code):
- """Runs Arborealis code.
- Calls `parse` and `do_parsed`.
- Uses `_flushinp` to prevent some buffering problems.
- """
- global current
- global root
- current = root = Node()
- _flushinp()
- do_parsed(parse(code))
- _flushinp()
- def run_from_cmdline():
- """Run a program file from a command-line argument.
- The first item in `sys.argv` after this file will be
- treated as the name of a file containing an Arborealis program
- and run.
- Arborealis program files should have the extension `.arb`,
- but this is not enforced.
- """
- argv = sys.argv
- if len(argv) != 2:
- raise ArborealisError('Wrong number of command-line arguments.')
- try:
- with open(argv[1]) as prog:
- run(prog.read())
- except EnvironmentError as e:
- raise ArborealisError('Error opening program file: '+e.message)
- if __name__ == '__main__':
- run_from_cmdline()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement