1 module appbase.utils.expression; 2 3 import std.conv; 4 import std.variant; 5 import std.uni; 6 import std.container.dlist; 7 8 import appbase.utils.utility; 9 import appbase.utils.container.stack; 10 11 class Expression 12 { 13 double calc(string express) 14 { 15 Stack!string stackOperators; 16 Stack!double stackNumerials; 17 18 Token[] tokens = scanner(express); 19 20 string operator = string.init, topOperator = string.init; 21 double numerial = 0.0, top1Numerial = 0.0, top2Numerial = 0.0; 22 23 for (size_t i = 0; i < tokens.length; i++) 24 { 25 Token token = tokens[i]; 26 27 if (token.type == 2) 28 { 29 stackNumerials.push(token.value.get!double); 30 31 continue; 32 } 33 34 operator = token.value.get!string; 35 36 if (operator == "[") 37 { 38 stackOperators.push(operator); 39 40 continue; 41 } 42 43 if (isCalcOperator(operator)) 44 { 45 if (i >= tokens.length - 1) 46 { 47 assert(0, "Syntax error in expression: " ~ express); 48 } 49 50 Token nextToken = tokens[i + 1]; 51 52 if ((nextToken.type != 2) && (nextToken.value.get!string != "[")) 53 { 54 assert(0, "Syntax error in expression: " ~ express); 55 } 56 57 if ((stackOperators.length == 0) || (!isCalcOperator(stackOperators.back()))) 58 { 59 stackOperators.push(operator); 60 61 continue; 62 } 63 64 topOperator = stackOperators.back(); 65 66 if (getPriority(operator) > getPriority(topOperator)) 67 { 68 stackOperators.push(operator); 69 70 continue; 71 } 72 73 topOperator = stackOperators.pop(); 74 top1Numerial = stackNumerials.pop(); 75 top2Numerial = stackNumerials.pop(); 76 numerial = calc(top2Numerial, top1Numerial, topOperator); 77 stackNumerials.push(numerial); 78 79 stackOperators.push(operator); 80 81 continue; 82 } 83 84 if (operator == "]") 85 { 86 if ((stackOperators.length == 0) || (!isCalcOperator(stackOperators.back()))) 87 { 88 assert(0, "Syntax error in expression: " ~ express); 89 } 90 91 while (stackOperators.length > 0) 92 { 93 topOperator = stackOperators.pop(); 94 top1Numerial = stackNumerials.pop(); 95 top2Numerial = stackNumerials.pop(); 96 numerial = calc(top2Numerial, top1Numerial, topOperator); 97 stackNumerials.push(numerial); 98 99 if (stackOperators.length == 0) 100 { 101 assert(0, "Syntax error in expression: " ~ express); 102 } 103 104 topOperator = stackOperators.back(); 105 106 if (topOperator == "[") 107 { 108 stackOperators.pop(); 109 110 break; 111 } 112 } 113 } 114 } 115 116 while (stackOperators.length > 0) 117 { 118 topOperator = stackOperators.pop(); 119 120 if (!isCalcOperator(topOperator)) 121 { 122 assert(0, "Syntax error in expression: " ~ express); 123 } 124 125 top1Numerial = stackNumerials.pop(); 126 top2Numerial = stackNumerials.pop(); 127 numerial = calc(top2Numerial, top1Numerial, topOperator); 128 stackNumerials.push(numerial); 129 } 130 131 numerial = stackNumerials.pop(); 132 return numerial; 133 } 134 135 private: 136 137 class Token 138 { 139 int type; // 1: operator, 2: numerical 140 Variant value; 141 142 this(int type, string value) 143 { 144 this.type = type; 145 this.value = Variant(value); 146 } 147 148 this(int type, double value) 149 { 150 this.type = type; 151 this.value = Variant(value); 152 } 153 } 154 155 Token[] scanner(string express) 156 { 157 Token[] result; 158 string token = ""; 159 160 for (size_t i = 0; i < express.length; i++) 161 { 162 char ch = express[i]; 163 164 if (isWhite(ch)) 165 { 166 continue; 167 } 168 169 if (isOperator(ch)) 170 { 171 if (token != string.init) 172 { 173 result ~= new Token(2, token.to!double); 174 token = ""; 175 } 176 177 result ~= new Token(1, ch.to!string()); 178 } 179 else 180 { 181 token ~= ch; 182 } 183 } 184 185 if (token != string.init) 186 { 187 result ~= new Token(2, token.to!double); 188 } 189 190 return result; 191 } 192 193 bool isOperator(char ch) 194 { 195 return inArray!char("[]+-*/^", ch); 196 } 197 198 bool isCalcOperator(string ch) 199 { 200 return ((ch == "+") || (ch == "-") || (ch == "*") || (ch == "/") || (ch == "^")); 201 } 202 203 int getPriority(string operator) 204 { 205 if ((operator == "[") || (operator == "]")) 206 { 207 return 4; 208 } 209 210 if (operator == "^") 211 { 212 return 3; 213 } 214 215 if ((operator == "*") || (operator == "/")) 216 { 217 return 2; 218 } 219 220 if ((operator == "+") || (operator == "-")) 221 { 222 return 1; 223 } 224 225 return -1; 226 } 227 228 double calc(double numerial1, double numerial2, string operator) 229 { 230 if (operator == "+") 231 { 232 return numerial1 + numerial2; 233 } 234 else if (operator == "-") 235 { 236 return numerial1 - numerial2; 237 } 238 else if (operator == "*") 239 { 240 return numerial1 * numerial2; 241 } 242 else if (operator == "/") 243 { 244 return numerial1 / numerial2; 245 } 246 else if (operator == "^") 247 { 248 return numerial1^^numerial2; 249 } 250 251 assert(0, "Syntax error in expression, Unknown operator: " ~ operator); 252 } 253 }