サンプルプログラム8(PL JavaScript編)

初歩的な電卓(2)

トークンを表すデータ型の検討

全体の流れ

解析木のデータ構造

function Node(op,l,r) {
    this.op=op; this.l=l; this.r=r;
}   // この関数をオブジェクトのコンストラクタとして(new演算子で)呼ぶ

改良版スキャナ

String.prototype.scan=function() {
  return this.match(/[-+\/*%()=]|\d+(?:\.\d+)?/g).
    map(e=>{
      if(e.match(/\d+\.\d+/)) return parseFloat(e)  // 実数
      else if(e.match(/\d+/)) return parseInt(e)    // 整数
      else if(e.match(/[-+\/*%()=]/)) return sym(e) // 演算子
      else return e // おそらく文字列(変数として扱う)
    })
}

構文解析1

構文木から結果を求める(評価器)

Node.prototype.val=function(){
  function val1(ope,r,l){       // 内部でのみ使える関数、計算を実行する
    // console.log("val1",ope,r,l)
    switch(ope){
      case sym('+'): return r+l
      case sym('-'): return r-l
      case sym('*'): return r*l
      case sym('/'): return r/l
      case sym('%'): return r%l
      default:  console.log(`unknown operator ${ope.toString()}`);
        return 0  // もしここに引っかかったらエラーとして検出できるよう
    }
  }
  function val0(n){ // 内部用再帰関数 
    // console.log(n)
    switch(typeof n) {
      case 'string': return 0  // 今は仮にこうしておく
      case 'number': return n  // 値をそのまま返す
      default: // then 'this' is Node object
        var op,l,r ;   ({op,l,r}=n)
        console.log('~val1:',op,l,r)
        return val1(op,val0(l),val0(r)) // 引数に再帰呼出を使っている
    }
  }
  return val0(this)
}