Розбираємо двовимірний синтаксис


25

Фон

Аліса та Боб створюють мову для гри в гольф, щоб виграти кожен виклик PPCG. Аліса хоче створити двовимірну мову, як> <>, але Боб віддає перевагу синтаксису префікса-інфікса, як у J. Як компроміс, вони вирішують створити двовимірну мову-інфіксацію префікса. Парсер - це біль писати, і їм потрібна ваша допомога!

Специфікація синтаксису

У мові Аліси та Боба є змінні , які представлені малими літерами ASCII a-z, та функції , які представлені великими літерами ASCII A-Z. Функцію можна викликати одним або двома аргументами. Програма представляє собою прямокутну сітку з букв a-zA-Zі пробілів, а верхній лівий кут не повинен містити пробіли. Це приклад дійсної програми:

F Gy
H   
R x 

Коли програма аналізується, вона перетворюється на вираз мови у стилі C (C, Java, Python ...), що містить однобуквені змінні та виклики функцій у форматі <func>(<arg>)або <func>(<arg1>,<arg2>). Наприклад, наведена програма призводить до цього виразу:

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

Деталі процесу розбору такі:

  • Пробіли просто заповнення, тому вони не розбираються.
  • Кожна змінна a-zзавжди розбирається як сама.
  • Кожна функція A-Zаналізується як виклик функції. Його аргументи - це найближчі вирази під ним і праворуч від нього в сітці, в такому порядку. Якщо присутній лише один із них, він наводиться як єдиний аргумент. Можна припустити, що всі функції мають принаймні один аргумент у сітці.

У наведеному вище прикладі змінні xі yаналізуються як самі. У функції Rнемає нічого нижче її та xправоруч, тому вона розбирається як виклик з одним аргументом R(x). Аналогічно Hрозбирається як H(R(x)), оскільки він знаходиться Rпід ним. Функція Gмає xїї нижче та yправоруч, тому вона розбирається як G(x,y)і аналогічно для F. Вираз, проаналізований у верхньому лівому куті, є результатом процесу розбору.

Вхід і вихід

Ваш вхід - це порожній прямокутний масив символів. Це завжди буде дійсною програмою мовою Аліси та Боба, але вона може містити вирази, які не використовуються у висновку. Вашим результатом має бути проаналізований вираз, отриманий в результаті вищевказаного процесу.

Правила та оцінка

Ви можете написати повну програму функції. Виграє найменший кількість байтів, а стандартні лазівки заборонені.

Тестові справи

Вони наведені у форматі grid <newline> expressionз дефісами ---між відмінками. Формат SE залишає деякі рядки порожніми, але вони повинні бути заповнені пробілами.

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

Чи (A (B (D x)) (C (D x)))підходить результат, як-от, чи форма фіксована?
coredump

1
@coredump У цьому виклику формат виводу є суворим; Аліса і Боб хочуть мати можливість прямо використовувати синтаксичний аналіз.
Згарб

Де знаходиться "інфіксована" частина мови? Я бачу лише префікс.
Paŭlo Ebermann

6
Чи можете ви, власне, створити мову із цим синтаксисом? :)
Мартін Ендер

4
Наступне завдання: напишіть мета-гольфіст для цього синтаксису (задавши дерево виразів, знайдіть найменшу сітку, що відповідає йому). Для додаткової складності розрізняйте комутативну та некомутативну функції.
Мартін Ендер

Відповіді:


8

CJam, 67 62 60 58 57 54 байт

Завдяки Деннісу за збереження 4 байт

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

Це визначає названий блок (функцію) Jі залишає його на стеці. Сама функція очікує масив рядків на стеку, який представляє вхідну сітку, і залишає бажаний рядок замість неї.

Перевірте це тут.

Я мав намір вирішити цю проблему з моменту її опублікування, але, мабуть, мені потрібна була щедра і надто довге рішення Pyth, щоб достатньо мотивувати себе.

Пояснення

Рішення, звичайно, рекурсивне і поступово нарощує рядок.

{
  :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

5

Пітон 2, 227 223 192 182 179 177 байт

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

(Чотири пробіли насправді вкладки)

В якості першого аргументу до r приймає 2d список символів.


5

Pyth, 97 байт

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

Мій бог, який зайняв багато часу (приблизно 5/6 годин?). Pyth насправді не був призначений для цього ...

Спробуйте тут .

Спроба пояснення, а також еквівалент пітона

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)

Де функції Pprintі assignповернути те, що їм дано.


Велика чіткість. Такі вау.
Аддісон Кримп

5

Haskell, 124 122 120 119 байт

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)

Приклад використання: (#id) ["RT Hq ","I xR k"]-> "R(I(x),T(H(R(k),q)))".

Принцип роботи: крім вхідної сітки r, функція #приймає ще одну функцію gяк аргумент, який застосовується, rколи верхній лівий символ є пробілом. Якщо натомість це малий шрифт, поверніть його. В іншому випадку він повинен бути великим символом і #викликається рекурсивно, один раз з tailіти вниз і один раз з map tailіти праворуч. !приєднується до результатів рекурсивних дзвінків з а ,, якщо потрібно. Все починається з вхідної сітки та функції ідентичності.


0

Пітон 3, 187 байт

Ще шукаю способи пограти в гольф, але мені просто приємно, що мені вдалося перетворити його на однолінійку.

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()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.