]> git.mxchange.org Git - simgear.git/blob - simgear/structure/SGExpression.cxx
b042cb90578a21318c37bc0ce64a526955932314
[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 (unsigned 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 }
105
106 // template<typename T>
107 // static SGExpression<T>*
108 // SGReadBExpression(SGPropertyNode *inputRoot, const SGPropertyNode *expression)
109 // {
110 //   if (!expression)
111 //     return 0;
112
113 //   std::string name = expression->getName();
114 //   if (name == "value") {
115 //     T value;
116 //     if (!SGReadValueFromContent(expression, value)) {
117 //       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"value\" expression.");
118 //       return 0;
119 //     }
120 //     return new SGConstExpression<T>(value);
121 //   }
122
123 //   return 0;
124 // }
125
126 template<typename T>
127 static SGExpression<T>*
128 SGReadIExpression(SGPropertyNode *inputRoot, const SGPropertyNode *expression)
129 {
130   if (!expression)
131     return 0;
132
133   std::string name = expression->getName();
134   if (name == "value") {
135     T value;
136     if (!SGReadValueFromContent(expression, value)) {
137       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"value\" expression.");
138       return 0;
139     }
140     return new SGConstExpression<T>(value);
141   }
142
143   if (name == "property") {
144     if (!inputRoot) {
145       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.\n"
146              "No inputRoot argument given!");
147       return 0;
148     }
149     if (!expression->getStringValue()) {
150       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
151       return 0;
152     }
153     SGPropertyNode* inputNode;
154     inputNode = inputRoot->getNode(expression->getStringValue(), true);
155     return new SGPropertyExpression<T>(inputNode);
156   }
157
158   if (name == "abs" || name == "fabs") {
159     if (expression->nChildren() != 1) {
160       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
161       return 0;
162     }
163     SGSharedPtr<SGExpression<T> > inputExpression;
164     inputExpression = SGReadIExpression<T>(inputRoot, expression->getChild(0));
165     if (!inputExpression) {
166       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
167       return 0;
168     }
169     return new SGAbsExpression<T>(inputExpression);
170   }
171
172   if (name == "sqr") {
173     if (expression->nChildren() != 1) {
174       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
175       return 0;
176     }
177     SGSharedPtr<SGExpression<T> > inputExpression;
178     inputExpression = SGReadIExpression<T>(inputRoot, expression->getChild(0));
179     if (!inputExpression) {
180       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
181       return 0;
182     }
183     return new SGSqrExpression<T>(inputExpression);
184   }
185
186   if (name == "clip") {
187     if (expression->nChildren() != 3) {
188       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
189       return 0;
190     }
191     const SGPropertyNode* minProperty = expression->getChild("clipMin");
192     T clipMin;
193     if (!SGReadValueFromContent(minProperty, clipMin))
194       clipMin = SGMisc<T>::min(SGLimits<T>::min(), -SGLimits<T>::max());
195
196     const SGPropertyNode* maxProperty = expression->getChild("clipMax");
197     T clipMax;
198     if (!SGReadValueFromContent(maxProperty, clipMax))
199       clipMin = SGLimits<T>::max();
200
201     SGSharedPtr<SGExpression<T> > inputExpression;
202     for (unsigned i = 0; !inputExpression && i < expression->nChildren(); ++i)
203       inputExpression = SGReadIExpression<T>(inputRoot, expression->getChild(i));
204     if (!inputExpression) {
205       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
206       return 0;
207     }
208     return new SGClipExpression<T>(inputExpression, clipMin, clipMax);
209   }
210
211   if (name == "div") {
212     if (expression->nChildren() != 2) {
213       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
214       return 0;
215     }
216     SGSharedPtr<SGExpression<T> > inputExpressions[2] = {
217       SGReadIExpression<T>(inputRoot, expression->getChild(0)),
218       SGReadIExpression<T>(inputRoot, expression->getChild(1))
219     };
220     if (!inputExpressions[0] || !inputExpressions[1]) {
221       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
222       return 0;
223     }
224     return new SGDivExpression<T>(inputExpressions[0], inputExpressions[1]);
225   }
226   if (name == "mod") {
227     if (expression->nChildren() != 2) {
228       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
229       return 0;
230     }
231     SGSharedPtr<SGExpression<T> > inputExpressions[2] = {
232       SGReadIExpression<T>(inputRoot, expression->getChild(0)),
233       SGReadIExpression<T>(inputRoot, expression->getChild(1))
234     };
235     if (!inputExpressions[0] || !inputExpressions[1]) {
236       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
237       return 0;
238     }
239     return new SGModExpression<T>(inputExpressions[0], inputExpressions[1]);
240   }
241
242   if (name == "sum") {
243     if (expression->nChildren() < 1) {
244       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
245       return 0;
246     }
247     SGSumExpression<T>* output = new SGSumExpression<T>;
248     if (!SGReadNaryOperands(output, inputRoot, expression)) {
249       delete output;
250       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
251       return 0;
252     }
253     return output;
254   }
255   if (name == "prod" || name == "product") {
256     if (expression->nChildren() < 1) {
257       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
258       return 0;
259     }
260     SGProductExpression<T>* output = new SGProductExpression<T>;
261     if (!SGReadNaryOperands(output, inputRoot, expression)) {
262       delete output;
263       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
264       return 0;
265     }
266     return output;
267   }
268   if (name == "min") {
269     if (expression->nChildren() < 1) {
270       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
271       return 0;
272     }
273     SGMinExpression<T>* output = new SGMinExpression<T>;
274     if (!SGReadNaryOperands(output, inputRoot, expression)) {
275       delete output;
276       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
277       return 0;
278     }
279     return output;
280   }
281   if (name == "max") {
282     if (expression->nChildren() < 1) {
283       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
284       return 0;
285     }
286     SGMaxExpression<T>* output = new SGMaxExpression<T>;
287     if (!SGReadNaryOperands(output, inputRoot, expression)) {
288       delete output;
289       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
290       return 0;
291     }
292     return output;
293   }
294
295   return 0;
296 }
297
298
299 template<typename T>
300 static SGExpression<T>*
301 SGReadFExpression(SGPropertyNode *inputRoot, const SGPropertyNode *expression)
302 {
303   SGExpression<T>* r = SGReadIExpression<T>(inputRoot, expression);
304   if (r)
305     return r;
306
307   if (!expression)
308     return 0;
309
310   std::string name = expression->getName();
311   if (name == "acos") {
312     if (expression->nChildren() != 1) {
313       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
314       return 0;
315     }
316     SGSharedPtr<SGExpression<T> > inputExpression;
317     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
318     if (!inputExpression) {
319       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
320       return 0;
321     }
322     return new SGACosExpression<T>(inputExpression);
323   }
324
325   if (name == "asin") {
326     if (expression->nChildren() != 1) {
327       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
328       return 0;
329     }
330     SGSharedPtr<SGExpression<T> > inputExpression;
331     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
332     if (!inputExpression) {
333       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
334       return 0;
335     }
336     return new SGASinExpression<T>(inputExpression);
337   }
338
339   if (name == "atan") {
340     if (expression->nChildren() != 1) {
341       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
342       return 0;
343     }
344     SGSharedPtr<SGExpression<T> > inputExpression;
345     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
346     if (!inputExpression) {
347       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
348       return 0;
349     }
350     return new SGATanExpression<T>(inputExpression);
351   }
352
353   if (name == "ceil") {
354     if (expression->nChildren() != 1) {
355       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
356       return 0;
357     }
358     SGSharedPtr<SGExpression<T> > inputExpression;
359     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
360     if (!inputExpression) {
361       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
362       return 0;
363     }
364     return new SGCeilExpression<T>(inputExpression);
365   }
366
367   if (name == "cos") {
368     if (expression->nChildren() != 1) {
369       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
370       return 0;
371     }
372     SGSharedPtr<SGExpression<T> > inputExpression;
373     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
374     if (!inputExpression) {
375       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
376       return 0;
377     }
378     return new SGCosExpression<T>(inputExpression);
379   }
380
381   if (name == "cosh") {
382     if (expression->nChildren() != 1) {
383       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
384       return 0;
385     }
386     SGSharedPtr<SGExpression<T> > inputExpression;
387     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
388     if (!inputExpression) {
389       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
390       return 0;
391     }
392     return new SGCoshExpression<T>(inputExpression);
393   }
394
395   if (name == "deg2rad") {
396     if (expression->nChildren() != 1) {
397       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
398       return 0;
399     }
400     SGSharedPtr<SGExpression<T> > inputExpression;
401     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
402     if (!inputExpression) {
403       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
404       return 0;
405     }
406     return new SGScaleExpression<T>(inputExpression, SGMisc<T>::pi()/180);
407   }
408
409   if (name == "exp") {
410     if (expression->nChildren() != 1) {
411       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
412       return 0;
413     }
414     SGSharedPtr<SGExpression<T> > inputExpression;
415     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
416     if (!inputExpression) {
417       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
418       return 0;
419     }
420     return new SGExpExpression<T>(inputExpression);
421   }
422
423   if (name == "floor") {
424     if (expression->nChildren() != 1) {
425       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
426       return 0;
427     }
428     SGSharedPtr<SGExpression<T> > inputExpression;
429     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
430     if (!inputExpression) {
431       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
432       return 0;
433     }
434     return new SGFloorExpression<T>(inputExpression);
435   }
436
437   if (name == "log") {
438     if (expression->nChildren() != 1) {
439       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
440       return 0;
441     }
442     SGSharedPtr<SGExpression<T> > inputExpression;
443     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
444     if (!inputExpression) {
445       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
446       return 0;
447     }
448     return new SGLogExpression<T>(inputExpression);
449   }
450
451   if (name == "log10") {
452     if (expression->nChildren() != 1) {
453       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
454       return 0;
455     }
456     SGSharedPtr<SGExpression<T> > inputExpression;
457     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
458     if (!inputExpression) {
459       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
460       return 0;
461     }
462     return new SGLog10Expression<T>(inputExpression);
463   }
464
465   if (name == "rad2deg") {
466     if (expression->nChildren() != 1) {
467       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
468       return 0;
469     }
470     SGSharedPtr<SGExpression<T> > inputExpression;
471     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
472     if (!inputExpression) {
473       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
474       return 0;
475     }
476     return new SGScaleExpression<T>(inputExpression, 180/SGMisc<T>::pi());
477   }
478
479   if (name == "sin") {
480     if (expression->nChildren() != 1) {
481       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
482       return 0;
483     }
484     SGSharedPtr<SGExpression<T> > inputExpression;
485     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
486     if (!inputExpression) {
487       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
488       return 0;
489     }
490     return new SGSinExpression<T>(inputExpression);
491   }
492
493   if (name == "sinh") {
494     if (expression->nChildren() != 1) {
495       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
496       return 0;
497     }
498     SGSharedPtr<SGExpression<T> > inputExpression;
499     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
500     if (!inputExpression) {
501       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
502       return 0;
503     }
504     return new SGSinhExpression<T>(inputExpression);
505   }
506
507   if (name == "sqrt") {
508     if (expression->nChildren() != 1) {
509       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
510       return 0;
511     }
512     SGSharedPtr<SGExpression<T> > inputExpression;
513     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
514     if (!inputExpression) {
515       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
516       return 0;
517     }
518     return new SGSqrtExpression<T>(inputExpression);
519   }
520
521   if (name == "tan") {
522     if (expression->nChildren() != 1) {
523       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
524       return 0;
525     }
526     SGSharedPtr<SGExpression<T> > inputExpression;
527     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
528     if (!inputExpression) {
529       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
530       return 0;
531     }
532     return new SGTanExpression<T>(inputExpression);
533   }
534
535   if (name == "tanh") {
536     if (expression->nChildren() != 1) {
537       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
538       return 0;
539     }
540     SGSharedPtr<SGExpression<T> > inputExpression;
541     inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
542     if (!inputExpression) {
543       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
544       return 0;
545     }
546     return new SGTanhExpression<T>(inputExpression);
547   }
548
549 // if (name == "table") {
550 // }
551 // if (name == "step") {
552 // }
553 // if (name == "condition") {
554 // }
555
556   if (name == "atan2") {
557     if (expression->nChildren() != 2) {
558       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
559       return 0;
560     }
561     SGSharedPtr<SGExpression<T> > inputExpressions[2] = {
562       SGReadFExpression<T>(inputRoot, expression->getChild(0)),
563       SGReadFExpression<T>(inputRoot, expression->getChild(1))
564     };
565     if (!inputExpressions[0] || !inputExpressions[1]) {
566       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
567       return 0;
568     }
569     return new SGAtan2Expression<T>(inputExpressions[0], inputExpressions[1]);
570   }
571   if (name == "div") {
572     if (expression->nChildren() != 2) {
573       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
574       return 0;
575     }
576     SGSharedPtr<SGExpression<T> > inputExpressions[2] = {
577       SGReadFExpression<T>(inputRoot, expression->getChild(0)),
578       SGReadFExpression<T>(inputRoot, expression->getChild(1))
579     };
580     if (!inputExpressions[0] || !inputExpressions[1]) {
581       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
582       return 0;
583     }
584     return new SGDivExpression<T>(inputExpressions[0], inputExpressions[1]);
585   }
586   if (name == "mod") {
587     if (expression->nChildren() != 2) {
588       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
589       return 0;
590     }
591     SGSharedPtr<SGExpression<T> > inputExpressions[2] = {
592       SGReadFExpression<T>(inputRoot, expression->getChild(0)),
593       SGReadFExpression<T>(inputRoot, expression->getChild(1))
594     };
595     if (!inputExpressions[0] || !inputExpressions[1]) {
596       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
597       return 0;
598     }
599     return new SGModExpression<T>(inputExpressions[0], inputExpressions[1]);
600   }
601   if (name == "pow") {
602     if (expression->nChildren() != 2) {
603       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
604       return 0;
605     }
606     SGSharedPtr<SGExpression<T> > inputExpressions[2] = {
607       SGReadIExpression<T>(inputRoot, expression->getChild(0)),
608       SGReadIExpression<T>(inputRoot, expression->getChild(1))
609     };
610     if (!inputExpressions[0] || !inputExpressions[1]) {
611       SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
612       return 0;
613     }
614     return new SGPowExpression<T>(inputExpressions[0], inputExpressions[1]);
615   }
616
617   return 0;
618 }
619
620 SGExpression<int>*
621 SGReadIntExpression(SGPropertyNode *inputRoot,
622                     const SGPropertyNode *configNode)
623 { return SGReadIExpression<int>(inputRoot, configNode); }
624
625 SGExpression<float>*
626 SGReadFloatExpression(SGPropertyNode *inputRoot,
627                       const SGPropertyNode *configNode)
628 { return SGReadFExpression<float>(inputRoot, configNode); }
629
630 SGExpression<double>*
631 SGReadDoubleExpression(SGPropertyNode *inputRoot,
632                        const SGPropertyNode *configNode)
633 { return SGReadFExpression<double>(inputRoot, configNode); }
634
635 // SGExpression<bool>*
636 // SGReadBoolExpression(SGPropertyNode *inputRoot,
637 //                      const SGPropertyNode *configNode)
638 // { return SGReadBExpression<bool>(inputRoot, configNode); }