/ / Jak analizować bardzo duży bufor za pomocą flex i bison - c ++, bison, flex-lexer, yacc, lex

Jak analizować bardzo duży bufor za pomocą flex i bison - c ++, bison, flex-lexer, yacc, lex

Napisałem bibliotekę json, która używa flex i bison, aby parsować serialized-json (tj. Ciągi) i deserializować je do obiektów json.To działa doskonale dla małych ciągów.

Jednak nie działa z bardzo dużymi strunami (próbowałem prawie strun 3 GB) z tym błędem:

‘fatal flex scanner internal error--end of buffer missed’

Chcę wiedzieć, jaki jest maksymalny rozmiar bufora, który mogę przekazać do tej funkcji:

//js: serialized json stored in std::string

yy_scan_bytes(js.data(), js.size());

i jak można sprawić, by flex / bison działał z dużymi buforami?

Odpowiedzi:

1 dla odpowiedzi № 1

Wydaje mi się, że używasz starej wersji sztywnego szkieletu (a więc i flexu), w którym zakłada się, że długości łańcuchów pasują do ints. Komunikat o błędzie, który obserwujesz, jest prawdopodobnie wynikiem int przepełnienie do wartości ujemnej.

Wierzę, że jeśli przejdziesz do wersji 2.5.37 lub nowszej, znajdziesz większość z nich intstały się size_t i nie powinieneś mieć problemu z dzwonieniem yy_scan_bytes z buforem wejściowym, którego rozmiar przekracza 2 gigabajty. (Prototyp dla tej funkcji zajmuje teraz size_t raczej niż int, na przykład.)

Trudno mi uwierzyć, że to dobry pomysł. Na początek, yy_scan_bytes kopiuje cały ciąg, ponieważ skaner leksykalny chce łańcucha, który może modyfikować, i ponieważ chce się upewnić, że łańcuch ma dwa NUL bajtów na końcu. Sprawienie, że ta kopia będzie niepotrzebna, zużywa dużo pamięci, a jeśli i tak zamierzasz skopiować bufor, możesz równie dobrze skopiować go w łatwe do zarządzania elementy (na przykład 64Kib lub nawet 1 MB). To będzie tylko problematyczne, jeśli masz pojedyncze żetony, które są znacznie większe niż rozmiar porcji, ponieważ flex zdecydowanie nie jest zoptymalizowany dla dużych pojedynczych tokenów, ale w przypadku wszystkich normalnych zastosowań prawdopodobnie zadziała znacznie lepiej.

Flex nie zapewnia interfejsu do dzielenia ogromnego bufora wejściowego na porcje, ale można to zrobić bardzo łatwo poprzez ponowne zdefiniowanie YY_INPUT makro. (Jeśli to zrobisz, prawdopodobnie użyjesz yyin jako wskaźnik do własnej struktury bufora, która teoretycznie jest nieprzenośna. Będzie jednak działać na dowolnej architekturze Posix, gdzie wszystkie wskaźniki obiektów mają taką samą reprezentację.)

Oczywiście normalnie nie chcesz czekać, gdy 3 GB danych zostanie zgromadzonych w pamięci, aby rozpocząć przetwarzanie. Podczas odczytu danych można parsować przyrostowo. (Możesz nadal potrzebować przedefiniować YY_INPUT, w zależności od tego, jak czytasz dane.)