Typescript で chevrotain による構文解析を試してみました。
受理する構文は以下の2つです。
{数字} + {数字}
{数字} - {数字}
chevrotain で文字列を解析して、上記の計算結果を返します。
■文法
calc ⇒ expr
expr ⇒ val Plus val
val Minus val
val ⇒ [0-9]+
Plus ⇒ +
Minus ⇒ -
■プログラム
■実行結果
受理する構文は以下の2つです。
{数字} + {数字}
{数字} - {数字}
chevrotain で文字列を解析して、上記の計算結果を返します。
■文法
calc ⇒ expr
expr ⇒ val Plus val
val Minus val
val ⇒ [0-9]+
Plus ⇒ +
Minus ⇒ -
■プログラム
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); // parser class CalcParser extends CstParser { public value_stack: any[] = []; constructor() { super(allTokens); this.performSelfAnalysis(); } public calc = this.RULE("calc", () => { this.SUBRULE(this.expr); if (! this.RECORDING_PHASE) { const obj = this.value_stack.pop(); this.value_stack.push(obj); } }); public expr = this.RULE("expr", () => { const item1: any = this.SUBRULE(this.val); let val1: any; if (! this.RECORDING_PHASE) { const obj1: any = this.value_stack.pop(); val1 = obj1.value; } let val2: any; const item: any = this.OR([ { ALT: () => { this.CONSUME1(Plus); this.SUBRULE1(this.val); if (! this.RECORDING_PHASE) { const obj2 = this.value_stack.pop(); val2 = obj2.value; this.value_stack.push({ value: val1 + val2 }); } }}, { ALT: () => { this.CONSUME2(Minus); this.SUBRULE2(this.val); if (! this.RECORDING_PHASE) { const obj2 = this.value_stack.pop(); let val2 = obj2.value; this.value_stack.push({ value: val1 - val2 }); } }}, ]); }); private val = this.RULE("val", () => { const item: any = this.CONSUME(Num); if (! this.RECORDING_PHASE) { this.value_stack.push({ value: parseInt(item.image) }); } }); } const parser = new CalcParser(); const productions: Record<string, Rule> = parser.getGAstProductions(); const texts = [ '1+2', '7-3', ]; for (let text of texts) { console.log(text); let lex_result = calcLexer.tokenize(text); parser.input = lex_result.tokens; parser.calc(); const obj = parser.value_stack.pop(); console.log(JSON.stringify(obj, null, 2)); }
■実行結果
1+2 { "value": 3 } 7-3 { "value": 4 }