IMP: niejawny parser mnożenia

9

Jack lubi język programowania C, ale nie lubi pisać wyrażeń takich jak V=a*b*h; zwielokrotnienie wartości.

V=abh;Zamiast tego chciałby napisać , dlaczego kompilator miałby narzekać na abhnieokreślony symbol, skoro int a, b, h;są zdefiniowane, abyśmy mogli wydedukować mnożenie?

Pomóż mu zaimplementować analizator składni, który rozszyfrowuje pojedynczy warunek mnożenia, pod warunkiem, że znany jest zestaw zmiennych zdefiniowanych w bieżącym zakresie.

Dla uproszczenia 2*a*bnie bierze się pod uwagę mnożenia przez liczbę (jak w ), pojawiają się tylko zmienne.

Dane wejściowe to warunek mnożenia T , spełniający wyrażenie regularne:

[a-zA-Z_][a-zA-Z_0-9]*

oraz zmienny zbiór Z .

Analiza składniowa P terminu T nad zestawem zmiennych Z jest ciągiem spełniającym następujące kryteria:

  1. po usunięciu wszystkich wystąpień *z P otrzymujemy T,
  2. albo jest nazwą zmiennej z Z, albo składa się z odpowiednich nazw zmiennych z Z podzielonych na pojedyncze *znaki.

Rozwiązanie powinno wydrukować wszystkie parsowania terminu.

Próba:

Vars           a, c, ab, bc
Term           abc
Solution       ab*c, a*bc

Vars           ab, bc
Term           abc
Solution       -

Vars           -
Term           xyz
Solution       -

Vars           xyz
Term           xyz
Solution       xyz

Vars           width, height
Term           widthheight
Solution       width*height

Vars           width, height
Term           widthheightdepth
Solution       -

Vars           aaa, a
Term           aaaa
Solution       aaa*a, a*aaa, a*a*a*a

Dane wejściowe (lista zmiennych i termin) mogą być dostarczone w dowolny sposób odpowiedni dla języka.

Dane wyjściowe mogą mieć dowolną sensowną formę (jedna parsowanie na wiersz lub listę oddzieloną przecinkami itp.) - ale powinny być jednoznaczne i możliwe do odczytania.

Puste wyjście jest akceptowalne, jeśli nie ma możliwości parsowania terminu (w przykładach użyłem „-” dla jasności).

To jest golf golfowy, więc wygrywa najkrótszy kod.

pawel.boczarski
źródło
1
W pierwszym przykładzie uważam, że ab*cjest to niepoprawna analiza, ponieważ cnie jest dozwoloną zmienną.
isaacg
1
Dzięki skanowi rekurencyjnemu znajduję dokładnie twój wynik w próbce. Ale to jest wątpliwe: dlaczego a*aaa aaa*ai nieab*c c*ab
edc65 13.04.15
Z powodu reguły 1. parsowania. Tak, mnożenie jest zwykle przemienne, ale nie idziemy tak daleko - chcemy po prostu „zrekonstruować” mnożenie w kolejności, w jakiej zostało wykonane. Właściwie w języku Jacka moglibyśmy mieć typ macierzy - wówczas mnożenie nie jest wtedy przemienne. A „aaaa” może być jednocześnie zestawieniem „aaa” i „a” lub „a” i „aaa” - nie chodzi tu o przemienność, lecz o dwuznaczność, którą bierzemy pod uwagę.
pawel.boczarski

Odpowiedzi:

4

Pyth, 18 znaków

mj\*dfqzsTsm^Qkhlz

To rozwiązanie zostało zaadaptowane z mojego rozwiązania Interpreting Fish . Problemy są bardzo podobne.

Oczekuje, że dane wejściowe jako takie:

aaaa
"a", "aaa"

Daje dane wyjściowe w następujący sposób:

['a*aaa', 'aaa*a', 'a*a*a*a']

Wypróbuj tutaj.

  • sm^Qkhlz: Generuje wszystkie sekwencje zmiennych zawierające do długości wejściowej liczby zmiennych.

  • fqzsT: Odfiltrowuje sekwencje zmiennych pasujące do ciągu wejściowego

  • mj\*d: Wstawia *symbol i drukuje.

isaacg
źródło
3

Python 2 - 147 94 bajty


R=lambda S,V,F=[]:S and[R(S[len(v):],V,F+[v])for v in V if v==S[:len(v)]]or print("*".join(F))

Definiuje funkcję, Rktóra ma być używana, np .:

>>> R("abc", ["a", "bc", "ab", "c"])

Wyświetla dane wyjściowe takie jak:

a*bc
ab*c
matsjoyce
źródło
1

JavaScript (ES6) 111

Na podstawie mojej odpowiedzi „ryby” główną różnicą jest znalezienie wszystkich rozwiązań, nie tylko pierwszych.

F=(v,t)=>(k=(s,r)=>s?v.map(v=>s.slice(0,l=v.length)==v&&k(s.slice(l),[...r,v])):console.log(r.join('*')))(t,[])

Dane wyjściowe są drukowane na konsoli. Wynik funkcji nie ma znaczenia i musi zostać odrzucony.

Przetestuj w konsoli Firefox / FireBug

F(['a','c','ab','bc'],'abc')  
a*bc  
ab*c

F(['ab','bc'],'abc')

F(['aaa','a'],'aaaa')
aaa*a
a*aaa
a*a*a*a

F(['xyz'],'xyz')
xyz
edc65
źródło