2015-03-11 7 views
1

Мне нужно использовать pycparser на предварительно обработанном C-коде (результаты, полученные «gcc -E»). Однако в настоящее время я сталкиваюсь с проблемой, которую я не могу понять или решить.Pycparser не работает над предварительно обработанным кодом

Я использую предоставленные образцы year2.c и func_defs.py, которые я модифицировал, чтобы использовать различные препроцессоры и поддельные библиотеки безрезультатно. Возможно, некоторые из вас могут изучить это и посмотреть, можете ли вы воспроизвести/решить проблему. Я добавлю все необходимые коды.

Ошибки создавались с использованием year2.c (обычного образца файла) и year2.i ('gcc -E' output). Для последнего не было приемлемого результата, в то время как первый работал с вариантами препроцессора/факелиба.

Я создал репортаж bitbucket со всеми соответствующими ошибками, используемый сценарий (хотя и только его последний вариант), и файлы year2.c и year2.i.

Error & Sample Repo

Спасибо за ваше время.

ответ

3

Ошибка вы получаете это:

pycparser.plyparser.ParseError: /usr/lib/gcc/x86_64-linux-gnu/4.8/include/stdarg.h:40:27: before: __gnuc_va_list 

линия обозначается как вызывает ошибку (stdarg.h:40):

typedef __builtin_va_list __gnuc_va_list; 

В GCC, __builtin_va_list есть, как указывает его название, построенный в компилятору. Следовательно, объявление такого типа не требуется (или разрешено).

Для компиляторов C очень часто используется метод на основе символьной таблицы для синтаксического анализа имен типов, поскольку в грамматике имеется несколько двусмысленностей, если вы не можете различить имя типа из другого идентификатора. Такой синтаксический анализатор будет считать, что необъявленный идентификатор не является typename, и если __builtin_va_list не является именем, то typedef является синтаксической ошибкой.

Итак, я полагаю, что используемая вами грамматика pyparser не знает о типах gcc builtin (и почему?).

Ваш факелиб, похоже, содержит тот же заголовочный файл. Это неудивительно, так как трудно подделать stdarg.h; хотя технически это заголовок библиотеки, он является частью небольшого набора заголовков, который должен предоставляться компилятором даже в автономной (без стандартной библиотеки) реализации: <float.h>, <iso646.h>, <limits.h>, <stdalign.h>, <stdarg.h>, <stdbool.h>, <stddef.h>, <stdint.h> и <stdnoreturn.h> (стандарт C11, пункт 4, пункт 6). Они должны быть реализованы компилятором, потому что внешняя библиотека не может достаточно знать о характере скомпилированного кода, чтобы правильно определить их.

В зависимости от того, что требуется от pyparsed выхода, вы можете быть в состоянии обойти это для pyparser, включив в определение __builtin_va_list, такие как:

typedef struct __builtin_va_list { } __builtin_va_list; 

__builtin_va_list не только встроенный НКУ типа данных, хотя вы не можете столкнуться с другими. Таким образом, вам может потребоваться повторить это решение несколько раз, пока вы не достигнете того, чего вы пытаетесь достичь.

+0

Привет, жаль, что я так долго, чтобы вернуться к вам. Я внедрил для изменения предложенный вами файл '', который дал мне ошибку, но ошибка остается прежней. Вот как выглядит место в файле сейчас. '#ifndef __GNUC_VA_LIST #define __GNUC_VA_LIST typedef struct __builtin_va_list {}; typedef __builtin_va_list __gnuc_va_list; # endif' Если у вас есть другой вход, я бы хотел его услышать. – Araiguma

+0

@Araiguma: К сожалению, извините. Это была очевидная ошибка; Я не знаю, о чем я думал. Это должно быть 'typedef struct __builtin_va_list {} __builtin_va_list;'; Я исправил это в ответе. – rici

0

Поскольку @rici объяснил причину ошибки. Я бы больше сосредоточился на том, как его решить.Я взял мой ответ из блога pycparser автора - http://eli.thegreenplace.net/2015/on-parsing-c-type-declarations-and-fake-headers

Идея заключается в том, что pycparser должен знать, что anyheader.h содержит так что он может правильно разобрать код. Поскольку на самом деле разбор anyheader.h и всех других заголовков, которые он транзитивно включает, может быть очень трудоемким и, возможно, не требуемым для вашей задачи, фальшивые заголовки могут использоваться. Подделка anyheader.h будет содержать только те части оригинала, которые необходимы для синтаксического анализа - #defines и typedefs.

gcc -nostdinc -E -I/home/rg/pycparser-master/utils/fake_libc_include test.c > testPP.c

Вышеуказанная команда предобработки test.c которая содержит <stdio.h> используя поддельные заголовки, поставляемые с пакетом pycparser. Флаг -nostdinc используется для блокировки некоторых предварительно заданных системных заголовков, которые gcc автоматически включает. Теперь, разбор предварительно обработанного файла, используя, например, ниже кода

import pycparser 
pycparser.parse_file('testPP.c') 

должен работать в большинстве случаев. Если он не гарантирует, что вы предоставите все зависимости для предварительной обработки. В случае, если для некоторых заголовков подделки не предусмотрены, вы можете подделать ошибку, вызвав typedef, используя #defining, например. чтобы устранить ошибку, вызванную __builtin_va_list, вы можете попробовать притворяется следующим образом:

gcc -nostdinc -E -D'__builtin_va_list(x)=' -I/home/rg/pycparser-master/utils/fake_libc_include test.c > testPP.c