Q

Kommentare anzeigen Worklog abonnieren

Worklogs Q

Orks im Quelltext

Freitag, 25. März 2011 von Farbfinsternis
Es gibt immer wieder Sachen die man beachten muss welche eigentlich Blödsinn sind, die aber dennoch nicht verboten werden sollten. Beispielsweise ein "Then" am Ende einer Zeile ... Dieses wird nun von Q ignoriert, Ihr dürft es also weiterhin sinnfrei an einen mehrzeiligen Vergleich hängen.

Eine Änderung gibt es bei den Types. Das Schlüsselwort für eine Methode heisst nun nicht mehr "Method" sondern "Function". Da ich Types nach "var myType = function(){" übersetze ist ohnehin jede Methode global.

Desweiteren werden nun auch nicht deklarierte Variablen und Funktionen erkannt und als Fehler bei Benutzung ausgegeben.

Um möglichst viele Syntaxfehler zu erkennen und um die Quelle bestmöglichst zu übersetzen habe ich nun Stacks für Variablen, Funktionen, Types und Type-Methoden eingeführt. Auf der Strecke geblieben ist der lesbare JavaScript Code. Der wird nun so erzeugt dass er funktioniert und gut komprimierbar ist, wer lesbaren JS Code benötigt darf jBB gern direkt verwenden.

Alles in Allem ist ein Release noch nicht in Sicht. Erst wenn auch die komplexeste und die bekloppteste Zeile interpretiert oder ignoriert wird, wird es ein Release geben.

If funktioniertNicht = True Then crap = True

Montag, 21. März 2011 von Farbfinsternis
Ich habe noch ein paar Probleme mit den Vergleichen. Es ist echt irre wieviele KOmbinationen man mit Basic erzeugen kann.

Folgendes Programm...
BlitzMax: [AUSKLAPPEN]
rem
Q Script
Mauszeiger im Canvas
endrem


Public pointer = LoadImage("media/pointer.png")

Function Init() As INIT
Graphics(800, 600)
ClsColor(90, 120, 200)
HidePointer()
EndFunction

Function Game() As Main
Cls()

Public mx = MouseX()
Public my = MouseY()

DrawImage(pointer, mx, my)

If mx > 400 Then
DrawText("Halbzeit", mx, my)
EndIf
EndFunction


... erzeugt z.Z. diese Ausgabe ...
Code: [AUSKLAPPEN]
<!DOCTYPE html>

<head>

   <title>Hallo Welt</title>

   <script type='text/javascript' src='http://www.sedm.de/jbb/js/jbb.js'></script>

   <script type='text/javascript'>

var pointer=LoadImage("media/pointer.png");

function Init(){   

Graphics("jBBCanvas", Game, 30);

   ClsColor(90,120,200);

   HidePointer();

};

function Game(){   

   Cls();

   var mx=MouseX();

   var my=MouseY();

   DrawImage(pointer,mx,my);

   if(mx>400)  ;

      DrawText("Halbzeit",mx,my);

   }

};

   </script>

</head>

<body onLoad="Init();">

<canvas id='jBBCanvas' width='800' height='600' oncontextmenu="return false;">

   Sorry, your browser doesn't support HTML5 Canvas.

</canvas>

</body>

</html>


Wie man sieht ist der "If Block" jetzt nicht so ganz richtig umgesetzt. Aber wo ein Problem ist lauert auch schon irgendwo die Lösung.

Desweiteren sieht man am obigen Q Script dass sich das Variablen Handling leicht von BMax unterscheidet. Prinzipiell ist eine Variable immer global (public). Nur in Types kann man bestimmen dass eine Variable privat (private) ist und nur Methoden eines Types darauf zugreifen können. In "Objects" ist es vollkommen egal ob man eine Variable als "private" oder "public" definiert, in "Objects" sind Variablen immer öffentlich.

Zudem funktionieren nun endlich Default-Werte für Funktionen und Methoden zuverlässig. Leider läuft das ableiten von Klassen noch nicht, aber auch das ist nur eine Baustelle die es zu beackern gilt.

Zielgerade

Donnerstag, 17. März 2011 von Farbfinsternis
Mittlerweile werden ca. 90% eines Q Programms nach JavaScript übersetzt. Im letzten Eintrag habe ich (nach erneutem Lesen) den Unterschied zwischen "Type" und "Object" nur unzureichend beschrieben. Lasst mich das jetzt nachholen.

Während man von einem Type beliebig viele Instanzen erzeugen kann, ist ein Object statisch. Man kann nicht mittels "new" eine Instanz von diesem Objekt bilden. Es ist sozusagen die Konstante unter den Klassen. Vorteil ist zum einen dass Objects wesentlich schneller sind als Types, und zum Anderen dass man sie ohne Umwege direkt per Ajax an externe Scripts schicken kann. Zu diesem Zweck ist bereits das AddOn "jBBAjax" in Arbeit, dieses verwendet jedoch jQuery als Grundlage.
Wie, wann und warum sollte man also ein Object anstelle eines Types verwenden?

Erstens: Wenn Du weißt dass Du nur eine einzige Instanz eines Types benötigen wirst, solltest Du ein Object verwenden ...

Zweitens: Wenn Du objektorientiert per Ajax mit einem Server kommunizieren willst solltest Du ein Object verwenden

Ein Object wird mit "Object [nameDesObjekts]" definiert (Objekte können nicht deklariert werden, sie sind mit ihrem Erscheinen definiert) und mit "EndObject" geschlossen. Der Zugriff auf die Eigenschaften und Methoden erfolgt dann über "[nameDesObjekts].Eigenschaft/Methode"

Beispiel:
Code: [AUSKLAPPEN]

Object myObject
    Local x = 0
    Local y = 0

    Function inkX()
        x++
    EndFunction

    Function inkY()
        y++
    EndFunction
EndObject

myObject.inkX()


Ich hoffe die Objekt-Geschichte nun einigermaßen klarer gemacht zu haben Wink

Funktionen, Methoden, Datentypen

Mittwoch, 16. März 2011 von Farbfinsternis
Mittlerweile werden schon weite Teile eines Q Programms übersetzt und viele mögliche Syntax-Fehler werden erkannt und ausgegeben. Für das Parsen von Funktionen und Methoden wird nun dieselbe Methode in der Klasse "TQ" verwendet. Ein weiteres Detail ist die Tatsache dass Datentypen für Variablen nun gesichert werden. Da Q typenlos ist (im Moment) werden diese nur erkannt und gesichert, aber noch nicht verwendet. Um Q mit Datentypen auszustatten muss der erzeugte JavaScript Code erheblich erweitert werden und es muss wesentlich defiziler ge-parsed werden als dies derzeit der Fall ist.

Die jetzt implementierten Datentypen sind experimentell und bewirken noch absolut gar nichts, sie sehen aber aus wie von BlitzMax bekannt:
BlitzMax: [AUSKLAPPEN]
Function myFunc(x:Int = 0, y:Int = 0, line:String = "Hello World")


Default-Werte für Funktionsparameter funktionieren bereit hervorragend (soetwas gibt es in JavaScript nicht).

Neu ist die Möglichkeit JSON Objekte aus JavaScript in Q zu nutzen:
Code: [AUSKLAPPEN]

Object myObject
    x = 10
    y = 20

    Function myFunc()
        DrawText("Hallo Welt", Self.x, Self.y)
    EndFunction
EndObject

Der Unterschied zwischen einem Object und einem Type ist dass für ein Object kein "Extends" existiert und das man Objects direkt an PHP schicken kann um dort die Daten auszuwerten.

Ich hoffe noch in dieser Woche ein Release bringen zu können ... bis dahin: have fun with jBB Wink

Mehr Passes

Dienstag, 15. März 2011 von Farbfinsternis
Es hat nicht genügt einen Source in zwei Passes zu analysieren. Außerdem habe ich den Automatismus entfernt der ablief sobald ich das Objekt "TQ" initialisiert hatte, stattdessen wird nun jeder Pass im Hauptprogramm aufgerufen. Das hat jetzt keine programmatischen Gründe, sondern wurde notwendig weil mir hier unter Linux nur die Standard IDE zur Verfügung steht und diese eigentlich völlig ungeeignet ist um mehr damit zu machen als einen Brief an die Oma zu schreiben.

Im ersten Pass werden Kommentare und Leerzeilen entfernt, es werden eindeutige Bezeichner bereits umgewandelt weil sie allein auf einer Zeile stehen müssen (EndIf, Wend, EndFunction, EndMethod, etc.) und Ausdrücke die durch ein Semikolon (";") getrennt auf einer Zeile stehen werden auf mehrere Zeilen verteilt.
Letzterer Fall wird zuerst durchgeführt so dass ein "While a == 1; b++; Wend" auch weiterhin funktioniert.

Der zweite Pass prüft ob grobe Syntax-Fehler vorliegen. Bspw. die Definition einer Funktion ohne Klammern, oder das Fehlen der "INIT" und/oder der "MAIN" Funktionen.

Der dritte Pass parsed jede einzelne Zeile und prüft dabei ob Schlüsselworte oder jBB-Funktionen vorliegen. Ist dies der Fall werden diese aufgeteilt und eine neue Zeile erzeugt die dem JS Syntax entspricht.

Desweiteren gab es Spezialfälle in denen ich Code doppelt hatte. So glich der Code eine Methode zu parsen dem eine Funktion zu parsen so sehr dass ich diese Fälle zusammen gefasst habe. Funktionen, Types und Methoden werden nun von derselben Methode behandelt (der globale State ist nur anders) um doppelten Code zu vermeiden.

Letzte Neuerung ist die Tatsache dass ich nun jede Zeile aufteile und nachschaue was passiert, auch wenn keine Q oder jBB Funktionen enthalten sind. Dies soll eine genauere Syntax Prüfung ermöglichen um mehr Fehler abzufangen.

Da ich keinen Compiler baue sondern nur einen MetaCompiler, ist es mir derzeit unmöglich Kontext-Fehler zu entdecken. Zwar kann ich meckern wenn eine Funktion in einer Funktion definiert wird, oder das eine Klammer fehlt ... aber wenn irgendwo eine Variable ohne vorherige Deklaration eingeführt wird geht das völlig unter. Eventuell baue ich noch einen Stack ein der es mir gestattet derartige Dinge zu entdecken. Auch eine Funktion ohne EndFunction wird nicht entdeckt.

Es gab einige Zeit eine Diskussion darüber ob es möglich wäre BMax Code nach jBB zu konvertieren. Mit Q wäre das prinzipiell möglich. Es müsste die Init- und die Main-Funktion entsprechend gekennzeichnet werden. Erste Idee wäre es dies über einen Kommentar zu tun:
BlitzMax: [AUSKLAPPEN]
Function myFunc() ' As Init

Das immer noch bestehende Problem ist aber dass nicht jeder beliebige BMax Code konvertiert werden kann weil jBB viele Dinge nicht unterstützt oder Dinge anders gehandhabt werden. Allein ein Array zu erzeugen sieht in jBB völlig anders aus als in BMax und Q folgt JavaScript und nicht BMax.

Aber gut. Q trennt jBB von JS und vielleicht lassen sich Lösungen finden um Q weiter an BMax anzunähern.

Das Q Karussell

Montag, 14. März 2011 von Farbfinsternis
Bei Q handelt es sich um eine Meta-Sprache welche nach HTML/JavaScript übersetzt wird. Die Ausgabedatei(en) greifen dann auf das JavaScript Framework jBB zu. So ermöglicht Q das Programmieren von Browsergames auf Basis des HTML5 Canvas Element, ohne direkt JavaScript verwenden zu müssen. Ein Q Source ähnelt sehr dem von BlitzMax:
BlitzMax: [AUSKLAPPEN]

Global myImage = LoadImage("media/pointer.png")

rem
eine Klasse
endrem

Type tType
Field x
Field y

Method getX()
Return x
EndMethod
EndType

Global mouseCoords = New tType

' "As INIT" definiert diese Funktion als Initialisierungsfunktion
Function myInit() As INIT
Graphics(800, 600, 30); SetColor(255, 255, 255); ClsColor(90, 120, 200)
HidePointer()
EndFunction

' "As MAIN" definiert diese Funktion als Hauptfunktion
Function myGame() As Main
Cls()

mouseCoords.x = MouseX()
mouseCoords.y = MouseY()

DrawImage(myImage, mouseCoords.getX(), mouseCoords.y ) ' Bild zeichnen

EndFunction

Der Q Transformer (ich mag ihn nicht Compiler nennen) ist in BlitzMax programmiert, ich werde ihn für Linux und Windows bereitstellen. Den Source werde ich bei Release beilegen so dass Interessierte sich das Programm auch für MacOS kompilieren können.

--------------------------------

Die Methode "Brute Force" funktioniert zwar am Ende, aber sie lässt den Quelltext quasi explodieren. Die Möglichkeit beliebig viele Leerzeichen zu setzen und auch Tabs einfach mal so zu spammen habe ich nun im Griff und normale Funktionen, Methoden und Types kommen nun damit klar. Auch Default-Werte für Funktionsparameter werden nun ordentlich in funktionierenden JavaScript Code umgewandelt.
Types werden nach "var FunktionsName = function(" umgebaut und Methoden nach "this.MethodenName = function(){". Derzeit gibt es noch keine Konstruktor-Parameter für Types aber ich will das unbedingt haben weil es mich schon immer gestört hat dass BMax diese nicht unterstützt.
Weiterhin werden nun jBB Funktionen korrekt umgesetzt und Q ist nicht mehr case-sensitive. Mittlerweile gibt der Compiler auch Fehler aus wenn er Syntax-Fehler findet, aber das ist noch sehr rudimentär. Das Problem ist wohl dass ich hier keinen klassischen Compiler/Interpreter baue (das ist mir viel zu kompliziert), sondern nur einen Quelltext in einen anderen überführe.

    Noch ein paar Sachen zu Q:
  • Q ist Typenlos ... man kann der Variable "t" ein "3.14" zuweisen, oder ein "1" oder ein "Hallo Welt"
  • in Q heißt es "EndFunction", "EndType", "EndMethod", "EndIf" etc ... ein "End Function" wird als Fehler angesehen
  • Q ist nicht case-sensitive was jBB oder Q Funktionen betrifft. Das heißt: Du kannst schreiben "endif" oder "EndIf", oder "eNdIf" ... spielt keine Rolle ... aber Deine eigenen Variablen oder Funktionen müssen exakt so geschrieben werden wie die definiert wurden. Hast Du also die Funktion "doSomething" erstellt, darfst Du sie nicht mit "dosomething" aufrufen. Gleiches gilt für Variablen. Es ist natürlich möglich dass diese Beschränkung in einer späteren Version von Q entfernt wird.
  • Q soll einmal Vererbung unterstützen. Derzeit ist dieses Feature nicht implementiert, auch wenn der Interpreter ein "extends" bereits verarbeitet.
  • Q ist ausschliesslich für jBB gedacht, deshalb gibt es das Schlüsselwort "AS" welches einer beliebigen Funktionsdefinition angefügt wird. "As" definiert eine Funktion als Initialisierungsfunktion oder als Hauptfunktion. Soll eine Funktion als "Init" dienen fügt man dem Funktionskopf "As Init" hinzu. Ist die Funktion als Hauptfunktion gedacht schreibt man "As Main" ... Beispiel: "Function myMain() As Main"
  • Q übernimmt klassische Operatoren. Ein "==" ist ein Vergleich, ein "=" ist eine Zuweisung. Die Operatoren "And", "Or" etc. werden von Q in die JavaScript Äquivalente übersetzt. Beispiel: "If a = 1" wird nicht prüfen ob a = 1 ist sondern a den Wert 1 zuweisen, nur "If a == 1" wird prüfen ob a = 1 ist.
  • Der Q "Compiler" wird über die Konsole/das Terminal bedient. Mindestens die Parameter "file" und "output" müssen übergeben werden, für alle anderen Parameter existieren Default-Werte.

Es gibt noch irre viel Arbeit ... wer nicht auf Q warten will kann sich ja mit JS beschäftigen solange direkt mit jBB arbeiten Wink Have Fun!

Links:
- jBB Framework
- jBB Community Forum