dak ブログ

python、rubyなどのプログラミング、MySQL、サーバーの設定などの備忘録。レゴの写真も。

Typescript で chevrotain による構文解析

2022-03-23 00:24:55 | python
Typescript で chevrotain による構文解析を試してみました。
受理する構文は以下の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
}


この記事についてブログを書く
« python での遺伝的アルゴリズ... | トップ | mysql で重複するレコードを... »

python」カテゴリの最新記事