OMeta

OMeta ist ein Objekt-Orientiertes Parser Framework für PEG’s. Die Implementierung ist in diversen dynamischen Programmiersprachen verfügbar (Javascript, Python, Common Lisp, C#, Scheme, Ruby). Diese muss aber als Interpretation des Modells angesehen werden.OMeta hat dabei die Ansprüche (welche auch durchaus durchgehalten werden), dass die Implementierung minimal sein sollte. Das äußert sich vor allem darin, dass Code stets wiederverwendbar sein soll und dabei minimalistisch und einfach zu verstehen sein soll.

Die Grundlage hierfür ist das Projekt ‘STEPS Toward the Reinvention of Programming’ vom Viewpoint Research Institut in Glendale, Kalifornien. OMeta dient diesem Projekt quasi als Instrument zur Entwicklung von Domänenspezifischen Programmiersprachen. Dabei ist der Funktionsumfang weitaus größer als der eines gewöhnlichen Parsers. Ähnlich wie DCGs in Prolog kann mithilfe dieses Frameworks problemlos eine Intermediäre Respräsentation der Sprache, z.B.: ein abstrakter Syntaxbaum erstellt werden. Darüber hinaus lassen sich beliebige Methoden ausführen. Beispielsweise kann über den Parser das komplette Bootstrapping einer Sprache gesteuert werden (z.B.: Parsen, Kompilieren in Bytecode, Interpretieren des Bytecodes).

Das Beispiel zeigt einen Parser, der gleichzeitig auch Interpreter für die Turing-vollständige Sprache Brainfuck ist. Die Grammatikregeln befinden sich in der Variabel bfgrammar.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
""" Simple Interpreter for the Brainfuck language. Implemented with the
Parser framework PyMeta2.
- http://de.wikipedia.org/wiki/Brainfuck
- http://www.allbuttonspressed.com/projects/pymeta
"""


__author__ = "Rene Bartelmus <rene.bartelmus@uni-duesseldorf.de>"
__date__ = "13 September 2012"
__version__ = 1, 0

import sys
from pymeta.grammar import OMeta

bfgrammar = """
skip = '[' ('.'|','|'<'|'>'|'+'|'-' | skip)* ']'
rule =    '.'   -> sys.stdout.write(chr(self.band[self.current]))
        | ','   -> self.read()
        | '<'   -> self.left()
        | '>'   -> self.right()
        | '+'   -> self.plus()
        | '-'   -> self.minus()
        | ~~('[') ?(self.test_true()) '[' -> self.loop_begin()
        | ~~('[') ?(self.test_false()) skip
        | ']'   -> self.loop_end()

grammar = rule+ end
"""


class Tape(dict):

    def __getitem__(self, key):
        if key not in self:
            super(Tape, self).__setitem__(key, 0)
        return super(Tape, self).__getitem__(key)

class Parser(OMeta.makeGrammar(bfgrammar, globals(), "MTGrammar")):
   
    band = Tape()
    current = 0
    loop = []
   
    def set_input(self, input):
        input = [ord(i) for i in input]
        input.reverse()
        self.in_stream = input
   
    def read(self):
        self.band[self.current] = self.in_stream.pop()
   
    def test_true(self):
        return not not self.band[self.current]
   
    def test_false(self):
        return not self.band[self.current]
   
    def plus(self):
        self.band[self.current] += 1
   
    def minus(self):
        self.band[self.current] -= 1
   
    def left(self):
        self.current += 1
       
    def right(self):
        self.current -= 1
   
    def loop_begin(self):
        self.loop.append(self.input.position-1)
   
    def loop_end(self):
        self.input.position = self.loop.pop()

if __name__ == "__main__":
    if len(sys.argv) == 3:
        p = Parser(sys.argv[1])
        p.set_input(sys.argv[2]+"\x00")
        try:
            p.apply("grammar")
        except Exception as e:
            print e.formatError(sys.argv[1])
            sys.exit(1)
    else:
        print 'Call example: python brainfuck.py PROGRAM INPUT'

Ein Beispielaufruf könnte sein:

python brainfuck.py ",.[,.]" "Rubidubiduu!"

mit der Ausgabe:

Rubidubiduu!

Weiterführende Links:

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert