This repository has been archived on 2023-07-11. You can view files and clone it, but cannot push or open issues or pull requests.
BWMirror-Generator/src/impl/CApiParser.java
2015-02-09 22:40:11 +01:00

582 lines
21 KiB
Java

package impl;
import c.*;
import generator.CJavaPipeline;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* User: PC
* Date: 26.2.2014
* Time: 20:24
*/
public class CApiParser {
enum LineState {
CLASS_DEF,
ENUM_DEF,
CONST_DEF,
MULTI_LINE,
OK,
SKIP,
WTF,
END
}
enum ACCESS {
PUBLIC, PRIVATE, PROTECTED
}
ACCESS access;
String currentNamespace = "";
//String FUNC_REGEX = "^(\\s*)(virtual)?\\s(\\w+)\\s(\\w+)\\((.*)\\)";
//String FUNC_REGEX = "^(\\s*)(virtual)?\\s([\\w\\*]+)\\s([\\w\\*]+)\\((.*)\\)(\\s=\\s0;)?";
//String FUNC_REGEX = "^(\\s*)(virtual)?\\s(BWAPI::)?([\\w\\*]+)\\s([\\w\\*]+)\\((.*)\\)((\\sconst)?\\s=\\s0;)?";
//String FUNC_REGEX = "^(\\s*)(virtual)?\\s((BWAPI)|(std)::)?([\\w\\*]+)\\s([\\w\\*]+)\\((.*)\\)((\\sconst)?\\s=\\s0;)?";
// 1 2 3 4 56 7 89 10 11 12 13 14,15 15,17
public static final String FUNC_REGEX = "^(\\s*)(virtual)?\\s(const\\s)?(static\\s)?((BWAPI::)|(std)::)?((set<(\\s*(BWAPI::)?\\w+\\*?\\s*)>)|([\\w\\*]+))&?\\s+(&?[\\w\\*]+)\\((.*)\\)(\\s*const)?(\\s*=\\s0)?(;)?\\s*";
static final int F_REGEX_STATIC = 4;
static final int F_REGEX_RETURN_TYPE = 8;
static final int F_REGEX_NAME = 13;
static final int F_REGEX_PARAMS = 14;
String ENUM_VALUE_REGEX = "^(\\s*)(\\w+)(\\s*=\\s*(0x)?([0-9A-Fa-f]+))?\\s*[\\,;]";
Pattern funcPattern = Pattern.compile(FUNC_REGEX);
Pattern enumPattern = Pattern.compile(ENUM_VALUE_REGEX);
private List<CDeclaration> declarations = new ArrayList<>();
private CClass globalClass = new Clazz("BwapiGlobals");
private int currentEnumValue = 0;
public CClass getGlobalClass() {
return globalClass;
}
public void setGlobalClass(CClass globalClass) {
this.globalClass = globalClass;
declarations.add(globalClass);
}
private String javadoc = null;
private LineState processLine(String line) {
line = line.trim();
if (javadoc == null && line.contains("/*")) {
if (line.endsWith("*")) {
line += "<br/><br/>";
}
if (line.contains("*/")) {
javadoc = "\t" + line.substring(line.indexOf("/*"), line.indexOf("*/") + 2) + "\n";
} else {
javadoc = "\t" + line.substring(line.indexOf("/*")) + "\n";
}
} else if (javadoc != null && !javadoc.endsWith("*/\n")) {
if (line.endsWith("*")) {
line += "<br/><br/>";
}
if (line.contains("*/")) {
javadoc += "\t" + line.substring(0, line.indexOf("*/") + 2) + "\n";
} else {
javadoc += "\t" + line + "\n";
}
}
if (line.startsWith("namespace")) {
currentNamespace = null;
line = line.substring("namespace".length()).trim();
if (!line.equals("BWAPI")) {
currentNamespace = line;
}
if (line.equals("Errors")) {
return LineState.END;
}
if (line.equals("Colors")) {
return LineState.END;
}
if (line.equals("Orders")) {
return LineState.END;
}
if(CJavaPipeline.isBWAPI3()) {
if (line.endsWith("Types")) {
return LineState.END;
}
if (line.equals("Races")) {
return LineState.END;
}
}
return LineState.SKIP;
}
if (isSkip(line)) {
return LineState.SKIP;
}
if (line.startsWith("extern const")) {
return LineState.CONST_DEF;
}
if (line.startsWith("typedef")) {
return LineState.OK;
}
if (line.startsWith("class")) {
return LineState.CLASS_DEF;
}
if (line.startsWith("enum")) {
return LineState.ENUM_DEF;
}
if (line.startsWith("public")) {
access = ACCESS.PUBLIC;
return LineState.OK;
}
if (line.startsWith("private")) {
access = ACCESS.PRIVATE;
return LineState.OK;
}
if (line.startsWith("protected")) {
access = ACCESS.PROTECTED;
return LineState.OK;
}
//skip non public members
if (access == ACCESS.PUBLIC) {
return LineState.OK;
}
return LineState.SKIP;
}
private static boolean isSkip(String line) {
if (line.isEmpty()) {
return true;
}
if (line.startsWith("//")) {
return true;
}
if (line.startsWith("#")) {
return true;
}
//forward declaration
if (line.startsWith("class") && line.endsWith(";")) {
return true;
}
if (line.startsWith("{")) {
return true;
}
if (line.startsWith("}")) {
return true;
}
if (line.startsWith("return")) {
return true;
}
if (line.startsWith("namespace")) {
return true;
}
return false;
}
private EnumValue processEnumValue(String line) {
Matcher matcher = enumPattern.matcher(line);
if (matcher.find()) {
int enumOrdinal = currentEnumValue;
if (matcher.group(3) != null) {
//is it hex? (0x...)
if (matcher.group(4) != null) {
enumOrdinal = Integer.parseInt(matcher.group(5), 16);
} else {
enumOrdinal = Integer.parseInt(matcher.group(5), 10);
}
// 1 2 3 4 5
// String ENUM_VALUE_REGEX = "^(\\s*)(\\w+)(\\s*=\\s*(0x)?([0-9A-Fa-f]+))?";
}
EnumValue enumValue = new EnumValue(matcher.group(2), enumOrdinal);
currentEnumValue = enumValue.second + 1;
return enumValue;
}
return null;
}
private Function processFunction(String line) {
if (line.trim().equals("Event& setType(EventType::Enum type);")) {
return null;
}
Matcher matcher = funcPattern.matcher(line);
if (matcher.find()) {
Function function = new Function();
function.returnType = matcher.group(F_REGEX_RETURN_TYPE);
function.name = matcher.group(F_REGEX_NAME);
if(function.name.startsWith("&")){
function.name = function.name.substring(1);
}
if (function.returnType.equals("operator")) {
return null;
}
if (function.returnType.equals("void*")) {
System.err.println("function skipped - void* return (" + function.name + ")");
return null;
}
if (function.returnType.equals("Type")) {
function.returnType = "double";
}
if (function.returnType.equals("GameData*")) {
System.err.println("function skipped - GameData* return (" + function.name + ")");
return null;
}
if (CJavaPipeline.isBWAPI3() && function.returnType.equals("UnitCommand")) {
System.err.println("function skipped - UnitCommand return (" + function.name + ")");
return null;
}
if (function.returnType.equals("Event")) {
System.err.println("function skipped - Event return (" + function.name + ")");
return null;
}
if (function.name.startsWith("*")) {
function.name = function.name.substring(1);
if (function.returnType.equals("char")) {
function.returnType = "string";
}
}
if(function.name.equals("setClientInfo")){
System.err.println("function skipped - BWAPI4 set client info return (" + function.name + ")");
return null;
}
if(function.name.equals("maxUnitWidth")){
System.err.println("function skipped - BWAPI4 (" + function.name + ")");
return null;
}
if(function.name.equals("maxUnitHeight")){
System.err.println("function skipped - BWAPI4 (" + function.name + ")");
return null;
}
if(matcher.group(F_REGEX_STATIC) != null){
function.setStatic(true);
}
if (matcher.group(F_REGEX_PARAMS) != null) {
String paramsString = matcher.group(F_REGEX_PARAMS);
String paramStrings[] = paramsString.split("\\,");
for (String param : paramStrings) {
if (param.isEmpty()) {
continue;
}
param = param.trim();
String[] arg = param.split("\\s");
if (arg[0].equals("...")) {
//function.args.add(new Param("Object[]", "arr"));
continue;
}
if (!param.contains(" ")) {
System.err.println("Macro function skipped " + function.name);
return null;
}
try {
String argType = "";
String argName = "";
if (arg[0].equals("const") || arg[0].equals("unsigned")) {
if (arg.length == 2) {
System.err.println("Macro function skipped " + function.name);
return null;
}
argType = arg[1];
argName = arg[2];
} else {
argType = arg[0];
argName = arg[1];
}
if (argType.startsWith("std::")) {
argType = argType.substring(argType.lastIndexOf("std::") + 5);
}
if (argType.startsWith("BWAPI::")) {
argType = argType.substring(argType.lastIndexOf("BWAPI::") + 7);
}
if (argType.startsWith("BWAPIC::")) {
argType = argType.substring(argType.lastIndexOf("BWAPIC::") + 8);
System.err.println("BWAPIC function skipped : " + function.name);
return null;
}
if (argType.contains("::") && !argType.contains("BWAPI")) {
argType = argType.replace("::", ".");
argType = "bwapi." + argType;
}
//
if (argType.equals("char") && argName.startsWith("*")) {
argType = "string";
argName = argName.substring(1);
argName = "cstr_" + argName;
}
if (argType.equals("char*")) {
argType = "string";
argName = "cstr_" + argName;
}
//
if (argType.equals("va_list")) {
if(function.name.startsWith("v")){
System.err.println("BWAPI4 va_list function skipped : " + function.name);
return null;
}
argType = "Object ...";
continue;
}
//
/*if (argType.equals("void") && argName.startsWith("*")) {
argType = "long";
argName = argName.substring(1);
} */
//
/* if(argType.contains("<")){
argType=argType.substring(0, argType.indexOf('<'));
} */
//
if (argName.startsWith("&")) {
argName = argName.substring(1);
}
if (argType.endsWith("&")) {
argType = argType.substring(0, argType.length() - 1);
}
//
if (argName.startsWith("*")) {
argName = argName.substring(1);
}
if (argType.endsWith("*")) {
argType = argType.substring(0, argType.length() - 1);
}
if (argType.equals("Type")) {
argType = "double";
}
if (argType.equals("RectangleArray<double>")) {
argType = "RectangleArray";
}
if (argType.equals("void")) {
System.err.println("function skipped - void* param (" + function.name + ")");
return null;
}
if (argType.equals("FILE")) {
System.err.println("function skipped - FILE param (" + function.name + ")");
return null;
}
if (argType.equals("RectangleArray")) {
System.err.println("function skipped - RectangleArray param (" + function.name + ")");
return null;
}
if (argType.equals("UnitFilter")) {
System.err.println("function skipped - UnitFilter param (" + function.name + ")");
return null;
}
if (argType.equals("BestUnitFilter")) {
System.err.println("function skipped - BestUnitFilter param (" + function.name + ")");
return null;
}
if (arg.length > 2 && arg[2].equals("=")) {
function.args.add(new Param(argType, argName, arg[3]));
} else {
function.args.add(new Param(argType, argName));
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
return function;
}
return null;
}
public Variable processVariable(String line) {
line = line.trim();
line = line.substring("extern const".length(), line.lastIndexOf(";")).trim();
String[] nameType = line.split("\\s");
Variable variable = new ClassVariable(nameType[0], nameType[1]);
return variable;
}
public List<CDeclaration> processFile(File file) {
try {
javadoc = null;
List<CClass> classes = new ArrayList<>();
List<CEnum> enums = new ArrayList<>();
//CClass cClass = new Clazz(file.getName().substring(0, file.getName().indexOf('.')));
if (file.getName().equals("Type.h")) {
return null;
}
BufferedReader br = new BufferedReader(new FileReader(file));
String line;
boolean skippingFunctions = false;
while ((line = br.readLine()) != null) {
LineState lineState = processLine(line);
if (lineState == LineState.END) {
skippingFunctions = true;
}
if (lineState == LineState.OK && !skippingFunctions) {
Function f = processFunction(line);
if (f != null) {
if (javadoc != null) {
f.setJavadoc(javadoc);
javadoc = null;
}
//skip constructors
if (f.returnType.isEmpty()) {
continue;
}
if (classes.isEmpty()) {
globalClass.getFields().add(f);
System.err.println("Global function - " + f.getName());
continue;
}
classes.get(classes.size() - 1).getFields().add(f);
continue;
}
}
if (!enums.isEmpty()) {
EnumValue ev = processEnumValue(line);
if (ev != null) {
enums.get(enums.size() - 1).getValues().add(ev);
}
}
if (lineState == LineState.CLASS_DEF) {
String clazzName = line.trim().split(" ")[1];
if (clazzName.endsWith("Interface") && !clazzName.equals("Interface")) {
clazzName = clazzName.substring(0, clazzName.length() - "Interface".length());
}
Clazz clz = new Clazz(clazzName);
if(!CJavaPipeline.isBWAPI3()){
if(clazzName.endsWith("Type") || clazzName.equals("Error") || clazzName.equals("Race")){
Function function = new Function();
function.name = "toString";
function.returnType = "string";
clz.fields.add(function);
}
}
if (javadoc != null) {
clz.setJavadoc(javadoc);
javadoc = null;
}
classes.add(clz);
}
if (lineState == LineState.ENUM_DEF) {
String enumName = line.trim().split(" ")[1];
if (currentNamespace != null && currentNamespace.equals("Size")) {
currentNamespace = "Text.Size";
}
Enum e = new Enum(enumName, currentNamespace);
if (javadoc != null) {
e.setJavadoc(javadoc);
javadoc = null;
}
enums.add(e);
currentEnumValue = 0;
}
if (lineState == LineState.CONST_DEF) {
if (classes.isEmpty()) {
System.err.println("Skipping constant, no class to add it to - " + line);
continue;
}
Variable variable = processVariable(line);
if (variable != null) {
if (javadoc != null) {
variable.setJavadoc(javadoc);
javadoc = null;
}
classes.get(classes.size() - 1).getFields().add(variable);
}
}
}
List<CDeclaration> result = new ArrayList<>();
result.addAll(classes);
result.addAll(enums);
return result;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public List<CDeclaration> parseDir(File dir) {
File[] files = dir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return dir.isDirectory() || name.endsWith(".h");
}
});
for (File file : files) {
if (file.isDirectory()) {
parseDir(file);
} else {
List<CDeclaration> declList = processFile(file);
if (declList != null) {
declarations.addAll(declList);
}
}
}
return declarations;
}
public static void main(String... args) {
CApiParser CApiParser = new CApiParser();
Function f = CApiParser.processFunction("bool isEnemy(Player player, Random me) const = 0;");
System.out.println();
}
}