Skip to content

Instantly share code, notes, and snippets.

@julbouln
Created February 16, 2015 07:55
Show Gist options
  • Save julbouln/af2b052e78aa32e465e8 to your computer and use it in GitHub Desktop.
Save julbouln/af2b052e78aa32e465e8 to your computer and use it in GitHub Desktop.
java to cpp
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