2022-02-14 12:48:59 +03:00
|
|
|
|
#pragma once
|
|
|
|
|
|
#include "Global.h"
|
2022-02-15 11:37:31 +01:00
|
|
|
|
#include "classes/IoTItem.h"
|
|
|
|
|
|
#include "classes/IoTScenario.h"
|
|
|
|
|
|
#include "utils/FileUtils.h"
|
2022-08-21 20:53:49 +03:00
|
|
|
|
#include "NTP.h"
|
2022-02-24 00:54:56 +03:00
|
|
|
|
|
2022-08-30 14:00:22 +03:00
|
|
|
|
|
2022-02-28 00:49:57 +03:00
|
|
|
|
bool isIotScenException; // признак исключения и попытки прекратить выполнение сценария заранее
|
|
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
// Лексический анализатор возвращает токены [0-255], если это неизвестны,
|
2022-02-14 12:48:59 +03:00
|
|
|
|
// иначе одну из известных единиц кода
|
|
|
|
|
|
enum Token {
|
2022-08-23 13:06:01 +02:00
|
|
|
|
tok_eof = -1,
|
|
|
|
|
|
|
|
|
|
|
|
// операнды (первичные выражения: идентификаторы, числа)
|
|
|
|
|
|
tok_identifier = -4,
|
|
|
|
|
|
tok_number = -5,
|
|
|
|
|
|
tok_string = -3,
|
|
|
|
|
|
|
|
|
|
|
|
// двухсимвольные операторы бинарных операций
|
|
|
|
|
|
tok_equal = -2,
|
|
|
|
|
|
tok_notequal = -9,
|
|
|
|
|
|
tok_lesseq = -10,
|
|
|
|
|
|
tok_greateq = -11,
|
|
|
|
|
|
|
|
|
|
|
|
// управление
|
|
|
|
|
|
tok_if = -6,
|
|
|
|
|
|
tok_then = -7,
|
|
|
|
|
|
tok_else = -8
|
2022-02-14 12:48:59 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
// Abstract Syntax Tree (Абстрактное Синтаксическое Дерево или Дерево Парсинга)
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
|
|
|
|
/// ExprAST - Базовый класс для всех узлов выражений.
|
|
|
|
|
|
ExprAST::~ExprAST() {}
|
2022-08-23 13:06:01 +02:00
|
|
|
|
IoTValue *ExprAST::exec() { return nullptr; }
|
|
|
|
|
|
int ExprAST::setValue(IoTValue *val) { return 0; } // 0 - установка значения не поддерживается наследником
|
|
|
|
|
|
bool ExprAST::hasEventIdName(String eventIdName) { return false; } // по умолчанию все узлы не связаны с ИД события, для которого выполняется сценарий
|
|
|
|
|
|
// struct IoTValue zeroIotVal;
|
|
|
|
|
|
|
2022-02-14 12:48:59 +03:00
|
|
|
|
/// NumberExprAST - Класс узла выражения для числовых литералов (Например, "1.0").
|
|
|
|
|
|
class NumberExprAST : public ExprAST {
|
2022-08-23 13:06:01 +02:00
|
|
|
|
IoTValue Val;
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
2022-09-05 16:26:27 +03:00
|
|
|
|
NumberExprAST(String val) {
|
|
|
|
|
|
Val.valD = strtod(val.c_str(), 0);
|
|
|
|
|
|
Val.valS = val;
|
|
|
|
|
|
}
|
2022-08-23 13:06:01 +02:00
|
|
|
|
|
|
|
|
|
|
IoTValue *exec() {
|
|
|
|
|
|
if (isIotScenException) return nullptr;
|
|
|
|
|
|
// Serial.printf("Call from NumberExprAST: %f\n", Val.valD);
|
|
|
|
|
|
return &Val;
|
|
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/// StringExprAST - Класс узла выражения для строковых литералов (Например, "Example with spaces and quotes").
|
|
|
|
|
|
class StringExprAST : public ExprAST {
|
2022-08-23 13:06:01 +02:00
|
|
|
|
IoTValue Val;
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
StringExprAST(String val) {
|
|
|
|
|
|
Val.isDecimal = false;
|
|
|
|
|
|
Val.valS = val;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
IoTValue *exec() {
|
|
|
|
|
|
if (isIotScenException) return nullptr;
|
|
|
|
|
|
// Serial.printf("Call from StringExprAST: %s\n", Val.valS.c_str());
|
|
|
|
|
|
return &Val;
|
|
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/// VariableExprAST - Класс узла выражения для переменных (например, "a").
|
2022-02-23 20:14:29 +03:00
|
|
|
|
class VariableExprAST : public ExprAST {
|
2022-08-23 13:06:01 +02:00
|
|
|
|
String Name;
|
|
|
|
|
|
IoTItem *Item; // ссылка на объект модуля (прямой доступ к идентификатору указанному в сценарии), если получилось найти модуль по ID
|
|
|
|
|
|
bool ItemIsLocal = false;
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
VariableExprAST(const String &name, IoTItem *item) : Name(name), Item(item) {
|
|
|
|
|
|
if (item) ItemIsLocal = item->iAmLocal;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int setValue(IoTValue *val) {
|
|
|
|
|
|
if (!ItemIsLocal) Item = findIoTItem(Name);
|
|
|
|
|
|
if (Item)
|
|
|
|
|
|
Item->setValue(*val);
|
|
|
|
|
|
else
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
IoTValue *exec() {
|
|
|
|
|
|
if (isIotScenException) return nullptr;
|
|
|
|
|
|
if (!ItemIsLocal) Item = findIoTItem(Name);
|
|
|
|
|
|
if (Item) {
|
|
|
|
|
|
// if (Item->value.isDecimal)
|
|
|
|
|
|
// 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());
|
|
|
|
|
|
return &(Item->value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nullptr; // Item не найден.
|
|
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/// BinaryExprAST - Класс узла выражения для бинарных операторов.
|
|
|
|
|
|
class BinaryExprAST : public ExprAST {
|
2022-08-23 13:06:01 +02:00
|
|
|
|
signed char Op;
|
|
|
|
|
|
ExprAST *LHS, *RHS;
|
|
|
|
|
|
IoTValue val;
|
|
|
|
|
|
String lhsStr, rhsStr;
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
BinaryExprAST(signed char op, ExprAST *lhs, ExprAST *rhs)
|
|
|
|
|
|
: Op(op), LHS(lhs), RHS(rhs) {}
|
|
|
|
|
|
|
|
|
|
|
|
~BinaryExprAST() {
|
|
|
|
|
|
if (LHS) delete LHS;
|
|
|
|
|
|
if (RHS) delete RHS;
|
|
|
|
|
|
// Serial.printf("Call from BinaryExprAST delete\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
IoTValue *exec() {
|
|
|
|
|
|
if (isIotScenException) return nullptr;
|
2022-08-28 21:56:47 +03:00
|
|
|
|
// String printStr = "";
|
|
|
|
|
|
|
|
|
|
|
|
// if (Op == tok_equal)
|
|
|
|
|
|
// printStr = "==";
|
|
|
|
|
|
// else if (Op == tok_notequal)
|
|
|
|
|
|
// printStr = "!=";
|
|
|
|
|
|
// else if (Op == tok_lesseq)
|
|
|
|
|
|
// printStr = "<=";
|
|
|
|
|
|
// else if (Op == tok_greateq)
|
|
|
|
|
|
// printStr = ">=";
|
|
|
|
|
|
// else
|
|
|
|
|
|
// printStr = printStr + (char)Op;
|
2022-08-23 13:06:01 +02:00
|
|
|
|
|
|
|
|
|
|
// Serial.printf("Call from BinaryExprAST: %s\n", printStr.c_str());
|
|
|
|
|
|
|
|
|
|
|
|
if (RHS == nullptr || LHS == nullptr) return nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
IoTValue *rhs = RHS->exec(); // получаем значение правого операнда для возможного использования в операции присваивания
|
2022-08-28 21:56:47 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
if (Op == '=' && LHS->setValue(rhs)) { // если установка значения не поддерживается, т.е. слева не переменная, то работаем по другим комбинациям далее
|
|
|
|
|
|
return rhs; // иначе возвращаем присвоенное значение справа
|
2022-02-14 12:48:59 +03:00
|
|
|
|
}
|
2022-08-23 13:06:01 +02:00
|
|
|
|
|
|
|
|
|
|
IoTValue *lhs = LHS->exec(); // если присваивания не произошло, значит операция иная и необходимо значение левого операнда
|
|
|
|
|
|
|
|
|
|
|
|
if (lhs != nullptr && rhs != nullptr) {
|
|
|
|
|
|
if (lhs->isDecimal && rhs->isDecimal) {
|
|
|
|
|
|
switch (Op) {
|
|
|
|
|
|
case '>':
|
|
|
|
|
|
val.valD = lhs->valD > rhs->valD;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case '<':
|
|
|
|
|
|
val.valD = lhs->valD < rhs->valD;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case tok_lesseq:
|
|
|
|
|
|
val.valD = lhs->valD <= rhs->valD;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case tok_greateq:
|
|
|
|
|
|
val.valD = lhs->valD >= rhs->valD;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case tok_equal:
|
|
|
|
|
|
val.valD = lhs->valD == rhs->valD;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case tok_notequal:
|
|
|
|
|
|
val.valD = lhs->valD != rhs->valD;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case '+':
|
|
|
|
|
|
val.valD = lhs->valD + rhs->valD;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case '-':
|
|
|
|
|
|
val.valD = lhs->valD - rhs->valD;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case '*':
|
|
|
|
|
|
val.valD = lhs->valD * rhs->valD;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case '/':
|
|
|
|
|
|
if (rhs->valD != 0)
|
|
|
|
|
|
val.valD = lhs->valD / rhs->valD;
|
|
|
|
|
|
else
|
|
|
|
|
|
val.valD = 3.4E+38;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case '|':
|
|
|
|
|
|
val.valD = lhs->valD || rhs->valD;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case '&':
|
|
|
|
|
|
val.valD = lhs->valD && rhs->valD;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
return &val;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!lhs->isDecimal || !rhs->isDecimal) {
|
|
|
|
|
|
if (lhs->isDecimal)
|
|
|
|
|
|
lhsStr = lhs->valD;
|
|
|
|
|
|
else
|
|
|
|
|
|
lhsStr = lhs->valS;
|
|
|
|
|
|
if (rhs->isDecimal)
|
|
|
|
|
|
rhsStr = rhs->valD;
|
|
|
|
|
|
else
|
|
|
|
|
|
rhsStr = rhs->valS;
|
|
|
|
|
|
switch (Op) {
|
|
|
|
|
|
case tok_equal:
|
|
|
|
|
|
val.valD = compStr(lhsStr, rhsStr);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case '+':
|
|
|
|
|
|
val.valS = lhsStr + rhsStr;
|
|
|
|
|
|
val.valD = 1;
|
|
|
|
|
|
val.isDecimal = false;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
return &val;
|
|
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
}
|
|
|
|
|
|
return &val;
|
|
|
|
|
|
}
|
2022-05-06 11:59:47 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
bool compStr(String str1, String str2) {
|
|
|
|
|
|
if (str1.length() != str2.length()) return false;
|
|
|
|
|
|
for (int i = 0; i < str1.length(); i++) {
|
|
|
|
|
|
if (str1[i] == '*' || str2[i] == '*') continue; //считаем, что если есть подстановочная звезда, то символы равны
|
|
|
|
|
|
if (str1[i] != str2[i]) return false;
|
|
|
|
|
|
}
|
2022-05-06 11:59:47 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
return true; // str1 == str2;
|
|
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/// CallExprAST - Класс узла выражения для вызова команды.
|
|
|
|
|
|
class CallExprAST : public ExprAST {
|
2022-08-23 13:06:01 +02:00
|
|
|
|
String Callee;
|
|
|
|
|
|
String Cmd;
|
|
|
|
|
|
std::vector<ExprAST *> Args;
|
|
|
|
|
|
IoTItem *Item; // ссылка на объект модуля (прямой доступ к идентификатору указанному в сценарии), если получилось найти модуль по ID
|
|
|
|
|
|
IoTValue ret; // хранение возвращаемого значения, т.к. возврат по ссылке осуществляется
|
|
|
|
|
|
bool ItemIsLocal = false;
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
CallExprAST(const String &callee, String &cmd, std::vector<ExprAST *> &args, IoTItem *item)
|
|
|
|
|
|
: Callee(callee), Cmd(cmd), Args(args), Item(item) {
|
|
|
|
|
|
if (item) ItemIsLocal = item->iAmLocal;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
IoTValue *exec() {
|
|
|
|
|
|
if (isIotScenException) return nullptr; // если прерывание, то сразу выходим
|
|
|
|
|
|
|
|
|
|
|
|
if (Cmd == "exit" || Callee == "exit") { // если системная команда, то выполняем и выходим
|
|
|
|
|
|
IoTValue *tmp;
|
|
|
|
|
|
if (Args.size() > 0 && Args[0])
|
|
|
|
|
|
tmp = Args[0]->exec();
|
|
|
|
|
|
else
|
|
|
|
|
|
SerialPrint("i", "SysExt", "Exit");
|
|
|
|
|
|
if (tmp) SerialPrint("i", "SysExt", "Exit = '" + tmp->valS + "'");
|
|
|
|
|
|
|
|
|
|
|
|
isIotScenException = true;
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
if (!ItemIsLocal) Item = findIoTItem(Callee); // пробуем найти переменную если она не локальная (могла придти по сети в процессе)
|
|
|
|
|
|
if (!Item) return nullptr; // ret = zeroIotVal; // если все же не пришла, то либо опечатка, либо уже стерлась - выходим
|
|
|
|
|
|
|
|
|
|
|
|
// если все же все ок, то готовим параметры для передачи в модуль
|
|
|
|
|
|
std::vector<IoTValue> ArgsAsIoTValue;
|
|
|
|
|
|
for (unsigned int i = 0; i < Args.size(); i++) {
|
|
|
|
|
|
if (Args[i] == nullptr) return nullptr;
|
|
|
|
|
|
IoTValue *tmp = Args[i]->exec();
|
|
|
|
|
|
if (tmp != nullptr)
|
|
|
|
|
|
ArgsAsIoTValue.push_back(*tmp);
|
|
|
|
|
|
else
|
|
|
|
|
|
return nullptr; // ArgsAsIoTValue.push_back(zeroIotVal);
|
|
|
|
|
|
}
|
2022-08-21 20:53:49 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
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);
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
~CallExprAST() {
|
|
|
|
|
|
for (unsigned int i = 0; i < Args.size(); i++) {
|
|
|
|
|
|
if (Args[i]) delete Args[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
Args.clear();
|
|
|
|
|
|
// Serial.printf("Call from CallExprAST delete\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Для сокращения количества преобразований используем числовые коды для фиксации названия системной функции,
|
2022-08-21 20:53:49 +03:00
|
|
|
|
// которые поддерживает прошивка
|
|
|
|
|
|
enum SysOp {
|
2022-08-23 13:06:01 +02:00
|
|
|
|
sysop_notfound = 0,
|
|
|
|
|
|
sysop_reboot = 1,
|
|
|
|
|
|
sysop_digitalRead,
|
|
|
|
|
|
sysop_analogRead, //
|
|
|
|
|
|
sysop_digitalWrite, //
|
|
|
|
|
|
sysop_digitalInvert, //
|
|
|
|
|
|
sysop_deepSleep, //
|
|
|
|
|
|
sysop_getHours, //
|
|
|
|
|
|
sysop_getMinutes, //
|
|
|
|
|
|
sysop_getSeconds, //
|
|
|
|
|
|
sysop_getMonth, //
|
|
|
|
|
|
sysop_getDay,
|
|
|
|
|
|
sysop_gethhmm,
|
|
|
|
|
|
sysop_gethhmmss,
|
|
|
|
|
|
sysop_getTime,
|
|
|
|
|
|
sysop_getIP,
|
|
|
|
|
|
sysop_mqttPub
|
2022-08-21 20:53:49 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
IoTValue sysExecute(SysOp command, std::vector<IoTValue> ¶m) {
|
|
|
|
|
|
IoTValue value = {};
|
|
|
|
|
|
|
|
|
|
|
|
if (_time_isTrust)
|
|
|
|
|
|
switch (command) {
|
|
|
|
|
|
case sysop_getHours:
|
|
|
|
|
|
value.valD = _time_local.hour;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case sysop_getMinutes:
|
|
|
|
|
|
value.valD = _time_local.minute;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case sysop_getSeconds:
|
|
|
|
|
|
value.valD = _time_local.second;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case sysop_getMonth:
|
|
|
|
|
|
value.valD = _time_local.month;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case sysop_getDay:
|
|
|
|
|
|
value.valD = _time_local.day_of_month;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case sysop_gethhmm:
|
|
|
|
|
|
value.isDecimal = false;
|
|
|
|
|
|
value.valS = getTimeLocal_hhmm();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case sysop_gethhmmss:
|
|
|
|
|
|
value.isDecimal = false;
|
|
|
|
|
|
value.valS = getTimeLocal_hhmmss();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case sysop_getTime:
|
|
|
|
|
|
value.isDecimal = false;
|
|
|
|
|
|
value.valS = getDateTimeDotFormated();
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
value.isDecimal = false;
|
|
|
|
|
|
value.valS = "none";
|
|
|
|
|
|
}
|
2022-08-23 10:06:45 +03:00
|
|
|
|
|
|
|
|
|
|
switch (command) {
|
2022-08-23 13:06:01 +02:00
|
|
|
|
case sysop_reboot:
|
|
|
|
|
|
ESP.restart();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case sysop_digitalRead:
|
|
|
|
|
|
if (param.size()) {
|
|
|
|
|
|
IoTgpio.pinMode(param[0].valD, INPUT);
|
|
|
|
|
|
value.valD = IoTgpio.digitalRead(param[0].valD);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case sysop_analogRead:
|
|
|
|
|
|
if (param.size()) {
|
|
|
|
|
|
IoTgpio.pinMode(param[0].valD, INPUT);
|
|
|
|
|
|
value.valD = IoTgpio.analogRead(param[0].valD);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case sysop_digitalWrite:
|
|
|
|
|
|
if (param.size() == 2) {
|
|
|
|
|
|
IoTgpio.pinMode(param[0].valD, OUTPUT);
|
|
|
|
|
|
IoTgpio.digitalWrite(param[0].valD, param[1].valD);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case sysop_digitalInvert:
|
|
|
|
|
|
if (param.size()) {
|
|
|
|
|
|
IoTgpio.pinMode(param[0].valD, OUTPUT);
|
|
|
|
|
|
IoTgpio.digitalInvert(param[0].valD);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case sysop_deepSleep:
|
|
|
|
|
|
if (param.size()) {
|
|
|
|
|
|
Serial.printf("Ушел спать на %d сек...", (int)param[0].valD);
|
2022-08-21 20:53:49 +03:00
|
|
|
|
#ifdef ESP32
|
2022-08-23 13:06:01 +02:00
|
|
|
|
esp_sleep_enable_timer_wakeup(param[0].valD * 1000000);
|
|
|
|
|
|
delay(1000);
|
|
|
|
|
|
esp_deep_sleep_start();
|
2022-08-21 20:53:49 +03:00
|
|
|
|
#else
|
2022-08-23 13:06:01 +02:00
|
|
|
|
ESP.deepSleep(param[0].valD * 1000000);
|
2022-08-21 20:53:49 +03:00
|
|
|
|
#endif
|
2022-08-23 13:06:01 +02:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case sysop_getIP:
|
|
|
|
|
|
value.valS = jsonReadStr(settingsFlashJson, F("ip"));
|
|
|
|
|
|
value.isDecimal = false;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case sysop_mqttPub:
|
|
|
|
|
|
if (param.size() == 2) {
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return value;
|
2022-08-21 20:53:49 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// SysCallExprAST - Класс узла выражения для вызова системных команд.
|
|
|
|
|
|
class SysCallExprAST : public ExprAST {
|
2022-08-23 13:06:01 +02:00
|
|
|
|
String Callee;
|
|
|
|
|
|
std::vector<ExprAST *> Args;
|
|
|
|
|
|
IoTValue ret; // хранение возвращаемого значения, т.к. возврат по ссылке осуществляется
|
|
|
|
|
|
// bool ItemIsLocal = false;
|
|
|
|
|
|
SysOp operation;
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
SysCallExprAST(const String &callee, std::vector<ExprAST *> &args)
|
|
|
|
|
|
: Callee(callee), Args(args) {
|
|
|
|
|
|
if (Callee == "reboot")
|
|
|
|
|
|
operation = sysop_reboot;
|
|
|
|
|
|
else if (Callee == "digitalRead")
|
|
|
|
|
|
operation = sysop_digitalRead;
|
|
|
|
|
|
else if (Callee == "analogRead")
|
|
|
|
|
|
operation = sysop_analogRead;
|
|
|
|
|
|
else if (Callee == "digitalWrite")
|
|
|
|
|
|
operation = sysop_digitalWrite;
|
|
|
|
|
|
else if (Callee == "digitalInvert")
|
|
|
|
|
|
operation = sysop_digitalInvert;
|
|
|
|
|
|
else if (Callee == "deepSleep")
|
|
|
|
|
|
operation = sysop_deepSleep;
|
|
|
|
|
|
else if (Callee == "getTime")
|
|
|
|
|
|
operation = sysop_getTime;
|
|
|
|
|
|
else if (Callee == "getHours")
|
|
|
|
|
|
operation = sysop_getHours;
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
IoTValue *exec() {
|
2022-08-30 23:31:38 +03:00
|
|
|
|
//Serial.printf("Call from SysCallExprAST exec %d\n", operation);
|
2022-08-23 13:06:01 +02:00
|
|
|
|
|
|
|
|
|
|
if (isIotScenException) return nullptr; // если прерывание, то сразу выходим
|
|
|
|
|
|
|
|
|
|
|
|
// готовим параметры для передачи в в функцию интерпретатор действий
|
|
|
|
|
|
std::vector<IoTValue> ArgsAsIoTValue;
|
|
|
|
|
|
for (unsigned int i = 0; i < Args.size(); i++) {
|
|
|
|
|
|
if (Args[i] == nullptr) return nullptr;
|
|
|
|
|
|
IoTValue *tmp = Args[i]->exec();
|
|
|
|
|
|
if (tmp != nullptr)
|
|
|
|
|
|
ArgsAsIoTValue.push_back(*tmp);
|
|
|
|
|
|
else
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ret = sysExecute(operation, ArgsAsIoTValue); // вызываем функцию интерпретатор с передачей всех аргументов
|
|
|
|
|
|
|
|
|
|
|
|
return &ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
~SysCallExprAST() {
|
|
|
|
|
|
for (unsigned int i = 0; i < Args.size(); i++) {
|
|
|
|
|
|
if (Args[i]) delete Args[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
Args.clear();
|
|
|
|
|
|
// Serial.printf("Call from CallExprAST delete\n");
|
|
|
|
|
|
}
|
2022-08-21 20:53:49 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
2022-02-14 12:48:59 +03:00
|
|
|
|
/// IfExprAST - Класс узла выражения для if/then/else.
|
|
|
|
|
|
class IfExprAST : public ExprAST {
|
2022-08-23 13:06:01 +02:00
|
|
|
|
ExprAST *Cond, *Then, *Else;
|
|
|
|
|
|
String _IDNames;
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
IfExprAST(ExprAST *cond, ExprAST *then, ExprAST *_else, String *IDNames)
|
|
|
|
|
|
: Cond(cond), Then(then), Else(_else) {
|
|
|
|
|
|
if (IDNames) {
|
|
|
|
|
|
_IDNames = *IDNames;
|
|
|
|
|
|
} else
|
|
|
|
|
|
_IDNames = "";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool hasEventIdName(String eventIdName) {
|
|
|
|
|
|
// Serial.printf("Call from BinaryExprAST _IDNames:%s\n", _IDNames.c_str());
|
|
|
|
|
|
return _IDNames.indexOf(" " + eventIdName + " ") >= 0; // определяем встречался ли ИД, для которого исполняем сценарий в выражении IF
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
IoTValue *exec() {
|
|
|
|
|
|
if (isIotScenException) return nullptr;
|
|
|
|
|
|
IoTValue *res_ret = nullptr;
|
|
|
|
|
|
IoTValue *cond_ret = nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
if (Cond) cond_ret = Cond->exec();
|
|
|
|
|
|
|
|
|
|
|
|
if (!cond_ret) {
|
|
|
|
|
|
// Serial.printf("Call from IfExprAST: Skip If\n");
|
|
|
|
|
|
return nullptr; //&zeroIotVal;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (cond_ret->isDecimal && cond_ret->valD) {
|
|
|
|
|
|
if (Then == nullptr) return nullptr;
|
|
|
|
|
|
res_ret = Then->exec();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if (Else == nullptr) return nullptr;
|
|
|
|
|
|
res_ret = Else->exec();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 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 Serial.printf("Call from IfExprAST: Cond result = %f, result = %s\n", cond_ret->valD, res_ret->valS.c_str());
|
|
|
|
|
|
Serial.printf("\n");
|
|
|
|
|
|
return cond_ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
~IfExprAST() {
|
|
|
|
|
|
if (Cond) delete Cond;
|
|
|
|
|
|
if (Then) delete Then;
|
|
|
|
|
|
if (Else) delete Else;
|
|
|
|
|
|
// Serial.printf("Call from IfExprAST delete\n");
|
|
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/// BracketsExprAST - Класс узла блока кода {}.
|
|
|
|
|
|
class BracketsExprAST : public ExprAST {
|
2022-08-23 13:06:01 +02:00
|
|
|
|
std::vector<ExprAST *> BracketsList;
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
public:
|
|
|
|
|
|
BracketsExprAST(std::vector<ExprAST *> &bracketsList)
|
|
|
|
|
|
: BracketsList(bracketsList) {}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
IoTValue *exec() {
|
|
|
|
|
|
if (isIotScenException) return nullptr;
|
|
|
|
|
|
// Serial.printf("Call from BracketsExprAST OperCount = %d \n", BracketsList.size());
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
IoTValue *lastExecValue = nullptr;
|
|
|
|
|
|
for (unsigned int i = 0; i < BracketsList.size(); i++) {
|
|
|
|
|
|
if (BracketsList[i] == nullptr) return nullptr;
|
|
|
|
|
|
lastExecValue = BracketsList[i]->exec();
|
|
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
return lastExecValue;
|
2022-02-14 12:48:59 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
~BracketsExprAST() {
|
|
|
|
|
|
for (unsigned int i = 0; i < BracketsList.size(); i++) {
|
|
|
|
|
|
if (BracketsList[i]) delete BracketsList[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
BracketsList.clear();
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
// Serial.printf("Call from BracketsExprAST delete\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
// Lexer (Лексический анализатор)
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-30 14:00:22 +03:00
|
|
|
|
int IoTScenario::getLastChar() {
|
2022-09-04 19:16:08 +03:00
|
|
|
|
if (mode == 0) {
|
|
|
|
|
|
if (file) {
|
|
|
|
|
|
LastChar = file.read();
|
|
|
|
|
|
if (LastChar == 10) curLine++;
|
|
|
|
|
|
return LastChar;
|
|
|
|
|
|
} else return EOF;
|
|
|
|
|
|
} else if (mode == 1) {
|
|
|
|
|
|
if (charCount < strFromFile.length()) {
|
|
|
|
|
|
LastChar = strFromFile.charAt(charCount);
|
|
|
|
|
|
//Serial.printf("%d, ", LastChar);
|
|
|
|
|
|
if (LastChar == 10) curLine++;
|
|
|
|
|
|
charCount++;
|
|
|
|
|
|
return LastChar;
|
|
|
|
|
|
} else return EOF;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
/// gettok - Возвращает следующий токен из стандартного потока ввода.
|
|
|
|
|
|
int IoTScenario::gettok() {
|
2022-02-14 12:48:59 +03:00
|
|
|
|
// Пропускаем пробелы.
|
|
|
|
|
|
while (isspace(LastChar))
|
2022-08-23 13:06:01 +02:00
|
|
|
|
LastChar = getLastChar();
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
if (isalpha(LastChar) || LastChar == '_') { // идентификатор: [a-zA-Z][a-zA-Z0-9]*
|
2022-08-30 14:00:22 +03:00
|
|
|
|
IdentifierStr = (char)LastChar;
|
2022-08-23 13:06:01 +02:00
|
|
|
|
while (isalnum((LastChar = getLastChar())) || LastChar == '_') {
|
2022-08-30 14:00:22 +03:00
|
|
|
|
IdentifierStr += (char)LastChar;
|
2022-08-23 13:06:01 +02:00
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
// Serial.printf("%s ", IdentifierStr.c_str());
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
if (IdentifierStr == "if") return tok_if;
|
|
|
|
|
|
if (IdentifierStr == "then") return tok_then;
|
|
|
|
|
|
if (IdentifierStr == "else") return tok_else;
|
|
|
|
|
|
return tok_identifier;
|
2022-02-14 12:48:59 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-09-05 16:26:27 +03:00
|
|
|
|
NumStr="";
|
2022-08-31 08:52:43 +03:00
|
|
|
|
if (LastChar == '-') {
|
|
|
|
|
|
LastChar = getLastChar();
|
|
|
|
|
|
if (isdigit(LastChar)) NumStr = "-";
|
|
|
|
|
|
else return '-';
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2022-08-23 13:06:01 +02:00
|
|
|
|
if (isdigit(LastChar)) { // Число: [0-9.]+
|
|
|
|
|
|
do {
|
2022-08-30 14:00:22 +03:00
|
|
|
|
NumStr += (char)LastChar;
|
2022-08-23 13:06:01 +02:00
|
|
|
|
LastChar = getLastChar();
|
|
|
|
|
|
} while (isdigit(LastChar) || LastChar == '.');
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
return tok_number;
|
2022-02-14 12:48:59 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (LastChar == '#') {
|
2022-08-23 13:06:01 +02:00
|
|
|
|
// Комментарий до конца строки
|
|
|
|
|
|
do LastChar = getLastChar();
|
2022-08-30 14:00:22 +03:00
|
|
|
|
while (LastChar != EOF && LastChar != '\n' && LastChar != '\r');
|
2022-08-28 20:33:43 +03:00
|
|
|
|
|
|
|
|
|
|
if (LastChar != EOF)
|
|
|
|
|
|
return gettok();
|
2022-08-23 13:06:01 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (LastChar == '"') { // "строка"
|
|
|
|
|
|
IdentifierStr = "";
|
2022-02-14 12:48:59 +03:00
|
|
|
|
LastChar = getLastChar();
|
2022-08-30 14:00:22 +03:00
|
|
|
|
while (LastChar != '"' && LastChar != EOF) {
|
|
|
|
|
|
IdentifierStr += (char)LastChar;
|
2022-08-23 13:06:01 +02:00
|
|
|
|
LastChar = getLastChar();
|
|
|
|
|
|
}
|
|
|
|
|
|
LastChar = getLastChar();
|
|
|
|
|
|
|
|
|
|
|
|
return tok_string;
|
2022-02-14 12:48:59 +03:00
|
|
|
|
}
|
2022-08-23 13:06:01 +02:00
|
|
|
|
|
2022-02-14 12:48:59 +03:00
|
|
|
|
// Проверка конца файла.
|
2022-08-30 14:00:22 +03:00
|
|
|
|
if (LastChar == EOF)
|
|
|
|
|
|
return tok_eof;
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
|
|
|
|
|
if (LastChar == '=') {
|
|
|
|
|
|
LastChar = getLastChar();
|
2022-08-23 13:06:01 +02:00
|
|
|
|
if (LastChar == '=') {
|
|
|
|
|
|
LastChar = getLastChar();
|
|
|
|
|
|
return tok_equal;
|
|
|
|
|
|
} else
|
|
|
|
|
|
return '=';
|
2022-02-14 12:48:59 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (LastChar == '!') {
|
|
|
|
|
|
LastChar = getLastChar();
|
2022-08-23 13:06:01 +02:00
|
|
|
|
if (LastChar == '=') {
|
|
|
|
|
|
LastChar = getLastChar();
|
|
|
|
|
|
return tok_notequal;
|
|
|
|
|
|
} else
|
|
|
|
|
|
return '!';
|
2022-02-14 12:48:59 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (LastChar == '<') {
|
|
|
|
|
|
LastChar = getLastChar();
|
2022-08-23 13:06:01 +02:00
|
|
|
|
if (LastChar == '=') {
|
|
|
|
|
|
LastChar = getLastChar();
|
|
|
|
|
|
return tok_lesseq;
|
|
|
|
|
|
} else
|
|
|
|
|
|
return '<';
|
2022-02-14 12:48:59 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (LastChar == '>') {
|
|
|
|
|
|
LastChar = getLastChar();
|
2022-08-23 13:06:01 +02:00
|
|
|
|
if (LastChar == '=') {
|
|
|
|
|
|
LastChar = getLastChar();
|
|
|
|
|
|
return tok_greateq;
|
|
|
|
|
|
} else
|
|
|
|
|
|
return '>';
|
2022-02-14 12:48:59 +03:00
|
|
|
|
}
|
2022-08-30 14:00:22 +03:00
|
|
|
|
|
2022-02-14 12:48:59 +03:00
|
|
|
|
// В противном случае просто возвращаем символ как значение ASCII
|
|
|
|
|
|
int ThisChar = LastChar;
|
|
|
|
|
|
LastChar = getLastChar();
|
|
|
|
|
|
return ThisChar;
|
2022-08-23 13:06:01 +02:00
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
// Parser (Парсер или Синтаксический Анализатор)
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
/// CurTok/getNextToken - Предоставляет простой буфер токенов. CurTok - это текущий
|
|
|
|
|
|
/// токен, просматриваемый парсером. getNextToken получает следующий токен от
|
|
|
|
|
|
/// лексического анализатора и обновляет CurTok.
|
|
|
|
|
|
int IoTScenario::getNextToken() {
|
2022-02-14 12:48:59 +03:00
|
|
|
|
return CurTok = gettok();
|
2022-08-23 13:06:01 +02:00
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
/// GetTokPrecedence - Возвращает приоритет текущего бинарного оператора.
|
|
|
|
|
|
int IoTScenario::GetTokPrecedence() {
|
2022-02-14 12:48:59 +03:00
|
|
|
|
if (!(isascii(CurTok) || BinopPrecedence.count(CurTok)))
|
2022-08-23 13:06:01 +02:00
|
|
|
|
return -1;
|
|
|
|
|
|
|
2022-02-14 12:48:59 +03:00
|
|
|
|
// Удостоверимся, что это объявленный бинарный оператор.
|
|
|
|
|
|
int TokPrec = BinopPrecedence[CurTok];
|
|
|
|
|
|
if (TokPrec <= 0) return -1;
|
|
|
|
|
|
return TokPrec;
|
2022-08-23 13:06:01 +02:00
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
/// Error* - Это небольшие вспомогательные функции для обработки ошибок.
|
|
|
|
|
|
ExprAST *IoTScenario::Error(const char *Str) {
|
2022-08-30 23:31:38 +03:00
|
|
|
|
Serial.printf("Scenario error in line %d: %s\n", curLine-1, Str);
|
2022-08-23 13:06:01 +02:00
|
|
|
|
return nullptr;
|
|
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
/// identifierexpr
|
|
|
|
|
|
/// ::= identifier
|
|
|
|
|
|
/// ::= identifier '(' expression* ')'
|
2022-09-03 21:32:39 +03:00
|
|
|
|
ExprAST *IoTScenario::ParseIdentifierExpr(String *IDNames, bool callFromCondition) {
|
2022-02-14 12:48:59 +03:00
|
|
|
|
String IdName = IdentifierStr;
|
|
|
|
|
|
String Cmd = "";
|
2022-08-23 13:06:01 +02:00
|
|
|
|
IoTItem *tmpItem = findIoTItem(IdName);
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
|
|
|
|
|
getNextToken(); // получаем идентификатор.
|
2022-08-23 13:06:01 +02:00
|
|
|
|
|
2022-02-14 12:48:59 +03:00
|
|
|
|
if (CurTok == '.') {
|
2022-08-23 13:06:01 +02:00
|
|
|
|
getNextToken();
|
|
|
|
|
|
Cmd = IdentifierStr;
|
|
|
|
|
|
getNextToken();
|
2022-02-14 12:48:59 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
if (CurTok != '(') { // Обычная переменная.
|
|
|
|
|
|
// if (tmpItem) return new VariableExprAST(IdName, tmpItem);
|
|
|
|
|
|
// else return new StringExprAST("id " + IdName + " not_found");
|
2022-02-26 10:50:40 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
// создаем экземпляр переменной в любом случае, даж если не нашли (tmpItem = nulptr), т.к. переменная может придти из сети позже
|
|
|
|
|
|
return new VariableExprAST(IdName, tmpItem);
|
2022-02-14 12:48:59 +03:00
|
|
|
|
}
|
2022-08-23 13:06:01 +02:00
|
|
|
|
|
2022-02-14 12:48:59 +03:00
|
|
|
|
// Вызов функции.
|
|
|
|
|
|
getNextToken(); // получаем (
|
2022-08-23 13:06:01 +02:00
|
|
|
|
std::vector<ExprAST *> Args;
|
2022-02-14 12:48:59 +03:00
|
|
|
|
if (CurTok != ')') {
|
2022-08-23 13:06:01 +02:00
|
|
|
|
while (1) {
|
2022-09-03 21:32:39 +03:00
|
|
|
|
ExprAST *Arg = ParseExpression(IDNames, callFromCondition);
|
2022-08-29 00:45:55 +03:00
|
|
|
|
if (!Arg) return nullptr;
|
2022-08-23 13:06:01 +02:00
|
|
|
|
Args.push_back(Arg);
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
if (CurTok == ')') break;
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
if (CurTok != ',')
|
|
|
|
|
|
return Error("Expected ')' or ',' in argument list");
|
|
|
|
|
|
getNextToken();
|
|
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-08-21 20:53:49 +03:00
|
|
|
|
// Получаем ';'.
|
2022-02-14 12:48:59 +03:00
|
|
|
|
getNextToken();
|
2022-08-21 20:53:49 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
if (Cmd == "")
|
|
|
|
|
|
return new SysCallExprAST(IdName, Args); // создаем объект запуска системной функции
|
|
|
|
|
|
else
|
|
|
|
|
|
return new CallExprAST(IdName, Cmd, Args, tmpItem); // создаем объект запуска функции в любом случае даж если не нашли Item
|
|
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
/// numberexpr ::= number
|
|
|
|
|
|
ExprAST *IoTScenario::ParseNumberExpr() {
|
2022-09-05 16:26:27 +03:00
|
|
|
|
ExprAST *Result = new NumberExprAST(NumStr);
|
2022-08-23 13:06:01 +02:00
|
|
|
|
getNextToken(); // получаем число
|
2022-02-14 12:48:59 +03:00
|
|
|
|
return Result;
|
2022-08-23 13:06:01 +02:00
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
/// parenexpr ::= '(' expression ')'
|
2022-09-03 21:32:39 +03:00
|
|
|
|
ExprAST *IoTScenario::ParseParenExpr(String *IDNames, bool callFromCondition) {
|
2022-02-14 12:48:59 +03:00
|
|
|
|
getNextToken(); // получаем (.
|
2022-09-03 21:32:39 +03:00
|
|
|
|
ExprAST *V = ParseExpression(IDNames, callFromCondition);
|
2022-08-29 00:45:55 +03:00
|
|
|
|
if (!V) return nullptr;
|
2022-08-23 13:06:01 +02:00
|
|
|
|
|
2022-02-14 12:48:59 +03:00
|
|
|
|
if (CurTok != ')')
|
2022-08-23 13:06:01 +02:00
|
|
|
|
return Error("expected ')'");
|
2022-08-30 23:31:38 +03:00
|
|
|
|
//getNextToken(); // получаем ).
|
2022-02-14 12:48:59 +03:00
|
|
|
|
return V;
|
2022-08-23 13:06:01 +02:00
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
/// bracketsexpr ::= '{' expression '}'
|
2022-09-03 21:32:39 +03:00
|
|
|
|
ExprAST *IoTScenario::ParseBracketsExpr(String *IDNames, bool callFromCondition) {
|
2022-02-14 12:48:59 +03:00
|
|
|
|
getNextToken(); // получаем {.
|
2022-08-23 13:06:01 +02:00
|
|
|
|
std::vector<ExprAST *> bracketsList;
|
2022-09-03 21:32:39 +03:00
|
|
|
|
|
|
|
|
|
|
while (CurTok != '}') {
|
|
|
|
|
|
ExprAST *Expr = ParseExpression(IDNames, callFromCondition);
|
2022-08-29 00:45:55 +03:00
|
|
|
|
if (!Expr) return nullptr;
|
2022-08-23 13:06:01 +02:00
|
|
|
|
bracketsList.push_back(Expr);
|
2022-09-03 21:32:39 +03:00
|
|
|
|
|
|
|
|
|
|
//if (CurTok == '}') break;
|
2022-08-23 13:06:01 +02:00
|
|
|
|
|
2022-09-04 19:16:08 +03:00
|
|
|
|
//Serial.printf("ParseBracketsExpr CurTok = %d \n", CurTok);
|
2022-08-23 13:06:01 +02:00
|
|
|
|
|
2022-09-03 21:32:39 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//if (CurTok != ';')
|
|
|
|
|
|
// return Error("Expected ';' in operation list");
|
|
|
|
|
|
|
|
|
|
|
|
//int ttok = getNextToken();
|
|
|
|
|
|
if (CurTok == tok_eof) {
|
|
|
|
|
|
return Error("Expected '}'");
|
|
|
|
|
|
}
|
2022-08-23 13:06:01 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-09-03 21:32:39 +03:00
|
|
|
|
getNextToken(); // получаем }.
|
2022-02-14 12:48:59 +03:00
|
|
|
|
return new BracketsExprAST(bracketsList);
|
2022-08-23 13:06:01 +02:00
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
/// quotesexpr ::= '"' expression '"'
|
|
|
|
|
|
ExprAST *IoTScenario::ParseQuotesExpr() {
|
2022-02-14 12:48:59 +03:00
|
|
|
|
String StringCont = IdentifierStr;
|
|
|
|
|
|
ExprAST *Result = new StringExprAST(StringCont);
|
2022-08-23 13:06:01 +02:00
|
|
|
|
getNextToken(); // получаем число
|
2022-02-14 12:48:59 +03:00
|
|
|
|
return Result;
|
2022-08-23 13:06:01 +02:00
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
/// ifexpr ::= 'if' expression 'then' expression 'else' expression
|
|
|
|
|
|
ExprAST *IoTScenario::ParseIfExpr(String *IDNames) {
|
2022-02-14 12:48:59 +03:00
|
|
|
|
getNextToken(); // Получаем if.
|
2022-08-23 13:06:01 +02:00
|
|
|
|
|
2022-02-14 12:48:59 +03:00
|
|
|
|
// условие.
|
2022-09-03 21:32:39 +03:00
|
|
|
|
ExprAST *Cond = ParseExpression(IDNames, true);
|
2022-08-29 00:45:55 +03:00
|
|
|
|
if (!Cond) return nullptr;
|
2022-08-23 13:06:01 +02:00
|
|
|
|
|
2022-02-14 12:48:59 +03:00
|
|
|
|
if (CurTok != tok_then)
|
2022-08-23 13:06:01 +02:00
|
|
|
|
return Error("expected then");
|
2022-02-14 12:48:59 +03:00
|
|
|
|
getNextToken(); // Получаем then
|
2022-08-23 13:06:01 +02:00
|
|
|
|
|
2022-09-03 21:32:39 +03:00
|
|
|
|
ExprAST *Then = ParseExpression(IDNames, false);
|
2022-08-29 00:45:55 +03:00
|
|
|
|
if (!Then) return nullptr;
|
2022-08-23 13:06:01 +02:00
|
|
|
|
|
|
|
|
|
|
// if (CurTok != tok_else)
|
|
|
|
|
|
// return Error("expected else");
|
2022-02-14 12:48:59 +03:00
|
|
|
|
ExprAST *Else = nullptr;
|
|
|
|
|
|
if (CurTok == tok_else) {
|
2022-08-23 13:06:01 +02:00
|
|
|
|
getNextToken();
|
2022-09-03 21:32:39 +03:00
|
|
|
|
Else = ParseExpression(IDNames, false);
|
|
|
|
|
|
if (!Else) return nullptr;
|
2022-02-14 12:48:59 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-03-03 22:58:39 +03:00
|
|
|
|
return new IfExprAST(Cond, Then, Else, IDNames);
|
2022-08-23 13:06:01 +02:00
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
/// primary
|
|
|
|
|
|
/// ::= identifierexpr
|
|
|
|
|
|
/// ::= numberexpr
|
|
|
|
|
|
/// ::= parenexpr
|
2022-09-03 21:32:39 +03:00
|
|
|
|
ExprAST *IoTScenario::ParsePrimary(String *IDNames, bool callFromCondition) {
|
2022-02-14 12:48:59 +03:00
|
|
|
|
switch (CurTok) {
|
2022-08-23 13:06:01 +02:00
|
|
|
|
default:
|
2022-08-29 16:01:25 +03:00
|
|
|
|
Serial.println(CurTok);
|
2022-08-23 13:06:01 +02:00
|
|
|
|
return Error("unknown token when expecting an expression");
|
|
|
|
|
|
case tok_identifier: {
|
2022-09-03 21:32:39 +03:00
|
|
|
|
if (callFromCondition && IDNames) {
|
2022-08-23 13:06:01 +02:00
|
|
|
|
String tmpstr = *IDNames;
|
|
|
|
|
|
*IDNames = tmpstr + " " + IdentifierStr + " ";
|
|
|
|
|
|
}
|
2022-09-03 21:32:39 +03:00
|
|
|
|
return ParseIdentifierExpr(IDNames, callFromCondition);
|
2022-08-23 13:06:01 +02:00
|
|
|
|
}
|
|
|
|
|
|
case tok_number:
|
|
|
|
|
|
return ParseNumberExpr();
|
|
|
|
|
|
case '(':
|
2022-09-03 21:32:39 +03:00
|
|
|
|
return ParseParenExpr(IDNames, callFromCondition);
|
2022-08-23 13:06:01 +02:00
|
|
|
|
case '{':
|
2022-09-03 21:32:39 +03:00
|
|
|
|
return ParseBracketsExpr(IDNames, callFromCondition);
|
2022-08-23 13:06:01 +02:00
|
|
|
|
case tok_string:
|
|
|
|
|
|
return ParseQuotesExpr();
|
|
|
|
|
|
case tok_if:
|
|
|
|
|
|
return ParseIfExpr(IDNames);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// binoprhs
|
|
|
|
|
|
/// ::= ('+' primary)*
|
2022-09-03 21:32:39 +03:00
|
|
|
|
ExprAST *IoTScenario::ParseBinOpRHS(int ExprPrec, ExprAST *LHS, String *IDNames, bool callFromCondition) {
|
2022-02-14 12:48:59 +03:00
|
|
|
|
// Если это бинарный оператор, получаем его приоритет
|
|
|
|
|
|
while (1) {
|
2022-08-23 13:06:01 +02:00
|
|
|
|
int TokPrec = GetTokPrecedence();
|
|
|
|
|
|
|
|
|
|
|
|
// Если этот бинарный оператор связывает выражения по крайней мере так же,
|
|
|
|
|
|
// как текущий, то используем его
|
|
|
|
|
|
if (TokPrec < ExprPrec)
|
|
|
|
|
|
return LHS;
|
|
|
|
|
|
|
|
|
|
|
|
// Отлично, мы знаем, что это бинарный оператор.
|
|
|
|
|
|
int BinOp = CurTok;
|
|
|
|
|
|
getNextToken(); // eat binop
|
|
|
|
|
|
|
|
|
|
|
|
// Разобрать первичное выражение после бинарного оператора
|
2022-09-03 21:32:39 +03:00
|
|
|
|
ExprAST *RHS = ParsePrimary(IDNames, callFromCondition);
|
2022-08-29 00:45:55 +03:00
|
|
|
|
if (!RHS) return nullptr;
|
2022-08-23 13:06:01 +02:00
|
|
|
|
|
|
|
|
|
|
// Если BinOp связан с RHS меньшим приоритетом, чем оператор после RHS,
|
|
|
|
|
|
// то берём часть вместе с RHS как LHS.
|
|
|
|
|
|
int NextPrec = GetTokPrecedence();
|
|
|
|
|
|
if (TokPrec < NextPrec) {
|
2022-09-03 21:32:39 +03:00
|
|
|
|
RHS = ParseBinOpRHS(TokPrec + 1, RHS, IDNames, callFromCondition);
|
2022-08-29 00:45:55 +03:00
|
|
|
|
if (RHS == nullptr) return nullptr;
|
2022-08-23 13:06:01 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Собираем LHS/RHS.
|
|
|
|
|
|
LHS = new BinaryExprAST(BinOp, LHS, RHS);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// expression
|
|
|
|
|
|
/// ::= primary binoprhs
|
|
|
|
|
|
///
|
2022-09-03 21:32:39 +03:00
|
|
|
|
ExprAST *IoTScenario::ParseExpression(String *IDNames, bool callFromCondition) {
|
|
|
|
|
|
ExprAST *LHS = ParsePrimary(IDNames, callFromCondition);
|
2022-08-29 00:45:55 +03:00
|
|
|
|
if (!LHS) return nullptr;
|
2022-09-03 21:32:39 +03:00
|
|
|
|
return ParseBinOpRHS(0, LHS, IDNames, callFromCondition);
|
2022-08-23 13:06:01 +02:00
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
|
2022-08-30 14:00:22 +03:00
|
|
|
|
|
|
|
|
|
|
void IoTScenario::loadScenario(String fileName) { // подготавливаем контекст для чтения и интерпретации файла
|
2022-09-04 19:16:08 +03:00
|
|
|
|
if (mode == 0) {
|
|
|
|
|
|
if (file) file.close();
|
|
|
|
|
|
file = FileFS.open(fileName.c_str(), "r");
|
|
|
|
|
|
if (!file) {
|
|
|
|
|
|
Error("Open file scenario error");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (mode == 1) {
|
|
|
|
|
|
file = FileFS.open(fileName.c_str(), "r");
|
|
|
|
|
|
if (!file) {
|
|
|
|
|
|
Error("Open file scenario error");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2022-09-04 11:20:33 +03:00
|
|
|
|
strFromFile = file.readString();
|
2022-09-04 19:16:08 +03:00
|
|
|
|
Serial.printf("strFromFile: %s, %s\n", strFromFile.c_str(), fileName.c_str());
|
2022-09-04 11:20:33 +03:00
|
|
|
|
file.close();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void IoTScenario::exec(String eventIdName) { // посимвольно считываем и сразу интерпретируем сценарий в дерево AST
|
|
|
|
|
|
if (mode == 0 && !file) return;
|
|
|
|
|
|
|
2022-08-30 14:00:22 +03:00
|
|
|
|
LastChar = 0;
|
|
|
|
|
|
CurTok = 0;
|
2022-08-30 23:31:38 +03:00
|
|
|
|
curLine = 1;
|
2022-09-04 19:16:08 +03:00
|
|
|
|
charCount = 0;
|
2022-08-30 14:00:22 +03:00
|
|
|
|
|
2022-09-04 19:16:08 +03:00
|
|
|
|
if (mode == 0) file.seek(0);
|
2022-09-04 11:20:33 +03:00
|
|
|
|
|
|
|
|
|
|
if (mode < 2) {
|
|
|
|
|
|
while (CurTok != EOF) {
|
|
|
|
|
|
switch (CurTok) {
|
|
|
|
|
|
case tok_if: {
|
|
|
|
|
|
IDNames = ""; // сбрасываем накопитель встречающихся идентификаторов в условии
|
|
|
|
|
|
ExprAST *tmpAST = ParseIfExpr(&IDNames);
|
|
|
|
|
|
if (!tmpAST) {
|
|
|
|
|
|
Error("IF Expr wrong.");
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (tmpAST->hasEventIdName(eventIdName)) {
|
|
|
|
|
|
tmpAST->exec();
|
|
|
|
|
|
}
|
|
|
|
|
|
delete tmpAST;
|
|
|
|
|
|
break;}
|
|
|
|
|
|
default: getNextToken(); break;
|
|
|
|
|
|
}
|
2022-02-14 12:48:59 +03:00
|
|
|
|
}
|
2022-08-23 13:06:01 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-02-24 17:18:03 +03:00
|
|
|
|
|
2022-08-23 13:06:01 +02:00
|
|
|
|
IoTScenario::IoTScenario() {
|
2022-02-14 12:48:59 +03:00
|
|
|
|
// Задаём стандартные бинарные операторы.
|
|
|
|
|
|
// 1 - наименьший приоритет.
|
2022-08-23 13:06:01 +02:00
|
|
|
|
BinopPrecedence['='] = 1;
|
|
|
|
|
|
BinopPrecedence['|'] = 5;
|
|
|
|
|
|
BinopPrecedence['&'] = 6;
|
|
|
|
|
|
BinopPrecedence[tok_equal] = 10; // ==
|
2022-02-25 21:51:20 +03:00
|
|
|
|
BinopPrecedence[tok_notequal] = 11; // !=
|
2022-08-23 13:06:01 +02:00
|
|
|
|
BinopPrecedence[tok_lesseq] = 15; // <=
|
|
|
|
|
|
BinopPrecedence[tok_greateq] = 16; // >=
|
2022-02-25 21:51:20 +03:00
|
|
|
|
BinopPrecedence['<'] = 20;
|
|
|
|
|
|
BinopPrecedence['>'] = 21;
|
|
|
|
|
|
BinopPrecedence['+'] = 25;
|
|
|
|
|
|
BinopPrecedence['-'] = 26;
|
2022-08-23 13:06:01 +02:00
|
|
|
|
BinopPrecedence['/'] = 27;
|
2022-02-25 21:51:20 +03:00
|
|
|
|
BinopPrecedence['*'] = 28; // highest.
|
2022-08-23 13:06:01 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-08-30 14:00:22 +03:00
|
|
|
|
IoTScenario::~IoTScenario() {
|
|
|
|
|
|
if (file) file.close();
|
|
|
|
|
|
}
|