To jest przeformułowanie Czy programy gramatyczne? poprzednio zadane przez Vag i z wieloma sugestiami komentujących.
W jaki sposób można postrzegać gramatykę jako model obliczeń? Jeśli na przykład weźmiemy prostą gramatykę bezkontekstową, taką jak
G ::= '1' -> '0' '+' '1'
'1' -> '1' '+' '0'
'2' -> '2' '+' '0'
'2' -> '1' '+' '1'
'2' -> '0' '+' '2'
'3' -> '3' '+' '0'
'3' -> '2' '+' '1'
'3' -> '1' '+' '2'
'3' -> '1' '+' '2'
Zakładając, że parser nie rozróżnia między symbolami terminalnymi i nieterminalnymi, jak to tutaj wykazałem, możliwe jest wykonanie prostej arytmetyki dla liczb do 3.
Na przykład weź ciąg
"2 + 0 + 1"
Uruchomienie parsera LR (1) na tym ciągu powinno dać nam następujące konkretne drzewo składniowe, w którym wynik obliczeń jest przechowywany w katalogu głównym drzewa:
'3'
/ | \
/ | \
'2' '+' '1'
/ | \
/ | \
'2' '+' '0'
Zatem, jeśli weźmiemy gramatykę za program, a generator parsera za kompilator , to czy moglibyśmy postrzegać język specyfikacji gramatyki jako język programowania ?
Ponadto, czy moglibyśmy zbudować kompletne programy Turinga, określając gramatyki podobne do tego, w jaki sposób można budować kompletne programy Turinga za pomocą automatów celullarnych lub rachunku lambda ?
Innymi słowy, wiadomo, że w sensie rozpoznawania języka, zwykłe języki odpowiadają automatom skończonym , języki bezkontekstowe odpowiadają automatom przesuwającym w dół , a języki kontekstowe odpowiadają automatom ograniczonym liniowo . Jeśli jednak patrzymy na gramatykę jako urządzenia obliczeniowe (tj. Programy w rozumieniu powyższego przykładu), to w jaki sposób klasyfikujemy siłę obliczeniową każdej klasy gramatyki w hierarchii Chomsky'ego?
- Regularne gramatyki
- Gramatyki bezkontekstowe
- Gramatyki kontekstowe
- Nieograniczone gramatyki (dla języków z wyliczaniem rekurencyjnym )
A co powiesz na mniej znane podklasy gramatyki, takie jak
- Deterministyczne gramatyki bezkontekstowe (także LR (k) / LL (k) / SLR / LALR itp.)
- Zagnieżdżone gramatyki słów
- Gramatyki przylegające do drzewa
- Indeksowane gramatyki
EDYTOWAĆ: Nawiasem mówiąc, to jest nitpick na moje własne pytanie, ale nie wspomniałem, że nie podałem żadnego symbolu początkowego dla gramatyki przykładowej i machałem ręką na potrzebę rozróżnienia terminali od nieterminali. Technicznie lub tradycyjnie myślę, że gramatyka prawdopodobnie musiałaby być napisana w bardziej skomplikowanej formie, takiej jak ta (gdzie S jest symbolem początkowym, a $ oznacza terminal końca strumienia):
G ::= S -> R0 '$'
S -> R1 '$'
S -> R2 '$'
R0 -> '0'
R0 -> R0 '+' '0'
R1 -> '1'
R1 -> R0 '+' '1'
R1 -> '1' '+' R0
R1 -> R0 '+' '1' '+' R0
R2 -> '2'
R2 -> R0 '+' '2'
R2 -> '2' '+' R0
R2 -> R0 '+' '2' '+' R0
R2 -> R1 '+' '1'
R2 -> R1 '+' '1' '+' R0
... nie żeby to naprawdę coś zmieniało, ale pomyślałem, że powinienem o tym wspomnieć.
EDYCJA: Coś innego, co przyszło mi do głowy, gdy czytam odpowiedź Gaschego, polega na tym, że każda gałąź drzewa w moim przykładzie reprezentuje obliczenia podrzędne. Jeśli spojrzysz na każdą regułę produkcyjną jako funkcję, w której LHS reprezentuje wynik, a RHS reprezentuje jej argumenty, to struktura gramatyki określa sposób tworzenia funkcji.
Innymi słowy, kontekst parsera wraz z mechanizmem lookahead pomaga nie tylko określić, które funkcje należy zastosować („trochę”, jak polimorfizm parametryczny), ale także to, jak należy je połączyć, aby utworzyć nowe funkcje.
Przynajmniej myślę, że możesz spojrzeć na to w ten sposób w przypadku jednoznacznych CFG, dla innych gramatyki gimnastyka mentalna jest dla mnie teraz trochę za dużo.