fukke.cafe

プログラミング言語を作る・その1

プログラムは 高級言語→(parse)→AST(抽象構文木)→(アセンブル)→アセンブラ言語→マシン語 のように変換されている。
JavaScriptを題材にASTについて学ぶ。
JavaScriptをASTに変換するプログラムとしてesprimaがある。
実際にesprimaを使って簡単なコードを変換する。
import * as esprisma from 'esprima'
import dedent from 'dedent-js'

const src = dedent`
const hoge = 10
`

const ast = esprisma.parseModule(src)

console.log(JSON.stringify(ast, null, 2))
この結果は以下のようになる。
{
  "type": "Program",
  "body": [
    {
      "type": "VariableDeclaration",
      "declarations": [
        {
          "type": "VariableDeclarator",
          "id": {
            "type": "Identifier",
            "name": "hoge"
          },
          "init": {
            "type": "Literal",
            "value": 10,
            "raw": "10"
          }
        }
      ],
      "kind": "const"
    }
  ],
  "sourceType": "module"
}
変数宣言を行ったのでtypeはVariableDeclaratorになる。 Identifierは変数名でhoge, initには初期値があり、Literalの10が入ってる。
例えばこのASTからWebAssemblyを生成できればJavaScriptからWebAssemblyを生成する自作言語が完成します。
次にJavaScriptで作られた汎用parserのparsimmonを使ってASTを生成してみます。
parser.ts
import * as parsimmon from 'parsimmon';
const flang = parsimmon.createLanguage({
  Number: () => parsimmon.regexp(/[0-9]+/).map(Number),
  WhiteSpace: () => parsimmon.optWhitespace,
  Identifier: () => parsimmon.regexp(/[a-zA-z]+/),
  Const: () => parsimmon.string("const"),
  Declaration: (r) =>
    parsimmon.seq(
      r.Const,
      r.WhiteSpace,
      r.Identifier,
      r.WhiteSpace,
      parsimmon.string("="),
      r.WhiteSpace,
      r.Number
    )
    .map(([_1, _2, identifier, _3, _4, _5, number]) => {
      return {
        type: 'ValiableDeclaration',
        declarations: [
          {
            type: "VariableDeclarator",
            id: {
              type: "Identifier",
              name: identifier
            },
            init: {
              type: "Literal",
              value: number,
            }
          }
        ],
        kind: "const"
      }
    }),
  parse: (r) => parsimmon.alt(r.Declaration)
})
const aa = `const a = 10`
console.log(JSON.stringify(flang.parse.tryParse(aa), null, 2))

公開日 2023/01/31

Thanks you for reading.