summaryrefslogtreecommitdiff
path: root/src/ops
diff options
context:
space:
mode:
Diffstat (limited to 'src/ops')
-rw-r--r--src/ops/basic.cc269
-rw-r--r--src/ops/comp.cc134
-rw-r--r--src/ops/express.cc173
-rw-r--r--src/ops/express.h79
-rw-r--r--src/ops/latex.cc101
-rw-r--r--src/ops/nnstyle.h53
-rw-r--r--src/ops/operator.cc44
-rw-r--r--src/ops/operator.h97
-rw-r--r--src/ops/string.cc274
-rw-r--r--src/ops/test.cc161
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
23OP1_IMPL(exp) { out<<exp(atof(a)); }
24OP1_IMPL(ln) { out<<log(atof(a)); }
25OP1_IMPL(abs) { out<<fabs(atof(a)); }
26OP1_IMPL(int) { out<<int(atof(a)); }
27
28OP1_IMPL(minus) { out<<-atof(a); }
29OP2_IMPL(minus) { out<<atof(L)-atof(R); }
30OP1_IMPL(plus) { out<<atof(a); }
31OP2_IMPL(plus) { out<<atof(L)+atof(R); }
32OP2_IMPL(mul) { out<<atof(L)*atof(R); }
33OP2_IMPL(divide) { out<<atof(L)/atof(R); }
34OP2_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}
40OP2_IMPL(imod) { out<<(atoi(L)%atoi(R)); }
41OP2_IMPL(div) { out<<(atoi(L)/atoi(R)); }
42OP2_IMPL(pow) { out<<pow(atof(L),atof(R)); }
43
44OP2_IMPL(eq) {out<<(L==R); }
45OP2_IMPL(ne) {out<<(L!=R);}
46OP2_IMPL(eqn) {out<<(L.compare(R,cset_lcase)==0);}
47OP2_IMPL(nen) {out<<(L.compare(R,cset_lcase)!=0);}
48OP2_IMPL(eqf) {out<<(atof(L)==atof(R));}
49OP2_IMPL(nef) {out<<(atof(L)!=atof(R));}
50
51OP1_IMPL(not) {out<<!atob(a);}
52OP2_IMPL(and) {out<<(atob(L)&atob(R)); }
53OP2_IMPL(or) {out<<(atob(L)|atob(R)); }
54OP2_IMPL(xor) {out<<(atob(L)^atob(R)); }
55
56OP2_IMPL(shiftleft) {out<<(atoi(L)<<atoi(R));}
57OP2_IMPL(shiftright) {out<<(atoi(L)>>atoi(R));}
58
59OP1_IMPL(bitnot) {out<<~atoi(a);}
60OP2_IMPL(bitand) {out<<(atoi(L)&atoi(R)); }
61OP2_IMPL(bitor) {out<<(atoi(L)|atoi(R)); }
62OP2_IMPL(bitxor) {out<<(atoi(L)^atoi(R)); }
63
64OP2_IMPL(SP) {out<<L<<" "<<R;}
65
66OP2_IMPL(comma) {out<<R;}
67
68OP1_IMPL(semi) {}
69OP2_IMPL(semi) {}
70
71void 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
23OP2_IMPL(lt) {out<<(L<R);}
24OP2_IMPL(le) {out<<(L<=R);}
25OP2_IMPL(ge) {out<<(L>=R);}
26OP2_IMPL(gt) {out<<(L>R);}
27OP2_IMPL(ltn) {out<<(L.compare(R,cset_lcase)<0);}
28OP2_IMPL(len) {out<<(L.compare(R,cset_lcase)<=0);}
29OP2_IMPL(gen) {out<<(L.compare(R,cset_lcase)>=0);}
30OP2_IMPL(gtn) {out<<(L.compare(R,cset_lcase)>0);}
31OP2_IMPL(ltnn) {out<<(nncomp(L,R)<0);}
32OP2_IMPL(lenn) {out<<(nncomp(L,R)<=0);}
33OP2_IMPL(genn) {out<<(nncomp(L,R)>=0);}
34OP2_IMPL(gtnn) {out<<(nncomp(L,R)>0);}
35OP2_IMPL(ltf) {out<<(atof(L)<atof(R));}
36OP2_IMPL(lef) {out<<(atof(L)<=atof(R));}
37OP2_IMPL(gef) {out<<(atof(L)>=atof(R));}
38OP2_IMPL(gtf) {out<<(atof(L)>atof(R));}
39
40void 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
22const mstring sp_tag="SP";
23
24////////////////////////////////////////////////////////////////
25
26uniheap<sizeof(expr_t)> expr_t::tree;
27void* expr_t::operator new(size_t n) { return tree.push(); }
28void expr_t::operator delete(void* p) { tree.pop(p); }
29
30////////////////////////////////////////////////////////////////
31
32inline 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
46static 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
56static 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
68void 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
78void 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
86void 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
94void 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
108void 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
27const int OP_LOCAL=1;
28const int OP_GLOBAL=2;
29const int OP_NINIT=4;
30const int OP_ALL=OP_LOCAL|OP_GLOBAL|OP_NINIT;
31
32class expr_t {
33public:
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);
62protected:
63 void copy(const expr_t& x);
64 static uniheap<36> tree;
65};
66
67////////////////////////////////////////////////////////////
68
69struct 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
23OP1_IMPL(minus) {out<<"-"<<a;}
24OP1_IMPL(plus) {out<<"+"<<a;}
25OP1_IMPL(plusminus) {out<<"\\pm"<<a;}
26OP1_IMPL(minusplus) {out<<"\\mp"<<a;}
27
28OP2_IMPL(minus) {out<<L<<"-"<<R;}
29OP2_IMPL(plus) {out<<L<<"+"<<R;}
30OP2_IMPL(plusminus) {out<<L<<"\\pm"<<R;}
31OP2_IMPL(minusplus) {out<<L<<"\\mp"<<R;}
32
33OP2_IMPL(mul) {out<<L<<"\times"<<R;}
34OP2_IMPL(divide) {out<<L<<"/"<<R;}
35OP2_IMPL(pow) {out<<L<<"<sup><font size=-1>"<<R<<"</font></sup>";}
36OP1_IMPL(pow) {out<<"<sup><font size=-1>"<<a<<"</font></sup>";}
37OP2_IMPL(sub) {out<<L<<"<sub><font size=-1>"<<R<<"</font></sub>";}
38OP1_IMPL(sub) {out<<"<sub><font size=-1>"<<a<<"</font></sub>";}
39OP2_IMPL(div) {out<<L<<"\\div"<<R;}
40
41OP2_IMPL(lt) {out<<L<<"<"<<R;}
42OP2_IMPL(le) {out<<L<<"\\leq"<<R;}
43OP2_IMPL(eq) {out<<L<<"="<<R;}
44OP2_IMPL(ne) {out<<L<<"\\neq"<<R;}
45OP2_IMPL(ge) {out<<L<<"\\geq"<<R;}
46OP2_IMPL(gt) {out<<L<<">"<<R;}
47
48OP2_IMPL(equiv) {out<<L<<"\\equiv"<<R;}
49OP2_IMPL(sim) {out<<L<<"\\sim"<<R;}
50OP2_IMPL(simeq) {out<<L<<"\\simeq"<<R;}
51
52OP1_IMPL(not) {out<<"!"<<a;}
53OP2_IMPL(and) {out<<L<<" and "<<R;}
54OP2_IMPL(or) {out<<L<<" or "<<R;}
55OP2_IMPL(xor) {out<<L<<" xor "<<R;}
56
57OP2_IMPL(assign) {out<<L<<" = "<<R;}
58
59OP2_IMPL(SP) {out<<L<<" "<<R;}
60
61OP1_IMPL(semi) {out<<a;}
62OP2_IMPL(semi) {out<<L<<R;}
63
64void 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
25const charset cset_wsdot=cset_ws|'.';
26
27inline 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
48inline 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>
22using namespace std;
23
24void opmap::clear() {
25 for(iterator p=begin();p!=end();p++) delete *p;
26 mrvec<opmap_t>::clear();
27}
28void opmap::erase(iterator p) {
29 delete *p; mrvec<opmap_t>::erase(p);
30}
31
32const 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
39const 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
26const mstring lt_tag="lt";
27
28///////////////////////////////////////////////
29
30class op_env;
31struct 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) \
51static void impl_##n(mstream& out,op_env& env,const sref& a)
52#define OP2_IMPL(n) \
53static void impl_##n(mstream& out,op_env& env,const sref& L,const sref& R)
54
55////////////////////////////////////////////////////////////
56
57typedef op_t* opmap_t;
58
59struct 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
87void opAddBasic(opmap& map);
88void opAddComp(opmap& map);
89void opAddString(opmap& map);
90inline void opAddHEXP(opmap& map) {
91 opAddBasic(map);
92 opAddComp(map);
93 opAddString(map);
94}
95void 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
24OP2_IMPL(intersect) { mset a(L),b(R),c; c.Intersection(a,b); out<<c; }
25OP2_IMPL(union) { mset a(L),b(R),c; c.Union(a,b); out<<c; }
26OP2_IMPL(difference) { mset a(L),b(R),c; c.Difference(a,b); out<<c; }
27OP2_IMPL(concats) {
28 if(L.nempty()&&R.nempty()) out<<L<<" "<<R;
29 else if(L.nempty()) out<<L;
30 else out<<R;
31}
32
33OP1_IMPL(lcase) {mstring s=a;s.tolower();out<<s;}
34OP1_IMPL(ucase) {mstring s=a;s.toupper();out<<s;}
35OP1_IMPL(nncase) {out<<nncase(a);}
36OP1_IMPL(skipws) {out<<a.right_first_not_of(cset_ws);}
37
38OP2_IMPL(eqnn) {out<<(nncomp(L,R)==0);}
39OP2_IMPL(nenn) {out<<(nncomp(L,R)!=0);}
40
41OP1_IMPL(first) {out<<First(a);}
42OP1_IMPL(last) {out<<Last(a);}
43OP1_IMPL(rest) {out<<Rest(a);}
44
45OP1_IMPL(count) {
46 sref first,rest=a; int n=0;
47 while(Split(first,rest)) n++;
48 out<<n;
49}
50
51OP2_IMPL(nth) {
52 sref first,rest=L; int n=atoi(R);
53 while(n-->0&&Split(first,rest));
54 out<<first;
55}
56
57OP2_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
63OP2_IMPL(cnt) {out<<(L.find(R)>=0);}
64OP2_IMPL(cntn) {out<<(L.find(R,cset_lcase)>=0);}
65
66OP2_IMPL(concat) {out<<L<<R;}
67
68OP2_IMPL(leftand) {out<<L.leftand_first(R);}
69OP2_IMPL(left) {out<<L.left_first(R);}
70OP2_IMPL(right) {out<<L.right_first(R);}
71OP2_IMPL(past) {out<<L.past_first(R);}
72
73OP2_IMPL(rleftand) {out<<L.leftand_last(R);}
74OP2_IMPL(rleft) {out<<L.left_last(R);}
75OP2_IMPL(rright) {out<<L.right_last(R);}
76OP2_IMPL(rpast) {out<<L.past_last(R);}
77
78void 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>
24using namespace std;
25
26static fp_stream mout(stdout),merr(stderr);
27
28struct 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) \
79static void impl_##n(mstream& out,tt_env& env,const sref& L,const sref& R)
80#define TT_ADDN(p,f,n,d) \
81M.add(new op_t(#n,0,p,1,2,0,(op_t::op2_t)impl_##f,d))
82
83TT_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
90TT_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
96TT_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
102inline 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
109main(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}
158catch(const merror_t& e) {
159 merr<<"ops("<<e.num<<") "<<e.desc<<"\n";
160 return -1;
161}