""" 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 <http://www.gnu.org/licenses/>.
"""

# 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)