Цель состоит в том, чтобы создать как можно меньший препроцессор для языка Си с точки зрения размера исходного кода в байтах на предпочитаемом вами языке. Его ввод будет исходным файлом C, а вывод - предварительно обработанным исходным кодом.
Элементы, которые нужно будет обработать, должны быть следующими: удаление комментариев (строка / блок), директивы #include (путем открытия файлов по относительным путям и замены текста в необходимой точке), #define, #undef, #if, #elif, #else, #endif, #ifdef, #ifndef иfined (). Другие директивы препроцессора C, такие как #pragmas или #errors, могут игнорироваться.
Нет необходимости вычислять арифметические выражения или операторы сравнения в директивах #if, мы предполагаем, что выражение будет иметь значение true, если оно содержит целое число, отличное от нуля (его основное использование будет для директивы define ()). Ниже приведены примеры возможного ввода и вывода (возможные лишние пробелы в выходных файлах были обрезаны для лучшего внешнего вида, для этого не требуется ваш код). Программа, способная правильно обрабатывать следующие примеры, будет считаться достаточной.
----Input file: foo.c (main file being preprocessed)
#include "bar.h" // Line may or may not exist
#ifdef NEEDS_BAZZER
#include "baz.h"
#endif // NEEDS_BAZZER
#ifdef _BAZ_H_
int main(int argc, char ** argv)
{
/* Main function.
In case that bar.h defined NEEDS_BAZ as true,
we call baz.h's macro BAZZER with the length of the
program's argument list. */
return BAZZER(argc);
}
#elif defined(_BAR_H_)
// In case that bar.h was included but didn't define NEEDS_BAZ.
#undef _BAR_H_
#define NEEDS_BARRER
#include "bar.h"
int main(int argc, char ** argv)
{
return BARRER(argc);
}
#else
// In case that bar.h wasn't included at all.
int main()
{return 0;}
#endif // _BAZ_H_
----Input file bar.h (Included header)
#ifndef _BAR_H_
#define _BAR_H_
#ifdef NEEDS_BARRER
int bar(int * i)
{
*i += 4 + *i;
return *i;
}
#define BARRER(i) (bar(&i), i*=2, bar(&i))
#else
#define NEEDS_BAZZER // Line may or may not exist
#endif // NEEDS_BARRER
#endif // _BAR_H_
----Input file baz.h (Included header)
#ifndef _BAZ_H_
#define _BAZ_H_
int baz(int * i)
{
*i = 4 * (*i + 2);
return *i;
}
#define BAZZER(i) (baz(&i), i+=2, baz(&i))
#endif // _BAZ_H_
----Output file foopp.c (no edits)
int baz(int * i)
{
*i = 4 * (*i + 2);
return *i;
}
int main(int argc, char ** argv)
{
return (baz(&argc), argc+=2, baz(&argc));
}
----Output file foopp2.c (with foo.c's first line removed)
int main()
{return 0;}
----Output file foopp3.c (with bar.h's line "#define NEEDS_BAZZER" removed)
int bar(int * i)
{
*i += 4 + *i;
return *i;
}
int main(int argc, char ** argv)
{
return (bar(&argc), argc*=2, bar(&argc));
}
#if
нужно поддерживать? т.е. должен ли препроцессор поддерживать выражения с арифметическими, побитовыми операциями и т. д.?Ответы:
Flex, 1170 + 4 = 1174
1170 символов в гибком коде + 4 символа для флага компиляции. Чтобы создать исполняемый файл, запустите
flex pre.l ; gcc lex.yy.c -lfl
.Запись пропускает память как сито и не закрывает включенные файлы.Но в остальном он должен быть полностью функциональным в соответствии со спецификацией.Некоторое объяснение:
a
иb
временные файлы для хранения строк из ввода.a
также используется в качестве параметра для функцииf
.v
содержит имена макросов иV
содержит V-значения макросовt
иT
«современные держатели, когда мы растемv
иV
i
это 'i'ncrementer для цикловs
's'ize макроса массиваo
это число 'o'penif
внутри ложного условногоg()
g'rows макро-массивыf()
'f' указывает макрос с тем же значением,v
что иa
d(y)
'd'rops последниеy
символы из текущего вводаD
для внутри 'D'efineF
для игнорирования условного 'F'alseI
«Я игнорируюelse
/elif
после того, как было найдено истинное условие».EDIT1: устранены многие утечки памяти и реализовано закрытие файлов
EDIT2: модифицированный код для более правильной обработки вложенных макросов
EDIT3: сумасшедшая игра в гольф
EDIT4: больше игры в гольф
EDIT5: больше игры в гольф; Я также заметил, что мой вызов fclose () вызывает проблемы на некоторых компьютерах ... глядя на это.
источник
#include
пишу, но я думаю, это связано с ошибкой в правке № 5. Кроме того, он не заменяет макросы, даже если он успешно обрабатывает блоки #if - если я не делаю что-то не так ... но в целом это выглядит очень хорошо, и это дает грубое представление о том, что может сделать лексер, так как Я могу понять это даже в его гольфовой форме. Попытайтесь выяснить, можно ли исправить ошибки, если нет, то все в порядке, как хорошо объясняется в коде, вероятно, это будет выбранный ответ, поскольку других записей нет.