aboutsummaryrefslogtreecommitdiffstats
path: root/doc/bulgarian/project.mg
blob: 013fb5c11c3f7ae4b946eaf61c0ba46c16cd931c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
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