""" StackLang v0.0.1.1 Copyright 2008 Paul Bonser < pib@paulbonser.com > 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, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . """ # Built-in words # math words def plus(i): i.stack.append(i.stack.pop()+i.stack.pop()) def minus(i): i.stack[-2:] = [i.stack[-2] - i.stack[-1]] def mul(i): i.stack.append(i.stack.pop()*i.stack.pop()) def div(i): i.stack[-2:] = [i.stack[-2] / i.stack[-1]] #comparison words def lt(i): i.stack[-2:] = [int(i.stack[-2] < i.stack[-1])] def gt(i): i.stack[-2:] = [i.stack[-2] > i.stack[-1]] def lte(i): i.stack[-2:] = [i.stack[-2] <= i.stack[-1]] def gte(i): i.stack[-2:] = [i.stack[-2] >= i.stack[-1]] def eq(i): i.stack[-2:] = [i.stack[-2] == i.stack[-1]] def neq(i): i.stack[-2:] = [i.stack[-2] != i.stack[-1]] # stack manipulation words def dup(i): i.stack.append(i.stack[-1]) def swap(i): i.stack[-2:] = [i.stack[-1], i.stack[-2]] def pop(i): i.stack.pop() # i/o words def echo(i): print i.stack.pop(), def echo_nl(i): print i.stack.pop() def read_int(i): i.stack.append(int(raw_input())) def read_string(i): i.stack.append(raw_input()) def dot(i): print i.stack # other def ifthen(i): """If the second from top item is true (1), then runs the top item and pushes a 1 to the stack. Otherwise, just pushes a 0 to the stack. If you aren't going to use an else statement with this, you'll need to pop the return value out of your way. """ expr = i.stack.pop() bool = i.stack.pop() if bool: i.run(expr) i.stack.append(1) else: i.stack.append(0) def ifelse(i): """If the second from the top item on the stack is false, run the top item on the stack. otherwise don't. This can be used as the else portion of an if-else statement. """ def add_word(i): expr = i.stack.pop() name = i.stack.pop() i.words[name] = lambda i: i.run(expr) builtins = { '+': plus, '-': minus, '*': mul, '/': div, 'dup': dup, 'swap': swap, 'echo': echo, 'echo_nl': echo_nl, 'pop': pop, '<': lt, '>': gt, '<=': lte, '>=': gte, '=': eq, '!=': neq, 'read_int': read_int, 'read_string': read_string, '.': dot, 'add_word': add_word, 'if': ifthen, 'else': ifelse } class Interpreter: def __init__(self): self.stack = [] self.words = builtins def eval(self, expr_str): parser = Parser(expr_str) expr = parser.parse() self.run(expr) def run(self, expr): for i in expr: if isinstance(i, Word): self.words[i](self) else: self.stack.append(i) class Word (str): pass # a class to differentiate words from strings class Parser: whitespace = set(" \t\n") string_delimiters = set('\'"') numerals = set('0123456789') white_and_sub = whitespace | set('}') def __init__(self, to_parse=''): self.in_str = to_parse self.pos = 0 # current parsing position self.len = len(to_parse) def skip_whitespace(self): while self.pos < self.len and self.in_str[self.pos] in self.whitespace: self.pos += 1 def read_to(self, delim, escape=False): start = self.pos while self.pos < self.len and self.in_str[self.pos] not in delim: if escape and self.in_str[self.pos] == '\\' and self.in_str[self.pos+1] == delim: self.pos += 2 else: self.pos += 1 return self.in_str[start:self.pos] def parse(self): """ Reads an expression made up of space separated numbers, strings, "words", and sub-expressions """ expr = [[]] while self.pos < self.len: self.skip_whitespace() #print 'expr:', expr, ', current:', "'"+self.in_str[self.pos]+"'", ', rest:', self.in_str[self.pos:] char = self.in_str[self.pos] if char in self.string_delimiters: self.pos += 1 expr[-1].append(self.read_to(char, escape=True)) self.pos += 1 elif char in self.numerals: expr[-1].append(eval(self.read_to(self.white_and_sub))) elif char == '{': # start a new sub_expression self.pos += 1 expr.append([]) elif char == '}': # append the sub_expression to the expression above it self.pos +=1 sub_expr = expr.pop() expr[-1].append(sub_expr) else: word = self.read_to(self.white_and_sub) expr[-1].append(Word(word)) return expr[0] if __name__ == "__main__": i = Interpreter() while True: try: input = raw_input('> ') except EOFError: break if input == 'quit': break else: i.eval(input)