Analizar una sintaxis bidimensional

25

Fondo

Alice y Bob están creando un lenguaje de golf para ganar cada desafío PPCG. Alice quiere hacer un lenguaje bidimensional, como> <>, pero Bob prefiere una sintaxis de prefijo-infijo como en J. Como compromiso, deciden crear un lenguaje de prefijo-infijo bidimensional. Es difícil escribir el analizador y necesitan tu ayuda.

Especificación de sintaxis

En el lenguaje de Alice y Bob, hay variables , que están representadas por letras minúsculas ASCII a-z, y funciones , que están representadas por letras mayúsculas ASCII A-Z. Se puede invocar una función con uno o dos argumentos. Un programa es una cuadrícula rectangular de letras a-zA-Zy espacios, y la esquina superior izquierda no debe contener un espacio. Este es un ejemplo de un programa válido:

F Gy
H   
R x 

Cuando se analiza el programa, se transforma en una expresión de un lenguaje de estilo C (C, Java, Python ...) que contiene variables de una sola letra y llamadas a funciones en el formato <func>(<arg>)o <func>(<arg1>,<arg2>). Por ejemplo, el programa anterior da como resultado esta expresión:

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

Los detalles del proceso de análisis son los siguientes:

  • Los espacios son solo de relleno, por lo que no se analizan.
  • Cada variable a-zsiempre se analiza como sí misma.
  • Cada función A-Zse analiza como una llamada a función. Sus argumentos son las expresiones más cercanas debajo y a su derecha en la cuadrícula, en este orden. Si solo uno de estos está presente, se da como único argumento. Puede suponer que todas las funciones tienen al menos un argumento en la cuadrícula.

En el ejemplo anterior, las variables xy yse analizan como ellas mismas. La función Rno tiene nada debajo y xa su derecha, por lo que se analiza como la invocación de un argumento R(x). Del mismo modo, Hse analiza como H(R(x)), ya que tiene Rdebajo de él. La función Gtiene xpor debajo de ella y ya su derecha, por lo que se analiza como G(x,y), y lo mismo para F. La expresión analizada en la esquina superior izquierda es el resultado del proceso de análisis.

Entrada y salida

Su entrada es una matriz rectangular de caracteres no vacía. Siempre será un programa válido en el lenguaje de Alice y Bob, pero puede contener expresiones que no se utilizan en la salida. Su salida será la expresión analizada resultante del proceso anterior.

Reglas y puntaje

Puede escribir un programa completo de una función. El conteo de bytes más bajo gana, y las lagunas estándar no se permiten.

Casos de prueba

Estos se dan en el formato grid <newline> expression, con guiones ---entre los casos. El formato SE deja algunas líneas en blanco, pero deben rellenarse con espacios.

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
fuente
¿Una salida como (A (B (D x)) (C (D x)))sería adecuada o el formato es fijo?
coredump
1
@coredump En este desafío, el formato de salida es estricto; Alice y Bob quieren poder usar la expresión analizada directamente.
Zgarb
¿Dónde está la parte "infija" del lenguaje? Solo veo el prefijo.
Paŭlo Ebermann
66
¿Puedes por favor crear un lenguaje con esta sintaxis? :)
Martin Ender
44
Reto de seguimiento: escriba un meta-golfista para esta sintaxis (dado un árbol de expresión, encuentre la cuadrícula más pequeña correspondiente). Para mayor dificultad, distinga entre funciones conmutativas y no conmutativas.
Martin Ender

Respuestas:

8

CJam, 67 62 60 58 57 54 bytes

Gracias a Dennis por guardar 4 bytes.

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

Esto define un bloque con nombre (función) Jy lo deja en la pila. La función en sí misma espera una matriz de cadenas en la pila, que representa la cuadrícula de entrada, y deja la cadena deseada en su lugar.

Pruébalo aquí.

He tenido la intención de abordar esto desde que se publicó, pero aparentemente necesitaba una recompensa y una solución Pyth demasiado larga para motivarme lo suficiente.

Explicación

La solución es, por supuesto, recursiva y aumenta gradualmente la cadena.

{
  :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
fuente
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()

(Los cuatro espacios son de hecho pestañas)

Toma una lista 2d de caracteres como primer argumento para r.

Azul
fuente
5

Pyth, 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

Dios mío, que tardó mucho en hacer (¿aproximadamente 5/6 horas?). Pyth realmente no fue diseñado para esto ...

Probarlo aquí .

Intento de explicación, así como el equivalente de 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)

Donde las funciones Pprinty assigndevolver lo que se les da.

Azul
fuente
Mucha concisión. Qué guau.
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)

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

Cómo funciona: además de la cuadrícula de entrada r, la función #toma otra función gcomo argumento que se aplica rsiempre que el carácter superior izquierdo es un espacio. Si se trata de un carácter en minúscula, devuélvelo. De lo contrario, debe ser un carácter en mayúscula y #se llama de forma recursiva, una vez tailpara bajar y otra map tailpara ir a la derecha. !une los resultados de las llamadas recursivas con a ,, si es necesario. Todo comienza con la cuadrícula de entrada y la función de identidad.

nimi
fuente
0

Python 3, 187 bytes

Todavía estoy buscando maneras de jugar golf, pero estoy contento de haber logrado convertirlo en una frase.

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
fuente