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 № 1Wydaje 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 int
s. 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 int
stał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.)