From 8eed597376e567d5572f4f53e37946e67d5e5e07 Mon Sep 17 00:00:00 2001 From: Galin Simeonov Date: Thu, 15 Jul 2021 18:18:29 +0300 Subject: added the project documentation --- doc/project.mg | 321 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 321 insertions(+) create mode 100644 doc/project.mg (limited to 'doc/project.mg') diff --git a/doc/project.mg b/doc/project.mg new file mode 100644 index 0000000..013fb5c --- /dev/null +++ b/doc/project.mg @@ -0,0 +1,321 @@ +.ps +1 +.vs +1 +.start +.ds C \f[B]C\f[] +.title "Проект по компютърни системи за управление на роботи" +.title "Език за улесняване на програмиране на вградени устройства" +.author "Галин Симеонов Ф.Н. 81635" "gtsimeonov@uni-sofia.bg" +.heading "Увод" +.paragraph +При програмирането на вградени устройства, +някои от проблемите се моделират чрез автомати. +Също е практика да се програмира на езици от ниско ниво, като \*[C], +при които ръчното имплементиране на автомати с каквито и да е размери +често е неинтуитивно, предразполагащо към грешки и трудоемко. +С цел да помогна разработването на програми, чийто модел е ориентиран околу +състоянията на системата, предлагам и имплементирам експериментален миниатюрен език транспилиращ до \*[C]. +.paragraph +За цели имам той да е прост, интуитивен и евентуално лесен за генериране от инстурменти с графичен интернфейс +.footnote +Макар, че директното генериране на код без този език да действа като посредник би било по-смислено. +.footnote end +\&. +.heading "Описание на езика" +.heading "Общ поглед" 2 +Една 'програма' съдържа един или повече 'машини', които действат като контейнери за състояния,събития и преходи. +Всяка машина си има име и има отделно пространство за имена на състояния и събития. +Чрез преходите може да се извикват външни функции. +Ето най-простият пример за това как изглежда кодът: + +.code +machine light_bulb +[ + states [ ON , OFF ]; + events [ TURN_ON , TURN_OFF , SWITCH_STATE ]; + starting on OFF; + transitions + [ + from ON to OFF on event TURN_OFF; + from ON to OFF on event SWITCH_STATE; + + from OFF to ON on event TURN_ON; + from OFF to ON on event TURN_ON; + ]; + +]; +.code end + +След транспилация се генерират 3 файла - xxx.h xxx.c и xxx_external.h, който съответно съдържат +декларациите на служебните функции, тяхната имплементация и декларациите на външните функции, които са използвани от някой преход. +Подаването на събития към тези 'автомати' става посредством служебната функция - \f[B]push_event_to_machine\f[] + +Горният пример не е много функционален, защото комуникацията е само в една посока. +За да може да връща информация и да има функционалност, на всеки преход може да се сложат функции, които да бъдат изпълнени преди преходът да е завършил +.footnote +Това свойство е важно и авторът се е стремил да го запази. Това позволява, например, да се подават събития от функции изпълнени по време на преход +.footnote end +\&. +Taка горният пример може да бъде преработен да вика функция, която действително да включва и изключва някаква лампа: + +.code +machine light_bulb +[ + states [ ON , OFF ]; + events [ TURN_ON , TURN_OFF , SWITCH_STATE ]; + starting on OFF; + transitions + [ + from ON to OFF on event TURN_OFF + execute light "off"; + from ON to OFF on event SWITCH_STATE + execute light "off"; + + from OFF to ON on event TURN_ON + execute light "on"; + from OFF to ON on event TURN_ON + execute light "on"; + ]; + +]; +.code end + +Тук също е демонстрирано как се подават аргументи към тези функции. +Символните низове са избрани като единствен начин да се подават аргументи, защото е предвидено да се транспилира до езици, различни от \*[C], +а въвеждането на типова система или нещо, което да описва различните аргументи би натоварило езикът твърде много и би донесло само минимална печалба. +.paragraph +Възможно е да има повече от една 'машина' в кодът. Например, нека към горния пример добавим: + +.code +machine light_controler +[ + states [ STATIC , BLINKING ]; + events [ SIGNAL , GO_STATIC, START_BLINKING ]; + starting on STATIC; + transitions + [ + from STATIC to BLINKING on event START_BLINKING; + from BLINKING to STATIC on event GO_STATIC; + + from BLINKING to BLINKING on event SIGNAL + execute prod_light_bulb; + + ]; + +]; + +machine timer +[ + states [ ON , OFF ]; + events [ TICK , START , STOP ]; + starting on OFF; + transitions + [ + from ON to OFF on event STOP; + from OFF to ON on event START + execute prod_timer; + from ON to ON on event TICK + execute prod_timer | prod_light_controler; + ]; + +]; +.code end + +Тук може да се види и 'навързване' на различни функции. +timer 'машината' праща сигнал до себе си и до light_controler, а light_controler праща сигнал до light_bulb. +Тук можем да прескочим предаването на събития между 'машините' чрез използването на \f[B]if\f[]. +Променяме третия преход от timer: + +.code + from ON to ON on event TICK + if(light_controler.BLINKING) + execute prod_timer | prod_light_bulb; + +.code end + +Това е условно изпълнение на командите, преходът се случва и състоянието е променено независимо от истинността на условието. +За реализацията на условен преход, в езикът има \f[B]granted\f[] ключовата дума. +Горното може да се опитаме да имплементираме по следния начин: + +.code + from ON to ON on event TICK granted (light_controler.BLINKING) + execute prod_timer | prod_light_bulb; +.code end + +Тук има проблема, че timer спира да работи ако light_controler не е в състояние BLINKING, +защото преходът няма да се случи и \f[B]execute prod_timer\f[] няма да се изпълни. +.footnote +Това, че този пример може да бъде имплементиран на \*[C] под 10 реда, е забелязано от автора. +.footnote end +.paragraph +\f[B]prod_timer\f[],\f[B]prod_light_bulb\f[],\f[B]prod_timer\f[] и \f[B]light\f[] са функции, чиято имплементация трябва да бъде предоставена от програмиста. +Всички външни функции се събират и се записват в генерирания xxxx_exter.h файл. Този пример би генерирал: + +.code +#ifndef XXXX_EXTERN_H +#define XXXX_EXTERN_H XXXX_EXTERN_H + +extern machine_buffer_t* light(machine_buffer_t *arguments,machine_buffer_t *input); +extern machine_buffer_t* prod_light_bulb(machine_buffer_t *arguments,machine_buffer_t *input); +extern machine_buffer_t* prod_light_controler(machine_buffer_t *arguments,machine_buffer_t *input); +extern machine_buffer_t* prod_timer(machine_buffer_t *arguments,machine_buffer_t *input); + +#endif + +.code end + +Ето и една примерна тяхна импелементация заедно с \f[B]main\f[] функцията: + +.code +machine_buffer_t* light(machine_buffer_t *arguments,machine_buffer_t *input) +{ + printf("light %s\n",arguments->buffer); + return NULL; +} +machine_buffer_t* prod_light_bulb(machine_buffer_t *arguments,machine_buffer_t *input) +{ + push_event_to_machine(light_bulb,light_bulb_EVENT_SWITCH_STATE,NULL); + return NULL; +} +machine_buffer_t* prod_light_controler(machine_buffer_t *arguments,machine_buffer_t *input) +{ + push_event_to_machine(light_controler,light_controler_EVENT_SIGNAL,NULL); + return NULL; +} +machine_buffer_t* prod_timer(machine_buffer_t *arguments,machine_buffer_t *input) +{ + push_event_to_machine(timer,timer_EVENT_TICK,NULL); + sleep(1); + return NULL; +} +int main() +{ + push_event_to_machine(light_controler,light_controler_EVENT_START_BLINKING,NULL); + push_event_to_machine(timer,timer_EVENT_START,NULL); + return 0; +} + +.code end +Това ни дава изхода: +.code +light on +light off +light on +light off +light on +light off +light on +light off +light on +\&... +\&... +.code end + +.heading "Формално описание на езика" 2 +Със затъмнените думи и символи обозначавам думи и символи, които трябва да се интерпретират директно. +.heading "Програма" 3 +.right +.nf +програма : машина [ програма ] +.fi +.right end +Програмата е поредица от машини. Всяка машина има уникално име. +.heading "Машина" 3 +.right +.nf +машина : \f[BI]machine\f[] име \f[BI][\f[] вътрешна част на машината \f[BI] ] ; \f[] +вътрешна част на машината : \f[BI]states [\f[] поредица от състояния \f[BI] ] ; \f[] [ вътрешна част на машината ] + \f[BI]events [\f[] поредица от събития \f[BI] ] ; \f[] [ вътрешна част на машината ] + \f[BI]transitions [\f[] поредица от преходи \f[BI] ] ; \f[] [ вътрешна част на машината ] + \f[BI]starting on \f[] име на състояние \f[BI];\f[] [ вътрешна част на машината ] +.fi +.right end + +В една машина може да се срещне само веднъж декларация на състоянията, събитията, преходите и посочване на стартиращо състояние. +Декларацията на стартиращо състояние трябва да е след декларацията на състоянията. То трябва да е сред декларираните състояния. +Декларацията на преходите трябва да е след декларациите на състоянията и на събитията. +Сред декларираните състояния и събития не трябва да има повтарящи се. +Сред преходите не трябва да има две различни, които излизат от едно състояние и имат за етикет едно събитие. +.heading "Преход" 3 +.right +.nf +преход : \f[BI] from \f[] име-на-състояние + \f[BI] to \f[] име-на-състояние \f[BI] on \f[] име-на-събитие [ опашка-на-прехода ] \f[BI];\f[] +опашка-на-прехода : [ \f[BI] granted \f[] израз ] [ условно-изпълнение ] +условно-изпълнение : \f[BI] if \f[] израз условно-изпълнение [ \f[BI] else \f[] условно-изпълнение ] +условно-изпълнение : \f[BI] execute \f[] опашка на изпълнението +опашка-на-изпълнението : име-на-външна-функция \f[BI]"\f[]символен-низ\f[BI]"\f[] [ \f[BI] | \f[] опашка-на-изпълнението ] +.fi +.right end + +Ако изразът след \f[BI]granted\f[] е истина то преходът се реализира и командите в условното изпълнение се изпълняват спрямо семантиката, +иначе преходът не се изпълнява и опашката на преходът не се изпълнява. +Ако изразът след \f[BI]if\f[] е истина то условното изпълнение след изразът се изпълнява, иначе, ако има \f[BI]else\f[] +съответстващ на \f[BI]if\f[]-а то условното узпълнение след \f[BI]else\f[] се изпълнява. +Ако условното изпълнение е от типа започващ с \f[BI]execute\f[] то външните функции се изпълняват в ред на срещане +като изходът на всяка се подава на следващата. Изходът на последната изпълнена функция се изхвърля. +.heading "Израз" 3 +.right +.nf +израз : израз-или +израз-или : израз-и [ \f[BI]|| \f[] израз-или ] +израз-и : израз-не [ \f[BI]&& \f[] израз-и ] +израз-не : [\f[BI]!\f[]]базов-израз +базов-израз : име-на-машина\f[BI].\f[]име-на-състояние | \f[BI](\f[]израз\f[BI])\f[] +.fi +.right end + +Израз може да се оцени до истина или лъжа. +Логическите оператори имат обичайната семантика. +В базовия израз е позволено да се посочват състояния на други машини, но не е позволено да се посочват състояния на машината, +в която се намира изразът. Тези посочвания се оценяват до истина ако посочената машина е заела посоченото състояние. +Могат да се посочват имена на машини, които са декларирани след сегашната, но те трябва да съществуват. Това важи и за състоянията, те трябва също и да принадлежат на посочената машина. + +.heading "Детайли на имплементацията" +За да се реализира обмена на информация между генерирания код и написания, +е дефинирана структура \f[B]machine_buffer_t\f[], в която се записват данните и техният размер. +Генерират се и няколко помощни функции, които улесняват работата с такива структури. +За да се запази свойството - командите на преходът да се изпълнят преди състоянието да се смени, +се използва опашка, в която се записват +.heading "Описание на командните аргументи" +Имплементацията на този език предадена от автора приема следните аргументи. + +.code +--print-tokens +.code end +Извежда разпознатите лексеми +.code +--print-ast +.code end +Извежда разпознатите структури в текста. ( Абстрактното синтактично дърво ) +.code +-o име-на-файл | --output име-на-файл +.code end +Посочва префиксът на генерираните файлове. Например \f[B]xxxx.h xxxx.c xxxx_external.h\f[]. +.code +--extern-mutex +.code end +Добавя мутекс преди и след подаването на събитие. Този мутекс трябва да се имплементира външно. +.code +--extern-queue +.code end +Дава възможност на програмиста да даде собствена имплементация на опашката използвана при задържането на събития. +.code +--extern-buffer +.code end +Дава възможност на програмиста да даде собствена имплементация на структурата използвана за пренос на данни. + +.heading "Забележки" +За имплементацията е използвана само стандартната \*[C] библиотека, което би помогнало този транспилатор да бъде +компилиран до много операционни системи. +.heading "Бъдещи насоки" +.list +.item +Да се добави ключова дума \f[B]signal\f[] която да праща сигнал до определена машина, за да не трябва да го имплементира програмистът. +.item +Да се добави семанитка за състояния и събития, като например - 'при пристигане до това състояние изпълни ... '. +.item +Да се направи така, че отделните машини да могат да бъдат на различни физически устройства, т.е. да бъде направен разпределен. +.item +Да се направи на пълен език за програмиране. +.list end +.finish -- cgit v1.2.3