1+ // / @file
2+ // / @brief PEGTL-based CIF parser with pluggable action handlers and Document construction.
3+ // /
4+ // / This header provides the complete CIF parsing infrastructure:
5+ // / - PEG grammar rules for CIF 1.1 syntax (namespace `rules`)
6+ // / - Customizable action handlers (templates specializing `Action<Rule>`)
7+ // / - Built-in actions that construct an in-memory Document
8+ // / - Entry points: read_file(), read_memory(), read_cstream(), read_istream(), read()
9+ // /
10+ // / For high-level parsing of standard formats (mmCIF, plain CIF), prefer read_cif.hpp.
11+
112// Copyright 2017 Global Phasing Ltd.
213//
314// CIF parser (based on PEGTL) with pluggable actions,
@@ -264,10 +275,22 @@ template<> struct Action<rules::loop> {
264275};
265276
266277
278+ // / @brief Parse CIF content from an input, populating a Document.
279+ // / @tparam Input PEGTL input type (e.g., pegtl::file_input, pegtl::memory_input).
280+ // / @param d Document to populate with parsed blocks and items.
281+ // / @param in PEGTL input object.
282+ // / @throws pegtl::parse_error on syntax errors.
267283template <typename Input> void parse_input (Document& d, Input&& in) {
268284 pegtl::parse<rules::file, Action, Errors>(in, d);
269285}
270286
287+ // / @brief Read a complete CIF file and return a Document.
288+ // / @tparam Input PEGTL input type.
289+ // / @param in PEGTL input object with a source() method.
290+ // / @param check_level Validation strictness: 0=no checks, 1=missing values & duplicates, 2=also empty loops.
291+ // / @return Fully parsed Document.
292+ // / @throws pegtl::parse_error on syntax errors.
293+ // / @throws std::runtime_error on validation failures (check_level > 0).
271294template <typename Input> Document read_input (Input&& in, int check_level=1 ) {
272295 Document doc;
273296 doc.source = in.source ();
@@ -286,6 +309,12 @@ template<typename Input> Document read_input(Input&& in, int check_level=1) {
286309 return doc;
287310}
288311
312+ // / @brief Parse a single CIF data block and add it to a Document.
313+ // / @tparam Input PEGTL input type.
314+ // / @param d Document to append to.
315+ // / @param in PEGTL input.
316+ // / @return Byte offset after parsing the block.
317+ // / @throws pegtl::parse_error on syntax errors.
289318template <typename Input>
290319size_t parse_one_block (Document& d, Input&& in) {
291320 pegtl::parse<rules::one_block, Action, Errors>(in, d);
@@ -302,21 +331,48 @@ size_t parse_one_block(Document& d, Input&& in) {
302331 tao::pegtl::file_input<> in (path)
303332#endif
304333
334+ // / @brief Read a CIF file from disk.
335+ // / @param filename Path to the CIF file.
336+ // / @param check_level Validation level (0-2).
337+ // / @return Parsed Document.
338+ // / @throws std::runtime_error if file cannot be opened.
339+ // / @throws pegtl::parse_error on syntax errors.
305340inline Document read_file (const std::string& filename, int check_level=1 ) {
306341 GEMMI_CIF_FILE_INPUT (in, filename);
307342 return read_input (in, check_level);
308343}
309344
345+ // / @brief Read CIF from memory.
346+ // / @param data Pointer to CIF content (need not be null-terminated).
347+ // / @param size Number of bytes to parse.
348+ // / @param name Label for error messages (e.g., "buffer").
349+ // / @param check_level Validation level (0-2).
350+ // / @return Parsed Document.
351+ // / @throws pegtl::parse_error on syntax errors.
310352inline Document read_memory (const char * data, size_t size, const char * name, int check_level=1 ) {
311353 pegtl::memory_input<> in (data, size, name);
312354 return read_input (in, check_level);
313355}
314356
357+ // / @brief Read CIF from a C FILE stream.
358+ // / @param f Open FILE pointer (e.g., stdin, or result of fopen()).
359+ // / @param bufsize Buffering size for reading (e.g., 16*1024).
360+ // / @param name Label for error messages.
361+ // / @param check_level Validation level (0-2).
362+ // / @return Parsed Document.
363+ // / @throws pegtl::parse_error on syntax errors.
315364inline Document read_cstream (std::FILE *f, size_t bufsize, const char * name, int check_level=1 ) {
316365 pegtl::cstream_input<> in (f, bufsize, name);
317366 return read_input (in, check_level);
318367}
319368
369+ // / @brief Read CIF from a C++ std::istream.
370+ // / @param is Input stream (e.g., std::ifstream, std::cin).
371+ // / @param bufsize Buffering size (e.g., 16*1024).
372+ // / @param name Label for error messages.
373+ // / @param check_level Validation level (0-2).
374+ // / @return Parsed Document.
375+ // / @throws pegtl::parse_error on syntax errors.
320376inline Document read_istream (std::istream &is, size_t bufsize, const char * name,
321377 int check_level=1 ) {
322378 pegtl::istream_input<> in (is, bufsize, name);
@@ -332,6 +388,11 @@ template<> struct CheckAction<rules::missing_value> {
332388 }
333389};
334390
391+ // / @brief Try parsing CIF without validation or error throwing.
392+ // / @tparam Input PEGTL input type.
393+ // / @param in PEGTL input.
394+ // / @param msg Optional pointer to store error message (if parsing fails).
395+ // / @return true if parse succeeded, false otherwise.
335396template <typename Input> bool try_parse (Input&& in, std::string* msg) {
336397 try {
337398 return pegtl::parse<rules::file, CheckAction, Errors>(in);
@@ -342,8 +403,13 @@ template<typename Input> bool try_parse(Input&& in, std::string* msg) {
342403 }
343404}
344405
345- // A function for transparent reading of normal and compressed files.
346- // T should have the same traits as BasicInput and MaybeGzipped.
406+ // / @brief Read CIF from a file or stream, handling compression transparently.
407+ // / @tparam T Type with methods: uncompress_into_buffer(), is_stdin(), is_compressed(), path().
408+ // / (Traits matching BasicInput and MaybeGzipped wrappers in Gemmi.)
409+ // / @param input Input wrapper (handles gzip, bzip2, and plain files).
410+ // / @param check_level Validation level (0-2).
411+ // / @return Parsed Document.
412+ // / @throws pegtl::parse_error on syntax errors.
347413template <typename T>
348414Document read (T&& input, int check_level=1 ) {
349415 if (CharArray mem = input.uncompress_into_buffer ())
@@ -353,6 +419,11 @@ Document read(T&& input, int check_level=1) {
353419 return read_file (input.path (), check_level);
354420}
355421
422+ // / @brief Check CIF syntax without building a Document.
423+ // / @tparam T Type with uncompress_into_buffer() and path() methods.
424+ // / @param input Input wrapper.
425+ // / @param msg Optional pointer to store error message.
426+ // / @return true if syntax is valid, false otherwise.
356427template <typename T>
357428bool check_syntax (T&& input, std::string* msg) {
358429 if (CharArray mem = input.uncompress_into_buffer ()) {
@@ -363,6 +434,13 @@ bool check_syntax(T&& input, std::string* msg) {
363434 return try_parse (in, msg);
364435}
365436
437+ // / @brief Read one CIF block from a file or stream into an existing Document.
438+ // / @tparam T Type with is_compressed(), is_stdin(), uncompress_into_buffer(size_t), path() methods.
439+ // / @param d Document to append block to.
440+ // / @param input Input wrapper.
441+ // / @param limit Max bytes to read from compressed file (0 = no limit).
442+ // / @return Byte offset after parsing the block.
443+ // / @throws pegtl::parse_error on syntax errors.
366444template <typename T>
367445size_t read_one_block (Document& d, T&& input, size_t limit) {
368446 if (input.is_compressed ()) {
0 commit comments