แยกวิเคราะห์ไวยากรณ์สองมิติ


25

พื้นหลัง

อลิซและบ็อบกำลังสร้างภาษากอล์ฟเพื่อชนะการท้าทาย PPCG ทุกครั้ง อลิซต้องการสร้างภาษาสองมิติเช่น> <> แต่บ๊อบชอบไวยากรณ์ prefix-infix เหมือนใน J ในการประนีประนอมพวกเขาตัดสินใจที่จะสร้างภาษา prefix-infix สองมิติ โปรแกรมแยกวิเคราะห์เป็นความเจ็บปวดที่จะเขียนและพวกเขาต้องการความช่วยเหลือจากคุณ!

ข้อกำหนดทางไวยากรณ์

ในภาษาของอลิซและบ๊อบมีตัวแปรซึ่งเป็นตัวแทนจากตัวอักษร ASCII ตัวพิมพ์เล็กa-zและฟังก์ชั่นA-Zซึ่งจะแทนด้วยตัวอักษรตัวพิมพ์ใหญ่ ASCII สามารถเรียกใช้ฟังก์ชันด้วยหนึ่งหรือสองอาร์กิวเมนต์ โปรแกรมเป็นตารางสี่เหลี่ยมของตัวอักษรa-zA-Zและช่องว่างและมุมบนด้านซ้ายไม่ต้องมีช่องว่าง นี่คือตัวอย่างของโปรแกรมที่ถูกต้อง:

F Gy
H   
R x 

เมื่อโปรแกรมจะแยกกันก็กลายเป็นแสดงออกของภาษาซี (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การแยกวิเคราะห์นิพจน์ที่มุมซ้ายบนเป็นผลลัพธ์ของกระบวนการแยกวิเคราะห์

อินพุตและเอาต์พุต

การป้อนข้อมูลของคุณเป็นอาร์เรย์อักขระที่ไม่ว่างเปล่า มันจะเป็นโปรแกรมที่ถูกต้องในภาษาของ Alice และ Bob แต่อาจมีนิพจน์ที่ไม่ได้ใช้ในผลลัพธ์ ผลลัพธ์ของคุณจะต้องมีการแยกวิเคราะห์การแสดงออกที่เกิดจากกระบวนการข้างต้น

กฎและการให้คะแนน

คุณสามารถเขียนโปรแกรมเต็มรูปแบบของฟังก์ชั่น จำนวนไบต์ต่ำสุดที่ชนะและช่องโหว่มาตรฐานไม่ได้รับอนุญาต

กรณีทดสอบ

สิ่งเหล่านี้ถูกกำหนดในรูปแบบ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 ในความท้าทายนี้รูปแบบผลลัพธ์มีความเข้มงวด Alice และ Bob ต้องการให้สามารถใช้การแยกวิเคราะห์นิพจน์โดยตรง
Zgarb

ส่วน "มัด" ของภาษาอยู่ที่ไหน ฉันเห็นคำนำหน้าเท่านั้น
Paŭlo Ebermann

6
คุณช่วยสร้างภาษาด้วยไวยากรณ์นี้ได้ไหม :)
Martin Ender

4
ความท้าทายในการติดตามผล: เขียน meta-golfer สำหรับไวยากรณ์นี้ (รับทรีนิพจน์ค้นหากริดที่เล็กที่สุดที่สอดคล้องกัน) สำหรับความยากพิเศษให้แยกแยะความแตกต่างระหว่างฟังก์ชั่นการเปลี่ยนและไม่เปลี่ยน
Martin Ender

คำตอบ:


8

CJam, 67 62 60 58 57 54 ไบต์

ขอบคุณเดนนิสสำหรับการบันทึก 4 ไบต์

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

สิ่งนี้จะกำหนดบล็อกที่มีชื่อ (ฟังก์ชั่น) Jและทิ้งไว้ในสแต็ก ฟังก์ชันคาดว่าอาร์เรย์ของสตริงบนสแต็กซึ่งแสดงถึงกริดอินพุตและปล่อยสตริงที่ต้องการแทน

ทดสอบที่นี่

ฉันได้รับความหมายที่จะแก้ไขปัญหานี้ตั้งแต่ถูกโพสต์ แต่เห็นได้ชัดว่าฉันต้องการเงินรางวัลและโซลูชั่น Pyth ที่ยาวเกินไปเพื่อกระตุ้นตัวเองอย่างเพียงพอ

คำอธิบาย

วิธีแก้ปัญหาคือ recursive แน่นอนและค่อย ๆ สร้างสายอักขระ

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

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

(ช่องว่างทั้งสี่อยู่ในแท็บข้อเท็จจริง)

รับรายการอักขระ 2d เป็นอาร์กิวเมนต์แรกถึง r


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ส่งคืนสิ่งที่ได้รับ


มีความกระชับมาก ว้าวดังกล่าว
Addison Crump

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จะไปทางขวา !รวมผลลัพธ์จากการเรียกซ้ำด้วย a ,หากจำเป็น ทั้งหมดเริ่มต้นด้วยกริดอินพุตและฟังก์ชันตัวตน


0

Python 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()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.