jenya7 0 15 мая, 2019 Опубликовано 15 мая, 2019 (изменено) · Жалоба В продолжение темы с уважаемым xvr. 14 hours ago, xvr said: Нашёл один свой движок, но вам он похоже не поможет - слишком полнофункциональный :( (И большой) Вот пример того, что ему можно дать на вход: (Он встраивался в WEB сервер) Вот выхлоп (в виде листинга) первой функции: Давайте лучше ваш случай рассмотрим. Что может быть в условии IF и в его теле? Все IF'ы выполняются последовательно или до первого сработавшего? Где выполняется трансляция программы (в МК или на хосте)? Куда записывается результат? (В FLASH, внешний DataFLASH или ещё куда)? Мне нужно исполнять скрипт. Пользователь передает его в микроконтролер, скрипт сохраняется (в FLASH) и исполняется. в основном это проверка входных условий (переменных) и если условия выполнились - изменение выходных условий (переменных). Самоя сложное выражение (пока) это к примеру такое Quote IF DIR=2 AND POS0>POS1 AND POS0-POS1>20 THEN PWM0-=100 AND PWM1+=100 Выражений может быть до .... ну не знаю пока 40. в IF все AND - поэтому если хоть одно условие не выполниться THEN не исполняется. Для начала я сделал лексер Spoiler char *ToLowerCase(char *str) { int i; for(i = 0; i < strlen(str); i++) { if(str[i]>='A' && str[i]<='Z') str[i]=str[i]+32; } //*str++ = '\0'; return str; } uint32_t IsAlphaNumeric(char c) { return ( ( c > 64 && c < 91 ) || (c > 96 && c < 123) || (c > 47 && c < 58) ); } uint32_t IsLetter(char c) { return (( c > 64 && c < 91 ) || (c > 96 && c < 123)); } uint32_t IsDigit(char c) { return (c > 47 && c < 58); } uint32_t IsNum(char c) { return ((c > 47 && c < 58) || c == '.' /*|| c == '-'*/); } uint32_t IsCompare(char c) { return ((c == '>') || (c == '<') || (c == '=') || (c == '!')); } uint32_t IsMath(char c) { return ((c == '+') || (c == '-') || (c == '*') || (c == '/') || (c == '=')); } uint32_t IsBitLogic(char c) { return ((c == '|') || (c == '&')); } uint32_t IsGroup (char c) { return ((c == '(') || (c == ')')); } uint32_t IsEnd(char c) { return (c == ';'); } uint32_t IsEndOfLine(char c) { return ((c == '\n') || (c == '\r')); } uint32_t IsLogic(char *str) { char *l_str = ToLower(str); return ( (strcmp(l_str,"or")==0) || (strcmp(l_str,"and")==0) || (strcmp(l_str,"||")==0) || (strcmp(l_str,"&&")==0)); } uint32_t IsIn(char *str) { char *l_str = ToLower(str); return ( (strcmp(l_str,"in")==0)); } uint32_t IsOut(char *str) { char *l_str = ToLower(str); return ( (strcmp(l_str,"out")==0)); } uint32_t IsIf(char *str) { char *l_str = ToLower(str); return ( (strcmp(l_str,"if")==0)); } uint32_t IsThen(char *str) { char *l_str = ToLower(str); return ( (strcmp(l_str,"then")==0)); } uint32_t LEXER_GetToken(char *expr, TOKEN *token, uint32_t *exp_idx) { //uint32_t idx = 0; uint32_t i = 0; uint32_t slen = strlen(expr); uint32_t space = 0; //end of expression if(expr[*exp_idx]=='\0') { (*exp_idx)++; return LEXER_OK; } //skip spaces while(expr[*exp_idx] == ' ') { //token->type = Space; space = 1; (*exp_idx)++; if (*exp_idx > slen) return LEXER_FAIL; } //get compare if (IsCompare(expr[*exp_idx])) { i = 0; while (IsCompare(expr[*exp_idx])) { token->name[i++] = expr[(*exp_idx)++]; if ( (i > 2) || (*exp_idx > slen)) return LEXER_FAIL; } token->name[i] = '\0'; token->type = Compare; return LEXER_OK; } //get a variable - start with a letter if (IsLetter(expr[*exp_idx])) { i = 0; while (IsLetter(expr[*exp_idx]) || IsDigit(expr[*exp_idx])) { token->name[i++] = expr[(*exp_idx)++]; if ( (i > TOKEN_MAX_SIZE) || (*exp_idx > slen)) return LEXER_FAIL; } token->name[i] = '\0'; if (IsIn(token->name)) token->type = In; else if (IsOut(token->name)) token->type = Out; else if (IsLogic(token->name)) token->type = Logic; else if (IsIf(token->name)) token->type = If; else if (IsThen(token->name)) token->type = Then; else token->type = Alphanumeric; return LEXER_OK; } //get a number if (IsNum(expr[*exp_idx])) { i = 0; while (IsDigit(expr[*exp_idx])) { token->name[i++] = expr[(*exp_idx)++]; if ( (i > TOKEN_MAX_SIZE) || (*exp_idx > slen) ) return LEXER_FAIL; } token->name[i] = '\0'; token->type = Number; return LEXER_OK; } //get an arithmetic if (IsMath(expr[*exp_idx])) { // '-' may be operand or negative number if (expr[*exp_idx] == '-') { i = 0; if (space == 1) { space = 0; token->name[i++] = expr[(*exp_idx)++]; if (IsDigit(expr[*exp_idx])) { while (IsDigit(expr[*exp_idx])) { token->name[i++] = expr[(*exp_idx)++]; if ( (i > TOKEN_MAX_SIZE) || (*exp_idx > slen) ) return LEXER_FAIL; } token->name[i] = '\0'; token->type = Number; return LEXER_OK; } else { while (IsMath(expr[*exp_idx])) { token->name[i++] = expr[(*exp_idx)++]; if ( (i > 2) || (*exp_idx > slen) ) return LEXER_FAIL; } token->name[i] = '\0'; token->type = Math; return LEXER_OK; } } else { while (IsMath(expr[*exp_idx])) { token->name[i++] = expr[(*exp_idx)++]; if ( (i > 2) || (*exp_idx > slen) ) return LEXER_FAIL; } token->name[i] = '\0'; token->type = Math; return LEXER_OK; } } else { i = 0; while (IsMath(expr[*exp_idx])) { token->name[i++] = expr[(*exp_idx)++]; if ( (i > 2) || (*exp_idx > slen) ) return LEXER_FAIL; } token->name[i] = '\0'; token->type = Math; } return LEXER_OK; } //get logic if (IsBitLogic(expr[*exp_idx])) { i = 0; while (IsBitLogic(expr[*exp_idx])) { token->name[i++] = expr[(*exp_idx)++]; if ( (i > 2) || (*exp_idx > slen) ) return LEXER_FAIL; } token->name[i] = '\0'; if (i==1) token->type = Bitlogic; else if (i==2) token->type = Logic; return LEXER_OK; } if (IsGroup(expr[*exp_idx])) { i = 0; token->name[i++] = expr[(*exp_idx)++]; token->name[i] = '\0'; token->type = Group; return LEXER_OK; } if (IsEnd(expr[*exp_idx])) { i = 0; token->name[i++] = expr[(*exp_idx)++]; token->name[i] = '\0'; token->type = End; return LEXER_OK; } return LEXER_OK; } после лексера я получаю token.name - "IF" token.type - If token.name - "DIR" token.type - Alphanumeric token.name - "=" token.type - Compare token.name - "2" token.type - Number token.name - "AND" token.type - Logic и так далее. вопрос - как двигаться дальше? могу показать свою версию, хотя она довольно уродливая. Изменено 15 мая, 2019 пользователем jenya7 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
arhiv6 14 15 мая, 2019 Опубликовано 15 мая, 2019 · Жалоба А Вам точно не подойдёт ни один из множества готовых встраиваемых скриптовых движков? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 60 15 мая, 2019 Опубликовано 15 мая, 2019 · Жалоба 1 hour ago, jenya7 said: В продолжение темы с уважаемым xvr. А можно ссылку с его профиля исправить на его тему, в продолжение которой вы открыли эту) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 15 мая, 2019 Опубликовано 15 мая, 2019 · Жалоба 1 hour ago, arhiv6 said: А Вам точно не подойдёт ни один из множества готовых встраиваемых скриптовых движков? я копался но так и не нашел чего то удобоваримого ''из коробки''. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
arhiv6 14 15 мая, 2019 Опубликовано 15 мая, 2019 · Жалоба А что Вы подразумеваете под "удобоваримостью" ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 15 мая, 2019 Опубликовано 15 мая, 2019 (изменено) · Жалоба 2 hours ago, haker_fox said: А можно ссылку с его профиля исправить на его тему, в продолжение которой вы открыли эту) исправил. 2 hours ago, arhiv6 said: А что Вы подразумеваете под "удобоваримостью" ? Ну скажем LWIP, FreeRTOS - легко портируется, куча примеров и документации. на таком уровне не нашел движка. все как то витают на абстрактном леере. и со списком этим я как то работал. там такие монстры. а мне надо что то заточенное под эмбедед. и еще замечание. все примеры скриптов которые я видел - это создание переменных и операции с ними. а мне нужно работать со своими переменными - данные в них я получаю от слейвов по CAN и мне нужно отслеживать эти данные и если нужно модифицировать данные и отсылать слейвам обратно. Изменено 15 мая, 2019 пользователем jenya7 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_pv 53 15 мая, 2019 Опубликовано 15 мая, 2019 · Жалоба возьмите пример калькулятора из книжки Страуструпа по плюсам, в него очень легко можно добавить логические операции и тернарный оператор ? : переменные, чтение/запись которых можно привязать к своим функциям там уже впринципе есть. ну а если не хочется каждый раз строку интерпретировать, можно "скомпилировать" в промежуточный байт-код https://github.com/rswier/c4 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 15 мая, 2019 Опубликовано 15 мая, 2019 · Жалоба 1 hour ago, _pv said: возьмите пример калькулятора из книжки Страуструпа по плюсам, в него очень легко можно добавить логические операции и тернарный оператор ? : переменные, чтение/запись которых можно привязать к своим функциям там уже впринципе есть. ну а если не хочется каждый раз строку интерпретировать, можно "скомпилировать" в промежуточный байт-код https://github.com/rswier/c4 спасибо. посмотрю. я конечно не хочу все время гонять строковое выражение. это не оптимально по скорости. в моем варианте я ''расфасовываю'' его в структуру. проблема что структура получается очень большая. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 15 мая, 2019 Опубликовано 15 мая, 2019 · Жалоба В идеале вам нужно компилятор скрипта в байткод оставить на хосте (там писать проще, чем на МК), а на МК гнать уже готовый байт код. Если это подойдёт могу рассказать как писать компилятор Quote в IF все AND - поэтому если хоть одно условие не выполниться THEN не исполняется. Т.е. цепочка простых условий соединённых через AND, после THEN - цепочка присваиваний (возможно с арифметикой). В таком случае можно сделать ещё более простой байткод: Quote IF DIR=2 AND POS0>POS1 AND POS0-POS1>20 THEN PWM0-=100 AND PWM1+=100 Mark label_end ReadVar DIR Const 2 CheckEQ ReadVar POS0 ReadVar POS1 CheckGT ReadVar POS0 ReadVar POS1 Sub Const 20 CheckGT Const -100 AddVar PWM0 Const 100 AddVar PWM1 label_end: 21-29 байтов Команда Mark задаёт точку выхода, команды Check* проверяют верхушку стека (2 ячейки) и если условие не выполняется - переходят на метку из последнего Mark Если подход устравивает, можно будет двигаться дальше Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 15 мая, 2019 Опубликовано 15 мая, 2019 (изменено) · Жалоба 1 hour ago, xvr said: В идеале вам нужно компилятор скрипта в байткод оставить на хосте (там писать проще, чем на МК), а на МК гнать уже готовый байт код. Если это подойдёт могу рассказать как писать компилятор Т.е. цепочка простых условий соединённых через AND, после THEN - цепочка присваиваний (возможно с арифметикой). В таком случае можно сделать ещё более простой байткод: 17-25 байтов Команда Mark задаёт точку выхода, команды Check* проверяют верхушку стека (2 ячейки) и если условие не выполняется - переходят на метку из последнего Mark Если подход устравивает, можно будет двигаться дальше да конечно. почему бы не компилить скрипт на хосте. это наверное даже лучше. Изменено 15 мая, 2019 пользователем jenya7 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 15 мая, 2019 Опубликовано 15 мая, 2019 · Жалоба Just now, jenya7 said: да конечно. почему бы не компилить скрипт на хосте. это наверное даже лучше. Ок, тогда предлагаю взять готовый тулз для построения компиляторов (flex+bison например) Ещё хочется определится с набором поддерживаемой арифметики - какие операции понадобятся? В частности нужна ли логика (кроме AND в теле IF)? Сколько переменных с которыми надо работать (по порядку величины)? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 15 мая, 2019 Опубликовано 15 мая, 2019 (изменено) · Жалоба 1 hour ago, xvr said: Ок, тогда предлагаю взять готовый тулз для построения компиляторов (flex+bison например) Ещё хочется определится с набором поддерживаемой арифметики - какие операции понадобятся? В частности нужна ли логика (кроме AND в теле IF)? Сколько переменных с которыми надо работать (по порядку величины)? в IF из логики -AND и OR. из операторов + - * % > < >= <= == !=. не думаю что понадобиться что то еще. flex+bison? они не идут в виде готовых тулзов. или я не там смотрю? Изменено 15 мая, 2019 пользователем jenya7 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
arhiv6 14 15 мая, 2019 Опубликовано 15 мая, 2019 · Жалоба Используйте Pawn. Синтаксис си-подобный, позволяет компилировать исходный код в байт-код на строне хоста. 4 часа назад, jenya7 сказал: и еще замечание. все примеры скриптов которые я видел - это создание переменных и операции с ними. https://iu4.ru/konf/2014_ts/02_tom01.pdf, страница 50 - "Использование скриптового движка Pawn для реализации системы управления сервоприводом" на примере stm32 показано как импортировать в прошивку виртуальную машину и управлять сервами из скрипта. Такой пример подойдёт? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 15 мая, 2019 Опубликовано 15 мая, 2019 (изменено) · Жалоба 1 hour ago, arhiv6 said: Используйте Pawn. Синтаксис си-подобный, позволяет компилировать исходный код в байт-код на строне хоста. https://iu4.ru/konf/2014_ts/02_tom01.pdf, страница 50 - "Использование скриптового движка Pawn для реализации системы управления сервоприводом" на примере stm32 показано как импортировать в прошивку виртуальную машину и управлять сервами из скрипта. Такой пример подойдёт? в свое время я портировал Pawn в свой проект. но как то не пошло. может стоит вернуться, взглянуть еще раз. пример очень примитивный. он по сути не обращается к переменным напрямую. Изменено 15 мая, 2019 пользователем jenya7 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 15 мая, 2019 Опубликовано 15 мая, 2019 · Жалоба 31 minutes ago, jenya7 said: в IF из логики -AND и OR. Если есть OR, то финт с одной точкой выхода не пойдёт, увы. Надеюсь, что логические операции внутри арифметики не нужны? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться