2015-09-11 4 views
0

Я использую pycparser разобрать некоторые C код, который я не могу компилировать с CPP перед разбором, поэтому я вручную вырежу все комментарии и директиву препроцессора с помощью следующей функции:pycparser ParseError с ЬурейиМи

def remove_comments(text): 
    def replacer(match): 
     s = match.group(0) 
     if s.startswith('/') or s.startswith('#'): 
      return "" 
     else: 
      return s 

    pattern = re.compile(
     r'#.*?$|//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', 
     re.DOTALL | re.MULTILINE 
    ) 
    return re.sub(pattern, replacer, text) 

Это выход из этой функции на файле memmgr.c из примеров:

typedef ulong Align; 

union mem_header_union 
{ 
    struct 
    { 


     union mem_header_union* next; 



     ulong size; 
    } s; 



    Align align_dummy; 
}; 

typedef union mem_header_union mem_header_t; 



static mem_header_t base; 



static mem_header_t* freep = 0; 



static byte pool[POOL_SIZE] = {0}; 
static ulong pool_free_pos = 0; 


void memmgr_init() 
{ 
    base.s.next = 0; 
    base.s.size = 0; 
    freep = 0; 
    pool_free_pos = 0; 
} 


static mem_header_t* get_mem_from_pool(ulong nquantas) 
{ 
    ulong total_req_size; 

    mem_header_t* h; 

    if (nquantas < MIN_POOL_ALLOC_QUANTAS) 
     nquantas = MIN_POOL_ALLOC_QUANTAS; 

    total_req_size = nquantas * sizeof(mem_header_t); 

    if (pool_free_pos + total_req_size <= POOL_SIZE) 
    { 
     h = (mem_header_t*) (pool + pool_free_pos); 
     h->s.size = nquantas; 
     memmgr_free((void*) (h + 1)); 
     pool_free_pos += total_req_size; 
    } 
    else 
    { 
     return 0; 
    } 

    return freep; 
} 










void* memmgr_alloc(ulong nbytes) 
{ 
    mem_header_t* p; 
    mem_header_t* prevp; 





    ulong nquantas = (nbytes + sizeof(mem_header_t) - 1)/sizeof(mem_header_t) + 1; 




    if ((prevp = freep) == 0) 
    { 
     base.s.next = freep = prevp = &base; 
     base.s.size = 0; 
    } 

    for (p = prevp->s.next; ; prevp = p, p = p->s.next) 
    { 

     if (p->s.size >= nquantas) 
     { 

      if (p->s.size == nquantas) 
      { 



       prevp->s.next = p->s.next; 
      } 
      else 
      { 
       p->s.size -= nquantas; 
       p += p->s.size; 
       p->s.size = nquantas; 
      } 

      freep = prevp; 
      return (void*) (p + 1); 
     } 



     else if (p == freep) 
     { 
      if ((p = get_mem_from_pool(nquantas)) == 0) 
      { 

       printf("!! Memory allocation failed !!\n"); 

       return 0; 
      } 
     } 
    } 
} 

Но я получаю эту ParseError:

pycparser.plyparser.ParseError: :1:15: before: Align 

Что не так с pycparser?

+0

Что произойдет, если вы переименуете ulong в длинный? – Har

+0

@Har Я получаю еще один 'ParseError',' pycparser.plyparser.ParseError:: 13: 9: before: ulong' – Vektor88

+0

hmm, так что он понимает долго, а не ulong, но не понимает typedef ... странно ... – Har

ответ

1

Я полагаю, что в каком-то включенном файле был typedef unsigned long ulong;. Без этой декларации ulong не может отображаться там, где для грамматики требуется имя типа.

Попробуйте добавить объявление ulong, где-то перед его первым использованием.


Чтобы более конкретно о вопросе: «Что случилось с pycparser?»:

Целью pycparser является для синтаксического анализа программ на языке Си. Это не приблизительный синтаксический анализатор; он на самом деле направлен на создание полного точного анализа любой действующей программы C99.

К сожалению, невозможно, чтобы точно разобрать программу на C, не зная, какие идентификаторы являются typenames. Нет необходимости знать точный тип идентификатора, поэтому pycparser не требует доступа ко всем прототипам и глобальным определениям; он, однако, требует доступа ко всем соответствующим typedef.

Это отражено в , что указывает на a longer discussion at the author's website:

The key point to understand here is that pycparser doesn't really care about the semantics of types. It only needs to know whether some token encountered in the source is a previously defined type. This is essential in order to be able to parse C correctly.

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

Эли Бэндерски эссе отлично, и стоит прочитать. Позвольте мне привести несколько примеров кода C, которые не могут быть проанализированы, не зная, является ли имя typedef или нет.

Классический пример, я думаю, хорошо известно:

(foo) - 3 * 4 

Это выражение имеет два возможных разборов, только один из которых может применяться в любой заданной программе. Слева синтаксический анализ, если foo - переменная; справа, синтаксический анализ, если foo тип:

-        * 
/\       /\ 
/ \      / \ 
foo *      cast 4 
    /\     /\ 
    / \     / \ 
    3  4     foo  - 
            | 
            | 
            3 

Другими словами, если foo переменная, выражение вычитает 3*4 от foo. Но если foo является типом, выражение отличает -3, чтобы ввести foo, а затем умножает результат на 4`.

По-видимому, конкретное приложение, из которого был получен этот вопрос, на самом деле не требует подробных знаний об анализе каждого выражения. Но нет способа передать этот факт pycparser; pycparser's предназначен для обеспечения полного анализа.

В любом случае можно построить, возможно, более подходящий пример. Рассмотрим два утверждения (которые не могут появляться в той же единице трансляции):

foo (*bar())(); 

и

foo (*bar())(); 

Несмотря на их сходство (:-)), эти два утверждения совершенно различны. Первый объявляет функцией с именем bar. Второй номер вызывает функцию с именем foo, после вызова функции с именем bar для вычисления аргумента foo.

Даже если вы только собирали декларации, было бы важно знать, было ли это заявление декларацией или нет. (Да, что конструкция очень редко, она не может появляться в любом месте кода базы анализируемой Но как pycparser знает, что.?)

Вот полные контексты:

#include <stdio.h>     | #include <stdio.h> 
typedef int foo;     | 
int answer() { return 42; }  | int answer() { return 42; } 
            | 
            | int (*foo(int a))() { 
            | printf("%d\n", a); 
            | return answer; 
            | } 
            | 
            | static const int unused = 43; 
int (*bar())() { return answer; } | int const* bar() { return &unused; } 
            | 
int main() {      | int main() { 
    /* Declare bar */    | /* Call foo */ 
foo (*bar())(); | foo (*bar())(); 
    printf("%d\n", bar()());   | return 0; 
    return 0;      | } 
}         | 

+0

что если я только забочусь о синтаксическом анализе произвольных фрагментов кода, чтобы, скажем, перечислить все методы? – Vektor88

+0

@ Vektor88: Невозможно разобрать код C, не зная, какие идентификаторы являются именами типов. (Можно получить примерный синтаксический анализ, но я думаю, что pycparser хочет правильно разобрать вход.) Почему вы не можете предварительно обработать файл? – rici

+0

Я только забочусь о грамматических аспектах кода, поэтому мне действительно не нужно удовлетворять зависимостям, и если бы я хотел обработать весь код ядра Linux, потребовалось бы много усилий и усилий для удовлетворения всех зависимостей. Видимо, пикпарсер не для меня. – Vektor88

1

Препроцессор C не только отделяет комментарии. Он также обрабатывает все макросы, включая #include, который извлекает файлы заголовков. В вашем случае, он пытается #include "memmgr.h", который имеет этот typedef:

typedef unsigned long ulong; 

наряду с некоторыми другими.

Суть в том, что вы должны вызывать препроцессор перед pycparser. Если у вас есть действительный код C, нет причин, по которым препроцессор не должен работать. Это может быть тема для отдельного вопроса SO в теге C.

+0

Как уже объяснялось, я хочу разобрать произвольный код и получить список функций, переменных и т. Д.Удовлетворение зависимостей в порядке, когда ваша цель проверяет, будет ли ваш код «работать», но требует много времени и бесполезен, если вам нужна только приблизительная информация о структуре кода, а код может быть даже объявлением метода, извлеченным из более сложного код. – Vektor88

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