aboutsummaryrefslogtreecommitdiffstats
path: root/doc/project.mg
diff options
context:
space:
mode:
Diffstat (limited to 'doc/project.mg')
-rw-r--r--doc/project.mg321
1 files changed, 321 insertions, 0 deletions
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