Интерпретировать /// (произносится как «косая черта»)

30

Потому что мы не можем насытиться эзотерическими языками, не так ли?

/// - произносится косая черта - забавный маленький язык, основанный на s///функции замены регулярных выражений славы Perl. Он содержит только два специальных символа, косую черту /и обратную косую черту \. Вы можете найти полную статью об этом на вики- сайте esolangs , но я приведу описание языка ниже, а также некоторые примеры.

Короче говоря, это работает, идентифицируя /pattern/repl/restв программе и делая замену столько раз, сколько возможно. Никакие символы не являются специальными, за исключением /и \: /разграничивает шаблоны и замены в программе, а также \позволяет вставлять литералы /или \символы в ваш код. Примечательно, что это не регулярные выражения, а просто подстановки строк.

Ваша задача состоит в том, чтобы создать интерпретатор для языка /// в виде программы, читающей STDIN, или функции, принимающей строковый аргумент, в минимально возможном количестве символов.

Вы можете использовать любой язык, кроме самого ///. Вы не можете использовать любые библиотеки, которые интерпретируют ///; вы можете, однако, использовать регулярные выражения, библиотеки регулярных выражений или библиотеки соответствия строк.


выполнение

Существует четыре состояния: печать , рисунок , замена и замена . В каждом штате, кроме замены :

  • Если программа пуста, выполнение останавливается.
  • Иначе, если первый символ есть \, сделайте что-нибудь со следующим символом (если он есть) и удалите оба из программы.
  • Иначе, если первый символ есть /, удалите его и перейдите к следующему состоянию.
  • Иначе, сделайте что-нибудь с первым символом и удалите его из программы.
  • Повторение.

Состояния циклически изменяются в порядке печати , рисунка , замены и замены .

  • В режиме печати «сделать что-то» означает вывод символа.
  • В режиме паттерна «сделать что-то» означает добавить символ в текущий паттерн.
  • В режиме замены «сделать что-то» означает добавить персонажа к текущей замене.

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

В программе /foo/foobar/foo foo fooпроисходит следующее:

/foo/foobar/foo foo foo
foo foo foo
foobar foo foo
foobarbar foo foo
foobarbarbar foo foo
...

Это зацикливается навсегда и никогда не выходит из режима замены . Точно так же, если шаблон пуст, то первое совпадение с пустой строкой - в начале программы - всегда совпадает, поэтому режим замены зацикливается навсегда, никогда не останавливаясь.


Примеры

no

Выход: no.

/ world! world!/Hello,/ world! world! world!

Выход: Hello, world!.

/foo/Hello, world!//B\/\\R/foo/B/\R

Выход: Hello, world!.

a/ab/bbaa/abb

Выход: a. Программа не останавливается.

//

Выход: нет.

///

Выход: нет. Программа не останавливается.

/\\/good/\/

Выход: good.

В вики есть также quine, которую вы можете попробовать.

algorithmshark
источник
/-/World//--/Hello//--W/--, w/---!Что не любить? (Попробуйте убрать тире с конца)
seequ
@Loovjo Символ \ экранирует любой следующий за ним символ, в том числе /, который впоследствии можно использовать как обычно. Хотя это выглядит не так много, это делает /// Тьюринг-завершенным .
алгоритмический
Я думаю, что это лучшее объяснение языка, чем статья в esolangs wiki. Будет использовать эту информацию в моей ///IDE, что я делаю!
clabe45

Ответы:

7

APL (133)

{T←''∘{(0=≢⍵)∨'/'=⊃⍵:(⊂⍺),⊂⍵⋄(⍺,N⌷⍵)∇⍵↓⍨N←1+'\'=⊃⍵}⋄⍞N←T⍵⋄p N←T 1↓N⋄r N←T 1↓N⋄''≡N:→⋄∇{⍵≡p:∇r⋄∨/Z←p⍷⍵:∇(r,⍵↓⍨N+≢p),⍨⍵↑⍨N←1-⍨Z⍳1⋄⍵}1↓N}

Это функция, которая принимает ///код в качестве правильного аргумента.

Неуправляемый, с объяснением:

slashes←{
   ⍝ a function to split the input string into 'current' and 'next' parts,
   ⍝ and unescape the 'current' bit
   split←''∘{
       ⍝ if the string is empty, or '/' is reached,
       ⍝ return both strings (⍺=accumulator ⍵=unprocessed)
       (0=≢⍵)∨'/'=⊃⍵:(⊂⍺),⊂⍵
       ⍝ otherwise, add current character to accumulator,
       ⍝ skipping over '\'s. (so if '\/' is reached, it skips '\',
       ⍝ adds '/' and then processes the character *after* that.)
       idx←1+'\'=⊃⍵
       (⍺,idx⌷⍵)∇idx↓⍵
   }

   ⍞   next ← split ⍵      ⍝ output stage
   pat next ← split 1↓next ⍝ pattern stage, and eat the '/'
   rpl next ← split 1↓next ⍝ replacement stage, and eat the '/'

   ⍝ if there are no characters left, halt.
   ''≡next:⍬

   ⍝ otherwise, replace and continue.
   ∇{  ⍝ if the input string equals the pattern, return the replacement and loop
       ⍵≡pat:∇rpl

       ⍝ otherwise, find occurences, if there are, replace the first and loop
       ∨/occ←pat⍷⍵:∇(rpl, (idx+≢pat)↓⍵),⍨ (idx←(occ⍳1)-1)↑⍵

       ⍝ if no occurences, return string
       ⍵

   }1↓next
}
Мэринус
источник
msgstr "если не осталось символов, остановитесь." Работает ли это правильно на ///и //foo/(то есть циклы навсегда)?
алгоритмическая
@algorithmshark: да, в этой ситуации /все равно останется в этой точке.
Маринус
11

J - 181 190 170 символов

Это был кошмар. Я переписал его с нуля, дважды, потому что он просто продолжал беспокоить меня. Это функция, принимающая единственный строковый аргумент, выводящий в STDOUT.

(0&$`((2{.{:@>&.>)((j{.]),-i@=`p@.~:~/@[,]}.~#@p+j=.0{p I.@E.])i 5;@}.&,'/';"0;&.>)@.(2<#)@}.[4:1!:2~{:@>@p=.>@{.@[)@((0;(0,:~1 0,.2);'\';&<1 0)<;._1@;:'/'&,)i=. ::](^:_)

Чтобы объяснить, я разобью его на подвыражения.

i =. ::](^:_))
parse =: ((0;(0,:~1 0,.2);'\';&<1 0)<;._1@;:'/'&,)
print =: 4:1!:2~{:@>@p=.>@{.@[
eval  =: 0&$`((2{.{:@>&.>)sub 5;@}.&,'/';"0;&.>)@.(2<#)@}.
sub   =: ((j{.]),-i@=`p@.~:~/@[,]}.~#@p+j=.0{p I.@E.])i

interp =: (eval [ print) @ parse i
  • i(сокращение от итерации ) - наречие. Он принимает аргумент глагола слева и возвращает глагол (f)i, который при применении к аргументу fнеоднократно применяется к аргументу до тех пор, пока не произойдет одно из двух: он не найдет фиксированную точку ( y = f y) или не выдаст ошибку. Поведение с фиксированной запятой присуще ^:_и ::]обрабатывает ошибки.

  • parseтокенизирует входные данные в то, что я называю полуразборенной формой, а затем обрезает их в неэкранированном «/» Он связывает экранирование с обратным слешем с их персонажами, но не избавляется от обратного слеша - так что мы можем либо отменить его, либо завершить его в зависимости от того, что мы хотим.

    Основная часть интересных работ происходит в ;:. Это примитив последовательного машинного интерпретатора, который содержит описание машины ( (0;(0,:~1 0,.2);'\';&<1 0)) слева и кое-что для анализа справа. Это делает токенизацию. Я отмечу, что эта конкретная машина на самом деле относится к первому символу как к особенной, даже если она \и должна быть привязана. Я делаю это по нескольким причинам: (1) таблица состояний более проста, так что ее можно играть дальше; (2) мы можем легко добавить фиктивного персонажа впереди, чтобы избежать проблемы; и (3) этот фиктивный персонаж наполовину разбирается без каких-либо дополнительных затрат, поэтому я могу использовать его для настройки на фазу обрезки, затем.

    Мы также используем, <;._1чтобы вырезать токенизированный результат на unescaped/ (это то, что я выбрал, чтобы быть первым ). Это удобно для извлечения вывода, шаблона и замены из out/patt/repl/restвсех за один шаг, но, к сожалению, также сокращает остальную часть программы, где мы нуждаемся в том, /чтобы они оставались нетронутыми. Я склеиваю их обратно во время eval, потому что если <;._1оставить их в покое, это будет стоить намного дороже.

  • Вилка (eval [ print)выполняетprint на результат из- parseза его побочных эффектов, а затем запускается eval. printэто простой глагол, который открывает первое поле (которое мы точно знаем, это вывод), заканчивает его разбор и отправляет в STDOUT. Тем не менее, мы также пользуемся возможностью определить вспомогательный глагол p.

    pопределяется как >@{.@[, поэтому он принимает свой левый аргумент (действует как идентификатор, если дан только один аргумент), берет первый элемент этого (идентификатор при наличии скаляра) и распаковывает его (идентификатор, если он уже распакован). Это очень пригодится sub.

  • evalоценивает остаток обработанной программы. Если у нас нет полного шаблона или полной замены, evalон выбрасывает его и просто возвращает пустой список, который завершает оценку ;:из-за parseошибки (from ) на следующей итерации. Иначе, evalполностью анализирует шаблон и замену, исправляет оставшуюся часть источника, а затем передает оба sub. Взрывом:

                                                  @}.  NB. throw out printed part
                                           @.(2<#)     NB. if we have a pattern and repl:
          2{.                                          NB.  take the first two cuts:
                 &.>                                   NB.   in each cut:
             {:@>                                      NB.    drop escaping \ from chars
         (          )                                  NB.  (these are pattern and repl)
                                       &.>             NB.  in each cut:
                                      ;                NB.   revert to source form
                                '/';"0                 NB.  attach a / to each cut
                              &,                       NB.  linearize (/ before each cut)
                         5  }.                         NB.  drop '/pattern/repl/'
                          ;@                           NB.  splice together
        (            sub                  )            NB.  feed these into sub
       `                                               NB. else:
    0&$                                                NB.  truncate to an empty list
    
  • subгде происходит один (возможно, бесконечный) раунд замен. Из-за того, как мы настроилиeval , источник является правильным аргументом, а шаблон и замена объединены в левом. Поскольку аргументы упорядочены следующим образом, и мы знаем, что шаблон и замена не меняются в цикле подстановок, мы можем использовать другую функцию i- тот факт, что он изменяет только правый аргумент и продолжает передаваться в том же левом - для делегирования J нужно беспокоиться о отслеживании состояния.

    Однако есть две проблемы. Во-первых, у глаголов J может быть не более двух аргументов, поэтому у нас нет простого способа получить доступ к любому из них, например, к шаблону и замене, здесь. Благодаря разумному использованию pутилиты, которую мы определили, это не такая большая проблема. Фактически, мы можем получить доступ к шаблону одним символом, просто используя pего >@{.@[определение: Unbox of the First item левого аргумента. Получить замену - сложная задача, но самый короткий путь будет на p&|.2 знака короче, чем вытащить ее вручную.

    Вторая проблема заключается в том, что происходит iвыход в фиксированных точках, а не в цикле навсегда, и если шаблон и замена равны, и вы делаете подстановку, которая выглядит как фиксированная точка для J. Мы справляемся с этим, вводя бесконечный цикл с отрицанием 1 над более, если мы обнаружим, что они равны: это -i@=`p@.~:~/часть, заменяющая p&|..

                                        p    E.]    NB. string search, patt in src
                                          I.@       NB. indices of matches
                                      0{            NB. take the first (error if none)
                                   j=.              NB. assign to j for later use
                               #@p+                 NB. add length of pattern
                           ]}.~                     NB. drop that many chars from src
                       /@[                          NB. between patt and repl:
                      ~                             NB.  patt as right arg, repl as left
                  @.~:                              NB.  if equal:
            -i@=                                    NB.   loop forever
                `p                                  NB.  else: return repl
     (j{.])                                         NB. first j chars of src
           ,              ,                         NB. append all together
    (                                           )i  NB. iterate
    
  • Этот цикл повторяется из-за использования iдо тех пор, пока что-то выходит за пределы subошибки. Насколько я знаю, это может произойти только тогда, когда у нас не будет символов, или когда мы выбрасываем неполный набор шаблонов и замен.

Интересные факты об этом гольфе:

  • На этот раз использование ;:короче, чем ручная итерация по строке.
  • 0{ должен иметь шанс на ошибку до sub перейдет в бесконечный цикл, так что это должно работать нормально, если шаблон соответствует замене, но никогда не отображается в оставшейся части источника. Тем не менее, это может или не может быть неопределенным поведением, так как я не могу найти цитату в любом случае в документах. Whoopsie.
  • Клавишные прерывания обрабатываются как спонтанные ошибки внутри запущенных функций. Однако из-за характераi , эти ошибки тоже попадают в ловушку. В зависимости от того, когда вы нажмете Ctrl + C, вы можете:
    • Выход из цикла отрицания-навсегда, ошибка из sub цикла и попытайтесь объединить число в строку, а затем продолжайте интерпретировать ///, как если бы вы закончили замену строки самим собой бесконечное число раз.
    • Оставлять sub на полпути и продолжайте интерпретировать выражение /// наполовину подобласти.
    • Выключите интерпретатор и верните неоцененную /// программу в REPL (но не STDOUT, хотя).

Пример использования:

   f=:(0&$`((2{.{:@>&.>)((j{.]),-i@=`p@.~:~/@[,]}.~#@p+j=.0{p I.@E.])i 5;@}.&,'/';"0;&.>)@.(2<#)@}.[4:1!:2~{:@>@p=.>@{.@[)@((0;(0,:~1 0,.2);'\';&<1 0)<;._1@;:'/'&,)i=. ::](^:_)
   f 'no'
no
   f '/ world! world!/Hello,/ world! world! world!'
Hello, world!
   f '/foo/Hello, world!//B\/\\R/foo/B/\R'
Hello, world!
   f '//'  NB. empty string

   f '/\\/good/\/'
good
algorithmshark
источник
Вау. Я бы назвал это мазохистским. +1
сикв
Когда я запускаю это, я получаю пустую строку из каждого теста. Я использую jqt64, что вы используете для запуска этого?
bcsb1001
@ bcsb1001 Я использовал (64-битный) двоичный файл jconsole напрямую. Теперь, проверяя jqt, я получаю ожидаемые результаты, кроме /\\/good/\/тестового примера; отладка говорит мне, что проблема в том, что я использую 1!:2&4, так как у jqt нет stdin / out. Будем расследовать. Какие у тебя 9!:12''и 9!:14''?
алгоритмистика
@algorithmshark Моему 9!:12''6 и 9!:14''является j701 / 2011-01-10 / 11: 25.
bcsb1001
4

Perl - 190

$|=1;$/=undef;$_=<>;while($_){($d,$_)=/(.)(.*)/;eval(!$e&&({'/','$a++','\\','$e=1'}->{$d})||('print$d','$b.=$d','$c.=$d')[$a].';$e=0');if($a==3){while($b?s/\Q$b/$c/:s/^/$c/){}$a=0;$b=$c=''}}

Читает ///программу от стандартного до EOF.

faubi
источник
Будет ли подход по принципу: « m/^(.*?)(?<!\\)\/(.*?)(?<!\\)\/(.*?)(?<!\\)\/(.*)$/sсовпадаем ли с выходом, схемой и заменой одновременно» сделать более короткий гольф? Сам я не знаю Perl.
алгоритмическая
Я считаю, что это не с/a/\0/a
Asone Tuhid
3

Пип , 100 102 байта

Я никогда не доказывал, что Пип является завершенным по Тьюрингу (хотя это вполне очевидно), и вместо того, чтобы идти по обычному маршруту БФ, я подумал, что /// будет интересно. Как только у меня было решение, я решил, что я буду играть в гольф и выложить его здесь.

101 байт кода, +1 для -rфлага:

i:gJnf:{a:xW#i&'/NE YPOia.:yQ'\?POiya}W#iI'\Q YPOiOPOiEIyQ'/{p:VfY0s:VfIyQ'/WpNi&YviR:Xp{++y?ps}}E Oy

Вот моя неутешительная версия с обильными комментариями:

; Use the -r flag to read the /// program from stdin
; Stdin is read into g as a list of lines; join them on newline and assign to c for code
c : gJn

; Loop while c is nonempty
W #c {
 ; Pop the first character of c and yank into y
 Y POc
 ; If y equals "\"
 I yQ'\
  ; Pop c again and output
  O POc
 ; Else if y equals "/"
 EI yQ'/ {
  ; Build up pattern p from empty string
  p : ""
  ; Pop c, yank into y, loop while that is not equal to "/" and c is nonempty
  W #c & '/ NE Y POc {
   ; If y equals "\"
   I yQ'\
    ; Pop c again and add that character to p
    p .: POc
   ; Else, add y to p
   E p .: y
  }

  ; Yank 0 so we can reliably tell whether the /// construct was completed or not
  Y0
  ; Build up substitution s from empty string
  s : ""
  ; Pop c, yank into y, loop while that is not equal to "/" and c is nonempty
  W #c & '/ NE Y POc {
   ; If y equals "\"
   I yQ'\
    ; Pop c again and add that character to s
    s .: POc
   ; Else, add y to s
   E s .: y
  }

  ; If the last value yanked was "/", then we have a complete substitution
  ; If not, the code must have run out; skip this branch, and then the outer loop
  ; will terminate
  I yQ'/ {
   ; While pattern is found in code:
   W pNc {
    ; Set flag so only one replacement gets done
    i : 0
    ; Convert p to a regex; replace it using a callback function: if ++i is 1,
    ; replace with s; otherwise, leave unchanged
    c R: Xp {++i=1 ? s p}
   }
  }
 }
 ; Else, output y
 E Oy
}

Попробуйте онлайн! (Обратите внимание, что TIO не выдает никаких выходных данных, когда программа не завершается, а также имеет ограничение по времени. Для более крупных примеров и бесконечных циклов рекомендуется запуск Pip из командной строки.)

DLosc
источник
Я думаю, что это должно быть pip + -r, 101 байт
Asone Tuhid
3

C ++: Visual C ++ 2013 = 423, g ++ 4.9.0 = 442

Это никогда не победит, но так как я решил, что все мои будущие программные проекты будут написаны на этом потрясающем языке, мне понадобился переводчик, и я подумал, что мог бы поделиться тем, что я сделал ...

Разница в баллах заключается в том, что Visual C ++ не нуждается в первом включении, а в g ++. Оценка предполагает, что окончания строки считаются за 1.

#include<string.h>
#include<string>
#define M(x)memset(x,0,99);
#define P o[i])
#define N(x)P;else if(n<x)(P==92?
#define O (o[++i]):(P==47?n++:
#define S std::string
int main(int n,char**m){S o=m[1];char p[99],*q=p,r[99],*s=r;M(p)M(r)for(int i=0,t;i<=o.size();++i){if(!N(3)putchar O putchar(N(4)*q++=O(*q++=N(5)*s++=O(*s++=P;if(n>4){for(;;){if((t=o.find(p,i+1))==S::npos)break;o=o.substr(0,t)+r+o.substr(t+strlen(p));}M(p)M(r)n=2;q=p;s=r;}}}
Джерри Иеремия
источник
1
Вы можете переписать if(!o[i]);так , if(Pчтобы сохранить символы, или я недоразумение как #define работает?
алгоритмическая
@algorithmshark как я это пропустил ?! если (! P идеально. Я изменю это.
Джерри Иеремия
Каждый экземпляр Pin mainимеет пробел после него, поэтому вы можете сохранить символ, заменив эти пробелы точкой с запятой и удалив его из #define. Затем, если вы можете использовать там #defineвнутри других, вы можете сэкономить еще немного переписав , N(x)как (92==Pвместо того , o[i]==92и Oтаким же образом.
алгоритмическая
@algorithmshark Вы, очевидно, намного лучше в этом, чем я. Спасибо за помощь.
Джерри Иеремия
Я знаю , что это примерно четыре года, но переписывания , N(x)как P;else if(n<x)(P==92?и изменение вызовов Nсоответственно может сэкономить несколько байт.
Захари
2

Python 2 (236), Python 3 (198?)

from __future__ import print_function
def d(i):
 t=0;p=['']*3+[1]
 while i:
  if'/'==i[0]:t+=1
  else:
   if'\\'==i[0]:i=i[1:]
   p[t]+=i[0]
  i=i[1:]
  print(end=p[0]);p[0]=''
  if t>2:
   while p[1]in i:i=i.replace(*p[1:])
   d(i);i=0

Называется как d(r"""/foo/Hello, world!//B\/\\R/foo/B/\R"""). Тройные кавычки нужны только если/// программа содержит новые строки: в противном случае простые кавычки в порядке.

РЕДАКТИРОВАТЬ: Этот интерпретатор теперь печатает материал, как ожидалось (ранее он печатался только в самом конце, см. Комментарии). Для Python 3 удалите первую строку (но у меня нет Python 3 в моей старой установке, поэтому я не могу быть уверен, что других изменений нет).

Бруно Ле Флох
источник
переводчик не печатает ничего, пока его завершение не вызывает проблем. запись бесконечного цикла в /// возможна, поэтому ваш интерпретатор завершается ошибкой в ​​программах, которые не заканчиваются, но все еще печатают что-то.
гордый haskeller
@proudhaskeller Исправлено.
Бруно Ле Флох
На самом деле, это не исправлено, ничего не печатается /a/ab/bbaa/abb.
Бета-распад
@BetaDecay /a/ab/bbaa/abbзастрянет в бесконечном цикле, ничего не печатая, потому что первая замена - a=> ab. Правильно a/ab/bbaa/abbработает как рекламируется.
алгоритмическая
@BetaDecay: помимо изменений, предложенных алгоритмом, вам может потребоваться включить параметр командной строки, -uчтобы заставить буфер вывода быть небуферизованным.
Бруно Ле Флох
2

Кобра - 226

sig Z as String
def f(l='')
    m=Z(do=[l[:1],l=l[1:]][0])
    n as Z=do
        if'/'<>(a=m())>'',return if(a=='\\',m(),a)+n()
        else,return''
    print n()stop
    p,s=n(),n()
    if''<l
        while p in l,l=l[:l.indexOf(p)+1]+s+l[p.length:]
        .f(l)
Οurous
источник
2

Руби , 119 110 байт

Завершается с исключением

r=->s,o=$>{s[k=s[0]]='';k==?/?o==$>?s.gsub!([r[s,''],e=r[s,'']][0]){e}:t=o:o<<(k==?\\?s[0]+s[0]='':k);t||redo}

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

Завершает чисто (116 байт)

r=->s,o=$>{s[k=s[0]||exit]='';k==?/?o==$>?s.gsub!([r[s,''],e=r[s,'']][0]){e}:t=o:o<<(k==?\\?s[0]+s[0]='':k);t||redo}

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

Асоне Тухид
источник
1

Python 2/3 (211 байт)

Следующий код, основанный на ответе Бруно Ле Флоша , совместим с Python 2 и Python 3.

Более того, будучи итеративным, а не рекурсивным, он не рискует достичь максимальной глубины рекурсии Python.

def S(c):
 while c:
  B=["","",1]
  for m in 0,1,2:
   while c:
    if"/"==c[0]:c=c[1:];break
    if"\\"==c[0]:c=c[1:]
    if m:B[m-1]+=c[0]
    else:yield c[0]
    c=c[1:]
  while c and B[0]in c:c=c.replace(*B)
Карлос Луна
источник
Привет и добро пожаловать в PPCG. Вы можете играть in(0,1,2)в гольф in 0,1,2и [""]*2+[1]обратно ["","",1], в результате чего получается 211 байт .
Джонатан Фрех
Я связался с приведенным ответом и добавил слово «байты». Если вы не согласны с моей правкой, не стесняйтесь откатываться назад.
Джонатан Фрех
Спасибо Джонатан, ваши предложения очень приветствуются!
Карлос Луна
0

BaCon , 391 387 395 байт

Из вкладов на этой странице я получил только программу Python для работы. Другие работают для некоторых /// образцов или не работают вообще. Поэтому я решил добавить свою версию, которая является реализацией в BASIC.

Соревноваться в соревнованиях CodeGolf с BASIC непросто, так как BASIC использует длинные слова в качестве утверждений. Единственная аббревиатура, обычно встречающаяся в бейсике, это «?» знак, что означает печать.

Таким образом, приведенная ниже программа может никогда не победить, но, по крайней мере, она работает со всем демонстрационным кодом на этой странице Codegolf и в Esolangs Wiki . Включая все версии "99 бутылок пива".

p$=""
r$=""
INPUT i$
WHILE LEN(i$)
t$=LEFT$(i$,1)
i$=MID$(i$,2)
IF NOT(e) THEN
IF t$="\\" THEN
e=1
CONTINUE
ELIF t$="/" THEN
o=IIF(o<2,o+1,0)
IF o>0 THEN CONTINUE
FI
FI
IF o=1 THEN
p$=p$&t$
ELIF o=2 THEN
r$=r$&t$
ELIF o=0 THEN
IF LEN(p$) THEN i$=REPLACE$(i$,p$,r$)
IF NOT(INSTR(t$&i$,"/")) THEN
?t$;
BREAK
ELSE
?LEFT$(i$,INSTR(i$,"/")-1);
i$=MID$(i$,INSTR(i$,"/"))
FI
p$=""
r$=""
FI
e=0
WEND
?i$
Питер
источник
Добавлен оператор INPUT для получения ввода от пользователя.
Питер