2013-06-05 2 views
1

Мне в основном нужно написать препроцессор C с Python, я искал его, и так как мне нужно полностью настраивать свой код и прекрасно понимать, что происходит, я лучше пишу сам.Создание препроцессора с Python

Вот где я. Сначала я разбираю некоторые файлы заголовков (.h), чтобы найти ключевое слово #define и создать словари со всеми установленными директивами (с их значениями, которые у них есть). Затем мне нужно проанализировать исходные файлы (.c) в зависимости от директив, которые я нашел ранее. Механизм, который я использую на данный момент, чтобы проверить, должен ли код обрабатываться, следующий: я беру все имя своего имени и их значения и делаю exec("define_name = define_value") (со значением «1», если не указано). Затем, чтобы разрешить условие, такое как #if defined DEFINE_1 || defined DEFINE_2 && (DEFINE_3 == 10) ...., я удаляю ключевое слово препроцессора C, чтобы сделать их стиль Python, который будет производить DEFINE_1 or defined DEFINE_2 and (DEFINE_3 == 10).

И наконец я использую eval(...) на этой строке, чтобы узнать результат.

ВОПРОС: Мне было интересно, нужно ли использовать exec/eval, и многие люди не хотят использовать их, есть ли лучшее решение?

+0

В моем опыте с препроцессорами на основе Python, Python слишком медленный, чтобы быть практичным для этого. Кроме того, стандартные библиотеки, например, MSVC плохо препроцесс (хотя хуже компиляции). Какую проблему ты пытаешься решить? – imallett

ответ

2

Конечно, exec() не требуется и не должен использоваться. Я даже не уверен, чего вы ожидаете от этого, так как это вызовет оболочку для установки переменной, которая будет существовать только в суб-оболочке.

И вообще, вы должны избегать заявлений eval(), а также редко это делать правильно.

Итак, что вы можете сделать?

1) сначала, так как программы могут быть записаны там, где один оператор перегружает предыдущий оператор, вы не можете предварительно обработать файл .h (или даже предположить, что #define вы ищете только в .h файлах) и заставить его работать. Рассмотрим это:

#define foo 1 
#if foo == 1 
this line is true! 
#endif 
#define foo 0 

Если вы предварительной обработки все, что вы установите «Foo» 1, то 0, а затем оценить #if позже. Вы не можете этого сделать ...

2) Более распространенной задачей было бы написать синтаксический анализатор, который идет по очереди и обрабатывает содержимое каждой строки по одному. Таким образом, вы можете даже написать рекурсивную функцию для работы с операторами #include, чтобы вы могли начать с всего лишь файла .c и позволить ему тянуть нужные заголовки, а не требовать их указания каким-либо другим способом.

В конце концов, вы должны в конечном итоге что-то вроде (в функции под названием «read_file»):

# ... file opening not shown ... 

for line in file: 
    includematch = re.match("#include\\s+\\"(.*)\\"", line) 
    if match: 
     # deal with an include statement by calling a function to process it 
     read_file(includematch.group(1), definedict) 

    definematch = re.match("#define\\s+(\\w+)\\s+(.*)") 
    if definematch: 
     # deal with define statements by saving it in a dict 
     definedict[match.group(1)] = definedict[match.group(2)] 

    #.... 

Очевидно, что если я показал вам все решения (и выше вряд ли довольно-код, но это краткое для показа целей) Я бы решил вашу проблему (домашнее задание?) для вас. Но выше это лучший способ архитектовать все, чем путь, по которому вы направлялись.

+0

Спасибо за ваш ответ, это не домашнее задание, это работа;). Просто для уточнения некоторых вещей, проект, над которым я работаю, очень строг, и людям не разрешено помещать '# define' там, где они хотят (у меня просто есть 1 или 2 файла, которые просто заполнены' # define', поэтому мне просто нужно разобрать, что), поэтому не будет переопределений, как вы сказали.У меня есть рабочий код на данный момент, но с нагрузками 'eval/exec', основная проблема заключается в том, как я могу обрабатывать сложные условия' # if/# elif' ... с тем, что было проанализировано до сих пор, не используя eval и exec ? – Jaay

+0

Ну, вы должны закончить или полномасштабный парсер (что сложнее, но безопаснее) или eval. Eval позволяет пропустить реализацию сопоставления парнов, логику и т. Д., И вы можете сосредоточиться только на замене значений, а затем на остальных. Вы всегда можете начать с eval и работать оттуда, заменив его идеально в будущем. –

+0

примечание: только потому, что у вас есть структурированная строгая среда теперь с определенными правилами, не означает, что эти правила не изменятся в будущем. Вы можете подумать о том, чтобы сделать это правильно, прежде всего, чтобы зеркально отобразить cpp как можно больше, чтобы помочь вам в будущем. –

Смежные вопросы