Écrivez un interprète classique de brain-flak!

18

Brain-Flak (un croisement entre Brainf ** k et Flak-Overstow) est un langage ésotérique basé sur la pile. Depuis que ce défi a été publié, la langue a évolué et s'est mise à jour, mais cette première révision de la langue est connue sous le nom de "brain-flak classic".

Vous devez écrire un programme ou une fonction qui prend une chaîne de code classique Brain-Flak et l'évalue. Il prendra également une liste (éventuellement vide) d'entiers. Il y a les entrées du programme classique Brain-Flak.

La langue

Brain-Flak a deux piles, appelées «gauche» et «droite». La pile active commence à gauche. Si une pile vide est sautée ou consultée, elle renverra 0. Il n'y a pas de variables. Lorsque le programme démarre, chaque entrée est poussée dans la pile active dans l'ordre (de sorte que la dernière entrée se trouve au-dessus de la pile).

Les seuls caractères valides d'un programme Brain-Flak le sont ()[]{}<>et ils doivent toujours être équilibrés . S'il y a des caractères non valides ou si les crochets ne correspondent pas, vous obtenez un comportement indéfini. Tout est valide.

Il existe deux types de fonctions: Nilades et Monades . Un nilad est une fonction qui prend 0 arguments. Voici toutes les nilades:

  • () +1.
  • [] -1.
  • {} Pop la pile active.
  • <> Basculez la pile active.

Ceux-ci sont concaténés ensemble lorsqu'ils sont évalués. Donc, si nous avions un «3» au-dessus de la pile active, cet extrait de code:

()(){}

évaluerait à 1 + 1 + active.pop()qui évaluerait à 5. est <>évalué à 0.

Les monades prennent un argument, un morceau de code Brain-Flak. Voici toutes les monades:

  • (n) Appuyez sur 'n' sur la pile active.
  • [n] Imprimez 'n' comme un int et une nouvelle ligne.
  • {foo}Pendant que active.peek ()! = 0, faites foo. Évalue à 0¹.
  • <foo> Exécutez foo, mais évaluez-le à 0.

Ces fonctions renverront également la valeur à l'intérieur d'eux, donc

(()()())

Poussera 3 et

[()()()]

Imprime 3 mais

[(()()())]

Imprime et pousse 3.

Lorsque le programme a terminé son exécution, chaque valeur restante sur la pile active est imprimée sous forme d'entier, avec une nouvelle ligne entre. Les valeurs de l'autre pile sont ignorées.

Règles:

  • Votre programme doit prendre en charge des nombres dans la plage (-128, 127) et une taille de pile d'au moins 255. Si vous prenez en charge plus grand, c'est parfait.

  • Le débordement / débordement n'est pas défini.

Exemple d'E / S:

Le programme vide:

Entrée: aucune

Sortie: aucune

Une addition. La source:

({}{})

Contribution:

2, 3

Production:

5

Soustraction. La source:

({}<>){({}[])<>({}[])<>}<>

Contribution:

2, 3

Production:

-1

Multiplication. La source:

({}<>)<>({}[]){({}[])<>(({}))<>}<>{({}<>{})<>}<>

Contribution:

7, 8

Production:

56

Fibonacci. La source:

<>((()))<>{({}[])<>({}<>)<>(({})<>({}<>))<>}<>

Contribution:

5

Production:

13
8
5
3
2
1
1

Machine de vérité

{[({})]}

Les failles standard s'appliquent et la réponse la plus courte en octets l'emporte.


  • ¹: C'était en fait une erreur de ma part. {...} devrait évaluer la somme de toutes ses courses, ce qui est l'OMI l'une des caractéristiques les plus cool de brain-flak. Cependant, pour les besoins de ce défi, supposons que {...} vaut 0.
DJMcMayhem
la source
Existe-t-il une règle concernant la valeur entière minimale que le programme doit gérer?
0 '
À quoi {...}évalue la monade ?
Neil
Dans quel ordre sont les arguments de soustraction? J'obtiens la négation de ce que j'attends.
Neil
@Neil Désolé à ce sujet. La monade est {...}évaluée à 0. De plus, les arguments sont poussés dans l'ordre, donc 2est poussé, puis 3est poussé, donc lorsque le programme démarre, la deuxième entrée ( 3) est au-dessus de la pile. Je vais clarifier les deux dans le post.
DJMcMayhem

Réponses:

6

Pip -n , 151 148 101 98 octets

YRVg;VqR^"{}()<>[]";,8R J,8<>2AL,8("POy|i o0Syl1v0W@y{ }1yPU$+[ ]&@y0 1P$+[ ]"R0" (V{"R1"i}) "^s)y

Prend la liste des entrées comme arguments de ligne de commande et le code Brain-Flak de (une ligne de) stdin. Essayez-le en ligne!

Modifier: j'ai sauvé beaucoup d'octets par rapport à mon approche d'origine en passant à une stratégie de traduction et d'évaluation.

Non golfé et commenté

Cette version inclut également une sortie de débogage montrant le code Pip résultant de la traduction, ainsi que le contenu de la pile après exécution.

;;; Setup ;;;

; y is the active stack, l is the off-stack
; y is initialized from command-line arguments
y:RVg   (reversed to put the last input at the top)
; l is preset to empty list by default

; p is the program (read from stdin)
p:q

; Translate from braces to numbers 0-7 (we do this so that the
; later replacement step won't try to replace the braces in the
; Pip code)
p R: ^"()[]{}<>" 0,8

;;; Replace nilads with the appropriate code ;;;

; () => o (variable preset to 1)
p R: 01 "o"

; [] => v (variable preset to -1)
p R: 23 "v"

; {} => POy|i
; Pop y; return that value OR i (variable preset to 0)
p R: 45 "POy|i"

; <> => (V{Syli})
; Eval the code Syl to swap stacks y and l, then return i (i.e. 0)
p R: 67 "(V{Syli})"

;;; Replace monads with the appropriate code ;;;

; ( ) => yPU$+[ ]&@y
; Sum ($+) the inside and push (PU) the sum onto y; return
; the just-pushed value, which is the first element of y (@y)
; y will always be truthy (nonempty), since we just pushed a value onto it
p R: 0 "yPU$+["
p R: 1 "]&@y"

; [ ] => P$+[ ]
; Sum ($+) the inside, print (P) the sum, and return it
p R: 2 "P$+["
p R: 3 "]"

; { } => (V{W@y{ }i})
; Eval the code W@y{ }, which wraps the inside in curly braces
; and runs it while (W) the first element of y (@y) is truthy
; (i.e. not zero, and not nil from an empty stack)
; Then return i (i.e. 0)
p R: 4 "(V{W@y{"
p R: 5 "}i})"

; < > => (V{ i})
; Eval the inside, then return i (i.e. 0)
p R: 6 "(V{"
p R: 7 "i})"

; Debug: print the resulting translated code and a blank line
Pp.n

;;; Run the code ;;;

; Eval the translated code
(Vp)

; Output the active stack, newline-separated
PyJn

; Debug: print the active stack and the off-stack
P"Active stack: ".RPy
"Off-stack: ".RPl
DLosc
la source
Le pip est-il plus récent que ce défi?
DJMcMayhem
@DJMcMayhem Non ! Je n'utilise pas non plus de fonctionnalités plus récentes que le défi.
DLosc
59

Brain-Flak Classic , 1271 1247 1239 octets

<>(()){<>((([][][][][])<(((({}){})(({})({}))[])({}(({})({}({})({}{}(<>)))))[])>{()<{}>}{})<{{}}{}>())}{}<>(<(({()(((<>))<>)}{}{<({}(([][][])((({})({}))[]{})){})>((){[]<({}{})((){[]<({}{}<>((({})({})){}{}){})(<>)>}{}){{}{}<>(<({}{}())>)(<>)}>}{}){(<{}{}{}((<>))<>>)}{}}<>)<{({}[]<({}<>)<>{(<{}>)<>{<>({}[])}{}<>({}<>)(<>)}{}>)}{}<>>)>)<>{(({}[])(){(<{}>)<><(({})[])>[][][][]{()()()()(<{}>)}{}<>}{}<>)<>}<>{}{(({})<({()<<>({}<>)>}{})>([]))((){[](<(({}()()(<>))()()()){(<{}>)<>}>)}{}<>){{}((){[]<({}())((){[]<({}())((){[]<({}())((){[]<({}())((){[]<({}())((){[]<({}())((){[](<{}<>{({}<>)<>}{}(({}))({<{}({}<>)<>>{}(<<>({}[]<>)>)}<><{({}<>)<>}>{})>)}{}){{}{}(<([])>)}>}{}){{}<>{({}<>)<>}{}((({})())<{({}[]<({}<>)<>>)}>{}){({}[]<><({}<><({()<({}[]<({}<>)<>>)>}{}<>)><>)<>({()<({}[]<({}<>)<>>)>}{}<>)>)}<>(<{({}<>)<>}>)}>}{}){{}{}(<(())>)}>}{}){(<{}{}>)<>{({}<>)<>}{}(({}))({<{}({}<>)<>>({})(<<>({}<>)>)}<><{({}<>)<>}>){{}([][][])<>(((<{}>)<>))}}>}{}){{}(<([{}])>)}>}{}){{}((<{}>))}>}{}){{}(({})(<()>)<<>{({}<>)<>}{}({}()<>)<>>)<>(<({}<>)>)<>{({}<>)<>}}{}(<({}<({}<>)<>>{})<>({}<>)>)<>(<({}())>)}{}({}<{({}[]<({}<>)<>>)}{}>){((({}[]<>){(<{}({}<>)>)}{}())<{({}()<({}<>)<>(({})[])>{[][](<{}>)}{})}{}>()){{}(<>)}}{}}{}{({}[]<[{}]>)}{}{({}[]<{}>)}{}

Essayez-le en ligne!

+4 octets de correction d'un bug avec la condition dans la {...}monade, et -36 octets de divers golfs.

1238 octets de code, +1 octet pour l' -aindicateur (qui peut être combiné avec l'indicateur de langue).

Ceci est désormais évalué {...}à zéro selon la spécification de défi. Notez que Brain-Flak lui-même a été évalué {...}comme la somme de toutes les exécutions depuis le correctif du 7 mai 2016, deux jours avant la publication de ce défi.

Le code suivant interprète Brain-Flak Classic correctement, avec {...}la somme de toutes les exécutions. La seule différence entre les deux interprètes est le placement d'une {}nilade.

<>(()){<>((([][][][][])<(((({}){})(({})({}))[])({}(({})({}({})({}{}(<>)))))[])>{()<{}>}{})<{{}}{}>())}{}<>(<(({()(((<>))<>)}{}{<({}(([][][])((({})({}))[]{})){})>((){[]<({}{})((){[]<({}{}<>((({})({})){}{}){})(<>)>}{}){{}{}<>(<({}{}())>)(<>)}>}{}){(<{}{}{}((<>))<>>)}{}}<>)<{({}[]<({}<>)<>{(<{}>)<>{<>({}[])}{}<>({}<>)(<>)}{}>)}{}<>>)>)<>{(({}[])(){(<{}>)<><(({})[])>[][][][]{()()()()(<{}>)}{}<>}{}<>)<>}<>{}{(({})<({()<<>({}<>)>}{})>([]))((){[](<(({}()()(<>))()()()){(<{}>)<>}>)}{}<>){{}((){[]<({}())((){[]<({}())((){[]<({}())((){[]<({}())((){[]<({}())((){[]<({}())((){[](<{}<>{({}<>)<>}{}(({}))({<{}({}<>)<>>{}(<<>({}[]<>)>)}<><{({}<>)<>}>{})>)}{}){{}{}(<([])>)}>}{}){{}<>{({}<>)<>}{}((({})())<{({}[]<({}<>)<>>)}>{}){({}[]<><({}<><({()<({}[]<({}<>)<>>)>}{}<>)><>)<>({()<({}[]<({}<>)<>>)>}{}<>)>)}<>(<{({}<>)<>}>)}>}{}){{}{}(<(())>)}>}{}){(<{}>)<>{({}<>)<>}{}(({}))({<{}({}<>)<>>({})(<<>({}<>)>)}<><{({}<>)<>}>{}){{}([][][])<>(((<{}>)<>))}}>}{}){{}(<([{}])>)}>}{}){{}((<{}>))}>}{}){{}(({})(<()>)<<>{({}<>)<>}{}({}()<>)<>>)<>(<({}<>)>)<>{({}<>)<>}}{}(<({}<({}<>)<>>{})<>({}<>)>)<>(<({}())>)}{}({}<{({}[]<({}<>)<>>)}{}>){((({}[]<>){(<{}({}<>)>)}{}())<{({}()<({}<>)<>(({})[])>{[][](<{}>)}{})}{}>()){{}(<>)}}{}}{}{({}[]<[{}]>)}{}{({}[]<{}>)}{}

Essayez-le en ligne!

L'entrée (vers l'un ou l'autre interprète) est le programme Brain-Flak Classic à interpréter, puis une nouvelle ligne, puis une liste d'entiers séparés par des espaces. Aucune validation n'est effectuée sur l'entrée. La nouvelle ligne est requise, même si le programme ou l'entrée est vide.

La première étape consiste à analyser toutes les entrées, en commençant par les crochets:

# Move to right stack, and push 1 to allow loop to start
<>(())
{
   # While keeping -5 on third stack:
   <>((([][][][][])<

       # Pop bracket or newline k from left stack, and push 0, k-10, k-40, k-60, k-91, k-123 on right stack
       (((({}){})(({})({}))[])({}(({})({}({})({}{}(<>)))))[])

   # Search this list for a zero, and push the number of nonzero entries popped minus 5 
   # (thus replacing the 0 if it was destroyed)
   >{()<{}>}{})

   # Remove rest of list, and push the same number plus 1
   # Result is -4 for {, -3 for [, -2 for <, -1 for (, 0 for newline, or 1 for everything else (assumed closing bracket)
   <{{}}{}>())

# Repeat until newline found
}{}<>

Ensuite, les entiers sont analysés. Cela ne serait normalement pas requis, mais l'entrée a été prise en ASCII. Cela a cependant une doublure argentée: la saisie de texte nous permet de déterminer la hauteur de la pile, ce qui simplifie les choses lorsque nous n'avons pas accès à la hauteur de pile nilad.

Les nombres entiers sont analysés en deux nombres sur la deuxième pile: un pour la valeur absolue et un pour le signe. Ceux-ci sont ensuite replacés dans la première pile.

Les piles interprétées sont stockées sous le code de la première pile dans l'ordre suivant: hauteur de pile actuelle, pile actuelle, autre hauteur de pile, autre pile. Le 0 pour l'autre hauteur de pile n'a pas besoin d'être poussé à ce stade, car ce sera un zéro implicite la première fois qu'il sera lu.

(<((

    # If stack nonempty, register first stack entry.
    {()(((<>))<>)}{}

    # For each byte k of input:
    {

        # Push -3, -13, and k-32
        <({}(([][][])((({})({}))[]{})){})>

        # Evaluate to 1 if space
        # If not space (32):
        ((){[]<

            # If not minus (45):
            ({}{})((){[]<

                # Replace top of right stack (n) with 10*n + (k-48)
                ({}{}<>((({})({})){}{}){})(<>)

            # Else (i.e., if minus):
            >}{}){

                # Remove excess "else" entry and -3
                {}{}

                # Set sign to negative (and destroy magnitude that shouldn't even be there yet)
                <>(<({}{}())>)(<>)}

        # Else (i.e., if space):
        >}{}){

            # Remove working data for byte, and push two more 0s onto right stack
            (<{}{}{}((<>))<>>)

    # Push number of integers found
    }{}}<>)

    # For each integer:
    <{({}[]<

        # Move magnitude back to left stack
        ({}<>)<>

        # If sign is negative, negate
        {(<{}>)<>{<>({}[])}{}<>({}<>)(<>)}{}

    >)}{}

    # Push stack height onto stack
    <>>)

# Push 0
>)

La représentation du code est maintenant replacée dans la pile de gauche. Pour faciliter les choses plus tard, nous soustrayons 4 des parenthèses ouvrantes des nilades, de sorte que chaque opération ait un entier unique de -1 à -8.

# For each bracket in the code:
<>{

    # Push k-1 and evaluate to k
    (({}[])()

    # If not closing bracket:
    {

        # Check next bracket (previously checked, since we started at the end here)
        (<{}>)<><(({})[])>

        # Subtract 4 if next bracket is closing bracket
        # Inverting this condition would save 8 bytes here, but cost 12 bytes later.
        [][][][]{()()()()(<{}>)}{}

    <>}{}

    # Push result onto left stack
    <>)

<>}<>{}

La partie principale du programme consiste en fait à interpréter les instructions. Au début de chaque itération de la boucle principale, l'instruction en cours se trouve en haut de la pile de gauche, tout ce qui se trouve après en dessous sur la même pile, et tout ce qui se trouve avant de se trouver sur la pile de droite. J'ai tendance à visualiser cela comme ayant un livre ouvert sur une certaine page.

{

    (

        # Get current instruction
        ({})

        # Move all code to left stack, and track the current position in code
        <({()<<>({}<>)>}{})>

        # Push -1, signifying that the code will move forward to just before a matching }.
        # In most cases, this will become 0 (do nothing special) before it is acted upon
        ([])

    # Push instruction minus 1
    )

    # If opening bracket:
    ((){[](<

        # Push instruction+1 and instruction+4
        (({}()()(<>))()()())

        # If instruction+4 is nonzero (not loop monad), replace the earlier -1 with 0 to cancel forward seek
        # This would be clearer as {(<{}>)<>(<{}>)<>}, but that would be unnecessarily verbose
        {(<{}>)<>}

    # Else (i.e., if closing bracket):
    >)}{}<>){

# If closing bracket, parse command
# Post-condition for all: if not moving to {, pop two and push evaluation, 0.
# (For nilads, can assume second from top is 0.)
# If moving to {, pop one, push -3, 0, 0.

        # Seven nested if/else statements, corresponding to eight possible instruction.
        # The "else" statements end with 0 already on the stack, so no need to push a 0 except in the innermost if.
        # Each one beyond the first increments the instruction by 1 to compare the result with 0
        # Each instruction will pop the instruction, leaving only its evaluation (with a 0 on top).
        {}((){[]<
        ({}())((){[]<
        ({}())((){[]<
        ({}())((){[]<
        ({}())((){[]<
        ({}())((){[]<
        ({}())((){[](<

            # -7: pop
            # Pop instruction to reveal existing 0 evaluation
            {}

            # Move code out of the way to access stack
            <>{({}<>)<>}{}

            # Duplicate stack height (only useful if stack height is zero)
            (({}))

            (

                # If stack height nonzero
                {

                    # Save stack height on second stack
                    <{}({}<>)<>>

                    # Pop stack
                    {}

                    # Move stack height back and subtract 1
                    (<<>({}[]<>)>)

                }

                # Move code back to normal position
                <><{({}<>)<>}>{}

            # Evaluate as popped entry (0 if nothing popped)
            )

        # (else)
        >)}{}){

            # -6: -1 nilad
            # Just evaluate as -1
            {}{}(<([])>)

        # (else)
        }>}{}){

            # -5: swap nilad
            # Move code out of the way to access stack
            {}<>{({}<>)<>}{}

            # Number of integers to move: stack height + 1 (namely, the stack height and every entry in the stack)
            ((({})())

            # Move to second stack
            <{({}[]<({}<>)<>>)}>{}

            # Do (stack height + 1) times again
            ){({}[]<><

                # Get stack element
                ({}<><

                    # Move alternate (interpreted) stack to second (real) stack, and push length on top of it
                    ({()<({}[]<({}<>)<>>)>}{}<>)

                # Push current stack element below alternate stack
                ><>)

                # Move alternate stack back above newly pushed element
                <>({()<({}[]<({}<>)<>>)>}{}<>)

            >)}

            # Move code back to normal position
            <>(<{({}<>)<>}>)

        # (else)
        }>}{}){

            # -4: 1
            # Just evaluate to 1
            {}{}(<(())>)

        # (else)
        }>}{}){

            # -3: loop
            # Create zero on stack while keeping existing evaluation
            # This becomes (<{}{}>) in the version that meets the challenge spec
            (<{}>)

            # Move code out of the way to access stack
            <>{({}<>)<>}{}

            # Duplicate stack height
            (({}))

            (

                # If stack height nonzero
                {

                    # Save stack height on second stack
                    <{}({}<>)<>>

                    # Peek at top of stack
                    ({})

                    # Move stack height back
                    (<<>({}<>)>)

                }

                # Move code back to normal position
                <><{({}<>)<>}>

            # Look at peeked entry
            # Remove the {} in the version meeting the challenge spec
            {})

            # If peeked entry is nonzero
            {

                # Replace -3 instruction on third stack
                {}([][][])

                # Replace loop indicator to 0 (to be incremented later to 1)
                <>(((<{}>)

                # Create dummy third stack entry to pop
                <>))

            }

        # (else)
        }>}{}){

            # -2: print
            # Just print evaluation without modifying it
            {}(<([{}])>)

        # (else)
        }>}{}){

            # -1: evaluate as zero
            # Just change evaluation to 0
            {}((<{}>))

        # else
        }>}{}){

            # 0: push
            # Get current evaluation (without modifying it)
            {}(({})

                # Create zero on stack as barrier
                (<()>)

                # Move code out of the way to access stack
                <<>{({}<>)<>}{}

                # Increment stack height and save on other stack
                ({}()<>)<>

            # Push evaluation
            >)

            # Move stack height back (and push zero)
            <>(<({}<>)>)

            # Move code back to normal position
            <>{({}<>)<>}

        }{}

        # Update third stack by adding evaluation to previous entry's evaluation
        # Previous entry's instruction is saved temporarily on left stack
        (<({}<({}<>)<>>{})<>({}<>)>)

        # Increment loop indicator
        # If instruction was loop monad and top of stack was nonzero, this increments 0 to 1 (search backward)
        # Otherwise, this increments -1 to 0 (do nothing)
        <>(<({}())>)

    }{}

    # While holding onto loop indicator
    ({}<

        # Go to immediately after executed symbol
        {({}[]<({}<>)<>>)}{}

    >)

    # If looping behavior:
    {

        # Switch stack and check if searching forward
        ((({}[]<>)

        # If so:
        {

            # Move just-executed { back to left stack, and move with it
            (<{}({}<>)>)

        }{}

        # Either way, we are currently looking at the just-executed bracket.
        # In addition, the position we wish to move to is on the current stack.

        # Push unmodified loop indicator as initial value in search
        ())

        # While value is nonzero:
        <{

            # Add 1
            ({}()

                # Move current instruction to other stack
                <({}<>)<>

                # Check whether next instruction is closing bracket
                (({})[])>

                # If opening bracket, subtract 2 from value
                {[][](<{}>)}{}

            )

        }{}>

        # If searching backward, move back to left stack
        ()){{}(<>)}

    }{}

}

Après avoir quitté la boucle principale, tout le code est sur la bonne pile. Les seules choses sur la pile de gauche sont un zéro et les deux piles interprétées. Produire la sortie correcte est une question simple.

# Pop the zero
{}

# Output current stack
{({}[]<[{}]>)}{}

# Discard other stack to avoid implicit printing
{({}[]<{}>)}{}
Nitrodon
la source
12
: O quoi le ... Ok, la prime immédiatement. Bon travail! : D
DJMcMayhem
4
Permettez-moi de clarifier les choses ... vous avez créé un interprète pour la langue à interpréter. YoDawg
tisaconundrum
OK, pourquoi n'a-t-il qu'un numéro de vote à 2 chiffres?
NieDzejkob
Bon travail sur la mise en œuvre correcte de l'accumulateur dans {...}, qui est le comportement correct pour le cerveau-flak moderne et (je pense) le cerveau-flak classique, cependant j'ai écrit dans le défi qui {...}vaut 0. Vous pourriez probablement jouer au golf un nombre important d'octets de en supprimant cette fonctionnalité, même si ce serait bien de conserver l'original parce qu'il est techniquement plus correct en général (juste mal pour ce défi)
DJMcMayhem
@DJMcMayhem Fixed. Ne me faites pas porter l'intégralité de l'interprète sur cette version hypothétique de Brain-Flak.
Nitrodon
8

APL, 255 257 octets

b←{S←(⌽⍺)⍬
e←{0=⍴⍵:0
v+∇⊃_ v←∇{r←⊂2↓⍵
'()'≡n←2↑⍵:r,1
'[]'≡n:r,¯1
'{}'≡n:r,{i←⊃⊃⊃S⋄S[1]↓⍨←1⋄i}⍬
'<>'≡n:r,0⊣S⌽⍨←1
r←⊂⍵↓⍨i←0⍳⍨(+\c=⍵)-+\')]>}'['([<{'⍳c←⊃⍵]=⍵
i←1↓¯1↓c←i↑⍵
'('=c←⊃c:r,S[1],⍨←⍺⍺i
'['=c:r,+⎕←⍺⍺i
'{'=c:r,{0≠⊃⊃⊃S:∇e i⋄0}⍬
'<'=c:r,0⊣⍺⍺i}⍵}
⎕←⍪⊃S⊣e⍵}

Cela prend le programme comme argument de droite et l'entrée du programme comme argument de gauche, c'est-à-dire:

      2 3 b '({}{})'
5
      2 3 b '({}<>){({}[])<>({}[])<>}<>'
¯1
      7 8 b '({}<>)<>({}[]){({}[])<>(({}))<>}<>{({}<>{})<>}<>'
56
      5 b '<>((()))<>{({}[])<>({}<>)<>(({})<>({}<>))<>}<>'
13
 8
 5
 3
 2
 1
 1

Version non golfée: ici .

marinus
la source
7

APL (Dyalog Classic) , 146 octets

↑⍕¨s⊣{⍎⍕1 ¯1'(s↓⍨←1)⊢⊃s' '0⊣s t←t s' 's,⍨←+/∇¨a' '⎕←+/∇¨a' '∇{×⊃s:∇⍺⍺¨a⋄0}0' '0⊣+/∇¨a'[(⊃⍵)+4×⍬≢a1↓⍵]}¨⍎∊(')',⍨'(',¨⍕¨⍳4)[0,4,⍨'([{<'⍳⍞]⊣s←⌽⎕⊣t←⍬

Essayez-le en ligne!

un classique en interprétant un autre :)

ngn
la source
6

Python 3, 429 octets

import re
S='s+=[v];v=0';T='v+=s.pop()';i=0
d={'()':'v+=1','(':S,')':'a+=[v];'+T,'[]':'v-=1','[':S,']':'print(v);'+T,'<>':'a.reverse()','<':S,'>':T,'{}':'v+=0if a[-1]==""else a.pop()','{':S+';while a[-1]:','}':T}
def r(m):global i;t=m.group();i-=(t=='}');s=' '*i;i+=(t=='{');return''.join(s+r+'\n'for r in d[t].split(';'))
def g(c,*a):
 a,s,v=['']+list(a),[],0;exec(re.sub(r'[<({[]?[]})>]?',r,c));
 while a[-1]!="":print(a.pop())

Utilisé comme g('[{}{}]', 2, 3)

Il utilise re.subpour «compiler» la source de brain-flak en python, puis exécute le python. (pour le débogage, remplacez execpar printpour obtenir une liste du code python)

Une indentation correctement imbriquée tandis que les boucles consomment beaucoup d'octets dans le code.

RootTwo
la source
3

Python, 616 octets

Instructions:

  1. Exécuter avec python
  2. Entrez la liste au [1,2,...]format, puis appuyez sur Entrée
  3. Collez / écrivez le programme, puis appuyez à nouveau sur Entrée
  4. Terminé

Fondamentalement, ce programme fait "compile" récursivement le code Brain-flak dans des listes imbriquées et interprète récursivement cette liste. Il y a probablement un moyen de combiner les deux ...

Je vais essayer de retravailler la logique plus tard.

y="([{<)]}>"
w,z,g=print,len,input
def c(s):
 if z(s)<1:return[]
 t,i,o=[],1,0
 t.append(y.index(s[0]))
 while z(t)>0:
  x=y.index(s[i])
  if x<4:t.append(x)
  else:o=t.pop()
  i+=1
 r=[[o,c(s[1:i-1])]]
 r.extend(c(s[i:]))
 return r
p=lambda t:t.pop()if z(t)>0 else 0
k=lambda t:t[z(t)-1]if z(t)>0 else 0
r,l=[],eval(g())
a=l
def i(u):
 v=0
 global a
 for t,n in u:
  if t<1:
   if n:o=i(n);v+=o;a.append(o)
   else:v+=1
  if t==1:
   if n:o=i(n);v+=o;w(o)
   else:v-=1
  if t==2:
   if n:
    while k(a)!=0:i(n)
   else:v+=p(a)
  if t>2:
   if n:i(n)
   elif a==l:a=r
   else:a=l
 return v
i(c(g()))
for n in a:w(n)
Bleu
la source
3

Perl 5.6, 419 414 octets

Je l'ai un peu joué au golf, mais il y a probablement des possibilités d'amélioration. Ajout de nouvelles lignes et d'onglets ici pour plus de lisibilité:

use Text::Balanced extract_bracketed;
$s=shift;
@a=reverse@ARGV;
sub p
{
    my($c)=@_;
    my$s=0;
    while(my$n=extract_bracketed($c)){
        $s+='()'eq$n||'{}'eq$n&&shift@a;
        $s-='[]'eq$n;
        @t=@a,@a=@i,@i=@t if'<>'eq$n;
        my$m=chop($n);
        $n=substr($n,1);
        if($n){
            p($n)while'}'eq$m&&$a[0];
            p($n)if'}'ne$m;
            $s+=$v,unshift@a,$v if')'eq$m;
            $s+=$v,print"n=$n m=$m v=$v\n"if']'eq$m;
        }
    }
    $v=$s;
}
p($s);
foreach(@a){
    print"$_\n";
}
Neil
la source
1

Python 2 , 361 , 348 octets

c,s=input();s=s,[]
a=s[0]
def w():global a,s;s=s[::-1];a=s[0];return 0
def p(c):a.append(c);return c
def n(c):print c;return c
z=lambda c:0
def l(f):
 global a
 while a and a[-1]:f()
 return 0
for x,y in zip("() ( [] {} <> [ < { } ] >".split(),"+1 +p( -1 +(len(a)and(a.pop())) +w() +n( +z( +l(lambda: ) ) )".split()):c=c.replace(x,y)
exec c
print a

Essayez-le en ligne!

-13 octets enregistrés grâce à @Mr. Xcoder!

DJMcMayhem
la source