Focus Core

Mój pierwszy kompilator
xD Pozdrowienia dla dociekliwych xD

2007-11-04

Edytor FocusParser :)

W końcu małe co nieco :). Przepisałem parser pascala z pascala do mojego nowego języka do tworzenia parsherów :). Może to UberScript ? :) Raczej jego nagłówek.

Na pierwszy rzut oka można powiedzieć że wygląda dość masochistycznie i topornie, jednak w istocie jest to bardzo prosty, intuicyjny język (jego opis zamieszczę niebawem).

W drodze przetwarzania jest z niego generowana składnia w Pascalu. Język ten jest pierwszą z kilku warstw kompilatora. Zapraszam do oglądania i komentowania :)

Link Do Kodu Źródłowego

2007-11-02

Książka - "Kompilatory - Reguły, metody i narzędzia"

W końcu! :) Po dość długim czasie udało mi się zdobyć książkę którą miałem upatrzoną od dość dawna, aczkolwiek nie miałem sposobności na jej zdobycie. Raz, że była zbyt droga (160zł) a dwa nie byłem studentem. Jako, że obecnie "jeszcze" jestem studentem a w mojej bibliotece (o dziwo) są aż 3 egzemplarze tej książki, pokusiłem się o wypożyczenie jednej z nich :).

Co dalej? Pożyjemy - zobaczymy.

2007-10-23

Teoria Wizualnego Tworzenia Kompilatorów

W związku z pracami nad internetowym systemem DaThoX linki przestały działać - dzięki za spostrzeżenie - naprawiłem. Nastąpiła dość długa przerwa, spowodowana studiami, trochę też robotą dla mojego gamedev teamu. Nic to :). Zamierzam kontynuować dotychczasowe blogowe osiągnięcia - co najmniej jeden post na jeden miesiąc.

Podczas męczenia się z Uber Script powstała wizja narzędzia nadrzędnego dla "Uber Scripta" - mianowicie "Langu Age". Wizja systemu logicznego dla Kompilatorów. Jako, że na jednym kompilatorze (tudzież języku skryptowym JIT) nie chciałbym poprzestać, projektuję na wyrost techniki które chciałbym wykorzystać w przyszłości.

Langu Age - narzędzie trzymające wszystkie dane, struktury kompilatora w ramach spójnej całości. Prosta edycja wyrażeń regularnych, tworzenie błędów na poziomie wstępnego przetwarzania języka oraz logicznej analizy. Mam nadzieję, że moja wizja przyniesie wymierne korzyści :)

Chciałbym zauważyć iż nie wzoruję się na żadnym znanym rozwiązaniu a tworzą całość wg. mojej koncepcji (dzięki temu nie jestem w żaden sposób ograniczony - z jednej strony może powstać coś innowacyjnego a z drugiej coś gorszego od znanych rozwiązań). Oglądając różne kompilatory najbardziej mnie dobijała ich struktura - dość hermetyczne w wprowadzaniu ulepszeń (może moje subiektywne odczucie? a może widziałem zbyt mało przykładów).

Nic to :).

Langu Age powinien wspomagać następujące warstwy kompilatora:

Stream - Odpowiada za wczytywanie danych (z plików źródłowych). Jest dość potrzebna by zapewnić obsługę znaków UTF-8, UTF-16 etc.

Lexer - Wczytuje "język". Język nieco bardziej niskopoziomowy. Trudno mi to dokładnie nazwać z powodu mojej niewiedzy, ale chodzi o czyszczenie źródeł (pomijanie) "white chars" i wykrywanie błędów w stylu "Illegal character in input file: 'ą' ($B9)" w przypadku gdy np. słowa kluczowe czy też nazwy zmiennych nie mogą zawierać polskich znaków (składają się tylko z liter angielskiego alfabetu i +/- znaku w stylu _).

Log Lexer - Na podstawie wstępnie oczyszczonych źródeł przez warstwę Lexer, następuje przetwarzanie przez Log Lexer. Ta warstwa dba o logikę języka, zgłasza błędy wyższego poziomu - "Declaration expected but identifier 'xxx' found"

Script Lex / Optimisation - Trudna decyzja. Być może osobne warstwy a być może złączone w jedną. Dane przetwarzane przez Log Lexer będą zmieniane w język skryptowy (NIE JIT - więc jeśli nie dam rady zaimplementować wersji IA-64 i tak skrypty będą działać na 64 bitach ponieważ mój Uber Language będzie trawiony na kod Delphi a 64 bitowa wersja kompilatora Delphi jest już w drodze pod kodową nazwą Commodore64). Tylko pytanie - optymalizacje w trakcie zamiany na język skryptowy czy tuż po niej(?) (bardziej prawdopodobne jest pierwsze rozwiązanie).

Odnośnie Script Lex nie sposób nie wspomnieć iż przetrawiony kod na język skryptowy będzie wspólny dla różnych języków jakie będzie można tworzyć przez Langu Age i Uber Scripta. Zachowanie takie jest bardzo właściwe i pożądane - będzie można szlifować optymalizacje niezależnie od języka w którym programujemy :D, oraz dodawać platformy docelowe jakie dusza zapragnie - jedna baza danych, różne języki, i wiele platform (cel baaardzo daleki i abstrakcyjny :)).

Binary Code - Przetwarzanie języka skryptowego do plików pośrednich, skryptów JIT. Nic dodać nic ująć :).

Linker - Linkowanie do plików w stylu EXE, DLL...

Podsumowanie Langu Age

Koncepcja szalona. Projekt długoterminowy z niepewną przyszłością. Dziś wydaje się mało realny, jak wiele rzeczy o których myślałem kiedyś - nigdy tego nie napiszę (a dzisiaj działają w pełni ukończone :)).

nie wiem czy moja koncepcja jest słuszna i jak sobie poradzę z Mem Menagerem, RTTI i wieloma innymi mechanizmami. Jednak powoli i konsekwentnie. Na początek muszę dojść do celu realizując tylko części projektu - język skryptowy z moich marzeń.

2007-09-01

Parser

Plik: Parser_TEST.rar

Po wielu różnych parserah w końcu doszedłem do odpowiedniej jego formy. Zawsze wychodziły za bardzo oddalone od kompilacji/przetwarzania logicznego albo zbytnio z nim powiązane. Pierwszy raz mam poczucie, że to jest dokładnie to co być powinno :). Parsery można pisać na wiele sposobów - elastycznie (łatwo je dostosować do dowolnej składni) czy też sztywno - przeznaczone dla konkretnego języka (co może zaowocować wydajnością). Są też dostępne generatory parserów lecz te zupełnie mi nie odpowiadają. Po pierwsze zastanawiająca jest wydajność czegoś takiego, a po drugie chciałbym by UberScript był niezależny od zewnętrznych narzędzi - nie ma to jak być na swoich śmieciach ;).

To działa ;):
wykrywanie błędów na poziomie parsera (w stylu error_constant_expression_expected za znakiem # czy error_unterminated_string, error_syntax_error_in_real_number), składanie w locie stringów, czyli na przykład takiego czegoś: #72#$45'''Napis w apostrofach'''#$FFFFFFFFF#55' :D działa' w jednym "pop" :) (co chyba nie jest niczym nadzwyczajnym?). Mam radochę :D.

Parser jest tylko niewielką częścią UberScript jednak najważniejszą ponieważ całość (przetwarzanie logiczne, generowanie binarek) odwołuję się do niego setki razy i dlatego tak ważna jest jego wydajność, niezawodność i sposób przekazywania danych dalej.

TESTY. Może ktoś miałby ochotę posprawdzać czy Parser działa bez zastrzeżeń? Byłbym wdzięczny za wykrycie jak największej liczby błędów :P. (parser pisałem na 100% zgodności z parserem Delphi - mam nadzieję, że się udało). A błędy jak nie teraz to i tak wyjdą kiedyś przy okazji :)...

PS. Zrezygnowałem jedynie z zabytkowych Delphi Caret Chars (które nie działają już poprawnie w najnowszych wersjach Delphi).

PS.PS. Parser do wstawek asm będzie bardzo podobny, właściwie taki sam tylko z kosmetycznymi poprawkami (drugie apostrofy " " do napisów i specyficzne nazwy etykiet)

2007-08-25

Objconv - przybyłem, zobaczyłem i zmieniłem pliki pośrednie.

Nowe przemyślenia o pośrednim formacie (pliki gotowe do linkowania w binarkę) i odkrycia :).

OBJCONV

Przeszukując google we wszystkie strony (od niepamiętnych czasów szukałem jakiegoś "dobrego" programu do konwersji COFF na OMF i... w końcu znalazłem) odkryłem ciekawy i dość nowy program (tz. z tego roku tj. 2007) do konwersji nie tyle z COFF do OMF to i z OMF do COFF (!) i z wszystkiego na wszystko :). Jak dla mnie genialne, w dodatku z kodem źródłowym, drukuje informacje lepsze od TDUMP, a ponadto potrafi zdeasemblować te wszystkie binarki (w tym EXE i DLL!). Zwie się Objconv i można go ściągnąć pod tym adresem.

UNDNAME

Przydatna zabawka M$ potrafi odkodować nazwy procedur wyciągniętych z plików COFF. I tu się rozczarowałem :(. Pliki OMF *.obj generowane przez Borland są dużo bardziej skomplikowane od plików COFF *.obj m$ (swoją drogą zabawne jest to, że niektóre kompilatory wieloplatformowe GPL/LGPL C++/Pascala generują pliki COFF a nie OMF... Format COFF jest przystosowany pod Windowsowe pliki EXE a nie pod Linuxowe BINarki...). Szkoda, że tak ważne pliki o takim samym rozszerzeniu mają inną budowę. OMF bije na głowę pliki COFF (patrząc na logi z plików OMF a COFF i ich uniwersalność). Właściwie to szkoda, że mają taką zawiłą strukturę przystosowana pod obiektowe kodowanie - będę musiał zrezygnować z tych plików.

Z Delphi do C++ i z C++ do Delphi

Skoro jestem przy temacie, trudno nie napisać o moich nowych odkryciach :). Nie tak dawno usiłowałem przenieść ciekawy silnik 2D Haaf's Game Engine do Delphi (wzorowany na silniku Grim 2D, jednej z moich ulubionych gier : Crimsonland), przez Turbo C++ dzięki wspomnianym plikom OMF *.obj (które Delphi potrafi w siebie wkompilować). Niestety :(. Borland C++ generuje inne pliki omf niż Delphi x_X. Nie tyle co inne, tylko o bardziej skomplikowanej strukturze. To niesprawiedliwe! Pliki OMF generowane w Delphi, C++ Builder używa sprawnie... Całe szczęście, że programuję w Delphi :D. Dzięki temu nie będzie problemu gdybym chciał użyć mojego kod w C++ Builder, bo ten potrafi sobie sam wygenerować pliki *.hpp (nagłówki z przekonwertowanymi typami Delphi na kod C++ i procedurami), skompilować *.pas do OMF *.obj i używać go xD... Tylko po co mam to robić? Może kiedyś się przyda ;).

Z C do Delphi

Dobrze, że chociaż plików *.c można "prawie" używać w Delphi :). Najpierw trawimy je w C++ Builder a później wciskamy do Delphi przez {$L plik.obj} i uzupełniamy luki w procedurach o jakie woła wygenerowany *.obj (artykuł o tym jest tutaj). Tak można przenieść np. język LUA (bez DLL) do Delphi w kilka minut, przez *.obj.

Podsumowanie

Mój format pośredni będzie nieco inny od COFF czy OMF. Użyję czegoś wygodniejszego :) (jak pisałęm gdzieś niżej) i zyskam sporo czasu bo nie będę musiał tracić go na "dokładne" poznawanie wspomnianych formatów (w przyszłości). W końcu moje pliki binarne mają pełnić nieco inną rolę, będą to pliki pośrednie i zarazem gotowe skrypty. Mam nadzieję, że ktoś dożyje jeszcze do następnego posta :D - na razie priorytet to DaThoX i Delphi GameDev - ale... Niebawem przejdę do intensywnych prac nad GUI a tam przydałaby się pomoc szybkiego języka skryptowego JIT. A patrząc na to co jest, wyprodukowanie działającej wersji nie powinno być takie trudne (tylko skrypt i kod bez kompilowania do EXE) i zbyt zajmujące.

2007-07-09

Mniej Czasu

W związku z rozpoczęciem pracy nad grą w DaThoX będę miał mniej czasu na Focus Core. Jako, że Focus Core jest już nawet ładnym językiem a szkoda go tak zostawiać, więc trzeba zrobić upgrade celów. Zrezygnuję z Focus Core kompilatora, a zostanę przy pierwotnej koncepcji Focus Core Script (JIT x86).

2007-07-01

Format Plików

Kod przed zlinkowaniem do EXE będzie kompilowany do postaci pośredniej (tak jak pliki *.pas do *.dcu). Początkowo chciałem użyć plików *.obj (w wersji COFF [używany w C++ MS i innych] lub OMF [opcjonalnie generowany w Delphi i przez C++ Borlanda]), jednak jak na początek są zbyt nieporęczne i zupełnie zbędne (jedynie skomplikują proces kompilacji i linkowania i zabiorą sporo czasu na zapoznanie się z ich dokładną strukturą). Zresztą co tu dużo pisać - Focus Core ma być też skryptem i pliki wymyślone specjalnie dla FC będą mogły służyć jako skompilowane skrypty.

W przyszłości chciałbym zapewnić kompatybilność z COFF i OMF, a jak to będzie - zobaczymy.

Pliki z kodem. Mało to istotne jednak mam ochotę o tym napisać ;P

  • *.fpr - Focu Core Project (to co *.dpr)
  • *.f - Moduł z kodem (to co *.pas)
  • *.fcu - Focus Compiled Unit (podobnie jak *.dcu z tym, że będą mogły pełnić funkcję skompilowanych skryptów)
Niebawem bardziej użyteczne posty ;)...