MADARA  3.4.1
Interpreter.cpp
Go to the documentation of this file.
1 #ifndef _INTERPRETER_CPP_
2 #define _INTERPRETER_CPP_
3 
4 #ifndef _MADARA_NO_KARL_
5 
6 #include <math.h>
7 #include <iostream>
8 #include <sstream>
9 #include <memory>
10 
87 
89 
91 
92 namespace madara
93 {
94 namespace expression
95 {
96 enum
97 {
114 };
115 
120 class Symbol
121 {
122 public:
124  Symbol(
125  logger::Logger& logger, Symbol* left, Symbol* right, int precedence_ = 0);
126 
128  virtual ~Symbol(void);
129 
132  virtual int precedence(void)
133  {
134  return precedence_;
135  }
136 
137  virtual int add_precedence(int accumulated_precedence) = 0;
138 
140 
141  virtual ComponentNode* build(void) = 0;
142 
144 
149 };
150 
151 typedef std::vector<Symbol*> Symbols;
152 
158 class Operator : public Symbol
159 {
160 public:
162  Operator(
163  logger::Logger& logger, Symbol* left, Symbol* right, int precedence_ = 1);
164 
166  virtual ~Operator(void);
167 };
168 
174 class TernaryOperator : public Operator
175 {
176 public:
179  logger::Logger& logger, Symbol* left, Symbol* right, int precedence_ = 1);
180 
182  virtual ~TernaryOperator(void);
183 
185 };
186 
193 {
194 public:
197 
199  virtual ~SystemCall(void);
200 
203 };
204 
209 class ClearVariable : public SystemCall
210 {
211 public:
214 
216  virtual int add_precedence(int accumulated_precedence);
217 
219  virtual ComponentNode* build(void);
220 
222  virtual ~ClearVariable(void);
223 };
224 
230 {
231 public:
234 
236  virtual int add_precedence(int accumulated_precedence);
237 
239  virtual ComponentNode* build(void);
240 
242  virtual ~DeleteVariable(void);
243 };
244 
249 class Eval : public SystemCall
250 {
251 public:
254 
256  virtual int add_precedence(int accumulated_precedence);
257 
259  virtual ComponentNode* build(void);
260 
262  virtual ~Eval(void);
263 };
264 
269 class ExpandEnv : public SystemCall
270 {
271 public:
274 
276  virtual int add_precedence(int accumulated_precedence);
277 
279  virtual ComponentNode* build(void);
280 
282  virtual ~ExpandEnv(void);
283 };
284 
290 {
291 public:
294 
296  virtual int add_precedence(int accumulated_precedence);
297 
299  virtual ComponentNode* build(void);
300 
302  virtual ~ExpandStatement(void);
303 };
304 
309 class Fragment : public SystemCall
310 {
311 public:
314 
316  virtual int add_precedence(int accumulated_precedence);
317 
319  virtual ComponentNode* build(void);
320 
322  virtual ~Fragment(void);
323 };
324 
329 class Print : public SystemCall
330 {
331 public:
334 
336  virtual int add_precedence(int accumulated_precedence);
337 
339  virtual ComponentNode* build(void);
340 
342  virtual ~Print(void);
343 };
344 
349 class Cos : public SystemCall
350 {
351 public:
354 
356  virtual int add_precedence(int accumulated_precedence);
357 
359  virtual ComponentNode* build(void);
360 
362  virtual ~Cos(void);
363 };
364 
369 class Sin : public SystemCall
370 {
371 public:
374 
376  virtual int add_precedence(int accumulated_precedence);
377 
379  virtual ComponentNode* build(void);
380 
382  virtual ~Sin(void);
383 };
384 
389 class Tan : public SystemCall
390 {
391 public:
394 
396  virtual int add_precedence(int accumulated_precedence);
397 
399  virtual ComponentNode* build(void);
400 
402  virtual ~Tan(void);
403 };
404 
409 class Power : public SystemCall
410 {
411 public:
414 
416  virtual int add_precedence(int accumulated_precedence);
417 
419  virtual ComponentNode* build(void);
420 
422  virtual ~Power(void);
423 };
424 
429 class SquareRoot : public SystemCall
430 {
431 public:
434 
436  virtual int add_precedence(int accumulated_precedence);
437 
439  virtual ComponentNode* build(void);
440 
442  virtual ~SquareRoot(void);
443 };
444 
450 {
451 public:
454 
456  virtual int add_precedence(int accumulated_precedence);
457 
459  virtual ComponentNode* build(void);
460 
462  virtual ~PrintSystemCalls(void);
463 };
464 
469 class RandDouble : public SystemCall
470 {
471 public:
474 
476  virtual int add_precedence(int accumulated_precedence);
477 
479  virtual ComponentNode* build(void);
480 
482  virtual ~RandDouble(void);
483 };
484 
489 class RandInt : public SystemCall
490 {
491 public:
494 
496  virtual int add_precedence(int accumulated_precedence);
497 
499  virtual ComponentNode* build(void);
500 
502  virtual ~RandInt(void);
503 };
504 
509 class ReadFile : public SystemCall
510 {
511 public:
514 
516  virtual int add_precedence(int accumulated_precedence);
517 
519  virtual ComponentNode* build(void);
520 
522  virtual ~ReadFile(void);
523 };
524 
529 class WriteFile : public SystemCall
530 {
531 public:
534 
536  virtual int add_precedence(int accumulated_precedence);
537 
539  virtual ComponentNode* build(void);
540 
542  virtual ~WriteFile(void);
543 };
544 
549 class Size : public SystemCall
550 {
551 public:
554 
556  virtual int add_precedence(int accumulated_precedence);
557 
559  virtual ComponentNode* build(void);
560 
562  virtual ~Size(void);
563 };
564 
569 class SetFixed : public SystemCall
570 {
571 public:
574 
576  virtual int add_precedence(int accumulated_precedence);
577 
579  virtual ComponentNode* build(void);
580 
582  virtual ~SetFixed(void);
583 };
584 
589 class SetPrecision : public SystemCall
590 {
591 public:
594 
596  virtual int add_precedence(int accumulated_precedence);
597 
599  virtual ComponentNode* build(void);
600 
602  virtual ~SetPrecision(void);
603 };
604 
609 class SetScientific : public SystemCall
610 {
611 public:
614 
616  virtual int add_precedence(int accumulated_precedence);
617 
619  virtual ComponentNode* build(void);
620 
622  virtual ~SetScientific(void);
623 };
624 
629 class ToBuffer : public SystemCall
630 {
631 public:
634 
636  virtual int add_precedence(int accumulated_precedence);
637 
639  virtual ComponentNode* build(void);
640 
642  virtual ~ToBuffer(void);
643 };
644 
649 class ToDouble : public SystemCall
650 {
651 public:
654 
656  virtual int add_precedence(int accumulated_precedence);
657 
659  virtual ComponentNode* build(void);
660 
662  virtual ~ToDouble(void);
663 };
664 
669 class ToDoubles : public SystemCall
670 {
671 public:
674 
676  virtual int add_precedence(int accumulated_precedence);
677 
679  virtual ComponentNode* build(void);
680 
682  virtual ~ToDoubles(void);
683 };
684 
690 class ToHostDirs : public SystemCall
691 {
692 public:
695 
697  virtual int add_precedence(int accumulated_precedence);
698 
700  virtual ComponentNode* build(void);
701 
703  virtual ~ToHostDirs(void);
704 };
705 
710 class ToInteger : public SystemCall
711 {
712 public:
715 
717  virtual int add_precedence(int accumulated_precedence);
718 
720  virtual ComponentNode* build(void);
721 
723  virtual ~ToInteger(void);
724 };
725 
730 class ToIntegers : public SystemCall
731 {
732 public:
735 
737  virtual int add_precedence(int accumulated_precedence);
738 
740  virtual ComponentNode* build(void);
741 
743  virtual ~ToIntegers(void);
744 };
745 
750 class ToString : public SystemCall
751 {
752 public:
755 
757  virtual int add_precedence(int accumulated_precedence);
758 
760  virtual ComponentNode* build(void);
761 
763  virtual ~ToString(void);
764 };
765 
770 class Sleep : public SystemCall
771 {
772 public:
775 
777  virtual int add_precedence(int accumulated_precedence);
778 
780  virtual ComponentNode* build(void);
781 
783  virtual ~Sleep(void);
784 };
785 
790 class Type : public SystemCall
791 {
792 public:
795 
797  virtual int add_precedence(int accumulated_precedence);
798 
800  virtual ComponentNode* build(void);
801 
803  virtual ~Type(void);
804 };
805 
810 class Isinf : public SystemCall
811 {
812 public:
815 
817  virtual int add_precedence(int accumulated_precedence);
818 
820  virtual ComponentNode* build(void);
821 
823  virtual ~Isinf(void);
824 };
825 
830 class LogLevel : public SystemCall
831 {
832 public:
835 
837  virtual int add_precedence(int accumulated_precedence);
838 
840  virtual ComponentNode* build(void);
841 
843  virtual ~LogLevel(void);
844 };
845 
850 class GetClock : public SystemCall
851 {
852 public:
855 
857  virtual int add_precedence(int accumulated_precedence);
858 
860  virtual ComponentNode* build(void);
861 
863  virtual ~GetClock(void);
864 };
865 
870 class GetTime : public SystemCall
871 {
872 public:
875 
877  virtual int add_precedence(int accumulated_precedence);
878 
880  virtual ComponentNode* build(void);
881 
883  virtual ~GetTime(void);
884 };
885 
891 {
892 public:
895 
897  virtual int add_precedence(int accumulated_precedence);
898 
900  virtual ComponentNode* build(void);
901 
903  virtual ~GetTimeSeconds(void);
904 };
905 
910 class SetClock : public SystemCall
911 {
912 public:
915 
917  virtual int add_precedence(int accumulated_precedence);
918 
920  virtual ComponentNode* build(void);
921 
923  virtual ~SetClock(void);
924 };
925 
931 class UnaryOperator : public Symbol
932 {
933 public:
936 
938  virtual ~UnaryOperator(void);
939 };
940 
946 class Number : public Symbol
947 {
948 public:
953  Number(logger::Logger& logger, double input);
954 
956  virtual ~Number(void);
957 
959  // virtual int precedence (void);
960  virtual int add_precedence(int accumulated_precedence);
961 
963  virtual ComponentNode* build(void);
964  // private:
967 };
968 
973 class Variable : public Symbol
974 {
975 public:
977  Variable(
979 
981  virtual ~Variable(void);
982 
984  // virtual int precedence (void);
985  virtual int add_precedence(int accumulated_precedence);
986 
988  virtual ComponentNode* build(void);
989  // private:
992 
995 };
996 
1001 class ArrayRef : public Symbol
1002 {
1003 public:
1005  ArrayRef(const std::string& key, Symbol* index,
1007 
1009  virtual ~ArrayRef(void);
1010 
1012  // virtual int precedence (void);
1013  virtual int add_precedence(int accumulated_precedence);
1014 
1016  virtual ComponentNode* build(void);
1017  // private:
1020 
1024 };
1025 
1032 {
1033 public:
1037 
1039  virtual ~VariableDecrement(void);
1040 
1042  // virtual int precedence (void);
1043  virtual int add_precedence(int accumulated_precedence);
1044 
1046  virtual ComponentNode* build(void);
1047  // private:
1049 
1052 
1055 };
1056 
1062 class VariableDivide : public Operator
1063 {
1064 public:
1068 
1070  virtual ~VariableDivide(void);
1071 
1073  // virtual int precedence (void);
1074  virtual int add_precedence(int accumulated_precedence);
1075 
1077  virtual ComponentNode* build(void);
1078  // private:
1080 
1083 
1086 };
1087 
1094 {
1095 public:
1099 
1101  virtual ~VariableIncrement(void);
1102 
1104  // virtual int precedence (void);
1105  virtual int add_precedence(int accumulated_precedence);
1106 
1108  virtual ComponentNode* build(void);
1109  // private:
1111 
1114 
1117 };
1118 
1125 {
1126 public:
1130 
1132  virtual ~VariableMultiply(void);
1133 
1135  // virtual int precedence (void);
1136  virtual int add_precedence(int accumulated_precedence);
1137 
1139  virtual ComponentNode* build(void);
1140  // private:
1142 
1145 
1148 };
1149 
1155 class VariableCompare : public Symbol
1156 {
1157 public:
1160  Symbol* rhs, int compare_type,
1162 
1164  virtual ~VariableCompare(void);
1165 
1167  // virtual int precedence (void);
1168  virtual int add_precedence(int accumulated_precedence);
1169 
1171  virtual ComponentNode* build(void);
1172  // private:
1174 
1177 
1180 
1183 
1186 };
1187 
1193 class List : public Symbol
1194 {
1195 public:
1198 
1200  virtual ~List(void);
1201 
1203  // virtual int precedence (void);
1204  virtual int add_precedence(int accumulated_precedence);
1205 
1207  virtual ComponentNode* build(void);
1208 
1209 private:
1212 };
1213 
1219 class Subtract : public Operator
1220 {
1221 public:
1224 
1226  virtual ~Subtract(void);
1227 
1229  // virtual int precedence (void);
1230  virtual int add_precedence(int accumulated_precedence);
1231 
1233  virtual ComponentNode* build(void);
1234 };
1235 
1241 class Add : public TernaryOperator
1242 {
1243 public:
1246 
1248  virtual ~Add(void);
1249 
1251  virtual int add_precedence(int accumulated_precedence);
1252 
1254  virtual ComponentNode* build(void);
1255 };
1256 
1262 class And : public TernaryOperator
1263 {
1264 public:
1267 
1269  virtual ~And(void);
1270 
1272  // virtual int precedence (void);
1273  virtual int add_precedence(int accumulated_precedence);
1274 
1276  virtual ComponentNode* build(void);
1277 };
1278 
1284 class Or : public TernaryOperator
1285 {
1286 public:
1289 
1291  virtual ~Or(void);
1292 
1294  // virtual int precedence (void);
1295  virtual int add_precedence(int accumulated_precedence);
1296 
1298  virtual ComponentNode* build(void);
1299 };
1300 
1306 class Both : public TernaryOperator
1307 {
1308 public:
1311 
1313  virtual ~Both(void);
1314 
1316  // virtual int precedence (void);
1317  virtual int add_precedence(int accumulated_precedence);
1318 
1320  virtual ComponentNode* build(void);
1321 };
1322 
1329 {
1330 public:
1333 
1335  virtual ~ReturnRight(void);
1336 
1338  virtual int add_precedence(int accumulated_precedence);
1339 
1341  virtual ComponentNode* build(void);
1342 };
1343 
1350 {
1351 public:
1354 
1356  virtual ~Sequence(void);
1357 
1359  // virtual int precedence (void);
1360  virtual int add_precedence(int accumulated_precedence);
1361 
1363  virtual ComponentNode* build(void);
1364 };
1365 
1371 class Implies : public Operator
1372 {
1373 public:
1376 
1378  virtual ~Implies(void);
1379 
1381  // virtual int precedence (void);
1382  virtual int add_precedence(int accumulated_precedence);
1383 
1385  virtual ComponentNode* build(void);
1386 };
1387 
1393 class Assignment : public Operator
1394 {
1395 public:
1398 
1400  virtual ~Assignment(void);
1401 
1403  // virtual int precedence (void);
1404  virtual int add_precedence(int accumulated_precedence);
1405 
1407  virtual ComponentNode* build(void);
1408 };
1409 
1415 class Equality : public Operator
1416 {
1417 public:
1420 
1422  virtual ~Equality(void);
1423 
1425  // virtual int precedence (void);
1426  virtual int add_precedence(int accumulated_precedence);
1427 
1429  virtual ComponentNode* build(void);
1430 };
1431 
1437 class Inequality : public Operator
1438 {
1439 public:
1442 
1444  virtual ~Inequality(void);
1445 
1447  // virtual int precedence (void);
1448  virtual int add_precedence(int accumulated_precedence);
1449 
1451  virtual ComponentNode* build(void);
1452 };
1453 
1460 {
1461 public:
1464 
1466  virtual ~GreaterThanEqual(void);
1467 
1469  // virtual int precedence (void);
1470  virtual int add_precedence(int accumulated_precedence);
1471 
1473  virtual ComponentNode* build(void);
1474 };
1475 
1481 class GreaterThan : public Operator
1482 {
1483 public:
1486 
1488  virtual ~GreaterThan(void);
1489 
1491  // virtual int precedence (void);
1492  virtual int add_precedence(int accumulated_precedence);
1493 
1495  virtual ComponentNode* build(void);
1496 };
1497 
1503 class LessThanEqual : public Operator
1504 {
1505 public:
1508 
1510  virtual ~LessThanEqual(void);
1511 
1513  // virtual int precedence (void);
1514  virtual int add_precedence(int accumulated_precedence);
1515 
1517  virtual ComponentNode* build(void);
1518 };
1519 
1525 class LessThan : public Operator
1526 {
1527 public:
1530 
1532  virtual ~LessThan(void);
1533 
1535  // virtual int precedence (void);
1536  virtual int add_precedence(int accumulated_precedence);
1537 
1539  virtual ComponentNode* build(void);
1540 };
1541 
1548 {
1549 public:
1551  Function(
1552  const std::string& name, madara::knowledge::ThreadSafeContext& context);
1553 
1555  virtual ~Function(void);
1556 
1558  // virtual int precedence (void);
1559  virtual int add_precedence(int accumulated_precedence);
1560 
1562  virtual ComponentNode* build(void);
1563 
1566 };
1567 
1574 {
1575 public:
1578 
1580  virtual ~ConstArray(void);
1581 
1583  // virtual int precedence (void);
1584  virtual int add_precedence(int accumulated_precedence);
1585 
1587  virtual ComponentNode* build(void);
1588 
1590 };
1591 
1597 class ForLoop : public UnaryOperator
1598 {
1599 public:
1601  ForLoop(Symbol* precondition, Symbol* condition, Symbol* postcondition,
1603 
1605  virtual ~ForLoop(void);
1606 
1608  // virtual int precedence (void);
1609  virtual int add_precedence(int accumulated_precedence);
1610 
1612  virtual ComponentNode* build(void);
1613 
1619 };
1620 
1627 {
1628 public:
1631 
1633  virtual ~SquareRootUnary(void);
1634 
1636  // virtual int precedence (void);
1637  virtual int add_precedence(int accumulated_precedence);
1638 
1640  virtual ComponentNode* build(void);
1641 };
1642 
1648 class Negate : public UnaryOperator
1649 {
1650 public:
1653 
1655  virtual ~Negate(void);
1656 
1658  // virtual int precedence (void);
1659  virtual int add_precedence(int accumulated_precedence);
1660 
1662  virtual ComponentNode* build(void);
1663 };
1664 
1671 {
1672 public:
1675 
1677  virtual ~Postdecrement(void);
1678 
1680  // virtual int precedence (void);
1681  virtual int add_precedence(int accumulated_precedence);
1682 
1684  virtual ComponentNode* build(void);
1685 };
1686 
1693 {
1694 public:
1697 
1699  virtual ~Postincrement(void);
1700 
1702  // virtual int precedence (void);
1703  virtual int add_precedence(int accumulated_precedence);
1704 
1706  virtual ComponentNode* build(void);
1707 };
1708 
1715 {
1716 public:
1719 
1721  virtual ~Predecrement(void);
1722 
1724  // virtual int precedence (void);
1725  virtual int add_precedence(int accumulated_precedence);
1726 
1728  virtual ComponentNode* build(void);
1729 };
1730 
1737 {
1738 public:
1741 
1743  virtual ~Preincrement(void);
1744 
1746  // virtual int precedence (void);
1747  virtual int add_precedence(int accumulated_precedence);
1748 
1750  virtual ComponentNode* build(void);
1751 };
1752 
1758 class Not : public UnaryOperator
1759 {
1760 public:
1763 
1765  virtual ~Not(void);
1766 
1768  // virtual int precedence (void);
1769  virtual int add_precedence(int accumulated_precedence);
1770 
1772  virtual ComponentNode* build(void);
1773 };
1774 
1781 {
1782 public:
1785 
1787  virtual ~Multiply(void);
1788 
1790  // virtual int precedence (void);
1791  virtual int add_precedence(int accumulated_precedence);
1792 
1794  virtual ComponentNode* build(void);
1795 };
1796 
1802 class Modulus : public Operator
1803 {
1804 public:
1807 
1809  virtual ~Modulus(void);
1810 
1812  // virtual int precedence (void);
1813  virtual int add_precedence(int accumulated_precedence);
1814 
1816  virtual ComponentNode* build(void);
1817 };
1818 
1824 class Divide : public Operator
1825 {
1826 public:
1829 
1831  virtual ~Divide(void);
1832 
1834  // virtual int precedence (void);
1835  virtual int add_precedence(int accumulated_precedence);
1836 
1838  virtual ComponentNode* build(void);
1839 };
1840 
1842 {
1843 public:
1846 
1848  const char* fn_name, fn_type fn)
1849  : SystemCall(context), name_(fn_name), fn_(fn)
1850  {
1851  }
1852 
1854  virtual int add_precedence(int accumulated_precedence)
1855  {
1856  return this->precedence_ = VARIABLE_PRECEDENCE + accumulated_precedence;
1857  }
1858 
1860  virtual ComponentNode* build(void)
1861  {
1862  if (left_ || right_)
1863  {
1864  std::stringstream str;
1865  str << name_ << "::build: KARL COMPILE ERROR: " << name_
1866  << " has a left or right child. Likely missing a semi-colon";
1867  std::string s = str.str();
1868 
1869  madara_logger_ptr_log(logger_, logger::LOG_ERROR, "%s\n", s.c_str());
1870 
1871  throw exceptions::KarlException(s);
1872  }
1873 
1874  return new SystemCallGeneric(context_, nodes_, name_, fn_);
1875  }
1876 
1877 private:
1878  const char* name_;
1880 };
1881 }
1882 }
1883 
1884 // constructor
1887  int precedence)
1888  : logger_(&logger), left_(left), right_(right), precedence_(precedence)
1889 {
1890 }
1891 
1892 // destructor
1894 {
1895  delete left_;
1896  delete right_;
1897 }
1898 
1899 // constructor
1901  logger::Logger& logger, Symbol* left, Symbol* right, int precedence)
1902  : Symbol(logger, left, right, precedence)
1903 {
1904 }
1905 
1906 // destructor
1908 
1909 // constructor
1911  logger::Logger& logger, Symbol* left, Symbol* right, int precedence)
1912  : Operator(logger, left, right, precedence)
1913 {
1914 }
1915 
1916 // destructor
1918 
1919 // constructor
1921  logger::Logger& logger, madara::expression::Symbol* right, int precedence)
1922  : madara::expression::Symbol(logger, 0, right, precedence)
1923 {
1924 }
1925 
1926 // destructor
1928 
1929 // constructor
1932  : Symbol(logger, 0, 0, NUMBER_PRECEDENCE)
1933 {
1934  item_.set_value(input);
1935 }
1936 
1937 // constructor
1939  : Symbol(logger, 0, 0, NUMBER_PRECEDENCE)
1940 {
1941  item_.set_value(input);
1942 }
1943 
1944 // constructor
1946  : Symbol(logger, 0, 0, NUMBER_PRECEDENCE)
1947 {
1948  item_.set_value(input);
1949 }
1950 
1951 // destructor
1953 
1954 // returns the precedence level
1956 {
1957  return this->precedence_ = NUMBER_PRECEDENCE + precedence;
1958 }
1959 
1960 // builds an equivalent ExpressionTree node
1962 {
1963  if (left_ || right_)
1964  {
1965  std::string message = "Number::build: KARL COMPILE ERROR: "
1966  "Number ";
1967  message += item_.to_string();
1968  message += " has a left or right child. Likely missing a semi-colon\n";
1969 
1970  madara_logger_ptr_log(logger_, logger::LOG_ERROR, message.c_str());
1971 
1972  throw exceptions::KarlException(message);
1973  }
1974 
1975  return new LeafNode(*(this->logger_), item_);
1976 }
1977 
1978 // constructor
1981 {
1982 }
1983 
1984 // destructor
1986 
1987 // returns the precedence level
1989 {
1990  return this->precedence_ = NEGATE_PRECEDENCE + precedence;
1991 }
1992 
1993 // builds an equivalent ExpressionTree node
1995 {
1996  // check for cascading nots
1997  Negate* next = dynamic_cast<Negate*>(right_);
1998  Symbol* right = right_;
1999  unsigned int i;
2000 
2001  if (left_)
2002  {
2004  "Negate::build: KARL COMPILE ERROR: "
2005  "Negate(-) has a left child. Likely missing a semi-colon\n");
2006 
2008  "Negate::build: KARL COMPILE ERROR: "
2009  "Negate(-) has a left child. Likely missing a semi-colon\n");
2010  }
2011 
2012  if (right_)
2013  {
2014  for (i = 1; next;
2015  ++i, right = next->right_, next = dynamic_cast<Negate*>(next->right_))
2016  {
2017  }
2018 
2019  if (i % 2 == 1)
2020  return new CompositeNegateNode(*(this->logger_), right->build());
2021  else
2022  return new CompositeNegateNode(*(this->logger_),
2023  new CompositeNegateNode(*(this->logger_), right->build()));
2024  }
2025  else
2026  {
2027  return new CompositeNegateNode(*(this->logger_), 0);
2028  }
2029 }
2030 
2031 // constructor
2033  const std::string& name, madara::knowledge::ThreadSafeContext& context)
2034  : TernaryOperator(context.get_logger(), 0, 0, VARIABLE_PRECEDENCE),
2035  name_(name),
2036  context_(context)
2037 {
2038 }
2039 
2040 // destructor
2042 
2043 // returns the precedence level
2045 {
2046  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2047 }
2048 
2049 // builds an equivalent ExpressionTree node
2051 {
2052  return new CompositeFunctionNode(name_, context_, nodes_);
2053 }
2054 
2055 // constructor
2058  : TernaryOperator(context.get_logger(), 0, 0, VARIABLE_PRECEDENCE),
2059  context_(context)
2060 {
2061 }
2062 
2063 // destructor
2065 
2066 // returns the precedence level
2068 {
2069  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2070 }
2071 
2072 // builds an equivalent ExpressionTree node
2074 {
2075  if (left_ || right_)
2076  {
2078  "array[]::build: KARL COMPILE ERROR: "
2079  "array[] has a left or right child. Likely missing a semi-colon\n");
2080 
2082  "array[]::build: KARL COMPILE ERROR: "
2083  "array[] has a left or right child. Likely missing a semi-colon\n");
2084  }
2085 
2086  return new CompositeConstArray(*(this->logger_), nodes_);
2087 }
2088 
2089 // constructor
2092  : TernaryOperator(context.get_logger(), 0, 0, VARIABLE_PRECEDENCE),
2093  context_(context)
2094 {
2095 }
2096 
2097 // destructor
2099 
2100 // constructor
2103  : SystemCall(context)
2104 {
2105 }
2106 
2107 // destructor
2109 
2110 // returns the precedence level
2112 {
2113  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2114 }
2115 
2116 // builds an equivalent ExpressionTree node
2118 {
2119  if (left_ || right_)
2120  {
2122  "#clear_var::build: KARL COMPILE ERROR: "
2123  "#clear_var has a left or right child. Likely missing a semi-colon\n");
2124 
2126  "#clear_var::build: KARL COMPILE ERROR: "
2127  "#clear_var has a left or right child. Likely missing a semi-colon\n");
2128  }
2129 
2130  return new SystemCallClearVariable(context_, nodes_);
2131 }
2132 
2133 // constructor
2136  : SystemCall(context)
2137 {
2138 }
2139 
2140 // destructor
2142 
2143 // returns the precedence level
2145 {
2146  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2147 }
2148 
2149 // builds an equivalent ExpressionTree node
2151 {
2152  if (left_ || right_)
2153  {
2155  "#delete_var::build: KARL COMPILE ERROR: "
2156  "#delete_var has a left or right child. Likely missing a semi-colon\n");
2157 
2159  "#delete_var::build: KARL COMPILE ERROR: "
2160  "#delete_var has a left or right child. Likely missing a semi-colon\n");
2161  }
2162 
2163  return new SystemCallDeleteVariable(context_, nodes_);
2164 }
2165 
2166 // constructor
2168  : SystemCall(context)
2169 {
2170 }
2171 
2172 // destructor
2174 
2175 // returns the precedence level
2177 {
2178  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2179 }
2180 
2181 // builds an equivalent ExpressionTree node
2183 {
2184  if (left_ || right_)
2185  {
2187  "#evaluate::build: KARL COMPILE ERROR: "
2188  "#evaluate has a left or right child. Likely missing a semi-colon\n");
2189 
2191  "#evaluate::build: KARL COMPILE ERROR: "
2192  "#evaluate has a left or right child. Likely missing a semi-colon\n");
2193  }
2194 
2195  return new SystemCallEval(context_, nodes_);
2196 }
2197 
2198 // constructor
2201  : SystemCall(context)
2202 {
2203 }
2204 
2205 // destructor
2207 
2208 // returns the precedence level
2210 {
2211  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2212 }
2213 
2214 // builds an equivalent ExpressionTree node
2216 {
2217  if (left_ || right_)
2218  {
2220  "#expand_env::build: KARL COMPILE ERROR: "
2221  "#expand_env has a left or right child. Likely missing a semi-colon\n");
2222 
2224  "#expand_env::build: KARL COMPILE ERROR: "
2225  "#expand_env has a left or right child. Likely missing a semi-colon\n");
2226  }
2227 
2228  return new SystemCallExpandEnv(context_, nodes_);
2229 }
2230 
2231 // constructor
2234  : SystemCall(context)
2235 {
2236 }
2237 
2238 // destructor
2240 
2241 // returns the precedence level
2243 {
2244  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2245 }
2246 
2247 // builds an equivalent ExpressionTree node
2249 {
2250  if (left_ || right_)
2251  {
2253  "#expand::build: KARL COMPILE ERROR: "
2254  "#expand has a left or right child. Likely missing a semi-colon\n");
2255 
2257  "#expand::build: KARL COMPILE ERROR: "
2258  "#expand has a left or right child. Likely missing a semi-colon\n");
2259  }
2260 
2261  return new SystemCallExpandStatement(context_, nodes_);
2262 }
2263 
2264 // constructor
2267  : SystemCall(context)
2268 {
2269 }
2270 
2271 // destructor
2273 
2274 // returns the precedence level
2276 {
2277  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2278 }
2279 
2280 // builds an equivalent ExpressionTree node
2282 {
2283  if (left_ || right_)
2284  {
2286  "#fragment::build: KARL COMPILE ERROR: "
2287  "#fragment has a left or right child. Likely missing a semi-colon\n");
2288 
2290  "#fragment::build: KARL COMPILE ERROR: "
2291  "#fragment has a left or right child. Likely missing a semi-colon\n");
2292  }
2293 
2294  return new SystemCallFragment(context_, nodes_);
2295 }
2296 
2297 // constructor
2300  : SystemCall(context)
2301 {
2302 }
2303 
2304 // destructor
2306 
2307 // returns the precedence level
2309 {
2310  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2311 }
2312 
2313 // builds an equivalent ExpressionTree node
2315 {
2316  if (left_ || right_)
2317  {
2319  "#log_level::build: KARL COMPILE ERROR: "
2320  "#log_level has a left or right child. Likely missing a semi-colon\n");
2321 
2323  "#log_level::build: KARL COMPILE ERROR: "
2324  "#log_level has a left or right child. Likely missing a semi-colon\n");
2325  }
2326 
2327  return new SystemCallLogLevel(context_, nodes_);
2328 }
2329 
2330 // constructor
2333  : SystemCall(context)
2334 {
2335 }
2336 
2337 // destructor
2339 
2340 // returns the precedence level
2342 {
2343  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2344 }
2345 
2346 // builds an equivalent ExpressionTree node
2348 {
2349  if (left_ || right_)
2350  {
2352  "#get_clock::build: KARL COMPILE ERROR: "
2353  "#get_clock has a left or right child. Likely missing a semi-colon\n");
2354 
2356  "#get_clock::build: KARL COMPILE ERROR: "
2357  "#get_clock has a left or right child. Likely missing a semi-colon\n");
2358  }
2359 
2360  return new SystemCallGetClock(context_, nodes_);
2361 }
2362 
2363 // constructor
2366  : SystemCall(context)
2367 {
2368 }
2369 
2370 // destructor
2372 
2373 // returns the precedence level
2375 {
2376  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2377 }
2378 
2379 // builds an equivalent ExpressionTree node
2381 {
2382  if (left_ || right_)
2383  {
2385  "#get_time::build: KARL COMPILE ERROR: "
2386  "#get_time has a left or right child. Likely missing a semi-colon\n");
2387 
2389  "#get_time::build: KARL COMPILE ERROR: "
2390  "#get_time has a left or right child. Likely missing a semi-colon\n");
2391  }
2392 
2393  return new SystemCallGetTime(context_, nodes_);
2394 }
2395 
2396 // constructor
2399  : SystemCall(context)
2400 {
2401 }
2402 
2403 // destructor
2405 
2406 // returns the precedence level
2408 {
2409  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2410 }
2411 
2412 // builds an equivalent ExpressionTree node
2414 {
2415  if (left_ || right_)
2416  {
2418  "#get_time_s::build: KARL COMPILE ERROR: "
2419  "#get_time_s has a left or right child. Likely missing a semi-colon\n");
2420 
2422  "#get_time_s::build: KARL COMPILE ERROR: "
2423  "#get_time_s has a left or right child. Likely missing a semi-colon\n");
2424  }
2425 
2426  return new SystemCallGetTimeSeconds(context_, nodes_);
2427 }
2428 
2429 // constructor
2432  : SystemCall(context)
2433 {
2434 }
2435 
2436 // destructor
2438 
2439 // returns the precedence level
2441 {
2442  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2443 }
2444 
2445 // builds an equivalent ExpressionTree node
2447 {
2448  if (left_ || right_)
2449  {
2451  "#set_clock::build: KARL COMPILE ERROR: "
2452  "#set_clock has a left or right child. Likely missing a semi-colon\n");
2453 
2455  "#set_clock::build: KARL COMPILE ERROR: "
2456  "#set_clock has a left or right child. Likely missing a semi-colon\n");
2457  }
2458 
2459  return new SystemCallSetClock(context_, nodes_);
2460 }
2461 
2462 // constructor
2465  : SystemCall(context)
2466 {
2467 }
2468 
2469 // destructor
2471 
2472 // returns the precedence level
2474 {
2475  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2476 }
2477 
2478 // builds an equivalent ExpressionTree node
2480 {
2481  if (left_ || right_)
2482  {
2484  "#set_fixed::build: KARL COMPILE ERROR: "
2485  "#set_fixed has a left or right child. Likely missing a semi-colon\n");
2486 
2488  "#set_fixed::build: KARL COMPILE ERROR: "
2489  "#set_fixed has a left or right child. Likely missing a semi-colon\n");
2490  }
2491 
2492  return new SystemCallSetFixed(context_, nodes_);
2493 }
2494 
2495 // constructor
2498  : SystemCall(context)
2499 {
2500 }
2501 
2502 // destructor
2504 
2505 // returns the precedence level
2507 {
2508  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2509 }
2510 
2511 // builds an equivalent ExpressionTree node
2513 {
2514  if (left_ || right_)
2515  {
2517  "#set_precision::build: KARL COMPILE ERROR: "
2518  "#set_precision has a left or right child. Likely missing a "
2519  "semi-colon\n");
2520 
2522  "#set_precision::build: KARL COMPILE ERROR: "
2523  "#set_precision has a left or right child. Likely missing a "
2524  "semi-colon\n");
2525  }
2526 
2527  return new SystemCallSetPrecision(context_, nodes_);
2528 }
2529 
2530 // constructor
2533  : SystemCall(context)
2534 {
2535 }
2536 
2537 // destructor
2539 
2540 // returns the precedence level
2542 {
2543  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2544 }
2545 
2546 // builds an equivalent ExpressionTree node
2548 {
2549  if (left_ || right_)
2550  {
2552  "#scientific::build: KARL COMPILE ERROR: "
2553  "#scientific has a left or right child. Likely missing a semi-colon\n");
2554 
2556  "#scientific::build: KARL COMPILE ERROR: "
2557  "#scientific has a left or right child. Likely missing a semi-colon\n");
2558  }
2559 
2560  return new SystemCallSetScientific(context_, nodes_);
2561 }
2562 
2563 // constructor
2565  : SystemCall(context)
2566 {
2567 }
2568 
2569 // destructor
2571 
2572 // returns the precedence level
2574 {
2575  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2576 }
2577 
2578 // builds an equivalent ExpressionTree node
2580 {
2581  if (left_ || right_)
2582  {
2584  "#print::build: KARL COMPILE ERROR: "
2585  "#print has a left or right child. Likely missing a semi-colon\n");
2586 
2588  "#print::build: KARL COMPILE ERROR: "
2589  "#print has a left or right child. Likely missing a semi-colon\n");
2590  }
2591 
2592  return new SystemCallPrint(context_, nodes_);
2593 }
2594 
2595 // constructor
2597  : SystemCall(context)
2598 {
2599 }
2600 
2601 // destructor
2603 
2604 // returns the precedence level
2606 {
2607  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2608 }
2609 
2610 // builds an equivalent ExpressionTree node
2612 {
2613  if (left_ || right_)
2614  {
2616  "#cos::build: KARL COMPILE ERROR: "
2617  "#cos has a left or right child. Likely missing a semi-colon\n");
2618 
2620  "#cos::build: KARL COMPILE ERROR: "
2621  "#cos has a left or right child. Likely missing a semi-colon\n");
2622  }
2623 
2624  return new SystemCallCos(context_, nodes_);
2625 }
2626 
2627 // constructor
2629  : SystemCall(context)
2630 {
2631 }
2632 
2633 // destructor
2635 
2636 // returns the precedence level
2638 {
2639  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2640 }
2641 
2642 // builds an equivalent ExpressionTree node
2644 {
2645  if (left_ || right_)
2646  {
2648  "#sin::build: KARL COMPILE ERROR: "
2649  "#sin has a left or right child. Likely missing a semi-colon\n");
2650 
2652  "#sin::build: KARL COMPILE ERROR: "
2653  "#sin has a left or right child. Likely missing a semi-colon\n");
2654  }
2655 
2656  return new SystemCallSin(context_, nodes_);
2657 }
2658 
2659 // constructor
2661  : SystemCall(context)
2662 {
2663 }
2664 
2665 // destructor
2667 
2668 // returns the precedence level
2670 {
2671  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2672 }
2673 
2674 // builds an equivalent ExpressionTree node
2676 {
2677  if (left_ || right_)
2678  {
2680  "#tan::build: KARL COMPILE ERROR: "
2681  "#tan has a left or right child. Likely missing a semi-colon\n");
2682 
2684  "#tan::build: KARL COMPILE ERROR: "
2685  "#tan has a left or right child. Likely missing a semi-colon\n");
2686  }
2687 
2688  return new SystemCallTan(context_, nodes_);
2689 }
2690 
2691 // constructor
2693  : SystemCall(context)
2694 {
2695 }
2696 
2697 // destructor
2699 
2700 // returns the precedence level
2702 {
2703  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2704 }
2705 
2706 // builds an equivalent ExpressionTree node
2708 {
2709  if (left_ || right_)
2710  {
2712  "#pow::build: KARL COMPILE ERROR: "
2713  "#pow has a left or right child. Likely missing a semi-colon\n");
2714 
2716  "#pow::build: KARL COMPILE ERROR: "
2717  "#pow has a left or right child. Likely missing a semi-colon\n");
2718  }
2719 
2720  return new SystemCallPow(context_, nodes_);
2721 }
2722 
2723 // constructor
2726  : SystemCall(context)
2727 {
2728 }
2729 
2730 // destructor
2732 
2733 // returns the precedence level
2735 {
2736  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2737 }
2738 
2739 // builds an equivalent ExpressionTree node
2741 {
2742  if (left_ || right_)
2743  {
2745  "#sqrt::build: KARL COMPILE ERROR: "
2746  "#sqrt has a left or right child. Likely missing a semi-colon\n");
2747 
2749  "#sqrt::build: KARL COMPILE ERROR: "
2750  "#sqrt has a left or right child. Likely missing a semi-colon\n");
2751  }
2752 
2753  return new SystemCallSqrt(context_, nodes_);
2754 }
2755 
2756 // constructor
2759  : SystemCall(context)
2760 {
2761 }
2762 
2763 // destructor
2765 
2766 // returns the precedence level
2768 {
2769  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2770 }
2771 
2772 // builds an equivalent ExpressionTree node
2774 {
2775  if (left_ || right_)
2776  {
2778  "#print_system_calls::build: KARL COMPILE ERROR: "
2779  "#print_system_calls has a left or right child. Likely missing a "
2780  "semi-colon\n");
2781 
2783  "#print_system_calls::build: KARL COMPILE ERROR: "
2784  "#print_system_calls has a left or right child. Likely missing a "
2785  "semi-colon\n");
2786  }
2787 
2788  return new SystemCallPrintSystemCalls(context_, nodes_);
2789 }
2790 
2791 // constructor
2794  : SystemCall(context)
2795 {
2796 }
2797 
2798 // destructor
2800 
2801 // returns the precedence level
2803 {
2804  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2805 }
2806 
2807 // builds an equivalent ExpressionTree node
2809 {
2810  if (left_ || right_)
2811  {
2813  "#rand_double::build: KARL COMPILE ERROR: "
2814  "#rand_double has a left or right child. Likely missing a "
2815  "semi-colon\n");
2816 
2817  throw exceptions::KarlException("#rand_double::build: KARL COMPILE ERROR: "
2818  "#rand_double has a left or right child. "
2819  "Likely missing a semi-colon\n");
2820  }
2821 
2822  return new SystemCallRandDouble(context_, nodes_);
2823 }
2824 
2825 // constructor
2828  : SystemCall(context)
2829 {
2830 }
2831 
2832 // destructor
2834 
2835 // returns the precedence level
2837 {
2838  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2839 }
2840 
2841 // builds an equivalent ExpressionTree node
2843 {
2844  if (left_ || right_)
2845  {
2847  "#rand_int::build: KARL COMPILE ERROR: "
2848  "#rand_int has a left or right child. Likely missing a semi-colon\n");
2849 
2851  "#rand_int::build: KARL COMPILE ERROR: "
2852  "#rand_int has a left or right child. Likely missing a semi-colon\n");
2853  }
2854 
2855  return new SystemCallRandInt(context_, nodes_);
2856 }
2857 
2858 // constructor
2861  : SystemCall(context)
2862 {
2863 }
2864 
2865 // destructor
2867 
2868 // returns the precedence level
2870 {
2871  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2872 }
2873 
2874 // builds an equivalent ExpressionTree node
2876 {
2877  if (left_ || right_)
2878  {
2880  "#read_file::build: KARL COMPILE ERROR: "
2881  "#read_file has a left or right child. Likely missing a semi-colon\n");
2882 
2884  "#read_file::build: KARL COMPILE ERROR: "
2885  "#read_file has a left or right child. Likely missing a semi-colon\n");
2886  }
2887 
2888  return new SystemCallReadFile(context_, nodes_);
2889 }
2890 
2891 // constructor
2894  : SystemCall(context)
2895 {
2896 }
2897 
2898 // destructor
2900 
2901 // returns the precedence level
2903 {
2904  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2905 }
2906 
2907 // builds an equivalent ExpressionTree node
2909 {
2910  if (left_ || right_)
2911  {
2913  "#write_file::build: KARL COMPILE ERROR: "
2914  "#write_file has a left or right child. Likely missing a semi-colon\n");
2915 
2917  "#write_file::build: KARL COMPILE ERROR: "
2918  "#write_file has a left or right child. Likely missing a semi-colon\n");
2919  }
2920 
2921  return new SystemCallWriteFile(context_, nodes_);
2922 }
2923 
2924 // constructor
2926  : SystemCall(context)
2927 {
2928 }
2929 
2930 // destructor
2932 
2933 // returns the precedence level
2935 {
2936  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2937 }
2938 
2939 // builds an equivalent ExpressionTree node
2941 {
2942  if (left_ || right_)
2943  {
2945  "#size::build: KARL COMPILE ERROR: "
2946  "#size has a left or right child. Likely missing a semi-colon\n");
2947 
2949  "#size::build: KARL COMPILE ERROR: "
2950  "#size has a left or right child. Likely missing a semi-colon\n");
2951  }
2952 
2953  return new SystemCallSize(context_, nodes_);
2954 }
2955 
2956 // constructor
2958  : SystemCall(context)
2959 {
2960 }
2961 
2962 // destructor
2964 
2965 // returns the precedence level
2967 {
2968  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
2969 }
2970 
2971 // builds an equivalent ExpressionTree node
2973 {
2974  if (left_ || right_)
2975  {
2977  "#sleep::build: KARL COMPILE ERROR: "
2978  "#sleep has a left or right child. Likely missing a semi-colon\n");
2979 
2981  "#sleep::build: KARL COMPILE ERROR: "
2982  "#sleep has a left or right child. Likely missing a semi-colon\n");
2983  }
2984 
2985  return new SystemCallSleep(context_, nodes_);
2986 }
2987 
2988 // constructor
2991  : SystemCall(context)
2992 {
2993 }
2994 
2995 // destructor
2997 
2998 // returns the precedence level
3000 {
3001  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
3002 }
3003 
3004 // builds an equivalent ExpressionTree node
3006 {
3007  if (left_ || right_)
3008  {
3010  "#to_buffer::build: KARL COMPILE ERROR: "
3011  "#to_buffer has a left or right child. Likely missing a semi-colon\n");
3012 
3014  "#to_buffer::build: KARL COMPILE ERROR: "
3015  "#to_buffer has a left or right child. Likely missing a semi-colon\n");
3016  }
3017 
3018  return new SystemCallToBuffer(context_, nodes_);
3019 }
3020 
3021 // constructor
3024  : SystemCall(context)
3025 {
3026 }
3027 
3028 // destructor
3030 
3031 // returns the precedence level
3033 {
3034  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
3035 }
3036 
3037 // builds an equivalent ExpressionTree node
3039 {
3040  if (left_ || right_)
3041  {
3043  "#to_double::build: KARL COMPILE ERROR: "
3044  "#to_double has a left or right child. Likely missing a semi-colon\n");
3045 
3047  "#to_double::build: KARL COMPILE ERROR: "
3048  "#to_double has a left or right child. Likely missing a semi-colon\n");
3049  }
3050 
3051  return new SystemCallToDouble(context_, nodes_);
3052 }
3053 
3054 // constructor
3057  : SystemCall(context)
3058 {
3059 }
3060 
3061 // destructor
3063 
3064 // returns the precedence level
3066 {
3067  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
3068 }
3069 
3070 // builds an equivalent ExpressionTree node
3072 {
3073  if (left_ || right_)
3074  {
3076  "#to_doubles::build: KARL COMPILE ERROR: "
3077  "#to_doubles has a left or right child. Likely missing a semi-colon\n");
3078 
3080  "#to_doubles::build: KARL COMPILE ERROR: "
3081  "#to_doubles has a left or right child. Likely missing a semi-colon\n");
3082  }
3083 
3084  return new SystemCallToDoubles(context_, nodes_);
3085 }
3086 
3087 // constructor
3090  : SystemCall(context)
3091 {
3092 }
3093 
3094 // destructor
3096 
3097 // returns the precedence level
3099 {
3100  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
3101 }
3102 
3103 // builds an equivalent ExpressionTree node
3105 {
3106  if (left_ || right_)
3107  {
3109  "#to_host_dirs::build: KARL COMPILE ERROR: "
3110  "#to_host_dirs has a left or right child. Likely missing a "
3111  "semi-colon\n");
3112 
3113  throw exceptions::KarlException("#to_host_dirs::build: KARL COMPILE ERROR: "
3114  "#to_host_dirs has a left or right child. "
3115  "Likely missing a semi-colon\n");
3116  }
3117 
3118  return new SystemCallToHostDirs(context_, nodes_);
3119 }
3120 
3121 // constructor
3124  : SystemCall(context)
3125 {
3126 }
3127 
3128 // destructor
3130 
3131 // returns the precedence level
3133 {
3134  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
3135 }
3136 
3137 // builds an equivalent ExpressionTree node
3139 {
3140  if (left_ || right_)
3141  {
3143  "#to_integer::build: KARL COMPILE ERROR: "
3144  "#to_integer has a left or right child. Likely missing a semi-colon\n");
3145 
3147  "#to_integer::build: KARL COMPILE ERROR: "
3148  "#to_integer has a left or right child. Likely missing a semi-colon\n");
3149  }
3150 
3151  return new SystemCallToInteger(context_, nodes_);
3152 }
3153 
3154 // constructor
3157  : SystemCall(context)
3158 {
3159 }
3160 
3161 // destructor
3163 
3164 // returns the precedence level
3166 {
3167  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
3168 }
3169 
3170 // builds an equivalent ExpressionTree node
3172 {
3173  if (left_ || right_)
3174  {
3176  "#to_integers::build: KARL COMPILE ERROR: "
3177  "#to_integers has a left or right child. Likely missing a "
3178  "semi-colon\n");
3179 
3180  throw exceptions::KarlException("#to_integers::build: KARL COMPILE ERROR: "
3181  "#to_integers has a left or right child. "
3182  "Likely missing a semi-colon\n");
3183  }
3184 
3185  return new SystemCallToIntegers(context_, nodes_);
3186 }
3187 
3188 // constructor
3191  : SystemCall(context)
3192 {
3193 }
3194 
3195 // destructor
3197 
3198 // returns the precedence level
3200 {
3201  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
3202 }
3203 
3204 // builds an equivalent ExpressionTree node
3206 {
3207  if (left_ || right_)
3208  {
3210  "#to_string::build: KARL COMPILE ERROR: "
3211  "#to_string has a left or right child. Likely missing a semi-colon\n");
3212 
3214  "#to_string::build: KARL COMPILE ERROR: "
3215  "#to_string has a left or right child. Likely missing a semi-colon\n");
3216  }
3217 
3218  return new SystemCallToString(context_, nodes_);
3219 }
3220 
3221 // constructor
3223  : SystemCall(context)
3224 {
3225 }
3226 
3227 // destructor
3229 
3230 // returns the precedence level
3232 {
3233  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
3234 }
3235 
3236 // builds an equivalent ExpressionTree node
3238 {
3239  if (left_ || right_)
3240  {
3242  "#type::build: KARL COMPILE ERROR: "
3243  "#type has a left or right child. Likely missing a semi-colon\n");
3244 
3246  "#type::build: KARL COMPILE ERROR: "
3247  "#type has a left or right child. Likely missing a semi-colon\n");
3248  }
3249 
3250  return new SystemCallType(context_, nodes_);
3251 }
3252 
3253 // constructor
3255  : SystemCall(context)
3256 {
3257 }
3258 
3259 // destructor
3261 
3262 // returns the precedence level
3264 {
3265  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
3266 }
3267 
3268 // builds an equivalent ExpressionTree node
3270 {
3271  if (left_ || right_)
3272  {
3274  "#is_inf::build: KARL COMPILE ERROR: "
3275  "#is_inf has a left or right child. Likely missing a semi-colon\n");
3276 
3278  "#is_inf::build: KARL COMPILE ERROR: "
3279  "#is_inf has a left or right child. Likely missing a semi-colon\n");
3280  }
3281 
3282  return new SystemCallIsinf(context_, nodes_);
3283 }
3284 
3285 // constructor
3287  Symbol* postcondition, Symbol* body,
3289  : UnaryOperator(context.get_logger(), 0, VARIABLE_PRECEDENCE),
3290  precondition_(precondition),
3291  condition_(condition),
3292  postcondition_(postcondition),
3293  body_(body),
3294  context_(context)
3295 {
3296 }
3297 
3298 // destructor
3300 {
3301  delete precondition_;
3302  delete postcondition_;
3303  delete condition_;
3304  delete body_;
3305 }
3306 
3307 // returns the precedence level
3309 {
3310  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
3311 }
3312 
3313 // builds an equivalent ExpressionTree node
3315 {
3316  if (body_)
3317  return new CompositeForLoop(precondition_->build(), condition_->build(),
3318  postcondition_->build(), body_->build(), context_);
3319  else
3320  {
3321  ComponentNode *left(0), *right(0);
3322 
3323  if (left_)
3324  left = precondition_->left_->build();
3325 
3326  if (right_)
3327  right = condition_->right_->build();
3328 
3329  return new CompositeAssignmentNode(context_.get_logger(), left, right);
3330  }
3331 }
3332 
3333 // constructor
3336 {
3337 }
3338 
3339 // destructor
3341 
3342 // returns the precedence level
3344 {
3345  return this->precedence_ = NEGATE_PRECEDENCE + precedence;
3346 }
3347 
3348 // builds an equivalent ExpressionTree node
3350 {
3351  ComponentNode* right(0);
3352 
3353  if (left_)
3354  {
3356  "var--::build: KARL COMPILE ERROR: "
3357  "var-- has a left child. Likely missing a semi-colon\n");
3358 
3360  "#var--::build: KARL COMPILE ERROR: "
3361  "#var-- has a left child. Likely missing a semi-colon\n");
3362  }
3363 
3364  if (right_)
3365  right = right_->build();
3366 
3367  return new CompositePostdecrementNode(*(this->logger_), right);
3368 }
3369 
3370 // constructor
3373 {
3374 }
3375 
3376 // destructor
3378 
3379 // returns the precedence level
3381 {
3382  return this->precedence_ = NEGATE_PRECEDENCE + precedence;
3383 }
3384 
3385 // builds an equivalent ExpressionTree node
3387 {
3388  ComponentNode* right(0);
3389 
3390  if (left_)
3391  {
3393  "var++::build: KARL COMPILE ERROR: "
3394  "var++ has a left child. Likely missing a semi-colon\n");
3395 
3397  "#var++::build: KARL COMPILE ERROR: "
3398  "#var++ has a left child. Likely missing a semi-colon\n");
3399  }
3400 
3401  if (right_)
3402  right = right_->build();
3403 
3404  return new CompositePostincrementNode(*(this->logger_), right);
3405 }
3406 
3407 // constructor
3410 {
3411 }
3412 
3413 // destructor
3415 
3416 // returns the precedence level
3418 {
3419  return this->precedence_ = NEGATE_PRECEDENCE + precedence;
3420 }
3421 
3422 // builds an equivalent ExpressionTree node
3424 {
3425  ComponentNode* right(0);
3426 
3427  if (left_)
3428  {
3430  "--var::build: KARL COMPILE ERROR: "
3431  "--var has a left child. Likely missing a semi-colon\n");
3432 
3434  "--var::build: KARL COMPILE ERROR: "
3435  "--var has a left child. Likely missing a semi-colon\n");
3436  }
3437 
3438  if (right_)
3439  right = right_->build();
3440 
3441  return new CompositePredecrementNode(*(this->logger_), right);
3442 }
3443 
3444 // constructor
3447 {
3448 }
3449 
3450 // destructor
3452 
3453 // returns the precedence level
3455 {
3456  return this->precedence_ = NEGATE_PRECEDENCE + precedence;
3457 }
3458 
3459 // builds an equivalent ExpressionTree node
3461 {
3462  ComponentNode* right(0);
3463 
3464  if (left_)
3465  {
3467  "++var::build: KARL COMPILE ERROR: "
3468  "++var has a left child. Likely missing a semi-colon\n");
3469 
3471  "++var::build: KARL COMPILE ERROR: "
3472  "++var has a left child. Likely missing a semi-colon\n");
3473  }
3474 
3475  if (right_)
3476  right = right_->build();
3477 
3478  return new CompositePreincrementNode(*(this->logger_), right);
3479 }
3480 
3481 // constructor
3484 {
3485 }
3486 
3487 // destructor
3489 
3490 // returns the precedence level
3492 {
3493  return this->precedence_ = NEGATE_PRECEDENCE + precedence;
3494 }
3495 
3496 // builds an equivalent ExpressionTree node
3498 {
3499  // check for cascading nots
3500  Not* next = dynamic_cast<Not*>(right_);
3501  Symbol* right = right_;
3502  unsigned int i;
3503 
3504  if (left_)
3505  {
3507  "Not(!)::build: KARL COMPILE ERROR: "
3508  "Logical Not(!) has a left child. Likely missing a semi-colon\n");
3509 
3511  "Not(!)::build: KARL COMPILE ERROR: "
3512  "Logical Not(!) has a left child. Likely missing a semi-colon\n");
3513  }
3514 
3515  if (right_)
3516  {
3517  for (i = 1; next;
3518  ++i, right = next->right_, next = dynamic_cast<Not*>(next->right_))
3519  {
3520  }
3521 
3522  if (i % 2 == 1)
3523  return new CompositeNotNode(*(this->logger_), right->build());
3524  else
3525  return new CompositeNotNode(*(this->logger_),
3526  new CompositeNotNode(*(this->logger_), right->build()));
3527  }
3528  else
3529  {
3530  return new CompositeNotNode(*(this->logger_), 0);
3531  }
3532 }
3533 
3534 // constructor
3537 {
3538 }
3539 
3540 // destructor
3542 
3543 // returns the precedence level
3545 {
3546  return this->precedence_ = NEGATE_PRECEDENCE + precedence;
3547 }
3548 
3549 // builds an equivalent ExpressionTree node
3551 {
3552  ComponentNode* right(0);
3553 
3554  if (left_)
3555  {
3557  "sqrt::build: KARL COMPILE ERROR: "
3558  "sqrt has a left child. Likely missing a semi-colon\n");
3559 
3561  "sqrt::build: KARL COMPILE ERROR: "
3562  "sqrt has a left child. Likely missing a semi-colon\n");
3563  }
3564 
3565  if (right_)
3566  right = right_->build();
3567 
3568  return new CompositeSquareRootNode(*(this->logger_), right);
3569 }
3570 
3571 // constructor
3574  : Symbol(context.get_logger(), 0, 0, VARIABLE_PRECEDENCE),
3575  key_(key),
3576  context_(context)
3577 {
3578 }
3579 
3580 // destructor
3582 
3583 // returns the precedence level
3585 {
3586  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
3587 }
3588 
3589 // builds an equivalent ExpressionTree node
3591 {
3592  if (left_ || right_)
3593  {
3594  std::string message = "Variable::build: KARL COMPILE ERROR: "
3595  "Variable (";
3596  message += key_;
3597  message += ") has a left or right child. Likely missing a semi-colon\n";
3598 
3599  madara_logger_ptr_log(logger_, logger::LOG_ERROR, message.c_str());
3600 
3601  throw exceptions::KarlException(message);
3602  }
3603 
3604  // is reserved?
3605  if (key_ == "true")
3606  {
3607  return new LeafNode(context_.get_logger(), (Integer)1);
3608  }
3609  else if (key_ == "false")
3610  {
3611  return new LeafNode(context_.get_logger(), (Integer)0);
3612  }
3613  else if (key_ == "nan")
3614  {
3615  return new LeafNode(context_.get_logger(), NAN);
3616  }
3617  else if (key_ == "inf")
3618  {
3619  return new LeafNode(context_.get_logger(), INFINITY);
3620  }
3621  else
3622  {
3623  return new VariableNode(key_, context_);
3624  }
3625 }
3626 
3627 // constructor
3630  : Symbol(context.get_logger(), 0, 0, VARIABLE_PRECEDENCE),
3631  key_(key),
3632  context_(context),
3633  index_(index)
3634 {
3635 }
3636 
3637 // destructor
3639 
3640 // returns the precedence level
3642 {
3643  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
3644 }
3645 
3646 // builds an equivalent ExpressionTree node
3648 {
3649  if (left_ || right_)
3650  {
3651  std::string message = "ArrayRef::build: KARL COMPILE ERROR: ";
3652  message += key_;
3653  message += "[] has a left or right child. Likely missing a semi-colon\n";
3654 
3655  madara_logger_ptr_log(logger_, logger::LOG_ERROR, message.c_str());
3656 
3657  throw exceptions::KarlException(message);
3658  }
3659 
3660  return new CompositeArrayReference(key_, index_->build(), context_);
3661 }
3662 
3663 // constructor
3667  : Operator(context.get_logger(), 0, rhs, ASSIGNMENT_PRECEDENCE),
3668  left_(lhs),
3669  value_(value),
3670  context_(context)
3671 {
3672 }
3673 
3674 // destructor
3676 
3677 // returns the precedence level
3679 {
3680  return this->precedence_ = ASSIGNMENT_PRECEDENCE + precedence;
3681 }
3682 
3683 // builds an equivalent ExpressionTree node
3685  void)
3686 {
3687  if (this->right_)
3688  return new VariableDecrementNode(
3689  left_->build(), value_, this->right_->build(), context_);
3690  else
3691  return new VariableDecrementNode(left_->build(), value_, 0, context_);
3692 }
3693 
3694 // constructor
3696  knowledge::KnowledgeRecord value, Symbol* rhs,
3698  : Operator(context.get_logger(), 0, rhs, ASSIGNMENT_PRECEDENCE),
3699  left_(lhs),
3700  value_(value),
3701  context_(context)
3702 {
3703 }
3704 
3705 // destructor
3707 
3708 // returns the precedence level
3710 {
3711  return this->precedence_ = ASSIGNMENT_PRECEDENCE + precedence;
3712 }
3713 
3714 // builds an equivalent ExpressionTree node
3716  void)
3717 {
3718  if (this->right_)
3719  return new VariableDivideNode(
3720  left_->build(), value_, this->right_->build(), context_);
3721  else
3722  return new VariableDivideNode(left_->build(), value_, 0, context_);
3723 }
3724 
3725 // constructor
3729  : Operator(context.get_logger(), 0, rhs, ASSIGNMENT_PRECEDENCE),
3730  left_(lhs),
3731  value_(value),
3732  context_(context)
3733 {
3734 }
3735 
3736 // destructor
3738 
3739 // returns the precedence level
3741 {
3742  return this->precedence_ = ASSIGNMENT_PRECEDENCE + precedence;
3743 }
3744 
3745 // builds an equivalent ExpressionTree node
3747  void)
3748 {
3749  if (this->right_)
3750  return new VariableIncrementNode(
3751  left_->build(), value_, this->right_->build(), context_);
3752  else
3753  return new VariableIncrementNode(left_->build(), value_, 0, context_);
3754 }
3755 
3756 // constructor
3760  : Operator(context.get_logger(), 0, rhs, ASSIGNMENT_PRECEDENCE),
3761  left_(lhs),
3762  value_(value),
3763  context_(context)
3764 {
3765 }
3766 
3767 // destructor
3769 
3770 // returns the precedence level
3772 {
3773  return this->precedence_ = ASSIGNMENT_PRECEDENCE + precedence;
3774 }
3775 
3776 // builds an equivalent ExpressionTree node
3778  void)
3779 {
3780  if (this->right_)
3781  return new VariableMultiplyNode(
3782  left_->build(), value_, this->right_->build(), context_);
3783  else
3784  return new VariableMultiplyNode(left_->build(), value_, 0, context_);
3785 }
3786 
3787 // constructor
3789  madara::knowledge::KnowledgeRecord value, Symbol* rhs, int compare_type,
3791  : Symbol(context.get_logger(), 0, 0, VARIABLE_PRECEDENCE),
3792  left_(lhs),
3793  value_(value),
3794  rhs_(rhs),
3795  compare_type_(compare_type),
3796  context_(context)
3797 {
3798 }
3799 
3800 // destructor
3802 
3803 // returns the precedence level
3805 {
3806  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
3807 }
3808 
3809 // builds an equivalent ExpressionTree node
3811  void)
3812 {
3813  if (rhs_)
3814  return new VariableCompareNode(
3815  left_->build(), value_, compare_type_, rhs_->build(), context_);
3816  else
3817  return new VariableCompareNode(
3818  left_->build(), value_, compare_type_, 0, context_);
3819 }
3820 
3821 // constructor
3823  : Symbol(context.get_logger(), 0, 0, VARIABLE_PRECEDENCE), context_(context)
3824 {
3825 }
3826 
3827 // destructor
3829 
3830 // returns the precedence level
3832 {
3833  return this->precedence_ = VARIABLE_PRECEDENCE + precedence;
3834 }
3835 
3836 // builds an equivalent ExpressionTree node
3838 {
3839  return new ListNode(context_);
3840 }
3841 
3842 // constructor
3845 {
3846 }
3847 
3848 // destructor
3850 
3851 // returns the precedence level
3853 {
3854  return this->precedence_ = ADD_PRECEDENCE + precedence;
3855 }
3856 
3857 // builds an equivalent ExpressionTree node
3859 {
3860  if (left_ && right_)
3861  {
3862  // check for cascading max
3863  Add* next = dynamic_cast<Add*>(left_);
3864  Symbol* left = left_;
3865 
3866  // push the right onto the deque
3867  nodes_.push_back(right_->build());
3868  delete right_;
3869  right_ = 0;
3870 
3871  for (; next; next = dynamic_cast<Add*>(left))
3872  {
3873  // we have a chained max node. Move the left into our nodes list
3874  if (next->right_)
3875  {
3876  nodes_.push_front(next->right_->build());
3877  delete next->right_;
3878  next->right_ = 0;
3879  }
3880 
3881  // set right to next->right_ and then clear next->right_ before deletion
3882  left = next->left_;
3883  next->left_ = 0;
3884  delete next;
3885  }
3886 
3887  // push the rightmost build from the compressed node and delete it.
3888  // then reset our right_, since we've already taken care of deletion
3889  if (left)
3890  {
3891  nodes_.push_front(left->build());
3892  delete left;
3893  }
3894  left_ = 0;
3895 
3896  return new CompositeAddNode(*(this->logger_), nodes_);
3897  }
3898  else if (left_)
3899  // all we have is a valid left child, so there is no reason to build
3900  // an Add operator
3901  return left_->build();
3902  else if (right_)
3903  // all we have is a valid right child, so there is no reason to build
3904  // a Add operator
3905  return right_->build();
3906  else
3907  {
3908  // we've got nothing. This node should eventually be pruned out of the
3909  // picture if at all possible.
3910  return new CompositeAddNode(*(this->logger_), nodes_);
3911  }
3912 }
3913 
3914 // constructor
3917 {
3918 }
3919 
3920 // destructor
3922 
3923 // returns the precedence level
3925 {
3926  return this->precedence_ = LOGICAL_PRECEDENCE + precedence;
3927 }
3928 
3929 // builds an equivalent ExpressionTree node
3931 {
3932  if (left_ && right_)
3933  {
3934  // check for cascading max
3935  And* next = dynamic_cast<And*>(left_);
3936  Symbol* left = left_;
3937 
3938  // push the right onto the deque
3939  nodes_.push_back(right_->build());
3940  delete right_;
3941  right_ = 0;
3942 
3943  for (; next; next = dynamic_cast<And*>(left))
3944  {
3945  // we have a chained max node. Move the left into our nodes list
3946  if (next->right_)
3947  {
3948  nodes_.push_front(next->right_->build());
3949  delete next->right_;
3950  next->right_ = 0;
3951  }
3952 
3953  // set right to next->right_ and then clear next->right_ before deletion
3954  left = next->left_;
3955  next->left_ = 0;
3956  delete next;
3957  }
3958 
3959  // push the rightmost build from the compressed node and delete it.
3960  // then reset our right_, since we've already taken care of deletion
3961  if (left)
3962  {
3963  nodes_.push_front(left->build());
3964  delete left;
3965  }
3966  left_ = 0;
3967 
3968  return new CompositeAndNode(*(this->logger_), nodes_);
3969  }
3970  else if (left_)
3971  // all we have is a valid left child, so there is no reason to build
3972  // an And operator
3973  return left_->build();
3974  else if (right_)
3975  // all we have is a valid right child, so there is no reason to build
3976  // an And operator
3977  return right_->build();
3978  else
3979  {
3980  // we've got nothing. This node should eventually be pruned out of the
3981  // picture if at all possible.
3982  return new CompositeAndNode(*(this->logger_), nodes_);
3983  }
3984 }
3985 
3986 // constructor
3989 {
3990 }
3991 
3992 // destructor
3994 
3995 // returns the precedence level
3997 {
3998  return this->precedence_ = LOGICAL_PRECEDENCE + precedence;
3999 }
4000 
4001 // builds an equivalent ExpressionTree node
4003 {
4004  if (left_ && right_)
4005  {
4006  // check for cascading max
4007  Or* next = dynamic_cast<Or*>(left_);
4008  Symbol* left = left_;
4009 
4010  // push the right onto the deque
4011  nodes_.push_back(right_->build());
4012  delete right_;
4013  right_ = 0;
4014 
4015  for (; next; next = dynamic_cast<Or*>(left))
4016  {
4017  // we have a chained max node. Move the left into our nodes list
4018  if (next->right_)
4019  {
4020  nodes_.push_front(next->right_->build());
4021  delete next->right_;
4022  next->right_ = 0;
4023  }
4024 
4025  // set right to next->right_ and then clear next->right_ before deletion
4026  left = next->left_;
4027  next->left_ = 0;
4028  delete next;
4029  }
4030 
4031  // push the rightmost build from the compressed node and delete it.
4032  // then reset our right_, since we've already taken care of deletion
4033  if (left)
4034  {
4035  nodes_.push_front(left->build());
4036  delete left;
4037  }
4038  left_ = 0;
4039 
4040  return new CompositeOrNode(*(this->logger_), nodes_);
4041  }
4042  else if (left_)
4043  // all we have is a valid left child, so there is no reason to build
4044  // a Both operator
4045  return left_->build();
4046  else if (right_)
4047  // all we have is a valid right child, so there is no reason to build
4048  // a Both operator
4049  return right_->build();
4050  else
4051  {
4052  // we've got nothing. This node should eventually be pruned out of the
4053  // picture if at all possible.
4054  return new CompositeOrNode(*(this->logger_), nodes_);
4055  }
4056 }
4057 
4058 // constructor
4061 {
4062 }
4063 
4064 // destructor
4066 
4067 // returns the precedence level
4069 {
4070  return this->precedence_ = BOTH_PRECEDENCE + precedence;
4071 }
4072 
4073 // builds an equivalent ExpressionTree node
4075 {
4076  // Since users can say something like ";;;;;;;;", it is very possible
4077  // that a both operation contains no valid children. So, we need
4078  // to check whether or not we have a valid child.
4079  if (left_ && right_)
4080  {
4081  // check for cascading max
4082  Both* next = dynamic_cast<Both*>(left_);
4083  Symbol* left = left_;
4084 
4085  // push the right onto the deque
4086  // nodes_.push_back (right_->build ());
4087  // delete right_;
4088  // right_ = 0;
4089 
4090  for (; next; next = dynamic_cast<Both*>(left))
4091  {
4092  // we have a chained max node. Move the left into our nodes list
4093  if (next->right_)
4094  {
4095  nodes_.push_front(next->right_->build());
4096  delete next->right_;
4097  next->right_ = 0;
4098  }
4099 
4100  // set right to next->right_ and then clear next->right_ before deletion
4101  left = next->left_;
4102  next->left_ = 0;
4103  delete next;
4104  }
4105 
4106  // push the rightmost build from the compressed node and delete it.
4107  // then reset our right_, since we've already taken care of deletion
4108  if (left)
4109  {
4110  nodes_.push_front(left->build());
4111  delete left;
4112  }
4113  left_ = 0;
4114 
4115  next = dynamic_cast<Both*>(right_);
4116  Symbol* right = right_;
4117 
4118  for (; next; next = dynamic_cast<Both*>(right))
4119  {
4120  // we have a chained max node. Move the left into our nodes list
4121  if (next->left_)
4122  {
4123  nodes_.push_back(next->left_->build());
4124  delete next->left_;
4125  next->left_ = 0;
4126  }
4127 
4128  // set right to next->right_ and then clear next->right_ before deletion
4129  right = next->right_;
4130  next->right_ = 0;
4131  delete next;
4132  }
4133 
4134  // push the rightmost build from the compressed node and delete it.
4135  // then reset our right_, since we've already taken care of deletion
4136  if (right)
4137  {
4138  nodes_.push_back(right->build());
4139  delete right;
4140  }
4141  right_ = 0;
4142 
4143  return new CompositeBothNode(*(this->logger_), nodes_);
4144  }
4145  else if (left_)
4146  // all we have is a valid left child, so there is no reason to build
4147  // a Both operator
4148  return left_->build();
4149  else if (right_)
4150  // all we have is a valid right child, so there is no reason to build
4151  // a Both operator
4152  return right_->build();
4153  else
4154  // we've got nothing. This node should eventually be pruned out of the
4155  // picture if at all possible.
4156  return new LeafNode(
4157  *(this->logger_), (madara::knowledge::KnowledgeRecord::Integer)0);
4158 }
4159 
4160 // constructor
4163 {
4164 }
4165 
4166 // destructor
4168 
4169 // returns the precedence level
4171 {
4172  return this->precedence_ = BOTH_PRECEDENCE + precedence;
4173 }
4174 
4175 // builds an equivalent ExpressionTree node
4177 {
4178  // Since users can say something like ";;;;;;;;", it is very possible
4179  // that a both operation contains no valid children. So, we need
4180  // to check whether or not we have a valid child.
4181  if (left_ && right_)
4182  {
4183  // check for cascading max
4184  ReturnRight* next = dynamic_cast<ReturnRight*>(left_);
4185  Symbol* left = left_;
4186 
4187  // push the right onto the deque
4188  // nodes_.push_back (right_->build ());
4189  // delete right_;
4190  // right_ = 0;
4191 
4192  for (; next; next = dynamic_cast<ReturnRight*>(left))
4193  {
4194  // we have a chained max node. Move the left into our nodes list
4195  if (next->right_)
4196  {
4197  nodes_.push_front(next->right_->build());
4198  delete next->right_;
4199  next->right_ = 0;
4200  }
4201 
4202  // set right to next->right_ and then clear next->right_ before deletion
4203  left = next->left_;
4204  next->left_ = 0;
4205  delete next;
4206  }
4207 
4208  // push the rightmost build from the compressed node and delete it.
4209  // then reset our right_, since we've already taken care of deletion
4210  if (left)
4211  {
4212  nodes_.push_front(left->build());
4213  delete left;
4214  }
4215  left_ = 0;
4216 
4217  next = dynamic_cast<ReturnRight*>(right_);
4218  Symbol* right = right_;
4219 
4220  for (; next; next = dynamic_cast<ReturnRight*>(right))
4221  {
4222  // we have a chained max node. Move the left into our nodes list
4223  if (next->left_)
4224  {
4225  nodes_.push_back(next->left_->build());
4226  delete next->left_;
4227  next->left_ = 0;
4228  }
4229 
4230  // set right to next->right_ and then clear next->right_ before deletion
4231  right = next->right_;
4232  next->right_ = 0;
4233  delete next;
4234  }
4235 
4236  // push the rightmost build from the compressed node and delete it.
4237  // then reset our right_, since we've already taken care of deletion
4238  if (right)
4239  {
4240  nodes_.push_back(right->build());
4241  delete right;
4242  }
4243  right_ = 0;
4244 
4245  return new CompositeReturnRightNode(*(this->logger_), nodes_);
4246  }
4247  else if (left_)
4248  // all we have is a valid left child, so there is no reason to build
4249  // a Both operator
4250  return left_->build();
4251  else if (right_)
4252  // all we have is a valid right child, so there is no reason to build
4253  // a Both operator
4254  return right_->build();
4255  else
4256  // we've got nothing. This node should eventually be pruned out of the
4257  // picture if at all possible.
4258  return new LeafNode(
4259  *(this->logger_), (madara::knowledge::KnowledgeRecord::Integer)0);
4260 }
4261 
4262 // constructor
4265 {
4266 }
4267 
4268 // destructor
4270 
4271 // returns the precedence level
4273 {
4274  return this->precedence_ = BOTH_PRECEDENCE + precedence;
4275 }
4276 
4277 // builds an equivalent ExpressionTree node
4279 {
4280  // Since users can say something like ";;;;;;;;", it is very possible
4281  // that a both operation contains no valid children. So, we need
4282  // to check whether or not we have a valid child.
4283  if (left_ && right_)
4284  {
4285  // check for cascading max
4286  Sequence* next = dynamic_cast<Sequence*>(left_);
4287  Symbol* left = left_;
4288 
4289  // push the right onto the deque
4290  // nodes_.push_back (right_->build ());
4291  // delete right_;
4292  // right_ = 0;
4293 
4294  for (; next; next = dynamic_cast<Sequence*>(left))
4295  {
4296  // we have a chained max node. Move the left into our nodes list
4297  if (next->right_)
4298  {
4299  nodes_.push_front(next->right_->build());
4300  delete next->right_;
4301  next->right_ = 0;
4302  }
4303 
4304  // set right to next->right_ and then clear next->right_ before deletion
4305  left = next->left_;
4306  next->left_ = 0;
4307  delete next;
4308  }
4309 
4310  // push the rightmost build from the compressed node and delete it.
4311  // then reset our right_, since we've already taken care of deletion
4312  if (left)
4313  {
4314  nodes_.push_front(left->build());
4315  delete left;
4316  }
4317  left_ = 0;
4318 
4319  next = dynamic_cast<Sequence*>(right_);
4320  Symbol* right = right_;
4321 
4322  for (; next; next = dynamic_cast<Sequence*>(right))
4323  {
4324  // we have a chained max node. Move the left into our nodes list
4325  if (next->left_)
4326  {
4327  nodes_.push_back(next->left_->build());
4328  delete next->left_;
4329  next->left_ = 0;
4330  }
4331 
4332  // set right to next->right_ and then clear next->right_ before deletion
4333  right = next->right_;
4334  next->right_ = 0;
4335  delete next;
4336  }
4337 
4338  // push the rightmost build from the compressed node and delete it.
4339  // then reset our right_, since we've already taken care of deletion
4340  if (right)
4341  {
4342  nodes_.push_back(right->build());
4343  delete right;
4344  }
4345  right_ = 0;
4346 
4347  return new CompositeSequentialNode(*(this->logger_), nodes_);
4348  }
4349  else if (left_)
4350  // all we have is a valid left child, so there is no reason to build
4351  // a Both operator
4352  return left_->build();
4353  else if (right_)
4354  // all we have is a valid right child, so there is no reason to build
4355  // a Both operator
4356  return right_->build();
4357  else
4358  // we've got nothing. This node should eventually be pruned out of the
4359  // picture if at all possible.
4360  return new LeafNode(
4361  *(this->logger_), (madara::knowledge::KnowledgeRecord::Integer)0);
4362 }
4363 
4364 // constructor
4367 {
4368 }
4369 
4370 // destructor
4372 
4373 // returns the precedence level
4375 {
4376  return this->precedence_ = IMPLIES_PRECEDENCE + precedence;
4377 }
4378 
4379 // builds an equivalent ExpressionTree node
4381 {
4382  ComponentNode *left(0), *right(0);
4383 
4384  if (left_)
4385  left = left_->build();
4386 
4387  if (right_)
4388  right = right_->build();
4389 
4390  return new CompositeImpliesNode(*(this->logger_), left, right);
4391 }
4392 
4393 // constructor
4396 {
4397 }
4398 
4399 // destructor
4401 
4402 // returns the precedence level
4404 {
4405  return this->precedence_ = ASSIGNMENT_PRECEDENCE + precedence;
4406 }
4407 
4408 // builds an equivalent ExpressionTree node
4410 {
4411  ComponentNode *left(0), *right(0);
4412 
4413  if (left_)
4414  left = left_->build();
4415 
4416  if (right_)
4417  right = right_->build();
4418 
4419  return new CompositeAssignmentNode(*(this->logger_), left, right);
4420 }
4421 
4422 // constructor
4425 {
4426 }
4427 
4428 // destructor
4430 
4431 // returns the precedence level
4433 {
4434  return this->precedence_ = CONDITIONAL_PRECEDENCE + precedence;
4435 }
4436 
4437 // builds an equivalent ExpressionTree node
4439 {
4440  ComponentNode *left(0), *right(0);
4441 
4442  if (left_)
4443  left = left_->build();
4444 
4445  if (right_)
4446  right = right_->build();
4447 
4448  return new CompositeEqualityNode(*(this->logger_), left, right);
4449 }
4450 
4451 // constructor
4454 {
4455 }
4456 
4457 // destructor
4459 
4460 // returns the precedence level
4462 {
4463  return this->precedence_ = CONDITIONAL_PRECEDENCE + precedence;
4464 }
4465 
4466 // builds an equivalent ExpressionTree node
4468 {
4469  ComponentNode *left(0), *right(0);
4470 
4471  if (left_)
4472  left = left_->build();
4473 
4474  if (right_)
4475  right = right_->build();
4476 
4477  return new CompositeInequalityNode(*(this->logger_), left, right);
4478 }
4479 
4480 // constructor
4483 {
4484 }
4485 
4486 // destructor
4488 
4489 // returns the precedence level
4491 {
4492  return this->precedence_ = CONDITIONAL_PRECEDENCE + precedence;
4493 }
4494 
4495 // builds an equivalent ExpressionTree node
4497  void)
4498 {
4499  ComponentNode *left(0), *right(0);
4500 
4501  if (left_)
4502  left = left_->build();
4503 
4504  if (right_)
4505  right = right_->build();
4506 
4507  return new CompositeGreaterThanEqualNode(*(this->logger_), left, right);
4508 }
4509 
4510 // constructor
4513 {
4514 }
4515 
4516 // destructor
4518 
4519 // returns the precedence level
4521 {
4522  return this->precedence_ = CONDITIONAL_PRECEDENCE + precedence;
4523 }
4524 
4525 // builds an equivalent ExpressionTree node
4527 {
4528  ComponentNode *left(0), *right(0);
4529 
4530  if (left_)
4531  left = left_->build();
4532 
4533  if (right_)
4534  right = right_->build();
4535 
4536  return new CompositeGreaterThanNode(*(this->logger_), left, right);
4537 }
4538 
4539 // constructor
4542 {
4543 }
4544 
4545 // destructor
4547 
4548 // returns the precedence level
4550 {
4551  return this->precedence_ = CONDITIONAL_PRECEDENCE + precedence;
4552 }
4553 
4554 // builds an equivalent ExpressionTree node
4556  void)
4557 {
4558  ComponentNode *left(0), *right(0);
4559 
4560  if (left_)
4561  left = left_->build();
4562 
4563  if (right_)
4564  right = right_->build();
4565 
4566  return new CompositeLessThanEqualNode(*(this->logger_), left, right);
4567 }
4568 
4569 // constructor
4572 {
4573 }
4574 
4575 // destructor
4577 
4578 // returns the precedence level
4580 {
4581  return this->precedence_ = CONDITIONAL_PRECEDENCE + precedence;
4582 }
4583 
4584 // builds an equivalent ExpressionTree node
4586 {
4587  ComponentNode *left(0), *right(0);
4588 
4589  if (left_)
4590  left = left_->build();
4591 
4592  if (right_)
4593  right = right_->build();
4594 
4595  return new CompositeLessThanNode(*(this->logger_), left, right);
4596 }
4597 
4598 // constructor
4601 {
4602 }
4603 
4604 // destructor
4606 
4607 // returns the precedence level
4609 {
4610  return this->precedence_ = ADD_PRECEDENCE + precedence;
4611 }
4612 
4613 // builds an equivalent ExpressionTree node
4615 {
4616  ComponentNode *left(0), *right(0);
4617 
4618  if (left_)
4619  left = left_->build();
4620 
4621  if (right_)
4622  right = right_->build();
4623 
4624  return new CompositeSubtractNode(*(this->logger_), left, right);
4625 }
4626 
4627 // constructor
4630 {
4631 }
4632 
4633 // destructor
4635 
4636 // returns the precedence level
4638 {
4639  return this->precedence_ = MULTIPLY_PRECEDENCE + precedence;
4640 }
4641 
4642 // builds an equivalent ExpressionTree node
4644 {
4645  if (left_ && right_)
4646  {
4647  Multiply* rhs = dynamic_cast<Multiply*>(right_);
4648 
4649  nodes_.push_back(left_->build());
4650 
4651  if (rhs)
4652  {
4653  nodes_.insert(nodes_.end(), rhs->nodes_.begin(), rhs->nodes_.end());
4654  rhs->nodes_.clear();
4655  }
4656  else
4657  {
4658  nodes_.push_back(right_->build());
4659  }
4660  return new CompositeMultiplyNode(*(this->logger_), nodes_);
4661  }
4662  else
4663  {
4664  return new CompositeMultiplyNode(*(this->logger_), nodes_);
4665  }
4666 }
4667 
4668 // constructor
4671 {
4672 }
4673 
4674 // destructor
4676 
4677 // returns the precedence level
4679 {
4680  return this->precedence_ = MODULUS_PRECEDENCE + precedence;
4681 }
4682 
4683 // builds an equivalent ExpressionTree node
4685 {
4686  ComponentNode *left(0), *right(0);
4687 
4688  if (left_)
4689  left = left_->build();
4690 
4691  if (right_)
4692  right = right_->build();
4693 
4694  return new CompositeModulusNode(*(this->logger_), left, right);
4695 }
4696 
4697 // constructor
4700 {
4701 }
4702 
4703 // destructor
4705 
4706 // returns the precedence level
4708 {
4709  return this->precedence_ = DIVIDE_PRECEDENCE + precedence;
4710 }
4711 
4712 // builds an equivalent ExpressionTree node
4714 {
4715  ComponentNode *left(0), *right(0);
4716 
4717  if (left_)
4718  left = left_->build();
4719 
4720  if (right_)
4721  right = right_->build();
4722 
4723  return new CompositeDivideNode(*(this->logger_), left, right);
4724 }
4725 
4726 // constructor
4728 
4729 // destructor
4731 
4732 // extracts precondition, condition, postcondition, and body from input
4735  const std::string& input, std::string::size_type& i,
4736  int& accumulated_precedence, ::std::list<Symbol*>& list,
4737  Symbol*& returnableInput)
4738 {
4739  ::std::list<Symbol*> substr_list;
4740  Symbol* lastValidInput(0);
4741  std::string::size_type begin = i;
4742  Operator* precondition(0); //, * condition (0), * postcondition (0);
4743  Symbol *body(0), *user_pre(0), *user_cond(0), *user_post(0);
4744 
4745  // for extracting and using substrings of input
4746  std::string::size_type count(0);
4747  std::string substr;
4748 
4749  if (variable == "")
4750  {
4751  variable = ".MADARA_I";
4752  }
4753 
4754  bool delimiter_found = false, handled = false, equal_to = false;
4755  std::string::size_type delimiter_begin = 0;
4756  std::string::size_type delimiter_end = 0;
4757  int paren_depth = 0;
4758  int index_depth = 0;
4759 
4760  // search for end of for_loop conditions. Be on lookout for delimiter.
4761  for (; i < input.length(); ++i)
4762  {
4763  if (index_depth == 0 && paren_depth == 0 && input[i] == '-' &&
4764  !delimiter_found)
4765  {
4766  delimiter_found = true;
4767  delimiter_begin = i;
4768  }
4769  else if (index_depth == 0 && paren_depth == 0 && delimiter_found &&
4770  input[i] == '>')
4771  {
4772  delimiter_end = i;
4773  }
4774  else if (input[i] == ']')
4775  {
4776  if (index_depth == 0 && paren_depth == 0)
4777  {
4778  break;
4779  }
4780  else
4781  {
4782  --index_depth;
4783  }
4784  }
4785  else if (input[i] == '(')
4786  {
4787  ++paren_depth;
4788  }
4789  else if (input[i] == '[')
4790  {
4791  ++index_depth;
4792  }
4793  else if (input[i] == ')')
4794  {
4795  if (paren_depth == 0)
4796  {
4797  break;
4798  }
4799  else
4800  {
4801  --paren_depth;
4802  }
4803  }
4804  }
4805 
4810  if (delimiter_found && delimiter_end == 0)
4811  {
4812  delimiter_found = false;
4813  }
4814 
4815  // this is actually an array index
4816  if (!delimiter_found)
4817  {
4818  // variable
4819  // begin to end--the index
4820  substr = input.substr(begin, i - begin);
4821 
4822  Symbol* index = nullptr;
4823 
4824  for (count = 0; count < substr.length();)
4825  {
4826  main_loop(context, substr, count, lastValidInput, handled,
4827  accumulated_precedence, substr_list);
4828  }
4829 
4831  "madara::expression::Interpreter: "
4832  "KaRL: For loop: Array reference created at %s\n",
4833  substr.c_str());
4834 
4835  // we have a precondition
4836  if (!substr_list.empty())
4837  {
4838  index = substr_list.back();
4839  substr_list.clear();
4840  }
4841 
4842  Symbol* op = new ArrayRef(variable, index, context);
4843  op->add_precedence(accumulated_precedence);
4844 
4845  // check for post increments and decrements
4846  if (i + 2 < input.size())
4847  {
4848  if (input[i + 1] == '+' && input[i + 2] == '+')
4849  {
4850  Symbol* array_ref = op;
4851  op = new Postincrement(context.get_logger());
4852  op->add_precedence(accumulated_precedence);
4853  op->right_ = array_ref;
4854  i += 2;
4855  }
4856  else if (input[i + 1] == '-' && input[i + 2] == '-')
4857  {
4858  Symbol* array_ref = op;
4859  op = new Postdecrement(context.get_logger());
4860  op->add_precedence(accumulated_precedence);
4861  op->right_ = array_ref;
4862  i += 2;
4863  }
4864  }
4865 
4866  lastValidInput = op;
4867 
4868  precedence_insert(context, op, list);
4869 
4870  returnableInput = op;
4871  ++i;
4872  return;
4873  }
4874 
4876  "madara::expression::Interpreter: "
4877  "KaRL: For loop: Within input string, the for loop delimiter begins at %d"
4878  " and ends at %d (should be at least 1). Loop construct begins at "
4879  "%d and ends at %d\n",
4880  (int)delimiter_begin, (int)delimiter_end, (int)begin, (int)i);
4881 
4882  // What did we end with? Less than? Greater than?
4883  if (input[i] == ']')
4884  equal_to = true;
4885  else if (input[i] != ')')
4886  {
4887  // this is an error. Essentially, it means the user did not close the
4888  // for loop.
4890  "madara::expression::Interpreter: "
4891  "KARL COMPILE ERROR:: No closing delimiter (']' or ')')"
4892  " has been specified on the for loop.\n");
4893 
4895  "madara::expression::Interpreter: "
4896  "KARL COMPILE ERROR:: No closing delimiter (']' or ')')"
4897  " has been specified on the for loop.\n");
4898  }
4899 
4900  // get the precondition, postcondition and condition ready
4901  precondition = new Assignment(context.get_logger());
4902  precondition->left_ = new Variable(variable, context);
4903 
4904  // this is the non-short-hand way of specifying, e.g., var[0,30] {}
4905  if (delimiter_found)
4906  {
4907  // setup precondition
4908  if (delimiter_begin - begin > 0)
4909  {
4910  // run main_loop on the precondition substring
4911  substr = input.substr(begin, delimiter_begin - begin);
4912 
4913  for (count = 0; count < substr.length();)
4914  {
4915  main_loop(context, substr, count, lastValidInput, handled,
4916  accumulated_precedence, substr_list);
4917  }
4918 
4920  "madara::expression::Interpreter: "
4921  "KaRL: For loop: Precondition is set to %s\n",
4922  substr.c_str());
4923 
4924  // we have a precondition
4925  if (!substr_list.empty())
4926  {
4927  user_pre = substr_list.back();
4928  substr_list.clear();
4929  }
4930  }
4931  else
4932  {
4934  "madara::expression::Interpreter: "
4935  "KaRL: For loop: No loop precondition was specified\n");
4936  }
4937 
4938  // check for special increment
4939  if (delimiter_end - delimiter_begin > 1)
4940  {
4941  count = 0;
4942  lastValidInput = 0;
4943  substr = input.substr(
4944  delimiter_begin + 1, delimiter_end - (delimiter_begin + 1));
4945 
4946  for (count = 0; count < substr.length();)
4947  {
4948  main_loop(context, substr, count, lastValidInput, handled,
4949  accumulated_precedence, substr_list);
4950  }
4951 
4953  "madara::expression::Interpreter: "
4954  "KaRL: For loop: Postcondition is set to %s\n",
4955  substr.c_str());
4956 
4957  // we have a postcondition
4958  if (!substr_list.empty())
4959  {
4960  user_post = substr_list.back();
4961 
4962  substr_list.clear();
4963  }
4964  }
4965  else
4966  {
4968  "KaRL: For loop: No loop special increment was specified\n");
4969  }
4970 
4971  // set condition
4972  if (i - delimiter_end >= 2)
4973  {
4974  lastValidInput = 0;
4975  substr = input.substr(delimiter_end + 1, i - (delimiter_end + 1));
4976 
4977  for (count = 0; count < substr.length();)
4978  {
4979  main_loop(context, substr, count, lastValidInput, handled,
4980  accumulated_precedence, substr_list);
4981  }
4982 
4983  // we have a condition
4984  if (!substr_list.empty())
4985  {
4987  "KaRL: For loop: Condition is set to %s\n", substr.c_str());
4988 
4989  user_cond = substr_list.back();
4990  substr_list.clear();
4991  }
4992  else
4993  {
4995  "KaRL: For loop: Condition was not set to %s\n", substr.c_str());
4996  }
4997  }
4998  else
4999  {
5001  "KaRL: For loop: No loop condition was specified\n");
5002  }
5003  }
5004  // if no delimiter found, this is the shorthand
5005  else
5006  {
5007  lastValidInput = 0;
5008  substr = input.substr(begin, i - begin);
5009 
5010  for (count = 0; count < substr.length();)
5011  {
5012  main_loop(context, substr, count, lastValidInput, handled,
5013  accumulated_precedence, substr_list);
5014  }
5015 
5017  "KaRL: For loop: Condition only is set to %s\n", substr.c_str());
5018 
5019  // we have a condition
5020  if (!substr_list.empty())
5021  {
5022  user_cond = substr_list.back();
5023  substr_list.clear();
5024  }
5025  }
5026 
5027  // if precondition not set, set to default
5028  if (!user_pre)
5029  {
5030  user_pre = new Number(
5032  }
5033 
5034  // set condition to default if not yet set
5035  if (!user_cond)
5036  {
5037  user_cond = new Number(
5039  }
5040 
5041  // set postcondition to default if not yet set
5042  if (!user_post)
5043  {
5044  user_post = new Number(
5047  "KaRL: For loop: Postcondition is set to 1 (def)\n");
5048  }
5049 
5050  // eat up whitespace so we can check for a parenthesis (function)
5051  for (++i; i < input.length() && is_whitespace(input[i]); ++i)
5052  ;
5053 
5054  // can't have a body without a parenthesis or brace
5055  if (i < input.length() && input[i] == '(')
5056  {
5057  ++i;
5058  lastValidInput = 0;
5059 
5061  "KaRL: For loop: Body is reading from %s\n",
5062  input.substr(i, input.size() - i).c_str());
5063 
5064  // we have a function instead of a variable
5065  handle_parenthesis(context, input, i, lastValidInput, handled,
5066  accumulated_precedence, substr_list);
5067 
5068  if (!substr_list.empty())
5069  {
5070  body = substr_list.back();
5071  substr_list.clear();
5072  }
5073  }
5074 
5075  // now, see if we can locate a body for the for loop
5076  if (body)
5077  {
5078  Assignment* assignment = dynamic_cast<Assignment*>(body);
5079  if (assignment)
5080  {
5081  Variable* variable_node = dynamic_cast<Variable*>(assignment->left_);
5082  Number* number = dynamic_cast<Number*>(assignment->right_);
5083 
5084  if (variable_node && number)
5085  {
5087  "KaRL: For loop: Body is a simple assignment of variable %s to "
5088  "%s\n",
5089  variable_node->key_.c_str(), number->item_.to_string().c_str());
5090  }
5091  else
5092  {
5094  "KaRL: For loop: For loop has a complex body\n");
5095  }
5096  }
5097 
5098  precondition->right_ = user_pre;
5101 
5102  // optimize postcondition
5103  Number* number = dynamic_cast<Number*>(user_post);
5104  if (number)
5105  {
5106  post_val = number->item_;
5107  delete number;
5108  user_post = 0;
5109  }
5110 
5111  // optimize condition
5112  number = dynamic_cast<Number*>(user_cond);
5113  if (number)
5114  {
5115  cond_val = number->item_;
5116  delete number;
5117  user_cond = 0;
5118  }
5119 
5120  int compare_type(0);
5121 
5122  if (equal_to)
5123  compare_type = 1;
5124 
5125  Variable* var_node = new Variable(variable, context);
5126 
5127  VariableIncrement* postcondition =
5128  new VariableIncrement(var_node, post_val, user_post, context);
5129  postcondition->add_precedence(accumulated_precedence + FOR_LOOP_PRECEDENCE);
5130 
5131  VariableCompare* condition = new VariableCompare(
5132  var_node, cond_val, user_cond, compare_type, context);
5133  condition->add_precedence(accumulated_precedence + FOR_LOOP_PRECEDENCE);
5134 
5135  Symbol* op =
5136  new ForLoop(precondition, condition, postcondition, body, context);
5137  op->add_precedence(accumulated_precedence);
5138 
5139  precedence_insert(context, op, list);
5140 
5141  lastValidInput = 0;
5142  }
5143  else
5144  {
5145  // user forgot to specify a for loop body, so they apparently just want us
5146  // to loop the variable from the precondition to the condition. Since we
5147  // assume the user doesn't want a busy loop, which this is, we instead
5148  // create an assignment for the variable to equal the condition and clean up
5149  // the pointers
5150 
5151  // if they specified a ']', they actually want something 1 greater than the
5152  // condition
5153  if (equal_to)
5154  {
5155  Number* number = dynamic_cast<Number*>(user_cond);
5156 
5157  if (number)
5158  ++number->item_;
5159  else
5160  {
5161  // if it wasn't already a number, then it must be something more
5162  // complex. We'll just add one to it and see if the prune () method can
5163  // optimize it a bit.
5164  Add* add = new Add(context.get_logger());
5165  add->left_ = new Number(context.get_logger(),
5167  add->right_ = user_cond;
5168  user_cond = add;
5169  }
5170  }
5171 
5172  delete precondition->right_;
5173  precondition->right_ = user_cond;
5174  precondition->add_precedence(accumulated_precedence);
5175 
5176  precedence_insert(context, precondition, list);
5177 
5178  lastValidInput = 0;
5179  }
5180 }
5181 
5182 // inserts a variable (leaf node / number) into the parse tree
5184  madara::knowledge::ThreadSafeContext& context, const std::string& input,
5185  std::string::size_type& i, int& accumulated_precedence,
5186  ::std::list<Symbol*>& list, Symbol*& lastValidInput)
5187 {
5188  // build a potential variable name (this could also be a function)
5189  std::string::size_type j = 1;
5190 
5191  for (; i + j < input.length() && is_alphanumeric(input[i + j]); ++j)
5192  continue;
5193 
5194  // the variable or function name is stored in input.substr (i,j)
5195  // is the next char a parenthesis?
5196 
5197  std::string name = input.substr(i, j);
5198 
5199  i += j;
5200 
5201  // eat up whitespace so we can check for a parenthesis (function)
5202  for (; i < input.length() && is_whitespace(input[i]); ++i)
5203  ;
5204 
5205  // if this is a reserved word, then treat it as a Leaf
5206  if (is_reserved_word(name))
5207  {
5208  if (name == "true")
5209  {
5211  "madara::expression::Interpreter: "
5212  "Inserting true(1) into expression tree.\n");
5213 
5214  Number* number = new Number(context.get_logger(), (Integer)1);
5215  number->add_precedence(accumulated_precedence);
5216  lastValidInput = number;
5217 
5218  precedence_insert(context, number, list);
5219  }
5220  else if (name == "false")
5221  {
5223  "madara::expression::Interpreter: "
5224  "Inserting false(0) into expression tree.\n");
5225 
5226  Number* number = new Number(context.get_logger(), (Integer)0);
5227  number->add_precedence(accumulated_precedence);
5228  lastValidInput = number;
5229 
5230  precedence_insert(context, number, list);
5231  }
5232  else if (name == "nan")
5233  {
5235  "madara::expression::Interpreter: "
5236  "Inserting NAN into expression tree.\n");
5237 
5238  Number* number = new Number(context.get_logger(), NAN);
5239  number->add_precedence(accumulated_precedence);
5240  lastValidInput = number;
5241 
5242  precedence_insert(context, number, list);
5243  }
5244  else if (name == "inf")
5245  {
5247  "madara::expression::Interpreter: "
5248  "Inserting INFINITY into expression tree.\n");
5249 
5250  Number* number = new Number(context.get_logger(), INFINITY);
5251  number->add_precedence(accumulated_precedence);
5252  lastValidInput = number;
5253 
5254  precedence_insert(context, number, list);
5255  }
5256  }
5257 
5258  else if (i < input.length() && input[i] == '(')
5259  {
5260  // save the function name and update i
5261  Function* function = new Function(name, context);
5262  function->add_precedence(accumulated_precedence);
5263 
5264  bool handled = false;
5265 
5266  ::std::list<Symbol*> param_list;
5267 
5268  int local_precedence = 0;
5269  Symbol* local_last_valid = 0;
5270 
5271  ++i;
5272 
5273  // we have a function instead of a variable
5274  handle_parenthesis(context, input, i, local_last_valid, handled,
5275  local_precedence, param_list, true);
5276 
5277  // if (param_list.size () > 0)
5278  // function->right_ = param_list.back ();
5279 
5280  function->nodes_.resize(param_list.size());
5281  int cur = 0;
5282 
5283  for (::std::list<Symbol*>::iterator arg = param_list.begin();
5284  arg != param_list.end(); ++arg, ++cur)
5285  {
5286  function->nodes_[cur] = (*arg)->build();
5287  }
5288 
5289  // function->right_ = new List (context);
5290 
5291  precedence_insert(context, function, list);
5292  lastValidInput = 0;
5293  }
5294  else if (i < input.length() && input[i] == '[')
5295  {
5296  ++i;
5297  handle_for_loop(
5298  context, name, input, i, accumulated_precedence, list, lastValidInput);
5299  }
5300  else
5301  {
5302  Symbol* op = new Variable(name, context);
5303  op->add_precedence(accumulated_precedence);
5304 
5305  // check for post increments and decrements
5306  if (i + 1 < input.size())
5307  {
5308  if (input[i] == '+' && input[i + 1] == '+')
5309  {
5310  Symbol* variable = op;
5311  op = new Postincrement(context.get_logger());
5312  op->add_precedence(accumulated_precedence);
5313  op->right_ = variable;
5314  i += 2;
5315  }
5316  else if (input[i] == '-' && input[i + 1] == '-')
5317  {
5318  Symbol* variable = op;
5319  op = new Postdecrement(context.get_logger());
5320  op->add_precedence(accumulated_precedence);
5321  op->right_ = variable;
5322  i += 2;
5323  }
5324  }
5325 
5326  lastValidInput = op;
5327 
5328  precedence_insert(context, op, list);
5329  }
5330 }
5331 
5332 // inserts a leaf node / number into the parse tree
5334  knowledge::ThreadSafeContext& context, const std::string& input,
5335  std::string::size_type& i, int& accumulated_precedence,
5336  ::std::list<madara::expression::Symbol*>& list,
5337  madara::expression::Symbol*& lastValidInput)
5338 {
5339  std::string::size_type j = 0;
5340  Number* number = 0;
5341 
5342  for (; i + j < input.length(); ++j)
5343  {
5344  if (input[i + j] == opener && input[i + j - 1] != '\\')
5345  break;
5346  }
5347 
5348  number = new Number(context.get_logger(), input.substr(i, j));
5349 
5350  number->add_precedence(accumulated_precedence);
5351 
5352  lastValidInput = number;
5353 
5354  // update i to next char for main loop or handle parenthesis.
5355 
5356  i += j + 1;
5357 
5358  precedence_insert(context, number, list);
5359 }
5360 
5361 // inserts a variable (leaf node / number) into the parse tree
5363  madara::knowledge::ThreadSafeContext& context, const std::string& input,
5364  std::string::size_type& i, int& accumulated_precedence,
5365  ::std::list<Symbol*>& list, Symbol*& lastValidInput)
5366 {
5367  // build a potential variable name (this could also be a function)
5368  std::string::size_type j = 1;
5369 
5370  for (; i + j < input.length() && is_alphanumeric(input[i + j]); ++j)
5371  continue;
5372 
5373  // the variable or function name is stored in input.substr (i,j)
5374  // is the next char a parenthesis?
5375 
5376  std::string name = input.substr(i, j);
5377 
5378  i += j;
5379 
5380  // eat up whitespace so we can check for a parenthesis (function)
5381  for (; i < input.length() && is_whitespace(input[i]); ++i)
5382  ;
5383 
5384  if (i < input.length() && input[i] == '(')
5385  {
5386  // save the function name and update i
5387  SystemCall* call = 0;
5388  char first_char = 0;
5389 
5390  if (name.size() > 1)
5391  {
5392  first_char = name[1];
5393  }
5394 
5395  switch (first_char)
5396  {
5397  case 'b':
5398  if (name == "#buffer")
5399  {
5400  call = new ToBuffer(context);
5401  }
5402  break;
5403  case 'c':
5404  if (name == "#clear_var" || name == "#clear_variable")
5405  {
5406  call = new ClearVariable(context);
5407  }
5408  else if (name == "#cos")
5409  {
5410  call = new Cos(context);
5411  }
5412  break;
5413  case 'd':
5414  if (name == "#delete_var" || name == "#delete_variable")
5415  {
5416  call = new DeleteVariable(context);
5417  }
5418  else if (name == "#double")
5419  {
5420  call = new ToDouble(context);
5421  }
5422  else if (name == "#doubles")
5423  {
5424  call = new ToDoubles(context);
5425  }
5426  break;
5427  case 'e':
5428  if (name == "#eval" || name == "#evaluate")
5429  {
5430  call = new Eval(context);
5431  }
5432  else if (name == "#expand" || name == "#expand_statement")
5433  {
5434  call = new ExpandStatement(context);
5435  }
5436  else if (name == "#expand_env" || name == "#expand_envs")
5437  {
5438  call = new ExpandEnv(context);
5439  }
5440  break;
5441  case 'f':
5442  if (name == "#fragment")
5443  {
5444  call = new Fragment(context);
5445  }
5446  else if (name == "#fixed")
5447  {
5448  call = new SetFixed(context);
5449  }
5450  break;
5451  case 'g':
5452  if (name == "#get_clock")
5453  {
5454  call = new GetClock(context);
5455  }
5456  else if (name == "#get_time" || name == "#get_time_ns" ||
5457  name == "#get_time_nano")
5458  {
5459  call = new GetTime(context);
5460  }
5461  else if (name == "#get_time_seconds" || name == "#get_time_s")
5462  {
5463  call = new GetTimeSeconds(context);
5464  }
5465  break;
5466  case 'i':
5467  if (name == "#integer")
5468  {
5469  call = new ToInteger(context);
5470  }
5471  else if (name == "#integers")
5472  {
5473  call = new ToIntegers(context);
5474  }
5475  else if (name == "#isinf")
5476  {
5477  call = new Isinf(context);
5478  }
5479  break;
5480  case 'l':
5481  if (name == "#log_level")
5482  {
5483  call = new LogLevel(context);
5484  }
5485  break;
5486  case 'p':
5487  if (name == "#pow")
5488  {
5489  call = new Power(context);
5490  }
5491  else if (name == "#print")
5492  {
5493  call = new Print(context);
5494  }
5495  else if (name == "#print_system_calls" || name == "#print_system_call")
5496  {
5497  call = new PrintSystemCalls(context);
5498  }
5499  else if (name == "#precision")
5500  {
5501  call = new SetPrecision(context);
5502  }
5503  break;
5504  case 'r':
5505  if (name == "#rand_double")
5506  {
5507  call = new RandDouble(context);
5508  }
5509  else if (name == "#rand_int" || name == "#rand_integer")
5510  {
5511  call = new RandInt(context);
5512  }
5513  else if (name == "#read_file")
5514  {
5515  call = new ReadFile(context);
5516  }
5517  break;
5518  case 's':
5519  if (name == "#scientific")
5520  {
5521  call = new SetScientific(context);
5522  }
5523  else if (name == "#set_clock")
5524  {
5525  call = new SetClock(context);
5526  }
5527  else if (name == "#set_fixed")
5528  {
5529  call = new SetFixed(context);
5530  }
5531  else if (name == "#set_precision")
5532  {
5533  call = new SetPrecision(context);
5534  }
5535  else if (name == "#set_scientific")
5536  {
5537  call = new SetScientific(context);
5538  }
5539  else if (name == "#sin")
5540  {
5541  call = new Sin(context);
5542  }
5543  else if (name == "#size")
5544  {
5545  call = new Size(context);
5546  }
5547  else if (name == "#sleep")
5548  {
5549  call = new Sleep(context);
5550  }
5551  else if (name == "#sqrt")
5552  {
5553  call = new SquareRoot(context);
5554  }
5555  else if (name == "#string")
5556  {
5557  call = new ToString(context);
5558  }
5559  break;
5560  case 't':
5561  if (name == "#tan")
5562  {
5563  call = new Tan(context);
5564  }
5565  else if (name == "#to_buffer")
5566  {
5567  call = new ToBuffer(context);
5568  }
5569  else if (name == "#to_double")
5570  {
5571  call = new ToDouble(context);
5572  }
5573  else if (name == "#to_doubles")
5574  {
5575  call = new ToDoubles(context);
5576  }
5577  else if (name == "#to_host_dirs")
5578  {
5579  call = new ToHostDirs(context);
5580  }
5581  else if (name == "#to_integer")
5582  {
5583  call = new ToInteger(context);
5584  }
5585  else if (name == "#to_integers")
5586  {
5587  call = new ToIntegers(context);
5588  }
5589  else if (name == "#to_string")
5590  {
5591  call = new ToString(context);
5592  }
5593  else if (name == "#type")
5594  {
5595  call = new Type(context);
5596  }
5597  break;
5598  case 'w':
5599  if (name == "#write_file")
5600  {
5601  call = new WriteFile(context);
5602  }
5603  break;
5604  default:
5605  break;
5606  }
5607 
5608  if (!call)
5609  {
5611  "madara::expression::Interpreter: "
5612  "System call %s is unsupported in this version of MADARA, "
5613  "defaulting to print_system_calls help menu.\n",
5614  name.c_str());
5615 
5616  throw exceptions::KarlException("madara::expression::Interpreter: "
5617  "System call %s does not exist.");
5618  }
5619  else
5620  {
5621  call->add_precedence(accumulated_precedence);
5622  }
5623 
5624  bool handled = false;
5625 
5626  ::std::list<Symbol*> param_list;
5627 
5628  ++i;
5629 
5630  // we have a function instead of a variable
5631  handle_parenthesis(context, input, i, lastValidInput, handled,
5632  accumulated_precedence, param_list, true);
5633 
5634  call->nodes_.resize(param_list.size());
5635  int cur = 0;
5636 
5637  for (::std::list<Symbol*>::iterator arg = param_list.begin();
5638  arg != param_list.end(); ++arg, ++cur)
5639  {
5640  call->nodes_[cur] = (*arg)->build();
5641  }
5642 
5643  precedence_insert(context, call, list);
5644  lastValidInput = 0;
5645  }
5646  else
5647  {
5648  std::string message = "madara::expression::Interpreter: "
5649  "KARL COMPILE ERROR: System call ";
5650  message += name;
5651  message += " does not have appropriate parentheses\n";
5652 
5653  madara_logger_log(context.get_logger(), logger::LOG_ERROR, message.c_str());
5654 
5655  throw exceptions::KarlException(message.c_str());
5656  }
5657 }
5658 
5659 // inserts a leaf node / number into the parse tree
5661  knowledge::ThreadSafeContext& context, const std::string& input,
5662  std::string::size_type& i, int& accumulated_precedence,
5663  ::std::list<madara::expression::Symbol*>& list,
5664  madara::expression::Symbol*& lastValidInput)
5665 {
5666  // merge all consecutive number chars into a single Number symbol,
5667  // eg '123' = int (123). Scope of j needs to be outside of the for
5668  // loop.
5669 
5670  std::string::size_type j = 1;
5671  Number* number = 0;
5672 
5673  for (; i + j <= input.length() && is_number(input[i + j]); ++j)
5674  continue;
5675 
5676  // do we have a float?
5677  if ((i + j <= input.length() && input[i + j] == '.') || input[i] == '.')
5678  {
5679  if (input[i] != '.')
5680  ++j;
5681 
5682  for (; i + j <= input.length() && is_number(input[i + j]); ++j)
5683  continue;
5684 
5685  // scientific notation
5686  if (i + j <= input.length() && (input[i + j] == 'e' || input[i + j] == 'E'))
5687  {
5688  ++j;
5689  if (i + j <= input.length() &&
5690  (input[i + j] == '+' || input[i + j] == '-'))
5691  {
5692  ++j;
5693  }
5694 
5695  for (; i + j <= input.length() && is_number(input[i + j]); ++j)
5696  continue;
5697  }
5698 
5699  double new_number;
5700 
5701  std::stringstream buffer;
5702  buffer << input.substr(i, j);
5703  buffer >> new_number;
5704 
5705  number = new Number(context.get_logger(), new_number);
5706  }
5707  else
5708  {
5709  // we have an integer
5710 
5712 
5713  std::stringstream buffer;
5714  buffer << input.substr(i, j);
5715  buffer >> new_number;
5716 
5717  number = new Number(context.get_logger(), new_number);
5718  }
5719 
5720  number->add_precedence(accumulated_precedence);
5721 
5722  lastValidInput = number;
5723 
5724  // update i to next char for main loop or handle parenthesis.
5725 
5726  i += j;
5727 
5728  precedence_insert(context, number, list);
5729 }
5730 
5731 // inserts a multiplication or division into the parse tree
5734  ::std::list<madara::expression::Symbol*>& list)
5735 {
5736  if (!list.empty())
5737  {
5738  // if last element was a number, then make that our left_
5739 
5740  Symbol* parent = list.back();
5741  Symbol* child = 0;
5742  Symbol* grandparent = 0;
5743 
5744  // check to see if op is an assignment or implication, which are treated
5745  // uniquely
5746  Assignment* op_assignment = dynamic_cast<Assignment*>(op);
5747  Implies* op_implies = dynamic_cast<Implies*>(op);
5748  UnaryOperator* op_unary = dynamic_cast<UnaryOperator*>(op);
5749 
5750  // move down the right side of the tree until we find either a null or
5751  // a precedence that is >= this operation's precedence. This puts us
5752  // in the situation that we know our op should be performed after child
5753  // or child should be null (assignment or implication not withstanding)
5754  for (child = parent->right_;
5755  child && child->precedence() < op->precedence(); child = child->right_)
5756  {
5757  grandparent = parent;
5758  parent = child;
5759  }
5760 
5761  // child casts
5762  Operator* child_operator = dynamic_cast<Operator*>(child);
5763  Operator* child_ternary = dynamic_cast<TernaryOperator*>(child);
5764 
5765  if (child && (child_operator == 0 && child_ternary == 0))
5766  {
5768  "Interpreter::precedence_insert: "
5769  "Level 1: child is neither an operator or ternary\n");
5770  }
5771 
5772  // parent->precedence is < op->precedence at this point
5773 
5774  if (op_assignment || op_implies || op_unary)
5775  {
5776  // if we are an assignment, implies, or unary op, we actually
5777  // need this op to have slightly higher precedence (it needs to be
5778  // evaluated first). This situation is signified by something like this
5779  // var1 = var2 = var3 = 1. In the list, will be var1 = var2 = var3, so
5780  // parent will be and assignment, and parent left will be var1, right and
5781  // child will be assignment and it will have a left of var2
5782 
5783  for (child = parent->right_;
5784  child && child->precedence() <= op->precedence();
5785  child = child->right_)
5786  {
5787  grandparent = parent;
5788  parent = child;
5789  }
5790 
5791  // child casts
5792  child_operator = dynamic_cast<Operator*>(child);
5793  child_ternary = dynamic_cast<TernaryOperator*>(child);
5794 
5795  if (child && (child_operator == 0 && child_ternary == 0))
5796  {
5798  "Interpreter::precedence_insert: "
5799  "Level 2: child is neither an operator or ternary\n");
5800  }
5801  }
5802 
5803  // Now that we have our parent and child setup appropriately according
5804  // to precedence relationships, we should be able to modify or replace
5805  // the tree in the list
5806 
5807  if (parent->precedence() < op->precedence() ||
5808  (parent->precedence() == op->precedence() &&
5809  (op_assignment || op_implies || op_unary)))
5810  {
5811  // this op needs to be evaluated before the parent
5812 
5813  // first let's do some error checking, so we can give helpful compile
5814  // errors
5815  Operator* parent_binary = dynamic_cast<Operator*>(parent);
5816  UnaryOperator* parent_unary = dynamic_cast<UnaryOperator*>(parent);
5817 
5818  // if the parent is a binary (like addition or &&), then it needs a left
5819  // hand side if it doesn't have this, let's report a warning and insert a
5820  // Leaf Node with a value of zero
5821  if (parent_binary && !parent->left_)
5822  {
5823  // try to give as specific message as possible
5824  Both* parent_both = dynamic_cast<Both*>(parent);
5825  if (parent_both)
5826  {
5828  "KARL COMPILE WARNING: Empty statements between ';' may"
5829  " cause slower execution, attempting to prune away the extra "
5830  "statement\n");
5831  }
5832  else
5833  {
5835  "madara::expression::Interpreter: "
5836  "KARL COMPILE WARNING: Binary operation has no left child. "
5837  "Inserting a zero\n");
5838 
5839  parent->left_ = new Number(context.get_logger(),
5841  }
5842  }
5843 
5844  // if the parent is a unary operator (like negate or not), then it should
5845  // NOT have a left child. This would only happen if someone input
5846  // something like 5 ! 3, which has no meaning. This is a compile error.
5847  if (parent_unary && parent->left_)
5848  {
5850  "madara::expression::Interpreter: "
5851  "KARL COMPILE ERROR: Unary operation shouldn't have a left "
5852  "child\n");
5853 
5855  "madara::expression::Interpreter: "
5856  "KARL COMPILE ERROR: "
5857  "Parent unary node has a left child, shouldn't be possible\n");
5858  }
5859 
5860  // if we've gotten to this point, then we need to
5861  // replace the child with ourself in the tree
5862  if (child)
5863  {
5864  if (op_unary)
5865  {
5866  // This is a compile error. Unary cannot have a left
5867  // child, and that is the only way that being at this
5868  // point would make sense.
5870  "madara::expression::Interpreter: "
5871  "KARL COMPILE ERROR: unary operation shouldn't have a left "
5872  "child\n");
5873 
5875  "madara::expression::Interpreter: "
5876  "KARL COMPILE ERROR: "
5877  "Unary node has a left child, shouldn't be possible\n");
5878  }
5879  else
5880  {
5882  "Interpreter::precedence_insert: "
5883  "Level 3: op is setting its left to the existing child\n");
5884 
5885  op->left_ = child;
5886  }
5887  }
5888 
5890  "Interpreter::precedence_insert: "
5891  "Level 3: parent->right is being set to current operator\n");
5892 
5893  parent->right_ = op;
5894  }
5895  else
5896  {
5897  // we are a lower precedence than our parent, so we need to replace
5898  // the tree in the list. This typically happens with assignment, implies,
5899  // logical operations (&&, ||) and equality checks
5900 
5901  op->left_ = parent;
5902 
5903  if (grandparent)
5904  grandparent->right_ = op;
5905  else
5906  {
5907  list.pop_back();
5908  list.push_back(op);
5909  }
5910  }
5911  }
5912  else
5913  {
5914  list.push_back(op);
5915  }
5916 }
5917 
5919  madara::knowledge::ThreadSafeContext& context, const std::string& input,
5920  std::string::size_type& i, madara::expression::Symbol*& lastValidInput,
5921  bool& handled, int& accumulated_precedence,
5922  ::std::list<madara::expression::Symbol*>& list, bool build_argument_list)
5923 {
5924  handled = false;
5925  if (is_number(input[i]) ||
5926  (i + 1 < input.size() && input[i] == '.' && is_number(input[i + 1])))
5927  {
5928  handled = true;
5929  // leaf node
5930  number_insert(
5931  context, input, i, accumulated_precedence, list, lastValidInput);
5932  }
5933  else if (is_alphanumeric(input[i]))
5934  {
5935  handled = true;
5936  // variable leaf node
5937  variable_insert(
5938  context, input, i, accumulated_precedence, list, lastValidInput);
5939  }
5940  else if (is_string_literal(input[i]))
5941  {
5942  char opener = input[i];
5943  ++i;
5944  handled = true;
5945  // string
5946  string_insert(opener, context, input, i, accumulated_precedence, list,
5947  lastValidInput);
5948  }
5949  else if (i < input.length() && input[i] == '[')
5950  {
5951  // save the function name and update i
5952  ConstArray* object = new ConstArray(context);
5953  object->add_precedence(accumulated_precedence);
5954 
5955  handled = false;
5956 
5957  ::std::list<Symbol*> param_list;
5958 
5959  int local_precedence = 0;
5960  Symbol* local_last_valid = 0;
5961 
5962  ++i;
5963 
5964  // we have an array
5965  handle_array(context, input, i, local_last_valid, handled, local_precedence,
5966  param_list);
5967 
5968  object->nodes_.resize(param_list.size());
5969  int cur = 0;
5970 
5971  for (::std::list<Symbol*>::iterator arg = param_list.begin();
5972  arg != param_list.end(); ++arg, ++cur)
5973  {
5974  object->nodes_[cur] = (*arg)->build();
5975  }
5976 
5977  precedence_insert(context, object, list);
5978  lastValidInput = 0;
5979  }
5980  else if (input[i] == '#')
5981  {
5982  handled = true;
5983  // variable leaf node
5984  system_call_insert(
5985  context, input, i, accumulated_precedence, list, lastValidInput);
5986  }
5987  else if (input[i] == '+')
5988  {
5989  handled = true;
5990  Symbol* op = 0;
5991 
5992  // is this a predecrement?
5993  if (i + 1 < input.size() && input[i + 1] == '+')
5994  {
5995  op = new Preincrement(context.get_logger());
5996  ++i;
5997  }
5998  // is this an atomic increment?
5999  else if (i + 1 < input.size() && input[i + 1] == '=')
6000  {
6001  Variable* var = dynamic_cast<Variable*>(lastValidInput);
6002  ArrayRef* array_ref = dynamic_cast<ArrayRef*>(lastValidInput);
6003  if (var || array_ref)
6004  {
6005  op = new VariableIncrement(
6006  lastValidInput, madara::knowledge::KnowledgeRecord(), 0, context);
6007  }
6008  else
6009  {
6011  "madara::expression::Interpreter: "
6012  "KARL COMPILE ERROR (+=): "
6013  "Assignments must have a variable left hand side.\n");
6014 
6016  "madara::expression::Interpreter: "
6017  "KARL COMPILE ERROR (+=): "
6018  "Assignments must have a variable left hand side");
6019  }
6020  ++i;
6021  }
6022  else
6023  op = new Add(context.get_logger());
6024 
6025  // insert the op according to left-to-right relationships
6026  op->add_precedence(accumulated_precedence);
6027  lastValidInput = 0;
6028  precedence_insert(context, op, list);
6029  ++i;
6030  }
6031  else if (input[i] == '-')
6032  {
6033  handled = true;
6034  Symbol* op = 0;
6035 
6036  // is this a predecrement?
6037  if (i + 1 < input.size() && input[i + 1] == '-')
6038  {
6039  op = new Predecrement(context.get_logger());
6040  ++i;
6041  }
6042  // is this an atomic decrement?
6043  else if (i + 1 < input.size() && input[i + 1] == '=')
6044  {
6045  Variable* var = dynamic_cast<Variable*>(lastValidInput);
6046  ArrayRef* array_ref = dynamic_cast<ArrayRef*>(lastValidInput);
6047  if (var || array_ref)
6048  {
6049  op = new VariableDecrement(
6050  lastValidInput, madara::knowledge::KnowledgeRecord(), 0, context);
6051  }
6052  else
6053  {
6055  "madara::expression::Interpreter: "
6056  "KARL COMPILE ERROR (-=): "
6057  "Assignments must have a variable left hand side.\n");
6058 
6060  "madara::expression::Interpreter: "
6061  "KARL COMPILE ERROR (-=): "
6062  "Assignments must have a variable left hand side");
6063  }
6064  ++i;
6065  }
6066  // is this a number literal? Handling this way allows for INT64_MIN
6067  else if (i + 1 < input.size() && is_number(input[i + 1]))
6068  {
6069  handled = true;
6070  // leaf node
6071  number_insert(
6072  context, input, i, accumulated_precedence, list, lastValidInput);
6073  }
6074  // Negate
6075  else if (!lastValidInput)
6076  op = new Negate(context.get_logger());
6077  // Subtract
6078  else
6079  op = new Subtract(context.get_logger());
6080 
6081  if (op)
6082  {
6083  // insert the op according to left-to-right relationships
6084  lastValidInput = 0;
6085  op->add_precedence(accumulated_precedence);
6086  precedence_insert(context, op, list);
6087  ++i;
6088  }
6089  }
6090  else if (input[i] == '*')
6091  {
6092  handled = true;
6093  Symbol* op = 0;
6094 
6095  // is this an atomic multiply?
6096  if (i + 1 < input.size() && input[i + 1] == '=')
6097  {
6098  Variable* var = dynamic_cast<Variable*>(lastValidInput);
6099  ArrayRef* array_ref = dynamic_cast<ArrayRef*>(lastValidInput);
6100  if (var || array_ref)
6101  {
6102  op = new VariableMultiply(
6103  lastValidInput, madara::knowledge::KnowledgeRecord(), 0, context);
6104  }
6105  else
6106  {
6108  "madara::expression::Interpreter: "
6109  "KARL COMPILE ERROR (*=): "
6110  "Assignments must have a variable left hand side.\n");
6111 
6113  "madara::expression::Interpreter: "
6114  "KARL COMPILE ERROR (*=): "
6115  "Assignments must have a variable left hand side");
6116  }
6117  ++i;
6118  }
6119  // multiplication operation
6120  else
6121  op = new Multiply(context.get_logger());
6122 
6123  // insert the op according to precedence relationships
6124  op->add_precedence(accumulated_precedence);
6125  lastValidInput = 0;
6126  precedence_insert(context, op, list);
6127  ++i;
6128  }
6129  else if (input[i] == '%')
6130  {
6131  // multiplication operation
6132  handled = true;
6133  Modulus* op = new Modulus(context.get_logger());
6134 
6135  // insert the op according to precedence relationships
6136  op->add_precedence(accumulated_precedence);
6137  lastValidInput = 0;
6138  precedence_insert(context, op, list);
6139  ++i;
6140  }
6141  else if (input[i] == '/')
6142  {
6143  // is this a one line comment?
6144  if (i + 1 < input.size() && input[i + 1] == '/')
6145  {
6146  // we have a one line comment
6147  for (; i < input.size() && input[i] != '\n'; ++i)
6148  ;
6149  }
6150  // is this a multi-line comment?
6151  else if (i + 1 < input.size() && input[i + 1] == '*')
6152  {
6153  // find the matching close
6154  std::string::size_type found = input.find("*/", i + 1);
6155 
6156  // if we were able to find the matching close,
6157  // then set i to the '/' in '*/'
6158  if (found != std::string::npos)
6159  i = found + 1;
6160 
6161  // otherwise, the user apparently wanted to
6162  // comment out the rest of the file
6163  else
6164  i = input.size();
6165  }
6166  // is this an atomic decrement?
6167  else
6168  {
6169  handled = true;
6170  // division operation
6171  Symbol* op = 0;
6172 
6173  // atomic division?
6174  if (i + 1 < input.size() && input[i + 1] == '=')
6175  {
6176  Variable* var = dynamic_cast<Variable*>(lastValidInput);
6177  ArrayRef* array_ref = dynamic_cast<ArrayRef*>(lastValidInput);
6178  if (var || array_ref)
6179  {
6180  op = new VariableDivide(
6181  lastValidInput, madara::knowledge::KnowledgeRecord(), 0, context);
6182  }
6183  else
6184  {
6186  "madara::expression::Interpreter: "
6187  "KARL COMPILE ERROR (/=): "
6188  "Assignments must have a variable left hand side.\n");
6189 
6191  "madara::expression::Interpreter: "
6192  "KARL COMPILE ERROR (/=): "
6193  "Assignments must have a variable left hand side");
6194  }
6195  ++i;
6196  }
6197  else
6198  op = new Divide(context.get_logger());
6199 
6200  op->add_precedence(accumulated_precedence);
6201  lastValidInput = 0;
6202  precedence_insert(context, op, list);
6203  }
6204  ++i;
6205  }
6206  else if (input[i] == '=')
6207  {
6208  handled = true;
6209  Symbol* op = 0;
6210 
6211  // is this an equality?
6212  if (i + 1 < input.size() && input[i + 1] == '=')
6213  {
6214  op = new Equality(context.get_logger());
6215  op->add_precedence(accumulated_precedence);
6216 
6217  lastValidInput = 0;
6218  ++i;
6219 
6220  // insert the op according to precedence relationships
6221  precedence_insert(context, op, list);
6222  }
6223  // is this an implication?
6224  else if (i + 1 < input.size() && input[i + 1] == '>')
6225  {
6226  op = new Implies(context.get_logger());
6227  op->add_precedence(accumulated_precedence);
6228 
6229  lastValidInput = 0;
6230  ++i;
6231 
6232  // insert the op according to precedence relationships
6233  precedence_insert(context, op, list);
6234  }
6235  // must be an assignment then
6236  else
6237  {
6238  op = new Assignment(context.get_logger());
6239  op->add_precedence(accumulated_precedence);
6240 
6241  lastValidInput = 0;
6242 
6243  // insert the op according to precedence relationships
6244  // assignment_insert (op, list);
6245  precedence_insert(context, op, list);
6246  }
6247  ++i;
6248  }
6249  else if (input[i] == '!')
6250  {
6251  handled = true;
6252  Symbol* op = 0;
6253 
6254  // is this an inequality?
6255  if (i + 1 < input.size() && input[i + 1] == '=')
6256  {
6257  op = new Inequality(context.get_logger());
6258  ++i;
6259  }
6260  // must be a logical not then
6261  else
6262  {
6263  op = new Not(context.get_logger());
6264  }
6265 
6266  // insert the op according to precedence relationships
6267  op->add_precedence(accumulated_precedence);
6268  lastValidInput = 0;
6269  precedence_insert(context, op, list);
6270  ++i;
6271  }
6272  // square root is ASCII 251 (UTF 8 format)
6273  else if ((uint8_t)input[i] == 251)
6274  {
6275  handled = true;
6276  Symbol* op = 0;
6277 
6278  op = new SquareRootUnary(context.get_logger());
6279 
6280  // insert the op according to precedence relationships
6281  op->add_precedence(accumulated_precedence);
6282  lastValidInput = 0;
6283  precedence_insert(context, op, list);
6284  ++i;
6285  }
6286  else if (input[i] == '&')
6287  {
6288  // is this a logical and?
6289  if (i + 1 < input.size() && input[i + 1] == '&')
6290  {
6291  handled = true;
6292  Symbol* op = new And(context.get_logger());
6293  ++i;
6294 
6295  // insert the op according to precedence relationships
6296  op->add_precedence(accumulated_precedence);
6297  lastValidInput = 0;
6298  precedence_insert(context, op, list);
6299  }
6300  else
6301  {
6302  // error. We currently don't allow logical and (A & B)
6304  "madara::expression::Interpreter: "
6305  "KARL COMPILE ERROR: "
6306  "Logical And (&) not available. "
6307  "You may want to use && instead in %s.\n",
6308  input.c_str());
6309 
6310  throw exceptions::KarlException("madara::expression::Interpreter: "
6311  "KARL COMPILE ERROR: "
6312  "Logical And (&) not available.");
6313  }
6314  ++i;
6315  }
6316  else if (input[i] == '|')
6317  {
6318  // is this a logical and?
6319  if (i + 1 < input.size() && input[i + 1] == '|')
6320  {
6321  handled = true;
6322  Symbol* op = new Or(context.get_logger());
6323  ++i;
6324 
6325  // insert the op according to precedence relationships
6326  op->add_precedence(accumulated_precedence);
6327  lastValidInput = 0;
6328  precedence_insert(context, op, list);
6329  }
6330  else
6331  {
6332  // error. We don't currently support logical or
6334  "KARL COMPILE ERROR: "
6335  "Logical Or (|) not available. "
6336  "You may want to use || instead in %s.\n",
6337  input.c_str());
6338 
6339  throw exceptions::KarlException("madara::expression::Interpreter: "
6340  "KARL COMPILE ERROR: "
6341  "Logical Or (|) not available.");
6342  }
6343  ++i;
6344  }
6345  else if (input[i] == ';')
6346  {
6347  handled = true;
6348  Symbol* op = 0;
6349 
6350  // is this a logical and?
6351  if (i + 1 < input.size() && input[i + 1] == '>')
6352  {
6353  op = new ReturnRight(context.get_logger());
6354  ++i;
6355  }
6356  else
6357  {
6358  op = new Both(context.get_logger());
6359  }
6360 
6361  // insert the op according to precedence relationships
6362  op->add_precedence(accumulated_precedence);
6363  lastValidInput = 0;
6364  precedence_insert(context, op, list);
6365  ++i;
6366  }
6367  else if (input[i] == ',')
6368  {
6369  if (build_argument_list)
6370  return;
6371 
6372  handled = true;
6373  Symbol* op = new Sequence(context.get_logger());
6374 
6375  // insert the op according to precedence relationships
6376  op->add_precedence(accumulated_precedence);
6377  lastValidInput = 0;
6378  precedence_insert(context, op, list);
6379  ++i;
6380  }
6381  else if (input[i] == '<')
6382  {
6383  handled = true;
6384  Symbol* op = 0;
6385 
6386  // is this a less than or equal to operator?
6387  if (i + 1 < input.size() && input[i + 1] == '=')
6388  {
6389  op = new LessThanEqual(context.get_logger());
6390  ++i;
6391  }
6392  // must be a less than operator
6393  else
6394  op = new LessThan(context.get_logger());
6395 
6396  // insert the op according to precedence relationships
6397  op->add_precedence(accumulated_precedence);
6398  lastValidInput = 0;
6399  precedence_insert(context, op, list);
6400  ++i;
6401  }
6402  else if (input[i] == '>')
6403  {
6404  handled = true;
6405  Symbol* op = 0;
6406 
6407  // is this a less than or equal to operator?
6408  if (i + 1 < input.size() && input[i + 1] == '=')
6409  {
6410  op = new GreaterThanEqual(context.get_logger());
6411  ++i;
6412  }
6413  // must be a less than operator
6414  else
6415  op = new GreaterThan(context.get_logger());
6416 
6417  // insert the op according to precedence relationships
6418  op->add_precedence(accumulated_precedence);
6419  lastValidInput = 0;
6420  precedence_insert(context, op, list);
6421  ++i;
6422  }
6423  else if (input[i] == '(')
6424  {
6425  handled = true;
6426  ++i;
6427  handle_parenthesis(context, input, i, lastValidInput, handled,
6428  accumulated_precedence, list);
6429  }
6430  else if (input[i] == '\t' || input[i] == ' ' || input[i] == '\r' ||
6431  input[i] == '\n')
6432  {
6433  handled = true;
6434  ++i;
6435  // skip whitespace
6436  }
6437 }
6438 
6440  madara::knowledge::ThreadSafeContext& context, const std::string& input,
6441  std::string::size_type& i, madara::expression::Symbol*& lastValidInput,
6442  bool& handled, int& accumulated_precedence,
6443  ::std::list<madara::expression::Symbol*>& master_list)
6444 {
6445  /* handle parenthesis is a lot like handling a new interpret.
6446  the difference is that we have to worry about how the calling
6447  function has its list setup */
6448 
6449  accumulated_precedence += PARENTHESIS_PRECEDENCE;
6450  int initial_precedence = accumulated_precedence;
6451 
6452  ::std::list<Symbol*> list;
6453 
6454  handled = false;
6455  bool closed = false;
6456  while (i < input.length())
6457  {
6458  main_loop(context, input, i, lastValidInput, handled,
6459  accumulated_precedence, list, true);
6460 
6461  if (input[i] == ']')
6462  {
6463  handled = true;
6464  closed = true;
6465  ++i;
6466  accumulated_precedence -= PARENTHESIS_PRECEDENCE;
6467  break;
6468  }
6469  else if (input[i] == ',')
6470  {
6471  ++i;
6472  while (list.size())
6473  {
6474  master_list.push_back(list.back());
6475  list.pop_back();
6476  }
6477  accumulated_precedence = initial_precedence;
6478  }
6479  else if (i == input.length() - 1)
6480  {
6481  break;
6482  }
6483  }
6484 
6485  if (!closed)
6486  {
6488  "madara::expression::Interpreter: "
6489  "KARL COMPILE ERROR: "
6490  "Forgot to close parenthesis in %s.\n",
6491  input.c_str());
6492  }
6493 
6494  if (list.size() > 0)
6495  {
6496  if (list.size() > 1)
6497  {
6499  "madara::expression::Interpreter: "
6500  "KARL COMPILE ERROR: "
6501  "A parenthesis was closed, leaving multiple list items (there should "
6502  "be a max of 1) in %s.\n",
6503  input.c_str());
6504  }
6505 
6506  while (list.size())
6507  {
6508  master_list.push_back(list.back());
6509  list.pop_back();
6510  }
6511  }
6512 
6513  list.clear();
6514 }
6515 
6517  madara::knowledge::ThreadSafeContext& context, const std::string& input,
6518  std::string::size_type& i, madara::expression::Symbol*& lastValidInput,
6519  bool& handled, int& accumulated_precedence,
6520  ::std::list<madara::expression::Symbol*>& master_list,
6521  bool build_argument_list)
6522 {
6523  /* handle parenthesis is a lot like handling a new interpret.
6524  the difference is that we have to worry about how the calling
6525  function has its list setup */
6526 
6527  accumulated_precedence += PARENTHESIS_PRECEDENCE;
6528  int initial_precedence = accumulated_precedence;
6529 
6530  ::std::list<Symbol*> list;
6531 
6532  handled = false;
6533  bool closed = false;
6534  while (i < input.length())
6535  {
6536  main_loop(context, input, i, lastValidInput, handled,
6537  accumulated_precedence, list, build_argument_list);
6538 
6539  if (input[i] == ')')
6540  {
6541  handled = true;
6542  closed = true;
6543  ++i;
6544  accumulated_precedence -= PARENTHESIS_PRECEDENCE;
6545  break;
6546  }
6547  else if (build_argument_list && input[i] == ',')
6548  {
6549  ++i;
6550  while (list.size())
6551  {
6552  master_list.push_back(list.back());
6553  list.pop_back();
6554  }
6555  accumulated_precedence = initial_precedence;
6556  }
6557  else if (i == input.length() - 1)
6558  {
6559  break;
6560  }
6561  }
6562 
6563  if (!build_argument_list && !closed)
6564  {
6566  "madara::expression::Interpreter: "
6567  "KARL COMPILE ERROR: "
6568  "Forgot to close parenthesis in %s.\n",
6569  input.c_str());
6570  }
6571 
6572  if (!build_argument_list && master_list.size() > 0 && list.size() > 0)
6573  {
6574  Symbol* lastSymbol = master_list.back();
6575  Operator* op = dynamic_cast<Operator*>(lastSymbol);
6576  UnaryOperator* unary = dynamic_cast<UnaryOperator*>(lastSymbol);
6577 
6578  // is it a node with 2 children?
6579  if (op || unary)
6580  {
6581  precedence_insert(context, list.back(), master_list);
6582  }
6583  else
6584  {
6585  // is it a terminal node (Number)
6586  // error
6587  }
6588  }
6589  else if (list.size() > 0)
6590  {
6591  if (list.size() > 1)
6592  {
6594  "madara::expression::Interpreter: "
6595  "KARL COMPILE ERROR: "
6596  "A parenthesis was closed, leaving multiple list items (there should "
6597  "be a max of 1) in %s.\n",
6598  input.c_str());
6599  }
6600 
6601  while (list.size())
6602  {
6603  master_list.push_back(list.back());
6604  list.pop_back();
6605  }
6606  }
6607 
6608  list.clear();
6609 }
6610 
6611 // converts a string and context into a parse tree, and builds an
6612 // expression tree out of the parse tree
6614  knowledge::ThreadSafeContext& context, const std::string& input)
6615 {
6616  // return the cached expression tree if it exists
6617  ExpressionTreeMap::const_iterator found = cache_.find(input);
6618  if (found != cache_.end())
6619  return found->second;
6620 
6621  ::std::list<Symbol*> list;
6622  // list.clear ();
6623  Symbol* lastValidInput = 0;
6624  bool handled = false;
6625  int accumulated_precedence = 0;
6626  std::string::size_type last_i = 0;
6627 
6628  for (std::string::size_type i = 0; i < input.length();)
6629  {
6630  // we took out the loop update from the for loop
6631  // and the main_loop or handle_parenthesis call
6632  // should now take care of this.
6633  main_loop(context, input, i, lastValidInput, handled,
6634  accumulated_precedence, list);
6635 
6636  if (i == last_i)
6637  {
6638  size_t start = i > 10 ? i - 10 : 0;
6639  size_t end = input.size() - i > 10 ? i + 10 : input.size();
6640 
6641  std::string snippet = input.substr(start, end - start);
6642 
6643  {
6645  "madara::expression::Interpreter: "
6646  "KARL: "
6647  "Compilation is spinning at %d in %s. Char is %c. Breaking out.\n",
6648  (int)i, snippet.c_str(), input[i]);
6649  }
6650  break;
6651  }
6652  else
6653  last_i = i;
6654 
6655  // store last valid input symbol. this is useful to the '-' operator
6656  // and will help us determine if '-' is a subtraction or a negation
6657  // if (input[i] != ' ' && input[i] != '\n')
6658  // lastValidInput = input[i];
6659  }
6660 
6661  // if the list has an element in it, then return the back of the list.
6662  if (!list.empty())
6663  {
6664  // Invoke a recursive ExpressionTree build starting with the root
6665  // symbol. This is an example of the builder pattern. See pg 97
6666  // in GoF book.
6667 
6668  ExpressionTree tree(context.get_logger(), list.back()->build(), false);
6669 
6670  // optimize the tree
6671  tree.prune();
6672  delete list.back();
6673 
6674  // store this optimized tree into cached memory
6675  cache_[input] = tree;
6676 
6677  return tree;
6678  }
6679 
6680  // If we reach this, we didn't have any symbols.
6681  return ExpressionTree(context.get_logger());
6682 }
6683 
6684 #endif // _MADARA_NO_KARL_
6685 
6686 #endif // _INTERPRETER_CPP_
madara::knowledge::KnowledgeRecord::Integer Integer
Definition: Interpreter.cpp:90
#define madara_logger_ptr_log(loggering, level,...)
Fast version of the madara::logger::log method for Logger pointers.
Definition: Logger.h:41
#define madara_logger_log(loggering, level,...)
Fast version of the madara::logger::log method.
Definition: Logger.h:20
madara::knowledge::KnowledgeRecord::Integer Integer
const ThreadSafeContext * context_
An exception for unrecoverable KaRL compilation issues.
Definition: KarlException.h:21
Addition node of the parse tree.
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ~Add(void)
destructor
Add(logger::Logger &logger)
constructor
Logically and node of the parse tree.
virtual ~And(void)
destructor
And(logger::Logger &logger)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Leaf node for an array reference.
madara::knowledge::ThreadSafeContext & context_
Context for variables.
ArrayRef(const std::string &key, Symbol *index, madara::knowledge::ThreadSafeContext &context)
constructors
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
const std::string key_
Key for retrieving value of this variable.
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ~ArrayRef(void)
destructor
Assign the value of an expression to a variable.
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Assignment(logger::Logger &logger)
constructor
virtual ~Assignment(void)
destructor
Evaluates both left and right children, regardless of values.
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ~Both(void)
destructor
Both(logger::Logger &logger)
constructor
Clears a variable in the knowledge base.
virtual ~ClearVariable(void)
destructor
ClearVariable(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
An abstract base class defines a simple abstract implementation of an expression tree node.
Definition: ComponentNode.h:37
A composite node that encompasses addition of two expressions.
A composite node that performs a logical and.
Defines a terminal node of that references the current value stored in a variable.
A composite node that allows for variable assignment.
A composite node that evaluates both left and right expressions regardless of their evaluations.
A composite node that contains an array of values.
A composite node that divides a left expression by a right one.
A composite node that compares left and right expressions for equality.
A composite node that iterates until a condition is met.
A composite node that calls a function.
A composite node that compares left and right expressions for greater than or equal to.
A composite node that compares left and right children for greater than.
A composite node that performs an implication (inference rule)
A composite node that compares left and right children for inequality.
A composite node that compares left and right children for less than or equal to.
A composite node that compares left and right children for less than.
A composite node that divides a left expression by a right expression and returns the remainder of th...
A composite node that multiplies a left expression by a right expression.
A composite node that integrally negates a right expression.
A composite node that logically nots a right expression.
A composite node that performs a logical or.
A composite node that decrements a left expression.
A composite node that increments a right expression.
A composite node that decrements a right expression.
A composite node that increments a right expression.
A composite node that evaluates both left and right expressions regardless of their evaluations.
A composite node that evaluates both left and right expressions regardless of their evaluations.
A composite node that takes the square root of a term.
A composite node that encompasses subtraction of a right expression from a left expression.
A constant array that should not be changed.
virtual ~ConstArray(void)
destructor
ConstArray(madara::knowledge::ThreadSafeContext &context)
constructor
madara::knowledge::ThreadSafeContext & context_
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Returns the cosine of a term (radians)
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual ~Cos(void)
destructor
Cos(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Deletes a variable from the knowledge base.
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual ~DeleteVariable(void)
destructor
DeleteVariable(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Division node of the parse tree.
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Divide(logger::Logger &logger)
constructor
virtual ~Divide(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Check and left and right arguments for equality.
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Equality(logger::Logger &logger)
constructor
virtual ~Equality(void)
destructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Evaluates a Knowledge Record and returns result.
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Eval(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual ~Eval(void)
destructor
Expands a statement, e.g.
ExpandEnv(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual ~ExpandEnv(void)
destructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Expands a statement, e.g.
virtual ~ExpandStatement(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
ExpandStatement(madara::knowledge::ThreadSafeContext &context_)
constructor
Encapsulates a MADARA KaRL expression into an evaluatable tree.
madara::knowledge::KnowledgeRecord prune(void)
Prunes the expression tree of unnecessary nodes.
Iterative looping node of the parse tree.
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
madara::knowledge::ThreadSafeContext & context_
ForLoop(Symbol *precondition, Symbol *condition, Symbol *postcondition, Symbol *body, madara::knowledge::ThreadSafeContext &context)
constructor
virtual ~ForLoop(void)
destructor
Fragment the Knowledge Record.
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Fragment(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual ~Fragment(void)
destructor
Function node of the parse tree.
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Function(const std::string &name, madara::knowledge::ThreadSafeContext &context)
constructor
madara::knowledge::ThreadSafeContext & context_
virtual ~Function(void)
destructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
GenericSystemCall(madara::knowledge::ThreadSafeContext &context, const char *fn_name, fn_type fn)
SystemCallGeneric::fn_type fn_type
SystemCallGeneric::fn_signature fn_signature
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Returns the clock of the argument or the system clock.
GetClock(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual ~GetClock(void)
destructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Returns the wall clock time in seconds.
GetTimeSeconds(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ~GetTimeSeconds(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Returns the wall clock time.
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual ~GetTime(void)
destructor
GetTime(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Check and left and right arguments for greater than or equal to.
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual ~GreaterThanEqual(void)
destructor
GreaterThanEqual(logger::Logger &logger)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Check and left and right arguments for greater than.
virtual ~GreaterThan(void)
destructor
GreaterThan(logger::Logger &logger)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Assign the value of an expression to a variable.
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ~Implies(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Implies(logger::Logger &logger)
constructor
Check and left and right arguments for inequality.
virtual ~Inequality(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Inequality(logger::Logger &logger)
constructor
void variable_insert(madara::knowledge::ThreadSafeContext &context, const std::string &input, std::string::size_type &i, int &accumulated_precedence, ::std::list< Symbol * > &list, Symbol *&lastValidInput)
Inserts a variable into the tree.
void number_insert(madara::knowledge::ThreadSafeContext &context, const std::string &input, std::string::size_type &i, int &accumulated_precedence, ::std::list< Symbol * > &list, Symbol *&lastValidInput)
Inserts a number into the tree.
void handle_parenthesis(madara::knowledge::ThreadSafeContext &context, const std::string &input, std::string::size_type &i, Symbol *&lastValidInput, bool &handled, int &accumulated_precedence, ::std::list< Symbol * > &list, bool build_argument_list=false)
Handles a parenthesis.
void handle_array(madara::knowledge::ThreadSafeContext &context, const std::string &input, std::string::size_type &i, Symbol *&lastValidInput, bool &handled, int &accumulated_precedence, ::std::list< Symbol * > &list)
Handles a parenthesis.
void system_call_insert(madara::knowledge::ThreadSafeContext &context, const std::string &input, std::string::size_type &i, int &accumulated_precedence, ::std::list< Symbol * > &list, Symbol *&lastValidInput)
Inserts a system call into the tree.
void precedence_insert(madara::knowledge::ThreadSafeContext &context, Symbol *op, ::std::list< Symbol * > &list)
Inserts a mathematical operator into the tree.
ExpressionTree interpret(madara::knowledge::ThreadSafeContext &context, const std::string &input)
Compiles an expression into an expression tree.
void handle_for_loop(madara::knowledge::ThreadSafeContext &context, std::string &variable, const std::string &input, std::string::size_type &i, int &accumulated_precedence, ::std::list< Symbol * > &list, Symbol *&returnableInput)
extracts precondition, condition, postcondition, and body from input
void string_insert(char opener, madara::knowledge::ThreadSafeContext &context, const std::string &input, std::string::size_type &i, int &accumulated_precedence, ::std::list< Symbol * > &list, Symbol *&lastValidInput)
Inserts a variable into the tree.
virtual ~Interpreter()
Destructor.
void main_loop(madara::knowledge::ThreadSafeContext &context, const std::string &input, std::string::size_type &i, Symbol *&lastValidInput, bool &handled, int &accumulated_precedence, ::std::list< Symbol * > &list, bool build_argument_list=false)
Inserts a variable into the tree.
Returns whether the first argument is an infinite number.
virtual ~Isinf(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Isinf(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Defines a node that contains a madara::knowledge::KnowledgeRecord::Integer value.
Definition: LeafNode.h:25
Check and left and right arguments for less than or equal to.
LessThanEqual(logger::Logger &logger)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ~LessThanEqual(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Check and left and right arguments for less than.
LessThan(logger::Logger &logger)
constructor
virtual ~LessThan(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Defines a terminal node that contains a list.
Definition: ListNode.h:28
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual ~List(void)
destructor
madara::knowledge::ThreadSafeContext & context_
Context for variables.
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
List(madara::knowledge::ThreadSafeContext &context)
constructors
Reads or sets the MADARA log level.
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual ~LogLevel(void)
destructor
LogLevel(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Modulus node of the parse tree (10 % 4 == 2)
Modulus(logger::Logger &logger)
constructor
virtual ~Modulus(void)
destructorm
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Multiplication node of the parse tree.
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ~Multiply(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Multiply(logger::Logger &logger)
constructor
Negate node of the parse tree.
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Negate(logger::Logger &logger)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ~Negate(void)
destructor
Logically not the right node.
virtual ~Not(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Not(logger::Logger &logger)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Leaf node of parse tree.
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
madara::knowledge::KnowledgeRecord item_
contains the value of the leaf node
Number(logger::Logger &logger, std::string input)
constructors
virtual ~Number(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Abstract base class for all parse tree node operators.
virtual ~Operator(void)
destructor
Operator(logger::Logger &logger, Symbol *left, Symbol *right, int precedence_=1)
constructor
Logically or node of the parse tree.
Or(logger::Logger &logger)
constructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ~Or(void)
destructor
Postdecrement node of the parse tree.
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ~Postdecrement(void)
destructor
Postdecrement(logger::Logger &logger)
constructor
Postincrement node of the parse tree.
virtual ~Postincrement(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Postincrement(logger::Logger &logger)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Returns a base term taken to a power (exponent)
virtual ~Power(void)
destructor
Power(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Predecrement node of the parse tree.
virtual ~Predecrement(void)
destructor
Predecrement(logger::Logger &logger)
constructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Preincrement node of the parse tree.
virtual ~Preincrement(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Preincrement(logger::Logger &logger)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Prints a help menu for all system calls.
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual ~PrintSystemCalls(void)
destructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
PrintSystemCalls(madara::knowledge::ThreadSafeContext &context_)
constructor
Prints a Knowledge Record to the stderr.
Print(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual ~Print(void)
destructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Generates a random double.
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual ~RandDouble(void)
destructor
RandDouble(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Generates a random integer.
virtual ~RandInt(void)
destructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
RandInt(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual ~ReadFile(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
ReadFile(madara::knowledge::ThreadSafeContext &context_)
constructor
Evaluates both left and right children and returns right value.
virtual ~ReturnRight(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
ReturnRight(logger::Logger &logger)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Evaluates both left and right children, regardless of values.
Sequence(logger::Logger &logger)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual ~Sequence(void)
destructor
Sets the system or a variable clock.
SetClock(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual ~SetClock(void)
destructor
Sets the output format to std::fixed.
SetFixed(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual ~SetFixed(void)
destructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Sets the precision of doubles.
SetPrecision(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ~SetPrecision(void)
destructor
Sets the output to std::scientific.
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
SetScientific(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual ~SetScientific(void)
destructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Returns the sin of a term (radians)
Sin(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual ~Sin(void)
destructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Returns the size of a record.
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Size(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual ~Size(void)
destructor
Sleeps for a certain amount of time.
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Sleep(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual ~Sleep(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
SquareRootUnary(logger::Logger &logger)
constructor
virtual ~SquareRootUnary(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Returns the square root of a term.
SquareRoot(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual ~SquareRoot(void)
destructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Subtraction node of the parse tree.
Subtract(logger::Logger &logger)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ~Subtract(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Abstract base class of all parse tree nodes.
virtual int add_precedence(int accumulated_precedence)=0
virtual ComponentNode * build(void)=0
abstract method for building an Expression ExpressionTree Node
Symbol(logger::Logger &logger, Symbol *left, Symbol *right, int precedence_=0)
constructor
virtual ~Symbol(void)
destructor
virtual int precedence(void)
abstract method for returning precedence level (higher value means higher precedence
logger::Logger * logger_
left and right pointers
Returns the cosine of a term in radians.
Definition: SystemCallCos.h:24
Evaluates a knowledge::KnowledgeRecord and returns the evaluation result.
Returns the expansion of a statement with environment vars.
Returns a fragment of the knowledge record.
General purpose system call KaRL node.
madara::knowledge::KnowledgeRecord(std::vector< madara::knowledge::KnowledgeRecord >) fn_signature
std::function< fn_signature > fn_type
Returns the system clock or a variable clock.
Returns the current time in seconds since epoch.
Returns the time in nanoseconds since epoch.
Returns the type of a specified knowledge record.
Sets or returns the current MADARA logging level.
Calculates a base term taken to a power.
Definition: SystemCallPow.h:24
Prints a Knowledge Record.
Reads a file from an user-provided file name.
Sets the system clock or a variable clock.
Sets the output format to use std::fixed.
Sets the double precision for converting doubles to a string and for printing.
Sets the output format to use std::scientific.
Returns the sin of a term in radians.
Definition: SystemCallSin.h:24
Returns the size of a specified knowledge record.
Sleeps for a certain amount of time.
Returns the square root of a term.
Returns the tangent of a term in radians.
Definition: SystemCallTan.h:24
Converts an argument into an unsigned char buffer.
Converts an argument to a double.
Converts an argument to an array of doubles.
Ensures the directory delimiters are appropriate for the host operating system (e....
Converts an argument to an integer.
Converts an argument to an array of integers.
Converts an argument to a string.
Returns the type of a specified knowledge record.
Writes a knowledge record to an user-specified file name.
Abstract base class for operators with 3+ potential subnodes.
SystemCall(madara::knowledge::ThreadSafeContext &context_)
constructor
madara::knowledge::ThreadSafeContext & context_
Context for variables.
virtual ~SystemCall(void)
destructor
Returns the tangent of a term (radians)
virtual ~Tan(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Tan(madara::knowledge::ThreadSafeContext &context_)
constructor
Abstract base class for operators with 3+ potential subnodes.
virtual ~TernaryOperator(void)
destructor
TernaryOperator(logger::Logger &logger, Symbol *left, Symbol *right, int precedence_=1)
constructor
virtual ~ToBuffer(void)
destructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
ToBuffer(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual ~ToDouble(void)
destructor
ToDouble(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Returns a double array.
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
ToDoubles(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual ~ToDoubles(void)
destructor
Returns a version that has a directory structure appropriate to the OS.
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
ToHostDirs(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual ~ToHostDirs(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ~ToInteger(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
ToInteger(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual ~ToIntegers(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
ToIntegers(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ~ToString(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
ToString(madara::knowledge::ThreadSafeContext &context_)
constructor
Returns the type of a record.
virtual ~Type(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Type(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Abstract base class for all parse tree node operators.
virtual ~UnaryOperator(void)
destructor
UnaryOperator(logger::Logger &logger, Symbol *right, int precedence_=1)
constructor
Defines a terminal node of that references the current value stored in a variable.
Increment a variable by a certain amount.
virtual ~VariableCompare(void)
destructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
madara::knowledge::KnowledgeRecord value_
value can be faster than rhs_, so use it if possible
madara::knowledge::ThreadSafeContext & context_
Context for variables.
VariableCompare(Symbol *lhs, madara::knowledge::KnowledgeRecord value, Symbol *rhs, int compare_type, madara::knowledge::ThreadSafeContext &context)
constructors
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
int compare_type_
type of comparison. See madara/Globals.h
Symbol * rhs_
rhs is used for complex rhs types (not a simple number)
Composite node that subtracts a variable by some right hand side.
Decrement a variable by a certain amount.
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
virtual ~VariableDecrement(void)
destructor
madara::knowledge::ThreadSafeContext & context_
Context for variables.
VariableDecrement(Symbol *lhs, madara::knowledge::KnowledgeRecord value, Symbol *rhs, madara::knowledge::ThreadSafeContext &context)
constructors
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
madara::knowledge::KnowledgeRecord value_
value can be faster than rhs_, so use it if possible
Composite node that divides a variable by some right hand side.
Divide a variable by a certain amount.
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
madara::knowledge::KnowledgeRecord value_
value can be faster than rhs_, so use it if possible
virtual ~VariableDivide(void)
destructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
VariableDivide(Symbol *lhs, madara::knowledge::KnowledgeRecord value, Symbol *rhs, madara::knowledge::ThreadSafeContext &context)
constructors
madara::knowledge::ThreadSafeContext & context_
Context for variables.
Defines a terminal node of that references the current value stored in a variable.
Increment a variable by a certain amount.
VariableIncrement(Symbol *lhs, madara::knowledge::KnowledgeRecord value, Symbol *rhs, madara::knowledge::ThreadSafeContext &context)
constructors
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
madara::knowledge::ThreadSafeContext & context_
Context for variables.
virtual ~VariableIncrement(void)
destructor
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
madara::knowledge::KnowledgeRecord value_
value can be faster than rhs_, so use it if possible
Composite node that multiplies a variable by some right hand side.
Multiply a variable by a certain amount.
VariableMultiply(Symbol *lhs, madara::knowledge::KnowledgeRecord value, Symbol *rhs, madara::knowledge::ThreadSafeContext &context)
constructors
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
madara::knowledge::KnowledgeRecord value_
value can be faster than rhs_, so use it if possible
virtual ~VariableMultiply(void)
destructor
madara::knowledge::ThreadSafeContext & context_
Context for variables.
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
Defines a terminal node of that references the current value stored in a variable.
Definition: VariableNode.h:29
Leaf node of parse tree.
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
Variable(const std::string &key, madara::knowledge::ThreadSafeContext &context)
constructors
virtual ~Variable(void)
destructor
const std::string key_
Key for retrieving value of this variable.
madara::knowledge::ThreadSafeContext & context_
Context for variables.
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
WriteFile(madara::knowledge::ThreadSafeContext &context_)
constructor
virtual ~WriteFile(void)
destructor
virtual int add_precedence(int accumulated_precedence)
returns the precedence level
virtual ComponentNode * build(void)
builds an equivalent ExpressionTree node
This class encapsulates an entry in a KnowledgeBase.
std::string to_string(const std::string &delimiter=", ") const
converts the value to a string.
void set_value(const KnowledgeRecord &new_value)
Sets the value from another KnowledgeRecord, does not copy toi, clock, and write_quality.
This class stores variables and their values for use by any entity needing state information in a thr...
logger::Logger & get_logger(void) const
Gets the logger used for information printing.
A multi-threaded logger for logging to one or more destinations.
Definition: Logger.h:165
std::deque< ComponentNode * > ComponentNodes
a vector of Component Nodes
std::vector< Symbol * > Symbols
constexpr string_t str
constexpr string_t string
Provides knowledge logging services to files and terminals.
Definition: GlobalLogger.h:12
Copyright(c) 2020 Galois.