30分で実装する自作言語もどき
この記事の目標
30分で自作言語もどきを実装する
うぷ主の環境
- macOS Catalina 10.15.7
- Node 12.16.3
手順
1. 自作言語の構文を考える
2. トランスパイル先の言語を決める
3. ファイルを読みこむ
4. トランスパイラを作る
5. トランスパイラをビルドする
トランスパイラとか難しい言葉がありますが80行ほどで実装できます
早速作っていきましょう
1. 自作言語の構文を考える
今回はjavascriptをベースにします
構文はlog "Hello World";
logでコンソールに出力
命令の間にスペースと文末に;は必須です
今回はとりあえずHello Worldだけにします
コンセプトは
pythonのように簡単な構文で
javascriptを書くなので
名前はjpyとします
2.トランスパイル先の言語を決める
今回はjavascriptです
トランスパイラもjavascriptで書きます
3.ファイルを読みこむ
Nodeには標準でファイルの入出力の機能が提供されているのでそれを利用します
スマートに書きたいのでES6で書いたのをES5にbabelでトランスパイルします
まずはモジュールを読み込みます
importfsfrom'fs';
まずはファイルの有無を判定する関数を作ります
あったらtrueなかったらfalseを返します
constcheck=(file)=>{lethasfaile=false;try{fs.statSync(file);hasfaile=true;}catch(err){hasfaile=false;}returnhasfaile;}
次はファイルを読み込みます
先ほどの関数を使ってfileがあったら読み込みます
読み込んだ結果を文字列で返します
letinpfile="";constread=(file)=>{if(check(file)){;inpfile=fs.readFileSync(file,'utf8');}returninpfile;}
4.トランスパイラを作る
今回の難所です
まず対応表を作ります
letjpy_command=["log "];letjs_command=[['console.log("',1,'");\n']];
次に変数を用意します
letout="";//出力結果
次にファイルを読み込みます
改行を消して
;ごとに区切ります
letinp=(read('src/index.jpy').replace(/\n/g,'')).split(/;/);
次は"を区切ります
for(constiininp){inp[i]=inp[i].split(/"/)}
これでトークン化的なことをした二次元配列が作成できました
最後にトランスパイル部分を作れば完成です
処理の流れは
1. 読み込み結果を一つずつ取り出す
2. jpyの命令を含んでいたら
3. javascriptの命令に変換して変数に追記
です
for(constiininp){for(constuinjpy_command){if(~inp[i][0].indexOf(jpy_command[u])){for(constfinjs_command[u]){if(typeofjs_command[u][f]=='number'){out+=inp[i][1]}else{out+=js_command[u][f]}}}}}
最後にfileを出力します
buidl_jpyを言うフォルダにbuild後のfileを出力をします
build_jpyがあったら出力
build_jpyがなかったらディレクトリを作成後出力と言う処理にします
if(check('build_jpy')){fs.writeFile('build_jpy/build.js',out,function(err){if(err){throwerr;}console.log('build成功');});}else{fs.mkdir('build_jpy',(err)=>{if(err){throwerr;}fs.writeFile('build_jpy/build.js',out,function(err){if(err){throwerr;}console.log('build成功');});});}
5. トランスパイラをビルドする
ここまでくればあとは楽勝です
babelのインストールだけですnpm init -y
npm install @babel/core @babel/cli @babel/preset-env
touch babel.config.js
constpresets=[["@babel/env",],];module.exports={presets};
./node_modules/.bin/babel src --out-dir dist
最後に実行しましょうnode dist/index.js
完成
まとめ
いつかプログラミング言語を作ってみたいと思っていましたが
そんな技術は残念ながら持ってないプログラマーによる自作言語もどきの作り方でした