Napisz klasycznego tłumacza na mózg!

18

Brain-Flak (skrzyżowanie Brainf ** k i Flak-Overstow) to ezoteryczny język oparty na stosach. Od czasu opublikowania tego wyzwania język ewoluował i był aktualizowany, ale ta pierwsza wersja języka znana jest jako „klasyczny flak mózgowy”.

Musisz napisać program lub funkcję, która pobiera ciąg klasycznego kodu Brain-Flak i ocenia go. Spowoduje to także przyjęcie (możliwej pustej) listy liczb całkowitych. Są dane wejściowe do klasycznego programu Brain-Flak.

Język

Brain-Flak ma dwa stosy, znane jako „lewy” i „prawy”. Aktywny stos zaczyna się od lewej. Jeśli pusty stos zostanie wysunięty lub zerknięty, zwróci 0. Nie ma żadnych zmiennych. Kiedy program się uruchamia, każde wejście jest wypychane do aktywnego stosu w kolejności (tak, aby ostatnie wejście było na szczycie stosu).

Jedynymi poprawnymi znakami w programie Brain-Flak są ()[]{}<>i zawsze muszą być zrównoważone . Jeśli występują niepoprawne znaki lub niedopasowane są nawiasy, zachowanie jest niezdefiniowane. Wszystko jest ważne.

Istnieją dwa rodzaje funkcji: Nilady i Monady . Nilad to funkcja, która zajmuje 0 argumenty. Oto wszystkie nilady:

  • () +1.
  • [] -1.
  • {} Pop aktywny stos.
  • <> Przełącz aktywny stos.

Są one łączone razem podczas oceny. Gdybyśmy mieli „3” nad aktywnym stosem, ten fragment kodu:

()(){}

oceniałby na, 1 + 1 + active.pop()co ocenia na 5. <>ocenia na 0.

Monady biorą jeden argument, kawałek kodu Brain-Flak. Oto wszystkie monady:

  • (n) Naciśnij 'n' na aktywnym stosie.
  • [n] Drukuj 'n' jako int i nowy wiersz.
  • {foo}Podczas gdy active.peek ()! = 0, wykonaj foo. Ocenia się na 0¹.
  • <foo> Wykonaj foo, ale oceń go jako 0.

Funkcje te zwrócą również wartość w nich, więc

(()()())

Naciska 3 i

[()()()]

Wydrukuje 3, ale

[(()()())]

Wydrukuje i pchnie 3.

Po zakończeniu wykonywania programu każda wartość pozostawiona na aktywnym stosie jest drukowana jako liczba całkowita, z nową linią między. Wartości na drugim stosie są ignorowane.

Zasady:

  • Twój program musi obsługiwać liczby z zakresu (-128, 127) i wielkość stosu co najmniej 255. Jeśli obsługujesz większe, świetnie.

  • Niedopełnienie / przepełnienie jest niezdefiniowane.

Próbka IO:

Pusty program:

Dane wejściowe: brak

Wyjście: brak

Dodanie. Źródło:

({}{})

Wejście:

2, 3

Wynik:

5

Odejmowanie. Źródło:

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

Wejście:

2, 3

Wynik:

-1

Mnożenie. Źródło:

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

Wejście:

7, 8

Wynik:

56

Fibonacciego. Źródło:

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

Wejście:

5

Wynik:

13
8
5
3
2
1
1

Maszyna prawdy

{[({})]}

Obowiązują standardowe luki, a najkrótsza odpowiedź w bajtach wygrywa.


  • ¹: To był właściwie błąd z mojej strony. {...} powinien ocenić sumę wszystkich swoich uruchomień, co jest IMO jedną z najfajniejszych cech uderzenia mózgu. Jednak na potrzeby tego wyzwania załóżmy, że wartość wynosi {...} 0.
DJMcMayhem
źródło
Czy istnieje reguła dotycząca minimalnej wartości całkowitej, którą program musi obsłużyć?
0 '
Co {...}ocenia monada ?
Neil
W jakiej kolejności są argumenty odejmowania? Dostaję negację tego, czego oczekuję.
Neil,
@Neil Przepraszamy za to. Monada ma {...}wartość 0. Ponadto argumenty są wypychane w kolejności, więc 2są wypychane, a następnie 3wypychane, więc gdy program się uruchamia, drugie wejście ( 3) znajduje się na górze stosu. Wyjaśnię oba w poście.
DJMcMayhem

Odpowiedzi:

6

Pip -n , 151 148 101 98 bajtów

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

Pobiera listę danych wejściowych jako argumenty wiersza polecenia i kod Brain-Flak z (linii) standardowego wejścia. Wypróbuj online!

Edycja: Oszczędź mnóstwo bajtów w porównaniu z moim oryginalnym podejściem, przechodząc na strategię tłumaczenia i ewaluacji.

Nie golfił i skomentował

Ta wersja zawiera również niektóre dane wyjściowe debugowania pokazujące kod Pip wynikający z tłumaczenia, a także zawartość stosu po wykonaniu.

;;; 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
źródło
Czy pip jest nowszy od tego wyzwania?
DJMcMayhem
@DJMcMayhem Nie ! Nie używam też żadnych funkcji nowszych niż wyzwanie.
DLosc
59

Brain-Flak Classic , 1271 1247 1239 bajtów

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

Wypróbuj online!

+4 bajty od naprawienia błędu z warunkiem w {...}monadzie i -36 bajtów z różnych pól golfowych.

1238 bajtów kodu, +1 bajt dla -aflagi (którą można połączyć z flagą języka).

To teraz ocenia się {...}jako zero według specyfikacji wyzwania. Zwróć uwagę, że sam Brain-Flak został oceniony {...}jako suma wszystkich przebiegów od poprawki 7 maja 2016 dwa dni przed opublikowaniem tego wyzwania.

Poniższy kod poprawnie interpretuje Brain-Flak Classic {...}jako sumę wszystkich przebiegów. Jedyną różnicą między dwoma tłumaczami jest umieszczenie jednego {}nilada.

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

Wypróbuj online!

Dane wejściowe (do dowolnego interpretera) to program Brain-Flak Classic do interpretacji, następnie nowa linia, a następnie rozdzielona spacjami lista liczb całkowitych. Na wejściu nie jest przeprowadzana walidacja. Nowa linia jest wymagana, nawet jeśli program lub dane wejściowe są puste.

Pierwszym krokiem jest parsowanie wszystkich danych wejściowych, zaczynając od nawiasów:

# 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
}{}<>

Następnie liczby całkowite są analizowane. Zwykle nie jest to wymagane, ale dane wejściowe zostały pobrane jako ASCII. Ma to jednak srebrną podszewkę: wprowadzanie tekstu pozwala nam określić wysokość stosu, co upraszcza rzeczy, gdy nie mamy dostępu do wysokości stosu nilad.

Liczby całkowite są parsowane na dwie liczby na drugim stosie: jeden dla wartości bezwzględnej i jeden dla znaku. Są one następnie przenoszone z powrotem na pierwszy stos.

Zinterpretowane stosy są przechowywane poniżej kodu na pierwszym stosie w następującej kolejności: bieżąca wysokość stosu, bieżąca wysokość stosu, inna wysokość stosu, inny stos. Wartość 0 dla drugiej wysokości stosu nie musi być w tym momencie wypychana, ponieważ będzie to domyślna wartość zero przy pierwszym czytaniu.

(<((

    # 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
>)

Reprezentacja kodu jest teraz przenoszona z powrotem na lewy stos. Aby ułatwić później, odejmujemy 4 od nawiasów otwierających niladów, aby każda operacja miała unikalną liczbę całkowitą od -1 do -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
    <>)

<>}<>{}

Główną częścią programu jest interpretacja instrukcji. Na początku każdej iteracji głównej pętli bieżąca instrukcja znajduje się na górze lewego stosu, wszystko po nim na tym samym stosie i wszystko przed nim na właściwym stosie. Zazwyczaj wyobrażam to sobie jako książkę otwartą na określoną stronę.

{

    (

        # 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
        ()){{}(<>)}

    }{}

}

Po wyjściu z głównej pętli cały kod znajduje się na odpowiednim stosie. Jedyne rzeczy na lewym stosie to zero i dwa interpretowane stosy. Uzyskanie prawidłowego wyniku jest prostą sprawą.

# Pop the zero
{}

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

# Discard other stack to avoid implicit printing
{({}[]<{}>)}{}
Nitrodon
źródło
12
: O, co ... Ok, od razu nagroda. Dobra robota! : D
DJMcMayhem
4
Pozwól mi to wyjaśnić ... stworzyłeś tłumacza języka, który ma być tłumaczony. YoDawg
tisaconundrum
OK, dlaczego ma tylko 2-cyfrowy numer upvote?
NieDzejkob
Dobra robota przy prawidłowym wdrażaniu akumulatora {...}, co jest poprawnym zachowaniem dla współczesnego flakera mózgu i (myślę) klasycznego flakera mózgu, jednak napisałem w wyzwaniu, które {...}ocenia się na 0. Prawdopodobnie mógłbyś zagrać w znaczną liczbę bajtów usuwając tę ​​funkcjonalność, chociaż dobrze byłoby zachować oryginał, ponieważ jest on technicznie ogólnie bardziej poprawny (po prostu niewłaściwy do tego wyzwania)
DJMcMayhem
@DJMcMayhem Naprawiono. Tylko nie zmuszaj mnie do przeniesienia całego tłumacza na tę hipotetyczną wersję Brain-Flak.
Nitrodon,
8

APL, 255 257 bajtów

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⍵}

Pobiera to program jako jego prawy argument, a dane wejściowe programu jako jego lewy argument, tj .:

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

Wersja bez golfa: tutaj .

marinus
źródło
7

APL (Dyalog Classic) , 146 bajtów

↑⍕¨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←⍬

Wypróbuj online!

jeden klasyczny tłumaczący inny :)

ngn
źródło
6

Python 3, 429 bajtów

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())

Używany jak g('[{}{}]', 2, 3)

Służy re.subdo „kompilacji” źródła wyładowań mózgowych do Pythona, a następnie uruchamia go. (dla debuging wymienić execz printaby uzyskać listę kodu Pythona)

Właściwe wcięcie zagnieżdżone podczas gdy pętle zjadają wiele bajtów w kodzie.

RootTwo
źródło
3

Python, 616 bajtów

Instrukcje:

  1. Uruchom z pythonem
  2. Wprowadź listę w [1,2,...]formacie, a następnie naciśnij klawisz Enter
  3. Wklej / napisz program, a następnie naciśnij ponownie Enter
  4. Gotowy

Zasadniczo program ten rekurencyjnie „kompiluje” kod Flake Brain w zagnieżdżone listy i rekursywnie interpretuje tę listę. Prawdopodobnie istnieje sposób na połączenie tych dwóch ...

Spróbuję przerobić logikę później.

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)
niebieski
źródło
3

Perl 5.6, 419 414 bajtów

Grałem trochę w golfa, ale prawdopodobnie istnieje możliwość poprawy. Nowe linie i zakładki dodane tutaj ze względu na odrobinę czytelności:

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
źródło
1

Python 2 , 361 , 348 bajtów

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

Wypróbuj online!

-13 bajtów zapisanych dzięki @Mr. Xcoder!

DJMcMayhem
źródło