#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
require "curses"
def keisan(shiki, ichi=0, ans=0.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,3] && shiki[ichi,3].downcase=="ans"
next [ans, ichi+3]
end
if shiki[ichi]=='-'
ichi += 1
v, ichi = yomu_atai.call
next [-v, ichi]
end
if shiki[ichi]=='('
v, ichi2 = keisan(shiki, ichi+1, ans)
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
curs_set(0)
nyuryoku=""; messeji="Enter=計算 / BS=削除 / Ctrl+L=クリア / q=終了"; kekka=""; ans=0.0
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
shiki = nyuryoku.strip
shiki = ans.to_s if shiki.empty?
shiki = ans.to_s + shiki if shiki.start_with?('+','*','/')
kotae, owari = keisan(shiki, 0, ans)
owari += 1 while shiki[owari]==' '
raise "式の後ろに余計な文字があります" if owari < shiki.length
ans = kotae
kekka = kotae.to_s; nyuryoku=""; messeji="計算しました(ans=#{ans})"
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