Скрипт-подпрограмма

Aven
Offline
Зарегистрирован: 16.04.2015

Есть контроллер на базе Arduino, подключен в сеть RS485.

Хочется загржать в него удаленно (в EEPROM) небольшие подпрограммы-скрипты с простейшней логикой И/ИЛИ/НЕ, вида:

ЕСЛИ ПИН(5)=1 И VAR_X=123 ТОГДА ПИН(2)=0

Понятно, что в EEPROM нет смысла хранить их в текстовом виде, надо представить в виде байт-коде.

Собственно вопрос, как это можно сделать (не как загружать, а как интерпретировать подпрограмму)?

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015
Ого! Первый интересный вопрос за долгое время.
 
Ну, в простейшем варианте, надо вычисляемое выражение (программу) представить либо в постфиксоной форме (вместо а+в писать ав+), либо в префиксной (вместо а+в писать +ав) форме. Такая запись бесскобочна по определению. Если надо не просто вычислять выражения, а интерпретировать полноценную программу, то всё также (присваивание - такая же операция и т.п.).
 
Лучше для такого представления написать что-то типа компилятора (он просто пишется) потому что руками - ошибётесь обязательно.
 
А алгоритм интерпретатора простой как валенок. Я опишу для постфиксной формы (для префиксной принципиально всё также).
 
Изначально имеем строку для интерпретации и стек на который для общности можно положить 0.
 
1. В строке ещё что-нибудь осталось? Если НЕТ - результат на стеке. СТОП
2. берём символ из строки.
3. Символ - операция?
     НЕТ - кладём символ на стек
     ДА - снимаем со стека нужное количество операндов, выполняем операцию и кладём результат на стек
4. переход к п.1
 
Например, выражение: (2 + 3) * 3.
В постфиксной форме: 23+3*
 
Идём по алгоритму:
 
2 - не операция - идёт на стек
3 - не операция - идёт не стек
+ - операция - снимаем со стека два операнда (3 и 2), складываем и результат (5) кладём на стек
3 - не операция - идёт на стек
* - операция  - снимаем со стека два операнда (3 и 5), перемножаем и результат (15) кладём на стек
в строке больше ничего нет. Результат вычислений (15) лежит на стеке
 
Ну, вот как-то так.
 
Прежде чем приступать к реальной реализации необходимо строго определить язык, выделить все операции и т.п. При выделении надо помнить, что унарный - и бинарный - -- это разные операции. Также надо предусмотреть опреации для связи с основной программой и вообще для работы с ардуино (типа digitalRead и т.п.) А программирования там немного.
Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

По-моему автор ведет речь о функциональных блоках.

Придумывается произвольный набор блоков, имеющих некую функциональность, со своими входами и выходами. Пишутся функции для всех блоков и программируются в контроллер. При конфигурировании в контроллер загружается структуа данных вроде:

{type, in1, in2, out1},{type, in1, in2, in3, out1, out2} и т.д

а так же таблица связей блоков, вроде: 1.1->2.1....

что значит выход1 блока1 связан с входом 1 блока 2 и т.д.

Далее в цикле:
-пересчитываем значения выходов во всех блоках в соответствии с их типом;
-переносим значения выходов на входы в соответствии с таблицей связей;

В итоге имеем конструктор из функциональных блоков.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, он говорил об интерпретаторе, я про интерпретатор и написал.

Да, одно другому не противоречит. Определи эти заранее написанные блоки как операции языка и интерпретируй, как я описал - будут вызываться, а куда денутся?

Aven
Offline
Зарегистрирован: 16.04.2015

Да, вариант с блоками вполне подошёл бы...

faeton
faeton аватар
Offline
Зарегистрирован: 21.03.2016

ЕвгенийП пишет:

Ну, он говорил об интерпретаторе, я про интерпретатор и написал.

Да, одно другому не противоречит. Определи эти заранее написанные блоки как операции языка и интерпретируй, как я описал - будут вызываться, а куда денутся?

Ваш алгоритм вполне подойдёт, если в нём алгебру поменять на буловскую логику, что и нужно ТС. Толь вот в  инверсной Польской записи ещё необходимо приоритет операций обрабатывать, а там уже стеком не обойтись - дерево необходмо строить, если я не ошибась.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

faeton пишет:

ещё необходимо приоритет операций обрабатывать, а там уже стеком не обойтись - дерево необходмо строить, если я не ошибась.

Польской записи приоритеты абсолютно пофигу, они обрабатывются раньше, при построении самой записи. Допустим:

a+b*c

должно быть построено как

abc*+      

А вот если выражение: (a+b)*c

тогда должно быть построено как

ab+с*

и проблема с приоритетами решена полностью.

Такой построитель (транслятор) с приоритетами тоже строится на основе одного стека. Если ТС потребуется, я дам алгоритм, да и в литературе его найти несложно.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Евгений! Простите за вмешательство, всегда с удовольствием Вас читаю, но тут должен дополнить.

Скобочная или инфиксная запись тоже интерпретируется одним стеком. Это базовая задачка из курса проектирования компиляторов:

(лексемы это или "операнд", или "знак операции" или "(" или ")" или конец строки)

======================

1. прочесть лексему

2. если скобка открывающая - в стек

3. если опреанд (ОПn) - в стек

4. если скобка закрывающая - то пока в вершине стека не ("(", операнд):  {взять три верхних лексемы, если они (оп1, опер, оп2) - выполнить и положить результат в стек};

4.1. если в стеке ("(", операнд), убрать открывающую скобку из-плод вершины, входную лексему - игнорировать, иначе - ошибка.

6. если "конец строки" - то пока стек не пуст: {взять три верхних лексемы, если они (оп1, опер, оп2) - выполнить и положить результат в стек};

7. если знак операции:

7.1. если в стеке(вершина -1) - "знак операции", то пока ее приоритет выше текущей:{взять три верхних лексемы, если они (оп1, опер, оп2) - выполнить и положить результат в стек};

7.2. лексему - в стек;

---

ошибки возможны также при выполнении: {взять три верхних ...}

=================

Вот тут и обрабатываются приоритеты, о которых вспомнил Фаэтон. Судя по всему мы тут все "старички", тогда вспомню YACC юниксовый, там примерно такой способ обработки приоритетов. Даже не только для "скобочных" выражений, а вообще для LALR(1)- грамматик с приоритетами. ...Сорри, стер пару листов теории формальных грамматик, чёт меня занесло.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Та, нет, ну я ещё не всё забыл, и это помню, хотя спасибо, напомнили, душу погрели. Я рекомендовал ТС пост/префиксную форму не потому, что в инфиксной это не делается, а потому, компиляция в постфиксную - это работа, которую можно сделать единожды, а при прямой интерпретации - собственно её же делаешь каждый раз.

Спасибо ещё раз. Похоже, не мне одному это вопрос душу погрел (см. мою первую фразу в превом посте) :))))

faeton
faeton аватар
Offline
Зарегистрирован: 21.03.2016

Во! wdrakula дело написал. Я уже тоже забыл тонкости, 100 лет не пользовался. В памяти осталось лишь построение дерева и получение из него различных вариантов путём различного обхода. :)  

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

faeton пишет:

уже тоже забыл тонкости

Ну, а раз забыли, зачем писали? То у Вас const'ы место занимают, то в постфиксной форме откуда-то проблема приоритетов взялась, хотя её там даже теоретически быть не может. Несолидно как-то. Не пишите то, чего не знаете - не выставляйте себя на смех. Вы же вовсе не обязаны отписаться абсолютно в каждой теме.

faeton
faeton аватар
Offline
Зарегистрирован: 21.03.2016

ЕвгенийП пишет:

faeton пишет:

уже тоже забыл тонкости

Ну, а раз забыли, зачем писали? То у Вас const'ы место занимают, то в постфиксной форме откуда-то проблема приоритетов взялась, хотя её там даже теоретически быть не может. Несолидно как-то. Не пишите то, чего не знаете - не выставляйте себя на смех. Вы же вовсе не обязаны отписаться абсолютно в каждой теме.

Не потфиксная форма записи, а приведённый Вами алгоритм её реализации. :) А const int - сказался рудимент ТурбоПаскаля, который типизированные константы в сегменте данных хранит. :)

Logik
Offline
Зарегистрирован: 05.08.2014

ЕвгенийП пишет:

faeton пишет:

уже тоже забыл тонкости

Ну, а раз забыли, зачем писали? То у Вас const'ы место занимают, то в постфиксной форме откуда-то проблема приоритетов взялась, хотя её там даже теоретически быть не может. Несолидно как-то. Не пишите то, чего не знаете - не выставляйте себя на смех. 

Та то у него фишка такая, писать не разбираясь и  в каждой теме быть затычкой.  

По теме. Кроме реализации алгебры для ТС еще и ввод, вывод с порта надо. Это само по себе не проблема, но намек на тенденцию. А она в том, что сам по себе скрипт с арифметикой не востребован, нужно еще работа с переферией, каналом, экраном и т.д. , а это вырастит задачу сильно. Может интересней изучить возможность удаленной прошивки куска кода? 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Logik пишет:

По теме. Кроме реализации алгебры для ТС еще и ввод, вывод с порта надо. Это само по себе не проблема, но намек на тенденцию. А она в том, что сам по себе скрипт с арифметикой не востребован, нужно еще работа с переферией, каналом, экраном и т.д. , а это вырастит задачу сильно. Может интересней изучить возможность удаленной прошивки куска кода? 

Так, нет, это просто, я таки вещи много раз делал. Просто при определении интерпретируемого языка вводишь операцию digitalRead с одним операндом, также digitalWrite с двумя операндами и т.д. (можно писать огромные, сложные функции и вводить их в язык как операции). А интерпретатор знает что с ними делать - как обычно, снять со стека операнд(ы), выполнить операцию и сложить на стек результат.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

faeton пишет:

Не потфиксная форма записи, а приведённый Вами алгоритм её реализации. :) 

Простфиксная форма сама по себе, независимо от алгоритма, не зависит от приоритеов операций.

И что Вам опять неймётся бред писать? Ну, не знаете чего-то - не пишите. Все так поступают.

faeton
faeton аватар
Offline
Зарегистрирован: 21.03.2016

ЕвгенийП пишет:

faeton пишет:

Не потфиксная форма записи, а приведённый Вами алгоритм её реализации. :) 

Простфиксная форма сама по себе, независимо от алгоритма, не зависит от приоритеов операций.

И что Вам опять неймётся бред писать? Ну, не знаете чего-то - не пишите. Все так поступают.

Да блин! Нефига неправильно Вы её формирование написали!!! Тестируйте 2+2*2 и (2+2)*2.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Logik пишет:
Та то у него фишка такая, писать не разбираясь и  в каждой теме быть затычкой. ...

Вы только за недавнее время уже дважды сели в лужу .. чего вам "неймется"? :)

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Почему неправильно? Давайте потестируем ..

Алгоритм:

1. В строке ещё что-нибудь осталось? Если НЕТ - результат на стеке. СТОП
2. берём символ из строки.
3. Символ - операция?
     НЕТ - кладём символ на стек
     ДА - снимаем со стека нужное количество операндов, выполняем операцию и кладём результат на стек
4. переход к п.1
 
Пример (ваш): 2+2*2 и (2+2)*2
 
Поехали!
 
1: мимо; 2: "2" - не операция -> на стек ["2"]
1: мимо; 2: "+" - операция берем со стека ДВА операнда .. упс. :)
 
Как понимаю, ПРЕДВАРИТЕЛЬНО строку НАДО преобразовать к постфиксной записи, типа такой: 2,2,2,*,+ и 2,2,+2* :)
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

faeton пишет:

Да блин! Нефига неправильно Вы её формирование написали!!! Тестируйте 2+2*2 и (2+2)*2.

Я её формирование вообще не описывал, я считал, что она уже сформирована. Давайте, Вы прекратите позориться, а?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Arhat109-2 пишет:

Пример (ваш): 2+2*2 и (2+2)*2

 
Поехали!
 
1: мимо; 2: "2" - не операция -> на стек ["2"]
1: мимо; 2: "+" - операция берем со стека ДВА операнда .. упс. :)

Вот и я про то же (редкий случай, когда мы согласны :))). Человек пишет в инфиксной форме и хочет, чтобы на ней алгоритм для постфиксной работал. Результат Вы правильно описали "упс ... прямо в лужу"

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Да, не. В лужу тут сели как раз Вы. Я внимательно перечитал ваш пост с алгоритом, Вы там реально ЗАБЫЛИ указать, про предварительную подготовку строки в постфикс. Фаэтон тут полностью прав, и я показал, как человек, прочитавший тот пост и взявший алгоритм, внезапно обнаружит его неработоспособность. :)

Ваш пост содержит это:

"Изначально имеем строку для интерпретации и стек на который для общности можно положить 0."

Где тут указание (да и ваще в нем) про ПРЕДВАРИТЕЛЬНУЮ ПОДГОТОВКУ? Есть только далее, что вы "можете с этим помочь" (чего там помогать, когда это классика курса компиляторов?) .. и оно описано в литературе (верно, в учебнике). :)

Кстати, ваша форма записи в постфикс, приведенная тут "как пример" - ущербна. В ней путаются числовые символы и оно годится только для чиселок от 0 до 9. Попробуйте в свой постфикс записать 22+22+1 :)

(*ответ*) получится 2222+1+ .. и? :)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Архат, Вы бредите. В моём посте черным по белому написано:

надо вычисляемое выражение (программу) представить либо в постфиксоной форме ....
 
Лучше для такого представления написать что-то типа компилятора (он просто пишется) ...
 
А алгоритм интерпретатора простой как валенок ....
Если из этого не следует, что перед интерпретацией нужна предварительная компиляция в постфикс, то .... даже не знаю.
 
Более того, в пример явно упомянуто это преобразование:
Например, выражение: (2 + 3) * 3.
В постфиксной форме: 23+3*
Что Вам ещё нужно? Захотелось придраться? Так здесь не к чему, ищите что-то другое.
 
Так что, вылазьте из лужи и идите сушиться.
Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Ну .. в принципе, ваше вступление можно и так трактовать, так что о'кей, будем сидеть в луже рядышком, согласен. :)

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Парни, дискуссия мимо кассы, автору вариант с функциональными блоками по душе.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Andy пишет:

Парни, дискуссия мимо кассы, автору вариант с функциональными блоками по душе.

Да, про автора давно уже все забыли. Это дискуссия ради дискусии - фаллометрия, знаете такое занятие :)))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Arhat109-2 пишет:

Ну .. в принципе, ваше вступление можно и так трактовать, так что о'кей, будем сидеть в луже рядышком, согласен. :)

Ну, я то не согласен, впрочем, Вам это, наверное, пофигу :)))

faeton
faeton аватар
Offline
Зарегистрирован: 21.03.2016

ЕвгенийП пишет:

Архат, Вы бредите. В моём посте черным по белому написано:

надо вычисляемое выражение (программу) представить либо в постфиксоной форме ....
 
Лучше для такого представления написать что-то типа компилятора (он просто пишется) ...
 
А алгоритм интерпретатора простой как валенок ....
Если из этого не следует, что перед интерпретацией нужна предварительная компиляция в постфикс, то .... даже не знаю.
 
Более того, в пример явно упомянуто это преобразование:
Например, выражение: (2 + 3) * 3.
В постфиксной форме: 23+3*
Что Вам ещё нужно? Захотелось придраться? Так здесь не к чему, ищите что-то другое.
 
Так что, вылазьте из лужи и идите сушиться.

Ну, вот тут теперь понятно в чём я неправ. Совершенно верно, я входное условие пропустил, ожидая полное решение. :)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Мне тут припёрло сделать небольшой интерпретатор для выполнения базовых операций. Хотел воспользоваться готовыми интерпретаторами для Arduino - типа Lisp, Forth, Basic, но все реализации, которые нашёл, отжирают практически всю память (зато языки реализованы почти полностью). Видимо, целью авторов было сделать полную реализацию языка, а не реальный инструмент для удалённого манипулирования микроконтроллером. В общем, определил предельно простой стековый язык по мотивам Forth, вроде не очень развесистая реализация получается. Это кому-нибудь, кроме меня, интересно?

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

ЕвгенийП пишет:

Это кому-нибудь, кроме меня, интересно?

Интересно. Бо давно надобность в чём-то маложрущем.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Хорошо, тогда при допиливании буду иметь в виду будущую публикацию :)

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Без избытка памяти форт не выйдет. Ну разве что подключить флешку и туда записывать уже библиотеку пользователя для новых функций.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ЕвгенийП пишет:

Хорошо, тогда при допиливании буду иметь в виду будущую публикацию :)

Женя! Прости, был занят. Это как раз моя тема. Но тут главное ограничние - ОЗУ. Но если делать под СТМ или хотя бы мегу - вполне нормально выйдел.

На Радио86РК, если помнишь, в 8К ПЗУ укладывали полный Бейсик или Паскаль. Именно рабочие варианты... я в юности их пользовал для лабораторных по ... военной кафедре! ;))))

В 328-й тоже прекрасно можно уложить даже сложный язык, если отказаться от любой рекурсии или цилков. Для внешнего управления - это не проблема, цикл может породжать внешняя система. Но если хочешь автономность контроллера с языком, то придется добавлять любой вид памяти SPI или I2C, тут Пух угадал. ;))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

qwone пишет:

Без избытка памяти форт не выйдет. 

А такой цели никто и не ставит. Я же ясно написал

ЕвгенийП пишет:
предельно простой стековый язык по мотивам Forth

И, собственно уже вышло, допилить тока надо.

Тут же вопрос в задаче. Я вовсе не собираюсь программировать МК на своём языке. Я хочу иметь возможность без дополнительного программирования посмотреть на значения переменных, почитать порты, писать в них, поисполнять функции основной программы. Транспортный протокол, само собой отделён от логики. Сейчас я использую сериал, но если в программе и так есть web или там ещё чего - это решается заменой транспортного протокола без изменений в программе. Код получается небольшой, его можно просто оставлять в проекте, чтобы при случае, хоть дистанционно посмотреть что там творится. Бывает нужно, чтобы лучше понимать причину проблем.

sadman41
Offline
Зарегистрирован: 19.10.2016

Это вы что, busybox изображаете на ардуину?

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Aven пишет:

Есть контроллер на базе Arduino, подключен в сеть RS485.

Хочется загржать в него удаленно (в EEPROM) небольшие подпрограммы-скрипты с простейшней логикой И/ИЛИ/НЕ, вида:

ЕСЛИ ПИН(5)=1 И VAR_X=123 ТОГДА ПИН(2)=0

Понятно, что в EEPROM нет смысла хранить их в текстовом виде, надо представить в виде байт-коде.

Собственно вопрос, как это можно сделать (не как загружать, а как интерпретировать подпрограмму)?

 

 

Както ходил по похожим граблям.

Logik
Offline
Зарегистрирован: 05.08.2014

Хоо! Привет.

Чеж грабли, очень прикольно замутили тогда. Да и не похоже оно нифига, там векторная графика а здесь бы яка с бизоном и VM надо заюзать.

Кстати буквально на днях вернулся к теме векторных шрифтов, к оптимизации хранения их. Чтоб брать и легко заменять старый матричный шрифт на новый векторный надо ужать расход флеша. Для полного, с кирилицей, шрифта в 160 символов и матрице 5*8 имеем 800 байт для шрифта и в них нужно вместить векторное описание. Борюсь с этим, пока векторный делать 1200байт удается. Но похоже ужать таки реально. Тогда любой старый проект можна будет апгрейдить и бонусом получить остальные фишки. А иначе тупо не влазит.