From 0b4f771c485bc9988d554fc6daf5fcd4efc10b5c Mon Sep 17 00:00:00 2001 From: biver Date: Mon, 14 Feb 2022 12:48:59 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D1=8F?= =?UTF-8?q?=D0=B5=D0=BC=20=D1=81=D1=86=D0=B5=D0=BD=D0=B0=D1=80=D0=B8=D0=B8?= =?UTF-8?q?=20https://github.com/biveraxe/IoTScenario?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data_svelte/scenario.txt | 13 + include/Main.h | 1 + include/classes/IoTItem.h | 12 +- include/classes/IoTScenario.h | 93 +++++ src/Main.cpp | 8 + src/classes/IoTItem.cpp | 11 +- src/classes/IoTScenario.cpp | 638 ++++++++++++++++++++++++++++++++++ src/modules/AnalogAdc.cpp | 4 +- 8 files changed, 775 insertions(+), 5 deletions(-) create mode 100644 data_svelte/scenario.txt create mode 100644 include/classes/IoTScenario.h create mode 100644 src/classes/IoTScenario.cpp diff --git a/data_svelte/scenario.txt b/data_svelte/scenario.txt new file mode 100644 index 00000000..0e22c536 --- /dev/null +++ b/data_svelte/scenario.txt @@ -0,0 +1,13 @@ +if x > 3 then 1 else x()/2 * x+2; #обратите внимание на приоритет операций +#if 1 < 3 then 1 else 2-1*1+2; +#if 5 < 3 then 1+4 else 2*1*1+2; +#if btn1=1 then rel2 = 1 else rel2 = 0; +#if bt1=1 | timenow>"07:00" then rel2 = 1; +#if 1 < 3 then par+4 else 2*1*1+2 +#if 1 < 3 then "par de" else 3*1*1+2 +#if rel3.run() > 30 then rel2.run(3, 45.1, "wert") else 3*1*1+2 +#if rel2 == 24 then "true" else "false" + +if rel2 != 1 then {rel2 = 12 + 12; rel2 = rel2 + 10;} +if rel2 != 24 then tablo.run("ddd") else "2222222222222" + diff --git a/include/Main.h b/include/Main.h index 88aab34f..304cd18e 100644 --- a/include/Main.h +++ b/include/Main.h @@ -11,3 +11,4 @@ #include "WsServer.h" #include "DeviceList.h" #include "PeriodicTasks.h" +#include "Classes/IoTScenario.h" diff --git a/include/classes/IoTItem.h b/include/classes/IoTItem.h index faa02106..ef02379c 100644 --- a/include/classes/IoTItem.h +++ b/include/classes/IoTItem.h @@ -1,6 +1,10 @@ #pragma once -#include +struct IoTValue { + float valD = 0; + String valS = ""; + bool isDecimal = true; +}; class IoTItem { public: @@ -9,7 +13,7 @@ class IoTItem { void loop(); virtual void doByInterval(); - virtual void execute(String command, String param); + virtual IoTValue execute(String command, std::vector ¶m); void regEvent(String value, String consoleInfo); void regEvent(float value, String consoleInfo); @@ -21,6 +25,8 @@ class IoTItem { unsigned long prevMillis; unsigned long difference; + IoTValue value; // хранение основного значения, котрое обновляется из сценария, execute(), loop() или doByInterval() + protected: String _subtype; String _id; @@ -34,3 +40,5 @@ class IoTItem { int _map4; int _round; // 1, 10, 100, 1000, 10000 }; + +IoTItem* findIoTItem(String name); // поиск экземпляра элемента модуля по имени diff --git a/include/classes/IoTScenario.h b/include/classes/IoTScenario.h new file mode 100644 index 00000000..f6d5ddf6 --- /dev/null +++ b/include/classes/IoTScenario.h @@ -0,0 +1,93 @@ +#pragma once +#include "Global.h" +#include "Classes/IoTItem.h" +#include + +class ExprAST { +public: + virtual ~ExprAST(); + virtual IoTValue* exec(); + virtual int setValue(IoTValue *val); // ret 0 - установка значения не поддерживается наследником +}; + +class IoTScenario { + //===----------------------------------------------------------------------===// + // Lexer (Лексический анализатор) + //===----------------------------------------------------------------------===// + + String IdentifierStr; // Заполняется, если tok_identifier + float NumVal; // Заполняется, если tok_number + char LastChar = ' '; + + /// gettok - Возвращает следующий токен из стандартного потока ввода. + int gettok(); + + //===----------------------------------------------------------------------===// + // Parser (Парсер или Синтаксический Анализатор) + //===----------------------------------------------------------------------===// + + /// CurTok/getNextToken - Предоставляет простой буфер токенов. CurTok - это текущий + /// токен, просматриваемый парсером. getNextToken получает следующий токен от + /// лексического анализатора и обновляет CurTok. + int CurTok; + int getNextToken(); + + /// BinopPrecedence - Содержит приоритеты для бинарных операторов + std::map BinopPrecedence; + + /// GetTokPrecedence - Возвращает приоритет текущего бинарного оператора. + int GetTokPrecedence(); + + /// Error* - Это небольшие вспомогательные функции для обработки ошибок. + ExprAST *Error(const char *Str); + + /// identifierexpr + /// ::= identifier + /// ::= identifier '(' expression* ')' + ExprAST *ParseIdentifierExpr(); + + /// numberexpr ::= number + ExprAST *ParseNumberExpr(); + + /// parenexpr ::= '(' expression ')' + ExprAST *ParseParenExpr(); + + /// bracketsexpr ::= '{' expression '}' + ExprAST *ParseBracketsExpr(); + + /// quotesexpr ::= '"' expression '"' + ExprAST *ParseQuotesExpr(); + + /// ifexpr ::= 'if' expression 'then' expression 'else' expression + ExprAST *ParseIfExpr(); + + /// primary + /// ::= identifierexpr + /// ::= numberexpr + /// ::= parenexpr + ExprAST *ParsePrimary(); + + /// binoprhs + /// ::= ('+' primary)* + ExprAST *ParseBinOpRHS(int ExprPrec, ExprAST *LHS); + + /// expression + /// ::= primary binoprhs + /// + ExprAST *ParseExpression(); + + std::vector ScenarioElements; // корневые элементы дерава + + String *strFromFile; + char getLastChar(); + int strIterator = 0; + + void clearScenarioElements(); + +public: + void loadScenario(String fileName); + void ExecScenario(); + + IoTScenario(); + ~IoTScenario(); +}; \ No newline at end of file diff --git a/src/Main.cpp b/src/Main.cpp index 2cb7b805..a20694b8 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -1,5 +1,7 @@ #include "Main.h" +IoTScenario iotScen; // объект управления сценарием + void setup() { Serial.begin(115200); Serial.flush(); @@ -57,6 +59,10 @@ void setup() { //запуск работы udp asyncUdpInit(); + + //загрузка сценария + iotScen.loadScenario("/scenario.txt"); + iotScen.ExecScenario(); // test Serial.println("-------test start--------"); @@ -88,4 +94,6 @@ void loop() { for (unsigned int i = 0; i < IoTItems.size(); i++) { IoTItems[i]->loop(); } + + //iotScen.ExecScenario(); } diff --git a/src/classes/IoTItem.cpp b/src/classes/IoTItem.cpp index ff964a8c..db69a31f 100644 --- a/src/classes/IoTItem.cpp +++ b/src/classes/IoTItem.cpp @@ -3,6 +3,7 @@ #include "Classes/ScenarioClass3.h" #include "Classes/IoTItem.h" #include "WsServer.h" +#include "ESPConfiguration.h" IoTItem::IoTItem(String parameters) { jsonRead(parameters, "int", _interval); @@ -72,6 +73,14 @@ void IoTItem::regEvent(float value, String consoleInfo = "") { void IoTItem::doByInterval() {} -void IoTItem::execute(String command, String param) {} +IoTValue IoTItem::execute(String command, std::vector ¶m) { return {};} + +IoTItem* findIoTItem(String name) { // поиск элемента модуля в существующей конфигурации + for (unsigned int i = 0; i < IoTItems.size(); i++) { + if(IoTItems[i]->getID() == name) return IoTItems[i]; + } + + return nullptr; +} IoTItem* myIoTItem; \ No newline at end of file diff --git a/src/classes/IoTScenario.cpp b/src/classes/IoTScenario.cpp new file mode 100644 index 00000000..b88b5fbf --- /dev/null +++ b/src/classes/IoTScenario.cpp @@ -0,0 +1,638 @@ +#include + +#pragma once +#include "Global.h" +#include "Classes/IoTItem.h" +#include "Classes/IoTScenario.h" +#include "Utils/FileUtils.h" + +// Лексический анализатор возвращает токены [0-255], если это неизвестны, +// иначе одну из известных единиц кода +enum Token { + 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 +}; + +//===----------------------------------------------------------------------===// +// Abstract Syntax Tree (Абстрактное Синтаксическое Дерево или Дерево Парсинга) +//===----------------------------------------------------------------------===// + +/// ExprAST - Базовый класс для всех узлов выражений. +ExprAST::~ExprAST() {} +IoTValue* ExprAST::exec() {return nullptr;} +int ExprAST::setValue(IoTValue *val) {return 0;} // 0 - установка значения не поддерживается наследником +struct IoTValue zeroIotVal; + +/// NumberExprAST - Класс узла выражения для числовых литералов (Например, "1.0"). +class NumberExprAST : public ExprAST { + IoTValue Val; +public: + NumberExprAST(float val) { Val.valD = val;} + + IoTValue* exec(){ + Serial.printf("Call from NumberExprAST: %f\n", Val.valD); + return &Val; + } +}; + +/// StringExprAST - Класс узла выражения для строковых литералов (Например, "Example with spaces and quotes"). +class StringExprAST : public ExprAST { + IoTValue Val; +public: + StringExprAST(String val) { Val.isDecimal = false; Val.valS = val;} + + IoTValue* exec(){ + Serial.printf("Call from StringExprAST: %s\n", Val.valS.c_str()); + return &Val; + } +}; + +/// VariableExprAST - Класс узла выражения для переменных (например, "a"). +class VariableExprAST : public ExprAST { + String Name; + IoTItem* Item; // ссылка на объект модуля (прямой доступ к идентификатору указанному в сценарии), если получилось найти модуль по ID + +public: + VariableExprAST(const String &name, IoTItem* item) : Name(name), Item(item) {} + + int setValue(IoTValue *val) { + Item->value = *val; // устанавливаем значение в связанном Item модуля напрямую + return 1; + } + + IoTValue* exec() { + 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); + } +}; + +/// BinaryExprAST - Класс узла выражения для бинарных операторов. +class BinaryExprAST : public ExprAST { + signed char Op; + ExprAST *LHS, *RHS; + IoTValue val; + +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(){ + 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; + + Serial.printf("Call from BinaryExprAST: %s\n", printStr.c_str()); + + IoTValue* rhs = RHS->exec(); // получаем значение правого операнда для возможного использования в операции присваивания + + if (Op == '=' && LHS->setValue(rhs)) { // если установка значения не поддерживается, т.е. слева не переменная, то работаем по другим комбинациям далее + return rhs; // иначе возвращаем присвоенное значение справа + } + + 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; + + default: + break; + } + return &val; + } + + if (!lhs->isDecimal && !rhs->isDecimal) { + switch (Op) { + case tok_equal: + val.valD = lhs->valS == rhs->valS; + break; + + default: + break; + } + return &val; + } + } + return nullptr; + } +}; + +/// CallExprAST - Класс узла выражения для вызова команды. +class CallExprAST : public ExprAST { + String Callee; + String Cmd; + std::vector Args; + IoTItem *Item; // ссылка на объект модуля (прямой доступ к идентификатору указанному в сценарии), если получилось найти модуль по ID + IoTValue ret; // хранение возвращаемого значения, т.к. возврат по ссылке осуществляется + +public: + CallExprAST(const String &callee, String &cmd, std::vector &args, IoTItem *item) + : Callee(callee), Cmd(cmd), Args(args), Item(item) {} + + IoTValue* exec() { + if (Item) { + std::vector ArgsAsIoTValue; + for (unsigned int i = 0; i < Args.size(); i++) { + IoTValue *tmp = Args[i]->exec(); + if (tmp != nullptr) ArgsAsIoTValue.push_back(*tmp); + else ArgsAsIoTValue.push_back(zeroIotVal); + } + ret = Item->execute(Cmd, ArgsAsIoTValue); // вызываем команду из модуля напрямую с передачей всех аргументов + } else ret = zeroIotVal; + + 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"); + } +}; + +/// IfExprAST - Класс узла выражения для if/then/else. +class IfExprAST : public ExprAST { + ExprAST *Cond, *Then, *Else; + +public: + IfExprAST(ExprAST *cond, ExprAST *then, ExprAST *_else) + : Cond(cond), Then(then), Else(_else) {} + + IoTValue* exec() { + IoTValue *res_ret = nullptr; + IoTValue *cond_ret = nullptr; + + if (Cond) cond_ret = Cond->exec(); + if (!cond_ret) cond_ret = &zeroIotVal; + if (cond_ret != nullptr && cond_ret->isDecimal && cond_ret->valD) res_ret = Then->exec(); + else if (Else) 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"); + } +}; + +/// BracketsExprAST - Класс узла блока кода {}. +class BracketsExprAST : public ExprAST { + std::vector BracketsList; + +public: + BracketsExprAST(std::vector &bracketsList) + : BracketsList(bracketsList) {} + + IoTValue* exec() { + Serial.printf("Call from BracketsExprAST OperCount = %d \n", BracketsList.size()); + + IoTValue* lastExecValue; + for (unsigned int i = 0; i < BracketsList.size(); i++) { + lastExecValue = BracketsList[i]->exec(); + } + + return lastExecValue; + } + + ~BracketsExprAST() { + for (unsigned int i = 0; i < BracketsList.size(); i++) { + if (BracketsList[i]) delete BracketsList[i]; + } + BracketsList.clear(); + + Serial.printf("Call from BracketsExprAST delete\n"); + } +}; + + + //===----------------------------------------------------------------------===// + // Lexer (Лексический анализатор) + //===----------------------------------------------------------------------===// + + + char IoTScenario::getLastChar() { + strIterator++; + return strFromFile->charAt(strIterator - 1); + } + + /// gettok - Возвращает следующий токен из стандартного потока ввода. + int IoTScenario::gettok() { + + // Пропускаем пробелы. + while (isspace(LastChar)) + LastChar = getLastChar(); + + if (isalpha(LastChar)) { // идентификатор: [a-zA-Z][a-zA-Z0-9]* + IdentifierStr = LastChar; + while (isalnum((LastChar = getLastChar()))){ + IdentifierStr += LastChar; + } + + //Serial.printf("%s ", IdentifierStr.c_str()); + + if (IdentifierStr == "if") return tok_if; + if (IdentifierStr == "then") return tok_then; + if (IdentifierStr == "else") return tok_else; + return tok_identifier; + } + + if (isdigit(LastChar)) { // Число: [0-9.]+ + String NumStr; + do { + NumStr += LastChar; + LastChar = getLastChar(); + } while (isdigit(LastChar) || LastChar == '.'); + + NumVal = strtod(NumStr.c_str(), 0); + return tok_number; + } + + if (LastChar == '#') { + // Комментарий до конца строки + do LastChar = getLastChar(); + while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); + + if (LastChar != EOF) + return gettok(); + } + + if (LastChar == '"') { // "строка" + IdentifierStr = ""; + LastChar = getLastChar(); + while (LastChar != '"') { + IdentifierStr += LastChar; + LastChar = getLastChar(); + } + LastChar = getLastChar(); + + return tok_string; + } + + // Проверка конца файла. + //if (LastChar == EOF) + // return tok_eof; + + if (LastChar == '=') { + LastChar = getLastChar(); + if (LastChar == '=') { + LastChar = getLastChar(); + return tok_equal; + } else return '='; + } + + if (LastChar == '!') { + LastChar = getLastChar(); + if (LastChar == '=') { + LastChar = getLastChar(); + return tok_notequal; + } else return '!'; + } + + if (LastChar == '<') { + LastChar = getLastChar(); + if (LastChar == '=') { + LastChar = getLastChar(); + return tok_lesseq; + } else return '<'; + } + + if (LastChar == '>') { + LastChar = getLastChar(); + if (LastChar == '=') { + LastChar = getLastChar(); + return tok_greateq; + } else return '>'; + } + + // В противном случае просто возвращаем символ как значение ASCII + int ThisChar = LastChar; + LastChar = getLastChar(); + return ThisChar; + } + + + //===----------------------------------------------------------------------===// + // Parser (Парсер или Синтаксический Анализатор) + //===----------------------------------------------------------------------===// + + + /// CurTok/getNextToken - Предоставляет простой буфер токенов. CurTok - это текущий + /// токен, просматриваемый парсером. getNextToken получает следующий токен от + /// лексического анализатора и обновляет CurTok. + int IoTScenario::getNextToken() { + return CurTok = gettok(); + } + + /// GetTokPrecedence - Возвращает приоритет текущего бинарного оператора. + int IoTScenario::GetTokPrecedence() { + if (!(isascii(CurTok) || BinopPrecedence.count(CurTok))) + return -1; + + // Удостоверимся, что это объявленный бинарный оператор. + int TokPrec = BinopPrecedence[CurTok]; + if (TokPrec <= 0) return -1; + return TokPrec; + } + + /// Error* - Это небольшие вспомогательные функции для обработки ошибок. + ExprAST* IoTScenario::Error(const char *Str) { Serial.printf("Error: %s\n", Str); return nullptr;} + + + /// identifierexpr + /// ::= identifier + /// ::= identifier '(' expression* ')' + ExprAST* IoTScenario::ParseIdentifierExpr() { + String IdName = IdentifierStr; + String Cmd = ""; + IoTItem* tmpItem = findIoTItem(IdName); + + getNextToken(); // получаем идентификатор. + + if (CurTok == '.') { + getNextToken(); + Cmd = IdentifierStr; + getNextToken(); + } + + if (CurTok != '(') { // Обычная переменная. + if (tmpItem) return new VariableExprAST(IdName, tmpItem); + else return new StringExprAST("id " + IdName + " not_found"); + } + + // Вызов функции. + getNextToken(); // получаем ( + std::vector Args; + if (CurTok != ')') { + while (1) { + ExprAST *Arg = ParseExpression(); + if (!Arg) return 0; + Args.push_back(Arg); + + if (CurTok == ')') break; + + if (CurTok != ',') + return Error("Expected ')' or ',' in argument list"); + getNextToken(); + } + } + + // Получаем ')'. + getNextToken(); + + if (tmpItem) return new CallExprAST(IdName, Cmd, Args, tmpItem); + else return new StringExprAST("id " + IdName + " not_found"); + } + + /// numberexpr ::= number + ExprAST* IoTScenario::ParseNumberExpr() { + ExprAST *Result = new NumberExprAST(NumVal); + getNextToken(); // получаем число + return Result; + } + + /// parenexpr ::= '(' expression ')' + ExprAST* IoTScenario::ParseParenExpr() { + getNextToken(); // получаем (. + ExprAST *V = ParseExpression(); + if (!V) return 0; + + if (CurTok != ')') + return Error("expected ')'"); + getNextToken(); // получаем ). + return V; + } + + /// bracketsexpr ::= '{' expression '}' + ExprAST* IoTScenario::ParseBracketsExpr() { + getNextToken(); // получаем {. + std::vector bracketsList; + if (CurTok != '}') { + while (1) { + ExprAST *Expr = ParseExpression(); + if (!Expr) return 0; + bracketsList.push_back(Expr); + + if (CurTok != ';') + return Error("Expected '}' or ';' in operation list"); + getNextToken(); + + if (CurTok == '}') break; + } + } + + getNextToken(); // получаем }. + return new BracketsExprAST(bracketsList); + } + + /// quotesexpr ::= '"' expression '"' + ExprAST* IoTScenario::ParseQuotesExpr() { + String StringCont = IdentifierStr; + ExprAST *Result = new StringExprAST(StringCont); + getNextToken(); // получаем число + return Result; + } + + /// ifexpr ::= 'if' expression 'then' expression 'else' expression + ExprAST* IoTScenario::ParseIfExpr() { + getNextToken(); // Получаем if. + + // условие. + ExprAST *Cond = ParseExpression(); + if (!Cond) return 0; + + if (CurTok != tok_then) + return Error("expected then"); + getNextToken(); // Получаем then + + ExprAST *Then = ParseExpression(); + if (Then == 0) return 0; + + //if (CurTok != tok_else) + // return Error("expected else"); + ExprAST *Else = nullptr; + if (CurTok == tok_else) { + getNextToken(); + Else = ParseExpression(); + } + + return new IfExprAST(Cond, Then, Else); + } + + /// primary + /// ::= identifierexpr + /// ::= numberexpr + /// ::= parenexpr + ExprAST* IoTScenario::ParsePrimary() { + switch (CurTok) { + default: return Error("unknown token when expecting an expression"); + case tok_identifier: return ParseIdentifierExpr(); + case tok_number: return ParseNumberExpr(); + case '(': return ParseParenExpr(); + case '{': return ParseBracketsExpr(); + case tok_string: return ParseQuotesExpr(); + case tok_if: return ParseIfExpr(); + } + } + + /// binoprhs + /// ::= ('+' primary)* + ExprAST* IoTScenario::ParseBinOpRHS(int ExprPrec, ExprAST *LHS) { + // Если это бинарный оператор, получаем его приоритет + while (1) { + int TokPrec = GetTokPrecedence(); + + // Если этот бинарный оператор связывает выражения по крайней мере так же, + // как текущий, то используем его + if (TokPrec < ExprPrec) + return LHS; + + // Отлично, мы знаем, что это бинарный оператор. + int BinOp = CurTok; + getNextToken(); // eat binop + + // Разобрать первичное выражение после бинарного оператора + ExprAST *RHS = ParsePrimary(); + if (!RHS) return 0; + + // Если BinOp связан с RHS меньшим приоритетом, чем оператор после RHS, + // то берём часть вместе с RHS как LHS. + int NextPrec = GetTokPrecedence(); + if (TokPrec < NextPrec) { + RHS = ParseBinOpRHS(TokPrec+1, RHS); + if (RHS == 0) return 0; + } + + // Собираем LHS/RHS. + LHS = new BinaryExprAST(BinOp, LHS, RHS); + } + } + + + /// expression + /// ::= primary binoprhs + /// + ExprAST* IoTScenario::ParseExpression() { + ExprAST *LHS = ParsePrimary(); + if (!LHS) return 0; + return ParseBinOpRHS(0, LHS); + } + + void IoTScenario::clearScenarioElements() { // удаляем все корневые элементы дерева AST + for (unsigned int i = 0; i < ScenarioElements.size(); i++) { + if (ScenarioElements[i]) delete ScenarioElements[i]; + } + ScenarioElements.clear(); + } + + void IoTScenario::loadScenario(String fileName) { // посимвольно считываем и сразу интерпретируем сценарий в дерево AST + clearScenarioElements(); // удаляем все корневые элементы перед загрузкой новых. + LastChar = ' '; + + File myfile = seekFile(fileName); + if (myfile.available()) { + strFromFile = new String(""); + *strFromFile = myfile.readString(); + myfile.close(); + + getNextToken(); + while (strIterator < strFromFile->length()-1) { + //Serial.printf("-%c", LastChar); + switch (CurTok) { + //case tok_eof: return; + //case ';': getNextToken(); break; // игнорируем верхнеуровневые точки с запятой. + case tok_if: ScenarioElements.push_back(ParseExpression()); break; + default: getNextToken(); break; + } + } + delete strFromFile; + strIterator = 0; + } else {Error("Open file scenario error");} + } + + void IoTScenario::ExecScenario() { // запускаем поочереди все корневые элементы выражений в сценарии, ожидаемо - это IFы + Serial.printf("Count root elements in scenario: %d\n", ScenarioElements.size()); + for (unsigned int i = 0; i < ScenarioElements.size(); i++) { + if (ScenarioElements[i]) ScenarioElements[i]->exec(); + } + } + + IoTScenario::IoTScenario() { + // Задаём стандартные бинарные операторы. + // 1 - наименьший приоритет. + BinopPrecedence['='] = 1; + BinopPrecedence[tok_equal] = 3; // == + BinopPrecedence[tok_notequal] = 4; // != + BinopPrecedence[tok_lesseq] = 5; // <= + BinopPrecedence[tok_greateq] = 6; // >= + BinopPrecedence['<'] = 10; + BinopPrecedence['>'] = 10; + BinopPrecedence['+'] = 20; + BinopPrecedence['-'] = 20; + BinopPrecedence['/'] = 35; + BinopPrecedence['*'] = 40; // highest. + } + + IoTScenario::~IoTScenario() {} \ No newline at end of file diff --git a/src/modules/AnalogAdc.cpp b/src/modules/AnalogAdc.cpp index b7251e6a..ff274289 100644 --- a/src/modules/AnalogAdc.cpp +++ b/src/modules/AnalogAdc.cpp @@ -32,9 +32,9 @@ class AnalogAdc : public IoTItem { //не используйте delay - помните, что данный loop общий для всех модулей. Если у вас планируется длительная операция, постарайтесь разбить ее на порции //и выполнить за несколько тактов void doByInterval() { - float value = analogRead(_pin); + value.valD = analogRead(_pin); - regEvent(value, "AnalogAdc"); //обязательный вызов хотяб один + regEvent(value.valD, "AnalogAdc"); //обязательный вызов хотяб один } //=======================================================================================================