[bmx] BlitzMax to Java 2.0 by Matt Merkulov [ 1+ years ago ]

Started by BlitzBot, June 29, 2017, 00:28:38

Previous topic - Next topic

BlitzBot

Title : BlitzMax to Java 2.0
Author : Matt Merkulov
Posted : 1+ years ago

Description : Most of converting work will be done by this program, but after it some point manual changements should be done anyway. Requires regular expressions module by Brucey.

Code :
Code (blitzmax) Select
SuperStrict

Import bah.regex


Type TClass
Global Classes:TMap = New TMap

Field ID:String
Field Package:String
Field Name:String

Function Create:TClass( Package:String, Name:String )
Local Class:TClass = New TClass
Classes.Insert( Name.ToLower(), Class )

If Name.StartsWith( "LT" ) Then Name = Name[ 2.. ]
If Name.StartsWith( "T" ) And Name.Length > 1 Then
If Name[ 1 ] >= Asc( "A" ) And Name[ 1 ] <= Asc( "Z" ) Then Name = Name[ 1.. ]
End If
Name = Name[ 0..1 ].ToUpper() + Name[ 1.. ]

Class.Name = Name
Class.Package = Package
Return Class
End Function
End Type

TClass.Create( "java.lang", "System" )
TClass.Create( "java.lang", "Math" )
TClass.Create( "java.util", "LinkedList" )
TClass.Create( "java.util", "HashMap" )


Type TIdentifier
Global Identifiers:TMap = New TMap

Field Result:String
Field Class:TClass
End Type

For Local Pair:String[] = Eachin [ ..
[ "Byte", "byte" ], ..
[ "Short", "short" ], ..
[ "Int", "int" ], ..
[ "Long", "long" ], ..
[ "Float", "float" ], ..
[ "Double", "double" ], ..
[ "Object", "Object" ], ..
..
[ "And", "&&" ], ..
[ "Or", "||" ], ..
[ "Not", "!" ], ..
[ "Mod", "%" ], ..
..
[ "String", "String" ], ..
[ "Length", "length" ], ..
[ "Find", "indexOf" ], ..
[ "FindLast", "lastIndexOf" ], ..
[ "Trim", "trim" ], ..
[ "Replace", "replaceAll" ], ..
[ "StartsWith", "startsWith" ], ..
[ "EndsWith", "endsWith" ], ..
[ "Join", "indexOf" ], ..
[ "Split", "split" ], ..
[ "ToLower", "toLowerCase" ], ..
[ "ToUpper", "toUpperCase" ], ..
[ "Length", "length()" ], ..
..
[ "TList", "LinkedList", "linkedlist" ], ..
[ "IsEmpty", "isEmpty" ], ..
[ "Contains", "contains" ], ..
[ "AddFirst", "addFirst" ], ..
[ "AddLast", "addLast" ], ..
[ "First", "getFirst" ], ..
[ "Last", "getLast" ], ..
[ "Remove", "remove" ], ..
[ "RemoveFirst", "removeFirst" ], ..
[ "RemoveLast", "removeLast" ], ..
[ "Clear", "clear" ], ..
[ "ValueAtIndex", "get" ], ..
[ "ToArray", "toArray" ], ..
[ "Count", "size" ], ..
..
[ "TMap", "HashMap", "hashmap" ], ..
[ "ValueForKey", "get" ], ..
[ "Insert", "put" ], ..
[ "Keys", "keySet" ], ..
[ "Values", "values" ], ..
..
[ "Millisecs", "System.currentTimeMillis()", "system" ], ..
..
[ "Max", "Math.max", "math" ], ..
[ "Min", "Math.min", "math" ], ..
[ "Sin", "Math.sin", "math" ], ..
[ "Cos", "Math.cos", "math" ], ..
[ "Tan", "Math.tan", "math" ], ..
[ "ACos", "Math.acos", "math" ], ..
[ "ASin", "Math.asin", "math" ], ..
[ "ATan", "Math.atan", "math" ], ..
[ "ATan2", "Math.atan2", "math" ], ..
[ "Floor", "Math.floor", "math" ], ..
[ "Ceil", "Math.ceil", "math" ], ..
[ "Abs", "Math.abs", "math" ], ..
[ "Sqr", "Math.sqrt", "math" ], ..
[ "Log", "Math.log", "math" ], ..
[ "Exp", "Math.exp", "math" ], ..
[ "Rnd", "Math.random", "math" ], ..
[ "Pi", "PI", "math" ], ..
..
[ "True", "true" ], ..
[ "False", "false" ], ..
[ "Null", "null" ], ..
..
[ "Return", "return" ], ..
[ "Exit", "break" ], ..
[ "Super", "super" ], ..
[ "Self", "this" ], ..
[ "Extends", "extends" ], ..
[ "New", "new" ] ..
]
'[ "", "" ], ..

Local Identifier:TIdentifier = New TIdentifier
Identifier.Result = Pair[ 1 ]
If Pair.Length = 3 Then Identifier.Class = TClass( TClass.Classes.ValueForKey( Pair[ 2 ] ) )
TIdentifier.Identifiers.Insert( Pair[ 0 ].ToLower(), Identifier )
Next



Const Directory:String = "D: empsrc"

GetClassNames( Directory )
ProcessDirectory( Directory )

Function GetClassNames( DirName:String, Package:String = "" )
Local Dir:Int = ReadDir( DirName )
Repeat
Local FileName:String = NextFile( Dir )
If Not FileName Then Exit
If FileName = "." Or FileName = ".." Then Continue

Local FullFileName:String = DirName + "" + FileName
If FileType( FullFileName ) = FILETYPE_DIR Then
Local NewPackage:String
If Package Then NewPackage = Package + "." + FileName Else NewPackage = FileName
GetClassNames( FullFileName, NewPackage )
Continue
End If

If Not FileName.ToLower().EndsWith( ".bmx" ) Then Continue

DebugLog "Retrieving class names from " + FileName
Local File:TStream = ReadFile( FullFileName )
While Not Eof( File )
Local Line:String = ReadLine( File ).Trim()
If Line.ToLower().StartsWith( "type" ) Then
Line = Line[ 4.. ].Trim() + " "
TClass.Create( Package, Line[ ..Line.Find( " " ) ] )
End If
WEnd
Forever
End Function

Global FileClasses:TMap

Function ProcessDirectory( DirName:String, Start:Int = -1 )
If Start < 0 Then Start = DirName.Length

Local Dir:Int = ReadDir( DirName )
Repeat
Local FileName:String = NextFile( Dir )
If Not FileName Then Exit
If FileName = "." Or FileName = ".." Then Continue

Local FullFileName:String = DirName + "" + FileName
If FileType( FullFileName ) = FILETYPE_DIR Then
ProcessDirectory( FullFileName, Start )
Continue
End If

If Not FileName.ToLower().EndsWith( ".bmx" ) Then Continue

FileClasses = New TMap

DebugLog "Converting " + FileName
Local File:TStream = ReadFile( FullFileName )
Local Text:String = ""
Local RemBlock:Int = False
While Not Eof( File )
Local Line:String = ReadLine( File )
Local Trimmed:String = Line.ToLower().Trim()
If Trimmed.StartsWith( "?" ) Then Continue
if Text Then Text :+ "~n"
If RemBlock Then
If Trimmed = "endrem" or Trimmed = "end rem" Then
Text :+ TRegEx.Create( "^(( | )*)(EndRem|End Rem)" ).ReplaceAll( Line, "1 */" )
RemBlock = False
Else
Local N:Int = 0
Repeat
N = Line.Find( "#", N ) + 1
If N = 0 or N = Line.Length Then Exit
Line = Line[ ..N ] + Chr( Line[ N ] ).ToLower() + Line [ N + 1.. ]
Forever

Line = TRegEx.Create( "^(( | )*)(bbdoc|about): *" ).ReplaceAll( Line, "1" )
Line = TRegEx.Create( "^(( | )*)returns: *" ).ReplaceAll( Line, "1@return " )
Line = TRegEx.Create( "^(( | )*)See also: *" ).ReplaceAll( Line, "1@see " )
Text :+ TRegEx.Create( "^(( | )*)(.*)$" ).ReplaceAll( Line, "1 * 3" )
End If
ElseIf Trimmed = "rem" Then
Text :+ TRegEx.Create( "^(( | )*)Rem" ).ReplaceAll( Line, "1/**" )
RemBlock = True
Else
If Trimmed.StartsWith( "import" ) Or Trimmed.StartsWith( "framework" ) Or Trimmed.StartsWith( "include" ) Then Continue
If Line.Trim() Then
Line :+ ";"

Local IdentifierBegin:Int = -1
Local Brackets:Int = False
Local N:Int = 0
While N < Line.Length
If Brackets Then
If Line[ N ] = Asc( "~q" ) Then Brackets = False
Else
If Line[ N ] = Asc( "~q" ) Then
Brackets = True
ElseIf Line[ N ] = Asc( "'" ) Then
Line = Line [ ..N ] + "//" + Line[ N + 1..Line.Length - 1 ]
Exit
ElseIf IdentifierBegin < 0 Then
If IsIdentifier( Line[ N ], True ) Then IdentifierBegin = N
ElseIf Not IsIdentifier( Line[ N ], False ) Then
Local NewIdentifier:String = ConvertIdentifier( Line[ IdentifierBegin..N ] )
Line = Line[ ..IdentifierBegin ] + NewIdentifier + Line[ N.. ]
N = IdentifierBegin + NewIdentifier.Length
IdentifierBegin = -1
End If
End If
N :+ 1
WEnd

Text :+ ApplyRegExs( Line )
End If
End If
WEnd
CloseFile File

If FileName.StartsWith( "LT" ) Then FullFileName = DirName + "" + FileName[ 2.. ]
If FileName[ 0 ] = Asc( "T" ) And FileName[ 1 ] >= Asc( "A" ) And FileName[ 1 ] <= Asc( "Z" ) Then FullFileName = DirName + "" + FileName[ 1.. ]
File = WriteFile( FullFileName[ ..FullFileName.Length - 4 ] + ".java" )

Local Package:String = DirName[ Start + 1.. ].Replace( "", "." )
WriteLine( File, "package " + Package + ";" )
For Local Class:TClass = Eachin FileClasses.Keys()
if Class.Package <> Package Then WriteLine( File, "import " + Class.Package + "." + Class.Name + ";" )
Next
WriteLine( File, "" )

WriteLine( File, Text )

CloseFile File
Forever
End Function

Function ApplyRegExs:String( Text:String )
Text = TRegEx.Create( "^(( | )*)Local " ).ReplaceAll( Text, "1" )
Text = TRegEx.Create( "^(( | )*)Global " ).ReplaceAll( Text, "1public static " )
Text = TRegEx.Create( "^(( | )*)Field " ).ReplaceAll( Text, "1public " )
Text = TRegEx.Create( "^(( | )*)Const " ).ReplaceAll( Text, "1public final " )

Text = TRegEx.Create( "^(( | )*)(Function|Method) *((w|d|_)*) *(" ).ReplaceAll( Text, "13 4:void(" )
Text = TRegEx.Create( "^(( | )*)Method (.*);" ).ReplaceAll( Text, "1public 3 {" )
Text = TRegEx.Create( "^(( | )*)Function (.*);" ).ReplaceAll( Text, "1public static 3 {" )
Text = TRegEx.Create( "^(( | )*)Type (.*);" ).ReplaceAll( Text, "1public class 3 {" )

Local RegEx:TRegEx = TRegEx.Create( "^(( | )*)If (.*)([^=])=([^=])(.*) Then" )
While RegEx.Find( Text )
Text = RegEx.ReplaceAll( Text, "1if 34==56 then" )
Wend
Text = TRegEx.Create( " *== *~q~q" ).ReplaceAll( Text, ".isEmpty()" )
Text = TRegEx.Create( " *== *~q(.*?)~q" ).ReplaceAll( Text, ".equals( ~q1~q )" )

Text = TRegEx.Create( "^(( | )*)(ElseIf|Else If) (.*?) Then(( | )*);" ).ReplaceAll( Text, "1} else if( 4 ) {" )
Text = TRegEx.Create( "^(( | )*)(ElseIf|Else If) (.*?)(( | )*);$" ).ReplaceAll( Text, "1} else if( 4 ) {" )
Local LowerText:String =Text.Trim().ToLower()
if LowerText.StartsWith( "if" ) Then If Not LowerText.Contains( "then" ) Then Text = Text[ ..Text.Length - 1 ] + "then;"
Text = TRegEx.Create( "^(( | )*)If (.*?) Then(( | )*);$" ).ReplaceAll( Text, "1if( 3 ) {" )
Text = TRegEx.Create( "^(( | )*)If (.*?) Then (.*?) else (.*?);$" ).ReplaceAll( Text, "1if( 3 ) 4; else 5;" )
Text = TRegEx.Create( "^(( | )*)If (.*?) Then (.*?)(( | )*);$" ).ReplaceAll( Text, "1if( 3 ) 4;" )
Text = TRegEx.Create( "^(( | )*)If (.*?) (( | )*);$" ).ReplaceAll( Text, "1if( 3 ) {" )
Text = TRegEx.Create( "^(( | )*)Else(( | )*);" ).ReplaceAll( Text, "1} else {" )

Text = TRegEx.Create( "^(( | )*)For Local ((w|d|_)*):((w|d|_)*) *= *(.*) To (.*) Step (.*);" ).ReplaceAll( Text, "1for( 3:5 = 7; 3 <= 8; 3 += 9 ) {" )
Text = TRegEx.Create( "^(( | )*)For ((w|d|_)*) *= *(.*) To (.*) Step (.*);" ).ReplaceAll( Text, "1for( 3 = 5; 3 <= 6; 3 += 7 ) {" )
Text = TRegEx.Create( "^(( | )*)For Local ((w|d|_)*):((w|d|_)*) *= *(.*) To (.*);" ).ReplaceAll( Text, "1for( 3:5 = 7; 3 <= 8; 3++ ) {" )
Text = TRegEx.Create( "^(( | )*)For ((w|d|_)*) *= *(.*) To (.*);" ).ReplaceAll( Text, "1for( 3 = 5; 3 <= 6; 3++ ) {" )
Text = TRegEx.Create( "^(( | )*)For Local ((w|d|_)*):((w|d|_)*) *= *(.*) Until (.*);" ).ReplaceAll( Text, "1for( 3:5 = 7; 3 <= 8; 3++ ) {" )
Text = TRegEx.Create( "^(( | )*)For ((w|d|_)*) *= *(.*) Until (.*);" ).ReplaceAll( Text, "1for( 3 = 5; 3 < 6; 3++ ) {" )
Text = TRegEx.Create( "^(( | )*)For Local ((w|d|_)*):((w|d|_)*) *= *EachIn (.*);" ).ReplaceAll( Text, "1for( 3:5 @@ 7 ) {" )
Text = TRegEx.Create( "^(( | )*)For ((w|d|_)*) *= *EachIn (.*);" ).ReplaceAll( Text, "1for( 3 @@ 5 ) {" )
Text = TRegEx.Create( "^(( | )*)While *(.*);" ).ReplaceAll( Text, "1while( 3 ) {" )
Text = TRegEx.Create( "^(( | )*)Repeat(( | )*);" ).ReplaceAll( Text, "1while( true ) {" )
Text = TRegEx.Create( "^(( | )*)Select *(.*);" ).ReplaceAll( Text, "1switch( 3 ) {" )
Text = TRegEx.Create( "^(( | )*)(EndMethod|End Method|EndIf|End If|End Function|EndFunction|End Type|EndType|Next|WEnd|Forever|End Select|EndSelect)(( | )*);" ).ReplaceAll( Text, "1}" )

Text = TRegEx.Create( "new +((w|d|_)*)" ).ReplaceAll( Text, "new 1()" )
Text = TRegEx.Create( "^((( | )*)case [^;^:]*);" ).ReplaceAll( Text, "1@@" )
Text = TRegEx.Create( "^((( | )*)default) *;" ).ReplaceAll( Text, "1@@" )

Text = TRegEx.Create( ":+" ).ReplaceAll( Text, "+=" )
Text = TRegEx.Create( ":-" ).ReplaceAll( Text, "-=" )
Text = TRegEx.Create( ":*" ).ReplaceAll( Text, "*=" )
Text = TRegEx.Create( ":/" ).ReplaceAll( Text, "/=" )

Text = TRegEx.Create( ">==" ).ReplaceAll( Text, ">=" )
Text = TRegEx.Create( "<==" ).ReplaceAll( Text, "<=" )
Text = TRegEx.Create( "<>" ).ReplaceAll( Text, "!=" )

Text = TRegEx.Create( "~~q" ).ReplaceAll( Text, "~q" )
Text = TRegEx.Create( "~~n" ).ReplaceAll( Text, "
" )
Text = TRegEx.Create( "~~t" ).ReplaceAll( Text, " " )
Text = TRegEx.Create( "..(( | )*);$" ).ReplaceAll( Text, "" )

Text = TRegEx.Create( "(d):Byte" ).ReplaceAll( Text, "1" )
Text = TRegEx.Create( "(d):Short" ).ReplaceAll( Text, "1" )
Text = TRegEx.Create( "(d):Int" ).ReplaceAll( Text, "1" )
Text = TRegEx.Create( "(d):Long" ).ReplaceAll( Text, "1l" )
Text = TRegEx.Create( "(d):Float" ).ReplaceAll( Text, "1f" )
Text = TRegEx.Create( "(d):Double" ).ReplaceAll( Text, "1d" )
Text = TRegEx.Create( "((w|d|_)*) *: *((w|d|_)*)" ).ReplaceAll( Text, "3 1" )

Text = TRegEx.Create( "$(d)" ).ReplaceAll( Text, "0x1" )
Text = TRegEx.Create( "%(d)" ).ReplaceAll( Text, "0b1" )

Text = Text.Replace( "@@", ":" )
'Text = TRegEx.Create( "" ).ReplaceAll( Text, "" )

Return Text
End Function

Function IsIdentifier:Int( Code:Int, StringBeginning:Int )
If StringBeginning And Code >= Asc( "0" ) And Code <= Asc( "9" ) Then Return True
If Code >= Asc( "A" ) And Code <= Asc( "Z" ) Then Return True
If Code >= Asc( "a" ) And Code <= Asc( "z" ) Then Return True
If Code = Asc( "_" ) Then Return True
End Function

Function ConvertIdentifier:String( Identifier:String )
Local LowerCaseIdentifer:String = Identifier.ToLower()

Local Class:TClass = TClass( TClass.Classes.ValueForKey( LowerCaseIdentifer ) )
If Class Then
FileClasses.Insert( Class, Null )
Return Class.Name
End If

Local ID:TIdentifier = TIdentifier( TIdentifier.Identifiers.ValueForKey( LowerCaseIdentifer ) )
If ID Then
If ID.Class Then FileClasses.Insert( ID.Class, Null )
Return ID.Result
End If

If Identifier.EndsWith( "@" ) Then Identifier = Identifier[ ..Identifier.Length - 1 ] + ":Byte"
If Identifier.EndsWith( "%" ) Then Identifier = Identifier[ ..Identifier.Length - 1 ] + ":Int"
If Identifier.EndsWith( "#" ) Then Identifier = Identifier[ ..Identifier.Length - 1 ] + ":Float"
If Identifier.EndsWith( "!" ) Then Identifier = Identifier[ ..Identifier.Length - 1 ] + ":Double"
If Identifier.EndsWith( "$" ) Then Identifier = Identifier[ ..Identifier.Length - 1 ] + ":String"

If LowerCaseIdentifer.StartsWith( "l_" ) Then Identifier = Identifier[ 2.. ]
Return Identifier[ 0..1 ].ToLower() + Identifier[ 1.. ]
End Function


Comments :


Captain Wicker (crazy hillbilly)(Posted 1+ years ago)

 Very Nicely Done! :DDo you plan on creating a Java to BlitzMax converter too?


Guy Fawkes(Posted 1+ years ago)

 Holy crap dude! Is there any way u can do this for Blitz3D?! O_O


Matt Merkulov(Posted 1+ years ago)

 <div class="quote"> Do you plan on creating a Java to BlitzMax converter too? </div>No, it's senseless, I guess.<div class="quote"> Is there any way u can do this for Blitz3D?! </div>I didn't use B3D for 5 years now and forgot a lot unfortunately.


Nexinarus(Posted 1+ years ago)

 damn.. It would be cool


Yasha(Posted 1+ years ago)

 Which way do you want, B3D->Java or Java->B3D? One's rather easier than the other!Ask nicely and I'll think about doing one, if Matt doesn't want to.I can't really imagine many scenarios where it would be very useful though, as B3D is heavily tied to the 2D/3D engines, and as far as I know, nobody's completed a Java port of either of them yet.


Guy Fawkes(Posted 1+ years ago)

 Could you please make a B3D->Java version? :) That would be wonderful! :) Thanks, Yasha! :)


Matt Merkulov(Posted 1+ years ago)

 B3D code can be ported to BlitzMax via BM IDE and then to Java. Though some additional automatic function name replacements can be done to tie B3D functions to MiniB3D ones (MiniB3D should be ported too then).


Jason W.(Posted 1+ years ago)

 Nice job Matt!Jason


Matt Merkulov(Posted 1+ years ago)

 Converter is heavily updated. List of changes:* now converter scans directory tree instead of "include" links, so you have to arrange your code in folder structure as in standard Java project first, "include", "import" and "framework" lines will be ignored* added class scanning pass before conversion* source file package will be set in output file* java source import strings will be properly set depending on classes used* some standard BlitzMax classes and methods will be converted to corresponding Java ones* proper conversion of comments including these for documentation generation* correct conversion of identifiers (classes to pascal case, others to camel case)* conversion of variable postfixes* fixed some bugs in conversion of conditions


salric(Posted 1+ years ago)

 Great stuff! Thanks!