Analyser une syntaxe bidimensionnelle

25

Contexte

Alice et Bob créent un langage de golf pour gagner chaque défi PPCG. Alice veut faire un langage bidimensionnel, comme> <>, mais Bob préfère une syntaxe préfixe-infixe comme dans J. Comme compromis, ils décident de créer un langage préfixe-infixé bidimensionnel. L'analyseur est une douleur à écrire, et ils ont besoin de votre aide!

Spécification de syntaxe

Dans le langage d'Alice et de Bob, il existe des variables , qui sont représentées par des lettres ASCII minuscules a-z, et des fonctions , qui sont représentées par des lettres ASCII majuscules A-Z. Une fonction peut être invoquée avec un ou deux arguments. Un programme est une grille rectangulaire de lettres a-zA-Zet d'espaces, et le coin supérieur gauche ne doit pas contenir d'espace. Voici un exemple de programme valide:

F Gy
H   
R x 

Lorsque le programme est analysé, il est transformé en une expression d'un langage de style C (C, Java, Python ...) contenant des variables à une lettre et des appels de fonction au format <func>(<arg>)ou <func>(<arg1>,<arg2>). Par exemple, le programme ci-dessus donne cette expression:

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

Les détails du processus d'analyse sont les suivants:

  • Les espaces sont juste remplis, donc ils ne sont pas analysés.
  • Chaque variable a-zest toujours analysée comme elle-même.
  • Chaque fonction A-Zest analysée comme un appel de fonction. Ses arguments sont les expressions les plus proches en dessous et à sa droite dans la grille, dans cet ordre. Si un seul d'entre eux est présent, il est donné comme seul argument. Vous pouvez supposer que toutes les fonctions ont au moins un argument dans la grille.

Dans l'exemple ci-dessus, les variables xet ysont analysées comme elles-mêmes. La fonction Rn'a rien en dessous et xà sa droite, elle est donc analysée comme l'invocation à un argument R(x). De même, Hest analysé comme H(R(x)), car il a en Rdessous. La fonction Ga en xdessous et yà droite, donc elle est analysée comme G(x,y), et de même pour F. L'expression analysée dans le coin supérieur gauche est le résultat du processus d'analyse.

Entrée et sortie

Votre entrée est un tableau rectangulaire de caractères non vide. Ce sera toujours un programme valide dans le langage d'Alice et de Bob, mais il peut contenir des expressions qui ne sont pas utilisées dans la sortie. Votre sortie doit être l'expression analysée résultant du processus ci-dessus.

Règles et notation

Vous pouvez écrire un programme complet d'une fonction. Le nombre d'octets le plus bas l'emporte et les failles standard sont interdites.

Cas de test

Ceux-ci sont donnés dans le format grid <newline> expression, avec des tirets ---entre les cas. Le format SE laisse certaines lignes vides, mais elles doivent être remplies d'espaces.

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
la source
Une sortie aimerait- (A (B (D x)) (C (D x)))elle convenir ou le format est-il fixe?
coredump
1
@coredump Dans ce défi, le format de sortie est strict; Alice et Bob veulent pouvoir utiliser directement l'expression analysée.
Zgarb
Où est la partie "infixe" de la langue? Je ne vois que le préfixe.
Paŭlo Ebermann
6
Pouvez-vous s'il vous plaît réellement créer un langage avec cette syntaxe? :)
Martin Ender
4
Défi de suivi: écrire un méta-golfeur pour cette syntaxe (étant donné un arbre d'expression, trouver la plus petite grille qui lui correspond). Pour une difficulté supplémentaire, faites la distinction entre les fonctions commutatives et non commutatives.
Martin Ender

Réponses:

8

CJam, 67 62 60 58 57 54 octets

Merci à Dennis d'avoir économisé 4 octets.

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

Ceci définit un bloc nommé (fonction) Jet le laisse sur la pile. La fonction elle-même attend un tableau de chaînes sur la pile, qui représente la grille d'entrée, et laisse la chaîne souhaitée à sa place.

Testez-le ici.

Je voulais aborder celui-ci depuis sa publication, mais apparemment, j'avais besoin d'une prime et d'une solution Pyth trop longue pour me motiver suffisamment.

Explication

La solution est bien sûr récursive et construit progressivement la chaîne.

{
  :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
la source
5

Python 2, 227 223 192 182 182 179 177 octets

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

(Les quatre espaces sont en fait des tabulations)

Prend une liste 2D de caractères comme premier argument de r.

Bleu
la source
5

Pyth, 97 octets

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

Mon dieu qui a mis beaucoup de temps à faire (environ 5/6 heures?). Pyth n'était vraiment pas conçu pour ça ...

Essayez-le ici .

Tentative d'explication ainsi que l'équivalent 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)

Où les fonctions Pprintet assignretourner ce qui leur est donné.

Bleu
la source
Beaucoup de concision. Un tel wow.
Addison Crump
5

Haskell, 124 122 120 120 119 octets

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)

Exemple d'utilisation: (#id) ["RT Hq ","I xR k"]-> "R(I(x),T(H(R(k),q)))".

Comment ça marche: outre la grille d'entrée r, la fonction #prend une autre fonction gcomme argument qui est appliqué rchaque fois que le caractère en haut à gauche est un espace. S'il s'agit plutôt d'un caractère minuscule, renvoyez-le. Sinon, il doit s'agir d'un caractère majuscule et #est appelé récursivement, une fois avec tailpour descendre et une fois avec map tailpour aller à droite. !joint les résultats des appels récursifs avec un ,, si nécessaire. Tout commence par la grille d'entrée et la fonction d'identité.

nimi
la source
0

Python 3, 187 octets

Toujours à la recherche de façons de jouer au golf, mais je suis juste content d'avoir réussi à le transformer en un doublé.

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
la source