Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtinfo / DtMmdb / StyleSheet / Expression.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 // $TOG: Expression.C /main/9 1998/04/17 11:48:40 mgreess $
24 #include "Attribute.h"
25 #include "AttributeList.h"
26 #include "Expression.h"
27 #include "FeatureValue.h"
28 #include "ResolverStack.h"
29 #include "StyleSheetExceptions.h"
30 #include "VariableTable.h"
31 #include "Renderer.h"
32 #include "Debug.h"
33 #include <stream.h>
34
35 #include "HardCopy/autoNumberFP.h"
36
37
38 extern const Element            *gCurrentElement;
39 extern const FeatureSet         *gCurrentLocalSet;
40 extern const FeatureSet         *gParentCompleteSet;
41
42 Expression::Expression(TermNode *root)
43 : f_root(root)
44 {
45 }
46
47 Expression::Expression(const Expression &e)
48 : f_root(e.f_root->clone())
49 {
50 }
51
52 ConstantNode::ConstantNode(FeatureValue *v)
53 : f_value(v)
54 {
55 }
56
57 VariableNode::VariableNode(const Symbol &name)
58 : f_name(name)
59 {
60 }
61
62 CompositeVariableNode::CompositeVariableNode()
63 : f_items(4)
64 {
65 }
66
67 CompositeVariableNode::CompositeVariableNode(size_t capac)
68 : f_items(capac)
69 {
70 }
71
72 CompositeVariableNode::~CompositeVariableNode()
73 {
74   f_items.clearAndDestroy();
75 }
76
77 void
78 CompositeVariableNode::prependItem(const Symbol& item)
79 {
80   f_items.prepend(new Symbol(item));
81 }
82
83 void
84 CompositeVariableNode::appendItem(const Symbol& item)
85 {
86   f_items.append(new Symbol(item));
87 }
88
89 const Symbol* 
90 CompositeVariableNode::convertableToVariable()
91 {
92    const Symbol* x = 0;
93    if ( f_items.entries() == 1 ) {
94       x = f_items.first();
95       if ( gVariableTable -> exists(*x) ) 
96          return x; 
97    }
98  
99    return 0;
100 }
101
102 BinaryOperatorNode::BinaryOperatorNode(operatorType t,
103                                        TermNode *left, TermNode *right)
104 : f_operator(t), f_left(left), f_right(right)
105 {
106 }
107
108 BinaryOperatorNode::~BinaryOperatorNode()
109 {
110   delete f_left ;
111   delete f_right;
112 }
113
114 SgmlAttributeNode::SgmlAttributeNode(const Symbol &name)
115 : f_name(name)
116 {
117 }
118
119 FeatureValue *
120 Expression::evaluate() const
121 {
122   return f_root->evaluate();
123 }
124
125 Expression::~Expression()
126 {
127   delete  f_root ;
128 }
129
130 TermNode::~TermNode()
131 {
132 }
133
134 ConstantNode::~ConstantNode()
135 {
136   delete f_value ;
137 }
138
139 FeatureValue *
140 BinaryOperatorNode::evaluate() const
141 {
142   // calculate children trees and then have feature value do the operation 
143
144 #if !defined(SC3) && !defined(_IBMR2) && !defined(__uxp__) && !defined(__osf__) && !defined(USL) && !defined(linux)
145   volatile
146 #endif
147   FeatureValue *left =  0;
148 #if !defined(SC3) && !defined(_IBMR2) && !defined(__uxp__) && !defined(__osf__) && !defined(USL) && !defined(linux)
149   volatile
150 #endif
151   FeatureValue *right = 0;
152 #if !defined(SC3) && !defined(_IBMR2) && !defined(__uxp__) && !defined(__osf__) && !defined(USL) && !defined(linux)
153   volatile
154 #endif
155   FeatureValue *result = 0;
156
157   try
158     {
159       left  = f_left->evaluate();
160       right = f_right->evaluate();
161
162       switch (f_operator)
163         {
164         case PLUS:
165           result = *left + *right ;
166           break;
167         case MINUS:
168           result = *left - *right ;
169           break;
170         case TIMES:
171           result = *left * *right ;
172           break;
173         case DIVIDE:
174           result = *left / *right ;
175           break;
176         }
177
178     }
179   catch_any()
180     {
181       delete left ;
182       delete right ;
183       delete result ;
184       rethrow;
185     }
186   end_try ;
187   delete left ;
188   delete right ;
189   return result ;
190
191 }
192
193
194 FeatureValue *
195 VariableNode::evaluate() const
196 {
197   // this could be a feature or a variable 
198   // first look in the parent feature set 
199
200   // NOTE: actual operation should be to look in the local feature set first
201   // before going to the parent unless the inherit operator was used. Not sure
202   // how to do this, because at this point, we are trying to evaluate the
203   // current feature set
204
205   // see if item exists in parent feature hierarchy, and if not, then we go to
206   // the variable table
207
208 //MESSAGE(cerr, "VariableNode::evaluate()");
209 //f_name.print(cerr);
210   
211   FeatureValue *variable_value = gVariableTable->lookup(f_name).evaluate();
212
213 //debug(cerr, int(variable_value));
214
215   if (!variable_value)
216     throw(CASTUVEXCEPT undefinedVariableException(f_name));
217
218   // have to evaluate it in case it contains expressions or other variables
219   // etc.  
220   FeatureValue *return_variable = 0;
221
222   try
223     {
224       return_variable = variable_value->evaluate() ;
225     }
226   catch_any()
227     {
228       delete return_variable; 
229       delete variable_value ;
230       rethrow;
231     }
232   end_try;
233
234 //MESSAGE(cerr, "VariableNode::evaluate() completes");
235
236   delete variable_value ;
237   return return_variable;
238 }
239
240 FeatureValue *
241 CompositeVariableNode::evaluate() const
242 {
243 /*
244 MESSAGE(cerr, "CompositeVariableNode::evaluate():");
245 print(cerr);
246 cerr << "\n";
247 f_items[0] -> print(cerr);
248 MESSAGE(cerr, "");
249 */
250
251 //debug(cerr, int(gCurrentLocalSet));
252 //debug(cerr, int(gParentCompleteSet));
253
254   const Feature *f = 0;
255
256   if ( gCurrentLocalSet )
257      f = gCurrentLocalSet->deep_lookup(f_items) ;
258
259 //debug(cerr, int(f));
260
261   if (!f && gParentCompleteSet )
262     f = gParentCompleteSet->deep_lookup(f_items);
263
264 //debug(cerr, int(f));
265
266   //if ( f == 0 && gRenderer ) {
267   if ( f == 0 ) {
268     FeatureValue* fv = gAutoNumberFP.evaluate(f_items[0] -> name());
269     if ( fv == 0 ) {
270        //print(cerr);
271        throw(CASTBEEXCEPT badEvaluationException());
272     } else
273        return fv;
274   }
275
276   if (!f) {
277     //print(cerr);
278     throw(CASTBEEXCEPT badEvaluationException());
279   }
280
281   return f->evaluate();
282 }
283
284
285
286
287 FeatureValue *
288 ConstantNode::evaluate() const
289 {
290   //return f_value->clone();
291   return f_value->evaluate();
292 }
293
294 extern unsigned g_validation_mode;
295
296 FeatureValue *
297 SgmlAttributeNode::evaluate() const
298 {
299   if ( g_validation_mode == true ) {
300     throw(CASTUAEXCEPT undefinedAttributeException(f_name));
301   }
302
303   const Attribute *attr = gCurrentElement->get_attribute(f_name);
304
305   if (attr)
306     return new FeatureValueString(attr->value());
307   
308   throw(CASTUAEXCEPT undefinedAttributeException(f_name));
309
310   return 0 ;
311 }
312
313
314  // ////////////////////////////////////////////////////////////////////////
315  // Printing
316  // ////////////////////////////////////////////////////////////////////////
317
318 ostream &operator<<(ostream &o, const Expression &e)
319 {
320   return e.print(o);
321 }
322
323 ostream &operator<< (ostream &o, const TermNode &t)
324 {
325   return t.print(o);
326 }
327
328 ostream &
329 Expression::print(ostream &o) const
330 {
331   return o << *f_root ; 
332 }
333
334 ostream &
335 VariableNode::print(ostream &o) const
336 {
337   return o << f_name ;
338 }
339
340 ostream &
341 BinaryOperatorNode::print(ostream &o) const
342 {
343   o << "(" << *f_left << ' ';
344   switch (f_operator)
345     {
346     case PLUS:
347       o << '+' ;
348       break;
349     case MINUS:
350       o << '-';
351       break;
352     case TIMES:
353       o << '*' ;
354       break;
355     case DIVIDE:
356       o << '/';
357       break;
358     }
359
360   return o << ' ' << *f_right << ')' ;
361 }
362
363 ostream &
364 SgmlAttributeNode::print(ostream &o) const
365 {
366   return o << '@' << f_name ;
367 }
368
369 ostream &
370 ConstantNode::print(ostream &o) const
371 {
372   return o << *f_value ;
373 }
374
375
376 ostream &
377 CompositeVariableNode::print(ostream &o) const
378 {
379   int length = f_items.entries();
380   for (int i = 0; i < length; i++)
381     {
382       o << *f_items[i] ;
383       if (i < length - 1)
384         o << "." ;
385     }
386
387   return o ;
388 }
389
390 // /////////////////////////////////////////////////////////////////////////
391 // cloning
392 // /////////////////////////////////////////////////////////////////////////
393
394 TermNode *
395 VariableNode::clone() const
396 {
397   return new VariableNode(f_name);
398 }
399
400 TermNode *
401 CompositeVariableNode::clone() const
402 {
403   int nitems = f_items.entries();
404   CompositeVariableNode *node = new CompositeVariableNode(nitems);
405
406   for (int i = 0; i < nitems; i++)
407     node->appendItem(*f_items(i));
408
409   return node ;
410 }
411
412 TermNode *
413 BinaryOperatorNode::clone() const
414 {
415   return new BinaryOperatorNode(f_operator, f_left->clone(), f_right->clone());
416 }
417
418 TermNode *
419 SgmlAttributeNode::clone() const
420 {
421   return new SgmlAttributeNode(f_name);
422 }
423
424 TermNode *
425 ConstantNode::clone() const
426 {
427   return new ConstantNode(f_value->clone());
428 }
429