Merge pull request #176 from biveraxe/ver4dev

Обновляем сценарии: блоки, чтение из файла, ошибки
This commit is contained in:
2022-08-30 14:01:29 +03:00
committed by GitHub
6 changed files with 74 additions and 87 deletions

0
data_svelte/scenario.txt Normal file
View File

View File

@@ -18,7 +18,7 @@ class IoTScenario {
String IdentifierStr; // Заполняется, если tok_identifier String IdentifierStr; // Заполняется, если tok_identifier
float NumVal; // Заполняется, если tok_number float NumVal; // Заполняется, если tok_number
char LastChar = ' '; int LastChar;
/// gettok - Возвращает следующий токен из стандартного потока ввода. /// gettok - Возвращает следующий токен из стандартного потока ввода.
int gettok(); int gettok();
@@ -32,6 +32,7 @@ class IoTScenario {
/// лексического анализатора и обновляет CurTok. /// лексического анализатора и обновляет CurTok.
int CurTok; int CurTok;
int getNextToken(); int getNextToken();
String IDNames; // накопитель встречающихся идентификаторов в условии
/// BinopPrecedence - Содержит приоритеты для бинарных операторов /// BinopPrecedence - Содержит приоритеты для бинарных операторов
std::map<signed char, int> BinopPrecedence; std::map<signed char, int> BinopPrecedence;
@@ -77,17 +78,12 @@ class IoTScenario {
/// ///
ExprAST *ParseExpression(String *IDNames); ExprAST *ParseExpression(String *IDNames);
std::vector<ExprAST *> ScenarioElements; // корневые элементы дерава int getLastChar();
fs::File file;
String *strFromFile;
char getLastChar();
int strIterator = 0;
void clearScenarioElements();
public: public:
void loadScenario(String fileName); void loadScenario(String fileName);
void ExecScenario(String eventIdName); void exec(String eventIdName);
IoTScenario(); IoTScenario();
~IoTScenario(); ~IoTScenario();

View File

@@ -52,7 +52,7 @@ void handleEvent() {
//здесь нужно пропускать данное событие через условия сценариев //здесь нужно пропускать данное событие через условия сценариев
//и если оно есть в условии сценария и совподает //и если оно есть в условии сценария и совподает
iotScen.ExecScenario(selectToMarker(event, " ")); iotScen.exec(selectToMarker(event, " "));
eventBuf = deleteBeforeDelimiter(eventBuf, ","); eventBuf = deleteBeforeDelimiter(eventBuf, ",");
} }

View File

@@ -62,9 +62,10 @@ void setup() {
//запуск работы udp //запуск работы udp
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

@@ -75,9 +75,24 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length)
} }
if (headerStr == "/oiranecs|") { if (headerStr == "/oiranecs|") {
writeFileUint8tByFrames("scenario.json", payload, length, headerLenth, 256); writeFileUint8tByFrames("scenario.json", payload, length, headerLenth, 256);
String strFromFile;
File myfile = seekFile("/scenario.json");
if (myfile.available()) {
strFromFile = myfile.readString();
strFromFile.replace("{\"scen\":\"", "");
strFromFile.replace("\\n", "\n");
strFromFile.replace("\\\"", "\"");
strFromFile.remove(strFromFile.length() - 2, 2);
}
myfile.close();
writeFile("/scenario.txt", strFromFile);
clearConfigure(); clearConfigure();
configure("/config.json"); configure("/config.json");
iotScen.loadScenario("/scenario.json"); 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

@@ -1,5 +1,3 @@
#include <fstream>
#pragma once #pragma once
#include "Global.h" #include "Global.h"
#include "classes/IoTItem.h" #include "classes/IoTItem.h"
@@ -7,6 +5,7 @@
#include "utils/FileUtils.h" #include "utils/FileUtils.h"
#include "NTP.h" #include "NTP.h"
bool isIotScenException; // признак исключения и попытки прекратить выполнение сценария заранее bool isIotScenException; // признак исключения и попытки прекратить выполнение сценария заранее
// Лексический анализатор возвращает токены [0-255], если это неизвестны, // Лексический анализатор возвращает токены [0-255], если это неизвестны,
@@ -586,9 +585,9 @@ class BracketsExprAST : public ExprAST {
// Lexer (Лексический анализатор) // Lexer (Лексический анализатор)
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
char IoTScenario::getLastChar() { int IoTScenario::getLastChar() {
strIterator++; if (file) return file.read();
return strFromFile->charAt(strIterator - 1); else return EOF;
} }
/// gettok - Возвращает следующий токен из стандартного потока ввода. /// gettok - Возвращает следующий токен из стандартного потока ввода.
@@ -598,9 +597,9 @@ int IoTScenario::gettok() {
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 = (char)LastChar;
while (isalnum((LastChar = getLastChar())) || LastChar == '_') { while (isalnum((LastChar = getLastChar())) || LastChar == '_') {
IdentifierStr += LastChar; IdentifierStr += (char)LastChar;
} }
// Serial.printf("%s ", IdentifierStr.c_str()); // Serial.printf("%s ", IdentifierStr.c_str());
@@ -614,7 +613,7 @@ int IoTScenario::gettok() {
if (isdigit(LastChar)) { // Число: [0-9.]+ if (isdigit(LastChar)) { // Число: [0-9.]+
String NumStr; String NumStr;
do { do {
NumStr += LastChar; NumStr += (char)LastChar;
LastChar = getLastChar(); LastChar = getLastChar();
} while (isdigit(LastChar) || LastChar == '.'); } while (isdigit(LastChar) || LastChar == '.');
@@ -634,8 +633,8 @@ int IoTScenario::gettok() {
if (LastChar == '"') { // "строка" if (LastChar == '"') { // "строка"
IdentifierStr = ""; IdentifierStr = "";
LastChar = getLastChar(); LastChar = getLastChar();
while (LastChar != '"') { while (LastChar != '"' && LastChar != EOF) {
IdentifierStr += LastChar; IdentifierStr += (char)LastChar;
LastChar = getLastChar(); LastChar = getLastChar();
} }
LastChar = getLastChar(); LastChar = getLastChar();
@@ -644,8 +643,8 @@ int IoTScenario::gettok() {
} }
// Проверка конца файла. // Проверка конца файла.
// if (LastChar == EOF) if (LastChar == EOF)
// return tok_eof; return tok_eof;
if (LastChar == '=') { if (LastChar == '=') {
LastChar = getLastChar(); LastChar = getLastChar();
@@ -682,7 +681,7 @@ int IoTScenario::gettok() {
} else } else
return '>'; return '>';
} }
// В противном случае просто возвращаем символ как значение ASCII // В противном случае просто возвращаем символ как значение ASCII
int ThisChar = LastChar; int ThisChar = LastChar;
LastChar = getLastChar(); LastChar = getLastChar();
@@ -747,7 +746,7 @@ ExprAST *IoTScenario::ParseIdentifierExpr(String *IDNames) {
if (CurTok != ')') { if (CurTok != ')') {
while (1) { while (1) {
ExprAST *Arg = ParseExpression(IDNames); ExprAST *Arg = ParseExpression(IDNames);
if (!Arg) return 0; if (!Arg) return nullptr;
Args.push_back(Arg); Args.push_back(Arg);
if (CurTok == ')') break; if (CurTok == ')') break;
@@ -778,7 +777,7 @@ ExprAST *IoTScenario::ParseNumberExpr() {
ExprAST *IoTScenario::ParseParenExpr() { ExprAST *IoTScenario::ParseParenExpr() {
getNextToken(); // получаем (. getNextToken(); // получаем (.
ExprAST *V = ParseExpression(nullptr); ExprAST *V = ParseExpression(nullptr);
if (!V) return 0; if (!V) return nullptr;
if (CurTok != ')') if (CurTok != ')')
return Error("expected ')'"); return Error("expected ')'");
@@ -793,7 +792,7 @@ ExprAST *IoTScenario::ParseBracketsExpr() {
if (CurTok != '}') { if (CurTok != '}') {
while (1) { while (1) {
ExprAST *Expr = ParseExpression(nullptr); ExprAST *Expr = ParseExpression(nullptr);
if (!Expr) return 0; if (!Expr) return nullptr;
bracketsList.push_back(Expr); bracketsList.push_back(Expr);
if (CurTok != ';') if (CurTok != ';')
@@ -826,14 +825,14 @@ ExprAST *IoTScenario::ParseIfExpr(String *IDNames) {
// условие. // условие.
ExprAST *Cond = ParseExpression(IDNames); ExprAST *Cond = ParseExpression(IDNames);
if (!Cond) return 0; if (!Cond) return nullptr;
if (CurTok != tok_then) if (CurTok != tok_then)
return Error("expected then"); return Error("expected then");
getNextToken(); // Получаем then getNextToken(); // Получаем then
ExprAST *Then = ParseExpression(nullptr); ExprAST *Then = ParseExpression(nullptr);
if (!Then) return 0; if (!Then) return nullptr;
// if (CurTok != tok_else) // if (CurTok != tok_else)
// return Error("expected else"); // return Error("expected else");
@@ -853,6 +852,7 @@ ExprAST *IoTScenario::ParseIfExpr(String *IDNames) {
ExprAST *IoTScenario::ParsePrimary(String *IDNames) { ExprAST *IoTScenario::ParsePrimary(String *IDNames) {
switch (CurTok) { switch (CurTok) {
default: default:
Serial.println(CurTok);
return Error("unknown token when expecting an expression"); return Error("unknown token when expecting an expression");
case tok_identifier: { case tok_identifier: {
if (IDNames) { if (IDNames) {
@@ -892,14 +892,14 @@ ExprAST *IoTScenario::ParseBinOpRHS(int ExprPrec, ExprAST *LHS, String *IDNames)
// Разобрать первичное выражение после бинарного оператора // Разобрать первичное выражение после бинарного оператора
ExprAST *RHS = ParsePrimary(IDNames); ExprAST *RHS = ParsePrimary(IDNames);
if (!RHS) return 0; if (!RHS) return nullptr;
// Если BinOp связан с RHS меньшим приоритетом, чем оператор после RHS, // Если BinOp связан с RHS меньшим приоритетом, чем оператор после RHS,
// то берём часть вместе с 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 == nullptr) return nullptr;
} }
// Собираем LHS/RHS. // Собираем LHS/RHS.
@@ -912,68 +912,41 @@ ExprAST *IoTScenario::ParseBinOpRHS(int ExprPrec, ExprAST *LHS, String *IDNames)
/// ///
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 nullptr;
return ParseBinOpRHS(0, LHS, IDNames); return ParseBinOpRHS(0, LHS, IDNames);
} }
void IoTScenario::clearScenarioElements() { // удаляем все корневые элементы дерева AST
for (unsigned int i = 0; i < ScenarioElements.size(); i++) { void IoTScenario::loadScenario(String fileName) { // подготавливаем контекст для чтения и интерпретации файла
if (ScenarioElements[i]) delete ScenarioElements[i]; if (file) file.close();
} file = FileFS.open(fileName, "r");
ScenarioElements.clear();
} }
void IoTScenario::loadScenario(String fileName) { // посимвольно считываем и сразу интерпретируем сценарий в дерево AST void IoTScenario::exec(String eventIdName) { // посимвольно считываем и сразу интерпретируем сценарий в дерево AST
clearScenarioElements(); // удаляем все корневые элементы перед загрузкой новых. if (!file) {
LastChar = ' ';
File myfile = seekFile(fileName);
if (myfile.available()) {
strFromFile = new String("");
String strFromF = myfile.readString();
Serial.println(strFromF);
jsonRead(strFromF, "scen", *strFromFile, true);
myfile.close();
// Serial.println(*strFromFile);
if (strFromFile->length()) {
getNextToken();
while (strIterator < strFromFile->length() - 1) {
// Serial.printf("-%c", LastChar);
switch (CurTok) {
// case tok_eof: return;
// case ';': getNextToken(); break; // игнорируем верхнеуровневые точки с запятой.
case tok_if: {
String IDNames = ""; // накопитель встречающихся идентификаторов в условии
ScenarioElements.push_back(ParseIfExpr(&IDNames));
break;
}
default:
getNextToken();
break;
}
}
}
delete strFromFile;
strIterator = 0;
} else {
Error("Open file scenario error"); Error("Open file scenario error");
return;
}
LastChar = 0;
CurTok = 0;
file.seek(0);
while ((getNextToken()) != EOF) {
switch (CurTok) {
case tok_if: {
IDNames = ""; // сбрасываем накопитель встречающихся идентификаторов в условии
ExprAST *tmpAST = ParseIfExpr(&IDNames);
if (!tmpAST) break;
if (tmpAST->hasEventIdName(eventIdName)) {
tmpAST->exec();
}
delete tmpAST;
break;}
}
} }
} }
void IoTScenario::ExecScenario(String eventIdName) { // запускаем поочереди все корневые элементы выражений в сценарии, ожидаемо - это IFы
// eventIdName - ID элемента для которого выполняем сценарий, т.е. игнорируем любые проверки, если нет такого ID в условиях
isIotScenException = false;
// 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]->hasEventIdName(eventIdName)) ScenarioElements[i]->exec();
// else Serial.printf("Call from ExecScenario: Skip ifexec because %s not found\n", eventIdName.c_str());
if (isIotScenException) return;
}
}
IoTScenario::IoTScenario() { IoTScenario::IoTScenario() {
// Задаём стандартные бинарные операторы. // Задаём стандартные бинарные операторы.
@@ -993,4 +966,6 @@ IoTScenario::IoTScenario() {
BinopPrecedence['*'] = 28; // highest. BinopPrecedence['*'] = 28; // highest.
} }
IoTScenario::~IoTScenario() {} IoTScenario::~IoTScenario() {
if (file) file.close();
}