https://github.com/yiminghe/kison
A LALR(1)/LL(1)/LL(K) parser generator for javascript/typescript
https://yiminghe.me/kison/examples/
npx kison@latest -g xx-grammar.js
cal-grammar.js: support operator precedence
module.exports = {
  productions: [
    {
      symbol: 'exp',
      rhs: ['primaryExpression'],
    },
    {
      symbol: 'exp',
      rhs: ['exp', '^', 'exp'],
      action() {
        return {
          v: Math.pow(this.$1.v, this.$3.v),
          l: this.$1,
          r: this.$3,
          op: '^',
        };
      },
    },
    {
      symbol: 'exp',
      rhs: ['exp', '-', 'exp'],
      action() {
        return { v: this.$1.v - this.$3.v, l: this.$1, r: this.$3, op: '-' };
      },
    },
    {
      symbol: 'exp',
      rhs: ['exp', '*', 'exp'],
      action() {
        return { v: this.$1.v * this.$3.v, l: this.$1, r: this.$3, op: '*' };
      },
    },
    {
      symbol: 'exp',
      rhs: ['exp', '/', 'exp'],
      action() {
        return { v: this.$1.v / this.$3.v, l: this.$1, r: this.$3, op: '/' };
      },
    },
    {
      symbol: 'exp',
      precedence: 'UMINUS',
      rhs: ['-', 'exp'],
      action() {
        return { v: -this.$2.v, op: 'UMINUS' };
      },
    },
    {
      symbol: 'exp',
      rhs: ['exp', '+', 'exp'],
      action() {
        return { v: this.$1.v + this.$3.v, l: this.$1, r: this.$3, op: '+' };
      },
    },
    {
      symbol: 'primaryExpression',
      rhs: ['(', 'exp', ')'],
      action() {
        return this.$2;
      },
    },
    {
      symbol: 'primaryExpression',
      rhs: ['NUMBER'],
      action() {
        return { v: Number(this.$1) };
      },
    },
  ],
  operators: [
    ['left', '+', '-'],
    ['left', '*', '/'],
    ['right', '^'],
    ['right', 'UMINUS'],
  ],
  lexer: {
    rules: [
      {
        regexp: /^\s+/,
        token: '$HIDDEN',
      },
      {
        regexp: /^[0-9]+(\.[0-9]+)?\b/,
        token: 'NUMBER'
      }
    ]
  }
};
cal-grammar.js:
| alternative natation(‘ | ’) | 
const startGroup = `'('`;
const endGroup = `')'`;
const alternative = `'|'`;
module.exports = () => ({
  productions: [
    {
      symbol: 'program',
      rhs: ['statements'],
    },
    {
      symbol: 'statements',
      rhs: [startGroup, 'exp', 'NEW_LINE', endGroup + '*'],
    },
    {
      symbol: 'exp',
      rhs: [
        'exp', '+', 'exp',
        alternative,
        'exp', '-', 'exp',
        alternative,
        'exp', '*', 'exp',
        alternative,
        'exp', '/', 'exp',
        alternative,
        'exp', '^', 'exp',
      ],
      label: 'binary-exp',
    },
    {
      symbol: 'exp',
      rhs: ['-', 'exp'],
      precedence: 'UMINUS',
    },
    {
      symbol: 'exp',
      rhs: ['NUMBER'],
    },
    {
      symbol: 'exp',
      rhs: ['(', 'exp', ')'],
    },
  ],
  operators: [
    ['left', '+', '-'],
    ['left', '*', '/'],
    ['right', '^'],
    ['right', 'UMINUS'],
  ],
  lexer: {
    rules: [
      {
        regexp: /^\n/,
        token: 'NEW_LINE',
      },
      {
        regexp: /^\s+/,
        token: '$HIDDEN',
      },
      {
        regexp: /^[0-9]+(\.[0-9]+)?\b/,
        token: 'NUMBER',
      },
    ],
  },
});
--es: generate es module-g: grammar file-m: ll or lalr or llk (llk is powerful than ll but less performant!)--babel: use babel to transform code. need install @babel/core@7.x and @babel/preset-env manually--declaration: generate d.ts type file for LL parsernpx kison@latest -g cal-grammar.js
ll parser generator
npx kison@latest -m ll -g cal-grammar.js
--declaration to generate d.ts type for LL