Code archives/File Utilities/Max to Java
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
This simple program uses the magic of regular expressions to do some of the grunt-work in converting BlitzMax files to a Java project: it replaces Basic-style keyword-delineated structures and variable declarations with C-style bracing and declarations, as well as a few other minor changes. This isn't supposed to actually produce runnable code, just to skip the incredible tedium of the work of replacing keywords with braces and so on, leaving you free to focus on the actual refactoring logic. With minor changes, it could be applied equally well to C#, which is very similar. Usage is simple: place in a folder containing all of the BlitzMax files to convert and run it there; it will load and rewrite every .bmx file in the folder, saving the changed versions as .java files (doesn't currently do subfolders, but this should be easy enough to add). Because it only uses text-replacement rather than actually parsing the BlitzMax source, there are a few places where it will make errors: most type declarations in the middle of expressions or declaration lists will be left in place most of the time, which is an error in C-like languages; it can't tell the difference between an "inline" If-statement that omits "Then" and the start of an If-block structure, and so on. Notably, the program will try to replace = with == where appropriate, but might get it wrong if you haven't written very conventional Blitz code. The main place where it will definitely get this wrong is if you use an = expression as the argument to a "command" (no parens). This is not intended to be rock-solid for all edge-cases, just convenient for very basic code, so the output will definitely need to be checked for errors in this area. A good IDE (such as Visual Studio) will catch almost all of the remaining errors, though. Although all line numbers should be correct, it also doesn't attempt to spare string-literals or commented out code, so you may have to replace these with pasted versions from the original. Should still be readable though. The resulting code will not be valid Java, unless the input program was extremely trivial; but it will be close enough to Java that it can be corrected quite easily in most cases, as long as the code is fully-OOP (unlike BlitzMax, Java doesn't really support procedural code at all), and a good IDE will be able to recognise many of the class and control structures. There are quite a few other minor syntactic differences between Max and Java that this doesn't address (no default parameters, different casting syntax, C-like for loops, arrays are objects, etc.). The code will probably also need extensive refactoring before it's good Java (no private members or generic types in Max, for a start). Requires bah.regex. | |||||
' Simple tool to do some batch find-and-replace tasks on all BMX files in the current directory SuperStrict Import bah.regex Local dir:Int = ReadDir(CurrentDir()) If Not dir Then RuntimeError "failed to read current directory" Repeat Local fn:String = NextFile(dir) If fn = "" Exit If fn = "." Or fn = ".." Or ExtractExt(fn) <> "bmx" Or FileType(fn) <> 1 Then Continue Local bsource:String = LoadText(fn) Local jsource:String = ReformatSource(bsource) SaveText(jsource, StripExt(fn) + ".java") Forever CloseDir dir End Function ReformatSource:String(bsource:String) Global regexen:TList If regexen = Null Then initRegexen() Local processed:String = bsource For Local r:RPair = EachIn regexen processed = r.regx.replaceall(processed, r.repl) Next Return processed Function initRegexen() regexen = New TList 'The order of some of these is important AddRPair "(?<=\W)Function\h*([\w\d_]+\h*[:!%#\$])", "public static \1" 'Just drop the Function/Method where a type exists AddRPair "(?<=\W)Method\h*([\w\d_]+\h*[:!%#\$])", "public \1" AddRPair "(?<=\W)Function\h*([\w\d_]+\h*\()", "public static void \1" 'Otherwise, add void AddRPair "(?<=\W)Method\h*([\w\d_]+\h*\()", "public void \1" AddRPair "(?<=\W)(public\h+[^\n']+\))(?!\h+abstract)", "\1 {" 'Opening brace for methods (all of which are public) AddRPair "(?<=\W)public\h+([^\n']+\))\h+abstract", "public abstract \1" 'Move abstract to start AddRPair "(?<=\W)Then\h+([^\n']+)(?='|\r\n)", "{ \1 }" AddRPair "(?<=\W)Else(\W+)(?!If)", "} else {\1" 'Else without If AddRPair "(?<=\W)Else\h*(?=If\W)", "} else " 'Convert to normal If AddRPair "(?<=\W)If\W+([^\n'\{]+)(?=\{)", "if ( \1 ) " AddRPair "(?<=\W)If\W+([^\n'\{]+)(?='|\r\n)", "if ( \1 ) {" AddRPair "(?<=\W)While\W+([^\n']+)(?='|\r\n)", "while ( \1 ) {" AddRPair "(?<=\W)For\W+([^\n']+)(?='|\r\n)", "for ( \1 ) {" AddRPair "(?<=\W)Select\W+([^\n']+)(?='|\r\n)", "switch ( \1 ) {" AddRPair "(?<=\W)Until\W+([^\n']+)(?='|\r\n)", "} while (!( \1 ));" AddRPair "(end(\h*)(method|function|type|while|try|if|select))", "} // \1" AddRPair "(?<=\W)(next|wend)(?=\W)", "} // \1" AddRPair "Extends", "extends" 'For reasons of case sensitivity AddRPair "Abstract", "abstract" AddRPair "Null", "null" AddRPair "(?<=\W)Self(?=\W)", "this" 'Java doesn't call it Self AddRPair "Super", "super" AddRPair "Int", "int" AddRPair "Float", "float" AddRPair "String", "String" AddRPair "Return", "return" AddRPair "Case", "case" AddRPair "Default", "default" AddRPair "Throw", "throw" AddRPair "True", "true" AddRPair "False", "false" AddRPair "(?<=\W)Exit(?=\W)", "break" AddRPair "Continue", "continue" AddRPair "New\h+([\w\d_]+)", "new \1()" AddRPair "(DebugLog)", "// \1" 'Add these again later, ignore for now AddRPair "(?<=\W)(Local)(?=\h)", "/* \1 */" 'Keep the declaration, to help check converted code AddRPair "(?<=\W)Field\h*", "public " 'All BlitzMax fields are public AddRPair "(?<=\W)Global\h*", "public static " 'This will be wrong for globals in functions AddRPair "(?<=\W)(Const)\h*", "/* \1 */ public static final " AddRPair "([\w\d_]+)%", "int \1" 'Convert type sigils to keywords AddRPair "([\w\d_]+)#", "float \1" AddRPair "([\w\d_]+)!", "double \1" AddRPair "([\w\d_]+)\$", "String \1" AddRPair "([\w\d_]+)(\h*):(\h*)([\w\d_\[\]]+)", "\4 \1" 'Swap name:type declaration syntax around AddRPair "([\.=\+\-\*&\|<>]\h*)(int|float|double|String)\h", "\1" 'Remove converted inline-sigils where obvious AddRPair "(?<!\*)(/\h*)(int|float|double|String)\h", "\1" 'Slash only when not a closing comment AddRPair "(?<=\W)Repeat(?=\W)", "do {" AddRPair "(?<=\W)Forever(?=\W)", "} while (true);" AddRPair "<>", "!=" AddRPair "=>", ">=" AddRPair "=<", "<=" AddRPair "(?<=\W)And(?=\W)", "&&" AddRPair "(?<=\W)Or(?=\W)", "||" AddRPair "(?<=\W)Not(?=\W)", "!" AddRPair "(?<=\W)Shl(?=\W)", "<<" AddRPair "(?<=\W)Shr(?=\W)", ">>" AddRPair "(?<=\W)Sar(?=\W)", ">>>" AddRPair "(?<=\W)Mod(?=\W)", "%" AddRPair ":(\+|-|\*|/|&|\||~~|<<|>>|>>>|%)", "\1=" 'Change compound assignment style AddRPair "(?<=\W)(class)(?=\W)", "\1_" 'Add any Java keywords in use as identifiers here AddRPair "(abstract\h+)?type\h+([\w\d_]+(\hextends\h([\w\d_]+))?)", "public \1class \2 {" 'Type to class AddRPair "([^\s\{\};\.,])(\h*)(?='|\r\n|\})", "\1;\2" 'Add semicolons where statements end AddRPair "(\[[^,\n\]]+),", "\1][" 'Replace commas in array elements with ][ - may not want this AddRPair "'", "//" 'Comments AddRPair "(?<=\W)end(\h*)rem(?=\W)", "*/" AddRPair "(?<=\W)Rem(?=\W)", "/*" AddRPair "=\h*EachIn(?=\W)", " : " 'Once the type signatures are done this is safe AddRPair "(\[[^\n\]=]+)=", "\1==" 'Replace = with == within array[element] access 'Try to replace = with == where appropriate - this may be horribly wrong! AddRPair "(?<=[\n;,\{])(((?!\(|\Wreturn\h|=)[^\n=;,\{])+(\(|\Wreturn\h|=)[^\n=;,]+)(?<=[^\!<>])=(?!=)", "\1==" End Function Function AddRPair(regx:String, repl:String) regexen.AddLast(RPair.Create(regx, repl)) End Function End Function Type RPair Field regx:TRegEx, repl:String Function Create:RPair(regx:String, repl:String) Local r:RPair = New RPair r.regx = TRegEx.Create(regx) ; r.repl = repl Return r End Function End Type |
Comments
| ||
nice! now implement that for Javascript so I can use it. :) |
Code Archives Forum