mirror of
https://github.com/IoTManagerProject/IoTManager.git
synced 2026-03-26 22:22:16 +03:00
Merge pull request #131 from biveraxe/ver4dev
Добавляем сценарии https://github.com/biveraxe/IoTScenario
This commit is contained in:
13
data_svelte/scenario.txt
Normal file
13
data_svelte/scenario.txt
Normal file
@@ -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"
|
||||
|
||||
@@ -11,3 +11,4 @@
|
||||
#include "WsServer.h"
|
||||
#include "DeviceList.h"
|
||||
#include "PeriodicTasks.h"
|
||||
#include "Classes/IoTScenario.h"
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <WString.h>
|
||||
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<IoTValue> ¶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); // поиск экземпляра элемента модуля по имени
|
||||
|
||||
93
include/classes/IoTScenario.h
Normal file
93
include/classes/IoTScenario.h
Normal file
@@ -0,0 +1,93 @@
|
||||
#pragma once
|
||||
#include "Global.h"
|
||||
#include "Classes/IoTItem.h"
|
||||
#include <map>
|
||||
|
||||
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<signed char, int> 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<ExprAST*> ScenarioElements; // корневые элементы дерава
|
||||
|
||||
String *strFromFile;
|
||||
char getLastChar();
|
||||
int strIterator = 0;
|
||||
|
||||
void clearScenarioElements();
|
||||
|
||||
public:
|
||||
void loadScenario(String fileName);
|
||||
void ExecScenario();
|
||||
|
||||
IoTScenario();
|
||||
~IoTScenario();
|
||||
};
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "Main.h"
|
||||
|
||||
IoTScenario iotScen; // объект управления сценарием
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.flush();
|
||||
@@ -58,6 +60,10 @@ void setup() {
|
||||
//запуск работы udp
|
||||
asyncUdpInit();
|
||||
|
||||
//загрузка сценария
|
||||
iotScen.loadScenario("/scenario.txt");
|
||||
iotScen.ExecScenario();
|
||||
|
||||
// test
|
||||
Serial.println("-------test start--------");
|
||||
Serial.println("--------test end---------");
|
||||
@@ -88,4 +94,6 @@ void loop() {
|
||||
for (unsigned int i = 0; i < IoTItems.size(); i++) {
|
||||
IoTItems[i]->loop();
|
||||
}
|
||||
|
||||
//iotScen.ExecScenario();
|
||||
}
|
||||
|
||||
@@ -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<IoTValue> ¶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;
|
||||
638
src/classes/IoTScenario.cpp
Normal file
638
src/classes/IoTScenario.cpp
Normal file
@@ -0,0 +1,638 @@
|
||||
#include <fstream>
|
||||
|
||||
#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<ExprAST*> Args;
|
||||
IoTItem *Item; // ссылка на объект модуля (прямой доступ к идентификатору указанному в сценарии), если получилось найти модуль по ID
|
||||
IoTValue ret; // хранение возвращаемого значения, т.к. возврат по ссылке осуществляется
|
||||
|
||||
public:
|
||||
CallExprAST(const String &callee, String &cmd, std::vector<ExprAST*> &args, IoTItem *item)
|
||||
: Callee(callee), Cmd(cmd), Args(args), Item(item) {}
|
||||
|
||||
IoTValue* exec() {
|
||||
if (Item) {
|
||||
std::vector<IoTValue> 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<ExprAST*> BracketsList;
|
||||
|
||||
public:
|
||||
BracketsExprAST(std::vector<ExprAST*> &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<ExprAST*> 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<ExprAST*> 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() {}
|
||||
@@ -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"); //обязательный вызов хотяб один
|
||||
}
|
||||
//=======================================================================================================
|
||||
|
||||
|
||||
Reference in New Issue
Block a user