import std.string; import std.conv; import std.stdio; interface Value {} class Space : Value {} class Number : Value { const int number; this(int n) { number = n; } } interface Operator : Value { @property int priority() const; Number compute(Number a, Number b) const; } class BinOp(string op, int p) : Operator { @property int priority() const { return p; } Number compute(Number a, Number b) { return new Number(mixin("a.number"~op~"b.number")); } } Value[] lex(string s) { Operator[string] operator_table; operator_table["|"] = new BinOp!("|", 1); operator_table["^"] = new BinOp!("^", 2); operator_table["&"] = new BinOp!("&", 3); operator_table["=="] = new BinOp!("==", 4); operator_table["!="] = new BinOp!("!=", 4); operator_table["<="] = new BinOp!("<=", 5); operator_table[">="] = new BinOp!(">=", 5); operator_table["<<"] = new BinOp!("<<", 6); operator_table[">>"] = new BinOp!(">>", 6); operator_table["+"] = new BinOp!("+", 7); operator_table["-"] = new BinOp!("-", 7); operator_table["*"] = new BinOp!("*", 8); operator_table["/"] = new BinOp!("/", 8); operator_table["%"] = new BinOp!("%", 8); // 手抜きなので認識できない記号を入れると無限ループするけど仕様です Value[] values; while( s.length > 0 ) { string sp = s.munch(" "); if( sp.length > 0 ) values ~= new Space; string num = s.munch("0123456789"); if( num.length > 0 ) values ~= new Number(num.to!int()); foreach(op, p; operator_table) if( s.length >= op.length && s[0..op.length] == op ) { values ~= p; s = s[op.length..$]; } } return values; } int parse(Value[] values) { Parser p_full = new Parser; Parser p = new Parser; foreach(v; values) if( cast(Space)v ) { p_full.shift(p); p = new Parser; } else { p.shift(v); } p_full.shift(p); return p_full.final_result(); } bool back_match(T, Pat...)(T[] vs, out Pat ps) { if( vs.length < ps.length ) return false; foreach(i, ref p; ps) if( (p = cast(typeof(p))vs[$-ps.length+i]) is null ) return false; return true; } class Parser { private Value[] values; void shift(Value v) { if( auto op = cast(Operator)v ) reduce(op.priority); values ~= v; } private void reduce( int next_priority = int.min ) { Number lhs, rhs; Operator op; if( values.back_match(lhs, op, rhs) && op.priority>=next_priority ) { values.length -= 3; values ~= op.compute(lhs, rhs); reduce(next_priority); } } int final_result() { reduce(); assert( values.length == 1 ); auto n = cast(Number) values[0]; assert( n ); return n.number; } void shift(Parser p) { p.reduce(); foreach(v; p.values) this.shift(v); } } void main() { for(;;) { write("> "); string s = readln().chomp(); if( s.length == 0 ) break; try { writeln(parse(lex(s))); } catch(Throwable e) { writeln("error: ", e); } } } unittest { assert( parse(lex("1+2*3")) == 7 ); assert( parse(lex("1+2 * 3")) == 9 ); assert( parse(lex("1+2 * 3+4")) == 21 ); assert( parse(lex("123* 456-789")) == (123*(456-789)) ); }