Простая вроде задача... много C-type структур в текстовых .h файлах - как обработать пакетом?

Данные

Возьмем типичный фонт для графической библиотеки, например AdafruitGFX. Обычно это файл с расширением .h и содержащий внутри исходный код С/С++, описывающий нужные структуры данных (пример, FreeSerifItalic9pt7b.h : )

const uint8_t FreeSerifItalic9pt7bBitmaps[] PROGMEM = {
  0x11, 0x12, 0x22, 0x24, 0x40, 0x0C, 0xDE, 0xE5, 0x40, 0x04, 0x82, 0x20,
  0x98, 0x24, 0x7F, 0xC4, 0x82, 0x23, 0xFC, 0x24, 0x11, 0x04, 0x83, 0x20,
  0x1C, 0x1B, 0x99, 0x4D, 0x26, 0x81, 0xC0, 0x70, 0x1C, 0x13, 0x49, 0xA4,
 ...
  0x28, 0x18, 0x08, 0x08, 0x08, 0x18, 0x00, 0x3F, 0x42, 0x04, 0x08, 0x10,
  0x20, 0x40, 0x72, 0x0E, 0x08, 0x61, 0x04, 0x30, 0x86, 0x08, 0x61, 0x04,
  0x30, 0xC3, 0x8F, 0x00, 0xFF, 0xF0, 0x1E, 0x0C, 0x10, 0x20, 0xC1, 0x82,
  0x04, 0x1C, 0x30, 0x40, 0x83, 0x04, 0x08, 0x20, 0x60, 0x99, 0x8E };

const GFXglyph FreeSerifItalic9pt7bGlyphs[] PROGMEM = {
  {     0,   0,   0,   5,    0,    1 },   // 0x20 ' '
  {     0,   4,  12,   6,    1,  -11 },   // 0x21 '!'
  {     6,   5,   4,   6,    3,  -11 },   // 0x22 '"'
  {     9,  10,  12,   9,    0,  -11 },   // 0x23 '#'
  {    24,   9,  15,   9,    1,  -12 },   // 0x24 '$'
  {    41,  14,  12,  15,    1,  -11 },   // 0x25 '%'
 ...
  {  1100,   9,   8,   8,   -1,   -7 },   // 0x78 'x'
  {  1109,   9,  12,   9,    0,   -7 },   // 0x79 'y'
  {  1123,   8,   9,   7,    0,   -7 },   // 0x7A 'z'
  {  1132,   6,  15,   7,    1,  -11 },   // 0x7B '{'
  {  1144,   1,  12,   5,    2,  -11 },   // 0x7C '|'
  {  1146,   7,  16,   7,    0,  -12 },   // 0x7D '}'
  {  1160,   8,   3,  10,    1,   -5 } }; // 0x7E '~'

const GFXfont FreeSerifItalic9pt7b PROGMEM = {
  (uint8_t  *)FreeSerifItalic9pt7bBitmaps,
  (GFXglyph *)FreeSerifItalic9pt7bGlyphs,
  0x20, 0x7E, 22 };

// Approx. 1835 bytes

Точное содержание и даже формат файла нам сейчас не важны.

Обычно такие файлы используют так - включают в проект строчку

#include "FreeSerifItalic9pt7b.h"

и далее обращаются к структурам и отдельным полям как переменным программы.

Проблема

Предположим мы хотим не использовать фонты в программе, а отредактировать их содержимое. Если файлов один или два, проще всего было бы написать С++ код, который подключает нужные фонты, меняет их данные и сохраняет отредактированные структуры в таком же формате. Но в результате нам придется компилировать код с каждым фонтом отдельно. А что делать если файлов 100? Или, для совсем абстрактного подхода - 10 тыс?
Другой вариант - написать парсер, который будет разбирать файл как текстовой, удалять комментарии, находить заголовки структур и вычитывать строчки шестнацатиричных чисел… Но это же гемор… и огромная опасность ошибок, если формат файла не очень жесткий.

И вроде бы, у нас под рукой есть компилятор, который как раз-таки написан для того, чтобы парсить исходные файлы.

Вопрос - есть какой-то простой и общепринятый способ решения подобной задачи? Я за два дня гугления не нашел.

Точнее, я нашел способ автоматизировать процесс сборки отдельного С-кода для каждого из набора файлов (через make) - и это работает. Но это же громоздко и неэффективно…

Не совсем понял бизнес-процесс.
Кто будет редактировать 1000 шрифтов и в каком смысле - редактировать? Если человек, то ему фонт нужно видеть, не до пакетной обработки. А кампутеру эти буквочки не нужны в принципе.

самый простой пример - конвертация в другой формат.

На самом деле я взял фонты для примера, как файлы с довольно сложной структурой (а не просто массив).

Вопрос максимально абстрактный - если у нас есть куча файлов, содержащих данные в формате “исходного кода” - какие есть варианты обработать их пакетно?

Поскольку мне не дает покоя мысль, что именно таким парсингом исходников занимается компилятор, то более узкий вопрос - нет ли у GCC или какой-то утилиты из его пакета такого режима, чтобы оно парсило исходный текст и выдавало на выходе дамп этой же структуры в двоичном виде? - это бы было самым простым решением, как мне кажется

Т.е. есть желание просто накидать каких попало шрифтов, а gcc чтоб расхлёбывал?

при чем тут это?

Да просто пытаюсь понять в чем тайный смысл использования чего-то из gcc в такой задаче.
Конвертирование подразумевает, что система “владеет” входным и выходным словарями, а так же формализованными правилами перевода первого во второе.
Сама она угадывать не может, тебе придётся описать все три сущности. И какая разница в чем - в gcc или perl? Хранить-то в итоге в чем - C-code или типа precompiled?

Описать правила перевода придется, это да. Но вопрос не в этом.
Вопрос в том, как, еще до преобразования - правильно извлечь данные из файла, в котором они хранятся в виде исходного кода С++.

Нет, если будешь использовать интерпретируемый язык (php, например).

Это означает парсинг кода как текста

И? Ты же сам этот вариант предложил, но тебе не нравилось “компилировать”…

а вот это интересно.

Судя по немногим откликам, похоже что я “хочу странного”. Возможно что поставновка задачи не вполне верная.
Буду думать дальше.

Автоматизируй компиляцию, оставь на ночь. Поутру откомпилирует тебе 100 или 10 тыщ файлов, например.

спасибо, я собственно так и сделал уже (написано в первом сообщении).

Это экстенсивный путь :slight_smile:

я для парсинга использую питон

не кошерно, хардкорд, только хардкорд

МММ, я не совсем понял цель, желаемый ризалт.
Менять шрифты (или некие данные) в ран тайм? Нужно код писать другой, не такой, как в Адафрут.
Или нужно подключать разные данные (библиотеки) при сборке? Или в ран тайм, как DLL в Виндоус?
Условия сборки какие? Всякие “симейки” умеют очень много.
Или задача написать парсер какого-то С-подобного кода? Очень много вариантов понимания твоего поста?

кашерно не кашерно. зато быстро и без установки , когда надо быстро прошерстить текст по условиям и создать новый .. я так фонты парсил в удобный мне формат … бат файл с запускам скрипта из командной строки и опана…

типа scrypt.ry кусок

filename = 'rle.c'
.........
........
........
with open(filename, 'r', encoding='utf-8') as file:
    lines = file.readlines()

result_lines = []
found = False

for line in lines:
    if not found:
        if 'const unsigned char* ArrayOfArrays' in line:
            found = True
            # нах эту строку и все, что после
            break
        else:
            result_lines.append(line)
    else:
        #  дальше игнориm
        break


.......
.......
.......


with open(filename, 'w', encoding='utf-8') as file:
    file.writelines(result_lines)

print(f'Удалено строка "const unsigned char* ArrayOfArray
1 лайк