BlockScript - 535
{[B':=?0:B';=?0:B'}=?0:B'{=?,A!,A!d1c&:B'?=?,A!,A!2e&:B''=?,,A!d3c&:B{[B'0<?0:B
'9>?0:1}!?B'0-{[,g!?c'0-B10*d+A!:Bd]A!d3c&}!:B'#=?{[,10=?,]A!:A!}!:,A!Bb&}{[AC[
B]DB?[AB{[Bh&hbhn!}{[B[AB]C?1-eA!:b}&[C1=?E[C]FHc&B!:C2=?{G?D:E[C}!FHcI!:C3=?E[
C]B!:C'!=?G[ABC]Hc&dbh&D?b@I!B!:b@I!:C'&=?HB!:C'@=?FGDI!:C'[=?GF&HDI!:C']=?F[A]
HDI!:C',=?,B!:C'.=?G.FHDI!:C'a'z{[DC<?0:DB>?0:1}!?Ce-HA!B!:C'A'Ze!?F[B]Cg-dA!B!
:{C'+=?{[CB+}:C'-=?{[CB-}:C'*=?{[CB*}:C'/=?{[CB/}:C'%=?{[CB%}:C'<=?{[CB<}:C'>=?
{[CB>}:C'==?{[CB=}:0}!?H[A][B]Ge!B!:FHDI!:c},c!0ac&0&0&0bho!;
BlockScript est un langage trivial basé sur la pile de spaghetti que j'ai créé spécifiquement pour ce défi. L'interpréteur de base est blockscript.c .
Exemple de programme (imprime les 15 premiers numéros de Fibonacci):
{[B?B10/A!B10%d&:0}
{[B0<?'-.0B-A!:{B?Bh!{[B?B[A]A!B[B]'0+.:}!:'0.}!10.}
{[B?Dd!DC+B1-CecA!:}
0 1 15d!
;
L'interprète lit à la fois le code source et l'entrée du programme à partir de l'entrée standard, dans cet ordre. Cela signifie que pour exécuter un interpréteur au sein d'un interprète au sein d'un interprète, copiez et collez simplement:
# Level 1
{[B':=?0:B';=?0:B'}=?0:B'{=?,A!,A!d1c&:B'?=?,A!,A!2e&:B''=?,,A!d3c&:B{[B'0<?0:B
'9>?0:1}!?B'0-{[,g!?c'0-B10*d+A!:Bd]A!d3c&}!:B'#=?{[,10=?,]A!:A!}!:,A!Bb&}{[AC[
B]DB?[AB{[Bh&hbhn!}{[B[AB]C?1-eA!:b}&[C1=?E[C]FHc&B!:C2=?{G?D:E[C}!FHcI!:C3=?E[
C]B!:C'!=?G[ABC]Hc&dbh&D?b@I!B!:b@I!:C'&=?HB!:C'@=?FGDI!:C'[=?GF&HDI!:C']=?F[A]
HDI!:C',=?,B!:C'.=?G.FHDI!:C'a'z{[DC<?0:DB>?0:1}!?Ce-HA!B!:C'A'Ze!?F[B]Cg-dA!B!
:{C'+=?{[CB+}:C'-=?{[CB-}:C'*=?{[CB*}:C'/=?{[CB/}:C'%=?{[CB%}:C'<=?{[CB<}:C'>=?
{[CB>}:C'==?{[CB=}:0}!?H[A][B]Ge!B!:FHDI!:c},c!0ac&0&0&0bho!;
# Level 2
{[B':=?0:B';=?0:B'}=?0:B'{=?,A!,A!d1c&:B'?=?,A!,A!2e&:B''=?,,A!d3c&:B{[B'0<?0:B
'9>?0:1}!?B'0-{[,g!?c'0-B10*d+A!:Bd]A!d3c&}!:B'#=?{[,10=?,]A!:A!}!:,A!Bb&}{[AC[
B]DB?[AB{[Bh&hbhn!}{[B[AB]C?1-eA!:b}&[C1=?E[C]FHc&B!:C2=?{G?D:E[C}!FHcI!:C3=?E[
C]B!:C'!=?G[ABC]Hc&dbh&D?b@I!B!:b@I!:C'&=?HB!:C'@=?FGDI!:C'[=?GF&HDI!:C']=?F[A]
HDI!:C',=?,B!:C'.=?G.FHDI!:C'a'z{[DC<?0:DB>?0:1}!?Ce-HA!B!:C'A'Ze!?F[B]Cg-dA!B!
:{C'+=?{[CB+}:C'-=?{[CB-}:C'*=?{[CB*}:C'/=?{[CB/}:C'%=?{[CB%}:C'<=?{[CB<}:C'>=?
{[CB>}:C'==?{[CB=}:0}!?H[A][B]Ge!B!:FHDI!:c},c!0ac&0&0&0bho!;
# Level 3
{[B?B10/A!B10%d&:0}
{[B0<?'-.0B-A!:{B?Bh!{[B?B[A]A!B[B]'0+.:}!:'0.}!10.}
{[B?Dd!DC+B1-CecA!:}
0 1 15d!
;
Comme le film Inception , vous ne pouvez pas aller plus loin que trois niveaux. Ce n'est pas une question de temps, mais d'espace. BlockScript perd énormément de mémoire, et cela a à voir avec la façon dont le langage lui-même est conçu.
Référence du langage:
Obtenez l'interprète ici
Dans BlockScript, la «pile» n'est pas un tableau qui est écrasé par des opérations ultérieures comme vous en avez l'habitude. Il est en fait implémenté comme une liste liée immuable et une pile persiste pendant la durée du programme. De plus, aucun opérateur (sauf@
) ne supprime les valeurs de la pile. Cependant, les modifications de pile n'affectent que le bloc dans lequel elles se produisent.
Sélection de valeur
a
à travers z
Récupérez l'élément 0-25th de la pile et poussez-le dans la pile. a
fait référence à la tête, ou au dernier élément poussé, de la pile.
A
à travers Z
Récupérez le 0-25ème élément de l'image actuelle et poussez-le dans la pile.
[
Ouvrez un "cadre" pour sélectionner les éléments de la référence de pile (voir ci-dessous) sur la tête de la pile. [
ne nécessite pas de correspondance ]
, mais les cadres ont une portée lexicale. Dans BlockScript, la "portée" est déterminée par des accolades ( {
... }
) qui forment des blocs. Ainsi, l'ouverture d'un cadre à l'intérieur d'un bloc n'aura aucun effet sur le code à l'extérieur du bloc.
]
Fermez l'image actuelle, en revenant à l'image précédente (le cas échéant).
Blocs
{
... }
Créez un "bloc" et poussez-le dans la pile. À l'intérieur d'un bloc, la pile commencera à ce qu'elle était avant le bloc, sauf que la pile de l'appelant sera poussée en haut. Les piles sont persistantes et immuables dans BlockScript, donc les blocs sont des fermetures. L'idiome {[
signifie ouvrir un bloc, puis ouvrir un cadre pour commencer à sélectionner des arguments (en utilisant A
through Z
). La valeur de retour d'un bloc est la tête de la pile lorsqu'elle }
est atteinte.
Exemple:
'3 '2 '1 {[ b. d. f. B. C. D. A! } 'D 'C 'B d!;
Cela imprime 123BCD123DCB123BCD123DCB…
. Les lettres minuscules font référence aux valeurs de la pile, tandis que les lettres majuscules font référence aux arguments (car le cadre est défini sur la pile de l'appelant). A!
prend la tête de l'appelant (qui est garanti d'être le bloc appelé) et l'appelle. Si vous vous demandez pourquoi il s'inverse à BCD
chaque fois, c'est parce qu'il B. C. D.
pousse ces arguments dans l'ordre inverse juste avant que le bloc ne s'appelle.
!
Appelez un bloc. Poussez la valeur de retour dans la pile.
Références de pile
&
Créez une référence de pile et poussez-la dans la pile. Considérez cela comme des «super-inconvénients», car il prend efficacement chaque élément de la pile et en forme un «tuple». L'idiome &[
signifie que tout a
, b
, c
appelés avant peut maintenant être consulté avec A
, B
, C
(pour le reste du bloc ou jusqu'à ce que]
l' on rencontre).
En partie parce qu'il &
capture plus de valeurs qu'il n'en a généralement besoin, BlockScript perd de la mémoire par conception.
@
Basculez vers la pile pointée par la référence de pile a
. Cet opérateur est plutôt bizarre, mais l'auto-interprète BlockScript l'utilise plusieurs fois pour éviter d'avoir à pousser deux fois les mêmes arguments. Les effets de @
(ou de toute opération de pile, d'ailleurs) sont limités au bloc dans lequel il est invoqué. De plus, le cadre n'est pas affecté par @
, donc le cadre peut être utilisé pour saisir les valeurs dont vous avez besoin après avoir changé de pile.
Expression conditionnelle
?
<sur vrai> :
<sur faux>
Expression conditionnelle, tout comme l'opérateur ternaire en C. Autrement dit, si a
est "vrai" (c'est-à-dire différent de zéro entier), alors faites <sur vrai> , sinon faites <sur faux> .
E / S
Remarque: L'entrée et la sortie se font en UTF-8. Un "caractère" est un entier correspondant à un index Unicode.
,
Obtenez le prochain caractère d'entrée et poussez-le dans la pile. Si la fin de l'entrée est atteinte, appuyez sur -1 à la place.
.
Sortez le personnage sur la tête de la pile.
Littéraux entiers / caractères
Remarque: les entiers et les caractères sont la même chose dans BlockScript.
Arithmétique
Ces opérateurs ne fonctionnent que sur des valeurs entières.
+
Calculer b
+ a
(en poussant le résultat, mais sans ignorer aucune valeur).
-
Calculer b
- a
.
*
Calculer b
* a
.
/
Calculer b
/ a
(division entière; arrondit vers l'infini négatif).
%
Calculer le b
% a
(module entier; arrondi vers l'infini négatif).
Opérateurs relationnels
Ces opérateurs ne fonctionnent que sur des valeurs entières.
<
Si b
est inférieur à a
, appuyez sur 1, sinon appuyez sur 0.
>
=
Divers
#
Commentaire à la fin de la ligne
- Le programme doit se terminer par
;
- Tous les autres personnages sont ignorés.
/usr/bin/cat
) qu'en est-il de Turing-complétude?