Created
February 16, 2015 07:55
-
-
Save julbouln/af2b052e78aa32e465e8 to your computer and use it in GitHub Desktop.
java to cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| require 'pp' | |
| require 'java' | |
| require '/usr/share/java/javaparser.jar' | |
| module Java2cpp | |
| class JavaFile | |
| attr_accessor :class_dependencies, :class_defined | |
| include_package "japa.parser" | |
| java_import "java.io.FileInputStream" | |
| java_import "japa.parser.ast.CompilationUnit" | |
| java_import "japa.parser.ast.visitor.VoidVisitorAdapter" | |
| def initialize | |
| @class_dependencies=[] | |
| @class_defined=[] | |
| end | |
| def to_c_bit_op(op) | |
| case op.to_s | |
| when "or" | |
| "||" | |
| when "and" | |
| "&&" | |
| when "binOr" | |
| "|" | |
| when "binAnd" | |
| "&" "" | |
| when "xor" | |
| "^" | |
| when "equals" | |
| "==" | |
| when "notEquals" | |
| "!=" | |
| when "less" | |
| "<" | |
| when "greater" | |
| ">" | |
| when "lessEquals" | |
| "<=" | |
| when "greaterEquals" | |
| ">=" | |
| when "lShift" | |
| "<<" | |
| when "rSignedShift" | |
| ">>" | |
| when "rUnsignedShift" | |
| ">>>" | |
| when "plus" | |
| "+" | |
| when "minus" | |
| "-" | |
| when "times" | |
| "*" | |
| when "divide" | |
| "/" | |
| when "remainder" | |
| "%" | |
| end | |
| end | |
| def to_c_assign_op(op) | |
| case op.to_s | |
| when "assign" | |
| "=" | |
| when "plus" | |
| "+=" | |
| when "minus" | |
| "-=" | |
| when "star" | |
| "*=" | |
| when "slash" | |
| "/=" | |
| when "and" | |
| "&=" | |
| when "or" | |
| "|=" | |
| when "xor" | |
| "^=" | |
| when "rem" | |
| "%=" | |
| when "lShift" | |
| "<<=" | |
| when "rSignedShift" | |
| ">>=" | |
| when "rUnsignedShift" | |
| ">>>=" | |
| end | |
| end | |
| def to_c_unary_op(op) | |
| case op.to_s | |
| when "positive" | |
| "+" | |
| when "negative" | |
| "-" | |
| when "preIncrement" | |
| "++" | |
| when "preDecrement" | |
| "--" | |
| when "not" | |
| "!" | |
| when "inverse" | |
| "~" | |
| when "posIncrement" | |
| "++" | |
| when "posDecrement" | |
| "-" | |
| end | |
| end | |
| def id_to_c_name(id) | |
| id.getName().to_s | |
| end | |
| def to_c_type_array(type) | |
| case type | |
| when Java::JapaParserAstType::ReferenceType | |
| if type.getArrayCount() > 0 | |
| "[]"*type.getArrayCount() | |
| else | |
| "" | |
| end | |
| else | |
| "" | |
| end | |
| end | |
| def to_c_type_args(type) | |
| c_type_args="" | |
| type_args=type.getTypeArgs() | |
| if type_args | |
| c_type_args+="<" | |
| targs=type_args.map do |ta| | |
| self.to_c_type(ta) | |
| end | |
| c_type_args+=targs.join(",") | |
| c_type_args+=">" | |
| end | |
| c_type_args | |
| end | |
| def to_c_type(type) | |
| case type | |
| when Java::JapaParserAstType::ReferenceType | |
| class_type=type.getType() | |
| self.to_c_type(class_type) | |
| when Java::JapaParserAstType::ClassOrInterfaceType | |
| class_name=type.getName().to_s | |
| # std type | |
| case class_name | |
| when "String" | |
| class_name="string" | |
| when "ArrayList" | |
| class_name="vector" | |
| when "LinkedHashMap", "HashMap" | |
| class_name="map" | |
| when "LinkedHashSet" | |
| class_name="set" | |
| when "Integer" | |
| class_name="int" | |
| when "Double" | |
| class_name="double" | |
| when "Random" | |
| class_name="int" | |
| else | |
| @class_dependencies << class_name | |
| @class_dependencies.uniq! | |
| end | |
| scope=type.getScope() | |
| while scope | |
| class_name=scope.getName().to_s+"::"+class_name | |
| scope=scope.getScope() | |
| end | |
| class_name+=self.to_c_type_args(type) | |
| class_name | |
| when Java::JapaParserAstType::WildcardType | |
| "T" | |
| when Java::JapaParserAstType::PrimitiveType | |
| prim_type=type.getType().to_s.downcase | |
| case prim_type | |
| when "boolean" | |
| prim_type="bool" | |
| end | |
| prim_type | |
| when Java::JapaParserAstType::VoidType | |
| "void" | |
| else | |
| "TODO_ctype#{type.inspect}" | |
| end | |
| end | |
| def to_c_parameters(parameters) | |
| c_params=[] | |
| if parameters | |
| parameters.each do |p| | |
| param_name=self.id_to_c_name(p.getId()) | |
| param_type=self.to_c_type(p.getType()) | |
| param_array=self.to_c_type_array(p.getType()) | |
| c_params << "#{param_type} #{param_name}#{param_array}" | |
| end | |
| end | |
| c_params.join(",") | |
| end | |
| def to_c_decl_parameters(parameters) | |
| c_params=[] | |
| if parameters | |
| parameters.each do |p| | |
| param_name=self.id_to_c_name(p.getId()) | |
| param_type=self.to_c_type(p.getType()) | |
| param_array=self.to_c_type_array(p.getType()) | |
| c_params << "#{param_type}#{param_array}" | |
| end | |
| end | |
| c_params.join(",") | |
| end | |
| def to_c_expr(expr) | |
| case expr | |
| when Java::JapaParserAstExpr::NameExpr | |
| name_expr=expr.getName().to_s | |
| name_expr | |
| when Java::JapaParserAstExpr::ThisExpr | |
| "this" | |
| when Java::JapaParserAstExpr::NullLiteralExpr | |
| "NULL" | |
| when Java::JapaParserAstExpr::BooleanLiteralExpr | |
| expr.getValue() ? "true" : "false" | |
| when Java::JapaParserAstExpr::CharLiteralExpr, | |
| Java::JapaParserAstExpr::IntegerLiteralExpr, | |
| Java::JapaParserAstExpr::DoubleLiteralExpr, | |
| Java::JapaParserAstExpr::LongLiteralExpr | |
| expr.getValue() | |
| when Java::JapaParserAstExpr::StringLiteralExpr | |
| "\"#{expr.getValue()}\"" | |
| when Java::JapaParserAstExpr::EnclosedExpr | |
| "("+self.to_c_expr(expr.getInner())+")" | |
| when Java::JapaParserAstExpr::CastExpr | |
| "("+self.to_c_type(expr.getType())+")"+self.to_c_expr(expr.getExpr()); | |
| when Java::JapaParserAstExpr::ArrayAccessExpr | |
| self.to_c_expr(expr.getName())+"["+self.to_c_expr(expr.getIndex())+"]" | |
| when Java::JapaParserAstExpr::AssignExpr | |
| self.to_c_expr(expr.getTarget())+" "+self.to_c_assign_op(expr.getOperator())+" "+self.to_c_expr(expr.getValue()) | |
| when Java::JapaParserAstExpr::BinaryExpr | |
| self.to_c_expr(expr.getLeft())+" "+self.to_c_bit_op(expr.getOperator())+" "+self.to_c_expr(expr.getRight()) | |
| when Java::JapaParserAstExpr::UnaryExpr | |
| self.to_c_unary_op(expr.getOperator())+self.to_c_expr(expr.getExpr()) | |
| when Java::JapaParserAstExpr::ClassExpr | |
| self.to_c_type(expr.getType()) | |
| when Java::JapaParserAstExpr::ArrayInitializerExpr | |
| c_values=[] | |
| values=expr.getValues() | |
| if values | |
| values.each do |v| | |
| c_values << self.to_c_expr(v) | |
| end | |
| end | |
| "{"+c_values.join(",")+"}" | |
| when Java::JapaParserAstExpr::ConditionalExpr | |
| if_expr=expr.getThenExpr() | |
| else_expr=expr.getElseExpr() | |
| self.to_c_expr(expr.getCondition()) + " ? " + self.to_c_expr(if_expr) + " : " + self.to_c_expr(else_expr) | |
| when Java::JapaParserAstExpr::FieldAccessExpr | |
| from_class=nil | |
| if expr.getScope() | |
| if expr.getScope().class==Java::JapaParserAstExpr::ThisExpr | |
| from_class="this->" | |
| else | |
| from_class=self.to_c_expr(expr.getScope()).to_s + "." | |
| end | |
| else | |
| from_class="this->" | |
| end | |
| from_class + expr.getField() | |
| when Java::JapaParserAstExpr::MethodCallExpr | |
| params=[] | |
| args=expr.getArgs() | |
| method_name=expr.getName().to_s | |
| # self.to_c_type_args(expr) | |
| if args | |
| args.each do |a| | |
| params << self.to_c_expr(a) | |
| end | |
| end | |
| from_class=nil | |
| if expr.getScope() | |
| from_class=self.to_c_expr(expr.getScope()).to_s + "." | |
| else | |
| from_class="this->" | |
| end | |
| suffix="" | |
| case from_class | |
| when "System.out." | |
| from_class="cout " | |
| method_name=" << " | |
| suffix=" << endl" | |
| when "Math." | |
| from_class="" | |
| end | |
| from_class + method_name+"("+params.join(",")+")"+suffix | |
| when Java::JapaParserAstExpr::ObjectCreationExpr | |
| params=[] | |
| args=expr.getArgs() | |
| if args | |
| args.each do |a| | |
| params << self.to_c_expr(a) | |
| end | |
| end | |
| class_name=expr.getType().getName().to_s | |
| case class_name | |
| when "Random" | |
| class_name="rand" | |
| end | |
| class_name+"("+params.join(",")+")" | |
| when Java::JapaParserAstExpr::VariableDeclarationExpr | |
| expr_type=self.to_c_type(expr.getType()) | |
| expr_name="TODO_expr_name" | |
| expr_array=self.to_c_type_array(expr.getType()) | |
| expr.getVars().each do |v| | |
| case v | |
| when Java::JapaParserAstBody::VariableDeclarator | |
| expr_name=self.id_to_c_name(v.getId())+expr_array | |
| init_expr=v.getInit() | |
| if init_expr | |
| expr_name+=" = "+self.to_c_expr(init_expr) | |
| end | |
| else | |
| expr_name="TODO_var#{v}" | |
| end | |
| end | |
| "#{expr_type} #{expr_name}" | |
| when Java::JapaParserAstExpr::ArrayCreationExpr | |
| # pp expr.getType() | |
| # pp expr.getArrayCount() | |
| # pp expr.getInitializer() | |
| dims=expr.getDimensions() | |
| if dims | |
| d=dims.map do |dim| | |
| "["+self.to_c_expr(dim)+"]" | |
| end.join(",") | |
| else | |
| init=expr.getInitializer() | |
| if init | |
| values=init.getValues() | |
| if values | |
| d="["+values.length.to_s+"]"+self.to_c_expr(expr.getInitializer()); | |
| end | |
| end | |
| end | |
| "new #{self.to_c_type(expr.getType())}#{d}" | |
| when nil | |
| "NIL" | |
| else | |
| "TODO_expr#{expr.inspect}" | |
| end | |
| end | |
| def to_c_stmt(stmt, level=0) | |
| c_stmt="" | |
| case stmt | |
| when Java::JapaParserAstStmt::BlockStmt | |
| stmts=stmt.getStmts() | |
| if stmts | |
| stmts.each do |s| | |
| c_stmt+=" "*level + self.to_c_stmt(s, level+1) | |
| end | |
| end | |
| when Java::JapaParserAstStmt::ExpressionStmt | |
| c_stmt=" "*level + self.to_c_expr(stmt.getExpression())+";\n" | |
| when Java::JapaParserAstStmt::ReturnStmt | |
| c_stmt=" "*level + "return "+self.to_c_expr(stmt.getExpr())+";\n" | |
| when Java::JapaParserAstStmt::BreakStmt | |
| c_stmt=" "*level + "break;\n" | |
| when Java::JapaParserAstStmt::SwitchStmt | |
| c_stmt=" "*level +"switch("+self.to_c_expr(stmt.getSelector())+"){\n" | |
| stmt.getEntries().each do |c| | |
| c_stmt+=" "*(level+2) +"case "+self.to_c_expr(c.getLabel())+":\n" | |
| c.getStmts().each do |s| | |
| c_stmt+=self.to_c_stmt(s, level+3) | |
| end | |
| end | |
| c_stmt+=" "*level +"}\n" | |
| when Java::JapaParserAstStmt::ForeachStmt | |
| c_stmt+=" "*level +"for("+self.to_c_expr(stmt.getVariable())+":"+self.to_c_expr(stmt.getIterable())+"){\n" | |
| c_stmt+=self.to_c_stmt(stmt.getBody(), level+1) | |
| c_stmt+=" "*level +"}\n" | |
| when Java::JapaParserAstStmt::WhileStmt | |
| c_stmt=" "*level +"while("+self.to_c_expr(stmt.getCondition())+"){\n" | |
| c_stmt+=self.to_c_stmt(stmt.getBody(), level+1) | |
| c_stmt+=" "*level +"}\n" | |
| when Java::JapaParserAstStmt::DoStmt | |
| c_stmt=" "*level +"do{\n" | |
| c_stmt+=self.to_c_stmt(stmt.getBody(), level+1) | |
| c_stmt+=" "*level +"}\n" | |
| c_stmt+=" "*level +"while("+self.to_c_expr(stmt.getCondition())+");\n" | |
| when Java::JapaParserAstStmt::ForStmt | |
| init_exprs=stmt.getInit() | |
| compare_expr=stmt.getCompare() | |
| update_exprs=stmt.getUpdate() | |
| c_stmt+=" "*level +"for(" | |
| c_stmt+=init_exprs.map do |i| | |
| self.to_c_expr(i) | |
| end.join(",") | |
| c_stmt+=";" | |
| c_stmt+=self.to_c_expr(compare_expr) | |
| c_stmt+=";" | |
| c_stmt+=update_exprs.map do |u| | |
| self.to_c_expr(u) | |
| end.join(",") | |
| c_stmt+=" "*level +"){\n" | |
| c_stmt+=self.to_c_stmt(stmt.getBody(), level+2) | |
| c_stmt+=" "*level +"}\n" | |
| when Java::JapaParserAstStmt::IfStmt | |
| if_stmt=stmt.getThenStmt() | |
| else_stmt=stmt.getElseStmt() | |
| c_stmt+=" "*level +"if("+self.to_c_expr(stmt.getCondition())+") {\n" | |
| c_stmt+=self.to_c_stmt(if_stmt, level+1) | |
| c_stmt+=" "*level +"}\n" | |
| if else_stmt | |
| c_stmt+=" "*level +"else {\n" | |
| c_stmt+=self.to_c_stmt(else_stmt, level+1) | |
| c_stmt+=" "*level +"}\n" | |
| end | |
| else | |
| c_stmt="// TODO_stmt#{stmt.inspect};\n" | |
| c_stmt+="/*"+stmt.to_s+"*/\n" | |
| end | |
| c_stmt | |
| end | |
| def convert(filename) | |
| puts "Convert #{filename}" | |
| out_c=filename.gsub(/.java/, ".cpp") | |
| out_h=filename.gsub(/.java/, ".h") | |
| c_code="" | |
| method_decl="" | |
| data = FileInputStream.new(filename) | |
| cu = JavaParser.parse(data) | |
| imports=cu.getImports() | |
| cu.getTypes().each do |t| | |
| class_name=t.getName() | |
| @class_defined << class_name | |
| @class_defined.uniq! | |
| struct_members=[] | |
| inherits=[] | |
| is_iface=false | |
| case t | |
| when Java::JapaParserAstBody::ClassOrInterfaceDeclaration | |
| is_iface=t.isInterface() | |
| exts=t.getExtends() | |
| if exts | |
| exts.each do |e| | |
| inherits << self.to_c_type(e) | |
| end | |
| end | |
| impls=t.getImplements() | |
| if impls | |
| impls.each do |i| | |
| inherits << self.to_c_type(i) | |
| end | |
| end | |
| t.getMembers().each do |m| | |
| case m | |
| when Java::JapaParserAstBody::FieldDeclaration | |
| var_type=self.to_c_type(m.getType()) | |
| var_array=self.to_c_type_array(m.getType()) | |
| m.getVariables().each do |v| | |
| var_name=self.id_to_c_name(v.getId()) | |
| struct_members << "#{var_type} #{var_name}#{var_array}" | |
| end | |
| when Java::JapaParserAstBody::ConstructorDeclaration | |
| params=self.to_c_parameters(m.getParameters()) | |
| c_code+="#{class_name}::#{class_name}(#{params}) {\n" | |
| c_code+= self.to_c_stmt(m.getBlock()) | |
| c_code+="}\n" | |
| params_decl=self.to_c_decl_parameters(m.getParameters()) | |
| method_decl+=" #{class_name}(#{params_decl});\n" | |
| # when Java::JapaParserAstBody::ClassOrInterfaceDeclaration | |
| # puts m.to_s | |
| # when Java::JapaParserAstBody::InitializerDeclaration | |
| # c_code+=self.to_c_stmt(m.getBlock()) | |
| when Java::JapaParserAstBody::MethodDeclaration | |
| method_name=m.getName().to_s | |
| method_type=self.to_c_type(m.getType()) | |
| method_array=self.to_c_type_array(m.getType()) | |
| params=self.to_c_parameters(m.getParameters()) | |
| c_code+="#{method_type}#{method_array} #{class_name}::#{method_name}(#{params}) {\n" | |
| c_code+= self.to_c_stmt(m.getBody()) | |
| c_code+="}\n" | |
| params_decl=self.to_c_decl_parameters(m.getParameters()) | |
| method_decl+=" #{method_type}#{method_array} #{method_name}(#{params_decl});\n" | |
| else | |
| c_code+="//TODO_declr#{m.inspect}\n" | |
| c_code+="/*"+m.to_s+"*/\n" | |
| end | |
| end | |
| else | |
| c_code+="//TODO_declr#{t.inspect}\n" | |
| c_code+="/*"+t.to_s+"*/\n" | |
| end | |
| header=File.open(out_h, "w") | |
| header.write "#ifndef #{class_name.upcase}_H\n" | |
| header.write "#define #{class_name.upcase}_H\n" | |
| header.write "#include <iostream>\n" | |
| header.write "#include <cmath>\n" | |
| header.write "#include <string>\n" | |
| header.write "#include <vector>\n" | |
| header.write "#include <map>\n" | |
| header.write "#include <set>\n" | |
| (@class_dependencies - @class_defined - ["Class","Object","T","StringBuilder","Iterator","Offset","Collection","File","Pattern","ScriptGetter"]).each do |cl| | |
| header.write "#include \"#{cl}.h\"\n" | |
| end | |
| # if imports | |
| # imports.each do |i| | |
| # puts i.getName() | |
| # end | |
| # end | |
| header.write "using namespace std;\n" | |
| header.write "class #{class_name}" | |
| if inherits.length>0 | |
| header.write " : "+inherits.map { |i| "public #{i}" }.join(",") | |
| end | |
| header.write " {\n" | |
| struct_members.each do |member| | |
| header.write " #{member};\n" | |
| end | |
| header.write "public:\n" | |
| header.write method_decl | |
| header.write "};\n" | |
| header.write "#endif // #{class_name.upcase}_H\n" | |
| header.close | |
| unless is_iface | |
| code=File.open(out_c, "w") | |
| code.write "#include \"#{File.basename(out_h)}\"\n" | |
| code.write c_code | |
| code.close | |
| end | |
| end | |
| end | |
| end | |
| end | |
| f=Java2cpp::JavaFile.new | |
| f.convert(ARGV[0]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment