![]() |
![]() |
![]() |
Scheme 版, Python 版, JavaScript 版 に続いて今回は Ruby 版です。 基本的に Python 版と同じです。 起動時の引数がない場合は対話モードで、 ファイル名を引数に与えると、そのファイルを開いて 1行ずつ計算していきます。
紫藤は Python に慣れているので Python の方が書きやすかったです。 Ruby は
興味のある人はダウンロードして遊んでみてください。 また、いけてないところが多々あると思いますので、ご指摘いただけたら幸いです。
[calc.rb]
001: #! ruby 002: # calculator, ruby version 003: 004: 005: 006: P_CST=6 007: P_LHB=5 008: P_FUN=4 009: P_POW=3 010: P_UPM=2 011: P_MD=1 012: P_BPM=0 013: 014: 015: 016: 017: class Operator 018: 019: def initialize(name, fun, priority) 020: @name=name 021: @fun=fun 022: @priority=priority 023: end 024: 025: def to_s 026: return @name 027: end 028: 029: def call(x=nil, y=nil) 030: if self.is_constant then return @fun 031: elsif self.is_unary or self.is_lhb then return @fun.call(x) 032: elsif self.is_binary then return @fun.call(x,y) 033: end 034: end 035: 036: def >(other) 037: return (other==nil or @priority > other.priority or (self.is_reverse and @priority==other.priority)) 038: end 039: 040: def priority 041: return @priority 042: end 043: 044: def is_constant 045: return @priority==P_CST 046: end 047: 048: def is_lhb 049: return @priority==P_LHB 050: end 051: 052: def is_func 053: return @priority==P_FUN 054: end 055: 056: def is_unary 057: return (@priority == P_FUN or @priority == P_UPM) 058: end 059: 060: def is_upm 061: return @priority == P_UPM 062: end 063: 064: def is_binary 065: return (@priority == P_MD or @priority == P_BPM or @priority == P_POW) 066: end 067: 068: def is_reverse 069: return (@priority == P_FUN or @priority == P_UPM or @priority == P_POW) 070: end 071: end 072: 073: 074: def fact(n) 075: if not n.is_a?(Integer) then 076: raise "fact needs integer" 077: end 078: if n < 0 then 079: raise "fact needs positive number" 080: end 081: if n==0 then return 1 082: else 083: j=1 084: for i in 1 .. n 085: j*=i 086: end 087: return j 088: end 089: end 090: 091: def permutation(m,n) 092: if not ( n.is_a?(Integer) and m.is_a?(Integer) ) then 093: raise "P needs integer" 094: end 095: 096: if n>m then 097: raise "LHS should be larger or equal to RHS" 098: end 099: 100: return fact(m)/fact(m-n) 101: end 102: 103: 104: def combination(m,n) 105: if not ( n.is_a?(Integer) and m.is_a?(Integer) ) then 106: raise "C needs integer" 107: end 108: 109: return permutation(m,n)/fact(n) 110: end 111: 112: 113: L_OP=[ 114: Operator.new('@+', lambda{|x| +x}, P_UPM), 115: Operator.new('@-', lambda{|x| -x}, P_UPM), 116: Operator.new('+', lambda{|x,y| x+y}, P_BPM), 117: Operator.new('-', lambda{|x,y| x-y}, P_BPM), 118: Operator.new('*', lambda{|x,y| x*y}, P_MD), 119: Operator.new('/', lambda{|x,y| x/y}, P_MD), 120: Operator.new('%', lambda{|x,y| x%y}, P_MD), 121: Operator.new('**', lambda{|x,y| x**y}, P_POW), 122: Operator.new('^', lambda{|x,y| x**y}, P_POW), 123: Operator.new('exp', lambda{|x| Math.exp(x)}, P_FUN), 124: Operator.new('log', lambda{|x| Math.log(x)}, P_FUN), 125: Operator.new('log10', lambda{|x| Math.log10(x)}, P_FUN), 126: Operator.new('sqrt', lambda{|x| Math.sqrt(x)}, P_FUN), 127: Operator.new('sin', lambda{|x| Math.sin(x)}, P_FUN), 128: Operator.new('cos', lambda{|x| Math.cos(x)}, P_FUN), 129: Operator.new('tan', lambda{|x| Math.tan(x)}, P_FUN), 130: Operator.new('asin', lambda{|x| Math.asin(x)}, P_FUN), 131: Operator.new('acos', lambda{|x| Math.acos(x)}, P_FUN), 132: Operator.new('atan', lambda{|x| Math.atan(x)}, P_FUN), 133: Operator.new('pi', Math::PI, P_CST), 134: Operator.new('e', Math::E, P_CST), 135: Operator.new('!', lambda{|x| fact(x)}, P_LHB), 136: Operator.new('P', lambda{|x,y| permutation(x,y)}, P_POW), 137: Operator.new('C', lambda{|x,y| combination(x,y)}, P_POW), 138: ] 139: 140: H_OP=Hash.new 141: L_OP.each{|op| H_OP[op.to_s] = op} 142: 143: 144: $r_fe=Regexp.new( 145: '^(?:(\()|(\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)|(' + 146: L_OP.delete_if{|op| 147: op.is_upm 148: }.map{|op| 149: op.to_s 150: }.sort{|x,y| 151: y.length <=> x.length 152: }.map{|s| 153: s.split('').map{|c| c.match(/w/) ? c : ('\' + c)}.join('') + 154: (H_OP[s].is_constant ? '(?=\W|$)' : H_OP[s].is_func ? '(?=\s|\()' : '') 155: }.join('|') + 156: '))') 157: 158: 159: 160: def find_close(s) 161: pos=0 162: count=0 163: s.each_byte{|c| 164: count += (c==40 ? 1 : c==41 ? -1 : 0) # ( -> 40, ) -> 41 165: if (pos > 0 and count==0) then 166: return pos 167: end 168: pos+=1 169: } 170: return -1 171: end 172: 173: 174: 175: def read_input(s0, ls=[]) 176: 177: s0.strip! 178: 179: if s0.length==0 then 180: return ls 181: end 182: 183: m=$r_fe.match(s0) 184: if not m then 185: raise "cannot parse input" 186: end 187: 188: if m[1] then 189: j=find_close(s0) 190: read_input(s0[j+1, s0.length], ls << read_input(s0[1, j-1])) 191: elsif m[2] then 192: read_input(s0[m.end(2), s0.length], ls << (m[2].match(/^d+$/) ? m[2].to_i : m[2].to_f)) 193: elsif m[3] then 194: read_input(s0[m.end(3), s0.length], 195: ls << H_OP[ 196: ((m[3]=='+' or m[3]=='-') and 197: (ls.length==0 or ls[-1].class== Operator)) ? 198: '@' + m[3] : m[3] 199: ]) 200: end 201: end 202: 203: 204: def operator_position(ls) 205: max_operator=nil 206: j=-1 207: ls.each_index{|i| 208: obj=ls[i] 209: if (obj.class==Operator and obj>max_operator) then 210: max_operator=obj 211: j=i 212: end 213: } 214: return j 215: end 216: 217: 218: def fappend(ls, val, pos1, pos2) 219: return (ls[0, pos1] << val) + ls[pos2, ls.length] 220: end 221: 222: 223: def is_number(ls) 224: return (ls.class==Float or ls.is_a?(Integer)) 225: end 226: 227: 228: def eval_formula(ls) 229: if is_number(ls) then 230: return ls 231: elsif ls.class==Operator and ls.is_constant then 232: return ls.call 233: elsif ls.length==1 then 234: return eval_formula(ls[0]) 235: else 236: pos = operator_position(ls) 237: op = ls[pos] 238: if op.is_constant then 239: return eval_formula(fappend(ls, op.call, pos, pos+1)) 240: elsif op.is_unary and pos < ls.length - 1 then 241: return eval_formula(fappend(ls, op.call(eval_formula(ls[pos+1])), pos, pos+2)) 242: elsif op.is_lhb and pos > 0 then 243: return eval_formula(fappend(ls, op.call(eval_formula(ls[pos-1])), pos-1, pos+1)) 244: elsif op.is_binary and 0 < pos and pos < ls.length - 1 then 245: return eval_formula(fappend(ls, op.call(eval_formula(ls[pos-1]), eval_formula(ls[pos+1])), pos-1, pos+2)) 246: else 247: raise "invalid formula" 248: end 249: end 250: end 251: 252: 253: #------ 254: 255: interactive= (ARGV.length==0) 256: 257: if interactive then 258: print "avairable opereters and constants are: " 259: print L_OP.delete_if{|op| op.is_upm}.map{|op| op.to_s}.join(', ') 260: print " " 261: end 262: 263: while 1 264: if interactive then print '> ' end 265: s=gets 266: if not s then break end 267: s.chomp! 268: if s.length>0 then 269: if (interactive and s=='q') then break end 270: begin 271: p eval_formula(read_input(s)) 272: rescue => em 273: p em 274: end 275: else 276: print " " 277: end 278: end
![]() |
![]() |
![]() |