言語仕様
– 文字列
– 整数123, 実数123.4
– グローバル変数、変数の値の参照
– 代入演算子(=)
– print関数でカンマ区切りで複数の引数指定
– 複数文は、セミコロンで区切る
– // から行末まではコメント
– 足し算、引き算
– 掛け算、割り算
### source.3
a = 1.24 / 2 - 1; print("a = 1.24 / 2 - 1 = ", a); b = 5 - 2 * 3; print("b = 5 - 2 * 3 = ", b);
### parse.js
module.exports = parser; var {expect, accept, show, error} = require("./utils.js"); var tokens; function parser(t){ tokens = t; var ast = semi(); if(tokens.length>0){ show("ast=", ast); show("処理後tokens =", tokens); error("tokensが余っています。"); } return ast; } function value(){ if(tokens.length == 0) return; return tokens.shift(); } function funccall(){ var left = value(); var op; while(op = accept(tokens, "(")){ var right = comma(); op += expect(tokens, ")"); left = {left, op, right}; } return left; } function mul(){ var left = funccall(); var op; while(op = accept(tokens,"*","/")){ var right = funccall(); left = {left, op, right}; } return left; } function plus(){ var left = mul(); var op; while(op = accept(tokens,"+","-")){ var right = mul(); left = {left, op, right}; } return left; } function assign(){ var left = plus(); var op; while(op = accept(tokens, "=")){ var right = comma(); left = {left, op, right}; } return left; } function comma(){ var left = assign(); var op; while(op = accept(tokens,",")){ var right = assign(); left = {left, op, right}; } return left; } function semi(){ var left = comma(); var op; while(op = accept(tokens, ";")){ var right = comma(); left = {left, op, right}; } return left; }
### run.js
const { error } = require("./utils"); module.exports = run; var global = {}; function run(a){ if(!a) return; if(!a.op){ if(a[0] == '"') return a.substr(1, a.length-2); if(/\d/.test(a[0])) return 1*a; if(global.hasOwnProperty(a)) return global[a]; return a; } else if (a.op==";"){ run(a.left); run(a.right); } else if (a.op==","){ return [run(a.left), run(a.right)].flat(); } else if (a.op=="="){ return global[run(a.left)] = run(a.right); } else if (a.op=="+"){ return run(a.left) + run(a.right); } else if (a.op=="-"){ return run(a.left) - run(a.right); } else if (a.op=="*"){ return run(a.left) * run(a.right); } else if (a.op=="/"){ return run(a.left) / run(a.right); } else if(a.op == "()") { var func = run(a.left); if(func == "print"){ var msg = [run(a.right)].flat().join(""); console.log(msg); } else { error("未実装の関数呼び出し func=", func); } } else { error("未実装の演算子 op=", a.op) } }
ASTのparse.jsで優先したいopをより深くvalueに近い位置でcallすれば、mulはplusよりも優先して処理される。