2009-09-26 8 views
10

Chcę zhackować z interpreterem Pythona i spróbować utworzyć małe DSL. Czy istnieje jakiś moduł, w którym mogę zrobić coś w rodzaju tego kodu teoretycznego (podobnie jak drzewa wyrażeń LINQ)?Czy jest jakiś sposób programowo wygenerować kod bajtowy Pythona?

expression_tree = Function(
    Print(
     String('Hello world!') 
    ) 
) 
compile_to_bytecode(expression_tree) 

A może po prostu łatwiej byłoby po prostu wygenerować kod źródłowy Pythona? Czy można to ułatwić, używając C, SWIG lub Cython?

+0

Biorąc pod uwagę ogromną siłę wyrazu języków OO (Python w szczególności) DSL jest dość głupie. Po prostu napisz Python. Jeśli podajesz dobre definicje klas, masz "podobny do DSL" Python i nie potrzebujesz tego. –

Odpowiedz

10

Praca przez ast i kompilacja drzewa do kodu bajtowego, jak sugeruje inna odpowiedź, jest prawdopodobnie najprostsza; generowanie źródeł i kompilowanie ich, prawie tak samo dobre.

Jednak w celu zbadania podejść niższego poziomu, sprawdź linki z this page; Zauważyłem, że byteplay jest szczególnie użyteczny (obecnie nie działa w wersji 2.6 ani 3. *, tylko w wersji 2.4 lub 2.5, ale myślę, że poprawienie go do wersji 2.6 powinno być łatwe, co jest obecnie omawiane w jego trackerze). Nie użyłem podobnego do Phila Eby'ego modelu BytecodeAssembler, ale biorąc pod uwagę reputację autora, jestem pewien, że warto go sprawdzić!

+0

+1 Ładne linki :) –

+0

Świetna odpowiedź jak zawsze. :-) –

0

Sprawdź modułu dezasembler znaleźć tutaj:

http://docs.python.org/library/dis.html

+0

Jedyna rzecz to to, że chciałem złożyć kod bajtowy, a nie * dis * go złożyć. :-) –

+0

ahh dobra uwaga, przykro mi z tego;) jednak zaletą modułu disassembler jest to, że pozwala on spojrzeć na wygenerowany kod bajtowy oraz podać szczegółowe instrukcje kodu bajtowego. – Nope

5

w Pythonie 2.x byś zazwyczaj podejść do tego z compiler module i jego ast podmodułem (należy jednak pamiętać, tego modułu jest przestarzałe od wersji 2.6). W Pythonie 3.X użyjesz tylko ast.

Obie oferują funkcję compile(), która przejdzie ze źródła/AST do "obiektu kodu, który może być wykonany za pomocą instrukcji exec lub eval()."

1

Fernando Meyer recently wrote a blog post wyjaśnienie, jak korzystać z dyrektywy # coding, aby określić własne rozszerzenia do Pythona. Przykład (rzeczywista definicja format jest w pyspec.py i tokenizer.py):

# coding: pyspec 

class Bow: 
    def shot(self): 
     print "got shot" 

    def score(self): 
     return 5 

describe Bowling: 
    it "should score 0 for gutter game": 
     bowling = Bow() 
     bowling.shot() 
     assert that bowling.score.should_be(5) 
2

Łatwiej do generowania kodu Pythona i uruchom go. Jeśli to zrobisz, możesz również łatwiej go debugować, ponieważ istnieje rzeczywiste źródło do wyświetlenia debuggera. Zobacz także artykuł Malte Borchs w lipcowym numerze magazynu Python, w którym opowiada o tym między innymi.

1

Aktualizacja dla Python3 - jest również bardzo interesujący asembler zachariahreed/byteasm.

Właściwie to jedyny, który pracuje dla mnie w Py3. Ma bardzo ładny & czyste API:

>>> import byteasm, dis 
>>> b = byteasm.FunctionBuilder() 
>>> b.add_positional_arg('x') 
>>> b.emit_load_const('Hello!') 
>>> b.emit_load_fast('x') 
>>> b.emit_build_tuple(2) 
>>> b.emit_return_value() 
>>> f = b.make('f') 
>>> f 
<function f at 0xb7012a4c> 
>>> dis.dis(f) 
    1   0 LOAD_CONST    0 ('Hello!') 
       3 LOAD_FAST    0 (x) 
       6 BUILD_TUPLE    2 
       9 RETURN_VALUE 
>>> f(108) 
('Hello!', 108) 
Powiązane problemy