---
title: 自分だけのプログラミング言語を作ろう
tags: 
author: [ashphy](https://convert.docswell.com/user/ashphy)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/G789165ZJD.jpg?width=480
description: 実際にプログラミング言語を作る過程を体験することでより深くプログラミング言語について理解する機会を提供します。（30分）  コード: https://github.com/ashphy/create-your-lang
published: January 30, 26
canonical: https://convert.docswell.com/s/ashphy/Z2QXME-2026-01-30-213552
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/G789165ZJD.jpg)

自分だけの
プログラミング言語を作ろう
ashphy
@ashphy@mstdn.nere9.help
2026/01/30


# Page. 2

![Page Image](https://bcdn.docswell.com/page/L7LWQ9Y1ER.jpg)

JSONPath実装を書いています
JSONから特定のデータを取得するためのクエリ言語 (RFC 9535)
{
}
&quot;firstName&quot;: &quot;John&quot;,
&quot;lastName&quot; : &quot;doe&quot;,
&quot;age&quot;
: 26,
&quot;address&quot; : {
&quot;streetAddress&quot;: &quot;naist street&quot;,
&quot;city&quot;
: &quot;Nara&quot;,
&quot;postalCode&quot;
: &quot;630-0192&quot;
},
&quot;phoneNumbers&quot;: [
{
&quot;type&quot; : &quot;iPhone&quot;,
&quot;number&quot;: &quot;0123-4567-8888&quot;
},
{
&quot;type&quot; : &quot;home&quot;,
&quot;number&quot;: &quot;0123-4567-8910&quot;
}
]
JSON
$.phoneNumbers[:1].type
[ &quot;iPhone&quot; ]
JSONPathクエリ
取得結果
2


# Page. 3

![Page Image](https://bcdn.docswell.com/page/4EM91ZN57W.jpg)

身の回りのドメイン固有言語 (DSL)
Twitterの検索クエリの解析
movie AND (love OR hate) -scary :) since:2015-12-21
3


# Page. 4

![Page Image](https://bcdn.docswell.com/page/PERGL6DZ79.jpg)

身の回りのドメイン固有言語 (DSL)
Twitterの検索クエリの解析
両方を含む
ポジティブな感情表現を含む
movie AND (love OR hate) -scary :) since:2015-12-21
キーワード
優先順位の変更
NOT検索
期間指定
4


# Page. 5

![Page Image](https://bcdn.docswell.com/page/P7XXWM117X.jpg)

自分でプログラミング言語を作ることができたら？
5


# Page. 6

![Page Image](https://bcdn.docswell.com/page/37KWVG2M7D.jpg)

自分だけの
プログラミング言語を作ろう
6


# Page. 7

![Page Image](https://bcdn.docswell.com/page/LJ31MN42E5.jpg)

プログラム って？
7


# Page. 8

![Page Image](https://bcdn.docswell.com/page/8JDX6WQ67G.jpg)

2 + 3 * 4
8


# Page. 9

![Page Image](https://bcdn.docswell.com/page/VEPPY9GZE8.jpg)

前から処理していくだけではダメ
2 + 3 * 4
先に計算しないといけない
もちろん前から処理するだけでいい文法を考えることもできる
9


# Page. 10

![Page Image](https://bcdn.docswell.com/page/27V2GM6M7Q.jpg)

プログラムは木構造である
+
2 + 3 * 4
2
*
3
構文木
4
10


# Page. 11

![Page Image](https://bcdn.docswell.com/page/5JGR8GNX7L.jpg)

プログラムを実行する
根（ルート）から処理する
+
2 + 3 * 4
2
*
3
4
11


# Page. 12

![Page Image](https://bcdn.docswell.com/page/47QV9XQ5EP.jpg)

プログラムを実行する
＋の処理をするために子を見に行く
子がないので2を返して終わり
2 + 3 * 4
+
2
*
3
4
12


# Page. 13

![Page Image](https://bcdn.docswell.com/page/KE4MX6NV71.jpg)

プログラムを実行する
もう一方の子を見に行く
両方の子は葉なので3*4を計算
2 + 3 * 4
+
2
*
3
4
13


# Page. 14

![Page Image](https://bcdn.docswell.com/page/L718NV54JG.jpg)

プログラムを実行する
子が12の値になる
+
2 + 3 * 4
2
12
14


# Page. 15

![Page Image](https://bcdn.docswell.com/page/G7WZ4L5Z72.jpg)

プログラムを実行する
子の値がそろったので＋が計算できる
+
2 + 3 * 4
2
12
15


# Page. 16

![Page Image](https://bcdn.docswell.com/page/4JZ12MNLE3.jpg)

プログラムを実行する
実行結果が得られる
14
← 実行結果
2 + 3 * 4
16


# Page. 17

![Page Image](https://bcdn.docswell.com/page/YE6LVN8M7V.jpg)

プログラムを実行する
+
2 + 3 * 4
2
*
3
4
17


# Page. 18

![Page Image](https://bcdn.docswell.com/page/GE51D59QJ4.jpg)

プログラムを実行する
+
2 + 3 * 4
2
*
3
深さ優先探索
4
18


# Page. 19

![Page Image](https://bcdn.docswell.com/page/97218N2WER.jpg)

TypeScriptの構文木を見てみよう
サンプルコード
19


# Page. 20

![Page Image](https://bcdn.docswell.com/page/DJYZ6PY9EM.jpg)

オリジナル言語を作る
20


# Page. 21

![Page Image](https://bcdn.docswell.com/page/V7N3Z5PD78.jpg)

まずは言語仕様を決めよう
● 数値計算を行うプログラミング言語
● 数値は0以上の整数のみ
● 演算は 加算、減算、乗算のみ
● () も使える
2 * (3 + 4)
サンプルコード
21


# Page. 22

![Page Image](https://bcdn.docswell.com/page/YJ99ZY38J3.jpg)

まずは言語仕様を決めよう
● 数値計算を行うプログラミング言語
● 数値は0以上の整数のみ
● 演算は 加算、減算、乗算のみ
自然言語で書くと曖昧さが残る
● () も使える
2 * (3 + 4)
サンプルコード
22


# Page. 23

![Page Image](https://bcdn.docswell.com/page/GJ8916MZED.jpg)

文法仕様を定義するための文法 PEG
Expression:
Term ((&quot;+&quot; | &quot;-&quot;) Term)*
Term:
Factor (&quot;*&quot; Factor)*
Factor:
| &quot;(&quot; Expression &quot;)&quot;
| Integer
Integer:
[0-9]+
実際にはPEGではなく、EBNFやABNFが使われることが多い 23


# Page. 24

![Page Image](https://bcdn.docswell.com/page/LJLWQ9317R.jpg)

文法仕様を定義するための文法 PEG
Expression:
Term ((&quot;+&quot; | &quot;-&quot;) Term)*
Term:
*: 0回以上の繰り返し
| : OR
Factor (&quot;*&quot; Factor)*
正規表現の知識で読める
Factor:
| &quot;(&quot; Expression &quot;)&quot;
| Integer
Integer:
[0-9]+
[0-9]: 文字クラス
+:
1回以上の繰り返し
実際にはPEGではなく、EBNFやABNFが使われることが多い 24


# Page. 25

![Page Image](https://bcdn.docswell.com/page/47M91ZD5JW.jpg)

LL(1) の再帰下降構文解析の説明をしています
コードから構文木を構築する
Expression:
Term ((&quot;+&quot; | &quot;-&quot;) Term)*
2 * (3 + 4)
Term:
Factor (&quot;*&quot; Factor)*
Factor:
| &quot;(&quot; Expression &quot;)&quot;
| Integer
Integer:
[0-9]+
25


# Page. 26

![Page Image](https://bcdn.docswell.com/page/P7RGL64ZJ9.jpg)

LL(1) の再帰下降構文解析の説明をしています
コードから構文木を構築する
Expression:
Term ((&quot;+&quot; | &quot;-&quot;) Term)*
↓ 現在位置
2 * (3 + 4)
Term:
Factor (&quot;*&quot; Factor)*
Factor:
| &quot;(&quot; Expression &quot;)&quot;
| Integer
Integer:
[0-9]+
26


# Page. 27

![Page Image](https://bcdn.docswell.com/page/PJXXWM21JX.jpg)

LL(1) の再帰下降構文解析の説明をしています
コードから構文木を構築する
Expression:
Term ((&quot;+&quot; | &quot;-&quot;) Term)*
Term:
↓ 現在位置
2 * (3 + 4)
Expression (式)
Factor (&quot;*&quot; Factor)*
Factor:
| &quot;(&quot; Expression &quot;)&quot;
| Integer
Integer:
[0-9]+
27


# Page. 28

![Page Image](https://bcdn.docswell.com/page/3JKWVGMMJD.jpg)

LL(1) の再帰下降構文解析の説明をしています
コードから構文木を構築する
Expression:
Term ((&quot;+&quot; | &quot;-&quot;) Term)*
Term:
↓ 現在位置
2 * (3 + 4)
Expression (式)
Factor (&quot;*&quot; Factor)*
Term (項)
Factor:
| &quot;(&quot; Expression &quot;)&quot;
| Integer
Integer:
[0-9]+
28


# Page. 29

![Page Image](https://bcdn.docswell.com/page/LE31MNY275.jpg)

LL(1) の再帰下降構文解析の説明をしています
コードから構文木を構築する
Expression:
Term ((&quot;+&quot; | &quot;-&quot;) Term)*
Term:
↓ 現在位置
2 * (3 + 4)
Expression (式)
Factor (&quot;*&quot; Factor)*
Term (項)
Factor:
| &quot;(&quot; Expression &quot;)&quot;
Factor (因子)
| Integer
Integer:
[0-9]+
29


# Page. 30

![Page Image](https://bcdn.docswell.com/page/8EDX6W56JG.jpg)

LL(1) の再帰下降構文解析の説明をしています
コードから構文木を構築する
Expression:
Term ((&quot;+&quot; | &quot;-&quot;) Term)*
Term:
↓ 現在位置
2 * (3 + 4)
Expression (式)
Factor (&quot;*&quot; Factor)*
Term (項)
Factor:
| &quot;(&quot; Expression &quot;)&quot;
| Integer
Integer:
[0-9]+
Factor (因子)
?
&quot;(&quot; Expression &quot;)&quot;
Integer (整数)
30


# Page. 31

![Page Image](https://bcdn.docswell.com/page/V7PPY9DZ78.jpg)

LL(1) の再帰下降構文解析の説明をしています
コードから構文木を構築する
Expression:
↓ 現在位置
Term ((&quot;+&quot; | &quot;-&quot;) Term)*
Term:
2 * (3 + 4)
1文字先読みする
Expression (式)
Factor (&quot;*&quot; Factor)*
Term (項)
Factor:
| &quot;(&quot; Expression &quot;)&quot;
| Integer
Integer:
[0-9]+
Factor (因子)
?
&quot;(&quot; Expression &quot;)&quot;
Integer (整数)
31


# Page. 32

![Page Image](https://bcdn.docswell.com/page/2JV2GM1MJQ.jpg)

LL(1) の再帰下降構文解析の説明をしています
コードから構文木を構築する
Expression:
↓ 現在位置
Term ((&quot;+&quot; | &quot;-&quot;) Term)*
Term:
2 * (3 + 4)
1文字先読みする
Expression (式)
Factor (&quot;*&quot; Factor)*
Term (項)
Factor:
| &quot;(&quot; Expression &quot;)&quot;
| Integer
Integer:
[0-9]+
Factor (因子)
?
&quot;(&quot; Expression &quot;)&quot;
Integer (整数)
32


# Page. 33

![Page Image](https://bcdn.docswell.com/page/5EGR8G2XJL.jpg)

LL(1) の再帰下降構文解析の説明をしています
コードから構文木を構築する
Expression:
↓ 現在位置
Term ((&quot;+&quot; | &quot;-&quot;) Term)*
Term:
2 * (3 + 4)
1文字先読みする
Factor (因子)
Factor (&quot;*&quot; Factor)*
Factor:
| &quot;(&quot; Expression &quot;)&quot;
| Integer
Integer:
[0-9]+
33


# Page. 34

![Page Image](https://bcdn.docswell.com/page/4JQV9XP57P.jpg)

LL(1) の再帰下降構文解析の説明をしています
コードから構文木を構築する
Expression:
Term ((&quot;+&quot; | &quot;-&quot;) Term)*
Term:
Factor (&quot;*&quot; Factor)*
↓ 現在位置
2 * (3 + 4)
1文字先読みする
Factor (因子)
?
&quot;(&quot; Expression &quot;)&quot;
Integer (整数)
Factor:
| &quot;(&quot; Expression &quot;)&quot;
| Integer
以下繰り返し
Integer:
[0-9]+
34


# Page. 35

![Page Image](https://bcdn.docswell.com/page/K74MX6YVJ1.jpg)

コードから構文木を構築する
Expression:
Term ((&quot;+&quot; | &quot;-&quot;) Term)*
Term:
Factor (&quot;*&quot; Factor)*
2 * (3 + 4)
Expression
└── Term
├── Factor
│
└── Integer
│
└── &quot;2&quot;
├── &quot;*&quot;
└── Factor
├── &quot;(&quot;
├── Expression
Factor:
| &quot;(&quot; Expression &quot;)&quot;
| Integer
│
├── Term
│
│
│
│
└── Integer
│
│
└── &quot;3&quot;
│
├── &quot;+&quot;
│
└── Term
│
Integer:
[0-9]+
└── Factor
└── Factor
│
└── Integer
│
└── &quot;4&quot;
└── &quot;)&quot;
35


# Page. 36

![Page Image](https://bcdn.docswell.com/page/LJ18NV64EG.jpg)

コードから構文木を構築する
Expression:
Term ((&quot;+&quot; | &quot;-&quot;) Term)*
Term:
Factor (&quot;*&quot; Factor)*
2 * (3 + 4)
Expression
└── Term
├── Factor
│
└── Integer
│
└── &quot;2&quot;
├── &quot;*&quot;
└── Factor
├── &quot;(&quot;
├── Expression
Factor:
| &quot;(&quot; Expression &quot;)&quot;
| Integer
│
├── Term
│
│
│
│
└── Integer
│
│
└── &quot;3&quot;
│
├── &quot;+&quot;
│
└── Term
│
Integer:
[0-9]+
└── Factor
└── Factor
│
└── Integer
│
└── &quot;4&quot;
└── &quot;)&quot;
36


# Page. 37

![Page Image](https://bcdn.docswell.com/page/GJWZ4LWZJ2.jpg)

コードから構文木を構築する
Term:
Factor (&quot;*&quot; Factor)*
Factor:
| &quot;(&quot; Expression &quot;)&quot;
| Integer
Integer:
[0-9]+
└── Term
下に書いてる方が先に処理される
Term ((&quot;+&quot; | &quot;-&quot;) Term)*
2 * (3 + 4)
Expression
Expression:
├── Factor
│
└── Integer
│
└── &quot;2&quot;
├── &quot;*&quot;
└── Factor
├── &quot;(&quot;
├── Expression
│
├── Term
│
│
│
│
└── Integer
│
│
└── &quot;3&quot;
│
├── &quot;+&quot;
│
└── Term
│
└── Factor
└── Factor
│
└── Integer
│
└── &quot;4&quot;
└── &quot;)&quot;
() が子にあるので
先に計算される
37


# Page. 38

![Page Image](https://bcdn.docswell.com/page/4EZ12M5L73.jpg)

コードから構文木を構築する
Expression:
Term ((&quot;+&quot; | &quot;-&quot;) Term)*
Term:
Factor (&quot;*&quot; Factor)*
2 * (3 + 4)
Expression
└── Term
├── Factor
│
└── Integer
│
└── &quot;2&quot;
├── &quot;*&quot;
└── Factor
├── &quot;(&quot;
├── Expression
Factor:
| &quot;(&quot; Expression &quot;)&quot;
| Integer
│
├── Term
│
│
│
│
└── Integer
│
│
└── &quot;3&quot;
│
├── &quot;+&quot;
│
└── Term
│
Integer:
[0-9]+
└── Factor
└── Factor
│
└── Integer
│
└── &quot;4&quot;
└── &quot;)&quot;
全部は要らない
38


# Page. 39

![Page Image](https://bcdn.docswell.com/page/Y76LVN9MJV.jpg)

構文木の仕様を決めよう
これだけあれば実行できる
BinaryExpression (*)
2 * (3 + 4)
構文解析
├── Integer (2)
└── BinaryExpression (+)
├── Integer (3)
└── Integer (4)
BinaryExpression: 二項演算式
Integer:
コード
整数
構文木
39


# Page. 40

![Page Image](https://bcdn.docswell.com/page/G751D5NQE4.jpg)

パーサージェネレーターってのがある
構文解析器（パーサー）を作成するためのプログラム
● yacc / bison
○ Ruby (3.2以前)
● ANTLR
○ Hibernate HQL, Twitter検索クエリ
● PEG
○ Python (3.9以降)
40


# Page. 41

![Page Image](https://bcdn.docswell.com/page/9J218N5W7R.jpg)

ライブコーディング
文法を定義して構文解析器を作成する
41


# Page. 42

![Page Image](https://bcdn.docswell.com/page/DEYZ6PK97M.jpg)

構文木を実行する評価機を作成する
{
}
&quot;type&quot;: &quot;BinaryExpression&quot;,
&quot;operator&quot;: &quot;*&quot;,
&quot;left&quot;: {
&quot;type&quot;: &quot;Integer&quot;,
&quot;value&quot;: 2
},
&quot;right&quot;: {
&quot;type&quot;: &quot;BinaryExpression&quot;,
&quot;operator&quot;: &quot;+&quot;,
&quot;left&quot;: {
&quot;type&quot;: &quot;Integer&quot;,
&quot;value&quot;: 3
},
&quot;right&quot;: {
&quot;type&quot;: &quot;Integer&quot;,
&quot;value&quot;: 4
}
}
function evaluate(node) {
switch (node.type) {
子要素を再帰で取得する
case &quot;Integer&quot;:
= 深さ優先探索
return node.value;
case &quot;BinaryExpression&quot;: {
const left = evaluate(node.left);
const right = evaluate(node.right);
switch (node.operator) {
case &quot;+&quot;:
return left + right;
case &quot;-&quot;:
計算した値を返す
return left - right;
case &quot;*&quot;:
return left * right;
}
}
}
42
}


# Page. 43

![Page Image](https://bcdn.docswell.com/page/VJN3Z5RDJ8.jpg)

ライブコーディング
プログラムを実行してみよう
43


# Page. 44

![Page Image](https://bcdn.docswell.com/page/YE99ZYM8E3.jpg)

このままではプログラムっぽくない
44


# Page. 45

![Page Image](https://bcdn.docswell.com/page/GE8916LZ7D.jpg)

変数の概念を導入する
新しいキーワード var を導入して変数を宣言できるようにする
変数を計算に使用できる
var x = 3;
var y = x + 4;
x * 2;
サンプルコード
45


# Page. 46

![Page Image](https://bcdn.docswell.com/page/LELWQ9L1JR.jpg)

変数の文法定義
Program:
Statement*
Statement:
| VariableDeclaration
| ExpressionStatement
VariableDeclaration:
&quot;var&quot; Identifier &quot;=&quot; Expression &quot;;&quot;
Factor:
| &quot;(&quot; Expression &quot;)&quot;
| Integer
| Identifier
Identifier:
[a-zA-Z_][a-zA-Z0-9_]*
46


# Page. 47

![Page Image](https://bcdn.docswell.com/page/4JM91ZM5EW.jpg)

変数の文法定義
Program:
Statement*
プログラムは Statement (文) の集合である
Statement:
| VariableDeclaration
| ExpressionStatement
VariableDeclaration:
&quot;var&quot; Identifier &quot;=&quot; Expression &quot;;&quot;
Factor:
| &quot;(&quot; Expression &quot;)&quot;
| Integer
| Identifier
Identifier:
[a-zA-Z_][a-zA-Z0-9_]*
47


# Page. 48

![Page Image](https://bcdn.docswell.com/page/PJRGL6VZE9.jpg)

変数の文法定義
Program:
Statement*
プログラムは Statement (文) の集合である
Statement:
| VariableDeclaration
| ExpressionStatement
VariableDeclaration:
&quot;var&quot; Identifier &quot;=&quot; Expression &quot;;&quot;
変数宣言
変数に格納する値には Expression が使える
Factor:
| &quot;(&quot; Expression &quot;)&quot;
| Integer
| Identifier
Identifier:
[a-zA-Z_][a-zA-Z0-9_]*
48


# Page. 49

![Page Image](https://bcdn.docswell.com/page/PEXXWMZ1EX.jpg)

変数の文法定義
Program:
Statement*
プログラムは Statement (文) の集合である
Statement:
| VariableDeclaration
| ExpressionStatement
VariableDeclaration:
&quot;var&quot; Identifier &quot;=&quot; Expression &quot;;&quot;
変数宣言
変数に格納する値には Expression が使える
Factor:
| &quot;(&quot; Expression &quot;)&quot;
| Integer
| Identifier
値として変数が使用できる
Identifier:
[a-zA-Z_][a-zA-Z0-9_]*
変数名
49


# Page. 50

![Page Image](https://bcdn.docswell.com/page/3EKWVG8MED.jpg)

ライブコーディング
文法に変数定義を追加する
50


# Page. 51

![Page Image](https://bcdn.docswell.com/page/L731MN22J5.jpg)

変数宣言を実装する
function executeStatement(statement, env) {
switch (statement.type) {
case &quot;VariableDeclaration&quot;: {
const name = statement.id.name;
const value = evaluateExpression(statement.init, env);
env[name] = value;
return undefined;
}
case &quot;ExpressionStatement&quot;:
return evaluateExpression(statement.expression, env);
}
}
51


# Page. 52

![Page Image](https://bcdn.docswell.com/page/87DX6WZ6EG.jpg)

変数宣言を実装する
変数を格納するオブジェクト {}
function executeStatement(statement, env) {
switch (statement.type) {
case &quot;VariableDeclaration&quot;: {
const name = statement.id.name;
const value = evaluateExpression(statement.init, env);
env[name] = value;
return undefined;
}
case &quot;ExpressionStatement&quot;:
return evaluateExpression(statement.expression, env);
}
}
52


# Page. 53

![Page Image](https://bcdn.docswell.com/page/VJPPY9YZJ8.jpg)

変数宣言を実装する
変数を格納するオブジェクト {}
function executeStatement(statement, env) {
switch (statement.type) {
初期値を評価する
case &quot;VariableDeclaration&quot;: {
const name = statement.id.name;
const value = evaluateExpression(statement.init, env);
env[name] = value;
return undefined;
}
case &quot;ExpressionStatement&quot;:
return evaluateExpression(statement.expression, env);
}
}
53


# Page. 54

![Page Image](https://bcdn.docswell.com/page/2EV2GMGMEQ.jpg)

変数宣言を実装する
変数を格納するオブジェクト {}
function executeStatement(statement, env) {
switch (statement.type) {
初期値を評価する
case &quot;VariableDeclaration&quot;: {
const name = statement.id.name;
const value = evaluateExpression(statement.init, env);
env[name] = value;
return undefined;
変数を格納する
}
case &quot;ExpressionStatement&quot;:
return evaluateExpression(statement.expression, env);
}
}
54


# Page. 55

![Page Image](https://bcdn.docswell.com/page/57GR8G8XEL.jpg)

変数の読み取りを実装する
変数を格納するオブジェクト
function evaluateExpression(expression, env) {
switch (expression.type) {
case &quot;Integer&quot;:
return expression.value;
case &quot;Identifier&quot;: {
const name = expression.name;
if (!(name in env)) {
throw new ReferenceError(`Undefined variable: ${name}`);
}
return env[name];
}
55


# Page. 56

![Page Image](https://bcdn.docswell.com/page/4EQV9X95JP.jpg)

変数の読み取りを実装する
変数を格納するオブジェクト
function evaluateExpression(expression, env) {
switch (expression.type) {
case &quot;Integer&quot;:
return expression.value;
case &quot;Identifier&quot;: {
const name = expression.name;
変数が定義されているか調べる
if (!(name in env)) {
throw new ReferenceError(`Undefined variable: ${name}`);
}
return env[name];
}
56


# Page. 57

![Page Image](https://bcdn.docswell.com/page/KJ4MX6XVE1.jpg)

変数の読み取りを実装する
変数を格納するオブジェクト
function evaluateExpression(expression, env) {
switch (expression.type) {
case &quot;Integer&quot;:
return expression.value;
case &quot;Identifier&quot;: {
const name = expression.name;
変数が定義されているか調べる
if (!(name in env)) {
throw new ReferenceError(`Undefined variable: ${name}`);
}
return env[name];
変数を取り出す
}
57


# Page. 58

![Page Image](https://bcdn.docswell.com/page/LE18NVN47G.jpg)

ライブコーディング
変数の評価機能を追加する
58


# Page. 59

![Page Image](https://bcdn.docswell.com/page/GEWZ4L4ZE2.jpg)

関数も欲しいですよね？
59


# Page. 60

![Page Image](https://bcdn.docswell.com/page/47Z12M2LJ3.jpg)

関数を導入する
新しいキーワード def を導入して任意の関数を定義できるようにする
def double(x) {
return x * 2;
}
double(2);
サンプルコード
60


# Page. 61

![Page Image](https://bcdn.docswell.com/page/YJ6LVNVMEV.jpg)

関数の文法を定義する
Statement:
| FunctionDeclaration
関数宣言の追加
| VariableDeclaration
| ExpressionStatement
FunctionDeclaration:
&quot;def&quot; Identifier &quot;(&quot; ParameterList? &quot;)&quot; BlockStatement
def 関数名 (引数) ブロック
ParameterList:
Identifier ( &quot;,&quot; Identifier)*
複数個の引数が宣言できる
BlockStatement:
&quot;{&quot; BlockBodyStatement* &quot;}&quot;
BlockBodyStatement:
| ReturnStatement
関数の本体には変数宣言と式が書ける
関数の中で関数は宣言できない
| VariableDeclaration
| ExpressionStatement
ReturnStatement:
&quot;return&quot; Expression &quot;;&quot;
CallExpression:
Identifier &quot;(&quot; ArgumentList? &quot;)&quot;
ArgumentList:
Expression (&quot;,&quot; Expression)*
関数の呼び出し
61


# Page. 62

![Page Image](https://bcdn.docswell.com/page/GJ51D5DQ74.jpg)

関数宣言の実装
function executeStatement(statement, env) {
switch (statement.type) {
case &quot;FunctionDeclaration&quot;: {
const name = statement.id.name;
const fnValue = {
name,
params: statement.params ?? [],
body: statement.body,
env,
};
env[name] = fnValue;
関数本体を変数と同じ環境に保存する
return undefined;
}
62


# Page. 63

![Page Image](https://bcdn.docswell.com/page/LE31MNMZ75.jpg)

関数呼び出しの実装
function callFunction(fnValue, args) {
const localEnv = Object.create(fnValue.env);
fnValue.params.forEach((param, i) =&gt; {
const name = param.name;
localEnv[name] = args[i];
});
const result = executeBlock(fnValue.body, localEnv);
return result[RETURN] ? result.value : undefined;
}
63


# Page. 64

![Page Image](https://bcdn.docswell.com/page/8EDX6W64JG.jpg)

関数呼び出しの実装
レキシカルスコープを作成する
function callFunction(fnValue, args) {
const localEnv = Object.create(fnValue.env);
fnValue.params.forEach((param, i) =&gt; {
const name = param.name;
localEnv[name] = args[i];
});
const result = executeBlock(fnValue.body, localEnv);
return result[RETURN] ? result.value : undefined;
}
64


# Page. 65

![Page Image](https://bcdn.docswell.com/page/V7PPY9YV78.jpg)

関数呼び出しの実装
レキシカルスコープを作成する
function callFunction(fnValue, args) {
const localEnv = Object.create(fnValue.env);
fnValue.params.forEach((param, i) =&gt; {
const name = param.name;
localEnv[name] = args[i];
});
引数を積む
const result = executeBlock(fnValue.body, localEnv);
return result[RETURN] ? result.value : undefined;
}
65


# Page. 66

![Page Image](https://bcdn.docswell.com/page/2JV2GMGRJQ.jpg)

関数呼び出しの実装
レキシカルスコープを作成する
function callFunction(fnValue, args) {
const localEnv = Object.create(fnValue.env);
fnValue.params.forEach((param, i) =&gt; {
const name = param.name;
localEnv[name] = args[i];
});
引数を積む
const result = executeBlock(fnValue.body, localEnv);
return result[RETURN] ? result.value : undefined;
関数を実行
}
66


# Page. 67

![Page Image](https://bcdn.docswell.com/page/5EGR8G86JL.jpg)

ライブコーディング
関数を追加する
67


# Page. 68

![Page Image](https://bcdn.docswell.com/page/4JQV9X927P.jpg)

せっかくならコンパイラにしたい
68


# Page. 69

![Page Image](https://bcdn.docswell.com/page/K74MX6XPJ1.jpg)

実行ファイルを作る
構文木から対応する機械語を生成すればよい
いきなり機械語をしゃべるのは面倒なのでアセンブラを間に挟む
2 + 3
コード
コンパイル
mov eax, 2
mov ebx, 3
add eax, ebx
アセンブラ (x86)
アセンブル
.exe
実行可能のファイル
69


# Page. 70

![Page Image](https://bcdn.docswell.com/page/LJ18NVNXEG.jpg)

直接アセンブラを書くのも結構めんどい
mov w0, #2
mov w1, #3
add w0, w0, w1
.app (Mach-O)
macOS
AARch64
2 + 3
コード
mov eax, 2
mov ebx, 3
add eax, ebx
.exe (Portable Executable)
Windows
x86
li t0, 2
li t1, 3
add t0, t0, t1
RICS-V
.o (ELF)
Linux
70


# Page. 71

![Page Image](https://bcdn.docswell.com/page/GJWZ4L4KJ2.jpg)

LLVM
プログラムを最適化するよう設計された、任意のプログラミング言語に対応可
能なコンパイラ基盤。最適化もやってくれる。
2 + 3
コード
コンパイル
%a = add i32 2, 3
LLVM IR (中間表現)
アセンブル
.exe
実行可能のファイル
71


# Page. 72

![Page Image](https://bcdn.docswell.com/page/4EZ12M2N73.jpg)

LLVM IRの例
declare i32 @printf(ptr, ...)
C標準のprintfを使う宣言
@.fmt = private unnamed_addr constant [6 x i8] c&quot;%lld\0A\00&quot;,
align 1
def double(x) {
return x * 2;
}
double(5);
コード
define i64 @double(i64 %x) {
entry:
%t1 = alloca i64, align 8
store i64 %x, ptr %t1, align 8
%t2 = load i64, ptr %t1, align 8
%t3 = mul i64 %t2, 2
ret i64 %t3
}
define i32 @main() {
entry:
%t1 = call i64 @double(i64 5)
%t2 = getelementptr inbounds [6 x i8], ptr @.fmt, i64 0, i64 0
call i32 (ptr, ...) @printf(ptr %t2, i64 %t1)
ret i32 0
}
LLVM IR
関数宣言
かけ算
仮想レジスタ
関数呼び出し
printf
72


# Page. 73

![Page Image](https://bcdn.docswell.com/page/Y76LVNV9JV.jpg)

ライブコーディング
LLVM IRを通して
実行可能ファイルを作成する
73


# Page. 74

![Page Image](https://bcdn.docswell.com/page/G751D5DDE4.jpg)

完成したオリジナル言語
Program: Statement*
Statement: | FunctionDeclaration
| VariableDeclaration
| ExpressionStatement
FunctionDeclaration: &quot;def&quot; Identifier &quot;(&quot; ParameterList? &quot;)&quot; BlockStatement
ParameterList: Identifier (&quot;,&quot; Identifier)*
BlockStatement: &quot;{&quot; BlockBodyStatement* &quot;}&quot;
BlockBodyStatement: | ReturnStatement
| VariableDeclaration
文
法
定
義
| ExpressionStatement
ReturnStatement: &quot;return&quot; Expression &quot;;&quot;
VariableDeclaration: &quot;var&quot; Identifier &quot;=&quot; Expression &quot;;&quot;
ExpressionStatement: Expression &quot;;&quot;
Expression: Term ((&quot;+&quot; | &quot;-&quot;) Term)*
Term: Factor (&quot;*&quot; Factor)*
Factor: | CallExpression
def rectArea(w, h) {
return w * h;
}
var width = 12;
var height = 4;
rectArea(width, height);
| &quot;(&quot; Expression &quot;)&quot;
| Integer
| Identifier
CallExpression: Identifier &quot;(&quot; ArgumentList? &quot;)&quot;
ArgumentList: Expression (&quot;,&quot; Expression)*
サンプルコード
Identifier: [a-zA-Z_][a-zA-Z0-9_]*
Integer: [0-9]+
74


# Page. 75

![Page Image](https://bcdn.docswell.com/page/9J218GMM7R.jpg)

付録
75


# Page. 76

![Page Image](https://bcdn.docswell.com/page/DEYZ6VXP7M.jpg)

PEG: Parsing expression grammars
● Ford, Bryan. &quot;Parsing expression grammars: a
recognition-based syntactic foundation&quot;. SIGPLAN Not. 39.
1(2004): 111–122.
● Peggy
○ JavaScriptによるPEG実装
76


# Page. 77

![Page Image](https://bcdn.docswell.com/page/VJN3ZM1MJ8.jpg)

文法定義
● Python
● JavaScript (ECMAScript)
● JSONPath: Query Expressions for JSON (RFC9535)
77


# Page. 78

![Page Image](https://bcdn.docswell.com/page/YE99ZN5WE3.jpg)

解説
● 低レイヤを知りたい人のためのCコンパイラ作成入門
● 筑波大学 プログラミング言語処理 講義資料
78


