2011年2月4日金曜日

D言語で簡単な計算プログラムを書いた 4

えっ?まだやってたの?


import std.conv : to; import std.math : pow; import std.stdio : writefln, readln; import std.format : format; import std.exception : collectException; alias collectException escape; real function (real, real) [char] compute; static this () { compute = [ '+' : function (real x, real y) { return x + y; }, '-' : function (real x, real y) { return x - y; }, '*' : function (real x, real y) { return x * y; }, '/' : function (real x, real y) { return !y ? error(x, y, '/') : x / y; }, '%' : function (real x, real y) { return !y ? error(x, y, '%') : x % y; }, '^' : function (real x, real y) { return pow(x, y); }, ]; } void main () { char[] line; INPUT: while (readln(line) > 2) { while ( line[$ - 1] == '\r' || line[$ - 1] == '\n' ) line = line[0 .. $ - 1]; PARSE: uint[] pos = group(line); if (pos == [uint.max, uint.max]) continue INPUT; char[] express = pos == [0, 0] ? line : line[pos[0] + 1 .. pos[1] - 1]; bool flag = true; real sum, operand; char operator; char[][] parsed; parsed = parse(express); if (parsed[$ - 1] == null) continue INPUT; sum = convert(parsed[0]); if (sum == real.max) continue INPUT; foreach (char[] part; parsed[1 .. $]) if (flag) { flag = false; operator = part[0]; } else { flag = true; operand = convert(part); if (operand == real.max) continue INPUT; sum = compute[operator] (sum, operand); if (sum == real.max) continue INPUT; } line = pos == [0, 0] ? null : ( line[0 .. pos[0]] ~ format("%.18g", sum).dup ~ line[pos[1] .. $] ); if (line != null) goto PARSE; writefln("= %.18g\n", sum); } } uint[] group (char[] express) { bool flag; uint pos, start, end; uint operand, operator; foreach (char part; express) if (flag || end && operand) break; else if (++pos && part == ' ') continue; else if (part == '(') { if (end) continue; start = pos; flag = cast(bool)(operand) ^ cast(bool)(operator) || operand > operator; } else if (part == ')') { if (end) continue; end = pos; operand = 0; operator = 0; } else if (part in compute) operator = end ? operator ? operator : pos : operator > operand ? 0 : pos; else operand = operand && end ? operand : pos; if ( cast(bool)(start) ^ cast(bool)(end) || start && end && ( flag || cast(bool)(operand) ^ cast(bool)(operator) || operand < operator ) ) { writefln("Error: %s\n", express); return [uint.max, uint.max]; } return [start, end] == [0, 0] ? [start, end] : [start - 1, end]; } char[][] parse (char[] express) { bool flag; char[][] parsed; parsed ~= [null]; foreach (char part; express) if (flag && part in compute) { flag = false; parsed ~= [part]; parsed ~= [null]; } else if (part != ' ') { flag = part == 'e' || part == 'E' ? false : true; parsed[$ - 1] ~= part; } if (parsed[$ - 1] == null) writefln("Error: %s\n", express); return parsed; } real convert (char[] numeric) { real number = real.max; if (escape(to!(real)(numeric), number)) writefln("Error: %s\n", numeric); return number; } real error (real x, real y, char z) { writefln("Error: %s %s %s\n", x, z, y); return real.max; }
文字列操作を再開発して書いてみた。このコード自体はライセンスフリーでどうぞ。
前回のコードとは違って、半角スペースを完全に無視するようになったりしてます。
Dは動的配列とかスライスとか連想配列とか無名関数とか色々と便利だわー。Cなんてもう嫌だ。

0 件のコメント:

コメントを投稿