summaryrefslogtreecommitdiff
path: root/src/ops/express.cc
diff options
context:
space:
mode:
authorHenrik Rydberg <rydberg@euromail.se>2011-10-08 20:30:28 +0200
committerHenrik Rydberg <rydberg@euromail.se>2011-10-08 20:30:28 +0200
commit5df79c53745fde5d6c3340a2979b1429cd5892c1 (patch)
tree1a81af141708b826e9c61e8a04019994fcca8298 /src/ops/express.cc
Initial import of htcd system 1.0
Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
Diffstat (limited to 'src/ops/express.cc')
-rw-r--r--src/ops/express.cc173
1 files changed, 173 insertions, 0 deletions
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}