提交 a14f0232 authored 作者: Thomas Mueller's avatar Thomas Mueller

A Java parser / Java to C converter.

上级 460425a5
/*
* Copyright 2004-2010 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.java;
import java.util.ArrayList;
import java.util.LinkedHashMap;
/**
* A class or interface.
*/
public class ClassObj {
/**
* The fully qualified class name.
*/
String name;
/**
* Whether this is an interface.
*/
boolean isInterface;
/**
* Whether this class is public.
*/
boolean isPublic;
/**
* Whether this is a primitive class (int, char,...)
*/
boolean isPrimitive;
/**
* The imported classes.
*/
ArrayList<ClassObj> imports = new ArrayList<ClassObj>();
/**
* The per-instance fields.
*/
LinkedHashMap<String, FieldObj> instanceFields = new LinkedHashMap<String, FieldObj>();
/**
* The static fields of this class.
*/
LinkedHashMap<String, FieldObj> staticFields = new LinkedHashMap<String, FieldObj>();
/**
* The methods.
*/
LinkedHashMap<String, MethodObj> methods = new LinkedHashMap<String, MethodObj>();
/**
* Add a method.
*
* @param method the method
*/
void addMethod(MethodObj method) {
methods.put(method.name, method);
}
/**
* Add an instance field.
*
* @param field the field
*/
void addInstanceField(FieldObj field) {
instanceFields.put(field.name, field);
}
/**
* Add a static field.
*
* @param field the field
*/
void addStaticField(FieldObj field) {
staticFields.put(field.name, field);
}
public String toString() {
if (isPrimitive) {
return name;
}
return "struct " + name;
}
}
/**
* A method.
*/
class MethodObj {
/**
* Whether this method is static.
*/
boolean isStatic;
/**
* Whether this method is private.
*/
boolean isPrivate;
/**
* The name.
*/
String name;
/**
* The statement block (if any).
*/
Statement block;
/**
* The return type.
*/
Type returnType;
/**
* The parameter list.
*/
ArrayList<FieldObj> parameters = new ArrayList<FieldObj>();
/**
* Whether this method is final.
*/
boolean isFinal;
/**
* Whether this method is public.
*/
boolean isPublic;
}
/**
* A field.
*/
class FieldObj {
/**
* The type.
*/
Type type;
/**
* The field name.
*/
String name;
/**
* Whether this field is static.
*/
boolean isStatic;
/**
* Whether this field is final.
*/
boolean isFinal;
/**
* Whether this field is private.
*/
boolean isPrivate;
/**
* Whether this field is public.
*/
boolean isPublic;
/**
* The initial value expression (may be null).
*/
Expr value;
}
/**
* A type.
*/
class Type {
/**
* The class.
*/
ClassObj type;
/**
* The array nesting level. 0 if not an array.
*/
int arrayLevel;
public String toString() {
if (arrayLevel == 0) {
return type.name;
}
StringBuilder buff = new StringBuilder();
buff.append(JavaParser.toC(type.name));
for (int i = 0; i < arrayLevel; i++) {
buff.append("[]");
}
return buff.toString();
}
}
/*
* Copyright 2004-2010 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.java;
import java.util.ArrayList;
/**
* An expression.
*/
public interface Expr {
// toString
}
/**
* A method call.
*/
class CallExpr implements Expr {
String object;
ArrayList<Expr> args = new ArrayList<Expr>();
public String toString() {
StringBuilder buff = new StringBuilder();
buff.append(JavaParser.toC(object)).append("(");
int i = 0;
for (Expr a : args) {
if (i > 0) {
buff.append(", ");
}
i++;
buff.append(a);
}
return buff.append(")").toString();
}
}
/**
* A assignment expression.
*/
class AssignExpr implements Expr {
Expr left;
String op;
Expr right;
public String toString() {
return left + " " + op + " " + right;
}
}
/**
* A conditional expression.
*/
class ConditionalExpr implements Expr {
Expr condition;
Expr ifTrue, ifFalse;
public String toString() {
return condition + " ? " + ifTrue + " : " + ifFalse;
}
}
/**
* A literal.
*/
class LiteralExpr implements Expr {
String literal;
public String toString() {
return literal;
}
}
/**
* An operation.
*/
class OpExpr implements Expr {
Expr left;
String op;
Expr right;
public String toString() {
if (left == null) {
return op + right;
} else if (right == null) {
return left + op;
}
return left + " " + op + " " + right;
}
}
/**
* A "new" expression.
*/
class NewExpr implements Expr {
String className;
public String toString() {
return "new " + className;
}
}
/**
* A String literal.
*/
class StringExpr implements Expr {
/**
* The literal.
*/
String text;
public String toString() {
return "\"" + javaEncode(text) + "\"";
}
/**
* Encode the String to Java syntax.
*
* @param s the string
* @return the encoded string
*/
static String javaEncode(String s) {
StringBuilder buff = new StringBuilder(s.length());
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
switch (c) {
case '\t':
// HT horizontal tab
buff.append("\\t");
break;
case '\n':
// LF linefeed
buff.append("\\n");
break;
case '\f':
// FF form feed
buff.append("\\f");
break;
case '\r':
// CR carriage return
buff.append("\\r");
break;
case '"':
// double quote
buff.append("\\\"");
break;
case '\\':
// backslash
buff.append("\\\\");
break;
default:
int ch = c & 0xffff;
if (ch >= ' ' && (ch < 0x80)) {
buff.append(c);
// not supported in properties files
// } else if(ch < 0xff) {
// buff.append("\\");
// // make sure it's three characters (0x200 is octal 1000)
// buff.append(Integer.toOctalString(0x200 | ch).substring(1));
} else {
buff.append("\\u");
// make sure it's four characters
buff.append(Integer.toHexString(0x10000 | ch).substring(1));
}
}
}
return buff.toString();
}
}
/*
* Copyright 2004-2010 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.java;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.text.ParseException;
import java.util.HashMap;
import java.util.HashSet;
/**
* Converts Java to C.
*/
public class JavaParser {
private static final int TOKEN_LITERAL_CHAR = 0;
private static final int TOKEN_LITERAL_STRING = 1;
private static final int TOKEN_LITERAL_NUMBER = 2;
private static final int TOKEN_RESERVED = 3;
private static final int TOKEN_IDENTIFIER = 4;
private static final int TOKEN_OTHER = 5;
private static final HashSet<String> RESERVED = new HashSet<String>();
private static final HashMap<String, ClassObj> BUILT_IN_TYPES = new HashMap<String, ClassObj>();
private static final HashMap<String, String> JAVA_IMPORT_MAP = new HashMap<String, String>();
private final String fileName;
private String source;
private ParseState current = new ParseState();
private String packageName;
private ClassObj classObj;
private HashMap<String, String> importMap = new HashMap<String, String>();
private HashMap<String, ClassObj> classes = new HashMap<String, ClassObj>();
static {
String[] list = new String[] { "abstract", "continue", "for", "new", "switch", "assert", "default", "if",
"package", "synchronized", "boolean", "do", "goto", "private", "this", "break", "double", "implements",
"protected", "throw", "byte", "else", "import", "public", "throws", "case", "enum", "instanceof",
"return", "transient", "catch", "extends", "int", "short", "try", "char", "final", "interface",
"static", "void", "class", "finally", "long", "strictfp", "volatile", "const", "float", "native",
"super", "while", "true", "false", "null" };
for (String s : list) {
RESERVED.add(s);
}
addBuiltInType(true, "void");
addBuiltInType(true, "int");
addBuiltInType(true, "char");
addBuiltInType(true, "byte");
addBuiltInType(true, "long");
addBuiltInType(true, "double");
addBuiltInType(true, "float");
addBuiltInType(true, "boolean");
addBuiltInType(true, "short");
String[] java = new String[] { "Boolean", "Byte", "Character", "Class", "ClassLoader", "Double", "Float",
"Integer", "Long", "Math", "Number", "Object", "Runtime", "Short", "String", "StringBuffer",
"StringBuilder", "System", "Thread", "ThreadGroup", "ThreadLocal", "Throwable", "Void" };
for (String s : java) {
JAVA_IMPORT_MAP.put(s, "java.lang." + s);
addBuiltInType(false, "java.lang." + s);
}
}
JavaParser(String baseDir, String className) {
this.fileName = baseDir + "/" + className.replace('.', '/') + ".java";
}
private static void addBuiltInType(boolean primitive, String type) {
ClassObj typeObj = new ClassObj();
typeObj.name = type;
typeObj.isPrimitive = primitive;
BUILT_IN_TYPES.put(type, typeObj);
}
/**
* Parse the source code.
*/
void parse() {
try {
RandomAccessFile file = new RandomAccessFile(fileName, "r");
byte[] buff = new byte[(int) file.length()];
file.readFully(buff);
source = new String(buff, "UTF-8");
file.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
source = removeRemarks(source);
try {
readToken();
parseCompilationUnit();
} catch (Exception e) {
throw new RuntimeException(source.substring(0, current.index) + "[*]" + source.substring(current.index), e);
}
}
private void parseCompilationUnit() {
if (readIf("package")) {
packageName = readQualifiedIdentifier();
read(";");
}
while (readIf("import")) {
String importPackageName = readQualifiedIdentifier();
String importClass = importPackageName.substring(importPackageName.lastIndexOf('.'));
importMap.put(importClass, importPackageName);
read(";");
}
while (true) {
classObj = new ClassObj();
classObj.isPublic = readIf("public");
if (readIf("class")) {
classObj.isInterface = false;
} else {
read("interface");
classObj.isInterface = true;
}
String name = readIdentifier();
classObj.name = packageName == null ? "" : (packageName + ".") + name;
// import this class
importMap.put(name, classObj.name);
classes.put(classObj.name, classObj);
parseClassBody();
if (current.token == null) {
break;
}
}
}
private ClassObj getClass(String type) {
ClassObj c = BUILT_IN_TYPES.get(type);
if (c != null) {
return c;
}
c = classes.get(type);
if (c != null) {
return c;
}
String mappedType = importMap.get(type);
if (mappedType == null) {
mappedType = JAVA_IMPORT_MAP.get(type);
if (mappedType == null) {
throw new RuntimeException("Unknown type: " + type);
}
}
c = classes.get(mappedType);
if (c == null) {
c = BUILT_IN_TYPES.get(mappedType);
if (c == null) {
throw new RuntimeException("Unknown class: " + mappedType);
}
}
return c;
}
private boolean isClass() {
if (BUILT_IN_TYPES.containsKey(current.token)) {
return true;
}
if (current.type != TOKEN_IDENTIFIER) {
return false;
}
return Character.isUpperCase(current.token.charAt(0));
}
private void parseClassBody() {
read("{");
while (true) {
if (readIf("}")) {
break;
}
boolean isStatic = false;
boolean isFinal = false;
boolean isPrivate = false;
boolean isPublic = false;
while (true) {
if (readIf("static")) {
isStatic = true;
} else if (readIf("final")) {
isFinal = true;
} else if (readIf("private")) {
isPrivate = true;
} else if (readIf("public")) {
isPublic = true;
} else {
break;
}
}
if (readIf("{")) {
MethodObj method = new MethodObj();
method.name = "init";
method.isStatic = isStatic;
method.block = readStatement();
classObj.addMethod(method);
} else {
Type type = readType();
String name = readIdentifier();
if (readIf("(")) {
MethodObj method = new MethodObj();
method.name = name;
method.returnType = type;
method.isStatic = isStatic;
method.isFinal = isFinal;
method.isPublic = isPublic;
method.isPrivate = isPrivate;
parseFormalParameters(method);
if (!readIf(";")) {
method.block = readStatement();
}
classObj.addMethod(method);
} else {
FieldObj field = new FieldObj();
field.type = type;
field.name = name;
field.isStatic = isStatic;
field.isFinal = isFinal;
field.isPublic = isPublic;
field.isPrivate = isPrivate;
if (isStatic) {
classObj.addStaticField(field);
} else {
classObj.addInstanceField(field);
}
if (readIf("=")) {
field.value = readExpr();
}
read(";");
}
}
}
}
private Type readType() {
String typeName = readTypeOrIdentifier();
Type type = new Type();
type.type = getClass(typeName);
while (readIf("[")) {
read("]");
type.arrayLevel++;
}
if (readIf("...")) {
type.arrayLevel++;
}
return type;
}
private void parseFormalParameters(MethodObj method) {
if (readIf(")")) {
return;
}
while (true) {
FieldObj field = new FieldObj();
field.type = readType();
field.name = readIdentifier();
method.parameters.add(field);
if (readIf(")")) {
break;
}
read(",");
}
}
private String readTypeOrIdentifier() {
if (current.type == TOKEN_RESERVED) {
if (BUILT_IN_TYPES.containsKey(current.token)) {
return read();
}
}
return readIdentifier();
}
private Statement readStatement() {
if (readIf(";")) {
return new EmptyStatement();
}
if (readIf("{")) {
StatementBlock stat = new StatementBlock();
while (true) {
stat.instructions.add(readStatement());
if (readIf("}")) {
break;
}
}
return stat;
} else if (readIf("if")) {
IfStatement ifStat = new IfStatement();
read("(");
ifStat.condition = readExpr();
read(")");
ifStat.block = readStatement();
if (readIf("else")) {
ifStat.elseBlock = readStatement();
}
return ifStat;
} else if (readIf("while")) {
WhileStatement whileStat = new WhileStatement();
read("(");
whileStat.condition = readExpr();
read(")");
whileStat.block = readStatement();
return whileStat;
} else if (readIf("break")) {
read(";");
return new BreakStatement();
} else if (readIf("continue")) {
read(";");
return new ContinueStatement();
} else if (readIf("switch")) {
SwitchStatement switchStat = new SwitchStatement();
read("(");
switchStat.expr = readExpr();
read(")");
read("{");
while (true) {
if (readIf("default")) {
read(":");
StatementBlock block = new StatementBlock();
switchStat.defaultBlock = block;
while (true) {
block.instructions.add(readStatement());
if (current.token.equals("case") || current.token.equals("default") || current.token.equals("}")) {
break;
}
}
} else if (readIf("case")) {
switchStat.cases.add(readExpr());
read(":");
StatementBlock block = new StatementBlock();
while (true) {
block.instructions.add(readStatement());
if (current.token.equals("case") || current.token.equals("default") || current.token.equals("}")) {
break;
}
}
switchStat.blocks.add(block);
} else if (readIf("}")) {
break;
}
}
return switchStat;
} else if (readIf("for")) {
ForStatement forStat = new ForStatement();
read("(");
forStat.init = readStatement();
forStat.condition = readExpr();
read(";");
do {
forStat.updates.add(readExpr());
} while (readIf(","));
read(")");
forStat.block = readStatement();
return forStat;
} else if (readIf("do")) {
DoWhileStatement doWhileStat = new DoWhileStatement();
doWhileStat.block = readStatement();
read("while");
read("(");
doWhileStat.condition = readExpr();
read(")");
read(";");
return doWhileStat;
} else if (readIf("return")) {
ReturnStatement returnStat = new ReturnStatement();
if (!readIf(";")) {
returnStat.expr = readExpr();
read(";");
}
return returnStat;
} else {
if (isClass()) {
ParseState start = copyParseState();
Type type = readType();
if (readIf(".")) {
current = start;
// ExprStatement
} else {
VarDecStatement dec = new VarDecStatement();
dec.type = type;
while (true) {
String name = readIdentifier();
Expr value = null;
if (readIf("=")) {
value = readExpr();
}
dec.variables.add(name);
dec.values.add(value);
if (readIf(";")) {
break;
}
read(",");
}
return dec;
}
}
ExprStatement stat = new ExprStatement();
stat.expr = readExpr();
read(";");
return stat;
}
}
private ParseState copyParseState() {
ParseState state = new ParseState();
state.index = current.index;
state.line = current.line;
state.token = current.token;
state.type = current.type;
return state;
}
private Expr readExpr() {
Expr expr = readExpr1();
String assign = current.token;
if (readIf("=") || readIf("+=") || readIf("-=") || readIf("*=") || readIf("/=") || readIf("&=") || readIf("|=")
|| readIf("^=") || readIf("%=") || readIf("<<=") || readIf(">>=") || readIf(">>>=")) {
AssignExpr assignOp = new AssignExpr();
assignOp.left = expr;
assignOp.op = assign;
assignOp.right = readExpr1();
expr = assignOp;
}
return expr;
}
private Expr readExpr1() {
Expr expr = readExpr2();
if (readIf("?")) {
ConditionalExpr ce = new ConditionalExpr();
ce.condition = expr;
ce.ifTrue = readExpr();
read(":");
ce.ifFalse = readExpr();
return ce;
}
return expr;
}
private Expr readExpr2() {
Expr expr = readExpr3();
String infixOp = current.token;
if (readIf("||") || readIf("&&") || readIf("|") || readIf("^") || readIf("&") || readIf("==") || readIf("!=")
|| readIf("<") || readIf(">") || readIf("<=") || readIf(">=") || readIf("<<") || readIf(">>")
|| readIf(">>>") || readIf("+") || readIf("-") || readIf("*") || readIf("/") || readIf("%")) {
OpExpr opExpr = new OpExpr();
opExpr.left = expr;
opExpr.op = infixOp;
opExpr.right = readExpr3();
expr = opExpr;
}
return expr;
}
private Expr readExpr3() {
if (readIf("(")) {
Expr expr = readExpr();
read(")");
return expr;
}
String prefix = current.token;
if (readIf("++") || readIf("--") || readIf("!") || readIf("~") || readIf("+") || readIf("-")) {
OpExpr expr = new OpExpr();
expr.op = prefix;
expr.right = readExpr3();
return expr;
}
Expr expr = readExpr4();
String suffix = current.token;
if (readIf("++") || readIf("--")) {
OpExpr opExpr = new OpExpr();
opExpr.left = expr;
opExpr.op = suffix;
expr = opExpr;
}
return expr;
}
private Expr readExpr4() {
if (readIf("new")) {
NewExpr expr = new NewExpr();
expr.className = readQualifiedIdentifier();
read("(");
read(")");
return expr;
}
if (readIf("false")) {
LiteralExpr expr = new LiteralExpr();
expr.literal = "false";
return expr;
}
if (readIf("true")) {
LiteralExpr expr = new LiteralExpr();
expr.literal = "true";
return expr;
}
if (readIf("null")) {
LiteralExpr expr = new LiteralExpr();
expr.literal = "null";
return expr;
}
if (current.type == TOKEN_LITERAL_NUMBER) {
LiteralExpr expr = new LiteralExpr();
expr.literal = current.token.substring(1);
readToken();
return expr;
}
if (current.type == TOKEN_LITERAL_STRING) {
StringExpr expr = new StringExpr();
expr.text = current.token.substring(1);
readToken();
return expr;
}
String name = readQualifiedIdentifier();
if (readIf("(")) {
CallExpr expr = new CallExpr();
expr.object = name;
if (!readIf(")")) {
while (true) {
expr.args.add(readExpr());
if (!readIf(",")) {
read(")");
break;
}
}
}
return expr;
}
VariableExpr expr = new VariableExpr();
expr.name = name;
return expr;
}
private void read(String string) {
if (!readIf(string)) {
throw getSyntaxException(string + " expected, got " + current.token);
}
}
private String readQualifiedIdentifier() {
String id = readIdentifier();
while (readIf(".")) {
id += "." + readIdentifier();
}
return id;
}
private String readIdentifier() {
if (current.type != TOKEN_IDENTIFIER) {
throw getSyntaxException("identifier expected, got " + current.token);
}
String result = current.token;
readToken();
return result;
}
private boolean readIf(String token) {
if (current.type != TOKEN_IDENTIFIER && token.equals(current.token)) {
readToken();
return true;
}
return false;
}
private String read() {
String token = current.token;
readToken();
return token;
}
private RuntimeException getSyntaxException(String message) {
return new RuntimeException(message, new ParseException(source, current.index));
}
/**
* Replace all Unicode escapes.
*
* @param s the text
* @return the cleaned text
*/
static String replaceUnicode(String s) {
StringBuilder buff = new StringBuilder(s.length());
for (int i = 0; i < s.length(); i++) {
if (s.substring(i).startsWith("\\\\")) {
buff.append("\\\\");
i++;
} else if (s.substring(i).startsWith("\\u")) {
i += 2;
while (s.charAt(i) == 'u') {
i++;
}
String c = s.substring(i, i + 4);
buff.append((char) Integer.parseInt(c, 16));
i += 4;
} else {
buff.append(s.charAt(i));
}
}
return buff.toString();
}
/**
* Replace all Unicode escapes and remove all remarks.
*
* @param s the source code
* @return the cleaned source code
*/
static String removeRemarks(String s) {
int idx = s.indexOf("\\u");
if (idx > 0) {
s = replaceUnicode(s);
}
char[] chars = s.toCharArray();
for (int i = 0; i >= 0 && i < s.length(); i++) {
if (s.charAt(i) == '\'') {
i++;
while (true) {
if (s.charAt(i) == '\\') {
i++;
} else if (s.charAt(i) == '\'') {
break;
}
i++;
}
continue;
} else if (s.charAt(i) == '\"') {
i++;
while (true) {
if (s.charAt(i) == '\\') {
i++;
} else if (s.charAt(i) == '\"') {
break;
}
i++;
}
continue;
}
String sub = s.substring(i);
if (sub.startsWith("/*")) {
int j = i;
i = s.indexOf("*/", i + 2) + 2;
for (; j < i; j++) {
if (chars[j] > ' ') {
chars[j] = ' ';
}
}
} else if (sub.startsWith("//")) {
int j = i;
i = s.indexOf('\n', i);
while (j < i) {
chars[j++] = ' ';
}
}
}
return new String(chars) + " ";
}
private void readToken() {
int ch;
while (true) {
if (current.index >= source.length()) {
current.token = null;
return;
}
ch = source.charAt(current.index);
if (ch == '\n') {
current.line++;
} else if (ch > ' ') {
break;
}
current.index++;
}
int start = current.index;
if (Character.isJavaIdentifierStart(ch)) {
while (Character.isJavaIdentifierPart(source.charAt(current.index))) {
current.index++;
}
current.token = source.substring(start, current.index);
if (RESERVED.contains(current.token)) {
current.type = TOKEN_RESERVED;
} else {
current.type = TOKEN_IDENTIFIER;
}
return;
} else if (Character.isDigit(ch) || (ch == '.' && Character.isDigit(source.charAt(current.index + 1)))) {
String s = source.substring(current.index);
current.token = "0" + readNumber(s);
current.index += current.token.length() - 1;
current.type = TOKEN_LITERAL_NUMBER;
return;
}
current.index++;
switch (ch) {
case '\'': {
while (true) {
if (source.charAt(current.index) == '\\') {
current.index++;
} else if (source.charAt(current.index) == '\'') {
break;
}
current.index++;
}
current.index++;
current.token = source.substring(start + 1, current.index);
current.token = "\'" + javaDecode(current.token, '\'');
current.type = TOKEN_LITERAL_CHAR;
return;
}
case '\"': {
while (true) {
if (source.charAt(current.index) == '\\') {
current.index++;
} else if (source.charAt(current.index) == '\"') {
break;
}
current.index++;
}
current.index++;
current.token = source.substring(start + 1, current.index);
current.token = "\"" + javaDecode(current.token, '\"');
current.type = TOKEN_LITERAL_STRING;
return;
}
case '(':
case ')':
case '[':
case ']':
case '{':
case '}':
case ';':
case ',':
case '?':
case ':':
break;
case '.':
if (source.charAt(current.index) == '.' && source.charAt(current.index + 1) == '.') {
current.index += 2;
}
break;
case '+':
if (source.charAt(current.index) == '=' || source.charAt(current.index) == '+') {
current.index++;
}
break;
case '-':
if (source.charAt(current.index) == '=' || source.charAt(current.index) == '-') {
current.index++;
}
break;
case '>':
if (source.charAt(current.index) == '>') {
current.index++;
if (source.charAt(current.index) == '>') {
current.index++;
}
}
if (source.charAt(current.index) == '=') {
current.index++;
}
break;
case '<':
if (source.charAt(current.index) == '<') {
current.index++;
}
if (source.charAt(current.index) == '=') {
current.index++;
}
break;
case '*':
case '/':
case '~':
case '!':
case '=':
case '%':
case '^':
if (source.charAt(current.index) == '=') {
current.index++;
}
break;
case '&':
if (source.charAt(current.index) == '&') {
current.index++;
} else if (source.charAt(current.index) == '=') {
current.index++;
}
break;
case '|':
if (source.charAt(current.index) == '|') {
current.index++;
} else if (source.charAt(current.index) == '=') {
current.index++;
}
break;
}
current.type = TOKEN_OTHER;
current.token = source.substring(start, current.index);
}
/**
* Parse a number literal and returns it.
*
* @param s the source code
* @return the number
*/
static String readNumber(String s) {
int i = 0;
if (s.startsWith("0x") || s.startsWith("0X")) {
i = 2;
while (true) {
char ch = s.charAt(i);
if ((ch < '0' || ch > '9') && (ch < 'a' || ch > 'f') && (ch < 'A' || ch > 'F')) {
break;
}
i++;
}
if (s.charAt(i) == 'l' || s.charAt(i) == 'L') {
i++;
}
} else {
while (true) {
char ch = s.charAt(i);
if ((ch < '0' || ch > '9') && ch != '.') {
break;
}
i++;
}
if (s.charAt(i) == 'e' || s.charAt(i) == 'E') {
i++;
if (s.charAt(i) == '-' || s.charAt(i) == '+') {
i++;
}
while (Character.isDigit(s.charAt(i))) {
i++;
}
}
if (s.charAt(i) == 'f' || s.charAt(i) == 'F' || s.charAt(i) == 'd'
|| s.charAt(i) == 'D' || s.charAt(i) == 'L' || s.charAt(i) == 'l') {
i++;
}
}
return s.substring(0, i);
}
private static RuntimeException getFormatException(String s, int i) {
return new RuntimeException(new ParseException(s, i));
}
private static String javaDecode(String s, char end) {
StringBuilder buff = new StringBuilder(s.length());
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == end) {
break;
} else if (c == '\\') {
if (i >= s.length()) {
throw getFormatException(s, s.length() - 1);
}
c = s.charAt(++i);
switch (c) {
case 't':
buff.append('\t');
break;
case 'r':
buff.append('\r');
break;
case 'n':
buff.append('\n');
break;
case 'b':
buff.append('\b');
break;
case 'f':
buff.append('\f');
break;
case '"':
buff.append('"');
break;
case '\'':
buff.append('\'');
break;
case '\\':
buff.append('\\');
break;
case 'u': {
try {
c = (char) (Integer.parseInt(s.substring(i + 1, i + 5), 16));
} catch (NumberFormatException e) {
throw getFormatException(s, i);
}
i += 4;
buff.append(c);
break;
}
default:
if (c >= '0' && c <= '9') {
try {
c = (char) (Integer.parseInt(s.substring(i, i + 3), 8));
} catch (NumberFormatException e) {
throw getFormatException(s, i);
}
i += 2;
buff.append(c);
} else {
throw getFormatException(s, i);
}
}
} else {
buff.append(c);
}
}
return buff.toString();
}
/**
* Write the C representation.
*
* @param out the output writer
*/
void writeC(PrintWriter out) {
for (ClassObj c : classes.values()) {
out.println("/* " + c.name + ".h */");
for (FieldObj f : c.staticFields.values()) {
if (f.isFinal) {
out.println("#define " + toC(c.name + "." + f.name) + " (" + f.value + ")");
} else {
out.print("extern " + toC(f.type.toString()) + " " + f.name);
if (f.value != null) {
out.print(" = " + f.value);
}
out.println(";");
}
}
out.println("struct " + toC(c.name) + " {");
for (FieldObj f : c.instanceFields.values()) {
out.print(" " + toC(f.type.toString()) + " " + f.name);
if (f.value != null) {
out.print(" = " + f.value);
}
out.println(";");
}
out.println("};");
for (MethodObj m : c.methods.values()) {
out.print(m.returnType + " " + toC(c.name) + "_" + m.name + "(");
int i = 0;
for (FieldObj p : m.parameters) {
if (i > 0) {
out.print(", ");
}
out.print(p.type + " " + p.name);
i++;
}
out.println(");");
}
}
out.println();
for (ClassObj c : classes.values()) {
out.println("/* " + c.name + ".c */");
for (MethodObj m : c.methods.values()) {
out.print(m.returnType + " " + toC(c.name) + "_" + m.name + "(");
int i = 0;
for (FieldObj p : m.parameters) {
if (i > 0) {
out.print(", ");
}
out.print(p.type + " " + p.name);
i++;
}
out.println(") {");
out.print(m.block.toString());
out.println("}");
}
}
}
private static String indent(String s, int spaces) {
StringBuilder buff = new StringBuilder(s.length() + spaces);
for (int i = 0; i < s.length();) {
for (int j = 0; j < spaces; j++) {
buff.append(' ');
}
int n = s.indexOf('\n', i);
n = n < 0 ? s.length() : n + 1;
buff.append(s.substring(i, n));
i = n;
}
if (!s.endsWith("\n")) {
buff.append('\n');
}
return buff.toString();
}
/**
* Move the source code 4 levels to the right.
*
* @param o the source code
* @return the indented code
*/
static String indent(String o) {
return indent(o, 4);
}
/**
* Get the C representation of this identifier.
*
* @param identifier the identifier
* @return the C representation
*/
static String toC(String identifier) {
return identifier.replace('.', '_');
}
}
/**
* The parse state.
*/
class ParseState {
int index;
int type;
String token;
int line;
}
\ No newline at end of file
/*
* Copyright 2004-2010 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.java;
import java.util.ArrayList;
/**
* A statement.
*/
public interface Statement {
// toString
}
/**
* A "return" statement.
*/
class ReturnStatement implements Statement {
Expr expr;
public String toString() {
return "return " + (expr == null ? "" : expr) + ";";
}
}
/**
* A "do .. while" statement.
*/
class DoWhileStatement implements Statement {
Expr condition;
Statement block;
public String toString() {
return "do {\n" + block + "} while (" + condition + ");";
}
}
/**
* A "continue" statement.
*/
class ContinueStatement implements Statement {
public String toString() {
return "continue;";
}
}
/**
* A "break" statement.
*/
class BreakStatement implements Statement {
public String toString() {
return "break;";
}
}
/**
* An empty statement.
*/
class EmptyStatement implements Statement {
public String toString() {
return ";";
}
}
/**
* A "switch" statement.
*/
class SwitchStatement implements Statement {
Expr expr;
StatementBlock defaultBlock;
ArrayList<Expr> cases = new ArrayList<Expr>();
ArrayList<StatementBlock> blocks = new ArrayList<StatementBlock>();
public String toString() {
StringBuilder buff = new StringBuilder();
buff.append("switch (").append(expr).append(") {\n");
for (int i = 0; i < cases.size(); i++) {
buff.append("case: " + cases.get(i) + ":\n");
buff.append(blocks.get(i).toString());
}
if (defaultBlock != null) {
buff.append("default:\n");
buff.append(defaultBlock.toString());
}
buff.append("}");
return buff.toString();
}
}
/**
* An expression statement.
*/
class ExprStatement implements Statement {
Expr expr;
public String toString() {
return expr + ";";
}
}
/**
* A "while" statement.
*/
class WhileStatement implements Statement {
Expr condition;
Statement block;
public String toString() {
String w = "while (" + condition + ")";
String s = block.toString();
return w + "\n" + s;
}
}
/**
* An "if" statement.
*/
class IfStatement implements Statement {
Expr condition;
Statement block;
Statement elseBlock;
public String toString() {
String w = "if (" + condition + ") {\n";
String s = block.toString();
if (elseBlock != null) {
s += "} else {\n" + elseBlock.toString();
}
return w + s + "}";
}
}
/**
* A "for" statement.
*/
class ForStatement implements Statement {
Statement init;
Expr condition;
Expr update;
Statement block;
ArrayList<Expr> updates = new ArrayList<Expr>();
public String toString() {
StringBuffer buff = new StringBuffer();
buff.append("for (").append(init.toString());
buff.append(" ").append(condition.toString()).append("; ");
for (int i = 0; i < updates.size(); i++) {
if (i > 0) {
buff.append(", ");
}
buff.append(updates.get(i));
}
buff.append(") {\n");
buff.append(block.toString()).append("}");
return buff.toString();
}
}
/**
* A statement block.
*/
class StatementBlock implements Statement {
ArrayList<Statement> instructions = new ArrayList<Statement>();
public String toString() {
StringBuilder buff = new StringBuilder();
for (Statement s : instructions) {
buff.append(JavaParser.indent(s.toString()));
}
return buff.toString();
}
}
/**
* A variable declaration.
*/
class VarDecStatement implements Statement {
Type type;
ArrayList<String> variables = new ArrayList<String>();
ArrayList<Expr> values = new ArrayList<Expr>();
public String toString() {
StringBuilder buff = new StringBuilder();
buff.append(type).append(' ');
for (int i = 0; i < variables.size(); i++) {
if (i > 0) {
buff.append(", ");
}
buff.append(variables.get(i));
Expr value = values.get(i);
if (value != null) {
buff.append(" = ").append(value);
}
}
buff.append(";");
return buff.toString();
}
}
/**
* A variable.
*/
class VariableExpr implements Expr {
public String name;
public String toString() {
return name;
}
}
/*
* Copyright 2004-2010 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.java;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import org.h2.test.TestBase;
/**
* A test for the Java parser.
*/
public class Test extends TestBase {
/**
* Start the task with the given arguments.
*
* @param args the arguments, or null
*/
public static void main(String... args) throws IOException {
new Test().test();
}
public void test() throws IOException {
// not supported yet:
// annotations
// HexadecimalFloatingPointLiteral
// import static
// import *
// only public or default level classes
// initializer blocks
// final variables (within blocks, parameter list)
// Identifier : (labels)
// ClassOrInterfaceDeclaration within blocks (or any other nested classes)
// assert
// array declaration at weird places: int x() [] { return null; }
assertEquals("\\\\" + "u0000", JavaParser.replaceUnicode("\\\\" + "u0000"));
assertEquals("\u0000", JavaParser.replaceUnicode("\\" + "u0000"));
assertEquals("\u0000", JavaParser.replaceUnicode("\\" + "uu0000"));
assertEquals("\\\\" + "\u0000", JavaParser.replaceUnicode("\\\\\\" + "u0000"));
assertEquals("0", JavaParser.readNumber("0a"));
assertEquals("0l", JavaParser.readNumber("0l"));
assertEquals("0xFFL", JavaParser.readNumber("0xFFLx"));
assertEquals("0xDadaCafe", JavaParser.readNumber("0xDadaCafex"));
assertEquals("1.40e-45f", JavaParser.readNumber("1.40e-45fx"));
assertEquals("1e1f", JavaParser.readNumber("1e1fx"));
assertEquals("2.f", JavaParser.readNumber("2.fx"));
assertEquals(".3d", JavaParser.readNumber(".3dx"));
assertEquals("6.022137e+23f", JavaParser.readNumber("6.022137e+23f+1"));
JavaParser parser = new JavaParser("src/tools", "org.h2.java.TestApp");
parser.parse();
PrintWriter w = new PrintWriter(System.out);
parser.writeC(w);
w.flush();
w = new PrintWriter(new FileWriter("bin/test.c"));
parser.writeC(w);
w.close();
}
}
/*
* Copyright 2004-2010 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.java;
/**
* A test application.
*/
public class TestApp {
private static final int FINAL_VALUE = 10;
public static void main(String... args) {
System.out.println("Hello World");
}
/**
* A test method.
*
* @param name ignored
* @param x ignored
* @return ignored
*/
public int getName(int name, int x) {
System.out.println("Hello");
int m = x;
m = FINAL_VALUE;
switch (x) {
case 1:
m = 3;
m = 4;
break;
default:
m = 4;
m = 5;
}
for (int i = 0; i < 10; i++, i--) {
getName(0, 0);
}
if (m > 0) {
getName(2, 3);
} else {
getName(1, 12);
}
do {
getName(0, 0);
return name;
} while (true);
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论