]> git.mxchange.org Git - simgear.git/blob - simgear/structure/SGExpression.cxx
5a04c509ced1bdf404ffd9c50108d700f3b9b1a6
[simgear.git] / simgear / structure / SGExpression.cxx
1 /* -*-c++-*-
2  *
3  * Copyright (C) 2006-2007 Mathias Froehlich 
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * 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 Street, Fifth Floor, Boston,
18  * MA 02110-1301, USA.
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #  include <simgear_config.h>
24 #endif
25
26 #include "SGExpression.hxx"
27
28 #include <string>
29 #include <sstream>
30 #include <simgear/props/props.hxx>
31
32 template<typename T>
33 static bool
34 SGReadValueFromString(const char* str, T& value)
35 {
36   if (!str) {
37     SG_LOG(SG_IO, SG_ALERT, "Cannot read string content.");
38     return false;
39   }
40   std::stringstream s;
41   s.str(std::string(str));
42   s >> value;
43   if (s.fail()) {
44     SG_LOG(SG_IO, SG_ALERT, "Cannot read string content.");
45     return false;
46   }
47   return true;
48 }
49
50 template<>
51 static bool
52 SGReadValueFromString(const char* str, bool& value)
53 {
54   if (!str) {
55     SG_LOG(SG_IO, SG_ALERT, "Cannot read string content.");
56     return false;
57   }
58   std::stringstream s;
59   s.str(std::string(str));
60   s >> value;
61   if (!s.fail())
62     return true;
63
64   std::string stdstr;
65   if (!SGReadValueFromString(str, stdstr))
66     return false;
67
68   if (stdstr == "true" || stdstr == "True" || stdstr == "TRUE") {
69     value = true;
70     return true;
71   }
72   if (stdstr == "false" || stdstr == "False" || stdstr == "FALSE") {
73     value = true;
74     return true;
75   }
76   return false;
77 }
78
79 template<typename T>
80 static bool
81 SGReadValueFromContent(const SGPropertyNode *node, T& value)
82 {
83   if (!node)
84     return false;
85   return SGReadValueFromString(node->getStringValue(), value);
86 }
87
88 template<typename T>
89 static SGExpression<T>*
90 SGReadIExpression(SGPropertyNode *inputRoot, const SGPropertyNode *expression);
91
92 template<typename T>
93 static bool
94 SGReadNaryOperands(SGNaryExpression<T>* nary,
95                    SGPropertyNode *inputRoot, const SGPropertyNode *expression)
96 {
97   for (int i = 0; i < expression->nChildren(); ++i) {
98     SGExpression<T>* inputExpression;
99     inputExpression = SGReadIExpression<T>(inputRoot, expression->getChild(i));
100     if (!inputExpression)
101       return false;
102     nary->addOperand(inputExpression);
103   }
104   return true;
105 }
106
107 // template<typename T>
108 // static SGExpression<T>*
109 // SGReadBExpression(SGPropertyNode *inputRoot, const SGPropertyNode *expression)
110 // {
111 //   if (!expression)
112 //     return 0;
113
114 //   std::string name = expression->getName();
115 //   if (name == "value") {
116 //     T value;
117 //     if (!SGReadValueFromContent(expression, value)) {
118 //       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"value\" expression.");
119 //       return 0;
120 //     }
121 //     return new SGConstExpression<T>(value);
122 //   }
123
124 //   return 0;
125 // }
126
127 template<typename T>
128 static SGExpression<T>*
129 SGReadIExpression(SGPropertyNode *inputRoot, const SGPropertyNode *expression)
130 {
131   if (!expression)
132     return 0;
133
134   std::string name = expression->getName();
135   if (name == "value") {
136     T value;
137     if (!SGReadValueFromContent(expression, value)) {
138       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"value\" expression.");
139       return 0;
140     }
141     return new SGConstExpression<T>(value);
142   }
143
144   if (name == "property") {
145     if (!inputRoot) {
146       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.\n"
147              "No inputRoot argument given!");
148       return 0;
149     }
150     if (!expression->getStringValue()) {
151       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
152       return 0;
153     }
154     SGPropertyNode* inputNode;
155     inputNode = inputRoot->getNode(expression->getStringValue(), true);
156     return new SGPropertyExpression<T>(inputNode);
157   }
158
159   if (name == "abs" || name == "fabs") {
160     if (expression->nChildren() != 1) {
161       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
162       return 0;
163     }
164     SGSharedPtr<SGExpression<T> > inputExpression;
165     inputExpression = SGReadIExpression<T>(inputRoot, expression->getChild(0));
166     if (!inputExpression) {
167       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
168       return 0;
169     }
170     return new SGAbsExpression<T>(inputExpression);
171   }
172
173   if (name == "sqr") {
174     if (expression->nChildren() != 1) {
175       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
176       return 0;
177     }
178     SGSharedPtr<SGExpression<T> > inputExpression;
179     inputExpression = SGReadIExpression<T>(inputRoot, expression->getChild(0));
180     if (!inputExpression) {
181       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
182       return 0;
183     }
184     return new SGSqrExpression<T>(inputExpression);
185   }
186
187   if (name == "clip") {
188     if (expression->nChildren() != 3) {
189       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
190       return 0;
191     }
192     const SGPropertyNode* minProperty = expression->getChild("clipMin");
193     T clipMin;
194     if (!SGReadValueFromContent(minProperty, clipMin))
195       clipMin = SGMisc<T>::min(SGLimits<T>::min(), -SGLimits<T>::max());
196
197     const SGPropertyNode* maxProperty = expression->getChild("clipMax");
198     T clipMax;
199     if (!SGReadValueFromContent(maxProperty, clipMax))
200       clipMin = SGLimits<T>::max();
201
202     SGSharedPtr<SGExpression<T> > inputExpression;
203     for (int i = 0; !inputExpression && i < expression->nChildren(); ++i)
204       inputExpression = SGReadIExpression<T>(inputRoot, expression->getChild(i));
205     if (!inputExpression) {
206       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
207       return 0;
208     }
209     return new SGClipExpression<T>(inputExpression, clipMin, clipMax);
210   }
211
212   if (name == "div") {
213     if (expression->nChildren() != 2) {
214       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
215       return 0;
216     }
217     SGSharedPtr<SGExpression<T> > inputExpressions[2] = {
218       SGReadIExpression<T>(inputRoot, expression->getChild(0)),
219       SGReadIExpression<T>(inputRoot, expression->getChild(1))
220     };
221     if (!inputExpressions[0] || !inputExpressions[1]) {
222       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
223       return 0;
224     }
225     return new SGDivExpression<T>(inputExpressions[0], inputExpressions[1]);
226   }
227   if (name == "mod") {
228     if (expression->nChildren() != 2) {
229       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
230       return 0;
231     }
232     SGSharedPtr<SGExpression<T> > inputExpressions[2] = {
233       SGReadIExpression<T>(inputRoot, expression->getChild(0)),
234       SGReadIExpression<T>(inputRoot, expression->getChild(1))
235     };
236     if (!inputExpressions[0] || !inputExpressions[1]) {
237       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
238       return 0;
239     }
240     return new SGModExpression<T>(inputExpressions[0], inputExpressions[1]);
241   }
242
243   if (name == "sum") {
244     if (expression->nChildren() < 1) {
245       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
246       return 0;
247     }
248     SGSumExpression<T>* output = new SGSumExpression<T>;
249     if (!SGReadNaryOperands(output, inputRoot, expression)) {
250       delete output;
251       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
252       return 0;
253     }
254     return output;
255   }
256   if (name == "prod" || name == "product") {
257     if (expression->nChildren() < 1) {
258       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
259       return 0;
260     }
261     SGProductExpression<T>* output = new SGProductExpression<T>;
262     if (!SGReadNaryOperands(output, inputRoot, expression)) {
263       delete output;
264       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
265       return 0;
266     }
267     return output;
268   }
269   if (name == "min") {
270     if (expression->nChildren() < 1) {
271       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
272       return 0;
273     }
274     SGMinExpression<T>* output = new SGMinExpression<T>;
275     if (!SGReadNaryOperands(output, inputRoot, expression)) {
276       delete output;
277       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
278       return 0;
279     }
280     return output;
281   }
282   if (name == "max") {
283     if (expression->nChildren() < 1) {
284       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
285       return 0;
286     }
287     SGMaxExpression<T>* output = new SGMaxExpression<T>;
288     if (!SGReadNaryOperands(output, inputRoot, expression)) {
289       delete output;
290       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
291       return 0;
292     }
293     return output;
294   }
295
296   return 0;
297 }
298
299
300 template<typename T>
301 static SGExpression<T>*
302 SGReadFExpression(SGPropertyNode *inputRoot, const SGPropertyNode *expression)
303 {
304   SGExpression<T>* r = SGReadIExpression<T>(inputRoot, expression);
305   if (r)
306     return r;
307
308   if (!expression)
309     return 0;
310
311   std::string name = expression->getName();
312   if (name == "acos") {
313     if (expression->nChildren() != 1) {
314       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
315       return 0;
316     }
317     SGSharedPtr<SGExpression<T> > inputExpression;
318     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
319     if (!inputExpression) {
320       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
321       return 0;
322     }
323     return new SGACosExpression<T>(inputExpression);
324   }
325
326   if (name == "asin") {
327     if (expression->nChildren() != 1) {
328       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
329       return 0;
330     }
331     SGSharedPtr<SGExpression<T> > inputExpression;
332     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
333     if (!inputExpression) {
334       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
335       return 0;
336     }
337     return new SGASinExpression<T>(inputExpression);
338   }
339
340   if (name == "atan") {
341     if (expression->nChildren() != 1) {
342       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
343       return 0;
344     }
345     SGSharedPtr<SGExpression<T> > inputExpression;
346     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
347     if (!inputExpression) {
348       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
349       return 0;
350     }
351     return new SGATanExpression<T>(inputExpression);
352   }
353
354   if (name == "ceil") {
355     if (expression->nChildren() != 1) {
356       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
357       return 0;
358     }
359     SGSharedPtr<SGExpression<T> > inputExpression;
360     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
361     if (!inputExpression) {
362       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
363       return 0;
364     }
365     return new SGCeilExpression<T>(inputExpression);
366   }
367
368   if (name == "cos") {
369     if (expression->nChildren() != 1) {
370       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
371       return 0;
372     }
373     SGSharedPtr<SGExpression<T> > inputExpression;
374     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
375     if (!inputExpression) {
376       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
377       return 0;
378     }
379     return new SGCosExpression<T>(inputExpression);
380   }
381
382   if (name == "cosh") {
383     if (expression->nChildren() != 1) {
384       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
385       return 0;
386     }
387     SGSharedPtr<SGExpression<T> > inputExpression;
388     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
389     if (!inputExpression) {
390       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
391       return 0;
392     }
393     return new SGCoshExpression<T>(inputExpression);
394   }
395
396   if (name == "deg2rad") {
397     if (expression->nChildren() != 1) {
398       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
399       return 0;
400     }
401     SGSharedPtr<SGExpression<T> > inputExpression;
402     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
403     if (!inputExpression) {
404       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
405       return 0;
406     }
407     return new SGScaleExpression<T>(inputExpression, SGMisc<T>::pi()/180);
408   }
409
410   if (name == "exp") {
411     if (expression->nChildren() != 1) {
412       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
413       return 0;
414     }
415     SGSharedPtr<SGExpression<T> > inputExpression;
416     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
417     if (!inputExpression) {
418       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
419       return 0;
420     }
421     return new SGExpExpression<T>(inputExpression);
422   }
423
424   if (name == "floor") {
425     if (expression->nChildren() != 1) {
426       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
427       return 0;
428     }
429     SGSharedPtr<SGExpression<T> > inputExpression;
430     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
431     if (!inputExpression) {
432       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
433       return 0;
434     }
435     return new SGFloorExpression<T>(inputExpression);
436   }
437
438   if (name == "log") {
439     if (expression->nChildren() != 1) {
440       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
441       return 0;
442     }
443     SGSharedPtr<SGExpression<T> > inputExpression;
444     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
445     if (!inputExpression) {
446       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
447       return 0;
448     }
449     return new SGLogExpression<T>(inputExpression);
450   }
451
452   if (name == "log10") {
453     if (expression->nChildren() != 1) {
454       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
455       return 0;
456     }
457     SGSharedPtr<SGExpression<T> > inputExpression;
458     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
459     if (!inputExpression) {
460       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
461       return 0;
462     }
463     return new SGLog10Expression<T>(inputExpression);
464   }
465
466   if (name == "rad2deg") {
467     if (expression->nChildren() != 1) {
468       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
469       return 0;
470     }
471     SGSharedPtr<SGExpression<T> > inputExpression;
472     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
473     if (!inputExpression) {
474       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
475       return 0;
476     }
477     return new SGScaleExpression<T>(inputExpression, 180/SGMisc<T>::pi());
478   }
479
480   if (name == "sin") {
481     if (expression->nChildren() != 1) {
482       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
483       return 0;
484     }
485     SGSharedPtr<SGExpression<T> > inputExpression;
486     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
487     if (!inputExpression) {
488       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
489       return 0;
490     }
491     return new SGSinExpression<T>(inputExpression);
492   }
493
494   if (name == "sinh") {
495     if (expression->nChildren() != 1) {
496       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
497       return 0;
498     }
499     SGSharedPtr<SGExpression<T> > inputExpression;
500     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
501     if (!inputExpression) {
502       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
503       return 0;
504     }
505     return new SGSinhExpression<T>(inputExpression);
506   }
507
508   if (name == "sqrt") {
509     if (expression->nChildren() != 1) {
510       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
511       return 0;
512     }
513     SGSharedPtr<SGExpression<T> > inputExpression;
514     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
515     if (!inputExpression) {
516       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
517       return 0;
518     }
519     return new SGSqrtExpression<T>(inputExpression);
520   }
521
522   if (name == "tan") {
523     if (expression->nChildren() != 1) {
524       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
525       return 0;
526     }
527     SGSharedPtr<SGExpression<T> > inputExpression;
528     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
529     if (!inputExpression) {
530       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
531       return 0;
532     }
533     return new SGTanExpression<T>(inputExpression);
534   }
535
536   if (name == "tanh") {
537     if (expression->nChildren() != 1) {
538       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
539       return 0;
540     }
541     SGSharedPtr<SGExpression<T> > inputExpression;
542     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
543     if (!inputExpression) {
544       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
545       return 0;
546     }
547     return new SGTanhExpression<T>(inputExpression);
548   }
549
550 // if (name == "table") {
551 // }
552 // if (name == "step") {
553 // }
554 // if (name == "condition") {
555 // }
556
557   if (name == "atan2") {
558     if (expression->nChildren() != 2) {
559       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
560       return 0;
561     }
562     SGSharedPtr<SGExpression<T> > inputExpressions[2] = {
563       SGReadFExpression<T>(inputRoot, expression->getChild(0)),
564       SGReadFExpression<T>(inputRoot, expression->getChild(1))
565     };
566     if (!inputExpressions[0] || !inputExpressions[1]) {
567       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
568       return 0;
569     }
570     return new SGAtan2Expression<T>(inputExpressions[0], inputExpressions[1]);
571   }
572   if (name == "div") {
573     if (expression->nChildren() != 2) {
574       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
575       return 0;
576     }
577     SGSharedPtr<SGExpression<T> > inputExpressions[2] = {
578       SGReadFExpression<T>(inputRoot, expression->getChild(0)),
579       SGReadFExpression<T>(inputRoot, expression->getChild(1))
580     };
581     if (!inputExpressions[0] || !inputExpressions[1]) {
582       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
583       return 0;
584     }
585     return new SGDivExpression<T>(inputExpressions[0], inputExpressions[1]);
586   }
587   if (name == "mod") {
588     if (expression->nChildren() != 2) {
589       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
590       return 0;
591     }
592     SGSharedPtr<SGExpression<T> > inputExpressions[2] = {
593       SGReadFExpression<T>(inputRoot, expression->getChild(0)),
594       SGReadFExpression<T>(inputRoot, expression->getChild(1))
595     };
596     if (!inputExpressions[0] || !inputExpressions[1]) {
597       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
598       return 0;
599     }
600     return new SGModExpression<T>(inputExpressions[0], inputExpressions[1]);
601   }
602   if (name == "pow") {
603     if (expression->nChildren() != 2) {
604       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
605       return 0;
606     }
607     SGSharedPtr<SGExpression<T> > inputExpressions[2] = {
608       SGReadIExpression<T>(inputRoot, expression->getChild(0)),
609       SGReadIExpression<T>(inputRoot, expression->getChild(1))
610     };
611     if (!inputExpressions[0] || !inputExpressions[1]) {
612       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
613       return 0;
614     }
615     return new SGPowExpression<T>(inputExpressions[0], inputExpressions[1]);
616   }
617
618   return 0;
619 }
620
621 SGExpression<int>*
622 SGReadIntExpression(SGPropertyNode *inputRoot,
623                     const SGPropertyNode *configNode)
624 { return SGReadIExpression<int>(inputRoot, configNode); }
625
626 SGExpression<float>*
627 SGReadFloatExpression(SGPropertyNode *inputRoot,
628                       const SGPropertyNode *configNode)
629 { return SGReadFExpression<float>(inputRoot, configNode); }
630
631 SGExpression<double>*
632 SGReadDoubleExpression(SGPropertyNode *inputRoot,
633                        const SGPropertyNode *configNode)
634 { return SGReadFExpression<double>(inputRoot, configNode); }
635
636 // SGExpression<bool>*
637 // SGReadBoolExpression(SGPropertyNode *inputRoot,
638 //                      const SGPropertyNode *configNode)
639 // { return SGReadBExpression<bool>(inputRoot, configNode); }