dak ブログ

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

chevrotain での加減算の構文解析結果を visitor で実行

2022-04-03 13:51:47 | Node.js
chevrotain での加減算の構文解析結果を visitor で実行する方法のメモ。

ここでは、以下の加減算の文法を対象とした構文解析器を作成します。
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 が返却されます。


この記事についてブログを書く
« python での正規表現によるひ... | トップ | chevrotain で簡易な正規表現... »

Node.js」カテゴリの最新記事