не рабочая версия

This commit is contained in:
Dmitry Borisenko
2022-08-23 13:06:01 +02:00
parent f7849894e5
commit 99e2fcfcb8
5 changed files with 808 additions and 750 deletions

View File

@@ -0,0 +1,3 @@
{
"scen": ""
}

View File

@@ -4,9 +4,9 @@
#include <map> #include <map>
class ExprAST { class ExprAST {
public: public:
virtual ~ExprAST(); virtual ~ExprAST();
virtual IoTValue* exec(); virtual IoTValue *exec();
virtual int setValue(IoTValue *val); // ret 0 - установка значения не поддерживается наследником virtual int setValue(IoTValue *val); // ret 0 - установка значения не поддерживается наследником
virtual bool hasEventIdName(String eventIdName); virtual bool hasEventIdName(String eventIdName);
}; };
@@ -60,13 +60,13 @@ class IoTScenario {
ExprAST *ParseQuotesExpr(); ExprAST *ParseQuotesExpr();
/// ifexpr ::= 'if' expression 'then' expression 'else' expression /// ifexpr ::= 'if' expression 'then' expression 'else' expression
ExprAST *ParseIfExpr(String* IDNames); ExprAST *ParseIfExpr(String *IDNames);
/// primary /// primary
/// ::= identifierexpr /// ::= identifierexpr
/// ::= numberexpr /// ::= numberexpr
/// ::= parenexpr /// ::= parenexpr
ExprAST *ParsePrimary(String* IDNames); ExprAST *ParsePrimary(String *IDNames);
/// binoprhs /// binoprhs
/// ::= ('+' primary)* /// ::= ('+' primary)*
@@ -77,7 +77,7 @@ class IoTScenario {
/// ///
ExprAST *ParseExpression(String *IDNames); ExprAST *ParseExpression(String *IDNames);
std::vector<ExprAST*> ScenarioElements; // корневые элементы дерава std::vector<ExprAST *> ScenarioElements; // корневые элементы дерава
String *strFromFile; String *strFromFile;
char getLastChar(); char getLastChar();
@@ -85,7 +85,7 @@ class IoTScenario {
void clearScenarioElements(); void clearScenarioElements();
public: public:
void loadScenario(String fileName); void loadScenario(String fileName);
void ExecScenario(String eventIdName); void ExecScenario(String eventIdName);

View File

@@ -63,7 +63,7 @@ void setup() {
asyncUdpInit(); asyncUdpInit();
//загрузка сценария //загрузка сценария
iotScen.loadScenario("/scenario.txt"); iotScen.loadScenario("/scenario.json");
// создаем событие завершения конфигурирования для возможности выполнения блока кода при загрузке // создаем событие завершения конфигурирования для возможности выполнения блока кода при загрузке
IoTItems.push_back((IoTItem *)new externalVariable("{\"id\":\"onStart\",\"val\":1,\"int\":60}")); IoTItems.push_back((IoTItem *)new externalVariable("{\"id\":\"onStart\",\"val\":1,\"int\":60}"));
generateEvent("onStart", ""); generateEvent("onStart", "");

View File

@@ -63,7 +63,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
sendFileToWs("/items.json", num, 1024); sendFileToWs("/items.json", num, 1024);
sendFileToWs("/widgets.json", num, 1024); sendFileToWs("/widgets.json", num, 1024);
sendFileToWs("/config.json", num, 1024); sendFileToWs("/config.json", num, 1024);
sendFileToWs("/scenario.txt", num, 1024); sendFileToWs("/scenario.json", num, 1024);
standWebSocket.sendTXT(num, settingsFlashJson); standWebSocket.sendTXT(num, settingsFlashJson);
} }
//**сохранение**// //**сохранение**//
@@ -73,7 +73,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
clearConfigure(); clearConfigure();
Serial.println("Start config"); Serial.println("Start config");
configure("/config.json"); configure("/config.json");
iotScen.loadScenario("/scenario.txt"); iotScen.loadScenario("/scenario.json");
} }
//**сохранение**// //**сохранение**//
if (headerStr == "/tuoyal|") { if (headerStr == "/tuoyal|") {
@@ -81,13 +81,9 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
} }
//**сохранение**// //**сохранение**//
if (headerStr == "/oiranecs|") { if (headerStr == "/oiranecs|") {
if (length - headerLenth == 0) { writeFileUint8tByFrames("scenario.json", payload, length, headerLenth, 256);
SerialPrint("i", "WS", "Scenario file empty"); iotScen.loadScenario("/scenario.json");
writeFile("/scenario.txt", "");
} else {
writeFileUint8tByFrames("scenario.txt", payload, length, headerLenth, 256);
iotScen.loadScenario("/scenario.txt");
}
// создаем событие завершения конфигурирования для возможности выполнения блока кода при загрузке // создаем событие завершения конфигурирования для возможности выполнения блока кода при загрузке
IoTItems.push_back((IoTItem*)new externalVariable("{\"id\":\"onStart\",\"val\":1,\"int\":60}")); IoTItems.push_back((IoTItem*)new externalVariable("{\"id\":\"onStart\",\"val\":1,\"int\":60}"));
generateEvent("onStart", ""); generateEvent("onStart", "");

View File

@@ -9,43 +9,49 @@
bool isIotScenException; // признак исключения и попытки прекратить выполнение сценария заранее bool isIotScenException; // признак исключения и попытки прекратить выполнение сценария заранее
// Лексический анализатор возвращает токены [0-255], если это неизвестны, // Лексический анализатор возвращает токены [0-255], если это неизвестны,
// иначе одну из известных единиц кода // иначе одну из известных единиц кода
enum Token { enum Token {
tok_eof = -1, tok_eof = -1,
// операнды (первичные выражения: идентификаторы, числа) // операнды (первичные выражения: идентификаторы, числа)
tok_identifier = -4, tok_number = -5, tok_string = -3, tok_identifier = -4,
tok_number = -5,
tok_string = -3,
// двухсимвольные операторы бинарных операций // двухсимвольные операторы бинарных операций
tok_equal = -2, tok_notequal = -9, tok_lesseq = -10, tok_greateq = -11, tok_equal = -2,
tok_notequal = -9,
tok_lesseq = -10,
tok_greateq = -11,
// управление // управление
tok_if = -6, tok_then = -7, tok_else = -8 tok_if = -6,
tok_then = -7,
tok_else = -8
}; };
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Abstract Syntax Tree (Абстрактное Синтаксическое Дерево или Дерево Парсинга) // Abstract Syntax Tree (Абстрактное Синтаксическое Дерево или Дерево Парсинга)
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// ExprAST - Базовый класс для всех узлов выражений. /// ExprAST - Базовый класс для всех узлов выражений.
ExprAST::~ExprAST() {} ExprAST::~ExprAST() {}
IoTValue* ExprAST::exec() {return nullptr;} IoTValue *ExprAST::exec() { return nullptr; }
int ExprAST::setValue(IoTValue *val) {return 0;} // 0 - установка значения не поддерживается наследником int ExprAST::setValue(IoTValue *val) { return 0; } // 0 - установка значения не поддерживается наследником
bool ExprAST::hasEventIdName(String eventIdName) {return false;} // по умолчанию все узлы не связаны с ИД события, для которого выполняется сценарий bool ExprAST::hasEventIdName(String eventIdName) { return false; } // по умолчанию все узлы не связаны с ИД события, для которого выполняется сценарий
//struct IoTValue zeroIotVal; // struct IoTValue zeroIotVal;
/// NumberExprAST - Класс узла выражения для числовых литералов (Например, "1.0"). /// NumberExprAST - Класс узла выражения для числовых литералов (Например, "1.0").
class NumberExprAST : public ExprAST { class NumberExprAST : public ExprAST {
IoTValue Val; IoTValue Val;
public:
NumberExprAST(float val) { Val.valD = val;}
IoTValue* exec() { public:
NumberExprAST(float val) { Val.valD = val; }
IoTValue *exec() {
if (isIotScenException) return nullptr; if (isIotScenException) return nullptr;
//Serial.printf("Call from NumberExprAST: %f\n", Val.valD); // Serial.printf("Call from NumberExprAST: %f\n", Val.valD);
return &Val; return &Val;
} }
}; };
@@ -53,12 +59,16 @@ public:
/// StringExprAST - Класс узла выражения для строковых литералов (Например, "Example with spaces and quotes"). /// StringExprAST - Класс узла выражения для строковых литералов (Например, "Example with spaces and quotes").
class StringExprAST : public ExprAST { class StringExprAST : public ExprAST {
IoTValue Val; IoTValue Val;
public:
StringExprAST(String val) { Val.isDecimal = false; Val.valS = val;}
IoTValue* exec() { public:
StringExprAST(String val) {
Val.isDecimal = false;
Val.valS = val;
}
IoTValue *exec() {
if (isIotScenException) return nullptr; if (isIotScenException) return nullptr;
//Serial.printf("Call from StringExprAST: %s\n", Val.valS.c_str()); // Serial.printf("Call from StringExprAST: %s\n", Val.valS.c_str());
return &Val; return &Val;
} }
}; };
@@ -66,29 +76,31 @@ public:
/// VariableExprAST - Класс узла выражения для переменных (например, "a"). /// VariableExprAST - Класс узла выражения для переменных (например, "a").
class VariableExprAST : public ExprAST { class VariableExprAST : public ExprAST {
String Name; String Name;
IoTItem* Item; // ссылка на объект модуля (прямой доступ к идентификатору указанному в сценарии), если получилось найти модуль по ID IoTItem *Item; // ссылка на объект модуля (прямой доступ к идентификатору указанному в сценарии), если получилось найти модуль по ID
bool ItemIsLocal = false; bool ItemIsLocal = false;
public: public:
VariableExprAST(const String &name, IoTItem* item) : Name(name), Item(item) { VariableExprAST(const String &name, IoTItem *item) : Name(name), Item(item) {
if (item) ItemIsLocal = item->iAmLocal; if (item) ItemIsLocal = item->iAmLocal;
} }
int setValue(IoTValue *val) { int setValue(IoTValue *val) {
if (!ItemIsLocal) Item = findIoTItem(Name); if (!ItemIsLocal) Item = findIoTItem(Name);
if (Item) Item->setValue(*val); if (Item)
else return 0; Item->setValue(*val);
else
return 0;
return 1; return 1;
} }
IoTValue* exec() { IoTValue *exec() {
if (isIotScenException) return nullptr; if (isIotScenException) return nullptr;
if (!ItemIsLocal) Item = findIoTItem(Name); if (!ItemIsLocal) Item = findIoTItem(Name);
if (Item) { if (Item) {
//if (Item->value.isDecimal) // if (Item->value.isDecimal)
// Serial.printf("Call from VariableExprAST: %s = %f\n", Name.c_str(), Item->value.valD); // Serial.printf("Call from VariableExprAST: %s = %f\n", Name.c_str(), Item->value.valD);
//else Serial.printf("Call from VariableExprAST: %s = %s\n", Name.c_str(), Item->value.valS.c_str()); // else Serial.printf("Call from VariableExprAST: %s = %s\n", Name.c_str(), Item->value.valS.c_str());
return &(Item->value); return &(Item->value);
} }
@@ -103,39 +115,44 @@ class BinaryExprAST : public ExprAST {
IoTValue val; IoTValue val;
String lhsStr, rhsStr; String lhsStr, rhsStr;
public: public:
BinaryExprAST(signed char op, ExprAST *lhs, ExprAST *rhs) BinaryExprAST(signed char op, ExprAST *lhs, ExprAST *rhs)
: Op(op), LHS(lhs), RHS(rhs) {} : Op(op), LHS(lhs), RHS(rhs) {}
~BinaryExprAST() { ~BinaryExprAST() {
if (LHS) delete LHS; if (LHS) delete LHS;
if (RHS) delete RHS; if (RHS) delete RHS;
//Serial.printf("Call from BinaryExprAST delete\n"); // Serial.printf("Call from BinaryExprAST delete\n");
} }
IoTValue* exec(){ IoTValue *exec() {
if (isIotScenException) return nullptr; if (isIotScenException) return nullptr;
String printStr = ""; String printStr = "";
if (Op == tok_equal) printStr = "=="; if (Op == tok_equal)
else if (Op == tok_notequal) printStr = "!="; printStr = "==";
else if (Op == tok_lesseq) printStr = "<="; else if (Op == tok_notequal)
else if (Op == tok_greateq) printStr = ">="; printStr = "!=";
else printStr = printStr + (char)Op; else if (Op == tok_lesseq)
printStr = "<=";
else if (Op == tok_greateq)
printStr = ">=";
else
printStr = printStr + (char)Op;
//Serial.printf("Call from BinaryExprAST: %s\n", printStr.c_str()); // Serial.printf("Call from BinaryExprAST: %s\n", printStr.c_str());
if (RHS == nullptr || LHS == nullptr) return nullptr; if (RHS == nullptr || LHS == nullptr) return nullptr;
IoTValue* rhs = RHS->exec(); // получаем значение правого операнда для возможного использования в операции присваивания IoTValue *rhs = RHS->exec(); // получаем значение правого операнда для возможного использования в операции присваивания
if (Op == '=' && LHS->setValue(rhs)) { // если установка значения не поддерживается, т.е. слева не переменная, то работаем по другим комбинациям далее if (Op == '=' && LHS->setValue(rhs)) { // если установка значения не поддерживается, т.е. слева не переменная, то работаем по другим комбинациям далее
return rhs; // иначе возвращаем присвоенное значение справа return rhs; // иначе возвращаем присвоенное значение справа
} }
IoTValue* lhs = LHS->exec(); // если присваивания не произошло, значит операция иная и необходимо значение левого операнда IoTValue *lhs = LHS->exec(); // если присваивания не произошло, значит операция иная и необходимо значение левого операнда
if (lhs != nullptr && rhs !=nullptr) { if (lhs != nullptr && rhs != nullptr) {
if (lhs->isDecimal && rhs->isDecimal) { if (lhs->isDecimal && rhs->isDecimal) {
switch (Op) { switch (Op) {
case '>': case '>':
@@ -167,8 +184,10 @@ public:
val.valD = lhs->valD * rhs->valD; val.valD = lhs->valD * rhs->valD;
break; break;
case '/': case '/':
if (rhs->valD != 0) val.valD = lhs->valD / rhs->valD; if (rhs->valD != 0)
else val.valD = 3.4E+38; val.valD = lhs->valD / rhs->valD;
else
val.valD = 3.4E+38;
break; break;
case '|': case '|':
@@ -185,8 +204,14 @@ public:
} }
if (!lhs->isDecimal || !rhs->isDecimal) { if (!lhs->isDecimal || !rhs->isDecimal) {
if (lhs->isDecimal) lhsStr = lhs->valD; else lhsStr = lhs->valS; if (lhs->isDecimal)
if (rhs->isDecimal) rhsStr = rhs->valD; else rhsStr = rhs->valS; lhsStr = lhs->valD;
else
lhsStr = lhs->valS;
if (rhs->isDecimal)
rhsStr = rhs->valD;
else
rhsStr = rhs->valS;
switch (Op) { switch (Op) {
case tok_equal: case tok_equal:
val.valD = compStr(lhsStr, rhsStr); val.valD = compStr(lhsStr, rhsStr);
@@ -207,40 +232,41 @@ public:
return &val; return &val;
} }
bool compStr(String str1, String str2){ bool compStr(String str1, String str2) {
if (str1.length() != str2.length()) return false; if (str1.length() != str2.length()) return false;
for (int i = 0; i < str1.length(); i++) { for (int i = 0; i < str1.length(); i++) {
if (str1[i] == '*' || str2[i] == '*') continue; //считаем, что если есть подстановочная звезда, то символы равны if (str1[i] == '*' || str2[i] == '*') continue; //считаем, что если есть подстановочная звезда, то символы равны
if (str1[i] != str2[i]) return false; if (str1[i] != str2[i]) return false;
} }
return true;//str1 == str2; return true; // str1 == str2;
} }
}; };
/// CallExprAST - Класс узла выражения для вызова команды. /// CallExprAST - Класс узла выражения для вызова команды.
class CallExprAST : public ExprAST { class CallExprAST : public ExprAST {
String Callee; String Callee;
String Cmd; String Cmd;
std::vector<ExprAST*> Args; std::vector<ExprAST *> Args;
IoTItem *Item; // ссылка на объект модуля (прямой доступ к идентификатору указанному в сценарии), если получилось найти модуль по ID IoTItem *Item; // ссылка на объект модуля (прямой доступ к идентификатору указанному в сценарии), если получилось найти модуль по ID
IoTValue ret; // хранение возвращаемого значения, т.к. возврат по ссылке осуществляется IoTValue ret; // хранение возвращаемого значения, т.к. возврат по ссылке осуществляется
bool ItemIsLocal = false; bool ItemIsLocal = false;
public: public:
CallExprAST(const String &callee, String &cmd, std::vector<ExprAST*> &args, IoTItem *item) CallExprAST(const String &callee, String &cmd, std::vector<ExprAST *> &args, IoTItem *item)
: Callee(callee), Cmd(cmd), Args(args), Item(item) { : Callee(callee), Cmd(cmd), Args(args), Item(item) {
if (item) ItemIsLocal = item->iAmLocal; if (item) ItemIsLocal = item->iAmLocal;
} }
IoTValue* exec() { IoTValue *exec() {
if (isIotScenException) return nullptr; // если прерывание, то сразу выходим if (isIotScenException) return nullptr; // если прерывание, то сразу выходим
if (Cmd == "exit" || Callee == "exit") { // если системная команда, то выполняем и выходим if (Cmd == "exit" || Callee == "exit") { // если системная команда, то выполняем и выходим
IoTValue* tmp; IoTValue *tmp;
if (Args.size() > 0 && Args[0]) tmp = Args[0]->exec(); if (Args.size() > 0 && Args[0])
else SerialPrint("i", "SysExt", "Exit"); tmp = Args[0]->exec();
else
SerialPrint("i", "SysExt", "Exit");
if (tmp) SerialPrint("i", "SysExt", "Exit = '" + tmp->valS + "'"); if (tmp) SerialPrint("i", "SysExt", "Exit = '" + tmp->valS + "'");
isIotScenException = true; isIotScenException = true;
@@ -248,21 +274,23 @@ public:
} }
if (!ItemIsLocal) Item = findIoTItem(Callee); // пробуем найти переменную если она не локальная (могла придти по сети в процессе) if (!ItemIsLocal) Item = findIoTItem(Callee); // пробуем найти переменную если она не локальная (могла придти по сети в процессе)
if (!Item) return nullptr; //ret = zeroIotVal; // если все же не пришла, то либо опечатка, либо уже стерлась - выходим if (!Item) return nullptr; // ret = zeroIotVal; // если все же не пришла, то либо опечатка, либо уже стерлась - выходим
// если все же все ок, то готовим параметры для передачи в модуль // если все же все ок, то готовим параметры для передачи в модуль
std::vector<IoTValue> ArgsAsIoTValue; std::vector<IoTValue> ArgsAsIoTValue;
for (unsigned int i = 0; i < Args.size(); i++) { for (unsigned int i = 0; i < Args.size(); i++) {
if (Args[i] == nullptr) return nullptr; if (Args[i] == nullptr) return nullptr;
IoTValue *tmp = Args[i]->exec(); IoTValue *tmp = Args[i]->exec();
if (tmp != nullptr) ArgsAsIoTValue.push_back(*tmp); if (tmp != nullptr)
else return nullptr; //ArgsAsIoTValue.push_back(zeroIotVal); ArgsAsIoTValue.push_back(*tmp);
else
return nullptr; // ArgsAsIoTValue.push_back(zeroIotVal);
} }
ret = Item->execute(Cmd, ArgsAsIoTValue); // вызываем команду из модуля напрямую с передачей всех аргументов ret = Item->execute(Cmd, ArgsAsIoTValue); // вызываем команду из модуля напрямую с передачей всех аргументов
//if (ret.isDecimal) Serial.printf("Call from CallExprAST ID = %s, Command = %s, exec result = %f\n", Callee.c_str(), Cmd.c_str(), ret.valD); // if (ret.isDecimal) Serial.printf("Call from CallExprAST ID = %s, Command = %s, exec result = %f\n", Callee.c_str(), Cmd.c_str(), ret.valD);
//else Serial.printf("Call from CallExprAST ID = %s, Command = %s, exec result = %s\n", Callee.c_str(), Cmd.c_str(), ret.valS.c_str()); // else Serial.printf("Call from CallExprAST ID = %s, Command = %s, exec result = %s\n", Callee.c_str(), Cmd.c_str(), ret.valS.c_str());
return &ret; return &ret;
} }
@@ -271,11 +299,10 @@ public:
if (Args[i]) delete Args[i]; if (Args[i]) delete Args[i];
} }
Args.clear(); Args.clear();
//Serial.printf("Call from CallExprAST delete\n"); // Serial.printf("Call from CallExprAST delete\n");
} }
}; };
// Для сокращения количества преобразований используем числовые коды для фиксации названия системной функции, // Для сокращения количества преобразований используем числовые коды для фиксации названия системной функции,
// которые поддерживает прошивка // которые поддерживает прошивка
enum SysOp { enum SysOp {
@@ -298,7 +325,7 @@ enum SysOp {
sysop_mqttPub sysop_mqttPub
}; };
IoTValue sysExecute(SysOp command, std::vector<IoTValue>& param) { IoTValue sysExecute(SysOp command, std::vector<IoTValue> &param) {
IoTValue value = {}; IoTValue value = {};
if (_time_isTrust) if (_time_isTrust)
@@ -382,7 +409,7 @@ IoTValue sysExecute(SysOp command, std::vector<IoTValue>& param) {
break; break;
case sysop_mqttPub: case sysop_mqttPub:
if (param.size() == 2) { if (param.size() == 2) {
//Serial.printf("Call from sysExecute %s %s\n", param[0].valS.c_str(), param[1].valS.c_str()); // Serial.printf("Call from sysExecute %s %s\n", param[0].valS.c_str(), param[1].valS.c_str());
value.valD = mqtt.publish(param[0].valS.c_str(), param[1].valS.c_str(), false); value.valD = mqtt.publish(param[0].valS.c_str(), param[1].valS.c_str(), false);
} }
break; break;
@@ -394,35 +421,53 @@ IoTValue sysExecute(SysOp command, std::vector<IoTValue>& param) {
/// SysCallExprAST - Класс узла выражения для вызова системных команд. /// SysCallExprAST - Класс узла выражения для вызова системных команд.
class SysCallExprAST : public ExprAST { class SysCallExprAST : public ExprAST {
String Callee; String Callee;
std::vector<ExprAST*> Args; std::vector<ExprAST *> Args;
IoTValue ret; // хранение возвращаемого значения, т.к. возврат по ссылке осуществляется IoTValue ret; // хранение возвращаемого значения, т.к. возврат по ссылке осуществляется
//bool ItemIsLocal = false; // bool ItemIsLocal = false;
SysOp operation; SysOp operation;
public: public:
SysCallExprAST(const String &callee, std::vector<ExprAST*> &args) SysCallExprAST(const String &callee, std::vector<ExprAST *> &args)
: Callee(callee), Args(args) { : Callee(callee), Args(args) {
if (Callee == "reboot") operation = sysop_reboot; else if (Callee == "reboot")
if (Callee == "digitalRead") operation = sysop_digitalRead; else operation = sysop_reboot;
if (Callee == "analogRead") operation = sysop_analogRead; else else if (Callee == "digitalRead")
if (Callee == "digitalWrite") operation = sysop_digitalWrite; else operation = sysop_digitalRead;
if (Callee == "digitalInvert") operation = sysop_digitalInvert; else else if (Callee == "analogRead")
if (Callee == "deepSleep") operation = sysop_deepSleep; else operation = sysop_analogRead;
if (Callee == "getTime") operation = sysop_getTime; else else if (Callee == "digitalWrite")
if (Callee == "getHours") operation = sysop_getHours; else operation = sysop_digitalWrite;
if (Callee == "getMinutes") operation = sysop_getMinutes; else else if (Callee == "digitalInvert")
if (Callee == "getSeconds") operation = sysop_getSeconds; else operation = sysop_digitalInvert;
if (Callee == "getMonth") operation = sysop_getMonth; else else if (Callee == "deepSleep")
if (Callee == "getDay") operation = sysop_getDay; else operation = sysop_deepSleep;
if (Callee == "getIP") operation = sysop_getIP; else else if (Callee == "getTime")
if (Callee == "mqttPub") operation = sysop_mqttPub; else operation = sysop_getTime;
if (Callee == "gethhmm") operation = sysop_gethhmm; else else if (Callee == "getHours")
if (Callee == "gethhmmss") operation = sysop_gethhmmss; else operation = sysop_getHours;
if (Callee == "getTime") operation = sysop_getTime; else else if (Callee == "getMinutes")
operation = sysop_getMinutes;
else if (Callee == "getSeconds")
operation = sysop_getSeconds;
else if (Callee == "getMonth")
operation = sysop_getMonth;
else if (Callee == "getDay")
operation = sysop_getDay;
else if (Callee == "getIP")
operation = sysop_getIP;
else if (Callee == "mqttPub")
operation = sysop_mqttPub;
else if (Callee == "gethhmm")
operation = sysop_gethhmm;
else if (Callee == "gethhmmss")
operation = sysop_gethhmmss;
else if (Callee == "getTime")
operation = sysop_getTime;
else
operation = sysop_notfound; operation = sysop_notfound;
} }
IoTValue* exec() { IoTValue *exec() {
Serial.printf("Call from SysCallExprAST exec %d\n", operation); Serial.printf("Call from SysCallExprAST exec %d\n", operation);
if (isIotScenException) return nullptr; // если прерывание, то сразу выходим if (isIotScenException) return nullptr; // если прерывание, то сразу выходим
@@ -432,8 +477,10 @@ public:
for (unsigned int i = 0; i < Args.size(); i++) { for (unsigned int i = 0; i < Args.size(); i++) {
if (Args[i] == nullptr) return nullptr; if (Args[i] == nullptr) return nullptr;
IoTValue *tmp = Args[i]->exec(); IoTValue *tmp = Args[i]->exec();
if (tmp != nullptr) ArgsAsIoTValue.push_back(*tmp); if (tmp != nullptr)
else return nullptr; ArgsAsIoTValue.push_back(*tmp);
else
return nullptr;
} }
ret = sysExecute(operation, ArgsAsIoTValue); // вызываем функцию интерпретатор с передачей всех аргументов ret = sysExecute(operation, ArgsAsIoTValue); // вызываем функцию интерпретатор с передачей всех аргументов
@@ -446,7 +493,7 @@ public:
if (Args[i]) delete Args[i]; if (Args[i]) delete Args[i];
} }
Args.clear(); Args.clear();
//Serial.printf("Call from CallExprAST delete\n"); // Serial.printf("Call from CallExprAST delete\n");
} }
}; };
@@ -455,20 +502,21 @@ class IfExprAST : public ExprAST {
ExprAST *Cond, *Then, *Else; ExprAST *Cond, *Then, *Else;
String _IDNames; String _IDNames;
public: public:
IfExprAST(ExprAST *cond, ExprAST *then, ExprAST *_else, String *IDNames) IfExprAST(ExprAST *cond, ExprAST *then, ExprAST *_else, String *IDNames)
: Cond(cond), Then(then), Else(_else) { : Cond(cond), Then(then), Else(_else) {
if (IDNames) { if (IDNames) {
_IDNames = *IDNames; _IDNames = *IDNames;
} else _IDNames = ""; } else
_IDNames = "";
} }
bool hasEventIdName(String eventIdName) { bool hasEventIdName(String eventIdName) {
//Serial.printf("Call from BinaryExprAST _IDNames:%s\n", _IDNames.c_str()); // Serial.printf("Call from BinaryExprAST _IDNames:%s\n", _IDNames.c_str());
return _IDNames.indexOf(" " + eventIdName + " ") >= 0; // определяем встречался ли ИД, для которого исполняем сценарий в выражении IF return _IDNames.indexOf(" " + eventIdName + " ") >= 0; // определяем встречался ли ИД, для которого исполняем сценарий в выражении IF
} }
IoTValue* exec() { IoTValue *exec() {
if (isIotScenException) return nullptr; if (isIotScenException) return nullptr;
IoTValue *res_ret = nullptr; IoTValue *res_ret = nullptr;
IoTValue *cond_ret = nullptr; IoTValue *cond_ret = nullptr;
@@ -476,7 +524,7 @@ public:
if (Cond) cond_ret = Cond->exec(); if (Cond) cond_ret = Cond->exec();
if (!cond_ret) { if (!cond_ret) {
//Serial.printf("Call from IfExprAST: Skip If\n"); // Serial.printf("Call from IfExprAST: Skip If\n");
return nullptr; //&zeroIotVal; return nullptr; //&zeroIotVal;
} }
@@ -488,9 +536,9 @@ public:
res_ret = Else->exec(); res_ret = Else->exec();
} }
//if (!res_ret) Serial.printf("Call from IfExprAST: Cond result = %f, no body result\n", cond_ret->valD); // if (!res_ret) Serial.printf("Call from IfExprAST: Cond result = %f, no body result\n", cond_ret->valD);
//else if (res_ret->isDecimal) Serial.printf("Call from IfExprAST: Cond result = %f, result = %f\n", cond_ret->valD, res_ret->valD); // else if (res_ret->isDecimal) Serial.printf("Call from IfExprAST: Cond result = %f, result = %f\n", cond_ret->valD, res_ret->valD);
//else Serial.printf("Call from IfExprAST: Cond result = %f, result = %s\n", cond_ret->valD, res_ret->valS.c_str()); // else Serial.printf("Call from IfExprAST: Cond result = %f, result = %s\n", cond_ret->valD, res_ret->valS.c_str());
Serial.printf("\n"); Serial.printf("\n");
return cond_ret; return cond_ret;
} }
@@ -499,23 +547,23 @@ public:
if (Cond) delete Cond; if (Cond) delete Cond;
if (Then) delete Then; if (Then) delete Then;
if (Else) delete Else; if (Else) delete Else;
//Serial.printf("Call from IfExprAST delete\n"); // Serial.printf("Call from IfExprAST delete\n");
} }
}; };
/// BracketsExprAST - Класс узла блока кода {}. /// BracketsExprAST - Класс узла блока кода {}.
class BracketsExprAST : public ExprAST { class BracketsExprAST : public ExprAST {
std::vector<ExprAST*> BracketsList; std::vector<ExprAST *> BracketsList;
public: public:
BracketsExprAST(std::vector<ExprAST*> &bracketsList) BracketsExprAST(std::vector<ExprAST *> &bracketsList)
: BracketsList(bracketsList) {} : BracketsList(bracketsList) {}
IoTValue* exec() { IoTValue *exec() {
if (isIotScenException) return nullptr; if (isIotScenException) return nullptr;
//Serial.printf("Call from BracketsExprAST OperCount = %d \n", BracketsList.size()); // Serial.printf("Call from BracketsExprAST OperCount = %d \n", BracketsList.size());
IoTValue* lastExecValue = nullptr; IoTValue *lastExecValue = nullptr;
for (unsigned int i = 0; i < BracketsList.size(); i++) { for (unsigned int i = 0; i < BracketsList.size(); i++) {
if (BracketsList[i] == nullptr) return nullptr; if (BracketsList[i] == nullptr) return nullptr;
lastExecValue = BracketsList[i]->exec(); lastExecValue = BracketsList[i]->exec();
@@ -530,35 +578,32 @@ public:
} }
BracketsList.clear(); BracketsList.clear();
//Serial.printf("Call from BracketsExprAST delete\n"); // Serial.printf("Call from BracketsExprAST delete\n");
} }
}; };
//===----------------------------------------------------------------------===//
// Lexer (Лексический анализатор)
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===// char IoTScenario::getLastChar() {
// Lexer (Лексический анализатор)
//===----------------------------------------------------------------------===//
char IoTScenario::getLastChar() {
strIterator++; strIterator++;
return strFromFile->charAt(strIterator - 1); return strFromFile->charAt(strIterator - 1);
} }
/// gettok - Возвращает следующий токен из стандартного потока ввода.
int IoTScenario::gettok() {
/// gettok - Возвращает следующий токен из стандартного потока ввода.
int IoTScenario::gettok() {
// Пропускаем пробелы. // Пропускаем пробелы.
while (isspace(LastChar)) while (isspace(LastChar))
LastChar = getLastChar(); LastChar = getLastChar();
if (isalpha(LastChar) || LastChar == '_') { // идентификатор: [a-zA-Z][a-zA-Z0-9]* if (isalpha(LastChar) || LastChar == '_') { // идентификатор: [a-zA-Z][a-zA-Z0-9]*
IdentifierStr = LastChar; IdentifierStr = LastChar;
while (isalnum((LastChar = getLastChar())) || LastChar == '_'){ while (isalnum((LastChar = getLastChar())) || LastChar == '_') {
IdentifierStr += LastChar; IdentifierStr += LastChar;
} }
//Serial.printf("%s ", IdentifierStr.c_str()); // Serial.printf("%s ", IdentifierStr.c_str());
if (IdentifierStr == "if") return tok_if; if (IdentifierStr == "if") return tok_if;
if (IdentifierStr == "then") return tok_then; if (IdentifierStr == "then") return tok_then;
@@ -599,7 +644,7 @@ public:
} }
// Проверка конца файла. // Проверка конца файла.
//if (LastChar == EOF) // if (LastChar == EOF)
// return tok_eof; // return tok_eof;
if (LastChar == '=') { if (LastChar == '=') {
@@ -607,7 +652,8 @@ public:
if (LastChar == '=') { if (LastChar == '=') {
LastChar = getLastChar(); LastChar = getLastChar();
return tok_equal; return tok_equal;
} else return '='; } else
return '=';
} }
if (LastChar == '!') { if (LastChar == '!') {
@@ -615,7 +661,8 @@ public:
if (LastChar == '=') { if (LastChar == '=') {
LastChar = getLastChar(); LastChar = getLastChar();
return tok_notequal; return tok_notequal;
} else return '!'; } else
return '!';
} }
if (LastChar == '<') { if (LastChar == '<') {
@@ -623,7 +670,8 @@ public:
if (LastChar == '=') { if (LastChar == '=') {
LastChar = getLastChar(); LastChar = getLastChar();
return tok_lesseq; return tok_lesseq;
} else return '<'; } else
return '<';
} }
if (LastChar == '>') { if (LastChar == '>') {
@@ -631,30 +679,29 @@ public:
if (LastChar == '=') { if (LastChar == '=') {
LastChar = getLastChar(); LastChar = getLastChar();
return tok_greateq; return tok_greateq;
} else return '>'; } else
return '>';
} }
// В противном случае просто возвращаем символ как значение ASCII // В противном случае просто возвращаем символ как значение ASCII
int ThisChar = LastChar; int ThisChar = LastChar;
LastChar = getLastChar(); LastChar = getLastChar();
return ThisChar; return ThisChar;
} }
//===----------------------------------------------------------------------===//
// Parser (Парсер или Синтаксический Анализатор)
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===// /// CurTok/getNextToken - Предоставляет простой буфер токенов. CurTok - это текущий
// Parser (Парсер или Синтаксический Анализатор) /// токен, просматриваемый парсером. getNextToken получает следующий токен от
//===----------------------------------------------------------------------===// /// лексического анализатора и обновляет CurTok.
int IoTScenario::getNextToken() {
/// CurTok/getNextToken - Предоставляет простой буфер токенов. CurTok - это текущий
/// токен, просматриваемый парсером. getNextToken получает следующий токен от
/// лексического анализатора и обновляет CurTok.
int IoTScenario::getNextToken() {
return CurTok = gettok(); return CurTok = gettok();
} }
/// GetTokPrecedence - Возвращает приоритет текущего бинарного оператора. /// GetTokPrecedence - Возвращает приоритет текущего бинарного оператора.
int IoTScenario::GetTokPrecedence() { int IoTScenario::GetTokPrecedence() {
if (!(isascii(CurTok) || BinopPrecedence.count(CurTok))) if (!(isascii(CurTok) || BinopPrecedence.count(CurTok)))
return -1; return -1;
@@ -662,19 +709,21 @@ public:
int TokPrec = BinopPrecedence[CurTok]; int TokPrec = BinopPrecedence[CurTok];
if (TokPrec <= 0) return -1; if (TokPrec <= 0) return -1;
return TokPrec; return TokPrec;
} }
/// Error* - Это небольшие вспомогательные функции для обработки ошибок. /// Error* - Это небольшие вспомогательные функции для обработки ошибок.
ExprAST* IoTScenario::Error(const char *Str) { Serial.printf("Error: %s\n", Str); return nullptr;} ExprAST *IoTScenario::Error(const char *Str) {
Serial.printf("Error: %s\n", Str);
return nullptr;
}
/// identifierexpr
/// identifierexpr /// ::= identifier
/// ::= identifier /// ::= identifier '(' expression* ')'
/// ::= identifier '(' expression* ')' ExprAST *IoTScenario::ParseIdentifierExpr(String *IDNames) {
ExprAST* IoTScenario::ParseIdentifierExpr(String *IDNames) {
String IdName = IdentifierStr; String IdName = IdentifierStr;
String Cmd = ""; String Cmd = "";
IoTItem* tmpItem = findIoTItem(IdName); IoTItem *tmpItem = findIoTItem(IdName);
getNextToken(); // получаем идентификатор. getNextToken(); // получаем идентификатор.
@@ -694,7 +743,7 @@ public:
// Вызов функции. // Вызов функции.
getNextToken(); // получаем ( getNextToken(); // получаем (
std::vector<ExprAST*> Args; std::vector<ExprAST *> Args;
if (CurTok != ')') { if (CurTok != ')') {
while (1) { while (1) {
ExprAST *Arg = ParseExpression(IDNames); ExprAST *Arg = ParseExpression(IDNames);
@@ -716,18 +765,17 @@ public:
return new SysCallExprAST(IdName, Args); // создаем объект запуска системной функции return new SysCallExprAST(IdName, Args); // создаем объект запуска системной функции
else else
return new CallExprAST(IdName, Cmd, Args, tmpItem); // создаем объект запуска функции в любом случае даж если не нашли Item return new CallExprAST(IdName, Cmd, Args, tmpItem); // создаем объект запуска функции в любом случае даж если не нашли Item
}
} /// numberexpr ::= number
ExprAST *IoTScenario::ParseNumberExpr() {
/// numberexpr ::= number
ExprAST* IoTScenario::ParseNumberExpr() {
ExprAST *Result = new NumberExprAST(NumVal); ExprAST *Result = new NumberExprAST(NumVal);
getNextToken(); // получаем число getNextToken(); // получаем число
return Result; return Result;
} }
/// parenexpr ::= '(' expression ')' /// parenexpr ::= '(' expression ')'
ExprAST* IoTScenario::ParseParenExpr() { ExprAST *IoTScenario::ParseParenExpr() {
getNextToken(); // получаем (. getNextToken(); // получаем (.
ExprAST *V = ParseExpression(nullptr); ExprAST *V = ParseExpression(nullptr);
if (!V) return 0; if (!V) return 0;
@@ -736,12 +784,12 @@ public:
return Error("expected ')'"); return Error("expected ')'");
getNextToken(); // получаем ). getNextToken(); // получаем ).
return V; return V;
} }
/// bracketsexpr ::= '{' expression '}' /// bracketsexpr ::= '{' expression '}'
ExprAST* IoTScenario::ParseBracketsExpr() { ExprAST *IoTScenario::ParseBracketsExpr() {
getNextToken(); // получаем {. getNextToken(); // получаем {.
std::vector<ExprAST*> bracketsList; std::vector<ExprAST *> bracketsList;
if (CurTok != '}') { if (CurTok != '}') {
while (1) { while (1) {
ExprAST *Expr = ParseExpression(nullptr); ExprAST *Expr = ParseExpression(nullptr);
@@ -751,28 +799,29 @@ public:
if (CurTok != ';') if (CurTok != ';')
return Error("Expected ';' in operation list"); return Error("Expected ';' in operation list");
int ttok = getNextToken(); int ttok = getNextToken();
if (!ttok) { Error("Expected '}'"); break; } if (!ttok) {
Error("Expected '}'");
break;
}
if (CurTok == '}') break; if (CurTok == '}') break;
} }
} }
getNextToken(); // получаем }. getNextToken(); // получаем }.
return new BracketsExprAST(bracketsList); return new BracketsExprAST(bracketsList);
} }
/// quotesexpr ::= '"' expression '"' /// quotesexpr ::= '"' expression '"'
ExprAST* IoTScenario::ParseQuotesExpr() { ExprAST *IoTScenario::ParseQuotesExpr() {
String StringCont = IdentifierStr; String StringCont = IdentifierStr;
ExprAST *Result = new StringExprAST(StringCont); ExprAST *Result = new StringExprAST(StringCont);
getNextToken(); // получаем число getNextToken(); // получаем число
return Result; return Result;
} }
/// ifexpr ::= 'if' expression 'then' expression 'else' expression /// ifexpr ::= 'if' expression 'then' expression 'else' expression
ExprAST* IoTScenario::ParseIfExpr(String *IDNames) { ExprAST *IoTScenario::ParseIfExpr(String *IDNames) {
getNextToken(); // Получаем if. getNextToken(); // Получаем if.
// условие. // условие.
@@ -786,7 +835,7 @@ public:
ExprAST *Then = ParseExpression(nullptr); ExprAST *Then = ParseExpression(nullptr);
if (!Then) return 0; if (!Then) return 0;
//if (CurTok != tok_else) // if (CurTok != tok_else)
// return Error("expected else"); // return Error("expected else");
ExprAST *Else = nullptr; ExprAST *Else = nullptr;
if (CurTok == tok_else) { if (CurTok == tok_else) {
@@ -795,15 +844,16 @@ public:
} }
return new IfExprAST(Cond, Then, Else, IDNames); return new IfExprAST(Cond, Then, Else, IDNames);
} }
/// primary /// primary
/// ::= identifierexpr /// ::= identifierexpr
/// ::= numberexpr /// ::= numberexpr
/// ::= parenexpr /// ::= parenexpr
ExprAST* IoTScenario::ParsePrimary(String* IDNames) { ExprAST *IoTScenario::ParsePrimary(String *IDNames) {
switch (CurTok) { switch (CurTok) {
default: return Error("unknown token when expecting an expression"); default:
return Error("unknown token when expecting an expression");
case tok_identifier: { case tok_identifier: {
if (IDNames) { if (IDNames) {
String tmpstr = *IDNames; String tmpstr = *IDNames;
@@ -811,17 +861,22 @@ public:
} }
return ParseIdentifierExpr(IDNames); return ParseIdentifierExpr(IDNames);
} }
case tok_number: return ParseNumberExpr(); case tok_number:
case '(': return ParseParenExpr(); return ParseNumberExpr();
case '{': return ParseBracketsExpr(); case '(':
case tok_string: return ParseQuotesExpr(); return ParseParenExpr();
case tok_if: return ParseIfExpr(IDNames); case '{':
} return ParseBracketsExpr();
case tok_string:
return ParseQuotesExpr();
case tok_if:
return ParseIfExpr(IDNames);
} }
}
/// binoprhs /// binoprhs
/// ::= ('+' primary)* /// ::= ('+' primary)*
ExprAST* IoTScenario::ParseBinOpRHS(int ExprPrec, ExprAST *LHS, String *IDNames) { ExprAST *IoTScenario::ParseBinOpRHS(int ExprPrec, ExprAST *LHS, String *IDNames) {
// Если это бинарный оператор, получаем его приоритет // Если это бинарный оператор, получаем его приоритет
while (1) { while (1) {
int TokPrec = GetTokPrecedence(); int TokPrec = GetTokPrecedence();
@@ -843,33 +898,32 @@ public:
// то берём часть вместе с RHS как LHS. // то берём часть вместе с RHS как LHS.
int NextPrec = GetTokPrecedence(); int NextPrec = GetTokPrecedence();
if (TokPrec < NextPrec) { if (TokPrec < NextPrec) {
RHS = ParseBinOpRHS(TokPrec+1, RHS, IDNames); RHS = ParseBinOpRHS(TokPrec + 1, RHS, IDNames);
if (RHS == 0) return 0; if (RHS == 0) return 0;
} }
// Собираем LHS/RHS. // Собираем LHS/RHS.
LHS = new BinaryExprAST(BinOp, LHS, RHS); LHS = new BinaryExprAST(BinOp, LHS, RHS);
} }
} }
/// expression
/// expression /// ::= primary binoprhs
/// ::= primary binoprhs ///
/// ExprAST *IoTScenario::ParseExpression(String *IDNames) {
ExprAST* IoTScenario::ParseExpression(String *IDNames) {
ExprAST *LHS = ParsePrimary(IDNames); ExprAST *LHS = ParsePrimary(IDNames);
if (!LHS) return 0; if (!LHS) return 0;
return ParseBinOpRHS(0, LHS, IDNames); return ParseBinOpRHS(0, LHS, IDNames);
} }
void IoTScenario::clearScenarioElements() { // удаляем все корневые элементы дерева AST void IoTScenario::clearScenarioElements() { // удаляем все корневые элементы дерева AST
for (unsigned int i = 0; i < ScenarioElements.size(); i++) { for (unsigned int i = 0; i < ScenarioElements.size(); i++) {
if (ScenarioElements[i]) delete ScenarioElements[i]; if (ScenarioElements[i]) delete ScenarioElements[i];
} }
ScenarioElements.clear(); ScenarioElements.clear();
} }
void IoTScenario::loadScenario(String fileName) { // посимвольно считываем и сразу интерпретируем сценарий в дерево AST void IoTScenario::loadScenario(String fileName) { // посимвольно считываем и сразу интерпретируем сценарий в дерево AST
clearScenarioElements(); // удаляем все корневые элементы перед загрузкой новых. clearScenarioElements(); // удаляем все корневые элементы перед загрузкой новых.
LastChar = ' '; LastChar = ' ';
@@ -877,41 +931,46 @@ public:
if (myfile.available()) { if (myfile.available()) {
strFromFile = new String(""); strFromFile = new String("");
*strFromFile = myfile.readString(); *strFromFile = myfile.readString();
Serial.println(*strFromFile);
jsonRead(*strFromFile, "scen", *strFromFile, true);
myfile.close(); myfile.close();
getNextToken(); getNextToken();
while (strIterator < strFromFile->length()-1) { while (strIterator < strFromFile->length() - 1) {
//Serial.printf("-%c", LastChar); // Serial.printf("-%c", LastChar);
switch (CurTok) { switch (CurTok) {
//case tok_eof: return; // case tok_eof: return;
//case ';': getNextToken(); break; // игнорируем верхнеуровневые точки с запятой. // case ';': getNextToken(); break; // игнорируем верхнеуровневые точки с запятой.
case tok_if: { case tok_if: {
String IDNames = ""; // накопитель встречающихся идентификаторов в условии String IDNames = ""; // накопитель встречающихся идентификаторов в условии
ScenarioElements.push_back(ParseIfExpr(&IDNames)); ScenarioElements.push_back(ParseIfExpr(&IDNames));
//Serial.printf("vvvvvvvvvvvvvvvv %s", IDNames.c_str()); // Serial.printf("vvvvvvvvvvvvvvvv %s", IDNames.c_str());
break; break;
} }
default: getNextToken(); break; default:
getNextToken();
break;
} }
} }
delete strFromFile; delete strFromFile;
strIterator = 0; strIterator = 0;
} else {Error("Open file scenario error");} } else {
Error("Open file scenario error");
} }
}
void IoTScenario::ExecScenario(String eventIdName) { // запускаем поочереди все корневые элементы выражений в сценарии, ожидаемо - это IFы void IoTScenario::ExecScenario(String eventIdName) { // запускаем поочереди все корневые элементы выражений в сценарии, ожидаемо - это IFы
// eventIdName - ID элемента для которого выполняем сценарий, т.е. игнорируем любые проверки, если нет такого ID в условиях // eventIdName - ID элемента для которого выполняем сценарий, т.е. игнорируем любые проверки, если нет такого ID в условиях
isIotScenException = false; isIotScenException = false;
Serial.printf("Count root elements in scenario: %d\n", ScenarioElements.size()); Serial.printf("Count root elements in scenario: %d\n", ScenarioElements.size());
for (unsigned int i = 0; i < ScenarioElements.size(); i++) { for (unsigned int i = 0; i < ScenarioElements.size(); i++) {
if (ScenarioElements[i] && ScenarioElements[i]->hasEventIdName(eventIdName)) ScenarioElements[i]->exec(); if (ScenarioElements[i] && ScenarioElements[i]->hasEventIdName(eventIdName)) ScenarioElements[i]->exec();
//else Serial.printf("Call from ExecScenario: Skip ifexec because %s not found\n", eventIdName.c_str()); // else Serial.printf("Call from ExecScenario: Skip ifexec because %s not found\n", eventIdName.c_str());
if (isIotScenException) return; if (isIotScenException) return;
} }
} }
IoTScenario::IoTScenario() {
IoTScenario::IoTScenario() {
// Задаём стандартные бинарные операторы. // Задаём стандартные бинарные операторы.
// 1 - наименьший приоритет. // 1 - наименьший приоритет.
BinopPrecedence['='] = 1; BinopPrecedence['='] = 1;
@@ -927,6 +986,6 @@ public:
BinopPrecedence['-'] = 26; BinopPrecedence['-'] = 26;
BinopPrecedence['/'] = 27; BinopPrecedence['/'] = 27;
BinopPrecedence['*'] = 28; // highest. BinopPrecedence['*'] = 28; // highest.
} }
IoTScenario::~IoTScenario() {} IoTScenario::~IoTScenario() {}