Interpretar /// (pronunciado 'barras')

30

Porque não podemos obter o suficiente de golfe esotérico, podemos?

/// - barras pronunciadas - é uma linguagem divertida, baseada na s///função de substituição de expressões regulares da fama do Perl. Ele contém apenas dois caracteres especiais, barra /e barra invertida \. Você pode encontrar um artigo completo no wiki do esolangs , mas reproduzirei uma descrição do idioma abaixo, além de alguns exemplos.

Em resumo, ele funciona identificando /pattern/repl/restno programa e fazendo a substituição quantas vezes for possível. Nenhum caractere é especial, exceto /e \: /demarca padrões e substituições no programa, enquanto \permite inserir caracteres /ou literais \no seu código. Notavelmente, essas não são expressões regulares, apenas substituições simples de strings.

Seu desafio é produzir um intérprete para a linguagem ///, como um programa que lê STDIN ou uma função que usa um argumento de string, com o menor número de caracteres possível.

Você pode usar qualquer idioma, exceto o ///. Você não pode usar nenhuma biblioteca que interprete ///; você pode, no entanto, usar expressões regulares, bibliotecas de expressões regulares ou bibliotecas de correspondência de cadeias.


Execução

Existem quatro estados, impressão , padrão , substituição e substituição . Em todos os estados, exceto substituição :

  • Se o programa estiver vazio, a execução será interrompida.
  • Senão, se o primeiro caractere for \, faça algo com o próximo caractere (se presente) e remova ambos do programa.
  • Senão, se o primeiro caractere for /, remova-o e mude para o próximo estado.
  • Senão, faça algo com o primeiro caractere e remova-o do programa.
  • Repetir.

Os estados alternam entre impressão , padrão , substituição e substituição em ordem.

  • No modo de impressão , 'fazer alguma coisa' significa gerar o caractere.
  • No modo padrão , 'fazer alguma coisa' significa adicionar o caractere ao padrão atual.
  • No modo de substituição , 'fazer alguma coisa' significa adicionar o caractere à Substituição atual.

No modo de substituição , você segue um conjunto diferente de regras. Substitua repetidamente a primeira ocorrência do padrão atual pela substituição atual no programa, até que não sejam possíveis mais substituições. Nesse ponto, limpe o Padrão e a Substituição e retorne ao modo de impressão .

No programa /foo/foobar/foo foo foo, acontece o seguinte:

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

Isso faz um loop para sempre e nunca sai do modo de substituição . Da mesma forma, se o Padrão estiver vazio, a primeira ocorrência da sequência vazia - no início do programa - sempre corresponderá, portanto o modo de substituição será repetido para sempre, sem parar.


Exemplos

no

Saída: no.

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

Saída: Hello, world!.

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

Saída: Hello, world!.

a/ab/bbaa/abb

Saída: a. Programa não para.

//

Saída: nenhuma.

///

Saída: nenhuma. Programa não para.

/\\/good/\/

Saída: good.

Há também um quine no wiki que você pode tentar.

algoritmshark
fonte
/-/World//--/Hello//--W/--, w/---!O que há para não amar? (Tente remover traços do final)
consulte 31/08/14
@Loovjo O \ caractere escapa de qualquer caractere que o segue, inclusive /, que pode ser usado posteriormente normalmente. Embora isso não pareça muito, isso faz com que o /// Turing seja completo .
algorithmshark
Eu acho que essa é uma explicação melhor do idioma do que o artigo da wiki da esolangs. Usarei essas informações no meu ///IDE que estou criando!
clabe45

Respostas:

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}

Essa é uma função que aceita o ///código como argumento correto.

Ungolfed, com explicação:

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
}
marinus
fonte
"se não houver caracteres restantes, pare." Isso funciona corretamente ///e //foo/(ou seja, faz um loop para sempre)?
algorithmshark
@algorithmshark: sim, nessa situação /, ainda seria deixado naquele ponto.
marinus
11

J - 181 190 170 char

Isso foi um pesadelo. Eu o reescrevi do zero, duas vezes, porque ele continuava me incomodando. Esta é uma função que recebe um argumento de cadeia única, produzindo para 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=. ::](^:_)

Para explicar, vou dividir em subexpressões.

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(abreviação de iterate ) é um advérbio. Ele pega um argumento do verbo à esquerda e retorna um verbo (f)i, que quando aplicado a um argumento, se aplica frepetidamente ao argumento até que uma das duas coisas aconteça: ele encontra um ponto fixo ( y = f y) ou gera um erro. O comportamento do ponto fixo é inerente ^:_e ::]manipula os erros.

  • parsetokeniza a entrada no que chamo de forma semi-analisada e, em seguida, corta-a no '/' sem escape. Ele vincula barras invertidas aos personagens, mas não se livra das barras invertidas - para que possamos revertê-lo ou finalizá-lo, dependendo do que queremos.

    A maior parte do trabalho interessante ocorre em ;:. Este é um primitivo interpretador de máquina seqüencial, tendo uma descrição da máquina ( (0;(0,:~1 0,.2);'\';&<1 0)) à esquerda e algo para analisar à direita. Isso faz a tokenização. Observarei que essa máquina específica realmente trata o primeiro caractere não-especial, mesmo que seja um \e deve ser vinculado. Faço isso por alguns motivos: (1) a tabela de estados é mais simples, para que possa ser jogada ainda mais; (2) podemos facilmente adicionar um caractere fictício à frente para evitar o problema; e (3) esse caractere fictício é meio analisado sem nenhum custo extra, para que eu possa usá-lo para configurar a fase de corte, a seguir.

    Também usamos <;._1para cortar o resultado tokenizado em sem escape /(que é o que eu escolhi para ser o primeiro caractere). Isso é útil para extrair a saída, o padrão e a substituição de out/patt/repl/restuma só etapa, mas infelizmente também corta o restante do programa, onde precisamos que eles /permaneçam intocados. Eu as costuro de volta durante eval, porque fazê <;._1-las em paz acaba custando muito mais.

  • O fork é (eval [ print)executado printno resultado de parseseus efeitos colaterais e, em seguida, é executado eval. printé um verbo simples que abre a primeira caixa (a que sabemos com certeza é a saída), termina de analisá-la e a envia para STDOUT. No entanto, também temos a chance de definir um verbo utilitário p.

    pé definido como >@{.@[, então ele pega seu arg esquerdo (age como a identidade se receber apenas um argumento), pega o primeiro item dele (identidade quando recebe um escalar) e desmarca-o (caixa de identidade se já estiver fora da caixa). Isso será muito útil no sub.

  • evalavalia o restante do programa processado. Se não tivermos um padrão completo ou uma substituição completa, o evaljogue fora e retorne uma lista vazia, que finaliza a avaliação cometendo um erro ;:(de parse) na próxima iteração. Senão, evalanalisa completamente o padrão e a substituição, corrige o restante da fonte e passa os dois para sub. Por explosão:

                                                  @}.  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é onde uma rodada (possivelmente infinita) de substituições acontece. Por causa da maneira como configuramos eval, a fonte é o argumento certo e o padrão e a substituição são agrupados à esquerda. Como os argumentos são ordenados assim e sabemos que o padrão e a substituição não mudam dentro de uma rodada de substituições, podemos usar outro recurso de i- o fato de que ele modifica apenas o argumento certo e continua passando na mesma esquerda - para delegar para a necessidade de se preocupar em acompanhar o estado.

    Existem dois pontos de problemas, no entanto. A primeira é que os verbos J podem ter no máximo dois argumentos, portanto, não temos uma maneira fácil de acessar os que estão agrupados, como padrão e substituição, aqui. Através do uso inteligente do putilitário que definimos, esse não é um grande problema. De fato, podemos acessar o padrão em um caractere, apenas usando p, devido à sua >@{.@[definição: a Unbox do primeiro item do argumento Esquerda. Conseguir a substituição é mais complicado, mas a maneira mais curta seria p&|., 2 caracteres mais curtos do que comprá-la manualmente.

    O segundo problema é que isai em pontos fixos em vez de repetir para sempre, e se o padrão e a substituição forem iguais e você fizer uma substituição, isso se parecerá com um ponto fixo para J. Lidamos com isso inserindo um loop infinito de negar 1 sobre e se detectarmos que são iguais: esta é a -i@=`p@.~:~/parte, substituindo 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
    
  • Esse ciclo se repete devido ao uso de i, até que algo fora dos suberros ocorra. Até onde sei, isso só pode acontecer quando estamos sem personagens, ou quando jogamos fora um conjunto incompleto de padrões e substituições.

Curiosidades sobre este golfe:

  • Pela primeira vez, o uso ;:é mais curto do que a iteração manual da string.
  • 0{deve ter a chance de errar antes de subentrar em um loop infinito; portanto, deve funcionar bem se o padrão corresponder à substituição, mas nunca aparecer no restante da fonte. No entanto, esse pode ou não ser um comportamento não especificado, pois não consigo encontrar uma citação nos documentos. Whoopsie.
  • As interrupções do teclado são processadas como erros espontâneos nas funções em execução. No entanto, devido à natureza de i, esses erros também ficam presos. Dependendo de quando você pressiona Ctrl + C, você pode:
    • Saia do loop negar para sempre, erro fora do subloop tentando concatenar um número para uma sequência e, em seguida, continue interpretando /// como se tivesse terminado de substituir uma sequência por si mesma um número infinito de vezes.
    • Deixe na submetade e continue interpretando uma expressão /// meio-subbedada.
    • Saia do intérprete e retorne um programa /// não avaliado ao REPL (embora não STDOUT).

Exemplo de uso:

   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
algoritmshark
fonte
Uau. Eu chamaria isso masoquista. +1
veja
Quando executo isso, recebo a string vazia de cada caso de teste. Estou usando o jqt64, o que você está usando para executar isso?
bcsb1001
@ bcsb1001 Estou usando o binário jconsole (64 bits) diretamente. Verificando o jqt agora, estou obtendo os resultados pretendidos, exceto no /\\/good/\/caso de teste; a depuração informa que o problema é meu uso 1!:2&4, pois o jqt não possui stdin / out. Irá investigar. Quais são seus 9!:12''e 9!:14''?
algorithmshark
@algorithmshark Meu 9!:12''é 6 e 9!:14''é j701 / 2011-01-10 / 11: 25.
precisa saber é o seguinte
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=''}}

Lê o ///programa de stdin até EOF.

faubi
fonte
Uma abordagem ao longo das linhas de m/^(.*?)(?<!\\)\/(.*?)(?<!\\)\/(.*?)(?<!\\)\/(.*)$/s--ie corresponderá à produção, ao padrão e à substituição de uma só vez - contribuirá para um golfe mais curto? Eu não conheço nenhum Perl, eu mesmo.
algorithmshark
Eu acredito que isso falha com/a/\0/a
Asone Tuhid
3

Pip , 100 102 bytes

Eu nunca tinha provado que Pip estava completo em Turing (embora seja obviamente óbvio) e, em vez de seguir a rota usual de BF, pensei / seria interessante. Depois de ter a solução, pensei em jogar e postar aqui.

101 bytes de código, +1 para -rsinalizador:

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

Aqui está a minha versão não destruída, com muitos comentários:

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

Experimente online! (Observe que o TIO não fornece saída quando o programa não termina e também possui um limite de tempo. Para exemplos maiores e loops infinitos, é recomendável executar o Pip na linha de comando.)

DLosc
fonte
Eu acho que isso deve ser pip + -r, 101 bytes
asone Tuhid
3

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

Isso nunca vai ganhar, mas desde que eu decidi que todos os meus futuros projetos de software serão escritos nessa linguagem incrível, eu precisava de um intérprete para isso e achei que poderia compartilhar o que fiz ...

A diferença na pontuação é que o Visual C ++ não precisa da primeira inclusão, mas o g ++ precisa. A pontuação assume que as terminações de linha contam como 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;}}}
Jerry Jeremiah
fonte
11
Você pode reescrever if(!o[i]);como if(Ppara salvar caracteres, ou estou mal-entendido como #define funciona?
algorithmshark
@algorithmshark como eu perdi isso ?! se (! P é perfeito. Vou mudar isso.
Jerry Jeremiah
Cada instância de Pin mainpossui um espaço a seguir, para que você possa salvar um personagem substituindo esses espaços por ponto e vírgula e removendo-o de #define. Então, se você puder usar #defines dentro de outros, poderá economizar um pouco mais reescrevendo N(x)como em (92==Pvez de o[i]==92e da Omesma forma.
algorithmshark
@algorithmshark você obviamente é muito melhor nisso do que eu. Obrigado pela ajuda.
Jerry Jeremiah
Eu sei que isto é cerca de quatro anos, mas reescrevendo N(x)como P;else if(n<x)(P==92?e mudando chamadas para Nconformidade poderia economizar alguns bytes.
Zacharý
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

Chamado como d(r"""/foo/Hello, world!//B\/\\R/foo/B/\R"""). As aspas triplas são necessárias apenas se o ///programa contiver novas linhas: caso contrário, aspas simples estão ok.

EDIT: Este intérprete agora imprime as coisas conforme o esperado (anteriormente, ele era impresso apenas no final, veja comentários). Para o Python 3, remova a primeira linha (mas não tenho o Python 3 na minha instalação antiga, portanto, não posso ter certeza de que não há outra alteração).

Bruno Le Floch
fonte
o intérprete não imprime nada até o término ser problemático. é possível escrever um loop infinito em ///, para que seu intérprete falhe em programas que não terminam, mas ainda imprimem alguma coisa.
haskeller orgulhoso
@proudhaskeller Fixed.
Bruno Le Floch
Na verdade, isso não é fixo, não imprime nada para /a/ab/bbaa/abb.
Beta Decay
O @BetaDecay /a/ab/bbaa/abbficará preso em um loop sem fim, sem imprimir nada, porque a primeira substituição é a=>ab . O correto a/ab/bbaa/abbfunciona como anunciado.
algorithmshark
@BetaDecay: além da alteração sugerida pelo algoritmo de compartilhamento, pode ser necessário incluir a opção de linha de comando -upara forçar o buffer de saída a ser armazenado em buffer.
Bruno Le Floch
2

Cobra - 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)
Furioso
fonte
2

Ruby , 119 110 bytes

Encerra com exceção

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}

Experimente online!

Termina de forma limpa (116 bytes)

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}

Experimente online!

Asone Tuhid
fonte
1

Python 2/3 (211 bytes)

O código a seguir, com base na resposta de Bruno Le Floch , é compatível com Python 2 e Python 3.

Além disso, por ser iterativo e não recursivo, não corre o risco de atingir a profundidade máxima de recursão do 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)
Carlos Luna
fonte
Olá e bem-vindo ao PPCG. Você pode jogar golfe in(0,1,2)para in 0,1,2e [""]*2+[1]para ["","",1], resultando em 211 bytes .
Jonathan Frech
Eu vinculei à resposta referida e adicionei a palavra "bytes". Se você não concorda com minha edição, sinta-se à vontade para reverter.
Jonathan Frech
Obrigado Jonathan, suas sugestões são muito bem-vindas!
Carlos Luna
0

BaCon , 391 387 395 bytes

A partir das contribuições desta página, consegui apenas o programa Python para trabalhar. Os outros trabalham para algumas amostras ///, ou não funcionam. Portanto, decidi adicionar minha versão, que é uma implementação no BASIC.

Competir em um concurso CodeGolf com o BASIC não é fácil, pois o BASIC usa palavras longas como declarações. A única abreviação comumente encontrada no BASIC é o '?' sinal, o que significa PRINT.

Portanto, o programa abaixo pode nunca vencer, mas pelo menos funciona com todo o código de demonstração nesta página do Codegolf e no Wiki da Esolangs . Incluindo todas as versões das "99 garrafas de cerveja".

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$
Pedro
fonte
Adicionada instrução INPUT para obter entrada do usuário.
Peter