[PYTHON] Bis Sie Ihren eigenen Dolmetscher selbst hosten

Ich mache einen Dolmetscher namens Calcium. Dieses Mal habe ich auf die Implementierung des Calcium-Interpreters in der Calcium-Sprache selbst zurückgeblickt.

Was ist die Calciumsprache?

Versuchen wir zuerst Hallo, Welt.

hello.json


[
  [1, [], "#", "0_18"],
  [1, [], "call", null, ["var", "print"], ["Hello, World!"]],
  [1, [], "end"]
]

Der Calcium-Sprachcode besteht aus JSON-Arrays. Der Grund, warum ich versucht habe, den Code in JSON zu schreiben, ist, dass keine Phrasenanalyse erforderlich ist (JSON.parse () usw.). Ich dachte auch irgendwie, dass es wahrscheinlich mit der Webumgebung kompatibel sein würde. Wenn es als Datenformat beschrieben werden kann, könnte es für etwas verwendet werden. (Als ich es später nachgeschlagen habe, habe ich beispielsweise irgendwo gesehen, dass die interne VM von Scratch in JSON geschrieben wurde.) Calcium in Calcium zu schreiben bedeutet also, einen Dolmetscher in ** JSON zu schreiben? ** Aber niemand hat Lust, solchen Code direkt zu schreiben. Es wird ein Programm sein, das genauso unter Klammern leidet wie LISP. Darüber hinaus gibt es viele Kommas und doppelte Anführungszeichen.

Konvertieren Sie von Python nach Calcium (JSON)

Glücklicherweise kann Calciumcode jetzt aus einer ** Teilmenge ** von Python konvertiert werden. Von Anfang an war ich mir Python bewusst und entschied mich für die Anweisungen zur Unterstützung. Auf den ersten Blick sieht das obige Beispiel wie ein Assembly-ähnlicher Mnemonic-Code aus. Aber es ist Python, das betroffen ist. Jedes Element des Calcium-JSON-Arrays (auch ein Array) entspricht einer Zeile in Python. Verwenden Sie das ast-Modul von Python, um den entsprechenden Calcium-Code aus Python-Code auszugeben. In Calcium entspricht die Ganzzahl des ersten Elements dem Einzug. Einrückungen nehmen in Blockanweisungen zu. Zum Beispiel die folgende "for" -Anweisung

loop.py


for i in range(10):
    print(i)

Es wird wie folgt konvertiert. (Der Wortlaut ist für gutes Aussehen)

loop.json


[
  [1, [], "#", "0_18"],
  [1, [], "for range", "i", [10]],
    [2, [], "call", null, ["var", "print"], [["var", "i"]]],
  [1, [], "end"]
]

Ich habe früher eine ** Teilmenge ** von Python geschrieben, aber es gibt Einschränkungen, wie man tatsächlich in die Calcium-Sprache konvertiert. Dies bedeutet, dass Sie nur einige der Sprachfunktionen von Python verwenden können. Es gibt andere "Bindungen", z. B. ist der Funktionsaufruf eher eine Anweisung als ein Ausdruck. Grundlegende Syntax wie "for", "while", "if-elif-else", "def", "class" kann jedoch in Calcium konvertiert werden. Das heißt, der Calcium-Interpreter unterstützt diese Anweisungen. Es ist ein bisschen lang, aber das Folgende kann in gültigen Calcium-Code umgewandelt werden.

sample.py


def is_remainder_zero(a, b):
    return (a % b) == 0

prime = []
for i in range(101):
    j = 2
    while j < i:
        is_zero = is_remainder_zero(i, j)
        if is_zero:
            break
        else:
            j += 1
    if j == i:
        prime.append(i)
result = prime
print(result)

sample.json


[
  [1, [], "#", "0_18"],
  [1, [], "def", "is_remainder_zero", ["a", "b"]],
    [2, [], "return", ["==", ["%", ["var", "a"], ["var", "b"]], 0]],
  [1, [], "=", ["var", "prime"], [[]]],
  [1, [], "for range", "i", [101]],
    [2, [], "=", ["var", "j"], 2],
    [2, [], "while", ["<", ["var", "j"], ["var", "i"]]],
      [3, [], "call", ["var", "is_zero"], ["var", "is_remainder_zero"], [["var", "i"], ["var", "j"]]],
      [3, [], "ifs"],
        [4, [], "if", ["var", "is_zero"]],
          [5, [], "break"],
        [4, [], "else"],
          [5, [], "+=", ["var", "j"], 1],
    [2, [], "ifs"],
      [3, [], "if", ["==", ["var", "j"], ["var", "i"]]],
        [4, [], "call", null, ["attr", "prime", "append"], [["var", "i"]]],
  [1, [], "=", ["var", "result"], ["var", "prime"]],
  [1, [], "call", null, ["var", "print"], [["var", "result"]]],
  [1, [], "end"]
]

Ich konnte aus einer Python-Teilmenge konvertieren, mit großen Unterschieden wie Funktionsaufrufanweisungen und zweistufiger Verschachtelung von if-Anweisungen. Der Konverter verwendet eine Python-Teilmenge als Eingabe und gibt Calcium-Code aus. (Dieser Konverter heißt py3ca.py) Dies bedeutet, dass Sie, wenn Sie den Calcium-Interpreter in einer Python-Teilmenge implementieren, den von Calcium selbst geschriebenen Calcium-Interpreter ausgeben können.

Implementierung eines Calcium-Interpreters

Derzeit ist Calcium in JavaScript oder Python implementiert. Es gibt Unterschiede in jeder Implementierung ("Try-Except" -Unterstützung, Verhalten des Äquivalenzoperators usw.), aber das JSON-Array wird wie oben beschrieben gelesen und ausgeführt.

Implementierung von calcium.js

Wir haben es zuerst in JavaScript als eine Umgebung implementiert, die in einem Browser ausgeführt werden kann. Der Grund ist, dass Sie die Debugger-Funktion verwenden können. Zunächst war es angebracht, es in JavaScript zu implementieren, um zu prüfen, ob es implementiert werden kann.

Realisierung von "wenn"

In der Calcium-Sprache wird jede Anweisung in gekachelten zweidimensionalen Koordinaten platziert. Die aktuelle Adresse wird durch (Einzug, Index des Arrays) dargestellt. スクリーンショット 2020-04-27 10.05.13.png Zum Beispiel wertet der Befehl "if" den bedingten Ausdruck aus und erhöht den Einzug um eins, wenn er wahr ist (rechts in der Abbildung). Wenn false, erhöhen Sie den Index, ohne den Einzug zu ändern (nach unten). Details zur Ausführungsreihenfolge finden Sie hier. Das Bild soll zur Laufzeit Einrückungen im Python-Code als Zahlen verwenden.

Realisierung der "for" -Anweisung

In Calcium sind Funktionsaufrufe Anweisungen, daher mussten wir die Iterationen wie "for i in range (10):" von den foreach-Anweisungen wie "for elem in my_list:" trennen. Entspricht den Anweisungen "für Bereich" bzw. "für jeden".

Implementierung von calcium.py

Portierte calcium.js nach Python. Wie oben erwähnt, mussten wir calcium.py mit der Einschränkung implementieren, dass nur einige der Sprachfunktionen von Python verwendet werden konnten. Zum Beispiel

Es gab viele Einschränkungen, aber als ich es implementierte, konnte ich es überraschend gut schreiben. Es passt in insgesamt ca. 1500 Codezeilen (calcium.js ist ca. 2500 Zeilen). Der Unterschied ist, dass calcium.py kein "try-without" unterstützt, aber ich habe nicht erwartet, dass es so kurz ist.

Laden Sie calcium.py in py3ca.py

Dies ist das Hauptthema. Da es sich um ein Programm handelt, das eine Python-Teilmenge in Calcium-Code konvertiert, gibt die Übergabe von calcium.py den Code aus, der Calcium in Calcium beschreibt. Das Ergebnis sind ungefähr 1300 Zeilen. Es ist kürzer als calcium.py, da keine Leerzeilen vorhanden sind. Befindet sich hier.

Führen Sie den Calcium-Interpreter aus

Derzeit unterstützt nur calcium.js "try-without". Überprüfen Sie daher, ob Calcium Calcium darauf ausführen kann. Ich habe den folgenden Code vorbereitet.

cac03.py


class Engine:
    # calcium.Inhalt von py...
code = [
  [1, [], "#", "0_18"],
  [1, [], "call", None, ["var", "print"], ["Hello, World!"]],
  [1, [], "end"]
]
engine = Engine(code)
engine.run()

Laden Sie dies in py3ca.py.

cac03.json


[
  [1, [], "#", "0_18"],
  [1, [], "class", "Engine", "object"],
 ...Abkürzung...
  [1, [], "=", ["var", "code"], [[[[1, [[]], "#", "0_18"]], [[1, [[]], "call", null, [["var", "print"]], [["Hello, World!"]]]], [[1, [[]], "end"]]]]],
  [1, [], "call", ["var", "engine"], ["var", "Engine"], [["var", "code"]]],
  [1, [], "call", null, ["attr", "engine", "run"], []],
  [1, [], "end"]
]

Übergeben Sie es an calcium.js.

const code = [...]; //Über dem JSON-Array
const engine = new calcium.Engine(code);
engine.setPrintFunction((desc) => { console.log(desc); });
engine.run();

Damit ist die Ausführung abgeschlossen.

Endlich (Werbung ...)

Calcium zeichnet sich dadurch aus, dass es in ein JSON-Array geschrieben wird, unterstützt jedoch Funktionen wie einfache Funktionen und Klassen.

Anwendung von Calcium

Als ich nach einer guten Möglichkeit zum Bearbeiten des JSON-Arrays suchte, fand ich Blockly. Ich werde nicht auf Details eingehen, aber Sie können hier auf den Entwicklungseditor zugreifen (https://crepekit.web.app/). Wir möchten ein visueller Editor sein, den Anfänger in der Programmierung verwenden können, bevor sie Python lernen. (Diese Editorumgebung verwendet calcium.js)

Calcium ist Open Source

Bei Interesse kontaktieren Sie uns bitte von GitHub. Wir suchen auch Menschen, die mit uns diskutieren und sich entwickeln können. Wir würden uns freuen, wenn Sie uns Ihre Meinung mitteilen könnten.

Recommended Posts

Bis Sie Ihren eigenen Dolmetscher selbst hosten
Bis Sie Ihre eigene Python-Bibliothek installieren
Bis Sie Ihre eigene Python-Bibliothek mit pip installieren können
Versuchen Sie, Ihre eigene CorDapp zu erstellen. (Bis zur Schaffung von Staaten)
Erstellen Sie Ihre eigene Ausnahme
Bis Sie MySQL-Python installieren
Erstellen Sie Ihre eigene Django-Middleware
Einführung in die Verwendung von Pytorch Lightning ~ Bis Sie Ihr eigenes Modell formatieren und auf Tensorboard ausgeben ~
Bis das Crashlytics Kit in eine kivy-basierte iOS-App integriert ist
Lassen Sie uns überlegen, ob es sich um eine PDF- und eine Ausnahmeverarbeitung handelt. Bis Sie Ihre eigene Ausnahmeverarbeitung erstellen