目录:
- 使用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 (五)
现在开始写一个简单公式计算器的parser.
expr.g4
grammar Expr ;
prog: stat+ ;
stat: expr NEWLINE # printExpr
| ID '=' expr NEWLINE # assign
| NEWLINE # empty
;
expr: expr op=(MUL|DIV) expr # MulDiv
| expr op=(ADD|SUB) expr # AddSub
| INT # int
| ID # id
| '(' expr ')' # parentheses
;
MUL : '*' ; // assigns token name to '*' used above in grammar '/' ;
DIV : '/' ;
ADD : '+' ;
SUB : '-' ;
ID : [a-zA-Z]+ ;
INT : [0-9]+ ;
NEWLINE : '\r'? '\n' ;
WS: [ \t]+ -> skip ;
#号后面的标签必不可少, 这是用来方便visitor来处理的, 具体可以参阅calculator-visitor
这里我们使用常见的visitor模式来处理(另一种是用listener), 使用命令如下
antlr4ts -visitor ./src/antlr/Expr.g4
CustomVisitor代码如下
import {ExprVisitor} from "./antlr/ExprVisitor";
import {
AddSubContext,
AssignContext,
ExprParser,
IdContext,
IntContext,
MulDivContext,
ParenthesesContext,
PrintExprContext
} from "./antlr/ExprParser";
import {AbstractParseTreeVisitor} from "antlr4ts/tree";
export class CustomVisitor extends AbstractParseTreeVisitor implements ExprVisitor {
/** "memory" for our calculator; variable/value pairs go here */
memory: Map = new Map();
/** ID '=' expr */
public visitAssign(ctx: AssignContext): number {
let id = ctx.ID().text; // id is left-hand side of '='
let value = this.visit(ctx.expr()); // compute value of expression on right
this.memory.set(id, value); // store it in our memory
return value;
}
/** expr */
public visitPrintExpr(ctx: PrintExprContext) {
return this.visit(ctx.expr()); // evaluate the expr child
}
/** INT */
public visitInt(ctx: IntContext) {
return parseInt(ctx.INT().text);
}
/** ID */
public visitId(ctx: IdContext) {
let id = ctx.ID().text;
if (this.memory.has(id)) {
let value = this.memory.get(id);
console.log(`this is a assign expr, the [${id}] value is [${value}]`)
return value;
}
return 0;
}
/** expr op=('*'|'/') expr */
public visitMulDiv(ctx: MulDivContext) {
let left = this.visit(ctx.expr(0)); // get value of left subexpression
let right = this.visit(ctx.expr(1)); // get value of right subexpression
if (ctx._op.type == ExprParser.MUL) return left * right;
return left / right; // must be DIV
}
/** expr op=('+'|'-') expr */
public visitAddSub(ctx: AddSubContext) {
let left = this.visit(ctx.expr(0)); // get value of left subexpression
let right = this.visit(ctx.expr(1)); // get value of right subexpression
if (ctx._op.type == ExprParser.ADD) return left + right;
return left - right; // must be SUB
}
/** '(' expr ')' */
public visitParentheses(ctx: ParenthesesContext) {
return this.visit(ctx.expr()); // return child expr's value
}
protected defaultResult(): number {
return undefined;
}
}
测试代码如下
import {ANTLRInputStream, CommonTokenStream} from "antlr4ts";
import {ExprLexer} from "./antlr/ExprLexer";
import {ExprParser, ProgContext} from "./antlr/ExprParser";
import {CustomVisitor} from "./CustomVisitor";
// Create the lexer and parser
let inputStream = new ANTLRInputStream("1+2+3\n");
let lexer = new ExprLexer(inputStream);
let tokenStream = new CommonTokenStream(lexer);
let parser = new ExprParser(tokenStream);
// Parse the input, where `compilationUnit` is whatever entry point you defined
let result: ProgContext = parser.prog();
// console.log(result);
let value = (new CustomVisitor()).visit(result);
console.log(value);
由于代码中可能包含赋值表达式, 所以对于赋值表达式在代码里作了打印操作.
现改变let inputStream = new ANTLRInputStream("1+2+3\n");
中的1+2+3\n
为其他计算表达式试试看结果对不对
下一章将开始解释java代码