view bin/gs2.py @ 12254:616be78bd12e draft

<oerjan> revert
author HackEso <hackeso@esolangs.org>
date Fri, 06 Dec 2019 07:54:58 +0000
parents c989a1669243
children
line wrap: on
line source

# gs2 interpreter (version 0.2)
# (c) nooodl 2014

import copy
import inspect
import itertools as it
import math
import operator
import os
import random
import re
import string
import struct
import sys
import traceback

from collections import namedtuple
from fractions import gcd

Block = namedtuple('Block', 'code')
STRING_ENDS = '\x05\x06' + ''.join(map(chr, range(0x9b, 0xa0)))

DEBUG = False

def log(x):
    if not DEBUG: return
    line, name = inspect.stack()[1][2:4]
    sys.stderr.write('\x1b[36m%s:%d\x1b[34m: %r\x1b[0m\n' % (name, line, x))

def lcm(a, b):
    if (a, b) == (0, 0): return 0
    return abs(a * b) // gcd(a, b)

def product(xs):
    p = 1
    for x in xs:
        p *= x
    return p

def split(a, b, clean=False):
    res = [[]]
    lb = len(b)

    i = 0
    while i < len(a):
        if a[i:i + lb] == b:
            res.append([])
            i += lb
        else:
            res[-1].append(a[i])
            i += 1

    return filter(None, res) if clean else res

def join(a, b):
    res = []
    for i, x in enumerate(a):
        if i > 0:
            res.extend(b)
        res.extend(x if is_list(x) else [x])
    return res

def set_diff(a, b):
    res = []
    for i in a:
        if i not in b:
            res.append(i)
    return res

def set_and(a, b):
    res = []
    for i in a:
        if i in b:
            res.append(i)
    return res

def set_or(a, b):
    return a + set_diff(b, a)

def set_xor(a, b):
    return set_diff(a, b) + set_diff(b, a)

# prime number functions
prime_list = []
sieved = 2
composite = set([1])

def sieve(limit):
    global prime_list
    global sieved
    global composite
    if limit <= sieved: return

    prime_list = []
    for i in range(2, limit):
        if i in composite: continue
        for j in range(i*i, limit, i):
            composite.add(j)
        prime_list.append(i)
    sieved = limit

sieve(1000)

def is_prime(n):
    global prime_list
    sieve(n+1)
    return n not in composite

def nth_prime(n):
    global prime_list
    sieve(int(math.log(n) * n) + 100)
    return prime_list[n-1]

def n_primes(n):
    global prime_list
    sieve(int(math.log(n) * n) + 100)
    return prime_list[:n]

def primes_below(n):
    global prime_list
    sieve(n+1)
    return list(it.takewhile(lambda x: x < n, prime_list))

def next_prime(n):
    n += 1
    while not is_prime(n): n += 1
    return n

def totient(n):
    count = 0
    for i in xrange(1, n+1):
        if gcd(n, i) == 1: count += 1
    return count
    
def factor(n, exps=False):
    if is_num(n):
        p = 2
        res = []
        while n > 1:
            while n % p == 0:
                res.append(p)
                n //= p
            p = next_prime(p)
        if exps:
            res = [[k, len(list(g))] for k, g in it.groupby(res)]
        return res
    elif is_list(n):
        if n and is_num(n[0]):
            n = zip(n[0::2], n[1::2])
        p = 1
        for b, e in n: p *= b ** e
        return p
    else:
        raise TypeError('factor')

def chunks(x, y):
    # chunks(range(12), 3) ==> [[0, 1, 2], [3, 4, 5], ...]
    while x:
        yield x[:y]
        x = x[y:]

def tokenize(prog):
    # string hack
    cs = STRING_ENDS
    if re.match('^[^\x04]*[%s]' % cs, prog):
        prog = '\x04' + prog
    
    mode = None
    if prog[0] in '\x30\x31\x32': # set mode
        mode = prog[0]
        prog = prog[1:]
    
    token_re = [
        '\x04[^%s]*[%s]' % (cs, cs), # string (array)
        '\x01.',                     # unsigned byte
        '\x02..',                    # signed short
        '\x03....',                  # signed long
        '\x07.',                     # 1 char string
        '.',                         # regular token
    ]

    tokens = re.findall('|'.join(token_re), prog, re.DOTALL)

    final = []
    blocks = [Block([])]
    i = 0 
    while i < len(tokens):
        t = tokens[i]
        log(tokens[i:])
        if t == '\x08': #= {
            blocks.append(Block([]))
            final.append('\x00')
        elif t == '\x09': #= }
            blocks[-2].code.append(blocks.pop())
            blocks[-1].code.append(final.pop())
        elif '\xe0' <= t <= '\xff' and ord(t) & 7 < 6:
            # quick block
            # 0b111XXYYY -- Y+1 is number of tokens, X is end token:
            #   0 = nop (0x00)  2 = filter (0x35)
            #   1 = map (0x34)  3 = both (0x38)
            # but 0xfe and 0xff are special (see below.)
            num = (ord(t) & 7) + 1
            ts = blocks[-1].code[-num:]
            del blocks[-1].code[-num:]
            blocks[-1].code.append(Block(ts))
            blocks[-1].code.append('\x00\x34\x35\x38'[(ord(t) >> 3) & 3])
        elif t in '\xee\xef': #= z1 zipwith1, z2 zipwith2
            # zipwith (1/2 tokens)
            num = (ord(t) & 1) + 1
            ts = blocks[-1].code[-num:]
            del blocks[-1].code[-num:]
            blocks[-1].code.append(Block(ts))
            blocks[-1].code.append('\xb1')
        elif t in '\xf6\xf7': #= dm1 dump-map1, df1 dump-filter1
            # like m1/f1 with dump prepended to block
            # useful with transpose, pairwise, cartesian-product, etc.
            f = {'\xf6': '\x34', '\xf7': '\x35'}[t]
            x = blocks[-1].code.pop()
            blocks[-1].code.extend([Block(['\x0e', x]), f])
        elif t == '\xfe': #= m:
            blocks.append(Block([]))
            final.append('\x34')
        elif t == '\xff': #= f:
            blocks.append(Block([]))
            final.append('\x35')
        else:
            blocks[-1].code.append(t)
        i += 1

    while final:
        blocks[-2].code.append(blocks.pop())
        blocks[-1].code.append(final.pop())
    
    assert len(blocks) == 1
    main = blocks[0]
    
    if mode == '\x30': #= line-mode
        main = Block(['\x2a', main, '\x34', '\x54'])
    elif mode == '\x31': #= word-mode
        main = Block(['\x2c', main, '\x34', '\x55'])
    elif mode == '\x32': #= line-mode-skip-first
        main = Block(['\x2a', '\x22', main, '\x34', '\x54'])
    
    main.code.extend(final)
    return main

is_num   = lambda v: isinstance(v, (int, long))
is_list  = lambda v: isinstance(v, list)
is_block = lambda v: isinstance(v, Block)

def to_gs(ps): return map(ord, ps)

def to_ps(gs):
    if is_list(gs): return ''.join(map(chr, gs))
    else: return chr(gs)
    
def regex_count(pattern):
    c = 0
    if pattern[0] == ']':
        c = 1
        pattern = pattern[1:]
    elif pattern[0] == '}':
        c = ord(pattern[1])
        pattern = pattern[2:]
    return (c, pattern)

def show(value, nest=False):
    if is_list(value):
        return ''.join(show(x, nest=True) for x in value)
    elif nest and is_num(value):
        return chr(value)
    else:
        return str(value)

class Stack(list):
    def __init__(self, *args):
        list.__init__(self, *args)
        self.junk = []
    def pop(self, i=-1, junk=True):
        x = list.pop(self, i)
        if junk: self.junk.append(x)
        return x

class GS2(object):
    def __init__(self, code, stdin=''):
        self.code = code
        self.stdin = to_gs(stdin)
        self.stack = Stack([self.stdin])
        self.regs = {
            0: to_gs(stdin),         # A
            1: len(stdin),           # B
            2: to_gs(code),          # C
            3: random.randint(0, 2), # D
        }
        self.counter = 1

    def run(self):
        try:
            self.evaluate(tokenize(self.code))
            sys.stdout.write(''.join(map(show, self.stack)))
        except Exception:
            # If the code fails, print something meaningful to stderr,
            # but quine on stdout: this allows GS2 to good at simple
            # "print this string" programs -- just upload a plaintext
            # file, it's unlikely to be valid GS2 code.
            traceback.print_exc()
            if not DEBUG: sys.stdout.write(self.code)

    def evaluate(self, block):
        log(block)
        for t in block.code:
            if is_block(t):
                self.stack.append(t)
            elif t[0] == '\x00': #= nop
                pass
            elif t[0] == '\x01': # push unsigned byte
                self.stack.append(struct.unpack('<B', t[1:])[0])
            elif t[0] == '\x02': # push signed short
                self.stack.append(struct.unpack('<h', t[1:])[0])
            elif t[0] == '\x03': # push signed long
                self.stack.append(struct.unpack('<l', t[1:])[0])

            elif t[0] == '\x04': # string
                assert len(t) >= 2
                assert t[-1] in STRING_ENDS
                strings = t[1:-1].split('\x07')
                strings = map(to_gs, strings)
                if t[-1] == '\x05': # regular
                    self.stack += strings
                elif t[-1] == '\x06': # array
                    self.stack.append(strings)
                elif t[-1] == '\x9b': # printf
                    f = to_ps(strings.pop())
                    n = f.count('%') - f.count('%%') * 2
                    x = tuple(map(to_ps, self.stack[-n:]))
                    del self.stack[-n:]
                    self.stack.append(to_gs(f % x))
                elif t[-1] == '\x9c': # regex match
                    pattern = to_ps(strings.pop())
                    c, pattern = regex_count(pattern)
                    s = to_ps(self.stack.pop())
                    f = re.match if c else re.search
                    self.stack.append(1 if f(pattern, s) else 0)
                elif t[-1] == '\x9d': # regex sub
                    repl = to_ps(strings.pop())
                    pattern = to_ps(strings.pop())
                    c, pattern = regex_count(pattern)
                    s = to_ps(self.stack.pop())
                    m = re.sub(pattern, repl, s, count=c)
                    self.stack.append(to_gs(m))
                elif t[-1] == '\x9e': # regex find
                    pattern = to_ps(strings.pop())
                    c, pattern = regex_count(pattern)
                    s = to_ps(self.stack.pop())
                    ms = re.findall(pattern, s)
                    if c > 0: ms = ms[0] if ms else []
                    self.stack.append(map(to_gs, ms))
                elif t[-1] == '\x9f': # regex split
                    pattern = to_ps(strings.pop())
                    c, pattern = regex_count(pattern)
                    s = to_ps(self.stack.pop())
                    m = re.split(pattern, s, maxsplit=c)
                    self.stack.append(map(to_gs, m))
                
            elif t[0] == '\x07': # single char string
                self.stack.append([ord(t[1])])

            # \x08 and \x09 are block syntax
            elif t == '\x0a': #= new-line
                self.stack.append([ord('\n')])
            elif t == '\x0b': #= empty-list
                self.stack.append([])
            elif t == '\x0c': #= empty-block
                self.stack.append(Block([]))
            elif t == '\x0d': #= space
                self.stack.append([ord(' ')])
            elif t == '\x0e': #= make-array extract-array dump
                x = self.stack.pop()
                if is_num(x):
                    self.stack[-x:] = [self.stack[-x:]]
                elif is_list(x):
                    for i in x:
                        self.stack.append(i)
                else:
                    raise TypeError('make-array / extract-array')

            elif t == '\x0f': #= exit
                break

            elif 0x10 <= ord(t[0]) <= 0x1a: # push small number
                self.stack.append(ord(t[0]) - 0x10)
            elif t == '\x1b': self.stack.append(100)
            elif t == '\x1c': self.stack.append(1000)
            elif t == '\x1d': self.stack.append(16)
            elif t == '\x1e': self.stack.append(64)
            elif t == '\x1f': self.stack.append(256)

            elif t == '\x20': #= negate reverse eval
                x = self.stack.pop()
                if is_num(x):
                    self.stack.append(-x)
                elif is_list(x):
                    self.stack.append(x[::-1])
                elif is_block(x):
                    self.evaluate(x)
                else:
                    raise TypeError('negate / reverse')

            elif t == '\x21': #= bnot head
                x = self.stack.pop()
                if is_num(x):
                    self.stack.append(~x)
                elif is_list(x):
                    self.stack.append(x[0])
                else:
                    raise TypeError('bitwise not / head')

            elif t == '\x22': #= not tail
                x = self.stack.pop()
                if is_num(x):
                    self.stack.append(0 if x else 1)
                elif is_list(x):
                    self.stack.append(x[1:])
                else:
                    raise TypeError('not / tail')

            elif t == '\x23': #= abs init
                x = self.stack.pop()
                if is_num(x):
                    self.stack.append(abs(x))
                elif is_list(x):
                    self.stack.append(x[:-1])
                else:
                    raise TypeError('abs / init')

            elif t == '\x24': #= digits last
                x = self.stack.pop()
                if is_num(x):
                    self.stack.append(map(int, str(abs(x))))
                elif is_list(x):
                    self.stack.append(x[-1])
                else:
                    raise ValueError('digits / last')

            elif t == '\x25': #= random
                x = self.stack.pop()
                if is_num(x):
                    self.stack.append(random.randrange(x))
                elif is_list(x):
                    self.stack.append(random.choice(x))
                else:
                    raise TypeError('random')

            elif t == '\x26': #= dec left-uncons
                x = self.stack.pop()
                if is_num(x):
                    self.stack.append(x - 1)
                elif is_list(x):
                    self.stack.append(x[1:])
                    self.stack.append(x[0])
                else:
                    raise TypeError('deincrement / left uncons')

            elif t == '\x27': #= inc right-uncons
                x = self.stack.pop()
                if is_num(x):
                    self.stack.append(x + 1)
                elif is_list(x):
                    self.stack.append(x[:-1])
                    self.stack.append(x[-1])
                else:
                    raise TypeError('increment / right uncons')

            elif t == '\x28': #= sign min
                x = self.stack.pop()
                if is_num(x):
                    self.stack.append(cmp(x, 0))
                elif is_list(x):
                    self.stack.append(min(x))
                else:
                    raise TypeError('sign / min')

            elif t == '\x29': #= thousand max
                x = self.stack.pop()
                if is_num(x):
                    self.stack.append(x * 1000)
                elif is_list(x):
                    self.stack.append(max(x))
                else:
                    raise TypeError('thousand / max')

            elif t == '\x2a': #= double lines
                x = self.stack.pop()
                if is_num(x):
                    self.stack.append(x * 2)
                elif is_list(x):
                    if x and x[-1] == ord('\n'):
                        x.pop()
                    self.stack.append(split(x, to_gs('\n')))
                else:
                    raise TypeError('double / line')

            elif t == '\x2b': #= half unlines
                x = self.stack.pop()
                if is_num(x):
                    self.stack.append(x // 2)
                elif is_list(x):
                    x = [to_gs(show(i)) for i in x]
                    self.stack.append(join(x, to_gs('\n')))
                else:
                    raise TypeError('half / unlines')

            elif t == '\x2c': #= square words
                x = self.stack.pop()
                if is_num(x):
                    self.stack.append(x * x)
                elif is_list(x):
                    self.stack.append(map(to_gs, to_ps(x).split()))
                else:
                    raise TypeError('square / words')

            elif t == '\x2d': #= sqrt unwords
                x = self.stack.pop()
                if is_num(x):
                    self.stack.append(int(math.sqrt(x)))
                elif is_list(x):
                    x = [to_gs(show(i)) for i in x]
                    self.stack.append(join(x, to_gs(' ')))
                else:
                    raise TypeError('sqrt / unwords')

            elif t == '\x2e': #= range length
                x = self.stack.pop()
                if is_num(x):
                    self.stack.append(range(x))
                elif is_list(x):
                    self.stack.append(len(x))
                else:
                    raise TypeError('range / length')

            elif t == '\x2f': #= range1 sort
                x = self.stack.pop()
                if is_num(x):
                    self.stack.append(range(1, x + 1))
                elif is_list(x):
                    self.stack.append(list(sorted(x)))
                elif is_block(x):
                    l = self.stack.pop()
                    def f(z):
                        self.stack.append(z)
                        self.evaluate(x)
                        return self.stack.pop(junk=False)
                    self.stack.append(list(sorted(l, key=f)))
                else:
                    raise TypeError('range1 / sort')

            elif t == '\x30': #= + add catenate
                y = self.stack.pop()
                x = self.stack.pop()
                if is_num(x) and is_num(y):
                    self.stack.append(x + y)
                elif is_list(x) and is_list(y):
                    self.stack.append(x + y)
                elif is_block(x) and is_block(y):
                    self.stack.append(Block(x.code + y.code))
                elif is_list(x) and not is_list(y):
                    self.stack.append(x + [y])
                elif not is_list(x) and is_list(y):
                    self.stack.append([x] + y)
                else:
                    raise TypeError('add / catenate')

            elif t == '\x31': #= - sub diff
                y = self.stack.pop()
                x = self.stack.pop()
                if is_num(x) and is_num(y):
                    self.stack.append(x - y)
                elif is_list(x) and is_list(y):
                    self.stack.append(set_diff(x, y))
                elif is_list(x) and not is_list(y):
                    self.stack.append(set_diff(x, [y]))
                elif not is_list(x) and is_list(y):
                    self.stack.append(set_diff(y, [x]))
                else:
                    raise TypeError('subtract / set diff')

            elif t == '\x32': #= * mul join times fold
                y = self.stack.pop()
                x = self.stack.pop()
                if is_num(x) and (is_block(y) or is_list(y)):
                    x, y = y, x
                if is_block(x) and is_list(y):
                    x, y = y, x

                if is_num(x) and is_num(y):
                    self.stack.append(x * y)
                elif is_list(x) and is_list(y):
                    self.stack.append(join(x, y))
                elif is_list(x) and is_num(y):
                    self.stack.append(x * y)
                elif is_block(x) and is_num(y):
                    for i in xrange(y):
                        self.evaluate(x)
                elif is_list(x) and is_block(y):
                    self.stack.append(x[0])
                    for i in x[1:]:
                        self.stack.append(i)
                        self.evaluate(y)
                else:
                    raise TypeError('multiply / join / times / fold')

            elif t == '\x33': #= / div chunks split each
                y = self.stack.pop()
                x = self.stack.pop()

                if not is_list(x) and is_list(y):
                    x, y = y, x

                if is_num(x) and is_num(y):
                    self.stack.append(x // y)
                elif is_list(x) and is_num(y):
                    self.stack.append(list(chunks(x, y)))
                elif is_list(x) and is_list(y):
                    self.stack.append(split(x, y))
                elif is_list(x) and is_block(y):
                    for i in x:
                        self.stack.append(i)
                        self.evaluate(y)
                else:
                    raise TypeError('divide / chunks / split / each')

            elif t == '\x34': #= % mod step clean-split map
                y = self.stack.pop()
                x = self.stack.pop()

                if not is_list(x) and is_list(y):
                    x, y = y, x

                if is_num(x) and is_num(y):
                    self.stack.append(x % y)
                elif is_list(x) and is_num(y):
                    self.stack.append(x[::y])
                elif is_list(x) and is_list(y):
                    self.stack.append(split(x, y, clean=True))
                elif is_list(x) and is_block(y):
                    self.eval_map(y, x)
                else:
                    raise TypeError('modulo / step / split\' / map')

            elif t == '\x35': #= & and get when filter
                y = self.stack.pop()
                x = self.stack.pop()

                if is_block(x) and is_num(y):
                    x, y = y, x
                if is_num(x) and is_list(y):
                    x, y = y, x
                if is_block(x) and is_list(y):
                    x, y = y, x

                if is_num(x) and is_num(y):
                    self.stack.append(x & y)
                elif is_list(x) and is_list(y):
                    self.stack.append(set_and(x, y))
                elif is_list(x) and is_num(y):
                    self.stack.append(x[y])
                elif is_num(x) and is_block(y):
                    if x: self.evaluate(y)
                elif is_list(x) and is_block(y):
                    self.eval_filter(y, x)
                else:
                    raise TypeError('and / get / when / filter')

            elif t == '\x36': #= | or unless
                y = self.stack.pop()
                x = self.stack.pop()

                if is_block(x) and is_num(y):
                    x, y = y, x

                if is_num(x) and is_num(y):
                    self.stack.append(x | y)
                elif is_list(x) and is_list(y):
                    self.stack.append(set_or(x, y))
                elif is_num(x) and is_block(y):
                    if not x: self.evaluate(y)
                else:
                    raise TypeError('bor / unless')

            elif t == '\x37': #= ^ xor concatmap
                y = self.stack.pop()
                x = self.stack.pop()

                if is_block(x) and is_list(y):
                    x, y = y, x

                if is_num(x) and is_num(y):
                    self.stack.append(x ^ y)
                elif is_list(x) and is_list(y):
                    self.stack.append(set_xor(x, y))
                elif is_list(x) and is_block(y):
                    res = []
                    for i in x:
                        self.stack.append(i)
                        self.evaluate(y)
                        res.extend(self.stack.pop(junk=False))
                    self.stack.append(res)
                else:
                    raise TypeError('xor / concatmap')

            elif t == '\x38': #= smallest both
                y = self.stack.pop()
                if is_block(y):
                    x = self.stack.pop()
                    self.evaluate(y)
                    self.stack.append(x)
                    self.evaluate(y)
                else:
                    x = self.stack.pop()
                    self.stack.append(min(x, y))

            elif t == '\x39': #= biggest
                y = self.stack.pop()
                x = self.stack.pop()
                self.stack.append(max(x, y))

            elif t == '\x3a': #= clamp
                z = self.stack.pop()
                y = self.stack.pop()
                x = self.stack.pop()
                self.stack.append(min(max(x, y), z))

            elif t == '\x3c': #= gcd take
                y = self.stack.pop()
                x = self.stack.pop()

                if is_num(x) and is_list(y):
                    x, y = y, x

                if is_num(x) and is_num(y):
                    self.stack.append(gcd(x, y))
                elif is_list(x) and is_num(y):
                    self.stack.append(x[:y])
                else:
                    raise TypeError('gcd / take')

            elif t == '\x3d': #= lcm drop
                y = self.stack.pop()
                x = self.stack.pop()

                if is_num(x) and is_list(y):
                    x, y = y, x

                if is_num(x) and is_num(y):
                    self.stack.append(lcm(x, y))
                elif is_list(x) and is_num(y):
                    self.stack.append(x[y:])
                else:
                    raise TypeError('lcm / drop')

            elif t == '\x3e': #= pow index
                y = self.stack.pop()
                x = self.stack.pop()

                if is_num(x) and is_list(y):
                    x, y = y, x

                if is_num(x) and is_num(y):
                    self.stack.append(x ** y)
                elif is_list(x) and is_num(y):
                    self.stack.append(x.index(y) if y in x else -1)
                else:
                    raise TypeError('power / index')

            elif t == '\x3f': #= log member
                y = self.stack.pop()
                x = self.stack.pop()
                
                if is_list(y):
                    x, y = y, x

                if is_num(x) and is_num(y):
                    self.stack.append(int(math.log(x, y)))
                elif is_list(x):
                    self.stack.append(1 if y in x else 0)
                else:
                    raise TypeError('log / member')

            elif t == '\x40': #= dup
                self.stack.append(self.stack[-1])
            elif t == '\x41': #= dup2
                self.stack.append(self.stack[-1])
                self.stack.append(self.stack[-1])
            elif t == '\x42': #= swap
                self.stack.append(self.stack.pop(-2))
            elif t == '\x43': #= rot
                self.stack.append(self.stack.pop(-3))
            elif t == '\x44': #= rrot
                self.stack.append(self.stack.pop(-3))
                self.stack.append(self.stack.pop(-3))
            elif t == '\x45': #= over
                self.stack.append(self.stack[-2])
            elif t == '\x46': #= nip
                self.stack.pop(-2)
            elif t == '\x47': #= tuck
                self.stack.insert(-2, self.stack[-1])
            elif t == '\x48': #= 2dup
                self.stack.append(self.stack[-2])
                self.stack.append(self.stack[-2])
            elif t == '\x49': #= pick
                n = self.stack.pop()
                self.stack.append(self.stack[-n])
            elif t == '\x4a': #= roll
                n = self.stack.pop()
                self.stack.append(self.stack.pop(-n))
            elif t == '\x4b': #= wrap-stack
                self.stack = [copy.deepcopy(self.stack)]
            elif t == '\x4c': #= leave-top
                del self.stack[:-1]
            elif t == '\x4d': #= itemize
                self.stack.append([self.stack.pop()])
            elif t == '\x4e': #= rrange
                x = self.stack.pop()
                self.stack.append(range(x)[::-1])
            elif t == '\x4f': #= crange
                y = self.stack.pop()
                x = self.stack.pop()
                if x > y: x, y = y, x
                self.stack.append(range(x, y))
            elif t == '\x50': #= pop
                self.stack.pop()
            elif t == '\x51': #= pop2
                self.stack.pop()
                self.stack.pop()
            elif t == '\x52': #= show
                x = self.stack.pop()
                self.stack.append(to_gs(show(x)))
            elif t == '\x53': #= map-show
                x = self.stack.pop()
                self.stack.append(map(to_gs, map(show, x)))
            elif t == '\x54': #= show-lines
                x = self.stack.pop()
                self.stack.append(to_gs('\n'.join(map(show, x))))
            elif t == '\x55': #= show-words
                x = self.stack.pop()
                self.stack.append(to_gs(' '.join(map(show, x))))
            elif t in '\x56\x57': #= read-num, read-nums
                x = to_ps(self.stack.pop())
                nums = map(int, re.findall(r'-?\d+', x))
                self.stack.append(nums[0] if t == '\x56' else nums)
            elif t == '\x58': #= show-line
                x = self.stack.pop()
                self.stack.append(to_gs(show(x) + '\n'))
            elif t == '\x59': #= show-space
                x = self.stack.pop()
                self.stack.append(to_gs(show(x) + ' '))
            elif t == '\x5a': #= show-comma
                x = self.stack.pop()
                self.stack.append(to_gs(', '.join(map(show, x))))
            elif t == '\x5b': #= show-python
                x = self.stack.pop()
                self.stack.append(to_gs(', '.join(map(show, x)).join('[]')))
            elif t in '\x5c\x5d\x5e': #= ljust, center, rjust
                fill = ' ' 
                if is_num(self.stack[-2]):
                    fill = chr(self.stack.pop())
                width = self.stack.pop()
                s = self.stack.pop()
                if t == '\x5c': g = show(s).ljust(width, fill)
                if t == '\x5d': g = show(s).center(width, fill)
                if t == '\x5e': g = show(s).rjust(width, fill)
                self.stack.append(to_gs(g))
            elif t == '\x5f': #= inspect
                self.stack.append(to_gs(repr(self.stack.pop())))
            elif t == '\x60': #= logical-and
                y = self.stack.pop()
                x = self.stack.pop()
                self.stack.append(x and y)
            elif t == '\x61': #= logical-or
                y = self.stack.pop()
                x = self.stack.pop()
                self.stack.append(x or y)
            elif t == '\x62': #= divides left-cons
                y = self.stack.pop()
                x = self.stack.pop()
                if is_num(x):
                    self.stack.append(0 if x % y else 1)
                elif is_list(x):
                    self.stack.append([y] + x)
                else:
                    raise TypeError('divides / left-cons')
            elif t == '\x63': #= divmod group
                y = self.stack.pop()
                if is_num(y):
                    x = self.stack.pop()
                    self.stack.append(x // y)
                    self.stack.append(x % y)
                elif is_list(y):
                    gb = [list(g) for k, g in it.groupby(y)]
                    self.stack.append(list(gb))
                else:
                    raise TypeError('divmod / group')
            elif t == '\x64': #= sum even
                x = self.stack.pop()
                if is_num(x):
                    self.stack.append(1 if x % 2 == 0 else 0)
                elif is_list(x):
                    self.stack.append(sum(x))
            elif t == '\x65': #= product odd
                x = self.stack.pop()
                if is_num(x):
                    self.stack.append(1 if x % 2 == 1 else 0)
                elif is_list(x):
                    self.stack.append(product(x))
            elif t == '\x66': #= fizzbuzz
                fizzbuzz = []
                for i in range(1, 101):
                    s = ("Fizz" if i % 3 == 0 else "") + \
                        ("Buzz" if i % 5 == 0 else "")
                    fizzbuzz.append(s or str(i))
                self.stack.append(to_gs('\n'.join(fizzbuzz)))
            elif t == '\x67': #= popcnt right-cons
                x = self.stack.pop()
                if is_num(x):
                    x = abs(x)
                    p = 0
                    while x:
                        p += (x & 1)
                        x >>= 1
                    self.stack.append(p)
                elif is_list(x):
                    y = self.stack.pop()
                    self.stack.append(x + [y])
            elif t == '\x68': #= hello
                x = 0
                if len(self.stack) >= 1 and is_num(self.stack[-1]):
                    x = self.stack.pop()
                    x = (range(0, 11) + [100, 1000, 16, 64, 256]).index(x)
                s1 = 'h' if x & 1 else 'H'
                s2 = 'W' if x & 2 else 'w'
                s3 = ['!', '', '.', '...'][((x & 4) >> 2) | ((x & 16) >> 3)]
                s4 = '' if x & 8 else ','
                f = '%sello%s %sorld%s' % (s1, s4, s2, s3)
                self.stack.append(to_gs(f))
            elif t in '\x69\x6a': #= base, binary
                b = 2 if t == '\x6a' else self.stack.pop()
                x = self.stack.pop()
                if is_num(x):
                    x = abs(x)
                    res = []
                    while x:
                        res.append(x % b)
                        x //= b
                    self.stack.append(res[::-1])
                elif is_list(x):
                    res = 0
                    for i in x:
                        res = res * b + i
                    self.stack.append(res)
                else:
                    raise TypeError('base / binary')
            elif t == '\x6b': #= is-prime
                x = self.stack.pop()
                if is_num(x):
                    self.stack.append(1 if is_prime(x) else 0)
                elif is_list(x):
                    self.stack.append(filter(is_prime, x))
                else:
                    raise TypeError('is-prime')
            elif t == '\x6c': #= primes
                op = self.stack.pop()
                x = self.stack.pop()
                if op == 0:   self.stack.append(n_primes(x))
                elif op == 1: self.stack.append(primes_below(x))
                elif op == 2: self.stack.append(next_prime(x))
                elif op == 3: self.stack.append(totient(x))
                elif op == 4: self.stack.append(factor(x, exps=False))
                elif op == 5: self.stack.append(factor(x, exps=True))
            elif t == '\x6d': #= scan
                f = self.stack.pop()
                def call_f(x, y):
                    self.stack.append(x)
                    self.stack.append(y)
                    self.evaluate(f)
                    return self.stack.pop()
                xs = self.stack.pop()
                res = [xs.pop(0)]
                while xs:
                    res.append(call_f(res[-1], xs.pop(0)))
                self.stack.append(res)
            elif t in '\x70\x71\x72\x73\x74\x75': #= lt <, eq =, gt >, ge >=, ne !=, le <=
                y = self.stack.pop()
                x = self.stack.pop()
                ops = {
                    '\x70': operator.lt,
                    '\x71': operator.eq,
                    '\x72': operator.gt,
                    '\x73': operator.ge,
                    '\x74': operator.ne,
                    '\x75': operator.le,
                }
                self.stack.append(1 if ops[t](x, y) else 0)
            elif t == '\x76': #= cmp
                y = self.stack.pop()
                x = self.stack.pop()
                self.stack.append(cmp(x, y))
            elif t == '\x77': #= is-sorted
                x = self.stack.pop()
                if is_list(x):
                    self.stack.append(1 if x == list(sorted(x)) else 0)
                elif is_block(x):
                    l = self.stack.pop()
                    def f(z):
                        self.stack.append(z)
                        self.evaluate(x)
                        return self.stack.pop()
                    sorted_l = list(sorted(l, key=f))
                    self.stack.append(1 if l == sorted_l else 0)
                else:
                    raise TypeError('sorted')
            elif t == '\x78': #= shift-left inits
                y = self.stack.pop()
                if is_list(y):
                    inits = []
                    for i in xrange(len(y) + 1):
                        inits.append(y[:i])
                    self.stack.append(inits)
                else:
                    x = self.stack.pop()
                    self.stack.append(x << y)
            elif t == '\x79': #= shift-right tails
                y = self.stack.pop()
                if is_list(y):
                    tails = []
                    for i in xrange(len(y) + 1):
                        tails.append(y[len(y)-i:])
                    self.stack.append(tails)
                else:
                    x = self.stack.pop()
                    self.stack.append(x >> y)
            elif t == '\x7a': #= digit-left enumerate
                y = self.stack.pop()
                if is_list(y):
                    self.stack.append(list(map(list, enumerate(y))))
                else:
                    x = self.stack.pop()
                    self.stack.append(x * (10 ** y))
            elif t == '\x7b': #= digit-right
                y = self.stack.pop()
                x = self.stack.pop()
                self.stack.append(x // (10 ** y))
            elif t == '\x7c': #= power-of-2
                self.stack.append(2 ** self.stack.pop())
            elif t == '\x7d': #= power-of-10
                self.stack.append(10 ** self.stack.pop())
            elif t == '\x7e': #= sub-power-of-2
                self.stack.append(2 ** self.stack.pop() - 1)
            elif t == '\x7f': #= sub-power-of-10
                self.stack.append(10 ** self.stack.pop() - 1)

            elif t == '\x80': #= pair
                y = self.stack.pop()
                x = self.stack.pop()
                self.stack.append([x, y])
            elif t == '\x81': #= copies
                n = self.stack.pop()
                x = self.stack.pop()
                self.stack.append([x for _ in xrange(n)])
            elif t == '\x82': #= take-end
                y = self.stack.pop()
                x = self.stack.pop()
                if is_num(x) and is_list(y):
                    x, y = y, x
                self.stack.append(x[-y:])
            elif t == '\x83': #= cartesian-product
                y = self.stack.pop()
                x = self.stack.pop()
                p = it.product(x, y)
                self.stack.append(list(map(list, p)))
            elif t == '\x84': #= uppercase-alphabet
                self.stack.append(range(ord('A'), ord('Z') + 1))
            elif t == '\x85': #= lowercase-alphabet
                self.stack.append(range(ord('a'), ord('z') + 1))
            elif t == '\x86': #= ascii-digits
                self.stack.append(range(ord('0'), ord('9') + 1))
            elif t == '\x87': #= printable-ascii
                self.stack.append(range(32, 127))
            elif t in '\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f': #= is-alnum, is-alpha, is-digit, is-lower, is-space, is-upper, is-printable, is-hexdigit
                m = [str.isalnum, str.isalpha, str.isdigit,
                     str.islower, str.isspace, str.isupper,
                     lambda x: all(32 <= ord(c) <= 126 for c in x),
                     lambda x: x in '0123456789abcdefABCDEF']
                p = m[ord(t) - 0x88]
                x = to_ps(self.stack.pop())
                self.stack.append(1 if p(x) else 0)
            elif t == '\x90': #= uniq nub
                xs = self.stack.pop()
                uniq = []
                for x in xs:
                    if x not in uniq:
                        uniq.append(x)
                self.stack.append(uniq)
            elif t == '\x91': #= compress
                ns = self.stack.pop()
                xs = self.stack.pop()
                new = []
                for n, x in zip(ns, xs):
                    new += [x for _ in xrange(n)]
                self.stack.append(new)
            elif t == '\x92': #= select
                xs = self.stack.pop()
                iis = self.stack.pop()
                new = []
                for i in iis:
                    new.append(xs[i])
                self.stack.append(new)
            elif t == '\x93': #= permutations
                xs = self.stack.pop()
                if is_num(xs):
                    n = xs
                    xs = self.stack.pop()
                else:
                    n = None
                ps = list(map(list, it.permutations(xs, n)))
                self.stack.append(ps)
            elif t == '\x94': #= fold-product
                xss = self.stack.pop()
                ys = list(map(list, it.product(*xss)))
                self.stack.append(ys)
            elif t == '\x95': #= repeat-product
                n = self.stack.pop()
                xs = self.stack.pop()
                ys = list(map(list, it.product(xs, repeat=n)))
                self.stack.append(ys)
            elif t == '\x96': #= combinations
                n = self.stack.pop()
                xs = self.stack.pop()
                ys = list(map(list, it.combinations(xs, n)))
                self.stack.append(ys)
            elif t == '\x97': #= combinations-with-replacement
                n = self.stack.pop()
                xs = self.stack.pop()
                ys = list(map(list, it.combinations_with_replacement(xs, n)))
                self.stack.append(ys)
            elif t == '\x98': #= pairwise
                xs = self.stack.pop()
                ys = map(list, zip(xs, xs[1:]))
                self.stack.append(ys)
            elif t == '\x99': #= flatten
                def flatten(xs):
                    acc = []
                    for x in xs:
                        if is_list(x):
                            acc += flatten(x)
                        else:
                            acc.append(x)
                    return acc
                xs = self.stack.pop()
                self.stack.append(flatten(xs))
            elif t == '\x9a': #= transpose
                xs = self.stack.pop()
                self.stack.append(map(list, zip(*xs)))
            elif '\xa0' <= t <= '\xaf': # junk (recently popped items)
                self.stack.append(self.stack.junk[-1 - (ord(t) & 15)])
            elif t == '\xb0': #= zip
                ys = self.stack.pop()
                xs = self.stack.pop()
                self.stack.append(map(list, zip(xs, ys)))
            elif t == '\xb1': #= zipwith
                f = self.stack.pop()
                ys = self.stack.pop()
                xs = self.stack.pop()
                l0 = len(self.stack)
                for x, y in zip(xs, ys):
                    self.stack.append(x)
                    self.stack.append(y)
                    self.evaluate(f)
                self.stack[l0:] = [self.stack[l0:]]
            elif t == '\xb2': #= counter
                self.stack.append(self.counter)
                self.counter += 1
            elif '\xc8' <= t <= '\xcb': # save
                self.regs[ord(t) & 3] = self.stack[-1]
            elif '\xcc' <= t <= '\xcf': # put
                self.regs[ord(t) & 3] = self.stack.pop()
            elif '\xd0' <= t <= '\xd3': # get
                self.stack.append(self.regs[ord(t) & 3])
            elif '\xd4' <= t <= '\xd7': # nip
                self.regs[ord(t) & 3] = self.stack.pop(-2)
            elif '\xd8' <= t <= '\xdb': # tuck
                self.stack.insert(-1, self.regs[ord(t) & 3])
            elif '\xdc' <= t <= '\xdf': # show
                self.stack.append(to_gs(show(self.regs[ord(t) & 3])))
            else:
                raise ValueError('invalid token %r' % t) 

    def eval_map(self, f, x):
        l0 = len(self.stack)
        for i in x:
            self.stack.append(i)
            self.evaluate(f)
        self.stack[l0:] = [self.stack[l0:]]

    def eval_filter(self, f, x):
        l0 = len(self.stack)
        for i in x:
            self.stack.append(i)
            self.evaluate(f)
            if self.stack.pop():
                self.stack.append(i)
        self.stack[l0:] = [self.stack[l0:]]

if __name__ == '__main__':
    if len(sys.argv) <= 1:
        print >> sys.stderr, 'usage: python %s [-d] <code file>' % sys.argv[0]
        sys.exit(1)

    if sys.argv[1] == '-d':
        DEBUG = True
        sys.argv.pop(1)

    code = open(sys.argv[1], 'rb').read()
    stdin = '' if sys.stdin.isatty() else sys.stdin.read()
    GS2(code, stdin).run()