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:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Global myImage = LoadImage("media/pointer.png")
Function myInit() As INIT Graphics 800, 600, 30 SetColor 255, 255, 255 ClsColor 90, 120, 200 HidePointer End Function
Function myGame() As Main Cls Local mx = MouseX() Local my = MouseY() DrawImage myImage, mx, my End Function
Function Test(x:Int, y:Int, val:String = "Hallo:Welt")
End Function
... daraus macht der Konverter folgendes:
Code: [AUSKLAPPEN] [EINKLAPPEN]
<!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: [AUSKLAPPEN] [EINKLAPPEN] 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:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] 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
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."
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
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.")
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) Local stream:TStream = ReadFile(inFile) If stream While Not stream.Eof() Local in:String = stream.ReadLine().Trim() If Left(in, 1) = "'" Then in = "" Local comment:Int = Instr(in, "'") If comment Then in = Left(in, comment - 1) 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 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 If Left(in, 8).toLower() = "function" functions = New tFunction rest = Right(in, in.length - 8).Trim() pos = Instr(rest, "(") functions.setName(Left(rest, pos - 1).Trim()) 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 = "" 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 If Instr(a, "=") Local pd:String[] = a.split("=") pDef = pd[1].Trim() EndIf functions.addParameter(pName, pTyp, pDef) Next 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 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() 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 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) For Local c:String = EachIn f.source 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 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 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 If c.length < 6 And Left(c.toLower(), 3) = "cls" ostream.WriteLine(tab + tab + tab + "Cls();") EndIf 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 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 If Left(c.toLower(), 11) = "hidepointer" Then ostream.WriteLine(tab + tab + tab + "HidePointer();") If Left(c.toLower(), 11) = "showpointer" Then ostream.WriteLine(tab + tab + tab + "ShowPointer();") Next 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
|