chevrotain での加減算の構文解析結果を visitor で実行する方法のメモ。
ここでは、以下の加減算の文法を対象とした構文解析器を作成します。
calc -> expr
expr -> val ('+' | '-') val
val -> [0-9]+
lexer で字句解析を行い、parser で構文解析を行います。
そして、visitor で構文解析結果を評価し、演算結果を取得します。
プログラムは以下の通りです。
■実行結果
対象外の文法の場合には、undefined が返却されます。
ここでは、以下の加減算の文法を対象とした構文解析器を作成します。
calc -> expr
expr -> val ('+' | '-') val
val -> [0-9]+
lexer で字句解析を行い、parser で構文解析を行います。
そして、visitor で構文解析結果を評価し、演算結果を取得します。
プログラムは以下の通りです。
import { CstParser, Lexer, createToken, Rule } from 'chevrotain' /** * lexer */ const Num = createToken({ name: "Num", pattern: /[0-9]+/ }); const Plus = createToken({ name: "Plus", pattern: /[+]/ }); const Minus = createToken({ name: "Minus", pattern: /[-]/ }); const allTokens = [ Num, Plus, Minus, ]; const calcLexer = new Lexer(allTokens, { positionTracking: "onlyOffset" }); /** * parser */ class CalcParser extends CstParser { public value_stack: any[] = []; constructor() { super(allTokens); this.performSelfAnalysis(); } public calc = this.RULE("calc", () => { this.SUBRULE(this.expr); }); public expr = this.RULE("expr", () => { this.SUBRULE1(this.val); this.OR([ { ALT: () => { this.CONSUME1(Plus); }}, { ALT: () => { this.CONSUME2(Minus); }}, ]); this.SUBRULE2(this.val); }); private val = this.RULE("val", () => { this.CONSUME(Num); }); } const parser = new CalcParser(); const BaseCstVisitor = parser.getBaseCstVisitorConstructor(); /** * visitor */ class CalcVisitor extends BaseCstVisitor { public constructor() { super(); this.validateVisitor(); } public calc(ctx: any) { const v = this.visit(ctx.expr); return { type: "calc", value: v.value, }; } public expr(ctx: any) { const v_val1 = this.visit(ctx.val[0]); const v_val2 = this.visit(ctx.val[1]); if (ctx.Plus) { return { type: "expr", value: v_val1.value + v_val2.value, }; } else { return { type: "expr", value: v_val1.value - v_val2.value, }; }; } public val(ctx: any) { const value = parseInt(ctx.Num[0].image); return { type: "val", value: value, }; } } const calc_visitor = new CalcVisitor(); const texts = [ '1+2', '7-3', '3*5', // 対象外の文法 ]; for (let text of texts) { console.log(text); let lex_result = calcLexer.tokenize(text); parser.input = lex_result.tokens; let cst = parser.calc(); let res = calc_visitor.visit(cst); console.log(res); }
■実行結果
1+2 3 7-3 4 3*5 undefined
対象外の文法の場合には、undefined が返却されます。