Je crée un interprète appelé Calcium. Cette fois, j'ai repensé à l'implémentation de l'interpréteur Calcium dans le langage Calcium lui-même.
Tout d'abord, essayons Hello, World.
hello.json
[
[1, [], "#", "0_18"],
[1, [], "call", null, ["var", "print"], ["Hello, World!"]],
[1, [], "end"]
]
Le code de langue Calcium est composé de tableaux JSON. La raison pour laquelle j'ai essayé d'écrire le code en JSON est qu'il ne nécessite pas d'analyse de phrase (JSON.parse ()
etc.). J'ai également pensé que ce serait probablement compatible avec l'environnement Web. S'il peut être décrit comme un format de données, il pourrait être utilisé pour quelque chose. (Quand je l'ai recherché plus tard, par exemple, je pense avoir vu quelque part que la VM interne de Scratch était écrite en JSON.)
Donc, écrire Calcium in Calcium signifie écrire un interpréteur en ** JSON? ** Mais personne n'a envie d'écrire un tel code directement. Ce sera un programme qui souffre autant des parenthèses que LISP. De plus, il existe de nombreuses virgules et guillemets doubles.
Heureusement, le code Calcium peut maintenant être converti à partir d'un ** sous-ensemble ** de Python. Dès le début, j'étais conscient de Python et j'ai décidé des instructions à prendre en charge. À première vue, l'exemple ci-dessus ressemble à un code mnémonique de type assemblage. Mais c'est Python qui est affecté. Chaque élément du tableau Calcium JSON (également un tableau) correspond à une ligne en Python.
Utilisez le module ʻastde Python pour sortir le code Calcium correspondant à partir du code Python. Dans Calcium, l'entier du premier élément correspond au retrait. Les retraits augmentent dans les instructions de bloc. Par exemple, l'instruction
for` suivante
loop.py
for i in range(10):
print(i)
Il est converti comme suit. (Le libellé est pour la beauté)
loop.json
[
[1, [], "#", "0_18"],
[1, [], "for range", "i", [10]],
[2, [], "call", null, ["var", "print"], [["var", "i"]]],
[1, [], "end"]
]
J'ai écrit ** sous-ensemble ** de Python plus tôt, mais il existe des restrictions sur la façon de convertir réellement en langage Calcium. Cela signifie que vous ne pouvez utiliser que certaines des fonctionnalités du langage Python. Il existe d'autres "liaisons" telles que l'appel de fonction est une instruction plutôt qu'une expression. Cependant, la syntaxe de base telle que «for», «while», «if-elif-else», «def», «class» peut être convertie en Calcium. Autrement dit, l'interpréteur Calcium prend en charge ces instructions. C'est un peu long, mais ce qui suit peut être converti en code Calcium valide.
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"]
]
J'ai pu convertir à partir d'un sous-ensemble Python, avec des différences majeures telles que les instructions d'appel de fonction et l'imbrication à deux niveaux des instructions ʻif`. Le convertisseur prend un sous-ensemble Python comme entrée et produit du code Calcium. (Ce convertisseur s'appelle py3ca.py) Cela signifie que si vous implémentez l'interpréteur Calcium dans un sous-ensemble Python, vous pouvez générer l'interpréteur Calcium écrit par Calcium lui-même.
Actuellement, Calcium est implémenté en JavaScript ou Python. Il existe des différences dans chaque implémentation (prise en charge de «try-except», comportement de l'opérateur d'équivalence, etc.), mais il lit et exécute le tableau JSON comme décrit ci-dessus.
Nous l'avons d'abord implémenté en JavaScript comme un environnement qui peut être exécuté dans un navigateur. La raison est que vous pouvez utiliser la fonction de débogage. Tout d'abord, il convenait de l'implémenter en JavaScript pour voir s'il pouvait être implémenté.
Dans le langage Calcium, chaque instruction est placée en coordonnées bidimensionnelles en mosaïque. L'adresse actuelle est représentée par (retrait, index du tableau). Par exemple, l'instruction ʻif` évalue l'expression conditionnelle et incrémente le retrait de un si vrai (à droite de la figure). Si faux, augmentez l'index sans changer le retrait (vers le bas). Les détails de l'ordre d'exécution peuvent être trouvés ici. L'image est que les retraits dans le code Python sont utilisés comme nombres au moment de l'exécution.
for
Dans Calcium, les appels de fonction sont des instructions, nous avons donc dû séparer les itérations telles que for i in range (10):
des instructions foreach telles que for elem in my_list:
. Correspond respectivement aux instructions "for range" et "for each".
Porté calcium.js vers Python. Comme mentionné ci-dessus, nous avons dû implémenter calcium.py avec la limitation que seules certaines fonctionnalités du langage Python pouvaient être utilisées. Par exemple
Il y avait de nombreuses restrictions, mais quand je l'ai implémenté, j'ai été capable de l'écrire étonnamment bien. Il tient dans un total d'environ 1500 lignes de code (calcium.js fait environ 2500 lignes). La différence est que calcium.py ne prend pas en charge try-except
, mais je ne m'attendais pas à ce que ce soit aussi court.
C'est le sujet principal. Puisqu'il s'agit d'un programme qui convertit un sous-ensemble Python en code Calcium, passer calcium.py produira le code qui décrit Calcium in Calcium. Le résultat est d'environ 1300 lignes. Il est plus court que calcium.py car il n'y a pas de lignes vides. Situé ici.
Actuellement, seul calcium.js prend en charge try-except
, alors vérifiez si Calcium peut exécuter du calcium dessus. J'ai préparé le code suivant.
cac03.py
class Engine:
# calcium.Contenu de py...
code = [
[1, [], "#", "0_18"],
[1, [], "call", None, ["var", "print"], ["Hello, World!"]],
[1, [], "end"]
]
engine = Engine(code)
engine.run()
Chargez ceci dans py3ca.py.
cac03.json
[
[1, [], "#", "0_18"],
[1, [], "class", "Engine", "object"],
...Abréviation...
[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"]
]
Passez-le à calcium.js.
const code = [...]; //Au-dessus du tableau JSON
const engine = new calcium.Engine(code);
engine.setPrintFunction((desc) => { console.log(desc); });
engine.run();
Ceci termine l'exécution.
Le calcium se caractérise par son écriture dans un tableau JSON, mais il prend en charge des fonctionnalités telles que des fonctions et des classes simples.
Lorsque j'ai recherché un bon moyen de modifier le tableau JSON, j'ai trouvé Blockly. Je n'entrerai pas dans les détails, mais vous pouvez accéder à l'éditeur de développement ici (https://crepekit.web.app/). Notre objectif est d'être un éditeur visuel que les débutants en programmation peuvent utiliser avant d'apprendre Python. (Cet environnement d'éditeur utilise calcium.js)
Si vous êtes intéressé, veuillez nous contacter depuis GitHub. Nous recherchons également des personnes pour discuter et évoluer avec nous. Nous vous serions reconnaissants de bien vouloir nous donner votre avis.
Recommended Posts