Aby język był programowalny, musi być oparty na gramatyce bezkontekstowej

23

W praktyce, dla języka, który można ostatecznie skompilować / przekształcić w instrukcje na poziomie systemu, czy konieczne jest, aby była to gramatyka bezkontekstowa?

np .: Czy wszystkie języki programowania / skryptów są wolne od kontekstu? Java oparta jest na CFG, ale czy w rzeczywistości wszystkie języki programowania są oparte na CFG?

Nie wydaje się to obowiązkowe, ale w moim rozumieniu są luki.

Pewien kontekst pytania: patrzyłem na specyfikację języka Java, która zawiera także reguły gramatyczne . To sprawiło, że pomyślałem o tym pytaniu.

sandeepkunkunuru
źródło
1
Ogólnie myślę, że po prostu chcesz, aby problem kompilacji był obliczalny, a analizowanie CFG jest przyjemne i łatwe. Chociaż słyszałem pewne twierdzenia, że ​​na przykład rozpoznawanie prawidłowych programów w Perlu jest w rzeczywistości problemem, którego nie można obliczyć.
Janne H. Korhonen,
2
właściwie wszystko, czego naprawdę potrzebujesz, to rozstrzygalna składnia Turinga (którą są wszystkie CFG). Ty również mógł uczynić język programowania, którego składnia który nie jest Turinga rozstrzygalne, ale po dokonaniu literówka kompilator nie może zatrzymać, podczas gdy stara się zdecydować, czy to jest poprawna składnia. to nie jest naprawdę przydatne
maniak ratchet
@ratchet, czy zakładasz, że składnia musi być rekurencyjnie wyliczalna?
David Harris
4
@JanneKorhonen: W szczególności Perl nie może być analizowany statycznie , to znaczy nie może być analizowany bez wykonania również; ponieważ wspomniane wykonanie może nie być zakończone, statyczne parsowanie Perla oznaczałoby rozwiązanie problemu zatrzymania.
Jon Purdy,
@janne Mam na myśli, że wstępne przetwarzanie, które może wiązać się z problemami, które mogą, ale nie muszą być obliczalne, jest na ogół przypadkiem, gdy końcowa gramatyka, względem której program jest sprawdzany, jest pozbawiona kontekstu. Aby być bardziej szczegółowym, po wstępnym przetworzeniu, w celu zidentyfikowania reguły, która pasuje do sekwencji tokenów, musimy spojrzeć na inne tokeny otaczające tę sekwencję. Nie wiem, czy mam sens, przepraszam za to. Właściwie jestem trochę zdezorientowany.
sandeepkunkunuru

Odpowiedzi:

20

Dwa razy nie.

Po pierwsze, większość HPL nie jest pozbawiona kontekstu. Chociaż zwykle mają składnię opartą na CFG, mają również to, co ludzie nazywają semantyką statyczną (co często jest również zawarte w składni terminu). Może to obejmować nazwy i typy, które muszą sprawdzić poprawność programu. Na przykład,

class A {
  String a = "a";
  int b = a + d;
}

jest poprawnym składniowo programem Java, ale nie będzie się kompilował, ponieważ dnie jest zdefiniowany i anie ma odpowiedniego typu.

Po drugie, można analizować w językach, które nie są wolne od kontekstu (jak oczywiście świadczy o istnieniu kompilatorów). Tyle tylko, że CFG mogą być skutecznie analizowane, podczas gdy CSG ogólnie nie. Można jednak dodawać pewne funkcje bezkontekstowe, zachowując jednocześnie wydajność.

Kompilatory często działają w fazach: najpierw tokenizacja (zwykła), następnie parsowanie bez kontekstu, a następnie analiza nazw i typów (kontekstowa, czasem nawet trudniejsza). Możesz zaobserwować to zachowanie, wyświetlając komunikaty o błędach.

Raphael
źródło
3
Nie zapomnij o public class Program { public static void main(String[] args) { ... } }... Java nie pozwoli ci tak łatwo zejść. :-)
Roy Tinker,
Technicznie class A { ... }jest całkowicie wystarczający, ponieważ javackompiluje rzeczy, których nie można właściwie wykonać (z powodu braku punktu wejścia). Ale tak
Raphael,
20

Parsowanie perla jest nierozstrzygalne.

http://www.jeffreykegler.com/Home/perl-and-undecidability/perl-and-undecidability-files/TPR3.pdf?attredirects=0

http://www.perlmonks.org/?node_id=663393

Niall Murphy
źródło
6
Wydaje mi się, że to powinien być żart Perla :)
Suresh Venkat
5
Suresh: Zrobiłem już ten żart, choć nie okazał się to bardzo dobry żart, w artykule „O nieelastycznych językach programowania” w SIGBOVIK 2011 ( sigbovik.org/2011/proceedings.pdf - strona 79- 82).
Rob Simmons,
1
Uwaga: interpreter Perla nie jest jeszcze niedeterministyczny, jeśli jest to dla każdego pocieszeniem :)
Roy Tinker
15

Nie wierzę, że gramatyka Pythona jest pozbawiona kontekstu. Wymóg, aby wiersze w tym samym bloku kodu miały tę samą wielkość wcięcia, nie jest czymś, co gramatyki bezkontekstowe dobrze sobie radzą.

Mówiąc ściślej, wydaje się, że istnieje homomorfizm z języka bloków pythonowych formy

jeśli warunek:
     linia 1
     linia 2
     linia3
jeszcze:
     linia4

0n10n10n

David Eppstein
źródło
4
Dokładnie masz rację, ale w kontekście języków programowania staramy się, aby język bezkontekstowy powstał po kroku wstępnego przetwarzania zwanym tokenizacją . Myślę, że wcześniej wcięcie zostało sprawdzone.
Diego de Estrada
7
Tak, leksyk Python (tokenizer) ma stos głębokości wcięć; strumień tokenów ma symbol INDENT na początku każdego bloku i symbol DEDENT na końcu, który można analizować w sposób bezkontekstowy (INDENT i DEDENT działają podobnie jak nawiasy klamrowe w C). C ma problem z „nie wiadomo, czy deklaracja lub wyrażenie”: czy foo * bar;deklaracja foojest wskaźnikiem, barczy foowielokrotnością bar?
Maks.
8
Ok, jasne, ale wtedy ukrywasz w leksyrze tę samą złożoność, a nie czynisz z niej przetwornik stanu skończonego, jak to często bywa.
David Eppstein,
1
@DavidEppstein: Mówiąc szczerze, złożoność wcale nie jest wielka.
Jon Purdy,
1
Oprócz obsługi INDENT / DEDENT w leksyrze, Python ma bardzo prostą gramatykę LL (1).
rmmh,
13

Bodo Manthey i Martin Böhme pokazują, że każdy kompilator C ++ jest koniecznie kompletny Turinga, to znaczy, że może obliczyć dowolną częściową funkcję rekurencyjną podczas kompilacji . Jest więc znacznie gorszy niż tylko kontekstowy.

http://wwwhome.math.utwente.nl/~mantheyb/journals/BotEATCS_BoehmeManthey_CompilingCPP.pdf

Markus Bläser
źródło
Tak, ale kompilator nigdy nie jest gramatyką kontekstową. Powinieneś omówić samą gramatykę, a nie kompilator.
Jeff Burdges
@Jeff: „Czas kompilacji” w mojej odpowiedzi oznacza „sprawdzenie, czy dany kod źródłowy C + jest poprawny”. Po niewielkiej modyfikacji konstrukcji w artykule wynika, że ​​można zredukować każdy rozstrzygalny język do zestawu wszystkich poprawnych programów C ++.
Markus Bläser,
7

Myślę, że deklaracja przed użyciem zmiennych i polimorfizm funkcji języków OOP to inne przykłady specyfikacji języków programowania, których nie można obsłużyć za pomocą gramatyki bezkontekstowej:

int myfun(int a) { ... }
int myfun(int a, int b) { ... }
int myfun(int a, int b, int c, ...) { ... }
...
int I_m_I_cfg = myfun(1,2);
...

Przeprowadziłem małe wyszukiwanie w Google i znalazłem ten artykuł: A Boolean Grammar for a Simple Boolean Language autorstwa A.Okhotin (2004); jego zdaniem prawdziwym problemem jest znalezienie języka programowania, który jest całkowicie opisany przez gramatykę formalną:

Zdefiniowano zabawkowy język programowania proceduralnego i zbudowano logikę gramatyczną dla zestawu poprawnie utworzonych programów w tym języku. Jest to najwidoczniej pierwsza specyfikacja języka programowania całkowicie oparta na gramatyce formalnej.

Część wstępna tego artykułu jest krótka, ale bardzo wyjaśniająca.

Marzio De Biasi
źródło
6

Uważam, że gramatyka języka C jest technicznie bezkontekstowa, ponieważ parsery zawsze używają technik bezkontekstowych do obsługi urządzenia Duffa .

Języki oparte na wcięciach nie są oczywiście pozbawione kontekstu, jak powiedział David, ale stają się pozbawione kontekstu względem sparametryzowanego tokena wcięcia.

Haskell umożliwia zmianę pierwszeństwa operatora za pomocą infix i infixl. Moduł ścisłej pragmy Perla jest implementowany przy użyciu ustawień leksykalnych $ ^ H i% ^ H, co sprawia, że ​​nie jest on kontekstowy, prawdopodobnie też inne ustawienia.

Istnieją języki ekspanderów makr, takie jak TeX, w których parsowanie afaik nie ma sensu bez wykonywania.

Prawdopodobnie istnieją nawet dwie bezkontekstowe gramatyki, których przecięcie nie jest pozbawione kontekstu, ale wciąż opisuje maszynę Turinga.

Java i asembler są prawdopodobnie naturalnie pozbawione kontekstu.

Jeff Burdges
źródło
2
Czy niejednoznaczność (a)-bsprawia, że ​​C jest wrażliwy na kontekst? ( amoże być zmienną lub typedef - z tego powodu niektóre inne języki nie zezwalają na rzutowanie wyrażeń
jednoznacznych
Przepraszam za bardzo opóźniony komentarz, ale urządzenie Duffa nie zawiera żadnych odchyleń składniowych. Szelki równoważą się prawidłowo. Funkcja C najczęściej ignorowana w dyskusjach na temat tego, czy C jest pozbawiona kontekstu, jest preprocesorem. Jestem sceptyczny, że istnieje jakakolwiek nieformalna interpretacja „bezkontekstowego”, która pozwala na użycie go do opisu języka z makroprocesorem, nawet dobrze zachowującego się. A preprocesor C nie zachowuje się dobrze.
rici
4

Nie, a wiele praktycznych języków nie jest pozbawionych kontekstu. Na przykład gramatyka C ++ nie jest, ponieważ w niektórych kontekstach rozdzielczość gramatyki zależy od pisania informacji, które nie są pozbawione kontekstu.

antti.huima
źródło
4

Najpierw pozwól mi dokonać rozróżnienia między składnią języka programowania a samym językiem.

Składnia wielu języków jest (przynajmniej oparta) na gramatyce bezkontekstowej (CFG), ponieważ są one dobrze zbadane i istnieją algorytmy, które mogą skutecznie analizować CFG, a przypadek krawędzi, którego nie można rozwiązać za pomocą CFG, można traktować specjalnie

Jednak wiele języków w rzeczywistości nie jest pozbawionych kontekstu (gdy używane są symbole deklaracji przed użyciem, na przykład w języku Java, C (++), D).

Ciekawostka: D ma całkowitą ocenę funkcji czasu kompilacji Turinga i rozszerzenie szablonu, dzięki czemu sam język nie jest rozstrzygalny przez Turinga. Jednak twórca języka dołożył wszelkich starań, aby uczynić składnię CFG.

maniak zapadkowy
źródło
Analiza nazw i typów zazwyczaj wykonuje z natury zadania bezkontekstowe.
Raphael
Meta-programowanie szablonów w C ++ zostało zakończone.
Jeff Burdges
3

O ile „Czy wszystkie języki programowania / skryptów są wolne od gramatyki?” część dotyczy, odpowiedź jest jednoznaczna Nie.

Re: główne pytanie „dla języka, który można ostatecznie skompilować / przekształcić w instrukcje na poziomie systemu”, „nie wiem, dlaczego koniecznie musi to być CFG. Jednak mogą pojawić się lepsze wyjaśnienia.

Kris
źródło
1
Kris, czy możesz podać kilka przykładów kontekstowych języków programowania opartych na gramatyce. To znaczy, po wstępnym przetwarzaniu, które może wiązać się z problemami, które mogą, ale nie muszą być obliczalne, ostateczną gramatyką, względem której program jest sprawdzany.
sandeepkunkunuru
3

Język programowania musi opierać się na pewnym formalizmie gramatycznym, którego przykładem są CFG. Podczas gdy CFG są najczęstsze (i są to zwykłe rzeczy nauczane na kursach kompilatora na uniwersytetach), istnieją inne formalizacje, takie jak gramatyka wyrażeń parsingowych, o których więcej można przeczytać tutaj (pdf) lub na Wikipedii, aby przeczytać więcej.

evilcandybag
źródło