Библиотека PREPR — API-документация
Пакет TMC Suite. Статическая библиотека — препроцессор входных текстовых файлов-шаблонов (
.tpl) для расчётных ядер. Язык документации: русский. Все сигнатуры приведены по исходникам изsrc/libs/PREPR/и общему заголовкуsrc/Include/Prepr1.h.
1. Назначение библиотеки
PREPR — статическая библиотека (StaticLibrary, toolset v145, собирается под Win32 и x64) — это препроцессор входных текстовых файлов-шаблонов (.tpl) для расчётных ядер пакета (PlanarRT_H / PlanarRT_X).
Важно: PREPR — это НЕ препроцессор языка C/C++. Несмотря на то что синтаксис директив внешне похож на директивы C-препроцессора (
#define,#include), PREPR обрабатывает текстовые входные файлы расчёта (шаблоны.tpl) и не имеет отношения к компиляции C++.
Библиотека выполняет над входным шаблоном следующие преобразования:
- обработку директив
#define ИМЯ@ТЕЛО— определение текстовых макросов, в том числе с формальными параметрами (разделитель@, параметры через;); - обработку директив
#include имя_файла— подстановку содержимого включаемого файла на место строки#include; - удаление комментариев — всё после символа
!отбрасывается; маркер\\обрабатывается как склейка строк; - подстановку макросов с фактическими параметрами — рекурсивно, от последнего
#defineк первому; - сохранение всех определений
#defineво временный файл$$vr$$s.prc.
Результат работы — развёрнутый текстовый файл, который далее читается расчётным ядром как обычный входной файл расчёта.
Точка входа — функция MainPrepr1(). Она вызывается из обёртки MainPrepr() (в библиотеке TMCIndan), а та, в свою очередь, — из счётного ядра. Это единственная точка вызова PREPR.
2. Расположение исходников в сборке
Исходники: src/libs/PREPR/. Заголовок: src/Include/Prepr1.h (в проекте подключается как ..\..\INCLUDE\Prepr1.h).
Проект сборки — Prepr.vcxproj (toolset v145, конфигурации Win32/x64, тип StaticLibrary). В сборку входят 9 файлов .cpp:
| Файл | Назначение (кратко) |
|---|---|
DEF_DEST.CPP |
Подстановка/назначение макроопределений (def_main_macdef, работа с целевым телом) |
DEF_ER.CPP |
Тексты сообщений об ошибках (def_err_get) |
DEF_ERD.CPP |
Проверка повторного определения макросов (def_err_dec) |
DEF_MACR.CPP |
Поиск и разбор макроопределений (def_macro, def_separ_mac_name и др.) |
DEF_STR.CPP |
Низкоуровневые операции со связным буфером строк |
DEFMIS.CPP |
Вспомогательные функции (DefineIncludeName, GetCurrentPath, DeleteComment) |
PREP_LD.CPP |
Загрузка/инициализация, работа с include и временным файлом (def_include, load_vr_file) |
PREP_MN.CPP |
Главная логика препроцессора (MainPrepr1, main_preproc, put_error_messege) |
READ_BUF.CPP |
Чтение буфера/строк (read_buf и сопутствующее) |
Файлы вне сборки (legacy / мёртвый код)
Следующие файлы присутствуют в каталоге, но не включены в Prepr.vcxproj и поэтому не описываются:
| Файл | Причина |
|---|---|
DR_BUF.CPP |
Старый автономный тестер со своей функцией main(); содержит единственную внешнюю ссылку на load_preproc_buff |
INCPATH.CPP |
Функции SetIncludePathName / GetIncludePathName — отсутствуют в Prepr1.h, наружу не объявлены |
3. Структуры данных
Объявлены в Prepr1.h.
3.1. BUFFER — связный буфер символов
Главный рабочий буфер препроцессора. Реализован как двусвязный список символов через два массива фиксированного размера NMAX. Вставка и удаление символов выполняются операциями над списком (изменением индексов) без физического сдвига памяти.
typedef struct
{
char *lsplex; // буфер символов (как связный список)
int *ilex; // индекс «следующего» элемента (связи списка)
int inp_p; // текущая позиция чтения
int inp_p_nul; // начало списка свободных ячеек
} BUFFER;
| Поле | Тип | Смысл |
|---|---|---|
lsplex |
char* |
Массив-буфер символов; каждая ячейка хранит один символ, доступ — как к элементу связного списка |
ilex |
int* |
Массив индексов: ilex[i] — номер следующего за i элемента в списке. Через него реализуются вставка/удаление без сдвига памяти |
inp_p |
int |
Текущая позиция чтения (индекс «головы» обрабатываемого участка) |
inp_p_nul |
int |
Начало списка свободных ячеек (откуда берутся ячейки при вставке и куда возвращаются при удалении) |
Размер массивов задаётся макросом NMAX (по умолчанию 30 000 000, см. Prepr1.h).
3.2. MACROS — описание одного макроопределения
Хранит разобранное определение #define: имя, формальные параметры и тело, разбитое на чередующиеся фрагменты («маску»).
typedef struct
{
char mac[ BUF_STR_N_MAX ]; // строка тела #define
char *m[ BUF_PAR_MAX ]; // m[0] — имя; m[1..j1] — имена формальных параметров
char *m1[ BUF_MASKA_MAX ]; // куски тела между параметрами («маска»)
int im1[ BUF_MASKA_MAX ]; // индекс формального параметра перед куском m1[i], или -1
int j1; // число формальных параметров
int i2; // число элементов маски
} MACROS;
| Поле | Тип | Смысл |
|---|---|---|
mac[] |
char[BUF_STR_N_MAX] |
Строка тела #define (исходное тело макроса) |
m[] |
char*[BUF_PAR_MAX] |
Указатели на имена: m[0] — имя макроса; m[1]..m[j1] — имена формальных параметров |
m1[] |
char*[BUF_MASKA_MAX] |
Текстовые фрагменты тела между параметрами — «маска». Тело хранится разбитым на чередующиеся куски |
im1[] |
int[BUF_MASKA_MAX] |
Для каждого фрагмента m1[i] — индекс формального параметра, стоящего перед ним; -1, если параметра нет |
j1 |
int |
Число формальных параметров |
i2 |
int |
Число элементов маски (фрагментов тела) |
Тело макроса хранится разбитым на чередующиеся текстовые фрагменты (m1) с привязанными к ним индексами формальных параметров (im1). При подстановке фрагменты выводятся подряд, а на места параметров вставляются фактические значения.
3.3. Константы размеров и имена (Prepr1.h)
| Константа | Значение | Смысл |
|---|---|---|
NMAX |
30000000 |
Размер массивов буфера BUFFER (число ячеек) |
BUF_STR_INLINE_MAX |
500000 |
Максимальная длина строки при построчной обработке |
BUF_STR_N_MAX |
500000 |
Размер поля MACROS::mac[] (длина тела #define) |
BUF_MASKA_MAX |
800000 |
Размер массивов маски MACROS::m1[] / im1[] |
BUF_PAR_MAX |
60 |
Размер массива MACROS::m[] (имя + формальные параметры) |
VR_MAC_FILE_NAME |
"$$vr$$s.prc" |
Имя временного файла для сохранения всех #define |
VR_MAC_INCLUDE |
"#include $$vr$$s.prc" |
Строка include для временного файла |
DEF_SEPARATOR |
'@' |
Разделитель «имя+параметры / тело» в #define |
Примечание:
DEF_SEPARATORупомянут в коде как символ-разделитель'@'; в самомPrepr1.hон может определяться в другом месте — при сомнении опираться на исходникиDEF_MACR.CPP.
4. Синтаксис директив входного файла
4.1. #define — определение макроса
#define ИМЯ par1; par2; ... @ ТЕЛО
- Распознаются обе формы начала директивы:
#define(с пробелом) и#define(с табуляцией). - Символ-разделитель
@(DEF_SEPARATOR = '@') отделяет «имя + список формальных параметров» от тела макроса. - Формальные параметры перечисляются после имени и разделяются символом
;(точка с запятой). - Если параметров нет, директива имеет вид:
#define ИМЯ@ТЕЛО
- Тело может занимать несколько строк (для переноса используется маркер склейки
\\, см. ниже).
4.2. #include — включение файла
#include имя_файла
- Распознаются обе формы:
#include(с пробелом) и#include(с табуляцией). - Полный путь к включаемому файлу формируется как
<GetCurrentPath()>\<имя_файла>— то есть имя трактуется относительно текущего каталога (см.MainPrepr1, параметрcsCurrentPath). - Содержимое включаемого файла подставляется на место строки
#include.
4.3. Комментарии и склейка строк
| Маркер | Обработка | Функция |
|---|---|---|
! |
Всё после ! в строке отбрасывается (заменяется на " \n") |
DeleteComment |
\\ |
Маркер склейки строк: заменяется на " \n" (используется для переноса длинного тела #define) |
def_sl |
4.4. Вызов (использование) макроса
ИМЯ(парам1; парам2; ...)
- Фактические параметры перечисляются в круглых скобках и разделяются символом
;. - Если фактический параметр целиком заключён в круглые скобки, эти скобки при подстановке заменяются пробелами.
- Подстановка выполняется рекурсивно функцией
def_main_macro— обход определений идёт от последнего#defineк первому. - Все определения
#defineдополнительно сохраняются во временный файл$$vr$$s.prc(функцияload_vr_file).
5. Публичные функции
О макросах
_near,_fortran. Это атрибуты модели памяти и соглашения о вызове из старого 16/32-битного кода. В современной сборке они на семантику не влияют. Ниже в сигнатурах опускаются. Где функция объявлена с такими атрибутами, это отмечено в описании.
5.1. Главная точка входа
void MainPrepr1(char *csTplFileNamePrepr, char *csTplFileName, char *csCurrentPath, char *csError)
Главная точка входа в препроцессор. Выделяет внутренние буферы (szError, szPathName), запускает основную обработку main_preproc, затем освобождает буфер (unload_prep_buf) и удаляет временный файл (dest_prep).
- Параметры:
csTplFileNamePrepr(char*) — имя выходного (развёрнутого, обработанного) файла;csTplFileName(char*) — имя исходного файла-шаблона.tpl;csCurrentPath(char*) — текущий каталог (используется для разрешения относительных путей в#include);csError(char*) — выход: строка ошибки. Пустая строка ("") при успехе, иначе — текст возникшей ошибки.- Возврат:
void(результат сообщается черезcsError).
char* main_preproc(char *szTargetFileName, char *szSourceFileName)
Основная процедура обработки. Читает исходный файл построчно, удаляет комментарии (DeleteComment), загружает текст в буфер, затем последовательно выполняет:
def_include— раскрытие#include;load_vr_file— сохранение всех#defineво временный файл;def_err_dec— проверку повторных определений;def_main_macro— рекурсивную подстановку макросов;
и записывает результат в целевой файл szTargetFileName.
- Параметры:
szTargetFileName(char*) — имя выходного (развёрнутого) файла;szSourceFileName(char*) — имя исходного файла-шаблона.- Возврат: указатель на глобальную строку ошибки
szError(значение""при успехе, иначе — текст ошибки).
5.2. Жизненный цикл и управление памятью
int unload_prep_buf(void)
Освобождает память рабочего буфера: массивы buf.lsplex и buf.ilex.
- Возврат: всегда
0.
int load_preproc_buff(void)
- Статус: функция объявлена в
Prepr1.h, но реализации в библиотеке нет. Единственная внешняя ссылка на неё — в неиспользуемом файлеDR_BUF.CPP(вне сборки). - Возврат: не определён (тела нет).
int dest_prep(void)
Удаляет временный файл <CurrentPath>\$$vr$$s.prc (вызовом remove).
- Возврат: код возврата
remove()(0при успехе удаления).
int buf_init(BUFFER *buf, int n)
Инициализирует буфер: выделяет массивы lsplex (char[n]) и ilex (int[n]) через alloc_mem_err, строит начальный список свободных ячеек.
- Параметры:
buf(BUFFER*) — инициализируемый буфер;n(int) — размер буфера (число ячеек), обычноNMAX.- Возврат:
BUF_NULL(0) при успехе;ERROR_INIT(-11) при нехватке памяти.
int InitCharArray(char **ch, int n)
Инициализация символьного массива: если *ch не NULL, освобождает его, затем выделяет malloc(n).
- Параметры:
ch(char**) — адрес указателя на массив;n(int) — размер выделяемого блока (байт).- Возврат:
0при успехе;-1при ошибке выделения.
int FreeCharArray(char **ch)
Освобождает символьный массив (free(*ch)) и обнуляет указатель (*ch = NULL).
- Параметры:
ch(char**) — адрес указателя на массив. - Возврат:
0.
5.3. Обработка #include и макросов
int def_include(BUFFER *buf)
Ищет директивы #include, подставляет содержимое включаемого файла вместо строки #include, затем выполняет обработку склейки строк (def_sl).
- Параметры:
buf(BUFFER*) — рабочий буфер. - Возврат:
0при успехе;-1,DEF_ERROR_INFILE(-7) при ошибке открытия включаемого файла;DEF_ERROR_MEMORY(-8) при нехватке памяти.
int def_sl(BUFFER *buf)
Заменяет маркер склейки строк \\ на " \n" (перенос строки в теле макроса).
- Параметры:
buf(BUFFER*) — рабочий буфер. - Возврат:
0при успехе;-1при ошибке.
int def_macro(BUFFER *buf)
Ищет очередную директиву #define / #define в буфере, не сдвигая текущую позицию inp_p.
- Параметры:
buf(BUFFER*) — рабочий буфер. - Возврат: позиция найденной директивы (
>= 0) или-1, если#defineне найдено.
int def_main_macro(BUFFER *buf)
Рекурсивно подставляет все макроопределения: обход идёт от последнего #define к первому (для корректного раскрытия макросов, использующих другие макросы).
- Параметры:
buf(BUFFER*) — рабочий буфер. - Возврат:
BUF_NULL(0) при успехе; отрицательный код ошибки (< 0) при сбое.
int def_main_macdef(BUFFER *buf)
Подставляет одно макроопределение: разбирает заголовок (def_separ_mac_name), формирует маску тела (def_set_formal_param), удаляет строку #define из буфера, выполняет подстановку (def_subst_mac).
- Параметры:
buf(BUFFER*) — рабочий буфер. - Возврат:
BUF_NULL(0) при успехе; отрицательный код ошибки при сбое. - Примечание: объявлена с атрибутами
_near fortran, но фактически экспортируется и используется.
int def_subst_mac(BUFFER *buf, MACROS *mac)
Ищет в буфере вызовы макроса mac->m[0] с фактическими параметрами (считываемыми через def_buf_gets_param) и подставляет тело макроса, заменяя формальные параметры на фактические.
- Параметры:
buf(BUFFER*) — рабочий буфер;mac(MACROS*) — разобранное определение макроса.- Возврат:
BUF_NULL(0) при успехе; отрицательный код ошибки при сбое.
int def_set_formal_param(BUFFER *buf, MACROS *mac, int i)
Разбирает тело макроса, заполняя массивы маски mac->m1[] (текстовые фрагменты) и mac->im1[] (индексы формальных параметров).
- Параметры:
buf(BUFFER*) — рабочий буфер;mac(MACROS*) — заполняемое определение;i(int) — начальная позиция (тела) в буфере.- Возврат: позиция конца тела (
>= 0) или-1при ошибке.
int def_separ_mac_name(BUFFER *buf, MACROS *mac)
Разбирает заголовок #define ИМЯ par1; par2; ... @ ТЕЛО: записывает имя в mac->m[0], формальные параметры — в mac->m[1..], число параметров — в mac->j1, находит разделитель @.
- Параметры:
buf(BUFFER*) — рабочий буфер;mac(MACROS*) — заполняемое определение.- Возврат: позиция разделителя
@(>= 0) или код ошибки:BUF_ERROR_NO_SEP(-6),BUF_ERROR_NO_FORMAL_PARAM(-9).
int def_err_dec(BUFFER *buf)
Проверяет повторное определение имени макроса (одно и то же имя в двух #define).
- Параметры:
buf(BUFFER*) — рабочий буфер. - Возврат:
BUF_NULL(0), если повторов нет;BUF_ERROR_REDEC(-10) при обнаружении повторного определения.
int load_vr_file(BUFFER *buf)
Сохраняет все определения #define во временный файл $$vr$$s.prc (VR_MAC_FILE_NAME). Многострочные определения разбиваются с маркером склейки \\.
- Параметры:
buf(BUFFER*) — рабочий буфер. - Возврат:
BUF_NULL(0) при успехе;-1при ошибке файла;-11(ERROR_INIT) при нехватке памяти.
5.4. Низкоуровневые операции со связным буфером (DEF_STR.CPP)
int buf_gets(char *str, int n, BUFFER *buf)
Читает строку из связного буфера в str (до завершающего \0), но не более n символов.
- Параметры:
str(char*) — приёмный буфер;n(int) — лимит символов;buf(BUFFER*) — рабочий буфер. - Возврат:
BUF_NULL/BUF_EOF/BUF_ABN(см. раздел 6).
int read_buf(char *str, int n, BUFFER *buf)
Аналогично buf_gets, но чтение завершается по \0 или по \n (читает одну строку).
- Параметры: как у
buf_gets. - Возврат:
BUF_NULL/BUF_EOF/BUF_ABN.
int buf_puts(char *str, BUFFER *buf)
Вставляет строку str (вместе с завершающим \0) в текущую позицию буфера, не сдвигая указатель.
- Параметры:
str(char*) — вставляемая строка;buf(BUFFER*) — рабочий буфер. - Возврат: код результата (
BUF_NULLпри успехе).
int buf_puts1(char *str, BUFFER *buf)
Как buf_puts, но без завершающего \0; указатель не сдвигается.
int buf_puts2(char *str, BUFFER *buf)
Без завершающего \0; указатель сдвигается на конец вставленного фрагмента.
int buf_puts3(char *str, BUFFER *buf)
С завершающим \0; указатель сдвигается на конец вставленного фрагмента. Используется при построчном чтении файла в буфер.
Сводка вариантов
buf_puts*:
Функция Завершающий \0Сдвиг указателя buf_putsда нет buf_puts1нет нет buf_puts2нет да buf_puts3да да
int buf_dels(BUFFER *buf, int n)
Удаляет n элементов начиная с текущей позиции (удалённые ячейки возвращаются в список свободных).
- Параметры:
buf(BUFFER*) — рабочий буфер;n(int) — число удаляемых элементов. - Возврат: код результата.
void def_gets(char *mac1, char *ch)
Копирует из ch в mac1 идентификатор (символы A-Z a-z 0-9 _) до первого символа, не входящего в идентификатор.
- Параметры:
mac1(char*) — приёмник идентификатора;ch(char*) — исходная строка.
int def_buf_gets_mac(BUFFER *buf, char *mac1)
Считывает из буфера идентификатор (имя макроса при поиске вызова) в mac1.
- Параметры:
buf(BUFFER*) — рабочий буфер;mac1(char*) — приёмник имени. - Возврат:
0при успехе;BUF_EOFпри конце буфера.
int def_buf_gets_param(BUFFER *buf, char *mac1)
Считывает один фактический параметр вызова макроса до символа ; (с учётом вложенных скобок). Если параметр целиком в круглых скобках, скобки заменяются пробелами.
- Параметры:
buf(BUFFER*) — рабочий буфер;mac1(char*) — приёмник параметра. - Возврат:
BUF_NULL/BUF_EOF/BUF_ERROR_FACT_PARAM(-5).
int buf_cmpn(BUFFER *buf, int n, char *mac)
Сравнивает n символов буфера (с текущей позиции) со строкой mac.
- Параметры:
buf(BUFFER*) — рабочий буфер;n(int) — число символов;mac(char*) — образец. - Возврат:
BUF_NULL(совпало) /BUF_EOF(не совпало или конец).
int buf_cmpn2(BUFFER *buf, int n, char *mac1, char *mac2)
Сравнивает n символов буфера с одной из двух строк mac1 / mac2. Применяется для распознавания пар форм директив: #define / #define и #include / #include.
- Параметры:
buf(BUFFER*) — рабочий буфер;n(int) — число символов;mac1,mac2(char*) — два образца. - Возврат:
BUF_NULL(совпало с одним из) /BUF_EOF.
5.5. Ошибки и вспомогательные функции
char* def_err_get(int i_err)
Возвращает текст сообщения об ошибке по её коду (внутренний массив error[], индексация error[-i_err]).
- Параметры:
i_err(int) — код ошибки (0..-11, см. раздел 6). - Возврат: указатель на строку-описание ошибки.
char* DefineIncludeName(char *str, char *str1)
- Статус: реализация в
DEFMIS.CPPфактически пустая (код закомментирован); функция возвращаетstrбез изменений. - Параметры:
str,str1(char*). - Возврат:
str(без обработки).
char* GetCurrentPath(void)
Возвращает текущий каталог — глобальную строку szPathName (устанавливается в MainPrepr1 из csCurrentPath). Используется при формировании путей #include.
- Возврат: указатель на строку текущего каталога.
void DeleteComment(char *pszStr)
Обрезает строку по символу !: всё начиная с ! заменяется на " \n" (удаление комментария).
- Параметры:
pszStr(char*) — обрабатываемая строка (изменяется на месте).
int put_error_messege(char *szError1)
Копирует текст ошибки szError1 в глобальную строку szError.
- Параметры:
szError1(char*) — текст ошибки. - Возврат: код результата.
- Примечание: в
Prepr1.hне объявлена; реализована вPREP_MN.CPPи используется внутри библиотеки.
6. Коды ошибок
Определены в Prepr1.h. Тексты возвращаются функцией def_err_get (файл DEF_ER.CPP).
| Константа | Код | Текст сообщения |
|---|---|---|
BUF_NULL |
0 |
all right (успех) |
BUF_EOF |
-1 |
very small memory |
BUF_ABN |
-2 |
error in buffer |
DEF_ER_BRACKET |
-3 |
error in bracket |
BUF_ERROR_MACR |
-4 |
error in macro define |
BUF_ERROR_FACT_PARAM |
-5 |
error in fact parameters |
BUF_ERROR_NO_SEP |
-6 |
not separator or error in formal param |
DEF_ERROR_INFILE |
-7 |
error when open include file |
DEF_ERROR_MEMORY |
-8 |
not memory |
BUF_ERROR_NO_FORMAL_PARAM |
-9 |
error in formal parameters |
BUF_ERROR_REDEC |
-10 |
redefine macros |
ERROR_INIT |
-11 |
error not enought memory |
Замечание о точности кодов. Некоторые функции при ошибке выделения памяти возвращают «сырой»
-1, что по таблице соответствуетBUF_EOFс текстомvery small memory. Текст не всегда точно отражает реальную причину сбоя — при диагностике следует учитывать контекст вызова, а не только сам код.
7. Зависимости
- Библиотеки
exprintиcomplex— НЕ используются. PREPR работает только с текстом, без вычисления выражений и комплексной арифметики. - Библиотека
TMCLibError— упоминается лишь в закомментированном коде. В рабочейMainPrepr1вместо классаCTmcLibErrorиспользуется простой параметрchar *csError. - Вызывающая сторона: PREPR вызывается из библиотеки TMCIndan — обёртка
MainPrepr()(TmcRTH_Indan.cpp:846) поверхMainPrepr1(с переходом отCString/CTmcLibError&кchar*). Это единственная точка вызова PREPR.
Общие заголовки (src/Include/), фигурирующие в исходниках PREPR:
Prepr1.h, typedef.h, error1.h, tmclimit.h, mainwndw.h, tpl_file.h, tmc_lib.h (предоставляет alloc_mem_err / free_mem), run_flag.h, listing.h, indan.h, descrptr.h.
The PREPR library — API documentation
TMC Suite package. A static library — a preprocessor of the input text template files (
.tpl) for the compute kernels. All signatures are taken from the sources insrc/libs/PREPR/and the shared headersrc/Include/Prepr1.h.
1. Purpose of the library
PREPR is a static library (StaticLibrary, toolset v145, built for Win32
and x64) — a preprocessor of the input text template files (.tpl) for the
package's compute kernels (PlanarRT_H / PlanarRT_X).
Important: PREPR is NOT a C/C++ language preprocessor. Even though the syntax of the directives outwardly resembles the C-preprocessor directives (
#define,#include), PREPR processes text computation input files (.tpltemplates) and has no relation to C++ compilation.
The library performs the following transformations on the input template:
- processing of
#define NAME@BODYdirectives — the definition of text macros, including ones with formal parameters (the@separator, parameters separated by;); - processing of
#include file_namedirectives — the substitution of the included file's contents in place of the#includeline; - removal of comments — everything after the
!character is discarded; the\\marker is processed as a line join; - substitution of macros with actual parameters — recursively, from the last
#defineto the first; - saving all the
#definedefinitions into a temporary file$$vr$$s.prc.
The result of the work is an expanded text file, which is then read by the compute kernel as an ordinary computation input file.
The entry point is the MainPrepr1() function. It is called from the wrapper
MainPrepr() (in the TMCIndan library), which in turn is called from the compute
kernel. This is the only call site of PREPR.
2. Location of the sources in the build
Sources: src/libs/PREPR/. Header: src/Include/Prepr1.h (in the project it is
included as ..\..\INCLUDE\Prepr1.h).
The build project is Prepr.vcxproj (toolset v145, Win32/x64 configurations,
type StaticLibrary). The build contains 9 .cpp files:
| File | Purpose (briefly) |
|---|---|
DEF_DEST.CPP |
Substitution/assignment of macro definitions (def_main_macdef, working with the target body) |
DEF_ER.CPP |
Error message texts (def_err_get) |
DEF_ERD.CPP |
Checking for macro re-definition (def_err_dec) |
DEF_MACR.CPP |
Finding and parsing macro definitions (def_macro, def_separ_mac_name, etc.) |
DEF_STR.CPP |
Low-level operations on the linked string buffer |
DEFMIS.CPP |
Auxiliary functions (DefineIncludeName, GetCurrentPath, DeleteComment) |
PREP_LD.CPP |
Loading/initialization, handling include and the temporary file (def_include, load_vr_file) |
PREP_MN.CPP |
The main preprocessor logic (MainPrepr1, main_preproc, put_error_messege) |
READ_BUF.CPP |
Reading the buffer/lines (read_buf and related) |
Files outside the build (legacy / dead code)
The following files are present in the directory but are not included in
Prepr.vcxproj and are therefore not described:
| File | Reason |
|---|---|
DR_BUF.CPP |
An old standalone tester with its own main() function; contains the only external reference to load_preproc_buff |
INCPATH.CPP |
The functions SetIncludePathName / GetIncludePathName — absent from Prepr1.h, not declared externally |
3. Data structures
Declared in Prepr1.h.
3.1. BUFFER — a linked character buffer
The main working buffer of the preprocessor. It is implemented as a doubly linked
list of characters through two fixed-size arrays NMAX. Insertion and deletion of
characters are performed by operations on the list (changing indices) without a
physical memory shift.
typedef struct
{
char *lsplex; // character buffer (as a linked list)
int *ilex; // index of the "next" element (list links)
int inp_p; // current reading position
int inp_p_nul; // start of the free-cell list
} BUFFER;
| Field | Type | Meaning |
|---|---|---|
lsplex |
char* |
The character buffer array; each cell stores one character, accessed as an element of a linked list |
ilex |
int* |
The index array: ilex[i] is the number of the element following i in the list. Through it insertion/deletion are implemented without a memory shift |
inp_p |
int |
The current reading position (the index of the "head" of the processed segment) |
inp_p_nul |
int |
The start of the list of free cells (from which cells are taken on insertion and to which they are returned on deletion) |
The size of the arrays is set by the NMAX macro (by default 30,000,000, see
Prepr1.h).
3.2. MACROS — the description of one macro definition
Stores a parsed #define definition: the name, the formal parameters, and the
body split into alternating fragments (a "mask").
typedef struct
{
char mac[ BUF_STR_N_MAX ]; // the #define body string
char *m[ BUF_PAR_MAX ]; // m[0] — the name; m[1..j1] — the formal parameter names
char *m1[ BUF_MASKA_MAX ]; // the body pieces between the parameters (the "mask")
int im1[ BUF_MASKA_MAX ]; // the index of the formal parameter before the m1[i] piece, or -1
int j1; // the number of formal parameters
int i2; // the number of mask elements
} MACROS;
| Field | Type | Meaning |
|---|---|---|
mac[] |
char[BUF_STR_N_MAX] |
The #define body string (the original macro body) |
m[] |
char*[BUF_PAR_MAX] |
Pointers to the names: m[0] — the macro name; m[1]..m[j1] — the names of the formal parameters |
m1[] |
char*[BUF_MASKA_MAX] |
The text fragments of the body between the parameters — the "mask". The body is stored split into alternating pieces |
im1[] |
int[BUF_MASKA_MAX] |
For each fragment m1[i] — the index of the formal parameter standing before it; -1 if there is no parameter |
j1 |
int |
The number of formal parameters |
i2 |
int |
The number of mask elements (body fragments) |
The macro body is stored split into alternating text fragments (m1) with the
indices of the formal parameters bound to them (im1). During substitution the
fragments are output in sequence, and the actual values are inserted in place of the
parameters.
3.3. Size constants and names (Prepr1.h)
| Constant | Value | Meaning |
|---|---|---|
NMAX |
30000000 |
The size of the BUFFER buffer arrays (the number of cells) |
BUF_STR_INLINE_MAX |
500000 |
The maximum line length during line-by-line processing |
BUF_STR_N_MAX |
500000 |
The size of the MACROS::mac[] field (the #define body length) |
BUF_MASKA_MAX |
800000 |
The size of the mask arrays MACROS::m1[] / im1[] |
BUF_PAR_MAX |
60 |
The size of the MACROS::m[] array (the name + formal parameters) |
VR_MAC_FILE_NAME |
"$$vr$$s.prc" |
The name of the temporary file for saving all #defines |
VR_MAC_INCLUDE |
"#include $$vr$$s.prc" |
The include line for the temporary file |
DEF_SEPARATOR |
'@' |
The "name+parameters / body" separator in #define |
Note:
DEF_SEPARATORis mentioned in the code as the separator character'@'; inPrepr1.hitself it may be defined elsewhere — when in doubt, rely on theDEF_MACR.CPPsources.
4. Syntax of the input-file directives
4.1. #define — a macro definition
#define NAME par1; par2; ... @ BODY
- Both forms of the directive start are recognized:
#define(with a space) and#define(with a tab). - The separator
@(DEF_SEPARATOR = '@') separates the "name + list of formal parameters" from the macro body. - The formal parameters are listed after the name and separated by the
;(semicolon). - If there are no parameters, the directive has the form:
#define NAME@BODY
- The body may span several lines (a
\\join marker is used for continuation, see below).
4.2. #include — file inclusion
#include file_name
- Both forms are recognized:
#include(with a space) and#include(with a tab). - The full path to the included file is formed as
<GetCurrentPath()>\<file_name>— that is, the name is treated relative to the current directory (seeMainPrepr1, thecsCurrentPathparameter). - The contents of the included file are substituted in place of the
#includeline.
4.3. Comments and line joining
| Marker | Processing | Function |
|---|---|---|
! |
Everything after ! in the line is discarded (replaced with " \n") |
DeleteComment |
\\ |
A line-join marker: replaced with " \n" (used to continue a long #define body) |
def_sl |
4.4. Calling (using) a macro
NAME(param1; param2; ...)
- The actual parameters are listed in parentheses and separated by the
;. - If an actual parameter is entirely enclosed in parentheses, those parentheses are replaced with spaces during substitution.
- Substitution is performed recursively by the
def_main_macrofunction — the definitions are traversed from the last#defineto the first. - All the
#definedefinitions are additionally saved into the temporary file$$vr$$s.prc(theload_vr_filefunction).
5. Public functions
About the
_near,_fortranmacros. These are memory-model and calling-convention attributes from old 16/32-bit code. In the modern build they do not affect the semantics. They are omitted from the signatures below. Where a function is declared with such attributes, this is noted in the description.
5.1. The main entry point
void MainPrepr1(char *csTplFileNamePrepr, char *csTplFileName, char *csCurrentPath, char *csError)
The main entry point into the preprocessor. It allocates the internal buffers
(szError, szPathName), runs the main processing main_preproc, then frees the
buffer (unload_prep_buf) and deletes the temporary file (dest_prep).
- Parameters:
csTplFileNamePrepr(char*) — the name of the output (expanded, processed) file;csTplFileName(char*) — the name of the source template file.tpl;csCurrentPath(char*) — the current directory (used to resolve relative paths in#include);csError(char*) — output: the error string. An empty string ("") on success, otherwise the text of the error that occurred.- Return:
void(the result is reported throughcsError).
char* main_preproc(char *szTargetFileName, char *szSourceFileName)
The main processing procedure. It reads the source file line by line, removes
comments (DeleteComment), loads the text into the buffer, then sequentially
performs:
def_include— the expansion of#include;load_vr_file— saving all#defines into the temporary file;def_err_dec— checking for re-definitions;def_main_macro— the recursive substitution of macros;
and writes the result into the target file szTargetFileName.
- Parameters:
szTargetFileName(char*) — the name of the output (expanded) file;szSourceFileName(char*) — the name of the source template file.- Return: a pointer to the global error string
szError(the value""on success, otherwise the error text).
5.2. Lifecycle and memory management
int unload_prep_buf(void)
Frees the memory of the working buffer: the arrays buf.lsplex and buf.ilex.
- Return: always
0.
int load_preproc_buff(void)
- Status: the function is declared in
Prepr1.h, but there is no implementation in the library. The only external reference to it is in the unused fileDR_BUF.CPP(outside the build). - Return: undefined (no body).
int dest_prep(void)
Deletes the temporary file <CurrentPath>\$$vr$$s.prc (by calling remove).
- Return: the return code of
remove()(0on successful deletion).
int buf_init(BUFFER *buf, int n)
Initializes the buffer: allocates the arrays lsplex (char[n]) and ilex
(int[n]) via alloc_mem_err, builds the initial free-cell list.
- Parameters:
buf(BUFFER*) — the buffer being initialized;n(int) — the buffer size (the number of cells), usuallyNMAX.- Return:
BUF_NULL(0) on success;ERROR_INIT(-11) on out of memory.
int InitCharArray(char **ch, int n)
Initializes a character array: if *ch is not NULL, frees it, then allocates
malloc(n).
- Parameters:
ch(char**) — the address of the pointer to the array;n(int) — the size of the allocated block (bytes).- Return:
0on success;-1on allocation error.
int FreeCharArray(char **ch)
Frees a character array (free(*ch)) and nulls the pointer (*ch = NULL).
- Parameters:
ch(char**) — the address of the pointer to the array. - Return:
0.
5.3. Processing #include and macros
int def_include(BUFFER *buf)
Finds #include directives, substitutes the contents of the included file in place
of the #include line, then performs line-join processing (def_sl).
- Parameters:
buf(BUFFER*) — the working buffer. - Return:
0on success;-1,DEF_ERROR_INFILE(-7) on an error opening the included file;DEF_ERROR_MEMORY(-8) on out of memory.
int def_sl(BUFFER *buf)
Replaces the line-join marker \\ with " \n" (a line break in a macro body).
- Parameters:
buf(BUFFER*) — the working buffer. - Return:
0on success;-1on error.
int def_macro(BUFFER *buf)
Finds the next #define / #define directive in the buffer without shifting
the current position inp_p.
- Parameters:
buf(BUFFER*) — the working buffer. - Return: the position of the found directive (
>= 0) or-1if#definewas not found.
int def_main_macro(BUFFER *buf)
Recursively substitutes all macro definitions: the traversal goes from the
last #define to the first (for the correct expansion of macros that use
other macros).
- Parameters:
buf(BUFFER*) — the working buffer. - Return:
BUF_NULL(0) on success; a negative error code (< 0) on failure.
int def_main_macdef(BUFFER *buf)
Substitutes one macro definition: parses the header (def_separ_mac_name),
forms the body mask (def_set_formal_param), removes the #define line from the
buffer, performs the substitution (def_subst_mac).
- Parameters:
buf(BUFFER*) — the working buffer. - Return:
BUF_NULL(0) on success; a negative error code on failure. - Note: declared with the
_near fortranattributes, but is actually exported and used.
int def_subst_mac(BUFFER *buf, MACROS *mac)
Finds in the buffer calls of the macro mac->m[0] with actual parameters (read via
def_buf_gets_param) and substitutes the macro body, replacing the formal
parameters with the actual ones.
- Parameters:
buf(BUFFER*) — the working buffer;mac(MACROS*) — the parsed macro definition.- Return:
BUF_NULL(0) on success; a negative error code on failure.
int def_set_formal_param(BUFFER *buf, MACROS *mac, int i)
Parses the macro body, filling the mask arrays mac->m1[] (text fragments) and
mac->im1[] (formal-parameter indices).
- Parameters:
buf(BUFFER*) — the working buffer;mac(MACROS*) — the definition being filled;i(int) — the start position (of the body) in the buffer.- Return: the position of the end of the body (
>= 0) or-1on error.
int def_separ_mac_name(BUFFER *buf, MACROS *mac)
Parses the header #define NAME par1; par2; ... @ BODY: writes the name into
mac->m[0], the formal parameters into mac->m[1..], the number of parameters into
mac->j1, and finds the @ separator.
- Parameters:
buf(BUFFER*) — the working buffer;mac(MACROS*) — the definition being filled.- Return: the position of the
@separator (>= 0) or an error code:BUF_ERROR_NO_SEP(-6),BUF_ERROR_NO_FORMAL_PARAM(-9).
int def_err_dec(BUFFER *buf)
Checks for the re-definition of a macro name (the same name in two #defines).
- Parameters:
buf(BUFFER*) — the working buffer. - Return:
BUF_NULL(0) if there are no repeats;BUF_ERROR_REDEC(-10) if a re-definition is detected.
int load_vr_file(BUFFER *buf)
Saves all the #define definitions into the temporary file $$vr$$s.prc
(VR_MAC_FILE_NAME). Multi-line definitions are split with the join marker \\.
- Parameters:
buf(BUFFER*) — the working buffer. - Return:
BUF_NULL(0) on success;-1on a file error;-11(ERROR_INIT) on out of memory.
5.4. Low-level operations on the linked buffer (DEF_STR.CPP)
int buf_gets(char *str, int n, BUFFER *buf)
Reads a string from the linked buffer into str (up to the terminating \0), but
no more than n characters.
- Parameters:
str(char*) — the receiving buffer;n(int) — the character limit;buf(BUFFER*) — the working buffer. - Return:
BUF_NULL/BUF_EOF/BUF_ABN(see section 6).
int read_buf(char *str, int n, BUFFER *buf)
Similar to buf_gets, but reading ends at \0 or at \n (reads one line).
- Parameters: as in
buf_gets. - Return:
BUF_NULL/BUF_EOF/BUF_ABN.
int buf_puts(char *str, BUFFER *buf)
Inserts the string str (together with the terminating \0) at the current buffer
position without shifting the pointer.
- Parameters:
str(char*) — the string to insert;buf(BUFFER*) — the working buffer. - Return: the result code (
BUF_NULLon success).
int buf_puts1(char *str, BUFFER *buf)
Like buf_puts, but without the terminating \0; the pointer is not
shifted.
int buf_puts2(char *str, BUFFER *buf)
Without the terminating \0; the pointer is shifted to the end of the inserted
fragment.
int buf_puts3(char *str, BUFFER *buf)
With the terminating \0; the pointer is shifted to the end of the inserted
fragment. Used when reading a file into the buffer line by line.
A summary of the
buf_puts*variants:
Function Terminating \0Pointer shift buf_putsyes no buf_puts1no no buf_puts2no yes buf_puts3yes yes
int buf_dels(BUFFER *buf, int n)
Deletes n elements starting from the current position (the deleted cells are
returned to the free list).
- Parameters:
buf(BUFFER*) — the working buffer;n(int) — the number of elements to delete. - Return: the result code.
void def_gets(char *mac1, char *ch)
Copies from ch into mac1 an identifier (the characters A-Z a-z 0-9 _) up to
the first character that is not part of the identifier.
- Parameters:
mac1(char*) — the identifier receiver;ch(char*) — the source string.
int def_buf_gets_mac(BUFFER *buf, char *mac1)
Reads an identifier from the buffer (the macro name when searching for a call) into
mac1.
- Parameters:
buf(BUFFER*) — the working buffer;mac1(char*) — the name receiver. - Return:
0on success;BUF_EOFat the end of the buffer.
int def_buf_gets_param(BUFFER *buf, char *mac1)
Reads one actual parameter of a macro call up to a ; character (taking nested
parentheses into account). If the parameter is entirely in parentheses, the
parentheses are replaced with spaces.
- Parameters:
buf(BUFFER*) — the working buffer;mac1(char*) — the parameter receiver. - Return:
BUF_NULL/BUF_EOF/BUF_ERROR_FACT_PARAM(-5).
int buf_cmpn(BUFFER *buf, int n, char *mac)
Compares n characters of the buffer (from the current position) with the string
mac.
- Parameters:
buf(BUFFER*) — the working buffer;n(int) — the number of characters;mac(char*) — the pattern. - Return:
BUF_NULL(matched) /BUF_EOF(not matched or end).
int buf_cmpn2(BUFFER *buf, int n, char *mac1, char *mac2)
Compares n characters of the buffer with one of two strings mac1 / mac2.
Used to recognize the pairs of directive forms: #define / #define and
#include / #include.
- Parameters:
buf(BUFFER*) — the working buffer;n(int) — the number of characters;mac1,mac2(char*) — the two patterns. - Return:
BUF_NULL(matched one of them) /BUF_EOF.
5.5. Errors and auxiliary functions
char* def_err_get(int i_err)
Returns the text of an error message by its code (the internal array error[],
indexed as error[-i_err]).
- Parameters:
i_err(int) — the error code (0..-11, see section 6). - Return: a pointer to the error description string.
char* DefineIncludeName(char *str, char *str1)
- Status: the implementation in
DEFMIS.CPPis in fact empty (the code is commented out); the function returnsstrunchanged. - Parameters:
str,str1(char*). - Return:
str(without processing).
char* GetCurrentPath(void)
Returns the current directory — the global string szPathName (set in MainPrepr1
from csCurrentPath). Used when forming #include paths.
- Return: a pointer to the current-directory string.
void DeleteComment(char *pszStr)
Truncates the string at the ! character: everything from ! onward is replaced
with " \n" (comment removal).
- Parameters:
pszStr(char*) — the string being processed (modified in place).
int put_error_messege(char *szError1)
Copies the error text szError1 into the global string szError.
- Parameters:
szError1(char*) — the error text. - Return: the result code.
- Note: not declared in
Prepr1.h; implemented inPREP_MN.CPPand used inside the library.
6. Error codes
Defined in Prepr1.h. The texts are returned by the def_err_get function (the
DEF_ER.CPP file).
| Constant | Code | Message text |
|---|---|---|
BUF_NULL |
0 |
all right (success) |
BUF_EOF |
-1 |
very small memory |
BUF_ABN |
-2 |
error in buffer |
DEF_ER_BRACKET |
-3 |
error in bracket |
BUF_ERROR_MACR |
-4 |
error in macro define |
BUF_ERROR_FACT_PARAM |
-5 |
error in fact parameters |
BUF_ERROR_NO_SEP |
-6 |
not separator or error in formal param |
DEF_ERROR_INFILE |
-7 |
error when open include file |
DEF_ERROR_MEMORY |
-8 |
not memory |
BUF_ERROR_NO_FORMAL_PARAM |
-9 |
error in formal parameters |
BUF_ERROR_REDEC |
-10 |
redefine macros |
ERROR_INIT |
-11 |
error not enought memory |
A note on the accuracy of the codes. On a memory-allocation error some functions return a "raw"
-1, which by the table corresponds toBUF_EOFwith the textvery small memory. The text does not always accurately reflect the real cause of the failure — when diagnosing, take the call context into account, not just the code itself.
7. Dependencies
- The
exprintandcomplexlibraries are NOT used. PREPR works only with text, without expression evaluation and complex arithmetic. - The
TMCLibErrorlibrary is mentioned only in commented-out code. In the workingMainPrepr1, instead of theCTmcLibErrorclass, a simple parameterchar *csErroris used. - The calling side: PREPR is called from the TMCIndan library — the wrapper
MainPrepr()(TmcRTH_Indan.cpp:846) overMainPrepr1(with a transition fromCString/CTmcLibError&tochar*). This is the only call site of PREPR.
The shared headers (src/Include/) that appear in the PREPR sources:
Prepr1.h, typedef.h, error1.h, tmclimit.h, mainwndw.h, tpl_file.h,
tmc_lib.h (provides alloc_mem_err / free_mem), run_flag.h, listing.h,
indan.h, descrptr.h.