Analisar uma sintaxe bidimensional

25

fundo

Alice e Bob estão criando uma linguagem de golfe para vencer todos os desafios do PPCG. Alice quer criar uma linguagem bidimensional, como> <>, mas Bob prefere uma sintaxe de prefixo-infixo como em J. Como compromisso, eles decidem criar uma linguagem bidimensional de prefixo-infixo. O analisador é difícil de escrever e eles precisam da sua ajuda!

Especificação de sintaxe

No idioma de Alice e Bob, existem variáveis representadas por letras ASCII minúsculas a-ze funções representadas por letras ASCII maiúsculas A-Z. Uma função pode ser chamada com um ou dois argumentos. Um programa é uma grade retangular de letras a-zA-Ze espaços, e o canto superior esquerdo não deve conter um espaço. Este é um exemplo de um programa válido:

F Gy
H   
R x 

Quando o programa é analisado, é transformado em uma expressão de uma linguagem de estilo C (C, Java, Python ...) contendo variáveis ​​de uma letra e chamadas de função no formato <func>(<arg>)ou <func>(<arg1>,<arg2>). Por exemplo, o programa acima resulta nesta expressão:

F(H(R(x)),G(x,y))

Os detalhes do processo de análise são os seguintes:

  • Os espaços são apenas de preenchimento e, portanto, não são analisados.
  • Toda variável a-zé sempre analisada como ela mesma.
  • Toda função A-Zé analisada como uma chamada de função. Seus argumentos são as expressões mais próximas abaixo e à direita na grade, nesta ordem. Se apenas um deles estiver presente, é dado como o único argumento. Você pode assumir que todas as funções têm pelo menos um argumento na grade.

No exemplo acima, as variáveis xe ysão analisadas como elas próprias. A função Rnão tem nada abaixo e xà direita; portanto, é analisada como a invocação de um argumento R(x). Da mesma forma, Hé analisado como H(R(x)), pois possui Rabaixo dele. A função Gtem xabaixo e yà direita, portanto é analisada como G(x,y)e da mesma forma para F. A expressão analisada no canto superior esquerdo é o resultado do processo de análise.

Entrada e saída

Sua entrada é uma matriz retangular não vazia de caracteres. Sempre será um programa válido na linguagem de Alice e Bob, mas pode conter expressões que não são usadas na saída. Sua saída deve ser a expressão analisada resultante do processo acima.

Regras e pontuação

Você pode escrever um programa completo de uma função. A menor contagem de bytes vence e as brechas padrão não são permitidas.

Casos de teste

Estes são dados no formato grid <newline> expression, com hífens ---entre os casos. O formato SE deixa algumas linhas em branco, mas elas devem ser preenchidas com espaços.

x
x
---
x y
z  
x
---
Fx
F(x)
---
Fx
y 
F(y,x)
---
ABu
A(B(u))
---
G
H
k
G(H(k))
---
ABCA
x xs
 DFk
A(x,B(D(F(k)),C(x,A(s))))
---
A  B  

C  D x
A(C(D(x)),B(D(x)))
---
RT Hq 
I xR k
R(I(x),T(H(R(k),q)))
---
A A  A a 
 S A  b  
B  C   Dx
d X  u f 
A(B(d,C(D(f,x))),A(X(u),A(u,a)))
Zgarb
fonte
Uma saída (A (B (D x)) (C (D x)))seria adequada ou o formato é fixo?
Coredump
1
@coredump Neste desafio, o formato de saída é rigoroso; Alice e Bob querem poder usar a expressão analisada diretamente.
Zgarb
Onde está a parte "infixo" do idioma? Eu só vejo prefixo.
Paŭlo Ebermann
6
Você pode realmente criar um idioma com esta sintaxe? :)
Martin Ender
4
Desafio de acompanhamento: escreva um meta-jogador para esta sintaxe (dada uma árvore de expressão, encontre a menor grade correspondente a ela). Para uma dificuldade extra, faça uma distinção entre funções comutativas e não comutativas.
Martin Ender

Respostas:

8

CJam, 67 62 60 58 57 54 bytes

Agradecimentos a Dennis por salvar 4 bytes.

{:Gsc_32&{"()"[GGz2{1m<_{S#}#>W<\}*z]{},{J}%',**+}|}:J

Isso define um bloco nomeado (função) Je o deixa na pilha. A própria função espera uma matriz de seqüências de caracteres na pilha, que representa a grade de entrada e deixa a sequência desejada em seu lugar.

Teste aqui.

Eu pretendo resolver esse problema desde que foi publicado, mas aparentemente eu precisava de uma recompensa e de uma solução Pyth muito longa para me motivar o suficiente.

Explicação

A solução é, obviamente, recursiva e constrói gradualmente a string.

{
  :G       e#  Store the current grid in G.
  sc       e#  Convert the grid to a string, flattening it, then to a character, which
           e#  discards everything but the first character. This is a golfed 0=0=.
           e#  This character will either be an upper-case letter (function) or a lower-
           e#  case letter (variable).
  _32&     e#  Make a copy of the character and take bitwise AND with 32. This gives a
           e#  NULL character for functions and a space for variables.
  {        e#  If the result is falsy... (i.e. NULL, i.e. we have a function)
    "()"   e#   Push parentheses for later use.
    [      e#   Remember the current stack depth.
    GGz    e#   Push an array which contains the grid and its transpose.
    2{     e#   Run this block twice... (it will be applied once to each grid)
      1m<  e#    Rotate the rows. This has two effects: a) It removes the first row
           e#    from the front such that we can go looking for the next non-space
           e#    character down the first column from the start. b) It places a row
           e#    at the end which we know doesn't start with a space, which acts as
           e#    a guard in case there are no further letters below the current one.
      _    e#    Duplicate this grid.
      {    e#    Find the first index where this block yields something truthy...
        S# e#     Find the index of the first space in the current row. If the row
           e#     starts with a space, this is 0, i.e. falsy and the search continues.
           e#     If there is a space in any later position, that will be positive and
           e#     truthy, so this index gets returned. If there is no space at all,
           e#     the result is -1 which is also truthy and ends the search.
      }#        
      >    e#     Discard all lines up to (but not including) the found index.
      W<   e#     Discard the guard row at the end.
      \    e#     Swap the grids so that the next pass processes the other grid.
    }*       
    z      e#    Transpose the second grid back to its original orientation.
    ]      e#    Wrap both processed grids in an array.
    {},    e#    Remove a grid if it's empty.
    {J}/   e#    For each remaining grid, call J recursively.
    ',*    e#    Join the grids with commas if there are still two of them.
    *      e#    Wrap this string in the parentheses below on the stack.
    +      e#    Prepend the function name.
  }|
}:J
Martin Ender
fonte
5

Python 2, 227 223 192 182 179 177 bytes

def r(i,y=0,x=0):
 c=i[y][x];z=[]
 for t in"pq":
    p=q=0
    try:
     while" "==i[y+p][x+q]or 1>p+q:exec t+"+=1"
     z+=[r(i,y+p,x+q)]
    except:1
 return c+"(%s)"%",".join(z)*c.isupper()

(Os quatro espaços são de fato guias)

Leva uma lista 2D de caracteres como o primeiro argumento para r.

Azul
fonte
5

Pitão, 97 bytes

D:TkdI}p@@QTkGR)=Z0p\(V2JK0W|q\ @@Q=b+TJ=H+kK!+JK=J+NJ=K+!NK)I!|gblQgHl@Q0p*Z\,:bH+=Z1d))p\);:000

Meu deus que demorou muito tempo para fazer (cerca de 5/6 horas?). Pyth realmente não foi projetado para isso ...

Experimente aqui .

Tentativa de explicação, bem como equivalente em python

Q = literal_eval(input())

def at_slice(T,k,d):
  if Pprint(Q[T][k]) in "abcdefghijklmnopqrstuvwxyz": return 
  Z = 0
  Pprint("(")
  for N in range(2):
    J=K=0
    while " "==Q[assign('b',T+J)][assign('H',k+K)] or not J+K:
      J+=N
      K+=not N
    if not (b>=len(Q) or H>=len(Q[0])):
      Pprint(Z*",")
      at_slice(b,H,assign('Z',1)+d)
   Pprint(")")
at_slice(0,0,0)

Onde as funções Pprinte assignretornam o que são dadas.

Azul
fonte
Muita concisão. Que uau.
Addison Crump
5

Haskell, 124 122 120 119 bytes

r@((c:_):_)#g|c>'_'=[c]|c<'!'=g%r|1<2=c:'(':(tail%r)!(map tail%r)++")"
_#_=""
g%r=g r#g
a!b=a++[','|a>"",b>""]++b
(#id)

Exemplo de uso: (#id) ["RT Hq ","I xR k"]-> "R(I(x),T(H(R(k),q)))".

Como funciona: além da grade de entrada r, a função #assume outra função gcomo argumento aplicado rsempre que o caractere superior esquerdo for um espaço. Se for um caractere minúsculo, retorne-o. Caso contrário, ele deve ser um caractere maiúsculo e #é chamado recursivamente, uma vez tailpara descer e outra map tailpara ir para a direita. !une os resultados das chamadas recursivas com a ,, se necessário. Tudo começa com a grade de entrada e a função de identidade.

nimi
fonte
0

Python 3, 187 bytes

Ainda estou procurando maneiras de jogar golfe, mas estou satisfeito por conseguir transformá-lo em uma linha.

lambda g,r=0,c=0:g[r][c]+'(%s)'%','.join([p(g,R,c)for R in range(r+1,len(g))if c<len(g[R])and' '!=g[R][c]][:1]+[p(g,r,C)for C in range(c+1,len(g[r]))if' '!=g[r][C]][:1])*g[r][c].isupper()
Tim Pederick
fonte