Kompilator SScript

27

Witam! :)

Jakiś czas temu, gdy nie miałem nic konkretnego do roboty, pomyślałem, że napiszę sobie kompilator. Ot - taki prosty, a nuż mi się może kiedyś przyda jak będę pisał inne projekty. Tak więc i zacząłem pisanie...
... a dzisiaj (po jakichś 4-5 miesiącach) ukończyłem wersję pierwszą*.
Jest to w gruncie rzeczy kompilator do bajtkodu**, maszyna wirtualna dzięki której można te programy uruchamiać oraz prosty edytor (wszystko pisanie w Pascalu: Lazarusie).

Sama składnia mojego języka (który nazwałem SScript, już sam nie wiem dlaczego) jest prosta i podobna do większości języków pokroju C, C++, Javy, ...:

function<int> main()
{
 return 0;
}

Najprostszy Hello World! wygląda tak:

@("stdlib\\stdio.ss") // dołączamy moduł; podwójny backslash, ponieważ parser kodu obsługuje escapowanie stringów (`\n`, `\r` i tym podobne), więc `\s` zostałoby potraktowane nieco inaczej, niż byśmy chcieli

function<int> main()
{
 println("Hello World!");
}
Istnieje 6 podstawowych typów dla zmiennych:
nazwa
objętość (bajty) zakres odpowiednik w Pascalu
bool 1 false..true Boolean
char 1 0..255 Char
int 4 -2147483648 .. 2147483647 LongInt
float 10 3.6 10-4951 .. 1.1 104932 Extended
string - - String
void - - -
Oraz parę podstawowych nagłówków:
nazwa
opis
math.ss proste operacje matematyczne (sin, round, potęga)
numbers.ss operacje na liczbach (zamiana na string itp.)
short_cast.ss funkcje do szybkiego castowania pomiędzy typami; i2f (int to float), b2s (bool to string) itd.
stdio.ss obsługa standardowego wejścia oraz wyjścia
string.ss operacje na ciągach znaków (strpos, strreplace itd.)
time.ss operacje związane z czasem

Przykład liczenia n-tej liczby Fibonacciego iteracyjnie:

@("stdlib\\stdio.ss")

// 'float' ma większy zakres od zwykłego 'int'-a, dlatego został ten typ tutaj użyty
function<float> fib(int n)
{
 var<float> a=1, b=1, c;

 if (n <= 0)
  return 0;

 if (n <= 2)
  return n;

 for (var<float> i=3; i<=n; i++)
 {
  c = a+b;
  a = b;
  b = c;
 }

 return c;
}

function<int> main()
{
 var<int> n = read_int_t("Którą liczbę policzyć? ");

 print("fibonacci(");
 print(n);
 print(") = ");
 print(fib(n));
 /*
  Te 4 printy powyżej można by równie dobrze połączyć w jeden (uprzednio dodając `numbers.ss`):
  println("fibonacci("+intstr(n)+") = "+fltstr(fib(n)));
  Lecz to jest wg.mnie zbyt mało czytelne, stąd zostawiłem to tak jak jest.
 */
}

Jeżeli ktoś pisze w C, C++, Javie lub podobnych składniowo językach, to chyba zbytnio zaskoczony nie jest ;)

W języku istnieją pętle for, while (ale póki co nie ma do..while), instrukcja if oraz zmienne (stałe także są dopiero w planach, najprawdopodobniej następna wersja już je będzie miała). Podobnie z typami - jest to jedynie zalążek i nie ma póki co możliwości tworzenia typów (chociaż wersja 2.0a je miała, ale to inna historia :>, bo aktualny 2.0b jest pisany całkowicie od zera).

Póki co niezbyt wiele można w nim napisać (z racji tego, że dzisiaj wyszła dopiero pierwsza wersja, jak i sam język planuję raczej celować jako język skryptowy do gier, a nie ogólnego użytku/przeznaczenia), lecz mam nadzieję, że z czasem konstrukcji językowych będzie więcej (tj.napiszę więcej) ;)

Jak też wspomniałem na początku - sam kompilator jest napisany w-miarę prosto, więc nie ma w nim rzeczy typu single-static-assignment, natomiast postanowiłem zrobić taki "myk", że każde wyrażenie (w tym pętla, warunek itp.) są trzymane w osobnej tablicy/liście i najpierw po wejściu do funkcji, każde z wyrażeń jest zamieniane na drzewko i zapisywane do tej tablicy, a dopiero pod koniec wszystko jest ewaluowane (dzięki temu myślę, że łatwiej mi będzie zrobić optymalizacje w samym kodzie (bo wykrycie kodu x=3; x=5; i usunięcie pierwszego przypisania nie będzie niczym trudnym), bo póki co mam jedynie optymalizator bajtkodu oraz skracanie wyrażeń stałych (2+2*2 jest bezpośrednio skracane do 6, o ile włączone są optymalizacje)).

Dając wam ten kompilator, maszynę wirtualną oraz edytor liczę na sugestie, co mógłbym poprawić, co usunąć, a co dodać (bo wiem, że jeszcze długa droga, nim całość będzie można ogłosić "tró kompilatorem") - zarówno od strony użytkownika, jak i kodu :)

PS: wiem, że póki co nie ma szczegółowych opisów cd.składni, lecz myślę, że dacie radę się połapać (pooglądajcie pliki źródłowe w compiler\stdlib, by połapać składnię).
PS2: jestem także w trakcie pisania opisu bibliotek i całej reszty SScript'u - http://sscriptwiki.xorg.pl
PS3: kod źródłowy (zajmujący nieco mniej od 6 MB) nie dał się wrzucić jako załącznik ("Rozmiar pliku przekracza rozmiar zadeklarowany w pliku konfiguracyjnym PHP"), więc wrzucam tutaj: http://speedy.sh/EfhZA/Kod.zip

* sam kompilator ma tak naprawdę wersję 2.0b, ponieważ nie jest to moje pierwsze podejście, a z pewnych powodów historycznych nie chciałem numerować od zera ;)
** oczywiście bajtkod autorski, chociaż kilka razy mi przez myśl przeszło, by pisać na JVM.
#Edit teraz zauważyłem, że zapomniałem usunąć z archiwów jeden ze starych plików: CTypes.pas - nieużywana pozostałość, o której zapomniałem ;P

Pozdrawiam! ;)

3

Najważniejsza w każdym projekcie jest dokumentacja. Wiele projektów umarło właśnie z powodu braku dokumentacji lub jej kiepskiej jakości.

0

Mam jeszcze pytanie czy ten język skompilowałby fibonacci w wersji rekurencyjnej?

0

Tak, działa także Fibonacci w wersji rekurencyjnej:

function<int> fib(int n)
{
 if (n <= 2)
  return 1;

 return fib(n-2)+fib(n-1);
}

Natomiast jest to znacznie wolniejsze od wersji iteracyjnej (głównie z powodu liczenia kilkukrotnie tych samych wartości).

0

No to zaraz sobie to przetestuję....

1

Odpaliłem program rekurencyjny i działa dobrze ale VM trochę namieszała mi na ekranie. Nie rozumiem po co cofasz kursor na początek konsoli wyświetlania.

0

Stały callstack :|

10

Nie wiem po co, ale fajne ;) Fajnie, że ci się chciało.

0

Brawo, przeglądając kod stwierdziłem że jest w to włożone naprawdę masa roboty. Ja zawsze chciałem właśnie coś takiego napisać ale za każdym razem wychodziły mi jakieś pseudo-języki które nijak nie miały się do rzeczywistości. Zapewne brakowało mi teorii ^^

Życzę powodzenia w dalszej pracy :)

3

Update!

Edytor 0.2, kompilator 2.1 oraz maszyna wirtualna 0.2


Changelog - edytor:

  • parę małych usprawnień edytora kodu (automatyczne dopełnianie nawiasów oraz możliwość zmiany, czy kursor może wychodzić poza linię (jak domyślnie w SynEdit) czy nie)
  • dodano możliwość wyboru, czy ostatnio otwierany projekt ma być automatycznie otwierany przy uruchomieniu edytora od nowa (jak np.jest w Lazarusie)
  • naprawiono błąd, gdy próbowano zamknąć niezapisaną kartę
  • naprawiono crash, gdy próbowano otworzyć nieistniejący plik z listy 'ostatnio otworzonych'
  • od teraz można stworzyć nowy projekt gdy jeden został już otwarty/stworzony bez konieczności restartu edytora
  • obsługa języków (domyślny angielski + polski w osobnym pliku; język do wyboru z ustawień środowiska)
  • dodano możliwość zapisu komunikatów kompilatora do schowka bądź pliku
  • poprawiono maksymalizowanie formy przy uruchamianiu edytora
  • edytor kodu ma teraz własne menu kontekstowe
  • dodano możliwość edycji parametrów przekazywanych do maszyny wirtualnej
  • poprawiono formatowanie kodu przy @
  • dodano nowe demo: fraktal Mandelbrota (zaimplementowany na podstawie kodu bodajże z http://monk.4programmers.net/)
  • dodano mały easter-egg ;)

    Changelog - kompilator:

  • dodano lokalne oraz globalne stałe
  • od teraz nie można stworzyć zmiennej lub parametru funkcji typu void
  • naprawiono konstrukcję return;
  • poprawiono optymalizator oraz dodano optymalizacje dla opcodów jednoparametrowych (call, jmp...)
  • dodano sprawdzanie typów dla operatorów +=, -=, *= (...)
  • naprawiono operator =, który nie działał w niektórych konstrukcjach (np.println(zmienna = 10) wyświetlało zero)
  • zmieniono sposób zapisu stringów w bajtkodzie
  • naprawiono pętlę do..while
  • dodano nowe komunikaty dla złego typu w przypisaniu oraz złego typu parametru przy wywoływaniu funkcji
  • dodano specjalne stałe (włączane poprzez -sconst):
    • __selffunc typu string = nazwa aktualnie parsowanej funkcji
    • __self typu string = aktualnie kompilowany plik (pełna ścieżka)
    • __compiler_version typu string = wersja kompilatora (np."2.1")
    • __compiler_iversion typu float = wersja kompilatora (np.2.1)
    • __line typu int = aktualna linia
    • __date typu string = data kompilacji; format: dd-mm-yyy
    • __time typu string = godzina kompilacji; format: hh:mm
  • naprawiono kolejność wykonywania kilku operatorów
  • naprawiono błąd w funkcji RemoveRedundantPushes, który - prostymi słowami - czasami usuwał rzeczy, których nie powinien.

    Changelog - maszyna wirtualna:

  • poprawiono wydajność (na koszt tego, że jeżeli wykona się np.jmp(92367129876123) to nastąpi crash maszyny jako Access violation, a we wcześniejszej wersji pokazałoby, że nastąpiła próba czytania poza bajtkodem - ale raczej wielki problem to nie jest, biorąc pod uwagę skok wydajności - na moim Intel Core 2 Duo - średnio o 500 opcodów na milisekundę więcej)
  • naprawiono opcody if_, jeżeli przekazane argumenty to były float, int bądź int, float
  • poprawiono literówki w operatorach TOpParam, gdy oba argumenty były floatami (porównywało nie te wartości, w konsekwencji zawsze zwracając true)
  • usunięto niepotrzebne dane z Opcodes.pas

    Jednocześnie mam do ogłoszenia także dwie rzeczy:
    1.Kiedyś postawiłem małą Wiki dla tego języka, teraz ją zaczynam powoli uzupełniać o opisy funkcji, poradniki itd. - link: http://sscriptwiki.xorg.pl (anonimowi użytkownicy nie mogą nic zmieniać, a rejestracja jest zamknięta - nie chcę mieć tam niepotrzebnego bałaganu; dodatkowo najlepiej przeglądać z włączonym AdBlockiem; może kiedyś postawię to na jakimś płatnym serwerze bez reklam, jeżeli kogoś ten projekt bardziej zainteresuje)
    2.Cały projekt już od tego 1.5 tygodnia jest na GitHubie, lecz postanowiłem, że dopiero przy tej wersji się podzielę tymi informacjami; tak więc i podaję linki:
    https://github.com/Piterolex/SScript-Editor
    https://github.com/Piterolex/SScript-Compiler
    https://github.com/Piterolex/SScript-VM
    Jeżeli ktoś znajdzie jakiś błąd, ma sugestię or something, niech tam pisze ;)

Pełna paczka z edytorem, przykładami i tym wszystkim do pobrania jest na:
https://github.com/Piterolex/SScript-Editor/tree/master/build

Pozdrawiam! ;)

#Edit: jeszcze odnośnie callstacka - alokuję ileś-tam rekordów na sztywno, by całość działała szybciej (bo nie trzeba się wtedy bawić w żadne kopiowanie skrawków pamięci i jej ponowne realokowanie cały czas); w następnej wersji VM-ki może jednak przemyślę robienie tego na mniej-sztywnej zasadzie, podobnie ze stosem.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0