Напишите классическую интерпретацию мозга!

18

Brain-Flak (помесь Brainf ** k и Flak-Overstow) является основанным на стеке эзотерическим языком. С тех пор как этот вызов был опубликован, язык развивался и обновлялся, но эта первая редакция языка известна как «классическая мозговая атака».

Вы должны написать программу или функцию, которая берет строку классического кода Brain-Flak и оценивает ее. Он также возьмет (возможно пустой) список целых чисел. Есть входы в классическую программу Brain-Flak.

Язык

Brain-Flak имеет два стека, известные как «левый» и «правый». Активный стек начинается слева. Если пустой стек выскочил или заглянул, он вернет 0. Нет переменных. Когда программа запускается, каждый вход помещается в активный стек по порядку (так, чтобы последний вход был сверху стека).

Единственными действительными символами в программе Brain-Flak являются ()[]{}<>, и они всегда должны быть сбалансированы . Если есть недопустимые символы или несоответствующие скобки, вы получите неопределенное поведение. Все действительно.

Есть два типа функций: Nilads и монады . Nilad это функция , которая принимает 0 аргументов. Вот все нилады:

  • () +1.
  • [] -1.
  • {} Поп активный стек.
  • <> Переключить активный стек.

Они объединяются вместе, когда они оцениваются. Итак, если у нас было 3 на вершине активного стека, этот фрагмент:

()(){}

оценил бы, 1 + 1 + active.pop()что оценил бы к 5. <>оценивает к 0.

Монады берут один аргумент, кусок кода Brain-Flak. Вот все монады:

  • (n) Нажмите 'n' в активном стеке.
  • [n] Выведите 'n' как int и перевод строки.
  • {foo}Пока active.peek ()! = 0, делайте foo. Оценивает до 0¹.
  • <foo> Выполните foo, но оцените его как 0.

Эти функции также будут возвращать значение внутри них, поэтому

(()()())

Будет толкать 3 и

[()()()]

Напечатает 3 но

[(()()())]

Напечатает и нажмет 3.

Когда выполнение программы завершено, каждое значение, оставленное в активном стеке, печатается как целое число с новой строкой между. Значения в другом стеке игнорируются.

Правила:

  • Ваша программа должна поддерживать числа в диапазоне (-128, 127) и размер стека не менее 255. Если вы поддерживаете больше, отлично.

  • Переполнение / переполнение не определено.

Образец ввода-вывода:

Пустая программа:

Вход: нет

Выход: нет

Дополнение. Источник:

({}{})

Входные данные:

2, 3

Выход:

5

Вычитание. Источник:

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

Входные данные:

2, 3

Выход:

-1

Умножение. Источник:

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

Входные данные:

7, 8

Выход:

56

Фибоначчи. Источник:

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

Входные данные:

5

Выход:

13
8
5
3
2
1
1

Правда машина

{[({})]}

Применяются стандартные лазейки, и выигрывает самый короткий ответ в байтах.


  • ¹: Это было на самом деле ошибка с моей стороны. {...} следует оценить сумму всех его прогонов, что является ИМО одной из самых крутых особенностей мозгового штурма. Тем не менее, для целей этой задачи предположим, что {...} оценивается как 0.
DJMcMayhem
источник
Существует ли правило относительно минимального целочисленного значения, которое должна обрабатывать программа?
0 '
Что {...}оценивает монада ?
Нейл
В каком порядке находятся аргументы вычитания? Я получаю отрицание того, что я ожидаю.
Нил
@Neil К сожалению об этом. Монада {...}оценивается как 0. Кроме того, аргументы передаются по порядку, поэтому передаются 2, затем 3передаются, поэтому, когда программа запускается, второй input ( 3) находится сверху стека. Я проясню оба из этого поста.
DJMcMayhem

Ответы:

6

Пип -n , 151 148 101 98 байт

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

Принимает список входных данных в качестве аргументов командной строки и код Brain-Flak из (строки) stdin. Попробуйте онлайн!

Изменить: сэкономил много байтов по сравнению с моим первоначальным подходом, переключившись на стратегию translate-and-eval.

Разоблаченный и прокомментированный

Эта версия также включает в себя некоторые выходные данные отладки, показывающие код Pip, полученный в результате перевода, а также содержимое стека после выполнения.

;;; 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
источник
Пип новее, чем этот вызов?
DJMcMayhem
@DJMcMayhem Нет ! Также я не использую какие-либо функции, более новые, чем вызов.
DLosc
59

Brain-Flak Classic , 1271 1247 1239 байт

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

Попробуйте онлайн!

+4 байта от исправления ошибки с состоянием в {...}монаде и -36 байтов от различных гольфов.

1238 байт кода, +1 байт для -aфлага (который можно комбинировать с языковым флагом).

Это теперь оценивается {...}как ноль согласно спецификации вызова. Обратите внимание, что сама Brain-Flak оценивается {...}как сумма всех запусков с момента исправления 7 мая 2016 года за два дня до публикации этого вызова.

Следующий код правильно интерпретирует Brain-Flak Classic с {...}суммой всех запусков. Единственная разница между двумя переводчиками - это размещение одного {}nilad.

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

Попробуйте онлайн!

Ввод (для любого интерпретатора) - это программа Brain-Flak Classic для интерпретации, затем новая строка, затем разделенный пробелами список целых чисел. На входе проверка не выполняется. Новая строка обязательна, даже если программа или ввод пустые.

Первым шагом является анализ всех входных данных, начиная с скобок:

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

Затем целые числа анализируются. Обычно это не требуется, но вход был взят как ASCII. Это имеет серебряную подкладку, хотя: ввод текста позволяет нам определять высоту стека, что упрощает вещи, когда у нас нет доступа к высоте стека nilad.

Целые числа разбиты на два числа во втором стеке: одно для абсолютного значения и одно для знака. Затем они перемещаются обратно в первый стек.

Интерпретируемые стеки хранятся под кодом в первом стеке в следующем порядке: текущая высота стека, текущий стек, другая высота стека, другой стек. 0 для другой высоты стека не нужно сдвигать в этой точке, так как это будет неявный ноль при первом чтении.

(<((

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

Представление кода теперь перемещено обратно в левый стек. Чтобы потом было легче, мы вычитаем 4 из открывающих скобок нилад, чтобы каждая операция имела уникальное целое число от -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
    <>)

<>}<>{}

Основная часть программы фактически интерпретирует инструкции. В начале каждой итерации основного цикла текущая инструкция находится в верхней части левого стека, все, что находится ниже того же стека, и все, что находится до того, как она находится в правом стэке. Я склонен визуализировать это как книгу, открытую для определенной страницы.

{

    (

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

    }{}

}

После выхода из основного цикла весь код находится в правильном стеке. Единственные вещи в левом стеке - это ноль и два интерпретированных стека. Получение правильного результата - дело простое.

# Pop the zero
{}

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

# Discard other stack to avoid implicit printing
{({}[]<{}>)}{}
Nitrodon
источник
12
: O, что за ... Хорошо, немедленно ловить Хорошая работа! : D
DJMcMayhem
4
Позвольте мне понять это прямо ... Вы создали переводчика для языка, который должен быть интерпретирован. YoDawg
tisaconundrum
Хорошо, почему он имеет только 2-значный номер upvote?
NieDzejkob
Хорошая работа по правильному внедрению аккумулятора {...}, который является правильным поведением для современных мозговых и (как мне кажется) классических мозговых атак, однако я написал в задаче, которая {...}оценивается как 0. Вы, вероятно, можете играть в гольф значительное количество байтов удалив эту функциональность, хотя было бы неплохо сохранить оригинал, потому что он технически более
точен
@DJMcMayhem Исправлено. Только не заставляйте меня переводить весь переводчик на эту гипотетическую версию Brain-Flak.
Нитродон
8

APL, 255 257 байт

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

Это принимает программу в качестве правого аргумента, а ввод программы - в качестве левого аргумента, то есть:

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

Безголовая версия: здесь .

Мэринус
источник
7

APL (Dyalog Classic) , 146 байтов

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

Попробуйте онлайн!

одна классика интерпретирует другую :)

СПП
источник
6

Python 3, 429 байт

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

Используется как g('[{}{}]', 2, 3)

Он использует re.subдля «компиляции» исходных текстов мозга в python, а затем выполняет питон. (для отладки замените execна, printчтобы получить список кода Python)

Правильный отступ для вложенных циклов while пожирает в коде много байтов.

RootTwo
источник
3

Python, 616 байт

Инструкции:

  1. Беги с питоном
  2. Введите список в [1,2,...]формате, затем нажмите ввод
  3. Вставьте / запишите программу, затем нажмите Enter еще раз
  4. Выполнено

По сути, эта программа рекурсивно «компилирует» код Brain-flak во вложенные списки и рекурсивно интерпретирует этот список. Там, вероятно, есть способ объединить два ...

Я постараюсь переработать логику позже.

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)
синий
источник
3

Perl 5,6, 419 414 байт

Я немного играл в гольф, но, вероятно, есть возможности для улучшения. Новые строки и вкладки добавлены здесь для удобства чтения:

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";
}
Нил
источник
1

Python 2 , 361 , 348 байт

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

Попробуйте онлайн!

-13 байтов сохранено благодаря @Mr. Xcoder!

DJMcMayhem
источник