Dies ist ein Nebenprojekt von
jBB. Es soll die
jBB Programmierung erleichtern.
Da viele JavaScript meiden weil es kompliziert erscheint oder als "hässlich" eingestuft wird, habe ich angefangen einen Konverter zu schreiben. Dieser kann leider nicht BMax oder BB Code konvertieren, auch wenn "Q" recht ähnlich aussieht. "Q" ist eine Mischung aus BB und BlitzMax und das einzige Programm dass der Konverter derzeit umsetzen kann sieht so aus:
Code: Alles auswählen
Global myImage = LoadImage("media/pointer.png")
' "As INIT" definiert diese Funktion als Initialisierungsfunktion
Function myInit() As INIT
Graphics 800, 600, 30
SetColor 255, 255, 255
ClsColor 90, 120, 200
HidePointer
End Function
' "As MAIN" definiert diese Funktion als Hauptfunktion
Function myGame() As MAIN
Cls
Local mx = MouseX()
Local my = MouseY()
DrawImage myImage, mx, my
End Function
rem
Diese Funktion ist frei und wird von der Hauptfunktion,
oder einer Funktion welche die Hauptfunktion aufruft,
aufgerufen
end rem
Function Test(x:Int, y:Int, val:String = "Hallo:Welt")
End Function
... daraus macht der Konverter folgendes:
Code: Alles auswählen
<!DOCTYPE html>
<html>
<head>
<title>Hallo Welt</title>
<script type='text/javascript' src='js/jbb.js'></script>
<script type='text/javascript'>
var myImage = LoadImage("media/pointer.png");
function myInit(){
Graphics('jBBGame', myGame, 30);
SetColor(255, 255, 255);
ClsColor(90, 120, 200);
HidePointer();
};
function myGame(){
Cls();
var mx = MouseX();
var my = MouseY();
DrawImage(myImage, mx, my);
};
function Test(x, y, val){
};
</script>
</head>
<body onLoad='myInit();'>
<canvas id='jBBGame' width='800' height='600'>
Sorry, your browser doesn't support Canvas.
</canvas>
</body>
</html>
Dieses Beispiel kann man sich
hier live anschauen.
Das Tool wird über die Konsole (Terminal) gestartet und erwartet zumindest den Parameter "file=meinFetterQCode"
Alles in Allem sind derzeit folgende Parameter für den Konverter definiert:
- file - definiert die Datei die konvertiert werden soll (muss angegeben werden!)
- output - wie heißt die Datei die erzeugt werden soll (".html" wird automatisch angefügt)
- strict - bewirkt derzeit noch nichts, in Zukunft werden bei strict = 1 alle Parameter eines Funktionsaufrufs auf ihren korrekten Typ hin überprüft.
- sitetitle - definiert den Titel der HTML Seite die erzeugt wird
- tabsize - gibt an mit wievielen Tabs eingerückt wird, voreingestellt ist 1 Tab
- waitforres - wird diesem Parameter 1 übergeben wartet das JS Programm in LoadImage() und LoadSound() solange bis die entsprechende Resource geladen wurde. Ich empfehle das sein zu lassen
- jbbsource - definiert von wo das Programm jBB einbinden soll. Default ist "js/jbb.js"
- nocanvas - definiert die Meldung die ausgegeben werden soll wenn der Browser das HTML5 Canvas nicht unterstützt.
Alle diese Daten haben Default-Werte, einzig "file" muss angegeben werden damit der Konverter weiß was er laden und konvertieren soll.
Beispiel:
Code: Alles auswählen
jbbconv file=test.jbb output=index.html sitetitle="Mein fettes HTML5 Game"
Wer StarTrek:TNG kennt wird wissen warum ich die "Sprache" (eigentlich ist es ja keine, der Source wird extrem naiv umgewandelt) "Q" genannt habe ;)
Hier der BMax Source des Konverters:
Code: Alles auswählen
SuperStrict
Framework brl.filesystem
Import brl.retro
Import brl.linkedlist
Const FUNC_TYPE_CUSTOM:Int = 0
Const FUNC_TYPE_INIT:Int = 1
Const FUNC_TYPE_MAIN:Int = 2
Type tParameter
Field parName:String
Field parType:String
Field parDefault: String
Method setName(pName:String)
Self.parName = pName
End Method
Method setType(pType:String)
Self.parType = pType
End Method
Method setDefault(pDefault:String)
Self.parDefault = pDefault
End Method
End Type
Type tFunction
Global _list:TList
Field funcName:String
Field funcType:Int
Field parameters:TList
Field source:TList
Method New()
If Self._list = Null Then Self._list = New TList
Self._list.AddLast(Self)
Self.parameters = New TList
Self.source = New TList
Self.funcType = FUNC_TYPE_CUSTOM
End Method
Method setName(fName:String)
Self.funcName = fName
End Method
Method setType(fType:Int)
Self.funcType = fType
End Method
Method addParameter(par:String, pType:String = "", pDefault:String = "")
Local p:tParameter = New tParameter
p.setName(par)
p.setType(pType)
p.setDefault(pDefault)
Self.parameters.AddLast(p)
End Method
Method addSourceLine(sourceLine:String)
Self.source.AddLast(sourceLine)
End Method
End Type
Global functions:tFunction
Type tGlobal
Global _list:TList
Field v:String
Field val:String
Function addGlobal(variable:String, value:String)
Local g:tGlobal = New tGlobal
If g._list = Null Then g._list = New TList
g.v = variable
g.val = value
g._list.AddLast(g)
End Function
End Type
' pruefen ob eine Datei uebergeben wurde
If AppArgs.length <= 1 Then QuitMessage("Nichts zum uebersetzen...")
Global strictMode:Byte = False
Global siteTitle:String = "jBB"
Global tabSize:Int = 1
Global tab:String = ""
Global inFile:String = ""
Global outFile:String = "output.html"
Global waitForRes:Byte = False
Global jBBSource:String = "js/jbb.js"
Global jBBWidth:Int = 800
Global jBBHeight:Int = 600
Global jBBSpeed:Int = 30
Global jBBCanvasID:String = "jBBGame"
Global jBBInitFunc:String = ""
Global jBBMainFunc:String = ""
Global noCanvasMessage:String = "Sorry, your browser doesn't support Canvas."
' weitere Argumente iterieren
For Local i:Int = 1 To AppArgs.length - 1
Local args:String[] = AppArgs[i].split("=")
Select args[0].toLower()
Case "file" ; inFile = args[1].Trim();
Case "output" ; outFile = args[1].Trim()
Case "strict" ; If args[1].Trim() = "1" Then strictMode = True;
Case "sitetitle" ; siteTitle = args[1].Trim()
Case "tabsize" ; tabSize = Int(args[1])
Case "waitforres" ; If args[1].Trim() = "1" Then waitForRes = True;
Case "jbbsource" ; jBBSource = args[1].Trim()
Case "width" ; jBBWidth = Int(args[1].Trim())
Case "height" ; jBBHeight = Int(args[1].Trim())
Case "fps" ; jBBSpeed = Int(args[1].Trim())
Case "canvasid" ; jBBCanvasID = args[1].Trim()
Case "nocanvas" ; noCanvasMessage = args[1].Trim()
End Select
Next
' TabSize setzen
For Local t:Int = 1 To tabSize
tab:+ Chr(9)
Next
If Not Instr(inFile, "/") Or Not Instr(inFile, "\") Then inFile = CurrentDir() + "/" + inFile
If FileType(inFile) <> 1 Then quitMessage("Die Eingabedatei kann nicht gelesen werden.")
' Ausgabedatei
If ExtractExt(outFile) <> "html" Then outFile:+ ".html"
Local ostream:TStream = WriteFile(outFile)
Local rest:String = ""
Local pos:Int = 0
Local fName:String = ""
Local pars:String = ""
If(ostream)
' Datei einlesen
Local stream:TStream = ReadFile(inFile)
If stream
While Not stream.Eof()
Local in:String = stream.ReadLine().Trim()
' einzeiliger Kommentar
If Left(in, 1) = "'" Then in = ""
' Kommentar am Ende der Zeile
Local comment:Int = Instr(in, "'")
If comment Then in = Left(in, comment - 1)
' mehrzeiliger Kommentar
If Left(in, 3).toLower() = "rem"
Repeat
in = stream.ReadLine().Trim()
Until Left(in, 6) = "endrem" Or Left(in, 7) = "end rem"
in = ""
EndIf
If in.length > 0
' globale Variable
If Left(in, 6).toLower() = "global"
Local rest:String = Right(in, in.length - 6).Trim()
Local parts:String[] = rest.split("=")
Local v:String = parts[0]
Local func:String = ""
If Left(parts[1].toLower().Trim(), 9) = "loadimage" Then func = parts[1] + ";"
If func = "" Then func = parts[1] + ";"
tGlobal.addGlobal(v, func)
EndIf
' Funktion hinzufügen
If Left(in, 8).toLower() = "function"
functions = New tFunction
' Funktionsnamen lesen
rest = Right(in, in.length - 8).Trim()
pos = Instr(rest, "(")
functions.setName(Left(rest, pos - 1).Trim())
' Parameterliste lesen
rest = Right(rest, rest.length - pos).Trim()
pos = Instr(rest, ")")
pars = Left(rest, pos - 1).Trim()
Local par:String[] = pars.split(",")
For Local a:String = EachIn par
Local pName:String = ""
Local pTyp:String = ""
Local pDef:String = ""
' auf Typisierung pruefen
If Instr(a, ":")
Local pt:String[] = a.split(":")
pName = pt[0].Trim()
pos = Instr(pt[1], "=")
If pos
pTyp = Left(pt[1], pos - 1).Trim()
Else
pTyp = pt[1].Trim()
EndIf
Else
pName = a.Trim()
EndIf
' auf Default pruefen
If Instr(a, "=")
Local pd:String[] = a.split("=")
pDef = pd[1].Trim()
EndIf
functions.addParameter(pName, pTyp, pDef)
Next
' evtl. Postdefs lesen
rest = Right(rest, rest.length - pos).Trim()
If Left(rest, 2).toLower() = "as"
rest = Right(rest, rest.length - 2).Trim()
Select rest.toLower()
Case "init"; functions.setType(FUNC_TYPE_INIT); jBBInitFunc = functions.funcName
Case "main"; functions.setType(FUNC_TYPE_MAIN); jBBMainFunc = functions.funcName
End Select
EndIf
' Rumpf lesen
Repeat
in = stream.ReadLine().Trim()
If in.toLower().Trim() <> "end function" And in.toLower().Trim() <> "endfunction"
functions.addSourceLine(in)
EndIf
Until in.toLower().Trim() = "end function" Or in.toLower().Trim() = "endfunction"
End If
EndIf
Wend
stream.Close()
'Header schreiben
ostream.WriteLine("<!DOCTYPE html>")
ostream.WriteLine("<html>")
ostream.WriteLine("<head>")
ostream.WriteLine(tab + "<title>" + siteTitle + "</title>")
ostream.WriteLine(tab + "<script type='text/javascript' src='" + jBBSource + "'></script>")
ostream.WriteLine(tab + "<script type='text/javascript'>")
For Local g:tGlobal = EachIn tGlobal._list
ostream.WriteLine(tab + tab + "var " + g.v + " = " + g.val)
Next
ostream.WriteLine("")
For Local f:tFunction = EachIn tFunction._list
' Funktionskopf
Local l:String = "function " + f.funcName + "("
For Local p:tParameter = EachIn f.parameters
l:+ p.parName + ", "
Next
l = Left(l, l.length - 2)
l:+ "){"
ostream.WriteLine(tab + tab + l)
' Funktionskoerper
For Local c:String = EachIn f.source
'------------------------------------------------------
' Graphics
If Left(c.toLower(), 8) = "graphics"
Replace(c, "(", " "); Replace(c, ")", "")
rest = Right(c, c.length - 9)
Local p:String[] = rest.Split(",")
If p.length = 1 Then jBBWidth = Int(p[0])
If p.length = 2 Then jBBHeight = Int(p[1])
If p.length = 3 Then jBBSpeed = Int(p[2])
ostream.WriteLine(tab + tab + tab + "Graphics('" + jBBCanvasID + "', " + jBBMainFunc + ", " + jBBSpeed + ");")
EndIf
'------------------------------------------------------
' SetColor
If Left(c.toLower(), 8) = "setcolor"
Local tmp:String[] = splitFunctionCall(c, "setcolor")
Local c:Int[] = [0, 0, 0]
Local z:Int = 0
For Local i:String = EachIn tmp
c[z] = Int(i); z:+ 1
Next
ostream.WriteLine(tab + tab + tab + "SetColor(" + c[0] + ", " + c[1] + ", " + c[2] + ");")
EndIf
'------------------------------------------------------
' ClsColor
If Left(c.toLower(), 8) = "clscolor"
Local tmp:String[] = splitFunctionCall(c, "clscolor")
Local c:Int[] = [0, 0, 0]
Local z:Int = 0
For Local i:String = EachIn tmp
c[z] = Int(i); z:+ 1
Next
ostream.WriteLine(tab + tab + tab + "ClsColor(" + c[0] + ", " + c[1] + ", " + c[2] + ");")
EndIf
'------------------------------------------------------
' Cls
If c.length < 6 And Left(c.toLower(), 3) = "cls"
ostream.WriteLine(tab + tab + tab + "Cls();")
EndIf
'------------------------------------------------------
' Local
If Left(c.toLower(), 5) = "local"
Local varName:String = ""
Local varProc:String = ""
Local rest:String = Right(c, c.length - 5).Trim()
Local pos:Int = Instr(rest, " ")
varName = Left(rest, pos - 1)
Local f:String = Right(rest, rest.length - (pos + 1)).Trim()
Select f.toLower()
Case "mousex()" ; varProc = "MouseX();"
Case "mousey()" ; varProc = "MouseY();"
Default ; varProc = f + ";"
End Select
ostream.WriteLine(tab + tab + tab + "var " + varName + " = " + varProc)
EndIf
'------------------------------------------------------
' DrawImage
If Left(c.toLower(), 9) = "drawimage"
Replace(c, "(", " "); Replace(c, ")", "")
Local rest:String = Right(c, c.length - 9).Trim()
ostream.WriteLine(tab + tab + tab + "DrawImage(" + rest + ");")
EndIf
'------------------------------------------------------
' HidePointer
If Left(c.toLower(), 11) = "hidepointer" Then ostream.WriteLine(tab + tab + tab + "HidePointer();")
'------------------------------------------------------
' ShowPointer
If Left(c.toLower(), 11) = "showpointer" Then ostream.WriteLine(tab + tab + tab + "ShowPointer();")
'ostream.WriteLine(tab + tab + tab + c)
Next
'abschliessen
ostream.WriteLine(tab + tab + "};")
ostream.WriteLine("")
Next
ostream.WriteLine(tab + "</script>")
ostream.WriteLine("</head>")
ostream.WriteLine("<body onLoad='" + jBBInitFunc + "();'>")
ostream.WriteLine(tab + "<canvas id='" + jBBCanvasID + "' width='" + jBBWidth + "' height='" + jBBHeight + "'>")
ostream.WriteLine(tab + tab + noCanvasMessage)
ostream.WriteLine(tab + "</canvas>")
ostream.WriteLine("</body>")
ostream.WriteLine("</html>")
ostream.Close()
Else
QuitMessage(inFile + " kann nicht gelesen werden.")
EndIf
Else
QuitMessage(outFile + " kann nicht geschrieben werden.")
EndIf
Function QuitMessage(msg:String)
WriteStdout("> " + msg + "~n")
End
End Function
Function splitFunctionCall:String[](in:String, funcName:String)
in = Replace(in, "(", " ")
in = Replace(in, ")", " ")
Local tmp:String = Right(in, in.length - funcName.length)
Local pars:String[] = tmp.Split(",")
Return pars
End Function