Kiedy ktoś pisze nowy język programowania, co pisze w nim?


162

Proszę wybaczyć moją ignorancję. Bawię się PHP i zmoczę nogi podczas przeglądania, i czuję się zmuszony zadać pytanie, nad którym zastanawiałem się od lat:

Kiedy piszesz zupełnie nowy język programowania, w jakim go piszesz ?

Prawdopodobnie brzmi to naprawdę głupio dla wszystkich programistów, do których mam ogromny szacunek, ale dla mnie jest to kłopotliwe. Co robisz? Powiedz sobie Dzisiaj wymyślę nowy język! a potem odpal ... Notatnik? Czy wszystkie kompilatory są zbudowane na wcześniej istniejących językach, takich, które były jednym z problemów, można było sporządzić wykres wszystkich języków programowania, które kiedykolwiek zostały opracowane w jednym potwornym drzewie rozgałęziającym, które ostatecznie ugruntowało się na ... Nie wiem, coś starego?

Z moim słabym intelektem uważam to za fascynujące ... Proszę, naucz mnie!

Odpowiedzi:


193

To nie jest głupie pytanie. To doskonałe pytanie.

Jak już odpowiedziałem, krótka odpowiedź brzmi: „Inny język”.

Cóż, to prowadzi do kilku interesujących pytań? A jeśli jest to pierwszy język napisany dla twojego konkretnego sprzętu? Bardzo realny problem dla osób pracujących na urządzeniach wbudowanych. Jak już odpowiedział „język na innym komputerze”. W rzeczywistości niektóre urządzenia wbudowane nigdy nie otrzymają kompilatora, ich programy będą zawsze kompilowane na innym komputerze.

Ale możesz to cofnąć jeszcze bardziej. A co z pierwszymi programami, jakie kiedykolwiek napisano?

Cóż, pierwsze kompilatory dla „języków wysokiego poziomu” zostałyby napisane w tak zwanym „języku asemblera”. Język asemblera to język, w którym każda instrukcja w języku odpowiada pojedynczej instrukcji do CPU. Jest to język na bardzo niskim poziomie, bardzo rozwlekły i bardzo pracochłonny przy pisaniu.

Ale nawet pisanie języka asemblera wymaga programu zwanego asemblerem, który przekształci język asemblera w „język maszynowy”. Wracamy dalej. Pierwsze asemblery zostały napisane w „kodzie maszynowym”. Program składający się wyłącznie z liczb binarnych, które są bezpośrednią korespondencją jeden do jednego z surowym językiem samego komputera.

Ale to wciąż się nie kończy. Nawet plik zawierający tylko surowe liczby nadal wymaga tłumaczenia. Nadal musisz przenieść te surowe liczby z pliku do komputera.

Wierzcie lub nie wierzcie lub nie, wczesne komputery miały rząd przełączników z przodu. Przekręcałeś przełączniki, aż przedstawiały liczbę binarną, potem pstryknąłeś innym przełącznikiem i załadowałeś tę pojedynczą liczbę do pamięci komputera. Następnie przechodziłeś przełączanie, aż załadowałeś minimalny program komputerowy, który mógł czytać programy z plików dyskowych lub kart perforowanych. Pstryknąłeś innym przełącznikiem i uruchomiłeś program. Kiedy poszedłem na uniwersytet w latach 80-tych, widziałem komputery, które miały taką pojemność, ale nigdy nie otrzymały zadania ładowania programu za pomocą przełączników.

A jeszcze wcześniej programy komputerowe musiały być na stałe połączone z płytami z wtyczkami !


20
+1, myślę, że ta odpowiedź naprawdę pasuje do ducha pytania.
stderr

30
Kiedyś poszedłem do klasy Assembler II i profesor zapytał, dlaczego wybraliśmy elekcję. Poszedłem na zabawną odpowiedź: „ponieważ chciałem łatwego A.” Myślałem, że mam najlepszą odpowiedź, ale mieliśmy fabrykę Honeywell w mieście, a następny facet powiedział: „Piszę mikrokod przez cały dzień i chciałem nauczyć się języka wysokiego poziomu”.
T.Rob,

3
Gorąco polecam Code: The Hidden Language of Computer Hardware and Software . Zasadniczo obejmuje ten sam materiał, co ta odpowiedź, od lamp próżniowych po kompilatory języków wysokiego poziomu.
MatrixFrog

Komputery ewoluowały tak jak istoty ludzkie, aczkolwiek w stosunkowo nieskończenie krótkim czasie.
Gaurav Ojha

To będzie niekonstruktywny komentarz, ale trzeba go napisać ... to genialna, błyskotliwa odpowiedź we wszystkich kształtach, formach i informacjach :-)
Lukáš Řádek

23

Najczęstsza odpowiedź brzmi C. Większość języków jest zaimplementowana w C lub jako hybryda języka C z wywołaniami zwrotnymi i „lekserem”, takim jak Flex i generatorem parsera, takim jak YACC . Są to języki, które są używane w jednym celu - do opisu składni innego języka. Czasami, jeśli chodzi o języki kompilowane, są one najpierw wdrażane w C. Następnie pierwsza wersja języka jest używana do tworzenia nowej wersji i tak dalej. (Jak Haskell .)


1
Niektóre języki są napisane w asemblerze, np. Picolisp. ( blog.kowalczyk.info/article/picoLisp-Arc-before-Arc.html )
Prof. Falken

1
A co z programami lex / yacc (flex / bison)? Czy są to dodatki do tworzenia języków w C?
Dave

1
Czy masz coś do udowodnienia, że ​​najczęstszą odpowiedzią jest C?
RichardOD

Zacząłem przeglądać listę tutaj: google.com/Top/Computers/Programming/Languages/Open_Source Potem przypadkowo zamknąłem okno edytora mniej więcej w języku 10 i straciłem motywację, aby przejść. W każdym razie około połowa do tej pory była zaimplementowana w C, a reszta głównie ładowała się samoczynnie.
Prof. Falken

3
Myślę, że musisz wspomnieć o Lex / Yacc (lub alternatywach). Zwykle nie zaczyna się pisać języka w C, ale raczej z lekserem i parserem, które są następnie obsługiwane przez kod C.
Steve Rowe,

14

Wiele języków jest bootstrapowych - to jest napisane w sobie . Jeśli chcesz to zrobić, często dobrym pomysłem jest zjedzenie własnej dogfood .

Artykuł w Wikipedii, do którego się odwołuję, omawia kwestię kurczaka i jajka . Myślę, że uznasz to za całkiem interesujące.


5
Co nie jest możliwe, gdy dopiero zaczynasz.
Michael Borgwardt

1
Tak, oczywiście. Ale wiele języków pisze się w ten sposób, gdy tylko jest to możliwe. Chciałem zwrócić na to uwagę, jak nikt inny, i czuję, że to ważna kwestia.
RichardOD

+1 za użycie terminu bootstrap. Ciekawe, że musisz dwukrotnie skompilować swój kompilator. Pierwszy raz jest oczywiście z kompilatorem bare-bones, który posiadasz, a drugi raz z kompilatorem, który właśnie zbudowałeś. Powiedzmy, że dodałeś optymalizację do swojego kompilatora. Kompilator, który zbudowałeś, może generować kod z tymi optymalizacjami, ale sam nie uruchamia zoptymalizowanego kodu, dopóki nie skompilujesz go ponownie za pomocą kompilatora optymalizującego.
Les

@ Les- Tak, bootstrap to ciekawa koncepcja.
RichardOD

2
Losowy komentarz tutaj. Odpowiedzią na odwieczne pytanie, kto był pierwszy (kura czy jajko) jest to, że kura był pierwszy. Powodem jest to, że aby coś powielać / powielać, musisz najpierw mieć już na miejscu reproduktor / replikator, aby móc odtworzyć / zreplikować.
SpicyWeenie

10

Prawie każdy język, chociaż użycie języka dostosowanego do pracy z wykresami i innymi złożonymi strukturami danych znacznie ułatwi. Kompilatory produkcyjne są często pisane w C lub C ++ ze względu na wydajność, ale języki takie jak OCaml, SML, Prolog i Lisp są prawdopodobnie lepsze do prototypowania języka.

Istnieje również kilka „małych języków” używanych w projektowaniu języków. Lex i yacc są używane na przykład do określania składni i gramatyki i kompilują się do C. (istnieją porty dla innych języków, takich jak ocamllex / ocamlyacc i wiele innych podobnych narzędzi).

W szczególnym przypadku nowe dialekty Lisp są często budowane na istniejących implementacjach Lispa, ponieważ mogą one korzystać z większości tej samej infrastruktury. Pisanie interpretera Scheme można wykonać w Scheme pod stroną kodu, w którym to momencie można łatwo dodać nowe funkcje.

Zasadniczo kompilatory to tylko programy, które w czymś czytają i tłumaczą to na coś innego - konwertując źródło LaTeX na DVI, konwertując kod C na asembler, a następnie na język maszynowy, konwertując specyfikację gramatyki na kod C dla parsera itp. Jego projektant określa struktura formatu źródłowego (parsowanie), co oznaczają te struktury, jak uprościć dane (optymalizacja) i rodzaj wyniku do wygenerowania. Tłumacze czytają źródło i wykonują je bezpośrednio. (Tłumacze są zwykle prostsi w pisaniu, ale znacznie wolniej).


4

Właściwie możesz pisać w prawie każdym języku, który lubisz. Nic nie stoi na przeszkodzie, aby napisać kompilator C w języku Ruby. Wszystko, co musisz zrobić, to przeanalizować program i wyemitować odpowiedni kod maszynowy. Jeśli potrafisz czytać / zapisywać pliki, twój język programowania prawdopodobnie wystarczy.

Jeśli zaczynasz od zera na nowej platformie, możesz wykonać cross-kompilację: napisać kompilator dla nowej platformy, który działa w Javie lub natywnie na x86. Programuj na swoim komputerze, a następnie przenieś program na nową platformę docelową.

Najbardziej podstawowymi kompilatorami są prawdopodobnie Assembler i C.


Ten „dowolny” język powinien jednak obsługiwać wywołania rekurencyjne. W przeciwnym razie implementacja analizatora składni i parsera będzie prawdziwym wyzwaniem.

2
Jeśli wybierzesz nieodpowiedni język do zadania, to Twoja wina. Może się to zdarzyć w przypadku każdego projektu, nie tylko kompilatorów / interpreterów.
ziggystar

4

„Pisanie nowego języka programowania” z technicznego punktu widzenia nie wymaga żadnego kodu. Po prostu wymyślam specyfikację tego, jak wygląda Twój język i jak działa. Kiedy już zorientujesz się, jaki jest Twój język, możesz pisać tłumaczy pisemnych i ustnych, aby rzeczywiście „działał”.

Tłumacz wprowadza program w jednym języku i wyświetla równoważny program w innym języku. Interpreter wprowadza program w jakimś języku i uruchamia go.

Na przykład kompilator C zazwyczaj tłumaczy kod źródłowy C (język wejściowy) na program w języku asemblerowym (język wyjściowy). Następnie asembler bierze program w języku asemblera i tworzy język maszynowy. Po uzyskaniu wyniku nie potrzebujesz tłumaczy do uruchomienia programu. Ponieważ masz teraz program w języku maszynowym, procesor działa jako interpreter.

Wiele języków jest implementowanych w różny sposób. Na przykład javacjest tłumaczem, który konwertuje kod źródłowy Java na kod bajtowy maszyny JVM. JVM to interpreter [1], który uruchamia kod bajtowy Java. Po uruchomieniu javaci uzyskaniu kodu bajtowego nie potrzebujesz javacjuż. Jednak zawsze, gdy chcesz uruchomić program, będziesz potrzebować JVM.

Fakt, że tłumacze nie muszą być w pobliżu, aby uruchomić program, umożliwia "załadowanie" twojego języka bez konieczności uruchamiania go "na" warstwach i warstwach innych języków.

[1] Większość maszyn JVM wykonuje tłumaczenia za kulisami, ale tak naprawdę nie są tłumaczami, ponieważ interfejs JVM nie jest „językiem wejściowym -> językiem wyjściowym”.


3

Ogólnie rzecz biorąc, możesz używać dowolnego języka. Na przykład PHP zostało napisane w C. Jeśli nie masz dostępu do żadnego kompilatora, będziesz musiał uciec się do napisania języka asemblera i skompilowania go ręcznie do kodu maszynowego.


2
Nie musisz kompilować kodu maszynowego. z definicji jest to język ojczysty procesora.
Stu Thompson

1
Prawdziwe. Miałem na myśli "skompiluj ręcznie kod maszynowy z języka asemblera lub czegoś podobnego". Mogę się mylić, ale zgaduję, że niewiele osób po prostu od razu wpisuje kod jako binarny / szesnastkowy.
Kaivosukeltaja

2

Wiele języków zostało najpierw napisanych w innym dostępnym języku, a następnie zaimplementowano je ponownie i załadowano w ten sposób (lub po prostu zachowano implementację w języku obcym, jak PHP i Perl), ale niektóre języki, takie jak pierwszy asembler, zostały ręcznie skompilowane do kodu maszynowego, np. pierwszy kompilator C został skompilowany ręcznie do asemblera.

Zainteresowałem się bootstrapowaniem odkąd o tym przeczytałem. Aby dowiedzieć się więcej, spróbowałem zrobić to sam, pisząc własny nadzbiór BF, który nazwałem EBF . pierwsza wersja EBF miała 3 dodatkowe prymitywy i ręcznie skompilowałem pierwszy plik binarny. Robiąc to, znalazłem dwustopniowy rytm. Zaimplementowałem funkcję w obecnym języku w jednym wydaniu i miałem słodkie wydanie, w którym przepisałem kod, aby wykorzystać zaimplementowaną funkcję. Język był na tyle ekspresyjny, że można go było wykorzystać do stworzenia tłumacza LISP- a .

Mam ręcznie skompilowaną wersję wraz ze źródłem w pierwszym tagu wydania, a kod jest dość mały. Ostatnia wersja jest 12 razy większa, a kod i pozwala na bardziej kompaktowy kod, więc ręczne kompilowanie bieżącej wersji byłoby trudne do uzyskania.

Edmund Grimley Evans zrobił coś podobnego ze swoim językiem HEX

Jedną z interesujących rzeczy w robieniu tego samodzielnie jest zrozumienie, dlaczego niektóre rzeczy są takie, jakie są. Mój kod był produktem, jeśli wprowadzono małe, przyrostowe poprawki, i wygląda raczej tak, jakby ewoluował, a nie został zaprojektowany od podstaw. Pamiętam o tym czytając dzisiaj kod, który wydaje mi się trochę dziwny.


1

Zwykle z językiem programowania ogólnego przeznaczenia, odpowiednim do tworzenia systemów, np. C, Haskell, ML, Lisp itp., Ale lista opcji jest długa. Zwykle z niektórymi językami specyficznymi dla domeny do implementacji języka, np. Generatory parserów i analizatorów leksykalnych, języki pośrednie, takie jak LLVM itp. I prawdopodobnie niektóre skrypty powłoki, frameworki testowe i system konfiguracji kompilacji, np. Autoconf.


1

Większość kompilatorów była napisana jako program podobny do C lub ac jeśli nie c to język asemblera jest drogą do zrobienia Jednak kiedy piszesz nowy język od zera i nie masz biblioteki makr lub kodu źródłowego z języka prototypowego musisz zdefiniować własne funkcje Teraz w jakim języku? Możesz po prostu napisać Formularz "kodu źródłowego zwanego psedocode na maszynie. Wygląda jak gramatyka bnf ze specyfikacji językowej zorientowanej obiektowo, takiej jak Fortran basic algo lisp. Więc obraz piszący krzyżowy kod przypominający składnię dowolnego z tych języków. To jest kod psedo


1
Nie wierzę, że kod psedo ma być odczytywalny maszynowo
Richard Tingle

0

Jeszcze dalsze operacje binarne lub asemblacyjne muszą zostać przetłumaczone na funkcje, czyli zadanie asemblera / kompilatora, a następnie na obiekt, z danych i funkcji, jeśli nie masz pliku źródłowego, aby zobaczyć, "jak te funkcje powinny być reprezentowane w twoim implementacja języka, Następnie musisz rozpoznać implementację „zobaczyć” lub zdefiniować własne funkcje, procedury i struktury danych, co wymaga dużej wiedzy, musisz zadać sobie pytanie, czym jest funkcja. Twój umysł staje się wówczas symulacją języka. To oddziela głównego programistę od reszty.


0

Ja też miałem to pytanie kilka miesięcy temu. Przeczytałem kilka artykułów i obejrzałem kilka filmów, które pomogły mi rozpocząć pisanie własnego języka zwanego soft. Nie jest to jeszcze ukończone, ale wiele się nauczyłem podczas tej podróży.

Podstawowe rzeczy, które powinieneś wiedzieć, to jak działa kompilator, gdy musi wykonać fragment kodu. Kompilator ma wiele faz, takich jak analiza leksykalna, analizator semantyczny, AST (drzewo składni abstrakcyjnej) itp.

To, co zrobiłem w moim nowym języku, można znaleźć tutaj - http://www.singhajit.com/writing-a-new-programming-language/

Jeśli piszesz język po raz pierwszy, wszystkiego najlepszego i masz przed sobą długą drogę.


0

Czym są ogólnie języki programowania?

języki programowania to tylko sposób na rozmowę z komputerami. z grubsza mówiąc na początku, ponieważ komputery mogły rozumieć tylko zera i jedynki (ze względu na fakt, że komputery są zbudowane z tranzystorów jako przełączniki, które mogą przyjmować tylko dwa stany, nazywamy te dwa stany 0 i 1) i praca z 0,1 była trudna dla my jako ludzie, więc informatycy postanowili wykonać mapowanie jeden do jednego z każdej instrukcji w postaci binarnej (0,1) do postaci bardziej czytelnej dla człowieka, którą nazwali językiem asemblerowym.

na przykład gdybyśmy mieli instrukcję taką jak:

11001101

w montażu nazywa się to:

LOAD_A 15

co oznacza, że ​​ładujemy zawartość rejestru a do komórki pamięci 15. tak jak powiedziałem, była to tylko konwencja wybierania 0 i 1 dla dwóch stanów tranzystorów lub czegokolwiek innego w komputerze. w ten sposób mając program z 50 instrukcjami, zapamiętanie języka asemblera byłoby łatwiejsze. więc użytkownik napisałby kod asemblera, a jakiś program (w tym przypadku asembler) przetłumaczyłby kody na instrukcje binarne lub język maszynowy, jak go nazywają.

ale potem, gdy komputery były ulepszane każdego dnia, było miejsce na bardziej skomplikowane programy z większą liczbą instrukcji, powiedzmy 10000.

w tym przypadku mapowanie jeden do jednego, takie jak asembler, nie zadziałałoby, więc stworzono inne języki programowania wysokiego poziomu. powiedzieli na przykład, że jeśli dla relacji z urządzeniami I / O do wydrukowania czegoś na ekranie stworzonym przez użytkownika potrzeba około 80 instrukcji, zróbmy coś tutaj i moglibyśmy spakować cały ten kod do jednej biblioteki i nazwać to na przykład printf a także stworzyć inny program, który mógłby przetłumaczyć to printf tutaj na powiązany kod asemblera i stamtąd assembler zrobi resztę. więc nazywają to kompilatorem.

więc teraz każdy użytkownik, który chce po prostu wydrukować coś na ekranie, nie musiałby pisać wszystkich instrukcji w postaci binarnej lub asemblacyjnej, po prostu wpisuje printf („coś”), a wszystkie programy, takie jak kompilator i asembler, zajmą się resztą. teraz później inne dłuższe kody byłyby pakowane w ten sam sposób, aby po prostu ułatwić pracę innym ludziom, jak widzisz, możesz po prostu uprościć tysiące linii kodu w jeden kod w Pythonie i spakować go do użytku innych osób.

więc powiedzmy, że spakowałeś wiele różnych kodów w Pythonie i utworzyłeś moduł (libray, pakiet lub cokolwiek chcesz go nazwać) i nazywasz ten moduł mgh (tylko moje imię). teraz powiedzmy, że w jakiś sposób stworzyliśmy tę mgh, którą każdy, kto mówi:

import mgh
mgh.connect(ip,port.data)...

mógł łatwo połączyć się ze zdalnym serwerem z określonym adresem IP i portem, a następnie wysłać dane (lub coś w tym rodzaju). teraz ludzie mogliby to wszystko zrobić używając jednej linii, ale dzieje się tak, że wykonywanych jest wiele kodów, które zostały pobrane z pliku mgh. a pakowanie nie służyło przyspieszeniu procesu wykonywania, ale raczej ułatwieniu pracy innym programistom. więc tutaj, jeśli ktoś chce najpierw użyć twojego kodu, powinien zaimportować plik, a następnie interpreter Pythona rozpozna cały kod w nim i będzie mógł zinterpretować kod.

teraz jeśli chcesz stworzyć język programowania i chcesz go wykonać, najpierw potrzebujesz tłumaczenia, na przykład powiedzmy, że tworzysz program, który mógłby zrozumieć składnię i przekonwertować go na c, w tym przypadku po przetłumaczeniu c, resztą zajmie się kompilator c, potem assembler, linker, .... chociaż musiałbyś zapłacić cenę wolniejszego, ponieważ najpierw trzeba go przeliczyć na c.

teraz jeszcze jedną rzeczą, którą możesz zrobić, jest stworzenie programu, który mógłby przetłumaczyć cały kod na równoważny język asemblera, tak jak dzieje się to z c, ale w tym przypadku program mógłby to zrobić bezpośrednio i stamtąd reszta byłaby wykonana przez konsolidator. wiemy, że ten program nazywa się kompilatorem.

więc mówię o tym, że jedyny kod, który system rozumie, to 0,1, więc w jakiś sposób powinieneś przekonwertować swoją składnię do tego, teraz w naszych systemach operacyjnych wiele różnych programów, takich jak assembler, linker i ... ma został stworzony, aby powiedzieć ci, że gdybyś mógł przekonwertować swój kod do asemblera, mogliby zająć się resztą lub, jak powiedziałem, możesz nawet użyć kompilatorów innych języków programowania, konwertując swój kod na ten język.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.