Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
221
Task/Arithmetic-evaluation/D/arithmetic-evaluation.d
Normal file
221
Task/Arithmetic-evaluation/D/arithmetic-evaluation.d
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
import std.stdio, std.string, std.ascii, std.conv, std.array,
|
||||
std.exception, std.traits;
|
||||
|
||||
struct Stack(T) {
|
||||
T[] data;
|
||||
alias data this;
|
||||
void push(T top) pure nothrow @safe { data ~= top; }
|
||||
|
||||
T pop(bool discard = true)() pure @nogc @safe {
|
||||
immutable static exc = new immutable(Exception)("Stack Empty");
|
||||
if (data.empty)
|
||||
throw exc;
|
||||
auto top = data[$ - 1];
|
||||
static if (discard)
|
||||
data.popBack;
|
||||
return top;
|
||||
}
|
||||
}
|
||||
|
||||
enum Type { Num, OBkt, CBkt, Add, Sub, Mul, Div }
|
||||
immutable opChar = ["#", "(", ")", "+", "-", "*", "/"];
|
||||
immutable opPrec = [ 0, -9, -9, 1, 1, 2, 2];
|
||||
|
||||
abstract class Visitor { void visit(XP e) pure @safe; }
|
||||
|
||||
final class XP {
|
||||
immutable Type type;
|
||||
immutable string str;
|
||||
immutable int pos; // Optional, to display AST struct.
|
||||
XP LHS, RHS;
|
||||
|
||||
this(string s=")", int p = -1) pure nothrow @safe {
|
||||
str = s;
|
||||
pos = p;
|
||||
auto localType = Type.Num;
|
||||
foreach_reverse (immutable t; [EnumMembers!Type[1 .. $]])
|
||||
if (opChar[t] == s)
|
||||
localType = t;
|
||||
this.type = localType;
|
||||
}
|
||||
|
||||
override int opCmp(Object other) pure @safe {
|
||||
auto rhs = cast(XP)other;
|
||||
enforce(rhs !is null);
|
||||
return opPrec[type] - opPrec[rhs.type];
|
||||
}
|
||||
|
||||
void accept(Visitor v) pure @safe { v.visit(this); }
|
||||
}
|
||||
|
||||
final class AST {
|
||||
XP root;
|
||||
Stack!XP opr, num;
|
||||
string xpr, token;
|
||||
int xpHead, xpTail;
|
||||
|
||||
void joinXP(XP x) pure @safe {
|
||||
x.RHS = num.pop;
|
||||
x.LHS = num.pop;
|
||||
num.push(x);
|
||||
}
|
||||
|
||||
string nextToken() pure @safe {
|
||||
while (xpHead < xpr.length && xpr[xpHead] == ' ')
|
||||
xpHead++; // Skip spc.
|
||||
xpTail = xpHead;
|
||||
if (xpHead < xpr.length) {
|
||||
token = xpr[xpTail .. xpTail + 1];
|
||||
switch (token) {
|
||||
case "(", ")", "+", "-", "*", "/": // Valid non-number.
|
||||
xpTail++;
|
||||
return token;
|
||||
default: // Should be number.
|
||||
if (token[0].isDigit) {
|
||||
while (xpTail < xpr.length && xpr[xpTail].isDigit())
|
||||
xpTail++;
|
||||
return xpr[xpHead .. xpTail];
|
||||
} // Else may be error.
|
||||
} // End switch.
|
||||
}
|
||||
if (xpTail < xpr.length)
|
||||
throw new Exception("Invalid Char <" ~ xpr[xpTail] ~ ">");
|
||||
return null;
|
||||
} // End nextToken.
|
||||
|
||||
AST parse(in string s) /*@safe*/ {
|
||||
bool expectingOP;
|
||||
xpr = s;
|
||||
try {
|
||||
xpHead = xpTail = 0;
|
||||
num = opr = null;
|
||||
root = null;
|
||||
opr.push(new XP); // CBkt, prevent evaluate null OP precedence.
|
||||
while ((token = nextToken) !is null) {
|
||||
XP tokenXP = new XP(token, xpHead);
|
||||
if (expectingOP) { // Process OP-alike XP.
|
||||
switch (token) {
|
||||
case ")":
|
||||
while (opr.pop!false.type != Type.OBkt)
|
||||
joinXP(opr.pop);
|
||||
opr.pop;
|
||||
expectingOP = true;
|
||||
break;
|
||||
case "+", "-", "*", "/":
|
||||
while (tokenXP <= opr.pop!false)
|
||||
joinXP(opr.pop());
|
||||
opr.push(tokenXP);
|
||||
expectingOP = false;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Expecting Operator or ), not <"
|
||||
~ token ~ ">");
|
||||
}
|
||||
} else { // Process Num-alike XP.
|
||||
switch (token) {
|
||||
case "+", "-", "*", "/", ")":
|
||||
throw new Exception("Expecting Number or (, not <"
|
||||
~ token ~ ">");
|
||||
case "(":
|
||||
opr.push(tokenXP);
|
||||
expectingOP = false;
|
||||
break;
|
||||
default: // Number.
|
||||
num.push(tokenXP);
|
||||
expectingOP = true;
|
||||
}
|
||||
}
|
||||
xpHead = xpTail;
|
||||
} // End while.
|
||||
|
||||
while (opr.length > 1) // Join pending Op.
|
||||
joinXP(opr.pop);
|
||||
} catch(Exception e) {
|
||||
writefln("%s\n%s\n%s^", e.msg, xpr, " ".replicate(xpHead));
|
||||
root = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
if (num.length != 1) { // Should be one XP left.
|
||||
"Parse Error...".writefln;
|
||||
root = null;
|
||||
} else {
|
||||
root = num.pop;
|
||||
}
|
||||
return this;
|
||||
} // End Parse.
|
||||
} // End class AST.
|
||||
|
||||
// To display AST fancy struct.
|
||||
void ins(ref char[][] s, in string v, in int p, in int l)
|
||||
pure nothrow @safe {
|
||||
if (l + 1 > s.length)
|
||||
s.length++;
|
||||
while (s[l].length < p + v.length + 1)
|
||||
s[l] ~= " ";
|
||||
s[l][p .. p + v.length] = v[];
|
||||
}
|
||||
|
||||
final class CalcVis : Visitor {
|
||||
int result, level;
|
||||
string resultStr;
|
||||
char[][] Tree;
|
||||
|
||||
static void opCall(AST a) @safe {
|
||||
if (a && a.root) {
|
||||
auto c = new CalcVis;
|
||||
a.root.accept(c);
|
||||
foreach (immutable i; 1 .. c.Tree.length) { // More fancy.
|
||||
bool flipflop = false;
|
||||
enum char mk = '.';
|
||||
foreach (immutable j; 0 .. c.Tree[i].length) {
|
||||
while (j >= c.Tree[i - 1].length)
|
||||
c.Tree[i - 1] ~= " ";
|
||||
immutable c1 = c.Tree[i][j];
|
||||
immutable c2 = c.Tree[i - 1][j];
|
||||
if (flipflop && (c1 == ' ') && c2 == ' ')
|
||||
c.Tree[i - 1][j] = mk;
|
||||
if (c1 != mk && c1 != ' ' &&
|
||||
(j == 0 || !isDigit(c.Tree[i][j - 1])))
|
||||
flipflop = !flipflop;
|
||||
}
|
||||
}
|
||||
foreach (const t; c.Tree)
|
||||
t.writefln;
|
||||
writefln("\n%s ==>\n%s = %s", a.xpr, c.resultStr, c.result);
|
||||
} else
|
||||
"Evalute invalid or null Expression.".writefln;
|
||||
}
|
||||
|
||||
// Calc. the value, display AST struct and eval order.
|
||||
override void visit(XP xp) @safe {
|
||||
ins(Tree, xp.str, xp.pos, level);
|
||||
level++;
|
||||
if (xp.type == Type.Num) {
|
||||
resultStr ~= xp.str;
|
||||
result = xp.str.to!int;
|
||||
} else {
|
||||
resultStr ~= "(";
|
||||
xp.LHS.accept(this);
|
||||
immutable int lhs = result;
|
||||
resultStr ~= opChar[xp.type];
|
||||
xp.RHS.accept(this);
|
||||
resultStr ~= ")";
|
||||
switch (xp.type) {
|
||||
case Type.Add: result = lhs + result; break;
|
||||
case Type.Sub: result = lhs - result; break;
|
||||
case Type.Mul: result = lhs * result; break;
|
||||
case Type.Div: result = lhs / result; break;
|
||||
default: throw new Exception("Invalid type");
|
||||
}
|
||||
}
|
||||
level--;
|
||||
}
|
||||
}
|
||||
|
||||
void main(string[] args) /*@safe*/ {
|
||||
immutable exp0 = "1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5" ~
|
||||
" - 22/(7 + 2*(3 - 1)) - 1)) + 1";
|
||||
immutable exp = (args.length > 1) ? args[1 .. $].join(' ') : exp0;
|
||||
new AST().parse(exp).CalcVis; // Should be 60.
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue