#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
require "curses"
def keisan(shiki, ichi=0)
  suuji=[]; enzan=[]; yuusen={'+'=>1,'-'=>1,'*'=>2,'/'=>2}
  tekiyou = ->{
    b=suuji.pop; a=suuji.pop; e=enzan.pop
    suuji << (e=='+' ? a+b : e=='-' ? a-b : e=='*' ? a*b : a/b)
  }
  yomu_atai = lambda do
    ichi += 1 while shiki[ichi]==' '
    raise "式の途中で終わりました" unless shiki[ichi]
    if shiki[ichi]=='-'
      ichi += 1
      v, ichi = yomu_atai.call
      next [-v, ichi]
    end
    if shiki[ichi]=='('
      v, ichi2 = keisan(shiki, ichi+1)
      raise "閉じカッコ ) がありません" unless shiki[ichi2]==')'
      next [v, ichi2+1]
    end
    hajime=ichi
    ichi += 1 while shiki[ichi] && shiki[ichi]=~/[0-9.]/
    raise "数値が見つかりません" if hajime==ichi
    [shiki[hajime...ichi].to_f, ichi]
  end
  atai_hoshii=true
  while ichi < shiki.length
    ichi += 1 while shiki[ichi]==' '
    break if ichi>=shiki.length || shiki[ichi]==')'
    if atai_hoshii
      v, ichi = yomu_atai.call
      suuji << v
      atai_hoshii=false
      next
    end
    e=shiki[ichi]
    raise "演算子が不正です" unless yuusen[e]
    while enzan.any? && yuusen[enzan[-1]] && yuusen[enzan[-1]] >= yuusen[e]
      tekiyou.call
    end
    enzan << e
    ichi += 1
    atai_hoshii=true
  end
  tekiyou.call while enzan.any?
  [suuji[0], ichi]
end
include Curses
init_screen
cbreak
noecho
stdscr.keypad(true)
curs_set(0)
nyuryoku=""; messeji="Enter=計算 / BS=削除 / Ctrl+L=クリア / q=終了"; kekka=""
begin
  loop do
    clear
    setpos(0,0); addstr("curses電卓（+-*/() 小数）"[0,cols-1])
    setpos(1,0); addstr(messeji[0,cols-1])
    setpos(2,0); addstr(("> "+nyuryoku)[0,cols-1])
    setpos(3,0); addstr(("= "+kekka)[0,cols-1])
    key=getch
    case key
    when 'q','Q' then break
    when 10,13
      begin
        kotae, owari = keisan(nyuryoku)
        owari += 1 while nyuryoku[owari]==' '
        raise "式の後ろに余計な文字があります" if owari < nyuryoku.length
        kekka = kotae.to_s; nyuryoku=""; messeji="計算しました"
      rescue => e
        kekka = ""; nyuryoku=""; messeji="エラー: #{e.message}"
      end
    when 12
      nyuryoku=""; kekka=""; messeji="クリアしました"
    when KEY_BACKSPACE,127,8
      nyuryoku = nyuryoku[0...-1]
    when Integer
      nyuryoku << key.chr if key>=32 && key<127
    when String
      nyuryoku << key if key.ord>=32 && key.ord<127
    end
  end
ensure
  close_screen
end
