Author Topic: [python] An interpreter for the Beatnik Programming Language  (Read 583 times)

0 Members and 1 Guest are viewing this topic.

Offline TheWormKill

  • EZ's Scripting Whore
  • Global Moderator
  • Knight
  • *
  • Posts: 257
  • Cookies: 66
  • The Grim Reaper of Worms
    • View Profile
Beatnik is an esoteric stack-based language:
http://cliffle.com/esoterica/beatnik.html
(read the link first, otherwise everything coming below is completely useless.)

And since I was bored last night, I wrote a simple (and quite dumb) interpreter for it.
It has no practical use whatsoever, but was fun to write and test.
Alas, here's the code:
Code: (Python) [Select]
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys


class Interpreter(object):
    def __init__(self, filepath):
        f = open(filepath, 'r')
        self.code = f.read().replace('\n', ' ').split(' ')
        f.close()
        self.pc = 0
        self.stack = []
        self.running = True
        self.run()

    def run(self):
        max_pc = len(self.code) - 1
        while self.running and 0 <= self.pc < max_pc:
            self.action()

    def action(self):
        score = self.get_score(self.code[self.pc])
        if score < 5:
            self.mock()
            self.pc += 1
        elif score == 5:
            self.push_next_word()
        elif score == 6:
            self.pop()
            self.pc += 1
        elif score == 7:
            self.add()
            self.pc += 1
        elif score == 8:
            self.get_character()
            self.pc += 1
        elif score == 9:
            self.put_character()
            self.pc += 1
        elif score == 10:
            self.substract()
            self.pc += 1
        elif score == 11:
            self.swap()
            self.pc += 1
        elif score == 12:
            self.duplicate()
            self.pc += 1
        elif score == 13:
            self.skip_fz()
        elif score == 14:
            self.skip_fnz()
        elif score == 15:
            self.skip_bz()
        elif score == 16:
            self.skip_bnz()
        elif score == 17:
            self.halt()
        elif 18 <= score <= 23:
            self.dont_mock()
            self.pc += 1
        else:
            self.applause()
            self.pc += 1

    def get_score(self, word):
        """
        Get the score of a word.
        """
        # scores taken from
        # https://en.wikipedia.org/wiki/Scrabble_letter_distributions
        scores = {'l': 1, 's': 1, 'u': 1, 'n': 1, 'r': 1, 't': 1, 'o': 1,
                  'a': 1, 'i': 1, 'e': 1,
                  'g': 2, 'd': 2,
                  'b': 3, 'c': 3, 'm': 3, 'p': 3,
                  'f': 4, 'h': 4, 'v': 4, 'w': 4, 'y': 4,
                  'k': 5,
                  'j': 6, 'x': 6,
                  'q': 7, 'z': 7
                  }
        ret = 0
        for char in word.lower():
            if char in scores:
                ret += scores[char]
        return ret

    def mock(self):
        """
        Mock the user.
        """
        print 'You are mocked now.'

    def push_next_word(self):
        """
        Push the word directly after the program counter and skip it.
        """
        if len(self.code) > self.pc:
            self.stack.append(self.get_score(self.code[self.pc+1]))
            self.pc += 2

    def pop(self):
        """
        Pop the top number of the stack and discard it.
        """
        if len(self.stack) >= 1:
            self.stack.pop()

    def add(self):
        """
        Add the top two numbers of the stack, remove them and push the result.
        """
        if len(self.stack) >= 2:
            result = self.stack.pop() + self.stack.pop()
            self.stack.append(result)

    def get_character(self):
        """
        Get a character from the user and push its value on the stack.
        """
        char = ''
        while char == '':
            temp = raw_input()
            if len(temp) == 1:
                char = temp
        self.stack.append(int(char))

    def put_character(self):
        """
        Pop a number off the stack and output the corresponding character.
        """
        if len(self.stack) >= 1:
            print chr(self.stack.pop()),

    def substract(self):
        """
        Substract the top two values from the stack and push the result.
        """
        if len(self.stack) >= 2:
            temp = self.stack.pop()
            result = self.stack.pop() - temp
            self.stack.append(result)

    def swap(self):
        """
        Swap the top two values on the stack.
        """
        if len(self.stack) >= 2:
            a = self.stack.pop()
            b = self.stack.pop()
            self.stack.append(a)
            self.stack.append(b)

    def duplicate(self):
        """
        Duplicate the top value on the stack.
        """
        if len(self.stack) >= 1:
            self.stack[-1] *= 2

    def skip_fz(self):
        """
        Skip n+1 words forward if the top value is zero, where n is
        the next word's value.
        """
        if len(self.stack) >= 1 and len(self.code) > self.pc:
            if self.stack[-1] == 0:
                self.pc += self.get_score(self.code[self.pc+1]) + 1

    def skip_fnz(self):
        """
        Skip n+1 words forward if the top value is not zero, where n is
        the next word's value.
        """
        if len(self.stack) >= 1 and len(self.code) > self.pc:
            if self.stack[-1] != 0:
                self.pc += self.get_score(self.code[self.pc+1]) + 1

    def skip_bz(self):
        """
        Skip n words backward if the top value is zero, where n is
        the next word's value.
        """
        if len(self.stack) >= 1 and len(self.code) > self.pc:
            if self.stack[-1] == 0:
                self.pc -= self.get_score(self.code[self.pc+1])

    def skip_bnz(self):
        """
        Skip n words backward if the top value is not zero, where n is
        the next word's value.
        """
        if len(self.stack) >= 1 and len(self.code) > self.pc:
            if self.stack[-1] != 0:
                self.pc -= self.get_score(self.code[self.pc+1])

    def halt(self):
        """
        Stop the program.
        """
        self.running = False

    def dont_mock(self):
        """
        Don't mock the user.
        """
        print 'You are not mocked now.'

    def applause(self):
        """
        Applaude the user.
        """
        print 'APPLAUSE!'

if __name__ == '__main__':
    interpreter = Interpreter(sys.argv[1])


And here is a Hello World:
Code: [Select]
k qqqqqqkkkkkk qg
k qqqqqqqqqqqqqqb qg
k qqqqqqqqqqqqqqqb qg
k qqqqqqqqqqqqqqqb qg
k qqqqqqqqqqqqqqqbb qg
k qqqqf qg
k qqqqqqqqqqqqb qg
k qqqqqqqqqqqqqqqbb qg
k qqqqqqqqqqqqqqqqg qg
k qqqqqqqqqqqqqqqb qg
k qqqqqqqqqqqqqqg qg
k qqqqk gq

Of course I cheated, the real challenge would be to use real words.

Have fun.
Stuff I did: How to think like a superuser, Iridium

He should make that "Haskell"
Quote
<m0rph-is-gay> fuck you thewormkill you python coding mother fucker