-
Notifications
You must be signed in to change notification settings - Fork 2
/
library.h
348 lines (298 loc) · 13.3 KB
/
library.h
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
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
/**\file
* \brief Интерфейс стандартной библиотеки РЕФАЛ.
*
* \addtogroup library Библиотечные функции РЕФАЛ-машины.
*
* В базовую библиотеку входят функции, которые затруднительно выразить на РЕФАЛ.
*
* Часть поля зрения, обрабатываемая функцией, называется _подвыражением_.
* _Активное подвыражение_ включает в себя имя функции.
*
* Реализации функций принимают параметрами:
* - адрес объекта с состоянием РЕФАЛ-машины;
* - номер ячейки, предшествующей начальной обрабатываемого подвыражения;
* - номер ячейки, следующей за конечной ячейкой обрабатываемого подвыражения.
*
* Описания функций заимствованы из книги Турчина В.Ф. (семантика с изменениями).
* Нотация из Refal-05 Коновалова Александра.
*
* \{
* \defgroup library-io Функции ввода-вывода.
* \defgroup library-math Арифметические функции.
* \defgroup library-str Обработка символов и строк.
* \defgroup library-rt Системные функции.
*
*/
#pragma once
#include "refal.h"
/**
* Максимальное количество файловых дескрипторов,
* поддерживаемых встроенными функциями классического РЕФАЛ-5.
*/
#define REFAL_LIBRARY_LEGACY_FILES 40
extern
const struct refal_import_descriptor library[];
/**\}*/
rf_function Card;
rf_cfunction Print;
rf_function Prout;
rf_function Open;
rf_function Close;
rf_function Get;
rf_function Put;
rf_function Putout;
rf_function Add;
rf_function Sub;
rf_function Mul;
rf_function Div;
rf_function Mod;
rf_function Compare;
rf_function Push;
rf_function Pop;
rf_function Type;
rf_function Numb;
rf_function Symb;
rf_function Chr;
rf_function Ord;
rf_function GetEnv;
rf_cfunction Exit;
rf_function System;
/**\addtogroup library-io
* \{
*/
/**
* Возвращает следующую строку из входного файла.
* Если ввод производится из файла, при достижении конца файла возвращается
* макро-цифра 0 (строк больше нет). При считывании с терминала тот же эффект
* вызывает ввод комбинации Ctrl+D (Ctrl+Z в Windows).
*
<Card> == s.CHAR* 0?
*/
int Card(struct refal_vm *vm, rf_index prev, rf_index next);
/**
* Вывод подвыражения в стандартный поток вывода с переводом строки.
* Сохраняет подвыражение в поле зрения.
*
<Print e.Expr> == e.Expr
*/
int Print(const struct refal_vm *vm, rf_index prev, rf_index next);
/**
* Вывод подвыражения в стандартный поток вывода с переводом строки.
* Удаляет подвыражение из поля зрения.
*
<Prout e.Expr> == []
*/
int Prout(struct refal_vm *vm, rf_index prev, rf_index next);
/**
* Открывает файл e.FileName и связывает его с файловым дескриптором s.FileNo.
* s.Mode является одним из символов: 'r' (открыть для чтения), 'w' (открыть для
* записи; если файл существует содержимое удаляется), либо 'a' (открыть для
* записи в конец файла).
* Дескриптор файла является целым числом в диапазоне 1…39
* \see REFAL_LIBRARY_LEGACY_FILES.
*
* Если текущим режимом является чтение, а файл не существует, выдаётся ошибка.
*
* TODO указанная конвенция малопригодна для практических применений.
*
<Open s.Mode s.FileNo e.FileName> == []
s.Mode ::=
'r' | 'w' | 'a'
*/
int Open(struct refal_vm *vm, rf_index prev, rf_index next);
/**
* Закрывает соответствующий дескриптору s.FileNo файл.
*
<Close s.FileNo> == []
*/
int Close(struct refal_vm *vm, rf_index prev, rf_index next);
/**
* Действует подобно Card, за исключением того, что получает данные из файла,
* указанного s.FileNo.
*
<Get s.FileNo> == s.Char* 0?
s.FileNo ::= s.NUMBER
*/
int Get(struct refal_vm *vm, rf_index prev, rf_index next);
int Put(struct refal_vm *vm, rf_index prev, rf_index next);
int Putout(struct refal_vm *vm, rf_index prev, rf_index next);
/**\addtogroup library-aux Вспомогательные функции.
* Не вызываются из РЕФАЛ-програм непосредственно.
* \{
* \}*/
/**\}*/
/**\addtogroup library-math
* \{
*/
/**
* Возвращает сумму операндов (2-х s-переменных).
*
<Add s.NUMBER s.NUMBER> == s.NUMBER
*/
int Add(struct refal_vm *vm, rf_index prev, rf_index next);
/**
* Вычитает 2-ю s-переменную из 1-й в возвращает разность.
*
<Sub s.NUMBER s.NUMBER> == s.NUMBER
*/
int Sub(struct refal_vm *vm, rf_index prev, rf_index next);
/**
* Возвращает произведение операндов (2-х s-переменных).
*
<Mul s.NUMBER s.NUMBER> == s.NUMBER
*/
int Mul(struct refal_vm *vm, rf_index prev, rf_index next);
/**
* Возвращает частное от деления 1-й s-переменной на 2-ю, или 0 при ошибке деления.
*
<Div s.NUMBER s.NUMBER> == s.NUMBER
*/
int Div(struct refal_vm *vm, rf_index prev, rf_index next);
/**
* Возвращает остаток от деления 1-й s-переменной на 2-ю, или 0 при ошибке деления.
*
<Mod s.NUMBER s.NUMBER> == s.NUMBER
*/
int Mod(struct refal_vm *vm, rf_index prev, rf_index next);
/**
* Сравнивает два числа и возвращает '-', когда s.X меньше, чем s.Y;
* '+', когда больше; '0', когда равны.
*
<Compare s.X s.Y>
== '-' | '0' | '+'
s.X, s.Y ::= s.NUMBER
*/
int Compare(struct refal_vm *vm, rf_index prev, rf_index next);
/**\}*/
/**\addtogroup library-stack
* \{
*/
/**
* <Br e.Name '=' e.Expr>
* Закапывает выражение \c e.Expr под именем \c e.Name.
* Имя не должно содержать знак \c '=' на верхнем уровне структуры.
*
* \c Push не использует \c '=' в качестве разделителя.
* Ожидает в качестве имени имя функции, предложения которой
* не содержат выражение-результат (то есть определены без =).
* Имя можно указать как идентификатором, так и текстом.
* Таким образом можно указать начальное содержимое и отчасти решается проблема
* «чтобы понять, какими глобальными переменными пользуется некоторая функция,
* нужно изучить исходный текст самой функции, а также других функций, которые
* она вызывает» стр.6 http://refal.botik.ru/events/IPSRAN-MGTU-seminar-17-06-2023/RAYAP_Lecture4.pdf
*
<Push s.Func | s.CHAR* e.Expr> == []
*/
int Push(struct refal_vm *vm, rf_index prev, rf_index next);
/**
* <Dg e.Name>
* Выкапывает выражение, закопанное под именем e.Name, то есть возвращает последнее
* выражение, закопанное под этим именем и удаляет его из стэка. Если не существует
* выражения, закопанного под именем e.Name, Dg возвращает пустое выражение.
*
* \c Pop работает подобно; имя можно указывать как идентификатором, так и текстом.
*
<Pop s.Func | s.CHAR*> == e.Value
*/
int Pop(struct refal_vm *vm, rf_index prev, rf_index next);
/**\}*/
/**\addtogroup library-str
* \{
*/
/**
* Возвращает s.Type s.SubType e.Expr, где e.Expr остаётся неизменным, а
* s.Type и s.SubType зависят от типа первого элемента выражения e.Expr:
* - 'Lu' заглавная латинская буква
* - 'Ll' строчная латинская буква
* - 'P0' печатный символ
* - 'O0' остальные символы
* - 'D0' десятичная цифра
* - 'Wi' идентификатор (функция). В книге 'F'.
* - 'N0' число
* - 'B0' скобка (открывающая)
* - '*0' пустое выражение
*
* TODO доработать для Unicode.
*/
int Type(struct refal_vm *vm, rf_index prev, rf_index next);
/**
* Возвращает макро-цифру, представленную строкой в поле зрения.
* Если аргумент не начинается с последовательности цифр, функция возвращает 0.
*
<Numb s.Digit* e.Skipped> == s.NUMBER
s.Digit ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
*/
int Numb(struct refal_vm *vm, rf_index prev, rf_index next);
/**
* Является обратной к функции Numb. Возвращает строку десятичных цифр,
* представляющую s.NUMBER. В данной реализации тип чисел знаковый.
*
<Symb s.NUMBER> == s.CHAR+
*/
int Symb(struct refal_vm *vm, rf_index prev, rf_index next);
/**
* Замещает всякое число в e.Expr литерой с соответствующим кодом.
*
<Chr e.Expr> == e.Expr’
*/
int Chr(struct refal_vm *vm, rf_index prev, rf_index next);
/**
* Замещает всякую литерой в e.Expr её кодом в UCS-4 (UTF-32).
*
<Ord e.Expr> == e.Expr’
*/
int Ord(struct refal_vm *vm, rf_index prev, rf_index next);
/**\}*/
/**\addtogroup library-rt
* \{
*/
/**
* Возвращает аргумент командной строки, который имеет порядковый номер s.N.
*
<Arg s.N>
* Не реализована (требует сохранять состояние в статических переменных,
* не ясно, как быть в случае встраивания интерпретатора).
*
* В программах РЕФАЛ рекомендуется использовать точку входа main или Main.
* Эти функции получают в поле зрения список аргументов как (e.Arg)+
*
* В случае встраивания, аргументы размещаются `rf_alloc_strv()`.
*/
int Arg(struct refal_vm *vm, rf_index prev, rf_index next);
/**
* Ищет в поле зрения элемент, являющийся идентификатором вычислимой функции,
* после чего применяет определённую им функцию к выражению e.Arg1 e.Arg2.
*
<Mu e.Arg1 s.Func e.Arg2> == <s.Func e.Arg>
Функция реализована непосредственно в исполнителе.
*/
int Mu(struct refal_vm *vm, rf_index prev, rf_index next);
/**
* Возвращает в поле зрения значение переменной окружения с именем e.EnvName.
*
* TODO Реализация из Refal-05 не различает случаи, когда переменная определена
* с пустым значением, или не определена.
*
<GetEnv e.EnvName> == e.EnvValue
e.EnvName, e.EnvValue ::= s.CHAR*
*/
int GetEnv(struct refal_vm *vm, rf_index prev, rf_index next);
/**
* Завершает исполнение процесса вызовом `exit()`, возвращая числовое
* значение s.RetCode.
*
<Exit s.RetCode>
*/
int Exit(const struct refal_vm *vm, rf_index prev, rf_index next);
/**
* Выполняет команду e.Command при помощи командного процессора системы.
*
* Если e.Command пуста, определяет наличие командного процессора и возвращает
* 0 в случае отсутствия.
*
<System e.Command> == e.RetCode
e.Command ::= s.CHAR*
e.RetCode ::= '-'? s.NUMBER
*/
int System(struct refal_vm *vm, rf_index prev, rf_index next);
/**\}*/