BlitzLLVM - BlitzBasic auf LLVM

Kommentare anzeigen Worklog abonnieren

Worklogs BlitzLLVM - BlitzBasic auf LLVM

Verbesserungen am Lexer

Samstag, 18. November 2017 von Xaymar
Der Lexer wird ab heute ein wenig intelligenter, denn dieser versteht nun den Unterschied zwischen einem internem Befehl und normalen Text, sowie den Unterschied zwischen Kommentar und Code. Aus folgendem Code:
BlitzBasic: [AUSKLAPPEN]
; Ein simpler Lexer Test
Local Variable = 1.0
Local Variable2$ = "Hallo Welt"

For I = 0 To 8
Variable = Variable + I
Next

While Variable
Variable = Variable - 1
Wend

Repeat
Variable = Variable + 1
Until Variable

Repeat
Exit
Forever

If Variable = 0 Then
Variable = 1
EndIf

Function DoVar(Var)
Return Var * Var
End Function

DoVar Variable
DoVar(Variable)

Global Variable3# = 7.2
Variable3 = Variable3 / 4 * 5 - 2 + 8 ^ 22

macht dieser nun folgende Token(Text) Auflistung:
Code: [AUSKLAPPEN]
; Comment( Ein simpler Lexer Test)
Local Text(Variable) = Decimal(1.0)
Local Text(Variable2) $ = " QuotedText(Hallo Welt) "

For Text(I) = Number(0) To Number(8)
Text(Variable) = Text(Variable) + Text(I)
Next

While Text(Variable)
Text(Variable) = Text(Variable) - Number(1)
Wend

Repeat
Text(Variable) = Text(Variable) + Number(1)
Until Text(Variable)

Repeat
Exit
Forever

If Text(Variable) = Number(0) Then
Text(Variable) = Number(1)
EndIf

Function Text(DoVar) ( Text(Var) )
Return Text(Var) * Text(Var)
End Function

Text(DoVar) Text(Variable)
Text(DoVar) ( Text(Variable) )

Global Text(Variable3) # = Decimal(7.2)
Text(Variable3) = Text(Variable3) / Number(4) * Number(5) - Number(2) + Number(8) ^ Number(22)


Damit wäre also nun der Weg frei für den Parser, der diesen in einen Abstract Syntax Tree (AST) umwandelt.

Commits:

Der Lexer: Umwandeln von Blitz in Maschinenlesbares

Montag, 13. November 2017 von Xaymar
Es gibt Tage an denen ist man mehr produktiv und es gibt Tage an denen geht einfach gar nichts voran. Zum Glück ist heute einer der Tag in dem es sehr rapide voranging, erst mit dem MiniBCC Eintrag und nun mit BlitzLLVM.

Der Lexer
Einer der wichtigsten Teile eines Compilers ist der Lexer und dieser ist nun in einem funktionierenden Zustand. Er kann sämtliche Blitz Dateien korrekt in ein Maschinenlesbares Format umwandeln, womit später der Parser dann arbeiten kann.

Dieser konvertiert also nun folgenden Code:
BlitzBasic: [AUSKLAPPEN]
Graphics 800,600,32,2
SetBuffer BackBuffer()

Local value% = 1
If value == 1 Then
Print "Hello World"
EndIf

In dieses Maschinenlesbare Format:
Code: [AUSKLAPPEN]
Text(Graphics) Number(800) , Number(600) , Number(32) , Number(2) NewLine
Text(SetBuffer) Text(BackBuffer) ( ) NewLine
NewLine
Text(Local) Text(value) % = Number(1) NewLine
Text(If) Text(value) = = Number(1) Text(Then) NewLine
Text(Print) " QuotedText(Hello World) " NewLine
Text(EndIf)


Ein recht gutes Ergebnis mit dem ich zufrieden bin. Ich werde noch einige der Grundbefehle von Text in echte Tokens umwandeln und dann geht es darum den Parser beizubringen wie man mit diesem Format umgeht.

Weitere Tests
Natürlich habe ich auch weitere Tests gemacht. Ein weiteres Beispiel das in der GitHub repository liegt hat folgenden Inhalt:
BlitzBasic: [AUSKLAPPEN]
; Ein simpler Lexer Test
Local Variable = 1.0
Local Variable2$ = "Hallo Welt"

For I = 0 To 8
Variable = Variable + I
Next

While Variable
Variable = Variable - 1
Wend

Repeat
Variable = Variable + 1
Until Variable

Repeat
Exit
Forever

If Variable = 0 Then
Variable = 1
EndIf

Function DoVar(Var)
Return Var * Var
End Function

DoVar Variable
DoVar(Variable)

Global Variable3# = 7.2
Variable3 = Variable3 / 4 * 5 - 2 + 8 ^ 22
;~IDEal Editor Parameters:
;~C#BlitzNext

Aus dem dann dieses wird:
Code: [AUSKLAPPEN]
; Text(Ein) Text(simpler) Text(Lexer) Text(Test) NewLine
Text(Local) Text(Variable) = Decimal(1.0) NewLine
Text(Local) Text(Variable2) $ = " QuotedText(Hallo Welt) " NewLine
NewLine
Text(For) Text(I) = Number(0) Text(To) Number(8) NewLine
Text(Variable) = Text(Variable) + Text(I) NewLine
Text(Next) NewLine
NewLine
Text(While) Text(Variable) NewLine
Text(Variable) = Text(Variable) - Number(1) NewLine
Text(Wend) NewLine
NewLine
Text(Repeat) NewLine
Text(Variable) = Text(Variable) + Number(1) NewLine
Text(Until) Text(Variable) NewLine
NewLine
Text(Repeat) NewLine
Text(Exit) NewLine
Text(Forever) NewLine
NewLine
Text(If) Text(Variable) = Number(0) Text(Then) NewLine
Text(Variable) = Number(1) NewLine
Text(EndIf) NewLine
NewLine
Text(Function) Text(DoVar) ( Text(Var) ) NewLine
Text(Return) Text(Var) * Text(Var) NewLine
Text(End) Text(Function) NewLine
NewLine
Text(DoVar) Text(Variable) NewLine
Text(DoVar) ( Text(Variable) ) NewLine
NewLine
Text(Global) Text(Variable3) # = Decimal(7.2) NewLine
Text(Variable3) = Text(Variable3) / Number(4) * Number(5) - Number(2) + Number(8) ^ Number(22) NewLine
; ~ Text(IDEal) Text(Editor) Text(Parameters) : NewLine
; ~ Text(C) # Text(BlitzNext)


Und auch der code von Holzchopf im MiniBCC #30 wird korrekt umgewandelt:
Code: [AUSKLAPPEN]
; Text(Sources) Text(einbinden) NewLine
Text(Include) " QuotedText(_srcbb/MinMax.bb) " NewLine
Text(Include) " QuotedText(_srcbb/consts.bb) " NewLine
Text(Include) " QuotedText(_srcbb/HUD.bb) " NewLine
Text(Include) " QuotedText(_srcbb/Menu.bb) " NewLine
Text(Include) " QuotedText(_srcbb/TGoal.bb) " NewLine
Text(Include) " QuotedText(_srcbb/TRobot.bb) " NewLine
Text(Include) " QuotedText(_srcbb/TSandbox.bb) " NewLine
Text(Include) " QuotedText(_srcbb/TSensor.bb) " NewLine
Text(Include) " QuotedText(_srcbb/TSimpFont.bb) " NewLine
NewLine
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * NewLine
; Text(Hier) Text(kommt) Text(deine) Text(AI) Text(hin) NewLine
Text(Include) " QuotedText(AIs/xaymar.bb) " NewLine
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * NewLine
NewLine
; Text(Spiel) NewLine
Text(Global) Text(gametime) % NewLine
Text(Global) Text(state) % , Text(controls) % NewLine
Text(Global) Text(mx) % , Text(my) % , Text(mh1) % NewLine
NewLine
; Text(Initialisieren) NewLine
Text(Local) Text(timer) % = Text(CreateTimer) ( Text(HERTZ) ) NewLine
Text(Local) Text(sandbox) Decimal(f) Text(TSandbox) = Text(CreateSandbox) ( ) NewLine
Text(state) = Text(STATE_MENU) NewLine
Text(controls) = Text(CONTROLS_AI) NewLine
NewLine
Text(Graphics3D) ( Text(SCREEN_WIDTH) , Text(SCREEN_HEIGHT) , Number(0) , Number(2) ) NewLine
Text(SetBuffer) ( Text(BackBuffer) ( ) ) NewLine
NewLine
; Text(Medien) Text(laden) NewLine
Text(LoadTiles) ( Text(sandbox) , " QuotedText(gfx/Tiles.png) " ) NewLine
Text(LoadMap) ( Text(sandbox) , " QuotedText(map.txt) " ) NewLine
NewLine
Text(Local) Text(font) Decimal(f) Text(TSimpFont) = Text(LoadSimpFont) ( " QuotedText(gfx/font) " , Number(32) ) NewLine
NewLine
Text(Local) Text(crosshairs) % = Text(LoadImage) ( " QuotedText(gfx/Crosshairs.png) " ) NewLine
Text(HandleImage) ( Text(crosshairs) , Number(200) , Number(200) ) NewLine
NewLine
Text(Origin) ( Text(HUD_SIDE_WIDTH) * Text(TILE_SIZE) , Number(0) ) NewLine
NewLine
Text(MoveMouse) ( Text(SCREEN_WIDTH) / Number(2) , Text(SCREEN_HEIGHT) / Number(2) ) NewLine
NewLine
; Text(Hauptschleife) NewLine
Text(Local) Text(timerruns) % = Number(1) NewLine
Text(Repeat) NewLine
Text(mx) = Text(MouseX) ( ) - Text(HUD_SIDE_WIDTH) * Text(TILE_SIZE) NewLine
Text(my) = Text(MouseY) ( ) NewLine
Text(mh1) = Text(MouseHit) ( Text(MOUSE_LEFT) ) NewLine
NewLine
; Text(FSM) NewLine
Text(Select) Text(state) NewLine
Text(Case) Text(STATE_SIMULATION) NewLine
; Text(synchrone) Text(Aktualisierung) NewLine
Text(Local) Text(r) % NewLine
Text(For) Text(r) = Number(1) Text(To) Text(timerruns) NewLine
Text(gametime) = Text(gametime) + Number(1) NewLine
; Text(Steuerung) Text(manuell) / Text(Autopilot) NewLine
Text(If) Text(controls) = Text(CONTROLS_HUMAN) Text(Then) NewLine
Text(MousePilotRobot) ( Text(sandbox) \ Text(robot) ) NewLine
Text(Else) NewLine
Text(AutoPilotRobot) ( Text(sandbox) \ Text(robot) , Text(sandbox) \ Text(dists) ) NewLine
Text(EndIf) NewLine
; Text(Simulation) Text(aktualisieren) NewLine
Text(UpdateSandbox) ( Text(sandbox) ) NewLine
Text(Next) NewLine
Text(End) Text(Select) NewLine
NewLine
; Text(Ausgabe) NewLine
Text(Cls) NewLine
NewLine
Text(DrawSandbox) ( Text(sandbox) ) NewLine
Text(DrawHUD) ( Text(sandbox) , Text(font) ) NewLine
NewLine
; Text(Hilfslinien) Text(bei) Text(manueller) Text(Steuerung) NewLine
Text(If) Text(controls) = Text(CONTROLS_HUMAN) Text(Then) NewLine
Text(DrawImage) ( Text(crosshairs) , Text(SCREEN_WIDTH) / Number(2) - Text(HUD_SIDE_WIDTH) * Text(TILE_SIZE) , Number(300) ) NewLine
Text(EndIf) NewLine
NewLine
Text(DrawMenu) ( Text(sandbox) , Text(font) ) NewLine
NewLine
Text(timerruns) = Text(WaitTimer) ( Text(timer) ) NewLine
Text(Flip) Number(0) NewLine
Text(Forever) NewLine
NewLine
Text(End) NewLine


Nachwort
Netterweise ist die Basic Sprache so simpel, dass das schreiben eines (lesbaren) Lexers für diese nur 119 Zeilen belegt. So kann ich also mehr Fokus auf einen besseren Parser setzen, welcher auch bei problematischen Code warnt. Dinge wie

BlitzBasic: [AUSKLAPPEN]
Local Mesh# = CreateMesh()


Würden dann korrekt erkannt und optional auch als Fehler gemeldet werden. Aber nun ist es Zeit wieder zurück in die Arbeitswoche einzutauchen, bis zum nächsten Samstag.

Bis zum nächsten mal,

- Xaymar

Aller Anfang ist schwer ...

Sonntag, 12. November 2017 von Xaymar
... doch diesmal geht es etwas leichter, dank Sibly und der massiven Vorarbeit die er/sie geleistet hat. Fangen wir doch erstmal mit dem grundlegenden Fragen an:

Was ist BlitzLLVM?
BlitzLLVM ist ein Projekt um die Blitz-Sprache auf LLVM kompilieren zu lassen und somit massiv bessere Performance und Plattform-Unterstützung zu bringen. Wer hier schon länger mit Blitz arbeitet hat sicherlich das eine oder andere ähnliche Projekt mitangesehen, welches heute schon längst wieder verstorben ist.

Unglücklicherweise kann ich nicht versprechen, dass das Projekt nicht auch irgendwann eingestampft wird. Es ist für mich nur ein Lernprojekt mit dem ich LLVM, Vulkan und eine noch unbestimmte Audiobibliothek lernen will.

Wie wird BlitzLLVM funktionieren?
Es wird sehr ähnlich funktionieren wie wir es bereits von BlitzBasic gewöhnt sind: Man kompiliert und daraus kommt dann ein ausführbares Format. Der größte Unterschied ist das die 2D/3D/Plus Funktionen nicht mehr im Compiler selbst sind, sondern als Benutzerbibliothek hinzugefügt werden.

Dies hat gleich mehrere Vorteile:
  • Die Funktionalität und Stabilität ist nicht so stark vom Compiler abhängig.
  • Es können verschiedene Versionen der Funktionen getestet werden ohne neu kompilieren zu müssen.
  • Man kann ohne Probleme sich eigene Versionen dieser Funktionen schreiben. (Irrlicht, Ogre3D, usw.)
  • Und es werden drastisch kleinere ausführbare Dateien erzeugt.


Was ist das Ziel?
Für den Anfang ist das Ziel die Umsetzung der Blitz-Sprache in LLVM code, so das der LLVM Compiler dieses in ein ausführbares Format umsetzt. Sofern dies geschehen ist kommen neue Ziele hinzu:

  1. Unterstützung für Benutzerbibliotheken
  2. Erstellen der Benutzerbibliotheken für:
    1. Eingabe
    2. Audio
    3. 2D/3D
    4. Plus/GUI
    5. Netzwerk
    6. Physik
  3. Hinzufügen weiterer Funktionalität, wie Funktionspointer, Variablenpointer, Threading, usw.


Wie weit ist das Projekt bereits?
Das Projekt ist derzeit noch in den Anfangsphasen, wo nur geplant und das grundlegende umgesetzt wird. Da ich nur Samstags und Sonntags daran arbeiten kann (und ich da oft was anderes tue) wird das Projekt eher langsam voran gehen.

Ist es Open Source?
Ja! Den Quellcode könnt ihr auf GitHub finden: https://github.com/Xaymar/BlitzLLVM

Unter welcher Lizenz wird das Projekt erstellt?
Das Projekt inklusive der eingebundenen Benutzerbibliotheken ist unter der GPLv3 Lizenz. Für kommerzielle Projekte bei denen der eigene Quellcode nicht verfügbar sein soll muss also vorher eine andere Lizenz mit mir ausgehandelt werden.

Wie testest du BlitzLLVM?
Am Anfang hetze ich BlitzLLVM auf eine simple BB Datei die einfach nur alle Standardbefehle und Funktionen durch geht, prüfe dann den generierten LLVM code und, sollte er falsch sein, korrigiere den Parser/Lexer. Danach geht es mit dem Testen in schwierigere Bereiche.

Der größte Test wird es Stranded II (von DarkCorner/DC) und Sirius Online (von vektorDex/vDex) zum laufen zu bringen. Sirius Online wird dabei mehr ein technisches Problem werden, da ich daran selbst gearbeitet habe und einiges im Speicher rumpfusche, wodurch halt auch BlitzNext enstanden war.

Nachwort
Damit wäre hoffentlich der Großteil erklärt. Ich beantworte gerne weitere Fragen in den Kommentaren oder im IRC (#basic).

Bis dahin,

- Xaymar