mantech 49 26 мая, 2019 Опубликовано 26 мая, 2019 · Жалоба 9 часов назад, sigmaN сказал: В общем, над безопасностью нужно хорошо подумать ) Либо использовать запуск в вирт. адресном пространстве (если МК с MMU) или делать свою сборку ГЦЦ с анализом адресов при компиляции и шифровании байткода, тогда никто не влезет Сам решал подобную задачу несколько лет назад, решил использовать интрепретатор, за основу взял проект, подобный с4, вышеуказанный, оставил один тип данных int32, добавил многопоточность, обработчик ошибок, парсер дефайнов и несколько функций. Получилось хорошее быстродействие, простота написания скрипта, хорошая функциональность (можно писать полноценные программы), вообщем ТСу рекомендую такой подход. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
=AK= 17 27 мая, 2019 Опубликовано 27 мая, 2019 · Жалоба On 5/15/2019 at 4:45 PM, jenya7 said: В продолжение темы с уважаемым xvr. Мне нужно исполнять скрипт. Пользователь передает его в микроконтролер, скрипт сохраняется (в FLASH) и исполняется. в основном это проверка входных условий (переменных) и если условия выполнились - изменение выходных условий (переменных). Самоя сложное выражение (пока) это к примеру такое Выражений может быть до .... ну не знаю пока 40. в IF все AND - поэтому если хоть одно условие не выполниться THEN не исполняется. Reveal hidden contents 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; } Самое простое - сделать интерпретатор виртуальной Форт-машины, FVM. Полной (по Тьюрингу) машине надо всего пару десятков команд (токенов), что реализуется в несколько сотен строк текста на С. Как вариант можно попробовать использовать такую тулзу для автоматической генерации интерпретатора и кросс-компилятора для него, однако написать интерпретатор самому "с нуля" может оказаться быстрее и проще. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 27 мая, 2019 Опубликовано 27 мая, 2019 · Жалоба On 5/25/2019 at 6:37 PM, jenya7 said: доинсталировал бизоновский пакет, прописал путь, все равно не видит бизон. Что то не так прописали. Откройте шелл (командную строку - cmd.exe) и наберите там bison - должен написать что он bison, версию и пр. Если не пишет - либо нет bison'а, либо нет путей On 5/25/2019 at 6:37 PM, jenya7 said: я другого не понимаю - главное это интерпретер, он делает всю работу. какая разница каким способом распарсить и передать ему опкоды? Никакой разницы. Можете хоть руками в хексе писать, или сделать свой собственный компилятор (если с bison'ом справится не можете). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 27 мая, 2019 Опубликовано 27 мая, 2019 · Жалоба 1 hour ago, xvr said: Что то не так прописали. Откройте шелл (командную строку - cmd.exe) и наберите там bison - должен написать что он bison, версию и пр. Если не пишет - либо нет bison'а, либо нет путей Никакой разницы. Можете хоть руками в хексе писать, или сделать свой собственный компилятор (если с bison'ом справится не можете). cmd.exe bison -V возвращает Quote bison (GNU Bison) 3.0.4 Written by Robert Corbett and Richard Stallman. Copyright (C) 2015 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 27 мая, 2019 Опубликовано 27 мая, 2019 · Жалоба On 5/25/2019 at 8:23 PM, sigmaN said: Раз уж тут никого не смущает бизон и запуск интерпретации на стороне ПК, то может быть просто воспользоваться LLVM? )))) 11 hours ago, mantech said: Либо использовать запуск в вирт. адресном пространстве (если МК с MMU) или делать свою сборку ГЦЦ с анализом адресов при компиляции и шифровании байткода, тогда никто не влезет 42 minutes ago, =AK= said: Самое простое - сделать интерпретатор виртуальной Форт-машины, FVM. Господа, ТС не может собрать готовый тривиальный проект VS на С++ (размером в 500 строк), а вы ему тут LLVM, FORTH, GCC и пр PS. FORTH не надо - это не гуманно по отношению к пользователям 1 minute ago, jenya7 said: cmd.exe bison -V возвращает Значит должно работать - VS перезапускали (после прописывания путей)? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 27 мая, 2019 Опубликовано 27 мая, 2019 · Жалоба Прикладываю собранный компилятор скрипта (32х битный код, статическая сборка - должно запустится где угодно) script.zip PS. Дайте файл var_defs.inc с реальным списком переменных - соберу с ним Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 27 мая, 2019 Опубликовано 27 мая, 2019 · Жалоба 1 hour ago, xvr said: Прикладываю собранный компилятор скрипта (32х битный код, статическая сборка - должно запустится где угодно) script.zip PS. Дайте файл var_defs.inc с реальным списком переменных - соберу с ним с переменными не совсем понятно. у меня массив переменных. скажем 8 моторов - отсюда восемь переменных содержащих позицию с энкодера POS0-POS7. как парсер поймет к какой переменной обратиться? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 27 мая, 2019 Опубликовано 27 мая, 2019 · Жалоба 13 minutes ago, jenya7 said: с переменными не совсем понятно. у меня массив переменных. скажем 8 моторов - отсюда восемь переменных содержащих позицию с энкодера POS0-POS7. как парсер поймет к какой переменной обратиться? В файле var_defs.inc должны быть такие строчки: VAR(POS0) VAR(POS1) VAR(POS2) VAR(POS3) VAR(POS4) VAR(POS5) VAR(POS6) VAR(POS7) Интерпретатор ожидает, что в МК есть 8 переменных (POS0, POS1, POS2, ... POS7), все типа int32_t (или аналогичного). И что они будут видны из кода самого интерпретатора. Если у вас нечто большее, то адаптируйте код в строках 58-60 в файле interpreter.c Адреса переменных связываются с индексами переменных посредством массива vars в строках 6-10 Можно в макрос VAR добавить полей, что бы можно было задать все возможные варианты адресации ваших переменных Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 27 мая, 2019 Опубликовано 27 мая, 2019 (изменено) · Жалоба так мы не получим адрес переменной. static int32_t* vars[] = { #define VAR(nm) &nm, #include "var_defs.inc" NULL }; у меня в скрипте не реальные имена а символы. я делал так чтоб получить адрес переменной static const SCRIPT_VAR script_vars[] = { { "flimsw", 6, VAR_TYPE_FLSW }, { "rlimsw", 6, VAR_TYPE_RLSW }, { "pos", 3, VAR_TYPE_POS }, { "cur", 3, VAR_TYPE_CUR }, { "dir", 3, VAR_TYPE_DIR }, { "pwm", 3, VAR_TYPE_PWM }, { "mot", 3, VAR_TYPE_MOT }, { "com", 3, VAR_TYPE_COM }, { "var", 3, VAR_TYPE_UVAR }, }; void * COMP_ParseVar(char * var, uint8_t *var_type, uint8_t *var_num) { uint32_t num, i, len; for (i = 0; i < script_vars_len; i++) { //command found if(strncmp(var, script_vars[i].name, script_vars[i].str_len)==0) { len = script_vars[i].str_len; if (strlen(var) < (len+1)) return 0; num = atoi(&var[len]); if (num < MAX_MOTORS) { *var_num = num; *var_type = script_vars[i].var_type; switch (script_vars[i].var_type) { case VAR_TYPE_FLSW: return &motor_rt_params[num].flimsw_state; break; case VAR_TYPE_RLSW: return &motor_rt_params[num].rlimsw_state; break; case VAR_TYPE_POS: return &motor_rt_params[num].position; break; case VAR_TYPE_CUR: return &motor_rt_params[num].current; break; case VAR_TYPE_DIR: return &motor_rt_params[num].direction; break; case VAR_TYPE_PWM: return &motor_rt_params[num].speed; break; case VAR_TYPE_MOT: return &motor_rt_params[num].action; break; case VAR_TYPE_COM: return &g_command; break; case VAR_TYPE_UVAR: return &user_vars[num]; break; case VAR_TYPE_CONST: return &user_consts[num]; break; } } else return 0; } } return 0; } Изменено 27 мая, 2019 пользователем jenya7 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 27 мая, 2019 Опубликовано 27 мая, 2019 · Жалоба Тогда вам нужно первым делом поделить все переменные на 4 группы (по способу адресации): те, что лежат в motor_rt_params, user_* и g_command Для них сделать 4 разных макроса VAR (либо физичекси в виде разных макросов либо в виде дополнительного параметра в самом VAR), и обеспечить конвертирование макросов в реальные адреса. Для начала - сколько у вас мотороров, пользовательских констант и переменных? (Уместится в 280 штук в сумме?) Далее (если вы не хотите выписывать руками ы var_defs.inc все переменные со всеми возможными индексами) надо изменить парсинг имён переменных в лексере (что бы номер брать отдельно от имени) Ну и решить какие именно 30 символов вам более дороги (что бы поместить их в начало списка - для них байткод короче на 1 байт на переменную) PS. bison в VS запустился? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 27 мая, 2019 Опубликовано 27 мая, 2019 · Жалоба 1 hour ago, xvr said: Тогда вам нужно первым делом поделить все переменные на 4 группы (по способу адресации): те, что лежат в motor_rt_params, user_* и g_command Для них сделать 4 разных макроса VAR (либо физичекси в виде разных макросов либо в виде дополнительного параметра в самом VAR), и обеспечить конвертирование макросов в реальные адреса. Для начала - сколько у вас мотороров, пользовательских констант и переменных? (Уместится в 280 штук в сумме?) Далее (если вы не хотите выписывать руками ы var_defs.inc все переменные со всеми возможными индексами) надо изменить парсинг имён переменных в лексере (что бы номер брать отдельно от имени) Ну и решить какие именно 30 символов вам более дороги (что бы поместить их в начало списка - для них байткод короче на 1 байт на переменную) PS. bison в VS запустился? для моторов 6*8, ну еще разных переменных около 20. а если передать дефайнами? #define POS0 (@motor_rt_params[0].position) или #define POS(N) (@motor_rt_params[N].position) VS не видит bison. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 27 мая, 2019 Опубликовано 27 мая, 2019 · Жалоба 18 minutes ago, jenya7 said: ну еще разных переменных около 20. Они тоже в виде массивов заданы, или самыми разными именами? И кто такие user_vars и user_consts? 30 minutes ago, jenya7 said: а если передать дефайнами? Там и так какие то дефайны появятся. Не хотелось бы все 48 штук (6*8) руками писать. 31 minutes ago, jenya7 said: VS не видит bison. Попробуйте задать в VS настройках проекта (правая кнопка мыши на script_gramm.y -> Свойства -> Настраиваемые инструменты -> Общее -> Командная строка) явный путь к bison Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 29 мая, 2019 Опубликовано 29 мая, 2019 (изменено) · Жалоба мне кажется инерпритатор не возьмет выражение типа VAR = 5-3. он не приравняет аккумулятивно. я не вижу механизма который сначала вычисляет правую часть равенства. Изменено 29 мая, 2019 пользователем jenya7 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 29 мая, 2019 Опубликовано 29 мая, 2019 · Жалоба 6 hours ago, jenya7 said: мне кажется инерпритатор не возьмет выражение типа VAR = 5-3. он не приравняет аккумулятивно. я не вижу механизма который сначала вычисляет правую часть равенства. Возмёт. Более того, компилятор из этого сделает VAR = 2 (разумеется это должно быть внутри какого то then) Исходник: if 1 then PWM0 = 5-3 Байткод: # if 1 then PWM0 = 5-3 0000: 01 Const 1 0001: E2 02 JumpF +2 (=> 0005) 0003: 02 Const 2 0004: A1 SetVar #1 (PWM0) 0005: FF Stop PS. Всё ещё жду ответ на вопрос - И кто такие user_vars и user_consts? И есть ли наиболее используемые переменные (или все используются одинаково часто)? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 29 мая, 2019 Опубликовано 29 мая, 2019 (изменено) · Жалоба 1 hour ago, xvr said: Возмёт. Более того, компилятор из этого сделает VAR = 2 (разумеется это должно быть внутри какого то then) Исходник: if 1 then PWM0 = 5-3 Байткод: # if 1 then PWM0 = 5-3 0000: 01 Const 1 0001: E2 02 JumpF +2 (=> 0005) 0003: 02 Const 2 0004: A1 SetVar #1 (PWM0) 0005: FF Stop PS. Всё ещё жду ответ на вопрос - И кто такие user_vars и user_consts? И есть ли наиболее используемые переменные (или все используются одинаково часто)? user_consts я убрал а user_vars это массив переменных int user_vars[8]. он нужен для промежуточных вычислений и всяких флагов (меток). хм. как то хитро. не вижу чтоб на стак легли 5 и 3 и операции между ними, но я так понимаю что JumpF +2 (=> 0005) делает 5-3? Изменено 29 мая, 2019 пользователем jenya7 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться