Замены препроцессора C

Я заинтересован в использовании чего-то другого, кроме препроцессора C, для предварительной обработки исходного кода C и Objective-C. Есть ли хорошие альтернативы?

Примером может быть что-то, что позволяет уйти в фрагмент кода Python или Perl в середине кода C, и где фрагмент выплевывает C, который затем компилируется как нормальный.


person Ken    schedule 28.12.2008    source источник
comment
Не могли бы вы привести конкретный пример, показывающий, как (и почему) вы хотите сгенерировать исходный код во время компиляции? Это может помочь нам составить предложения, соответствующие вашим конкретным потребностям. (Например, я предполагаю, что шаблоны C ++ не будут работать в вашем случае, но было бы хорошо подтвердить.)   -  person reuben    schedule 28.12.2008
comment
Неплохая идея: вот статья IBM, в которой автор использует сценарий Perl для создания таблицы поиска. ibm.com/developerworks/linux/library/l-metaprog1/ index.html   -  person    schedule 27.08.2011


Ответы (13)


Вы можете использовать PHP в качестве препроцессора C. Преимущества:

  • очень похожий синтаксис, поэтому подсветка синтаксиса работает.
  • <? и ?> не используются в стандартном C (с нестандартным C единственное, что ломается, - это старый оператор расширения GCC, который возвращает min / max)
  • он богат библиотеками.
  • это полный Тьюринг.
  • использование макросов очень явное. (по сравнению с подлыми макросами препроцессора C)

Однако для серьезного использования необходимо заставить PHP печатать директивы #line для отладки предварительно обработанного кода.

<?php include_once "stdio.h"; ?>

int main()
{
    <?php
        for($i = 0; $i < 20; $i++)
            echo 'printf("%d\n", '.$i.');';
    ?>
}
person milleniumbug    schedule 27.04.2013
comment
это увлекательно - person Félix Adriyel Gagnon-Grenier; 07.10.2016
comment
Поскольку это сейчас распространяется в Твиттере, Reddit и т. Д., Люди, пожалуйста, помните - просто потому, что вы можете или могли, не означает, что вы должны. - person Esko; 07.10.2016
comment
@Esko: На самом деле, я думаю, что это отличная идея, если вы хотите динамически генерировать код во время компиляции - в частности, если препроцессор C недостаточно мощный для того, что вы пытаетесь сделать. - person thejh; 07.10.2016
comment
Ух ты. Это пессимум. - person Warren P; 08.10.2016
comment
Я наконец нашел истинное значение аббревиатуры: PHP Header Preprocesser. Это идеальный инструмент для предварительной обработки .h файлов. - person Star Brilliant; 08.10.2016

Возможно, вам стоит рассмотреть m4.
http://www.gnu.org/software/m4/

person David Poole    schedule 28.12.2008
comment
Для меня m4 слишком похож на научный проект и недостаточно похож на язык препроцессора. В прошлый раз, когда я посмотрел, в нем не было конструкции цикла, но вместо этого были инструкции о том, как сделать ее с помощью рекурсии. Я воспринял это как явный сигнал, что авторы были слишком умны для моей же пользы. - person Michael Kohne; 28.12.2008
comment
циклические конструкции вроде этих? [gnu.org/software/m4/manual/html_node/. - person Hasturkun; 29.12.2008
comment
m4 действительно чрезвычайно универсален, но этот синтаксис настолько жесток.! Я действительно хотел бы, чтобы у нас был более современный макропроцессор unix, но один, скомпилированный из C, например, почтенный m4. - person J. M. Becker; 06.06.2013
comment
Я написал в блоге сообщение об использовании m4 с C, которое может помочь некоторым начать работу: kvanberendonck .id.au / using-m4-with-c - person kvanbere; 27.04.2014
comment
@TechZilla, Майкл, Дэвид, Хастуркун, Ребята, я что-то упустил? Что плохого в использовании настоящего скриптового языка, такого как PHP / JavaScript / Perl, в качестве препроцессора? - person Pacerier; 16.05.2015
comment
@Pacerier, Вы имеете ввиду для варианта использования или просто вообще? Я говорил в целом, что для этого варианта использования все эти варианты подойдут. Вообще говоря, мне лучше использовать универсальный, но современный макроязык. Что-то специфическое для этой чрезвычайно распространенной области, но при этом фактическое создание сценариев не потребуется. - person J. M. Becker; 21.08.2015
comment
Я был потрясен тем, что M4 не упоминался ранее. Вы можете переопределить практически каждый его аспект, синтаксис будет таким, каким вы его называете. Хотите, чтобы он разбирал предварительную обработку C? Сделанный. Скрипты Autoconf с уродливыми функциями повсюду? Сделанный. Макросы для ассемблера, использующие синтаксис, более похожий на C? Готово - см. kevinpt.github.io/opbasm/rst/m4 .html # c-style-syntax. - person Christoffer Bubach; 07.12.2020

Cog не совсем препроцессор, но он встроен в код и генерирует вещи на лету.

person Michael Kohne    schedule 28.12.2008
comment
Можете ли вы расширить свой ответ (я верю, что это лучший ответ), приведя пример (в противном случае я сделаю свой) - person Xavier Combelle; 07.10.2016

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

Я знаю, как решить эту проблему с помощью Lua. Я использовал string.gsub с функцией антиквотации, которую написал сам. Я использовал синтаксис оболочки для антиквотации. Как и в оболочке, код без кавычек возвращает строку, которая затем вставляется в код.

Ниже prog находится код C с текстом, не заключенным в кавычки, а antiquote - функция отмены кавычек. Я в полной мере использовал специальные строковые кавычки Lua в двойных квадратных скобках. На практике вы бы этого не сделали; вы бы поместили prog в отдельный файл.

names = { 'John', 'Paul', 'George', 'Ringo' }

local prog = [===[
#include <stdio.h>

main() {
  $(local out = { }
    for _, n in ipairs(names) do
      table.insert(out, string.format([[  printf("The name is %%s\n", %q);]], n))
    end
    return table.concat(out, '\n  ')
   )
}
]===]


local function antiquote(s)
  local body = s:match '^%$%((.*)%)$'
  return assert(loadstring(body))()
end

prog = prog:gsub('%$%b()', antiquote)
io.stdout:write(prog)

При использовании программа выглядит так:

: nr@curlycoat 1181 ; lua /home/nr/tmp/emit-c.lua
#include <stdio.h>

main() {
    printf("The name is %s\n", "John");
    printf("The name is %s\n", "Paul");
    printf("The name is %s\n", "George");
    printf("The name is %s\n", "Ringo");
}
person Norman Ramsey    schedule 29.12.2008

Конечно, стандартный препроцессор C очень ограничен.
Недавно я сделал такой инструмент: https://github.com/d-ash/perlpp

Например это

<?
    my @types = ('char', 'int', 'long'); 
    foreach (@types) {
?>
        <?= $_ ?> read_<?= uc($_) ?>(<?= $_ ?>* v);
<?  } ?>

становится этим

char read_CHAR(char* v);
int read_INT(int* v);
long read_LONG(long* v);

Синтаксис похож на PHP, но вместо этого он использует Perl и может захватывать тексты в Perl stings.

Редактировать, cxw С одобрения @ d-ash я также поддерживаю perlpp. Если у вас есть вопросы, напишите мне!

person d-ash    schedule 22.02.2013
comment
Вы должны добавить пример того, как это работает. - person António Almeida; 22.02.2013
comment
Это отлично работает для меня, и спасибо, что принял мой запрос на перенос! - person cxw; 04.12.2016

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

В настоящее время я использую Jinja2 (Python) для большей части работы с шаблонами - я обнаружил, что он очень настраиваемый во всех отношениях.

person Morten Siebuhr    schedule 28.07.2009

Если вы готовы запачкать руки некоторым C ++, в Boost есть синтаксический анализатор Wave, который построен с использованием синтаксического анализатора рекурсивного спуска Spirit. Это полный препроцессор C, который соответствует всем последним спецификациям для C и C ++ (и, соответственно, Objective C, AFAICS).

Он очень модульный, поэтому вы можете переключить свой собственный драйвер, который может выполнять те дополнительные функции, которые вам нужны.

http://www.boost.org/libs/wave/doc/introduction.html

person philsquared    schedule 28.12.2008
comment
Обновленная ссылка: ‹boost.org/doc/libs/ 1_54_0 / libs / wave / doc / Introduction.html ›бессрочная ссылка: ‹boost.org/libs/wave/doc/introduction.html - person Rhubbarb; 30.10.2013

Я думал об этой же проблеме в прошлом. Убедитесь, что вы согласны с тем фактом, что любому, кто хочет скомпилировать ваш код, также понадобится новый инструмент предварительной обработки. Если вы единственный, кто когда-либо будет над этим работать, нет проблем, но если вы хотите сделать код доступным для других, вы можете подумать, является ли добавление требования к инструменту хорошей идеей.

person Michael Kohne    schedule 28.12.2008
comment
Я определенно не уверен, что меня это устраивает. Но мне интересно посмотреть. :-) - person Ken; 29.12.2008
comment
@ Кен, это соображение не совсем так уж однозначно, например ... сколько раз вы извлекали tar.gz и запускали ./configure? Все исходники для регенерации все еще были там, но вам не нужно было искать правильные версии automake / autoconf. Итак, все, что вам нужно сделать, это предоставить ОБЕИ исходный код и уже обработанную версию. - person J. M. Becker; 03.06.2013
comment
@TechZilla - откровенно говоря, это не лучшая идея в мире. Если вы предоставите уже обработанный код, люди в конечном итоге будут ИЗМЕНИТЬ уже обработанный код, и, если вам ДЕЙСТВИТЕЛЬНО не повезет, кто-то будет изменять сгенерированные разделы (несмотря на предупреждения «Не изменяйте - он сгенерирован!»). Тогда, если вам нужно разобраться с этим кодом в дальнейшем, у вас на руках СЕРЬЕЗНАЯ проблема. - person Michael Kohne; 03.06.2013
comment
@MichaelKohne: Я не оспариваю эту проблему, но это не та проблема, о которой вы изначально говорили. Убедитесь, что вы согласны с тем фактом, что любому, кто хочет скомпилировать ваш код, также понадобится новый инструмент предварительной обработки. Кроме того, эта новая проблема, о которой вы упомянули, в равной степени должна относиться к моей аналогии с automake / makefile. Каждый проект, зависящий от автопроизводителя, также должен был бы решить те же проблемы, что было моей исходной точкой. Причина предоставления обоих, как и проектов, зависимых от automake, заключается в том, что конечным пользователям для регулярной компиляции не требуются инструменты для генерации кода. - person J. M. Becker; 06.06.2013

Короткий ответ - нет." Препроцессор настолько тесно связан с семантикой C, что вы не можете удалить его, и на самом деле в некоторых компиляторах нет даже отдельной фазы, как это было раньше - компиляция Objective C на Mac просто разбирает синтаксис Objective C. Таким образом, хотя вы, безусловно, могли бы использовать другой макропроцессор, например m4, для обработки исходного текста перед его передачей в C, вы бы не исключили препроцессор C, вы бы добавили еще один шаг предварительной обработки.

Но здесь возникает более глубокий вопрос: что вы хотите получить, исключив фазу CPP?

person Charlie Martin    schedule 28.12.2008
comment
Я согласен с тем, что он должен дополнять, а не заменять CPP. Однако я не согласен с тем, что предварительная обработка выполняется компилятором принудительно. По крайней мере, GCC предоставляет способ пропустить этап предварительной обработки. - person strager; 28.12.2008
comment
Я не собираюсь исключать фазу cpp - дополнительная фаза в порядке. Меня интересуют альтернативы, потому что cpp ограничен и полон подводных камней. Никаких циклов, никаких массивов - что-либо сложное, вероятно, просто плохая идея в cpp. - person Ken; 29.12.2008
comment
Тогда у меня возникнет соблазн использовать что-нибудь вроде Perl и покончить с этим. M4, безусловно, сделает это - он полный по Тьюрингу, но он покрыт волосами и неприятно загадочен. Даже по сравнению с perl. - person Charlie Martin; 29.12.2008
comment
Если вы загрузите исходный файл C в perl, он просто не будет компилироваться. Вместо этого вы можете создать сценарий Perl, который встраивает исходный код C в виде более или менее одной большой строки, которая выводится на печать, но это было бы некрасиво. - person Ken; 29.12.2008
comment
Чувак, я не имею в виду скормить C Perl. Напишите сценарий Perl, который создает шаблоны, используя исходный файл C в качестве входных данных. Что-то вроде инструментария шаблонов template-toolkit.org - person Charlie Martin; 29.12.2008
comment
Итак, вы говорите, что я должен написать свой собственный препроцессор. :-) Да, это вариант, но я знал об этом. - person Ken; 29.12.2008
comment
Нет, я говорю, что существует миллион макропроцессоров. У вас действительно есть что-то, что вы хотите сделать, или вы просто говорите, что препроцессор C недостаточно хорош? - person Charlie Martin; 29.12.2008
comment
Например, CPP не может рекурсировать, синтаксис ужасен. boost :: preprocessor упрощает задачу, но по-прежнему сложно и утомительно, а проблему рекурсии трудно решить. - person chila; 10.12.2014
comment
Я думаю, что мы потеряли здесь вопрос. Боги знают, что есть препроцессоры лучше, чем CPP. Черт, у UNIX был M4 миллион лет назад. Но до тех пор, пока #define и #include не исчезнут из кода, вы не сможете исключить CPP, и даже если вы их не используете, CPP все равно будет валяться в пакете. - person Charlie Martin; 11.12.2014

CPP делает много важных вещей для кода C, которые вам, вероятно, не нужно повторно реализовывать. Вместо этого вы, кажется, ищете процесс создания шаблонов, который генерирует код C.

Cheetah - лишь один из многих, позволяющих использовать Python. Есть другие, которые используют python и еще больше на других языках, но Cheetah известен тем, что не зависит от вывода, когда некоторые механизмы шаблонов очень сильно ориентированы на HTML / XML. Проведите свое исследование.

person HUAGHAGUAH    schedule 29.12.2008

Я вижу статью 2001 года, в которой описывается препроцессор типа python http://ray.cg.tuwien.ac.at/rft/Papers/PYM/pym.html. Непонятно, кто им пользуется ..

person Ken    schedule 28.12.2008
comment
Ссылка мертва - я разместил зеркало на GitHub. Взносы приветствуются! - person cxw; 20.02.2017

Вы можете использовать свой любимый язык программирования для создания скрипта / инструмента для создания исходных файлов (.c / .cpp или .h, или что-то еще). Просто #include их или скомпилируйте в свой проект. Комментарии рядом с #include могут помочь определить, что / где находится инструмент и что создается.

Это может быть не так удобно (или чисто), как использование «настоящего» препроцессора, но это сработает. Опять же, это действительно зависит от вашего случая.

person strager    schedule 28.12.2008

Мне было бы интересно посмотреть, что люди придумывают. Я имел обыкновение делать небольшие нестандартные вещи с помощью препроцессоров, написанных на Perl. Создать Makefile, вызывающий препроцессор, несложно. Например, вот правило вызова программы с именем «meta» для создания «file.c» из «file.c.meta».

% :: %.meta
    meta $< > $@

Я занимаюсь забавными вещами с «мета», например, создаю настраиваемые структуры данных C. Я определенно предлагаю изучить это направление. Я надеюсь, что в конечном итоге получу мета-библиотеку, примерно параллельную шаблонам C ++.

person Nathan Kurz    schedule 29.12.2008