diff options
| author | Henrik Rydberg <rydberg@euromail.se> | 2011-10-08 20:30:28 +0200 |
|---|---|---|
| committer | Henrik Rydberg <rydberg@euromail.se> | 2011-10-08 20:30:28 +0200 |
| commit | 5df79c53745fde5d6c3340a2979b1429cd5892c1 (patch) | |
| tree | 1a81af141708b826e9c61e8a04019994fcca8298 /src/ops | |
Initial import of htcd system 1.0
Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
Diffstat (limited to 'src/ops')
| -rw-r--r-- | src/ops/basic.cc | 269 | ||||
| -rw-r--r-- | src/ops/comp.cc | 134 | ||||
| -rw-r--r-- | src/ops/express.cc | 173 | ||||
| -rw-r--r-- | src/ops/express.h | 79 | ||||
| -rw-r--r-- | src/ops/latex.cc | 101 | ||||
| -rw-r--r-- | src/ops/nnstyle.h | 53 | ||||
| -rw-r--r-- | src/ops/operator.cc | 44 | ||||
| -rw-r--r-- | src/ops/operator.h | 97 | ||||
| -rw-r--r-- | src/ops/string.cc | 274 | ||||
| -rw-r--r-- | src/ops/test.cc | 161 |
10 files changed, 1385 insertions, 0 deletions
diff --git a/src/ops/basic.cc b/src/ops/basic.cc new file mode 100644 index 0000000..b30e351 --- /dev/null +++ b/src/ops/basic.cc | |||
| @@ -0,0 +1,269 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <ops/operator.h> | ||
| 21 | #include <math.h> | ||
| 22 | |||
| 23 | OP1_IMPL(exp) { out<<exp(atof(a)); } | ||
| 24 | OP1_IMPL(ln) { out<<log(atof(a)); } | ||
| 25 | OP1_IMPL(abs) { out<<fabs(atof(a)); } | ||
| 26 | OP1_IMPL(int) { out<<int(atof(a)); } | ||
| 27 | |||
| 28 | OP1_IMPL(minus) { out<<-atof(a); } | ||
| 29 | OP2_IMPL(minus) { out<<atof(L)-atof(R); } | ||
| 30 | OP1_IMPL(plus) { out<<atof(a); } | ||
| 31 | OP2_IMPL(plus) { out<<atof(L)+atof(R); } | ||
| 32 | OP2_IMPL(mul) { out<<atof(L)*atof(R); } | ||
| 33 | OP2_IMPL(divide) { out<<atof(L)/atof(R); } | ||
| 34 | OP2_IMPL(mod) { | ||
| 35 | double a=atof(L),b=atof(R); | ||
| 36 | a-=b*int(a/b); | ||
| 37 | if(a<0) a+=fabs(b); | ||
| 38 | out<<a; | ||
| 39 | } | ||
| 40 | OP2_IMPL(imod) { out<<(atoi(L)%atoi(R)); } | ||
| 41 | OP2_IMPL(div) { out<<(atoi(L)/atoi(R)); } | ||
| 42 | OP2_IMPL(pow) { out<<pow(atof(L),atof(R)); } | ||
| 43 | |||
| 44 | OP2_IMPL(eq) {out<<(L==R); } | ||
| 45 | OP2_IMPL(ne) {out<<(L!=R);} | ||
| 46 | OP2_IMPL(eqn) {out<<(L.compare(R,cset_lcase)==0);} | ||
| 47 | OP2_IMPL(nen) {out<<(L.compare(R,cset_lcase)!=0);} | ||
| 48 | OP2_IMPL(eqf) {out<<(atof(L)==atof(R));} | ||
| 49 | OP2_IMPL(nef) {out<<(atof(L)!=atof(R));} | ||
| 50 | |||
| 51 | OP1_IMPL(not) {out<<!atob(a);} | ||
| 52 | OP2_IMPL(and) {out<<(atob(L)&atob(R)); } | ||
| 53 | OP2_IMPL(or) {out<<(atob(L)|atob(R)); } | ||
| 54 | OP2_IMPL(xor) {out<<(atob(L)^atob(R)); } | ||
| 55 | |||
| 56 | OP2_IMPL(shiftleft) {out<<(atoi(L)<<atoi(R));} | ||
| 57 | OP2_IMPL(shiftright) {out<<(atoi(L)>>atoi(R));} | ||
| 58 | |||
| 59 | OP1_IMPL(bitnot) {out<<~atoi(a);} | ||
| 60 | OP2_IMPL(bitand) {out<<(atoi(L)&atoi(R)); } | ||
| 61 | OP2_IMPL(bitor) {out<<(atoi(L)|atoi(R)); } | ||
| 62 | OP2_IMPL(bitxor) {out<<(atoi(L)^atoi(R)); } | ||
| 63 | |||
| 64 | OP2_IMPL(SP) {out<<L<<" "<<R;} | ||
| 65 | |||
| 66 | OP2_IMPL(comma) {out<<R;} | ||
| 67 | |||
| 68 | OP1_IMPL(semi) {} | ||
| 69 | OP2_IMPL(semi) {} | ||
| 70 | |||
| 71 | void opAddBasic(opmap& M) | ||
| 72 | { | ||
| 73 | OP_ADD(32,exp, | ||
| 74 | "C style\n" | ||
| 75 | "Natural exponential function\n" | ||
| 76 | "Syntax: exp (real)\n" | ||
| 77 | "Returns: (real)\n" | ||
| 78 | ); | ||
| 79 | OP_ADD(32,ln, | ||
| 80 | "C style\n" | ||
| 81 | "Natural logarithm function\n" | ||
| 82 | "Syntax: ln (real)\n" | ||
| 83 | "Returns: (real)\n" | ||
| 84 | ); | ||
| 85 | OP_ADD(32,abs, | ||
| 86 | "C style\n" | ||
| 87 | "Absolute value\n" | ||
| 88 | "Syntax: abs (real)\n" | ||
| 89 | "Returns: (real)\n" | ||
| 90 | ); | ||
| 91 | OP_ADD(32,int, | ||
| 92 | "C style\n" | ||
| 93 | "Integer truncation\n" | ||
| 94 | "Syntax: int (real)\n" | ||
| 95 | "Returns: (int)\n" | ||
| 96 | "\n" | ||
| 97 | "Note that truncation is just as when converting to int, not rounding\n" | ||
| 98 | ); | ||
| 99 | |||
| 100 | OP_ADDN(30,bitnot,~, | ||
| 101 | "C style\n" | ||
| 102 | "Bitwise NOT\n" | ||
| 103 | "Syntax: ~ (int)\n" | ||
| 104 | "Returns: (int)\n" | ||
| 105 | ); | ||
| 106 | OP_ADDN(30,not,!, | ||
| 107 | "C style\n" | ||
| 108 | "Logical NOT\n" | ||
| 109 | "Syntax: ! (int)\n" | ||
| 110 | "Returns: (int)\n" | ||
| 111 | ); | ||
| 112 | OP_ADD2(30,24,plus,+, | ||
| 113 | "C style\n" | ||
| 114 | "Addition\n" | ||
| 115 | "Syntax: (real) + (real)\n" | ||
| 116 | "Returns: (real)\n" | ||
| 117 | ); | ||
| 118 | OP_ADD2(30,24,minus,-, | ||
| 119 | "C style\n" | ||
| 120 | "Subtraction\n" | ||
| 121 | "Syntax: (real) - (real)\n" | ||
| 122 | "Returns: (real)\n" | ||
| 123 | ); | ||
| 124 | |||
| 125 | OP_ADDN(27,pow,**, | ||
| 126 | "Power\n" | ||
| 127 | "Syntax: (real) a ** (real) b\n" | ||
| 128 | "Returns: (real) a to the power of b\n" | ||
| 129 | ); | ||
| 130 | |||
| 131 | OP_ADDN(26,mul,*, | ||
| 132 | "C style\n" | ||
| 133 | "Multiplication\n" | ||
| 134 | "Syntax: (real) * (real)\n" | ||
| 135 | "Returns: (real)\n" | ||
| 136 | ); | ||
| 137 | OP_ADDN(26,divide,/, | ||
| 138 | "C style\n" | ||
| 139 | "Division\n" | ||
| 140 | "Syntax: (real) / (real)\n" | ||
| 141 | "Returns: (real)\n" | ||
| 142 | "\n" | ||
| 143 | "Note computerese; same precedence as *\n" | ||
| 144 | ); | ||
| 145 | OP_ADDN(26,imod,%, | ||
| 146 | "C style\n" | ||
| 147 | "Integer modulus\n" | ||
| 148 | "Syntax: (int) % (int)\n" | ||
| 149 | "Returns: (int)\n" | ||
| 150 | ); | ||
| 151 | |||
| 152 | OP_ADD(25,div, | ||
| 153 | "Integer division\n" | ||
| 154 | "Syntax: (int) div (int)\n" | ||
| 155 | "Returns: (int)\n" | ||
| 156 | "\n" | ||
| 157 | "Note that this is the same as integer / in C, but with lower precedence\n" | ||
| 158 | ); | ||
| 159 | // plus/minus 24 | ||
| 160 | OP_ADD(23,mod, | ||
| 161 | "General moulus\n" | ||
| 162 | "Syntax: (real) mod (real)\n" | ||
| 163 | "Returns: (real)\n" | ||
| 164 | "\n" | ||
| 165 | "Modulus on ring; negative vals are mapped onto base\n" | ||
| 166 | ); | ||
| 167 | |||
| 168 | OP_ADDN(22,shiftleft,<<, | ||
| 169 | "C style\n" | ||
| 170 | "Shift left\n" | ||
| 171 | "Syntax: (int) << (int)\n" | ||
| 172 | "Returns: (int)\n" | ||
| 173 | ); | ||
| 174 | OP_ADDN(22,shiftright,>>, | ||
| 175 | "C style\n" | ||
| 176 | "Shift right\n" | ||
| 177 | "Syntax: (int) >> (int)\n" | ||
| 178 | "Returns: (int)\n" | ||
| 179 | ); | ||
| 180 | |||
| 181 | OP_ADD(18,eq, | ||
| 182 | "Lexicographic equal\n" | ||
| 183 | "Syntax: (string) eq (string)\n" | ||
| 184 | "Returns: (int)\n" | ||
| 185 | ); | ||
| 186 | OP_ADD(18,eqn, | ||
| 187 | "Lexicographic equal, case insensitive\n" | ||
| 188 | "Syntax: (string) eqn (string)\n" | ||
| 189 | "Returns: (int)\n" | ||
| 190 | ); | ||
| 191 | OP_ADDN(18,eqf,==, | ||
| 192 | "Arithmetic equal\n" | ||
| 193 | "Syntax: (real) == (real)\n" | ||
| 194 | "Returns: (int)\n" | ||
| 195 | ); | ||
| 196 | OP_ADD(18,ne, | ||
| 197 | "Lexicographic not equal\n" | ||
| 198 | "Syntax: (string) ne (string)\n" | ||
| 199 | "Returns: (int)\n" | ||
| 200 | ); | ||
| 201 | OP_ADD(18,nen, | ||
| 202 | "Lexicographic not equal, case insensitive\n" | ||
| 203 | "Syntax: (string) nen (string)\n" | ||
| 204 | "Returns: (int)\n" | ||
| 205 | ); | ||
| 206 | OP_ADDN(18,nef,!=, | ||
| 207 | "Arithmetic not equal\n" | ||
| 208 | "Syntax: (real) != (real)\n" | ||
| 209 | "Returns: (int)\n" | ||
| 210 | ); | ||
| 211 | |||
| 212 | OP_ADDN(16,bitand,&, | ||
| 213 | "C style\n" | ||
| 214 | "Bitwise AND\n" | ||
| 215 | "Syntax: (int) & (int)\n" | ||
| 216 | "Returns: (int)\n" | ||
| 217 | ); | ||
| 218 | OP_ADDN(14,bitxor,^, | ||
| 219 | "C style\n" | ||
| 220 | "Bitwise XOR\n" | ||
| 221 | "Syntax: (int) ^ (int)\n" | ||
| 222 | "Returns: (int)\n" | ||
| 223 | ); | ||
| 224 | OP_ADDN(12,bitor,|, | ||
| 225 | "C style\n" | ||
| 226 | "Bitwise OR\n" | ||
| 227 | "Syntax: (int) | (int)\n" | ||
| 228 | "Returns: (int)\n" | ||
| 229 | ); | ||
| 230 | |||
| 231 | OP_ADDN(10,and,&&, | ||
| 232 | "C style\n" | ||
| 233 | "Logical AND\n" | ||
| 234 | "Syntax: (int) && (int)\n" | ||
| 235 | "Returns: (int)\n" | ||
| 236 | ); | ||
| 237 | OP_ADDN(9,xor,^^, | ||
| 238 | "Logical XOR\n" | ||
| 239 | "Syntax: (int) ^^ (int)\n" | ||
| 240 | "Returns: (int)\n" | ||
| 241 | ); | ||
| 242 | OP_ADDN(8,or,||, | ||
| 243 | "C style\n" | ||
| 244 | "Logical OR\n" | ||
| 245 | "Syntax: (int) || (int)\n" | ||
| 246 | "Returns: (int)\n" | ||
| 247 | ); | ||
| 248 | |||
| 249 | /* | ||
| 250 | OP_ADD(3,SP, | ||
| 251 | "Whitespace padding\n" | ||
| 252 | "Syntax: a ws OR ws a OR a ws b\n" | ||
| 253 | "Returns: a b\n" | ||
| 254 | ); | ||
| 255 | */ | ||
| 256 | |||
| 257 | M.add(new op_t(",",2,impl_comma, | ||
| 258 | "C style\n" | ||
| 259 | "Separate expression\n" | ||
| 260 | "Syntax: a , b\n" | ||
| 261 | "Returns: b\n" | ||
| 262 | )); | ||
| 263 | OP_ADD2(1,1,semi,;, | ||
| 264 | "C style\n" | ||
| 265 | "End expression\n" | ||
| 266 | "Syntax: a ; OR a ; b\n" | ||
| 267 | "Returns: nothing\n" | ||
| 268 | ); | ||
| 269 | } | ||
diff --git a/src/ops/comp.cc b/src/ops/comp.cc new file mode 100644 index 0000000..aa40246 --- /dev/null +++ b/src/ops/comp.cc | |||
| @@ -0,0 +1,134 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <ops/operator.h> | ||
| 21 | #include <ops/nnstyle.h> | ||
| 22 | |||
| 23 | OP2_IMPL(lt) {out<<(L<R);} | ||
| 24 | OP2_IMPL(le) {out<<(L<=R);} | ||
| 25 | OP2_IMPL(ge) {out<<(L>=R);} | ||
| 26 | OP2_IMPL(gt) {out<<(L>R);} | ||
| 27 | OP2_IMPL(ltn) {out<<(L.compare(R,cset_lcase)<0);} | ||
| 28 | OP2_IMPL(len) {out<<(L.compare(R,cset_lcase)<=0);} | ||
| 29 | OP2_IMPL(gen) {out<<(L.compare(R,cset_lcase)>=0);} | ||
| 30 | OP2_IMPL(gtn) {out<<(L.compare(R,cset_lcase)>0);} | ||
| 31 | OP2_IMPL(ltnn) {out<<(nncomp(L,R)<0);} | ||
| 32 | OP2_IMPL(lenn) {out<<(nncomp(L,R)<=0);} | ||
| 33 | OP2_IMPL(genn) {out<<(nncomp(L,R)>=0);} | ||
| 34 | OP2_IMPL(gtnn) {out<<(nncomp(L,R)>0);} | ||
| 35 | OP2_IMPL(ltf) {out<<(atof(L)<atof(R));} | ||
| 36 | OP2_IMPL(lef) {out<<(atof(L)<=atof(R));} | ||
| 37 | OP2_IMPL(gef) {out<<(atof(L)>=atof(R));} | ||
| 38 | OP2_IMPL(gtf) {out<<(atof(L)>atof(R));} | ||
| 39 | |||
| 40 | void opAddComp(opmap& M) | ||
| 41 | { | ||
| 42 | OP_ADD(20,lt, | ||
| 43 | "Lexicographic less than\n" | ||
| 44 | "Syntax: (string) lt (string)\n" | ||
| 45 | "Returns: (int)\n" | ||
| 46 | ); | ||
| 47 | OP_ADD(20,le, | ||
| 48 | "Lexicographic less or equal\n" | ||
| 49 | "Syntax: (string) le (string)\n" | ||
| 50 | "Returns: (int)\n" | ||
| 51 | ); | ||
| 52 | OP_ADD(20,ge, | ||
| 53 | "Lexicographic greater or equal\n" | ||
| 54 | "Syntax: (string) ge (string)\n" | ||
| 55 | "Returns: (int)\n" | ||
| 56 | ); | ||
| 57 | OP_ADD(20,gt, | ||
| 58 | "Lexicographic greater than\n" | ||
| 59 | "Syntax: (string) gt (string)\n" | ||
| 60 | "Returns: (int)\n" | ||
| 61 | ); | ||
| 62 | |||
| 63 | OP_ADD(20,ltn, | ||
| 64 | "Lexicographic less than, case insensitive\n" | ||
| 65 | "Syntax: (string) ltn (string)\n" | ||
| 66 | "Returns: (int)\n" | ||
| 67 | ); | ||
| 68 | OP_ADD(20,len, | ||
| 69 | "Lexicographic less or equal, case insensitive\n" | ||
| 70 | "Syntax: (string) len (string)\n" | ||
| 71 | "Returns: (int)\n" | ||
| 72 | ); | ||
| 73 | OP_ADD(20,gen, | ||
| 74 | "Lexicographic greater or equal, case insensitive\n" | ||
| 75 | "Syntax: (string) gen (string)\n" | ||
| 76 | "Returns: (int)\n" | ||
| 77 | ); | ||
| 78 | OP_ADD(20,gtn, | ||
| 79 | "Lexicographic greater than, case insensitive\n" | ||
| 80 | "Syntax: (string) gtn (string)\n" | ||
| 81 | "Returns: (int)\n" | ||
| 82 | ); | ||
| 83 | |||
| 84 | OP_ADD(20,ltnn, | ||
| 85 | "Lexicographic less than, NN-style\n" | ||
| 86 | "Syntax: (string) ltnn (string)\n" | ||
| 87 | "Returns: (int)\n" | ||
| 88 | "\n" | ||
| 89 | "NN-style compares names as <lastname> <initials>\n" | ||
| 90 | ); | ||
| 91 | OP_ADD(20,lenn, | ||
| 92 | "Lexicographic less or equal, NN-style\n" | ||
| 93 | "Syntax: (string) lenn (string)\n" | ||
| 94 | "Returns: (int)\n" | ||
| 95 | "\n" | ||
| 96 | "NN-style compares names as <lastname> <initials>\n" | ||
| 97 | ); | ||
| 98 | OP_ADD(20,genn, | ||
| 99 | "Lexicographic greater or equal, NN-style\n" | ||
| 100 | "Syntax: (string) genn (string)\n" | ||
| 101 | "Returns: (int)\n" | ||
| 102 | "\n" | ||
| 103 | "NN-style compares names as <lastname> <initials>\n" | ||
| 104 | ); | ||
| 105 | OP_ADD(20,gtnn, | ||
| 106 | "Lexicographic greater than, NN-style\n" | ||
| 107 | "Syntax: (string) gtnn (string)\n" | ||
| 108 | "Returns: (int)\n" | ||
| 109 | "\n" | ||
| 110 | "NN-style compares names as <lastname> <initials>\n" | ||
| 111 | ); | ||
| 112 | |||
| 113 | OP_ADDN(20,ltf,<, | ||
| 114 | "Arithmetic less than\n" | ||
| 115 | "Syntax: (real) < (real)\n" | ||
| 116 | "Returns: (int)\n" | ||
| 117 | ); | ||
| 118 | OP_ADDN(20,lef,<=, | ||
| 119 | "Arithmetic less or equal\n" | ||
| 120 | "Syntax: (real) <= (real)\n" | ||
| 121 | "Returns: (int)\n" | ||
| 122 | ); | ||
| 123 | OP_ADDN(20,gef,>=, | ||
| 124 | "Arithmetic greater or equal\n" | ||
| 125 | "Syntax: (real) >= (real)\n" | ||
| 126 | "Returns: (int)\n" | ||
| 127 | ); | ||
| 128 | OP_ADDN(20,gtf,>, | ||
| 129 | "Arithmetic greater than\n" | ||
| 130 | "Syntax: (real) > (real)\n" | ||
| 131 | "Returns: (int)\n" | ||
| 132 | ); | ||
| 133 | |||
| 134 | } | ||
diff --git a/src/ops/express.cc b/src/ops/express.cc new file mode 100644 index 0000000..2cd3114 --- /dev/null +++ b/src/ops/express.cc | |||
| @@ -0,0 +1,173 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <ops/express.h> | ||
| 21 | |||
| 22 | const mstring sp_tag="SP"; | ||
| 23 | |||
| 24 | //////////////////////////////////////////////////////////////// | ||
| 25 | |||
| 26 | uniheap<sizeof(expr_t)> expr_t::tree; | ||
| 27 | void* expr_t::operator new(size_t n) { return tree.push(); } | ||
| 28 | void expr_t::operator delete(void* p) { tree.pop(p); } | ||
| 29 | |||
| 30 | //////////////////////////////////////////////////////////////// | ||
| 31 | |||
| 32 | inline int precedence(const expr_t* root,const op_t* op) | ||
| 33 | { | ||
| 34 | if(!root->op) return 1; | ||
| 35 | else if(!op) return 0; | ||
| 36 | else if(root->left) { | ||
| 37 | if(root->right) return op->pre2&&root->op->pre2>=op->pre2; | ||
| 38 | else return root->op->pre2>=op->pre1; | ||
| 39 | } | ||
| 40 | else { | ||
| 41 | if(root->right) return op->pre2&&root->op->pre1>=op->pre2; | ||
| 42 | else return root->op->pre1>=op->pre1; | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | static int ins_node_sp(expr_t*& root,op_env& env, | ||
| 47 | const sref& in,const op_t* op) throw(merror_t) | ||
| 48 | { | ||
| 49 | if(root==0) { root=new expr_t(in,op); root->expand(env); return 1; } | ||
| 50 | else if(precedence(root,op)) { | ||
| 51 | if(op) { root=new expr_t(in,op,root); return 1; } else return 0; | ||
| 52 | } | ||
| 53 | else return ins_node_sp(root->right,env,in,op); | ||
| 54 | } | ||
| 55 | |||
| 56 | static void ins_node(expr_t*& root,op_env& env,const sref& in) throw(merror_t) | ||
| 57 | { | ||
| 58 | const op_t* op=env.ops->get(in); | ||
| 59 | if(!ins_node_sp(root,env,in,op)) { | ||
| 60 | if(!ins_node_sp(root,env,sp_tag,env.ops->get(sp_tag))) | ||
| 61 | THROW("ops: ("<<root->expr<<" ["<<in<<"]): operator expected"); | ||
| 62 | ins_node_sp(root,env,in,op); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | /////////////////////////////////////////////////////////////// | ||
| 67 | |||
| 68 | void expr_t::clear() | ||
| 69 | { | ||
| 70 | expr.clear(); | ||
| 71 | op=0; | ||
| 72 | status=OP_ALL; | ||
| 73 | result.clear(); | ||
| 74 | delete left; left=0; | ||
| 75 | delete right; right=0; | ||
| 76 | } | ||
| 77 | |||
| 78 | void expr_t::copy(const expr_t& x) | ||
| 79 | { | ||
| 80 | expr=x.expr; | ||
| 81 | op=x.op; | ||
| 82 | if(x.left) left=new expr_t(*x.left); | ||
| 83 | if(x.right) right=new expr_t(*x.right); | ||
| 84 | } | ||
| 85 | |||
| 86 | void expr_t::trav(mstream& out,int n) | ||
| 87 | { | ||
| 88 | if(n&&left) left->trav(out,n-1); | ||
| 89 | for(int i=0;i<3*n;i++) out.put(' '); | ||
| 90 | out<<"["<<expr<<"]("<<status<<") -> "<<result<<"\n"; | ||
| 91 | if(n&&right) right->trav(out,n-1); | ||
| 92 | } | ||
| 93 | |||
| 94 | void expr_t::expand(op_env& env) throw(merror_t) | ||
| 95 | { | ||
| 96 | if(!op) { | ||
| 97 | sref first,rest=expr; | ||
| 98 | env.split(first,rest); | ||
| 99 | if(first!=expr) { | ||
| 100 | do ins_node(right,env,first); | ||
| 101 | while(env.split(first,rest)); | ||
| 102 | } | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | /////////////////////////////////////////////////////////////// | ||
| 107 | |||
| 108 | void expr_t::eval(mstream& out,op_env& env,int opt) throw(merror_t) | ||
| 109 | { | ||
| 110 | if(op) { | ||
| 111 | if(left) { | ||
| 112 | if(op->left>1) { | ||
| 113 | if(left->status&opt) { | ||
| 114 | swrite sw(left->result); | ||
| 115 | left->eval(sw,env,opt); | ||
| 116 | } | ||
| 117 | } | ||
| 118 | else if(!op->left) | ||
| 119 | THROW("ops: ("<<left->expr<<" ["<<expr<<"]): not an L operator") | ||
| 120 | else if(left->op) | ||
| 121 | THROW("ops: (["<<left->expr<<"] "<<expr<<"): Lvalue required") | ||
| 122 | else { | ||
| 123 | left->status=OP_LOCAL; | ||
| 124 | left->result=left->expr; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | if(right) { | ||
| 128 | if(op->right>1) { | ||
| 129 | if(right->status&opt) { | ||
| 130 | swrite sw(right->result); | ||
| 131 | right->eval(sw,env,opt); | ||
| 132 | } | ||
| 133 | } | ||
| 134 | else if(!op->right) | ||
| 135 | THROW("ops: ("<<right->expr<<" ["<<expr<<"]): not an R operator") | ||
| 136 | else if(right->op) | ||
| 137 | THROW("ops: (["<<right->expr<<"] "<<expr<<"): Lvalue required") | ||
| 138 | else { | ||
| 139 | right->status=OP_LOCAL; | ||
| 140 | right->result=right->expr; | ||
| 141 | } | ||
| 142 | } | ||
| 143 | if(left) { | ||
| 144 | if(right) { | ||
| 145 | status=left->status|right->status; | ||
| 146 | if((status&OP_NINIT)==0) op->f2(out,env,left->result,right->result); | ||
| 147 | } | ||
| 148 | else if(!op->f1) | ||
| 149 | THROW("ops: ("<<left->expr<<" "<<expr<<" [R]): missing R argument") | ||
| 150 | else { | ||
| 151 | status=left->status; | ||
| 152 | if((status&OP_NINIT)==0) op->f1(out,env,left->result); | ||
| 153 | } | ||
| 154 | } | ||
| 155 | else if(right) { | ||
| 156 | if(!op->f1) | ||
| 157 | THROW("ops: ([L] "<<expr<<" "<<right->expr<<"): missing L argument") | ||
| 158 | else { | ||
| 159 | status=right->status; | ||
| 160 | if((status&OP_NINIT)==0) op->f1(out,env,right->result); | ||
| 161 | } | ||
| 162 | } | ||
| 163 | else THROW("ops: ["<<expr<<"]: operator not expected"); | ||
| 164 | } | ||
| 165 | else { | ||
| 166 | if(right) { | ||
| 167 | right->eval(out,env,opt); | ||
| 168 | status=right->status; | ||
| 169 | } | ||
| 170 | else env.term(out,this); | ||
| 171 | } | ||
| 172 | if(status&OP_NINIT) THROW("ops: unfinished expression ["<<expr<<"]"); | ||
| 173 | } | ||
diff --git a/src/ops/express.h b/src/ops/express.h new file mode 100644 index 0000000..79148f6 --- /dev/null +++ b/src/ops/express.h | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #ifndef EXPRESSH | ||
| 21 | #define EXPRESSH | ||
| 22 | |||
| 23 | #include <ops/operator.h> | ||
| 24 | #include <mt/split.h> | ||
| 25 | #include <mt/uniheap.h> | ||
| 26 | |||
| 27 | const int OP_LOCAL=1; | ||
| 28 | const int OP_GLOBAL=2; | ||
| 29 | const int OP_NINIT=4; | ||
| 30 | const int OP_ALL=OP_LOCAL|OP_GLOBAL|OP_NINIT; | ||
| 31 | |||
| 32 | class expr_t { | ||
| 33 | public: | ||
| 34 | sref expr; | ||
| 35 | const op_t* op; | ||
| 36 | int status; | ||
| 37 | mstring result; | ||
| 38 | expr_t *left,*right; | ||
| 39 | |||
| 40 | expr_t(): | ||
| 41 | expr(),op(0),status(OP_ALL),result(),left(0),right(0) {} | ||
| 42 | expr_t(const expr_t& x): | ||
| 43 | expr(),op(0),status(OP_ALL),result(),left(0),right(0) { copy(x); } | ||
| 44 | expr_t(const sref& s): | ||
| 45 | expr(s),op(0),status(OP_ALL),result(),left(0),right(0) {} | ||
| 46 | expr_t(const sref& s,const op_t* o): | ||
| 47 | expr(s),op(o),status(OP_ALL),result(),left(0),right(0) {} | ||
| 48 | expr_t(const sref& s,const op_t* o,expr_t* p): | ||
| 49 | expr(s),op(o),status(OP_ALL),result(),left(p),right(0) {} | ||
| 50 | ~expr_t() { delete left; delete right; } | ||
| 51 | |||
| 52 | void clear(); | ||
| 53 | expr_t& operator=(const expr_t& x) { clear(); copy(x); return *this; } | ||
| 54 | expr_t& operator=(const sref& in) { clear(); expr=in; return *this; } | ||
| 55 | |||
| 56 | void trav(mstream& out,int n); | ||
| 57 | void expand(op_env& env) throw(merror_t); | ||
| 58 | void eval(mstream& out,op_env& env,int opt) throw(merror_t); | ||
| 59 | |||
| 60 | static void* operator new(size_t n); | ||
| 61 | static void operator delete(void* p); | ||
| 62 | protected: | ||
| 63 | void copy(const expr_t& x); | ||
| 64 | static uniheap<36> tree; | ||
| 65 | }; | ||
| 66 | |||
| 67 | //////////////////////////////////////////////////////////// | ||
| 68 | |||
| 69 | struct op_env { | ||
| 70 | opmap* ops; | ||
| 71 | |||
| 72 | op_env() : ops(0) {} | ||
| 73 | op_env(opmap& map) : ops(&map) {} | ||
| 74 | |||
| 75 | virtual int split(sref& first,sref& rest) throw(merror_t) { return 0; } | ||
| 76 | virtual void term(mstream& out,expr_t* x) throw(merror_t) { x->status=0; } | ||
| 77 | }; | ||
| 78 | |||
| 79 | #endif | ||
diff --git a/src/ops/latex.cc b/src/ops/latex.cc new file mode 100644 index 0000000..01ccfc0 --- /dev/null +++ b/src/ops/latex.cc | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <ops/express.h> | ||
| 21 | #include <math.h> | ||
| 22 | |||
| 23 | OP1_IMPL(minus) {out<<"-"<<a;} | ||
| 24 | OP1_IMPL(plus) {out<<"+"<<a;} | ||
| 25 | OP1_IMPL(plusminus) {out<<"\\pm"<<a;} | ||
| 26 | OP1_IMPL(minusplus) {out<<"\\mp"<<a;} | ||
| 27 | |||
| 28 | OP2_IMPL(minus) {out<<L<<"-"<<R;} | ||
| 29 | OP2_IMPL(plus) {out<<L<<"+"<<R;} | ||
| 30 | OP2_IMPL(plusminus) {out<<L<<"\\pm"<<R;} | ||
| 31 | OP2_IMPL(minusplus) {out<<L<<"\\mp"<<R;} | ||
| 32 | |||
| 33 | OP2_IMPL(mul) {out<<L<<"\times"<<R;} | ||
| 34 | OP2_IMPL(divide) {out<<L<<"/"<<R;} | ||
| 35 | OP2_IMPL(pow) {out<<L<<"<sup><font size=-1>"<<R<<"</font></sup>";} | ||
| 36 | OP1_IMPL(pow) {out<<"<sup><font size=-1>"<<a<<"</font></sup>";} | ||
| 37 | OP2_IMPL(sub) {out<<L<<"<sub><font size=-1>"<<R<<"</font></sub>";} | ||
| 38 | OP1_IMPL(sub) {out<<"<sub><font size=-1>"<<a<<"</font></sub>";} | ||
| 39 | OP2_IMPL(div) {out<<L<<"\\div"<<R;} | ||
| 40 | |||
| 41 | OP2_IMPL(lt) {out<<L<<"<"<<R;} | ||
| 42 | OP2_IMPL(le) {out<<L<<"\\leq"<<R;} | ||
| 43 | OP2_IMPL(eq) {out<<L<<"="<<R;} | ||
| 44 | OP2_IMPL(ne) {out<<L<<"\\neq"<<R;} | ||
| 45 | OP2_IMPL(ge) {out<<L<<"\\geq"<<R;} | ||
| 46 | OP2_IMPL(gt) {out<<L<<">"<<R;} | ||
| 47 | |||
| 48 | OP2_IMPL(equiv) {out<<L<<"\\equiv"<<R;} | ||
| 49 | OP2_IMPL(sim) {out<<L<<"\\sim"<<R;} | ||
| 50 | OP2_IMPL(simeq) {out<<L<<"\\simeq"<<R;} | ||
| 51 | |||
| 52 | OP1_IMPL(not) {out<<"!"<<a;} | ||
| 53 | OP2_IMPL(and) {out<<L<<" and "<<R;} | ||
| 54 | OP2_IMPL(or) {out<<L<<" or "<<R;} | ||
| 55 | OP2_IMPL(xor) {out<<L<<" xor "<<R;} | ||
| 56 | |||
| 57 | OP2_IMPL(assign) {out<<L<<" = "<<R;} | ||
| 58 | |||
| 59 | OP2_IMPL(SP) {out<<L<<" "<<R;} | ||
| 60 | |||
| 61 | OP1_IMPL(semi) {out<<a;} | ||
| 62 | OP2_IMPL(semi) {out<<L<<R;} | ||
| 63 | |||
| 64 | void opAddLatex(opmap& M) | ||
| 65 | { | ||
| 66 | OP_ADD(30,not,"logic not"); | ||
| 67 | |||
| 68 | OP_ADD2(30,28,sub,_,"sub index"); | ||
| 69 | OP_ADD2(30,27,pow,^,"raised index"); | ||
| 70 | |||
| 71 | OP_ADD2(30,24,plus,+,"plus"); | ||
| 72 | OP_ADD2(30,24,minus,-,"minus"); | ||
| 73 | OP_ADD2(30,24,plusminus,+-,"plusminus"); | ||
| 74 | OP_ADD2(30,24,minusplus,-+,"minusplus"); | ||
| 75 | |||
| 76 | OP_ADDN(26,mul,*,"multiply"); | ||
| 77 | OP_ADDN(25,divide,/,"divide"); | ||
| 78 | OP_ADD(25,div,"divide-sign"); | ||
| 79 | // plus/minus 24 | ||
| 80 | |||
| 81 | OP_ADDN(20,lt,<,"less than"); | ||
| 82 | OP_ADDN(20,le,<=,"less or equal"); | ||
| 83 | OP_ADDN(20,ge,>=,"greater or equal"); | ||
| 84 | OP_ADDN(20,gt,>,"greater than"); | ||
| 85 | |||
| 86 | OP_ADDN(18,eq,==,"equal"); | ||
| 87 | OP_ADDN(18,ne,!=,"not equal"); | ||
| 88 | OP_ADDN(18,equiv,===,"equivalent"); | ||
| 89 | OP_ADDN(18,sim,~,"similar"); | ||
| 90 | OP_ADDN(18,simeq,~=,"similar equal"); | ||
| 91 | |||
| 92 | OP_ADD(10,and,"logic and"); | ||
| 93 | OP_ADD(9,xor,"logic xor"); | ||
| 94 | OP_ADD(8,or,"logic or"); | ||
| 95 | |||
| 96 | OP_ADDN(4,assign,=,"assignment"); | ||
| 97 | |||
| 98 | OP_ADD(3,SP,"Whitespace padding"); | ||
| 99 | |||
| 100 | OP_ADD2(1,1,semi,;,"concatenation"); | ||
| 101 | } | ||
diff --git a/src/ops/nnstyle.h b/src/ops/nnstyle.h new file mode 100644 index 0000000..4b8be5e --- /dev/null +++ b/src/ops/nnstyle.h | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #ifndef NNSTYLEH | ||
| 21 | #define NNSTYLEH | ||
| 22 | |||
| 23 | #include <mt/split.h> | ||
| 24 | |||
| 25 | const charset cset_wsdot=cset_ws|'.'; | ||
| 26 | |||
| 27 | inline mstring nncase(const sref& b) | ||
| 28 | { | ||
| 29 | static const mstring comma_tag(","),and_tag("and"); | ||
| 30 | mstring acc,a,name; | ||
| 31 | sref next,first,rest=b; | ||
| 32 | while(Split(first,rest,cset_wsdot)) { | ||
| 33 | if(first==comma_tag||eqn(first,and_tag)) continue; | ||
| 34 | (name=first.left_first(comma_tag)).tosim(); | ||
| 35 | name[0]=cset_ucase[name[0]]; | ||
| 36 | next=First(rest); | ||
| 37 | if(first.back()==','||next.empty()||*next==','||eqn(next,and_tag)) { | ||
| 38 | a.insert(0,name); | ||
| 39 | if(acc.nempty()) { acc+=' '; acc+=and_tag; acc+=' '; } | ||
| 40 | acc+=a; | ||
| 41 | a.clear(); | ||
| 42 | } | ||
| 43 | else { a+=' '; a+=name[0]; a+='.'; } | ||
| 44 | } | ||
| 45 | return acc; | ||
| 46 | } | ||
| 47 | |||
| 48 | inline int nncomp(const sref& L,const sref& R) | ||
| 49 | { | ||
| 50 | return nncase(L).compare(nncase(R)); | ||
| 51 | } | ||
| 52 | |||
| 53 | #endif | ||
diff --git a/src/ops/operator.cc b/src/ops/operator.cc new file mode 100644 index 0000000..f668340 --- /dev/null +++ b/src/ops/operator.cc | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <ops/operator.h> | ||
| 21 | #include <algorithm> | ||
| 22 | using namespace std; | ||
| 23 | |||
| 24 | void opmap::clear() { | ||
| 25 | for(iterator p=begin();p!=end();p++) delete *p; | ||
| 26 | mrvec<opmap_t>::clear(); | ||
| 27 | } | ||
| 28 | void opmap::erase(iterator p) { | ||
| 29 | delete *p; mrvec<opmap_t>::erase(p); | ||
| 30 | } | ||
| 31 | |||
| 32 | const op_t* opmap::get(const sref& t) const | ||
| 33 | { | ||
| 34 | pair<const_iterator,const_iterator> p= | ||
| 35 | equal_range(begin(),end(),(opmap_t)0,comp_t(t)); | ||
| 36 | return p.first!=p.second?*p.first:0; | ||
| 37 | } | ||
| 38 | |||
| 39 | const op_t* opmap::add(op_t* op) | ||
| 40 | { | ||
| 41 | pair<iterator,iterator> p=equal_range(begin(),end(),(opmap_t)0,comp_t(op->name)); | ||
| 42 | if(p.first!=p.second) { delete *p.first; return *p.first=op; } | ||
| 43 | else return *insert(p.second,op); | ||
| 44 | } | ||
diff --git a/src/ops/operator.h b/src/ops/operator.h new file mode 100644 index 0000000..d4a7af8 --- /dev/null +++ b/src/ops/operator.h | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #ifndef OPERATORH | ||
| 21 | #define OPERATORH | ||
| 22 | |||
| 23 | #include <mt/mstring.h> | ||
| 24 | #include <mt/mvec.h> | ||
| 25 | |||
| 26 | const mstring lt_tag="lt"; | ||
| 27 | |||
| 28 | /////////////////////////////////////////////// | ||
| 29 | |||
| 30 | class op_env; | ||
| 31 | struct op_t { | ||
| 32 | typedef void (*op1_t)(mstream&,op_env&,const sref&); | ||
| 33 | typedef void (*op2_t)(mstream&,op_env&,const sref&,const sref&); | ||
| 34 | |||
| 35 | mstring name,desc; | ||
| 36 | int pre1,pre2; | ||
| 37 | int left,right; | ||
| 38 | op1_t f1; op2_t f2; | ||
| 39 | |||
| 40 | op_t(const mstring& s,int p1,int p2,int l,int r,op1_t op1,op2_t op2,const mstring& d): | ||
| 41 | name(s),pre1(p1),pre2(p2),left(l),right(r),f1(op1),f2(op2),desc(d) {} | ||
| 42 | op_t(const mstring& s,int p1,int p2,op1_t op1,op2_t op2,const mstring& d): | ||
| 43 | name(s),pre1(p1),pre2(p2),left(2),right(2),f1(op1),f2(op2),desc(d) {} | ||
| 44 | op_t(const mstring& s,int p,op1_t op,const mstring& d): | ||
| 45 | name(s),pre1(p),pre2(0),left(0),right(2),f1(op),f2(0),desc(d) {} | ||
| 46 | op_t(const mstring& s,int p,op2_t op,const mstring& d): | ||
| 47 | name(s),pre1(0),pre2(p),left(2),right(2),f1(0),f2(op),desc(d) {} | ||
| 48 | }; | ||
| 49 | |||
| 50 | #define OP1_IMPL(n) \ | ||
| 51 | static void impl_##n(mstream& out,op_env& env,const sref& a) | ||
| 52 | #define OP2_IMPL(n) \ | ||
| 53 | static void impl_##n(mstream& out,op_env& env,const sref& L,const sref& R) | ||
| 54 | |||
| 55 | //////////////////////////////////////////////////////////// | ||
| 56 | |||
| 57 | typedef op_t* opmap_t; | ||
| 58 | |||
| 59 | struct opmap : public mrvec<opmap_t> { | ||
| 60 | typedef mrvec<opmap_t>::iterator iterator; | ||
| 61 | typedef mrvec<opmap_t>::const_iterator const_iterator; | ||
| 62 | |||
| 63 | struct comp_t { | ||
| 64 | sref key; | ||
| 65 | comp_t(const sref& skey) : key(skey) {} | ||
| 66 | bool operator()(const op_t* a,const op_t* b) const { | ||
| 67 | return (a?((const sref&)a->name):key)<(b?((const sref&)b->name):key); | ||
| 68 | } | ||
| 69 | }; | ||
| 70 | |||
| 71 | opmap() : mrvec<opmap_t>() {} | ||
| 72 | ~opmap() { clear(); } | ||
| 73 | |||
| 74 | void clear(); // overrides parent | ||
| 75 | void erase(iterator p); // overrides parent | ||
| 76 | |||
| 77 | const op_t* get(const sref& t) const; | ||
| 78 | const op_t* add(op_t* op); | ||
| 79 | }; | ||
| 80 | |||
| 81 | #define OP_ADD(p,f,d) M.add(new op_t(#f,p,impl_##f,d)) | ||
| 82 | #define OP_ADDN(p,f,n,d) M.add(new op_t(#n,p,impl_##f,d)) | ||
| 83 | #define OP_ADD2(p1,p2,f,n,d) M.add(new op_t(#n,p1,p2,impl_##f,impl_##f,d)) | ||
| 84 | |||
| 85 | /////////////////////////////////////////// | ||
| 86 | |||
| 87 | void opAddBasic(opmap& map); | ||
| 88 | void opAddComp(opmap& map); | ||
| 89 | void opAddString(opmap& map); | ||
| 90 | inline void opAddHEXP(opmap& map) { | ||
| 91 | opAddBasic(map); | ||
| 92 | opAddComp(map); | ||
| 93 | opAddString(map); | ||
| 94 | } | ||
| 95 | void opAddLatex(opmap& map); | ||
| 96 | |||
| 97 | #endif | ||
diff --git a/src/ops/string.cc b/src/ops/string.cc new file mode 100644 index 0000000..76b7e72 --- /dev/null +++ b/src/ops/string.cc | |||
| @@ -0,0 +1,274 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <ops/operator.h> | ||
| 21 | #include <ops/nnstyle.h> | ||
| 22 | #include <mt/mset.h> | ||
| 23 | |||
| 24 | OP2_IMPL(intersect) { mset a(L),b(R),c; c.Intersection(a,b); out<<c; } | ||
| 25 | OP2_IMPL(union) { mset a(L),b(R),c; c.Union(a,b); out<<c; } | ||
| 26 | OP2_IMPL(difference) { mset a(L),b(R),c; c.Difference(a,b); out<<c; } | ||
| 27 | OP2_IMPL(concats) { | ||
| 28 | if(L.nempty()&&R.nempty()) out<<L<<" "<<R; | ||
| 29 | else if(L.nempty()) out<<L; | ||
| 30 | else out<<R; | ||
| 31 | } | ||
| 32 | |||
| 33 | OP1_IMPL(lcase) {mstring s=a;s.tolower();out<<s;} | ||
| 34 | OP1_IMPL(ucase) {mstring s=a;s.toupper();out<<s;} | ||
| 35 | OP1_IMPL(nncase) {out<<nncase(a);} | ||
| 36 | OP1_IMPL(skipws) {out<<a.right_first_not_of(cset_ws);} | ||
| 37 | |||
| 38 | OP2_IMPL(eqnn) {out<<(nncomp(L,R)==0);} | ||
| 39 | OP2_IMPL(nenn) {out<<(nncomp(L,R)!=0);} | ||
| 40 | |||
| 41 | OP1_IMPL(first) {out<<First(a);} | ||
| 42 | OP1_IMPL(last) {out<<Last(a);} | ||
| 43 | OP1_IMPL(rest) {out<<Rest(a);} | ||
| 44 | |||
| 45 | OP1_IMPL(count) { | ||
| 46 | sref first,rest=a; int n=0; | ||
| 47 | while(Split(first,rest)) n++; | ||
| 48 | out<<n; | ||
| 49 | } | ||
| 50 | |||
| 51 | OP2_IMPL(nth) { | ||
| 52 | sref first,rest=L; int n=atoi(R); | ||
| 53 | while(n-->0&&Split(first,rest)); | ||
| 54 | out<<first; | ||
| 55 | } | ||
| 56 | |||
| 57 | OP2_IMPL(which) { | ||
| 58 | sref first,rest=L; int n=0; | ||
| 59 | while(Split(first,rest)) { n++; if(first==R) { out<<n; return; } } | ||
| 60 | out<<0; | ||
| 61 | } | ||
| 62 | |||
| 63 | OP2_IMPL(cnt) {out<<(L.find(R)>=0);} | ||
| 64 | OP2_IMPL(cntn) {out<<(L.find(R,cset_lcase)>=0);} | ||
| 65 | |||
| 66 | OP2_IMPL(concat) {out<<L<<R;} | ||
| 67 | |||
| 68 | OP2_IMPL(leftand) {out<<L.leftand_first(R);} | ||
| 69 | OP2_IMPL(left) {out<<L.left_first(R);} | ||
| 70 | OP2_IMPL(right) {out<<L.right_first(R);} | ||
| 71 | OP2_IMPL(past) {out<<L.past_first(R);} | ||
| 72 | |||
| 73 | OP2_IMPL(rleftand) {out<<L.leftand_last(R);} | ||
| 74 | OP2_IMPL(rleft) {out<<L.left_last(R);} | ||
| 75 | OP2_IMPL(rright) {out<<L.right_last(R);} | ||
| 76 | OP2_IMPL(rpast) {out<<L.past_last(R);} | ||
| 77 | |||
| 78 | void opAddString(opmap& M) | ||
| 79 | { | ||
| 80 | OP_ADD(32,lcase, | ||
| 81 | "Lower case\n" | ||
| 82 | "Syntax: lcase (string)\n" | ||
| 83 | "Returns: (string)\n" | ||
| 84 | ); | ||
| 85 | OP_ADD(32,ucase, | ||
| 86 | "Upper case\n" | ||
| 87 | "Syntax: ucase (string)\n" | ||
| 88 | "Returns: (string)\n" | ||
| 89 | ); | ||
| 90 | OP_ADD(32,nncase, | ||
| 91 | "NN-style case\n" | ||
| 92 | "Syntax: nncase (string)\n" | ||
| 93 | "Returns: (string)\n" | ||
| 94 | "\n" | ||
| 95 | "NN-style converts names to <lastname> <initials>\n" | ||
| 96 | ); | ||
| 97 | OP_ADD(32,skipws, | ||
| 98 | "Skip whitespace\n" | ||
| 99 | "Syntax: skipws (string)\n" | ||
| 100 | "Returns: (string)\n" | ||
| 101 | "\n" | ||
| 102 | "Skips trailing whitespace\n" | ||
| 103 | ); | ||
| 104 | |||
| 105 | OP_ADD(32,first, | ||
| 106 | "First element in list\n" | ||
| 107 | "Syntax: first (list)\n" | ||
| 108 | "Returns: (string)\n" | ||
| 109 | "\n" | ||
| 110 | "Elements are separated by whitespace\n" | ||
| 111 | ); | ||
| 112 | OP_ADD(32,last, | ||
| 113 | "Last element in list\n" | ||
| 114 | "Syntax: last (list)\n" | ||
| 115 | "Returns: (string)\n" | ||
| 116 | "\n" | ||
| 117 | "Elements are separated by whitespace\n" | ||
| 118 | ); | ||
| 119 | OP_ADD(32,rest, | ||
| 120 | "Rest of elements in list\n" | ||
| 121 | "Syntax: rest (list)\n" | ||
| 122 | "Returns: (list)\n" | ||
| 123 | "\n" | ||
| 124 | "Elements are separated by whitespace\n" | ||
| 125 | ); | ||
| 126 | OP_ADD(32,count, | ||
| 127 | "Count elements in list\n" | ||
| 128 | "Syntax: count (list)\n" | ||
| 129 | "Returns: (int)\n" | ||
| 130 | "\n" | ||
| 131 | "Elements are separated by whitespace\n" | ||
| 132 | ); | ||
| 133 | |||
| 134 | OP_ADD(30,nth, | ||
| 135 | "Nth element in list\n" | ||
| 136 | "Syntax: (list) nth (int)\n" | ||
| 137 | "Returns: (string)\n" | ||
| 138 | "\n" | ||
| 139 | "First element is denoted 1\n" | ||
| 140 | "Elements out of range returns empty\n" | ||
| 141 | "Elements are separated by whitespace\n" | ||
| 142 | ); | ||
| 143 | OP_ADD(30,which, | ||
| 144 | "Which element in list\n" | ||
| 145 | "Syntax: (list) a which (string) b\n" | ||
| 146 | "Returns: (int)\n" | ||
| 147 | "\n" | ||
| 148 | "Which element in a is b (0 if not found)\n" | ||
| 149 | "First element is denoted 1\n" | ||
| 150 | "Elements are separated by whitespace\n" | ||
| 151 | ); | ||
| 152 | |||
| 153 | OP_ADD(28,left, | ||
| 154 | "Left of substring\n" | ||
| 155 | "Syntax: (string) a left (string) b\n" | ||
| 156 | "Returns: (string)\n" | ||
| 157 | "\n" | ||
| 158 | "Everything in a to the left of first b, of a if b not found in a\n" | ||
| 159 | ); | ||
| 160 | OP_ADD(28,leftand, | ||
| 161 | "Left of substring inclusive\n" | ||
| 162 | "Syntax: (string) a leftand (string) b\n" | ||
| 163 | "Returns: (string)\n" | ||
| 164 | "\n" | ||
| 165 | "Everything in a to the left of first b inclusive, of a if b not found in a\n" | ||
| 166 | ); | ||
| 167 | OP_ADD(28,right, | ||
| 168 | "Right of substring inclusive\n" | ||
| 169 | "Syntax: (string) a right (string) b\n" | ||
| 170 | "Returns: (string)\n" | ||
| 171 | "\n" | ||
| 172 | "Everything in a to the right of first b inclusive, of empty if b not found in a\n" | ||
| 173 | ); | ||
| 174 | OP_ADD(28,past, | ||
| 175 | "Right of substring\n" | ||
| 176 | "Syntax: (string) a past (string) b\n" | ||
| 177 | "Returns: (string)\n" | ||
| 178 | "\n" | ||
| 179 | "Everything in a to the right of first b, of empty if b not found in a\n" | ||
| 180 | ); | ||
| 181 | |||
| 182 | OP_ADD(28,rleft, | ||
| 183 | "Left of substring (reversed)\n" | ||
| 184 | "Syntax: (string) a rleft (string) b\n" | ||
| 185 | "Returns: (string)\n" | ||
| 186 | "\n" | ||
| 187 | "Everything in a to the left of last b, of a if b not found in a\n" | ||
| 188 | ); | ||
| 189 | OP_ADD(28,rleftand, | ||
| 190 | "Left of substring inclusive, (reversed)\n" | ||
| 191 | "Syntax: (string) a rleftand (string) b\n" | ||
| 192 | "Returns: (string)\n" | ||
| 193 | "\n" | ||
| 194 | "Everything in a to the left of last b inclusive, of a if b not found in a\n" | ||
| 195 | ); | ||
| 196 | OP_ADD(28,rright, | ||
| 197 | "Right of substring inclusive (reversed)\n" | ||
| 198 | "Syntax: (string) a rright (string) b\n" | ||
| 199 | "Returns: (string)\n" | ||
| 200 | "\n" | ||
| 201 | "Everything in a to the right of last b inclusive, of empty if b not found in a\n" | ||
| 202 | ); | ||
| 203 | OP_ADD(28,rpast, | ||
| 204 | "Right of substring (reversed)\n" | ||
| 205 | "Syntax: (string) a rpast (string) b\n" | ||
| 206 | "Returns: (string)\n" | ||
| 207 | "\n" | ||
| 208 | "Everything in a to the right of last b, of empty if b not found in a\n" | ||
| 209 | ); | ||
| 210 | |||
| 211 | OP_ADDN(24,concat,++, | ||
| 212 | "String concatenation\n" | ||
| 213 | "Syntax: (string) ++ (string)\n" | ||
| 214 | "Returns: (string)\n" | ||
| 215 | ); | ||
| 216 | OP_ADDN(24,concats,+++, | ||
| 217 | "List concatenation\n" | ||
| 218 | "Syntax: (list) +++ (list)\n" | ||
| 219 | "Returns: (list)\n" | ||
| 220 | "\n" | ||
| 221 | "Lists are concatenated with space\n" | ||
| 222 | ); | ||
| 223 | |||
| 224 | OP_ADD(18,cnt, | ||
| 225 | "Contains substring\n" | ||
| 226 | "Syntax: (string) a cnt (string) b\n" | ||
| 227 | "Returns: (int)\n" | ||
| 228 | "\n" | ||
| 229 | "Nonzero if b found in a\n" | ||
| 230 | ); | ||
| 231 | OP_ADD(18,cntn, | ||
| 232 | "Contains substring, case insensitive\n" | ||
| 233 | "Syntax: (string) a cnt (string) b\n" | ||
| 234 | "Returns: (int)\n" | ||
| 235 | "\n" | ||
| 236 | "Nonzero if b found in a\n" | ||
| 237 | ); | ||
| 238 | OP_ADD(18,eqnn, | ||
| 239 | "NN-style equal\n" | ||
| 240 | "Syntax: (string) eqnn (string)\n" | ||
| 241 | "Returns: (int)\n" | ||
| 242 | "\n" | ||
| 243 | "NN-style converts names to <lastname> <initials>\n" | ||
| 244 | ); | ||
| 245 | OP_ADD(18,nenn, | ||
| 246 | "NN-style not equal\n" | ||
| 247 | "Syntax: (string) eqnn (string)\n" | ||
| 248 | "Returns: (int)\n" | ||
| 249 | "\n" | ||
| 250 | "NN-style converts names to <lastname> <initials>\n" | ||
| 251 | ); | ||
| 252 | |||
| 253 | OP_ADDN(10,intersect,&&&, | ||
| 254 | "List intersection\n" | ||
| 255 | "Syntax: (list) a &&& (list) b\n" | ||
| 256 | "Returns: (list)\n" | ||
| 257 | "\n" | ||
| 258 | "Finds the set intersection of a and b\n" | ||
| 259 | ); | ||
| 260 | OP_ADDN(9,difference,---, | ||
| 261 | "List difference\n" | ||
| 262 | "Syntax: (list) a &&& (list) b\n" | ||
| 263 | "Returns: (list)\n" | ||
| 264 | "\n" | ||
| 265 | "Finds the set difference of a and b\n" | ||
| 266 | ); | ||
| 267 | OP_ADDN(9,union,|||, | ||
| 268 | "List union\n" | ||
| 269 | "Syntax: (list) a &&& (list) b\n" | ||
| 270 | "Returns: (list)\n" | ||
| 271 | "\n" | ||
| 272 | "Finds the set union of a and b\n" | ||
| 273 | ); | ||
| 274 | } | ||
diff --git a/src/ops/test.cc b/src/ops/test.cc new file mode 100644 index 0000000..b6058fc --- /dev/null +++ b/src/ops/test.cc | |||
| @@ -0,0 +1,161 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <ops/express.h> | ||
| 21 | #include <mt/msmap.h> | ||
| 22 | #include <iostream> | ||
| 23 | #include <fstream> | ||
| 24 | using namespace std; | ||
| 25 | |||
| 26 | static fp_stream mout(stdout),merr(stderr); | ||
| 27 | |||
| 28 | struct tt_env : public op_env { | ||
| 29 | sspile var; | ||
| 30 | tt_env(opmap& map) : op_env(map) {} | ||
| 31 | int split(sref& first,sref& rest) throw(merror_t) { | ||
| 32 | static const charset spec("+-*%/<=>^_!~&|,?:;"); | ||
| 33 | static const charset delim("()\"\\"); | ||
| 34 | static const charset specws=spec|delim|cset_ws; | ||
| 35 | int s; | ||
| 36 | rest=rest.right_first_not_of(cset_ws); | ||
| 37 | if((s=rest.skip(cset_quotes))>0) { | ||
| 38 | first=rest.left(s); | ||
| 39 | rest=rest.right(s); | ||
| 40 | } | ||
| 41 | else if((s=rest.skip(cset_para))>0) { | ||
| 42 | first=Trim(rest.left(s),cset_para); | ||
| 43 | rest=rest.right(s); | ||
| 44 | } | ||
| 45 | else if((s=rest.skip(cset_braces))>0) { | ||
| 46 | first=rest.left(s); | ||
| 47 | rest=rest.right(s); | ||
| 48 | } | ||
| 49 | else if(spec.test(*rest)) { | ||
| 50 | first=rest.left_first_not_of(spec); | ||
| 51 | rest=rest.adv(first); | ||
| 52 | } | ||
| 53 | else { | ||
| 54 | first=rest.left_first_of(specws); | ||
| 55 | rest=rest.adv(first); | ||
| 56 | } | ||
| 57 | return first.nempty(); | ||
| 58 | } | ||
| 59 | void term(mstream& out,expr_t* x) throw(merror_t) { | ||
| 60 | if(x->expr.empty()) { | ||
| 61 | x->status=0; | ||
| 62 | } | ||
| 63 | else if(x->expr.skip(cset_quotes)==x->expr.size()) { | ||
| 64 | out<<x->expr(1,-3); | ||
| 65 | x->status=0; | ||
| 66 | } | ||
| 67 | else if(x->expr.find_not_of(cset_real)<0) { | ||
| 68 | out<<x->expr; | ||
| 69 | x->status=0; | ||
| 70 | } | ||
| 71 | else { | ||
| 72 | for(sspile::iterator s=var.begin();s!=var.end();s++) | ||
| 73 | if(s->first==x->expr) { out<<s->second; x->status=OP_LOCAL; break; } | ||
| 74 | } | ||
| 75 | } | ||
| 76 | }; | ||
| 77 | |||
| 78 | #define TT_IMPL(n) \ | ||
| 79 | static void impl_##n(mstream& out,tt_env& env,const sref& L,const sref& R) | ||
| 80 | #define TT_ADDN(p,f,n,d) \ | ||
| 81 | M.add(new op_t(#n,0,p,1,2,0,(op_t::op2_t)impl_##f,d)) | ||
| 82 | |||
| 83 | TT_IMPL(assign) { | ||
| 84 | sspile& var=env.var; | ||
| 85 | for(sspile::iterator p=var.begin();p!=var.end();p++) | ||
| 86 | if(p->first==L) { p->second=R; return; } | ||
| 87 | var.push_back(sstring(L,R)); | ||
| 88 | } | ||
| 89 | |||
| 90 | TT_IMPL(incr) { | ||
| 91 | sspile& var=env.var; | ||
| 92 | for(sspile::iterator p=var.begin();p!=var.end();p++) | ||
| 93 | if(p->first==L) { p->second=itoa(atoi(p->second)+atoi(R)); break; } | ||
| 94 | } | ||
| 95 | |||
| 96 | TT_IMPL(decr) { | ||
| 97 | sspile& var=env.var; | ||
| 98 | for(sspile::iterator p=var.begin();p!=var.end();p++) | ||
| 99 | if(p->first==L) { p->second=itoa(atoi(p->second)-atoi(R)); break; } | ||
| 100 | } | ||
| 101 | |||
| 102 | inline void opAddTT(opmap& M) { | ||
| 103 | TT_ADDN(4,assign,=,"C style"); | ||
| 104 | TT_ADDN(4,assign,:=,"new var"); | ||
| 105 | TT_ADDN(4,incr,+=,"C style"); | ||
| 106 | TT_ADDN(4,decr,-=,"C style"); | ||
| 107 | } | ||
| 108 | |||
| 109 | main(int argc,char* argv[]) try | ||
| 110 | { | ||
| 111 | opmap ops; | ||
| 112 | opAddHEXP(ops); | ||
| 113 | opAddTT(ops); | ||
| 114 | tt_env env(ops); | ||
| 115 | mstring buf; | ||
| 116 | sref_t line; | ||
| 117 | expr_t expr; | ||
| 118 | if(argc>1) { | ||
| 119 | buf.load(sref(argv[1])); | ||
| 120 | sref first,rest=buf; | ||
| 121 | Splitln(first,rest); | ||
| 122 | if(first.left(2)!=sref("#!")) rest=buf; | ||
| 123 | (expr=buf).expand(env); | ||
| 124 | expr.eval(mout,env,OP_ALL); | ||
| 125 | mout<<"\n"; | ||
| 126 | } | ||
| 127 | else { | ||
| 128 | while(1) { | ||
| 129 | merr<<"ops>"; | ||
| 130 | cin.getline(line,sizeof(sref_t)); | ||
| 131 | sref first,rest(line); | ||
| 132 | Split(first,rest); | ||
| 133 | if(first==sref("exit")) { | ||
| 134 | break; | ||
| 135 | } | ||
| 136 | else if(first==sref("tree")) { | ||
| 137 | expr.trav(mout,12); | ||
| 138 | } | ||
| 139 | else if(first==sref("eval")) { | ||
| 140 | expr.eval(mout,env,OP_ALL); | ||
| 141 | mout<<"\n"; | ||
| 142 | } | ||
| 143 | else { | ||
| 144 | buf=line; | ||
| 145 | try { | ||
| 146 | (expr=buf).expand(env); | ||
| 147 | expr.eval(mout,env,OP_ALL); | ||
| 148 | mout<<"\n"; | ||
| 149 | } | ||
| 150 | catch(const merror_t& e) { | ||
| 151 | merr<<e.desc<<"\n"; | ||
| 152 | } | ||
| 153 | } | ||
| 154 | } | ||
| 155 | } | ||
| 156 | return 0; | ||
| 157 | } | ||
| 158 | catch(const merror_t& e) { | ||
| 159 | merr<<"ops("<<e.num<<") "<<e.desc<<"\n"; | ||
| 160 | return -1; | ||
| 161 | } | ||
