使用antlr4, 用ts/js还原protobuf生成的jav
2017-03-23 本文已影响0人
ThirstyZebra
目录:
- 使用antlr4, 用ts/js还原protobuf生成的java代码为pb (一)
- 使用antlr4, 用ts/js还原protobuf生成的java代码为pb (二)
- 使用antlr4, 用ts/js还原protobuf生成的java代码为pb (三)
- 使用antlr4, 用ts/js还原protobuf生成的java代码为pb (四)
- 使用antlr4, 用ts/js还原protobuf生成的java代码为pb (五)
test004.ts
import {ANTLRInputStream, CommonTokenStream} from "antlr4ts";
import {JavaLexer} from "../antlr/Java/JavaLexer";
import {CompilationUnitContext, JavaParser} from "../antlr/Java/JavaParser";
import {fs} from "mz";
import {CustomJavaListener} from "./CustomJavaListener";
import {ParseTreeWalker} from "antlr4ts/tree";
import * as nodefs from "fs";
import {CustomClassBodyDeclarationVisitor} from "./CustomClassBodyDeclarationVisitor";
import {PbStructure} from "./PbStructure";
let data = nodefs.readFileSync('./../../src/ref/msg_svc$PbGetDiscussMsgResp.java', "utf-8");
beginParse(data);
function beginParse(data) {
let inputStream = new ANTLRInputStream(data);
let lexer = new JavaLexer(inputStream);
let tokenStream = new CommonTokenStream(lexer);
let parser = new JavaParser(tokenStream);
// Parse the input, where `compilationUnit` is whatever entry point you defined
let tree: CompilationUnitContext = parser.compilationUnit();
// let walker: ParseTreeWalker = new ParseTreeWalker(); // create standard walker
// let javaListener: CustomJavaListener = new CustomJavaListener();
// walker.walk(javaListener, tree); // initiate walk of tree with listener
let pbStructure = new PbStructure();
let javaVisitor = new CustomClassBodyDeclarationVisitor(pbStructure);
javaVisitor.visit(tree);
console.log(pbStructure);
// console.log(tree);
// console.log(value);
}
好了, 看下使用visitor写的代码, 这是解析fieldMap字段的
import {JavaVisitor} from "../antlr/Java/JavaVisitor";
import {AbstractParseTreeVisitor} from "antlr4ts/tree";
import {
ArrayInitializerContext,
ClassDeclarationContext,
CreatorContext,
ExpressionListContext,
FieldDeclarationContext,
VariableDeclaratorContext,
VariableInitializerContext
} from "../antlr/Java/JavaParser";
import {PbStructure} from "./PbStructure";
export class CustomClassBodyDeclarationVisitor<Result> extends AbstractParseTreeVisitor<Result> implements JavaVisitor<Result> {
public constructor(public pbStructure: PbStructure) {
super();
}
public visitClassDeclaration(ctx: ClassDeclarationContext): Result {
this.pbStructure.messageName = ctx.Identifier().text;
this.pbStructure.extend = ctx.typeType().classOrInterfaceType().Identifier(0).text;
this.visit(ctx.classBody());
return;
}
public visitFieldDeclaration(ctx: FieldDeclarationContext): Result {
if (
ctx.typeType().text == 'MessageMicro.FieldMap'
) {
this.visit(ctx.variableDeclarators());
}
return;
}
public visitVariableDeclarator(ctx: VariableDeclaratorContext): Result {
if (ctx.variableDeclaratorId().text == '__fieldMap__') {
if (ctx.variableInitializer()) {
this.visitFieldMapVariableInitializer(ctx.variableInitializer());
}
}
return;
}
protected defaultResult(): Result {
return undefined;
}
/**
* // MessageMicro.initFieldMap(
* // new int[] { 8, 16, 24, 32 },
* // new String[] { "uint32_start_time", "rpt_uint32_fieldlist", "rpt_uint64_uinlist", "uint64_bind_uin" },
* // new Object[] { Integer.valueOf(0), Integer.valueOf(0), Long.valueOf(0L), Long.valueOf(0L) },
* // ReqBody.class
* // );
* @param ctx
*/
private visitFieldMapVariableInitializer(ctx: VariableInitializerContext) {
let initFunc = ctx.expression().expression(0);
if (initFunc.text != 'MessageMicro.initFieldMap') {
throw new Error('fieldMap function name must be "MessageMicro.initFieldMap"');
}
let expressList = ctx.expression().expressionList();
this.visitFieldMapExpressList(expressList);
}
/**
* // MessageMicro.initFieldMap(
* expression 0-> // new int[] { 8, 16, 24, 32 },
* expression 1-> // new String[] { "uint32_start_time", "rpt_uint32_fieldlist", "rpt_uint64_uinlist", "uint64_bind_uin" },
* expression 2-> // new Object[] { Integer.valueOf(0), Integer.valueOf(0), Long.valueOf(0L), Long.valueOf(0L) },
* // ReqBody.class
* // );
* @param ctx
*/
private visitFieldMapExpressList(ctx: ExpressionListContext) {
this.pbStructure.flags = this.visit(ctx.expression(0));
this.pbStructure.fields = this.visit(ctx.expression(1));
this.pbStructure.defaultValues = this.visit(ctx.expression(2));
}
public visitCreator(ctx: CreatorContext): Result | any {
let creatorName = ctx.createdName().text;
let arrayInitializr = ctx.arrayCreatorRest().arrayInitializer();
switch (creatorName) {
case 'int':
return this.visitIntArrayInitializer(arrayInitializr);
case 'String':
return this.visitStringArrayInitializer(arrayInitializr);
case 'Object':
return this.visitObjectArrayInitializer(arrayInitializr);
default:
return this.visitDefaultArrayInitializer(arrayInitializr);
}
}
public visitDefaultArrayInitializer(ctx: ArrayInitializerContext) {
return ctx.variableInitializer().map(variable => variable);
}
public visitIntArrayInitializer(ctx: ArrayInitializerContext) {
return ctx.variableInitializer().map(variable => parseInt(variable.text));
}
public visitObjectArrayInitializer(ctx: ArrayInitializerContext) {
return ctx.variableInitializer().map(variable => {
//类型初始化
let expr = variable.expression();
if (expr &&
expr.getChild(1).text == '(' &&
expr.getChild(3).text == ')'
) {
switch (expr.expression(0).text) {
case 'Integer.valueOf':
case 'Long.valueOf':
return parseInt(expr.expressionList().text);
default:
return variable.text;
}
} else {
return variable.text;
}
});
}
public visitStringArrayInitializer(ctx: ArrayInitializerContext) {
return ctx.variableInitializer().map(variable => variable.text.replace(/"(.+?)"|'(.+?)'/, "$1$2"));
}
}
运行一下查看一下PbStructure类
PbStructure {
messageName: 'Oidb_0x5d0$ReqBody',
extend: 'MessageMicro',
flags: [ 8, 16, 24, 32 ],
fields:
[ 'uint32_start_time',
'rpt_uint32_fieldlist',
'rpt_uint64_uinlist',
'uint64_bind_uin' ],
defaultValues: [ 0, 0, 0, 0 ] }
完善其他字段
再次添加解析所有字段声明的代码
PbStructure类
export class PbStructure {
public messageName;
//another info
public extend;
public flags;
public fields;
public defaultValues;
fieldMap: Map<string, { type, name, defaultValue, repeated }>;
constructor() {
this.fieldMap = new Map();
}
}
CustomClassBodyDeclarationVisitor
import {JavaVisitor} from "../antlr/Java/JavaVisitor";
import {AbstractParseTreeVisitor} from "antlr4ts/tree";
import {
ArrayInitializerContext,
ClassDeclarationContext,
CreatorContext,
ExpressionListContext,
FieldDeclarationContext,
VariableDeclaratorContext,
VariableInitializerContext
} from "../antlr/Java/JavaParser";
import {PbStructure} from "./PbStructure";
export class CustomClassBodyDeclarationVisitor<Result> extends AbstractParseTreeVisitor<Result> implements JavaVisitor<Result> {
private currentHandleField;
private resetCurrentHandleField() {
this.currentHandleField = {
type: null,
name: null,
defaultValue: null,
repeated: null
};
}
public constructor(public pbStructure: PbStructure) {
super();
}
public visitClassDeclaration(ctx: ClassDeclarationContext): Result {
this.pbStructure.messageName = ctx.Identifier().text;
this.pbStructure.extend = ctx.typeType().classOrInterfaceType().Identifier(0).text;
this.visit(ctx.classBody());
return;
}
public visitFieldDeclaration(ctx: FieldDeclarationContext): Result {
switch (ctx.typeType().text) {
case 'MessageMicro.FieldMap':
this.visit(ctx.variableDeclarators());
break;
case 'PBBoolField':
case 'PBBytesField':
case 'PBDoubleField':
case 'PBEnumField':
case 'PBField':
case 'PBFixed32Field':
case 'PBFixed64Field':
case 'PBFloatField':
case 'PBInt32Field':
case 'PBInt64Field':
case 'PBPrimitiveField':
case 'PBRepeatField':
case 'PBRepeatMessageField':
case 'PBSFixed32Field':
case 'PBSFixed64Field':
case 'PBSInt32Field':
case 'PBSInt64Field':
case 'PBStringField':
case 'PBUInt32Field':
case 'PBUInt64Field':
this.resetCurrentHandleField();
this.currentHandleField.type = ctx.typeType().text;
this.visit(ctx.variableDeclarators());
this.pbStructure.fieldMap.set(this.currentHandleField.name, this.currentHandleField);
this.resetCurrentHandleField();
break;
}
return;
}
public visitVariableDeclarator(ctx: VariableDeclaratorContext): Result {
if (ctx.variableDeclaratorId().text == '__fieldMap__') {
if (ctx.variableInitializer()) {
this.visitFieldMapVariableInitializer(ctx.variableInitializer());
}
} else {
if (ctx.variableInitializer()) {
this.currentHandleField.name = ctx.variableDeclaratorId().text;
this.visitPBFieldVariableInitializer(ctx.variableInitializer());
}
}
return;
}
public visitPBFieldVariableInitializer(ctx: VariableInitializerContext) {
let expr = ctx.expression();
if (expr &&
expr.getChild(1).text == '(' &&
expr.getChild(3).text == ')'
) {
switch (expr.expression(0).text) {
case 'PBField.initBool':
case 'PBField.initFixed32':
case 'PBField.initInt32':
case 'PBField.initInt64':
case 'PBField.initSFixed32':
case 'PBField.initSFixed64':
case 'PBField.initSInt32':
case 'PBField.initSInt64':
case 'PBField.initUInt32':
case 'PBField.initUInt64':
this.currentHandleField.defaultValue = parseInt(expr.expressionList().text);
break;
case 'PBField.initBytes'://ByteStringMicro/byte[]
this.currentHandleField.defaultValue = expr.expressionList().text;
break;
case 'PBField.initEnum':
break;
case 'PBField.initFloat':
case 'PBField.initDouble':
this.currentHandleField.defaultValue = parseFloat(expr.expressionList().text);
break;
case 'PBField.initRepeat':
const index = expr.expressionList().text.indexOf('__repeatHelper__');
if (index > 0) {
this.currentHandleField.repeated = expr.expressionList().text.substring(0, index - 1);
}
break;
case 'PBField.initString':
this.currentHandleField.defaultValue = expr.expressionList().text.replace(/"(.+?)"|'(.+?)'/, "$1$2")
}
} else {
}
}
protected defaultResult(): Result {
return undefined;
}
/**
* // MessageMicro.initFieldMap(
* // new int[] { 8, 16, 24, 32 },
* // new String[] { "uint32_start_time", "rpt_uint32_fieldlist", "rpt_uint64_uinlist", "uint64_bind_uin" },
* // new Object[] { Integer.valueOf(0), Integer.valueOf(0), Long.valueOf(0L), Long.valueOf(0L) },
* // ReqBody.class
* // );
* @param ctx
*/
private visitFieldMapVariableInitializer(ctx: VariableInitializerContext) {
let initFunc = ctx.expression().expression(0);
if (initFunc.text != 'MessageMicro.initFieldMap') {
throw new Error('fieldMap function name must be "MessageMicro.initFieldMap"');
}
let expressList = ctx.expression().expressionList();
this.visitFieldMapExpressList(expressList);
}
/**
* // MessageMicro.initFieldMap(
* expression 0-> // new int[] { 8, 16, 24, 32 },
* expression 1-> // new String[] { "uint32_start_time", "rpt_uint32_fieldlist", "rpt_uint64_uinlist", "uint64_bind_uin" },
* expression 2-> // new Object[] { Integer.valueOf(0), Integer.valueOf(0), Long.valueOf(0L), Long.valueOf(0L) },
* // ReqBody.class
* // );
* @param ctx
*/
private visitFieldMapExpressList(ctx: ExpressionListContext) {
this.pbStructure.flags = this.visit(ctx.expression(0));
this.pbStructure.fields = this.visit(ctx.expression(1));
this.pbStructure.defaultValues = this.visit(ctx.expression(2));
}
public visitCreator(ctx: CreatorContext): Result | any {
let creatorName = ctx.createdName().text;
let arrayInitializr = ctx.arrayCreatorRest().arrayInitializer();
switch (creatorName) {
case 'int':
return this.visitIntArrayInitializer(arrayInitializr);
case 'String':
return this.visitStringArrayInitializer(arrayInitializr);
case 'Object':
return this.visitObjectArrayInitializer(arrayInitializr);
default:
return this.visitDefaultArrayInitializer(arrayInitializr);
}
}
public visitDefaultArrayInitializer(ctx: ArrayInitializerContext) {
return ctx.variableInitializer().map(variable => variable);
}
public visitIntArrayInitializer(ctx: ArrayInitializerContext) {
return ctx.variableInitializer().map(variable => parseInt(variable.text));
}
public visitStringArrayInitializer(ctx: ArrayInitializerContext) {
return ctx.variableInitializer().map(variable => variable.text.replace(/"(.+?)"|'(.+?)'/, "$1$2"));
}
public visitObjectArrayInitializer(ctx: ArrayInitializerContext) {
return ctx.variableInitializer().map(variable => {
//类型初始化
let expr = variable.expression();
if (expr &&
expr.getChild(1).text == '(' &&
expr.getChild(3).text == ')'
) {
switch (expr.expression(0).text) {
case 'Integer.valueOf':
case 'Long.valueOf':
return parseInt(expr.expressionList().text);
default:
return variable.text;
}
} else {
return variable.text;
}
});
}
}
查看打印出来的PbStructure类
PbStructure {
fieldMap:
Map {
'rpt_uint32_fieldlist' => { type: 'PBRepeatField',
name: 'rpt_uint32_fieldlist',
defaultValue: null,
repeated: 'PBUInt32Field' },
'rpt_uint64_uinlist' => { type: 'PBRepeatField',
name: 'rpt_uint64_uinlist',
defaultValue: null,
repeated: 'PBUInt64Field' },
'uint32_start_time' => { type: 'PBUInt32Field',
name: 'uint32_start_time',
defaultValue: 0,
repeated: null },
'uint64_bind_uin' => { type: 'PBUInt64Field',
name: 'uint64_bind_uin',
defaultValue: 0,
repeated: null } },
messageName: 'Oidb_0x5d0$ReqBody',
extend: 'MessageMicro',
flags: [ 8, 16, 24, 32 ],
fields:
[ 'uint32_start_time',
'rpt_uint32_fieldlist',
'rpt_uint64_uinlist',
'uint64_bind_uin' ],
defaultValues: [ 0, 0, 0, 0 ] }
最后通过PbStructure类生成proto文件
添加GeneProtoFile代码
import {PbStructure} from "./PbStructure";
import {Java2PBType, JavaFieldMap, PBType} from "./PBMap";
export class GeneProtoFile {
private indent: number = 0;
public constructor(private pbStructure: PbStructure) {
}
public indentWrite(string) {
this.indentInc();
this.write(string);
this.indentDec();
}
public indentWriteLn(string) {
this.indentInc();
this.writeLn(string);
this.indentDec();
}
public write(string) {
let indent = this.indent;
while (indent-- > 0) {
this.put(" ");
}
this.put(string);
}
public writeLn(string) {
this.write(string);
this.put("\n");
}
public put(string) {
process.stdout.write(string);
}
public indentInc() {
++this.indent;
}
public indentDec() {
--this.indent;
if (this.indent < 0) {
this.indent = 0;
}
}
public emitProto() {
this.emitMessage();
}
private emitMessage() {
this.writeLn(`message ${this.pbStructure.messageName} {`)
this.indentInc();
this.emitProtoBody();
this.indentDec();
this.write(`}`)
}
private emitProtoBody() {
this.pbStructure.flags.map((flag, index) => {
this.emitProtoField(index);
});
}
private emitProtoField(index) {
let name = this.pbStructure.fields[index];
let fieldData = this.pbStructure.fieldMap.get(name);
switch (fieldData.type) {
case JavaFieldMap.PBBytesField:
this.writeLn(`${PBType.bytes} ${fieldData.name};`);
break;
case JavaFieldMap.PBDoubleField:
this.writeLn(`${PBType.double} ${fieldData.name};`);
break;
case JavaFieldMap.PBEnumField:
this.writeLn(`enum ${fieldData.name};`);//fixme
break;
case JavaFieldMap.PBField:
this.writeLn(`pb ${fieldData.name};`);//fixme
break;
case JavaFieldMap.PBFixed32Field:
this.writeLn(`${PBType.fixed32} ${fieldData.name};`);
break;
case JavaFieldMap.PBFixed64Field:
this.writeLn(`${PBType.fixed64} ${fieldData.name};`);
break;
case JavaFieldMap.PBFloatField:
this.writeLn(`${PBType.float} ${fieldData.name};`);
break;
case JavaFieldMap.PBInt32Field:
this.writeLn(`${PBType.int32} ${fieldData.name};`);
break;
case JavaFieldMap.PBInt64Field:
this.writeLn(`${PBType.int64} ${fieldData.name};`);
this.put(`;`);
break;
case JavaFieldMap.PBPrimitiveField:
this.writeLn(`primitive ${fieldData.name};`);//fixme
break;
case JavaFieldMap.PBRepeatField:
this.writeLn(`repeated ${Java2PBType[fieldData.repeated]} ${fieldData.name};`);
break;
case JavaFieldMap.PBRepeatMessageField:
this.writeLn(`repeated message ${fieldData.type} ${fieldData.name};`);
break;
case JavaFieldMap.PBSFixed32Field:
this.writeLn(`${PBType.sfixed32} ${fieldData.name};`);
break;
case JavaFieldMap.PBSFixed64Field:
this.writeLn(`${PBType.sfixed64} ${fieldData.name};`);
break;
case JavaFieldMap.PBSInt32Field:
this.writeLn(`${PBType.sint32} ${fieldData.name};`);
break;
case JavaFieldMap.PBSInt64Field:
this.writeLn(`${PBType.sint64} ${fieldData.name};`);
break;
case JavaFieldMap.PBStringField:
this.writeLn(`${PBType.string} ${fieldData.name};`);
break;
case JavaFieldMap.PBUInt32Field:
this.writeLn(`${PBType.uint32} ${fieldData.name};`);
break;
case JavaFieldMap.PBUInt64Field:
this.writeLn(`${PBType.uint64} ${fieldData.name};`);
break;
}
}
}
修改test004.ts添加如下几行
let gene = new GeneProtoFile(pbStructure);
gene.emitProto();
最后完成批量解析, 以及一些bug修正
git地址: http://git.oschina.net/gradee/antlr
https://github.com/linbolen/botmm