Kirill Simonov avatar Kirill Simonov committed 75eb8f6

Add functions for constructing, parsing and emitting YAML documents.

Comments (0)

Files changed (15)

 #       else:
 #           YAML_AGE = 0
 m4_define([YAML_RELEASE], 0)
-m4_define([YAML_CURRENT], 0)
+m4_define([YAML_CURRENT], 1)
 m4_define([YAML_REVISION], 0)
 m4_define([YAML_AGE], 0)
 
 /**
  * Get the library version numbers.
  *
- * @param[out]  major   Major version number.
- * @param[out]  minor   Minor version number.
- * @param[out]  patch   Patch version number.
+ * @param[out]      major   Major version number.
+ * @param[out]      minor   Minor version number.
+ * @param[out]      patch   Patch version number.
  */
 
 YAML_DECLARE(void)
 typedef unsigned char yaml_char_t;
 
 /** The version directive data. */
-typedef struct {
+typedef struct yaml_version_directive_s {
     /** The major version number. */
     int major;
     /** The minor version number. */
 } yaml_version_directive_t;
 
 /** The tag directive data. */
-typedef struct {
+typedef struct yaml_tag_directive_s {
     /** The tag handle. */
     yaml_char_t *handle;
     /** The tag prefix. */
 } yaml_tag_directive_t;
 
 /** The stream encoding. */
-typedef enum {
+typedef enum yaml_encoding_e {
     YAML_ANY_ENCODING,
     YAML_UTF8_ENCODING,
     YAML_UTF16LE_ENCODING,
 
 /** Line break types. */
 
-typedef enum {
+typedef enum yaml_break_e {
     YAML_ANY_BREAK,
     YAML_CR_BREAK,
     YAML_LN_BREAK,
 } yaml_break_t;
 
 /** Many bad things could happen with the parser and emitter. */
-typedef enum {
+typedef enum yaml_error_type_e {
     YAML_NO_ERROR,
 
     YAML_MEMORY_ERROR,
     YAML_READER_ERROR,
     YAML_SCANNER_ERROR,
     YAML_PARSER_ERROR,
+    YAML_COMPOSER_ERROR,
 
     YAML_WRITER_ERROR,
     YAML_EMITTER_ERROR
 } yaml_error_type_t;
 
 /** The pointer position. */
-typedef struct {
+typedef struct yaml_mark_s {
     /** The position index. */
     size_t index;
 
  */
 
 /** Scalar styles. */
-typedef enum {
+typedef enum yaml_scalar_style_e {
     YAML_ANY_SCALAR_STYLE,
 
     YAML_PLAIN_SCALAR_STYLE,
 } yaml_scalar_style_t;
 
 /** Sequence styles. */
-typedef enum {
+typedef enum yaml_sequence_style_e {
     YAML_ANY_SEQUENCE_STYLE,
 
     YAML_BLOCK_SEQUENCE_STYLE,
 } yaml_sequence_style_t;
 
 /** Mapping styles. */
-typedef enum {
+typedef enum yaml_mapping_style_e {
     YAML_ANY_MAPPING_STYLE,
 
     YAML_BLOCK_MAPPING_STYLE,
  */
 
 /** Token types. */
-typedef enum {
+typedef enum yaml_token_type_e {
     YAML_NO_TOKEN,
 
     YAML_STREAM_START_TOKEN,
 } yaml_token_type_t;
 
 /** The token structure. */
-typedef struct {
+typedef struct yaml_token_s {
 
     /** The token type. */
     yaml_token_type_t type;
  */
 
 /** Event types. */
-typedef enum {
+typedef enum yaml_event_type_e {
     YAML_NO_EVENT,
 
     YAML_STREAM_START_EVENT,
 } yaml_event_type_t;
 
 /** The event structure. */
-typedef struct {
+typedef struct yaml_event_s {
 
     /** The event type. */
     yaml_event_type_t type;
 /**
  * Create the STREAM-START event.
  *
- * @param[out]  event       An empty event object.
- * @param[in]   encoding    The stream encoding.
+ * @param[out]      event       An empty event object.
+ * @param[in]       encoding    The stream encoding.
  *
  * @returns @c 1 if the function succeeded, @c 0 on error.
  */
 /**
  * Create the STREAM-END event.
  *
- * @param[out]  event       An empty event object.
+ * @param[out]      event       An empty event object.
  *
  * @returns @c 1 if the function succeeded, @c 0 on error.
  */
  * The @a implicit argument is considered as a stylistic parameter and may be
  * ignored by the emitter.
  *
- * @param[out]  event                   An empty event object.
- * @param[in]   version_directive       The %YAML directive value or @c NULL.
- * @param[in]   tag_directives_start    The beginning of the %TAG directives list.
- * @param[in]   tag_directives_end      The end of the %TAG directives list.
- * @param[in]   implicit                If the document start indicator is implicit.
+ * @param[out]      event                   An empty event object.
+ * @param[in]       version_directive       The %YAML directive value or
+ *                                          @c NULL.
+ * @param[in]       tag_directives_start    The beginning of the %TAG
+ *                                          directives list.
+ * @param[in]       tag_directives_end      The end of the %TAG directives
+ *                                          list.
+ * @param[in]       implicit                If the document start indicator is
+ *                                          implicit.
  *
  * @returns @c 1 if the function succeeded, @c 0 on error.
  */
  * The @a implicit argument is considered as a stylistic parameter and may be
  * ignored by the emitter.
  *
- * @param[out]  event       An empty event object.
- * @param[in]   implicit    If the document end indicator is implicit.
+ * @param[out]      event       An empty event object.
+ * @param[in]       implicit    If the document end indicator is implicit.
  *
  * @returns @c 1 if the function succeeded, @c 0 on error.
  */
 /**
  * Create an ALIAS event.
  *
- * @param[out]  event       An empty event object.
- * @param[in]   anchor      The anchor value.
+ * @param[out]      event       An empty event object.
+ * @param[in]       anchor      The anchor value.
  *
  * @returns @c 1 if the function succeeded, @c 0 on error.
  */
  * Either the @a tag attribute or one of the @a plain_implicit and
  * @a quoted_implicit flags must be set.
  *
- * @param[out]  event           An empty event object.
- * @param[in]   anchor          The scalar anchor or @c NULL.
- * @param[in]   tag             The scalar tag or @c NULL.
- * @param[in]   value           The scalar value.
- * @param[in]   length          The length of the scalar value.
- * @param[in]   plain_implicit  If the tag may be omitted for the plain style.
- * @param[in]   quoted_implicit If the tag may be omitted for any non-plain style.
- * @param[in]   style           The scalar style.
+ * @param[out]      event           An empty event object.
+ * @param[in]       anchor          The scalar anchor or @c NULL.
+ * @param[in]       tag             The scalar tag or @c NULL.
+ * @param[in]       value           The scalar value.
+ * @param[in]       length          The length of the scalar value.
+ * @param[in]       plain_implicit  If the tag may be omitted for the plain
+ *                                  style.
+ * @param[in]       quoted_implicit If the tag may be omitted for any
+ *                                  non-plain style.
+ * @param[in]       style           The scalar style.
  *
  * @returns @c 1 if the function succeeded, @c 0 on error.
  */
  *
  * Either the @a tag attribute or the @a implicit flag must be set.
  *
- * @param[out]  event       An empty event object.
- * @param[in]   anchor      The sequence anchor or @c NULL.
- * @param[in]   tag         The sequence tag or @c NULL.
- * @param[in]   implicit    If the tag may be omitted.
- * @param[in]   style       The sequence style.
+ * @param[out]      event       An empty event object.
+ * @param[in]       anchor      The sequence anchor or @c NULL.
+ * @param[in]       tag         The sequence tag or @c NULL.
+ * @param[in]       implicit    If the tag may be omitted.
+ * @param[in]       style       The sequence style.
  *
  * @returns @c 1 if the function succeeded, @c 0 on error.
  */
 /**
  * Create a SEQUENCE-END event.
  *
- * @param[out]  event       An empty event object.
+ * @param[out]      event       An empty event object.
  *
  * @returns @c 1 if the function succeeded, @c 0 on error.
  */
  *
  * Either the @a tag attribute or the @a implicit flag must be set.
  *
- * @param[out]  event       An empty event object.
- * @param[in]   anchor      The mapping anchor or @c NULL.
- * @param[in]   tag         The mapping tag or @c NULL.
- * @param[in]   implicit    If the tag may be omitted.
- * @param[in]   style       The mapping style.
+ * @param[out]      event       An empty event object.
+ * @param[in]       anchor      The mapping anchor or @c NULL.
+ * @param[in]       tag         The mapping tag or @c NULL.
+ * @param[in]       implicit    If the tag may be omitted.
+ * @param[in]       style       The mapping style.
  *
  * @returns @c 1 if the function succeeded, @c 0 on error.
  */
 /**
  * Create a MAPPING-END event.
  *
- * @param[out]  event       An empty event object.
+ * @param[out]      event       An empty event object.
  *
  * @returns @c 1 if the function succeeded, @c 0 on error.
  */
 /**
  * Free any memory allocated for an event object.
  *
- * @param[out]  event   An event object.
+ * @param[in,out]   event   An event object.
  */
 
 YAML_DECLARE(void)
 
 #define YAML_DEFAULT_SCALAR_TAG     YAML_STR_TAG
 #define YAML_DEFAULT_SEQUENCE_TAG   YAML_SEQ_TAG
-#define YAML_DEFAULT_MAPPING_STYLE  YAML_MAP_TAG
+#define YAML_DEFAULT_MAPPING_TAG    YAML_MAP_TAG
 
 /** Node types. */
-typedef enum {
+typedef enum yaml_node_type_e {
     YAML_NO_NODE,
 
     YAML_SCALAR_NODE,
     YAML_MAPPING_NODE
 } yaml_node_type_t;
 
-#if 0
+/** The forward definition of a document node structure. */
+typedef struct yaml_node_s yaml_node_t;
 
-typedef struct _yaml_node_t yaml_node_item_t;
+/** An element of a sequence node. */
+typedef int yaml_node_item_t;
 
-typedef struct {
-    yaml_node_item_t key;
-    yaml_node_item_t value;
+/** An element of a mapping node. */
+typedef struct yaml_node_pair_s {
+    /** The key of the element. */
+    int key;
+    /** The value of the element. */
+    int value;
 } yaml_node_pair_t;
 
 /** The node structure. */
-typedef struct _yaml_node_t {
+struct yaml_node_s {
 
     /** The node type. */
     yaml_node_type_t type;
 
-    /* The reference counter. */
-    int references;
+    /** The node tag. */
+    yaml_char_t *tag;
 
     /** The node data. */
     union {
         
         /** The scalar parameters (for @c YAML_SCALAR_NODE). */
         struct {
-            /** The tag. */
-            yaml_char_t *tag;
             /** The scalar value. */
             yaml_char_t *value;
             /** The length of the scalar value. */
 
         /** The sequence parameters (for @c YAML_SEQUENCE_NODE). */
         struct {
-            /** The tag. */
-            yaml_char_t *tag;
             /** The stack of sequence items. */
             struct {
                 /** The beginning of the stack. */
-                struct yaml_node_item_t *start;
+                yaml_node_item_t *start;
                 /** The end of the stack. */
-                struct yaml_node_item_t *end;
+                yaml_node_item_t *end;
                 /** The top of the stack. */
-                struct yaml_node_item_t *top;
+                yaml_node_item_t *top;
             } items;
             /** The sequence style. */
             yaml_sequence_style_t style;
 
         /** The mapping parameters (for @c YAML_MAPPING_NODE). */
         struct {
-            /** The tag. */
-            yaml_char_t *tag;
-            /** The stack of mapping pairs. */
+            /** The stack of mapping pairs (key, value). */
             struct {
                 /** The beginning of the stack. */
-                struct yaml_node_pair_t *start;
+                yaml_node_pair_t *start;
                 /** The end of the stack. */
-                struct yaml_node_pair_t *end;
+                yaml_node_pair_t *end;
                 /** The top of the stack. */
-                struct yaml_node_pair_t *top;
+                yaml_node_pair_t *top;
             } pairs;
             /** The mapping style. */
             yaml_mapping_style_t style;
     /** The end of the node. */
     yaml_mark_t end_mark;
 
-} yaml_node_t;
+};
+
+/** The document structure. */
+typedef struct yaml_document_s {
+
+    /** The document nodes. */
+    struct {
+        /** The beginning of the stack. */
+        yaml_node_t *start;
+        /** The end of the stack. */
+        yaml_node_t *end;
+        /** The top of the stack. */
+        yaml_node_t *top;
+    } nodes;
+
+    /** The version directive. */
+    yaml_version_directive_t *version_directive;
+
+    /** The list of tag directives. */
+    struct {
+        /** The beginning of the tag directives list. */
+        yaml_tag_directive_t *start;
+        /** The end of the tag directives list. */
+        yaml_tag_directive_t *end;
+    } tag_directives;
+
+    /** Is the document start indicator implicit? */
+    int start_implicit;
+    /** Is the document end indicator implicit? */
+    int end_implicit;
+
+    /** The beginning of the document. */
+    yaml_mark_t start_mark;
+    /** The end of the document. */
+    yaml_mark_t end_mark;
+
+} yaml_document_t;
 
 /**
- * Create a SCALAR node.
+ * Create a YAML document.
  *
- * The @a style argument may be ignored by the emitter.
- *
- * @param[out]  node            An empty node object.
- * @param[in]   tag             The scalar tag.
- * @param[in]   value           The scalar value.
- * @param[in]   length          The length of the scalar value.
- * @param[in]   style           The scalar style.
+ * @param[out]      document                An empty document object.
+ * @param[in]       version_directive       The %YAML directive value or
+ *                                          @c NULL.
+ * @param[in]       tag_directives_start    The beginning of the %TAG
+ *                                          directives list.
+ * @param[in]       tag_directives_end      The end of the %TAG directives
+ *                                          list.
+ * @param[in]       start_implicit          If the document start indicator is
+ *                                          implicit.
+ * @param[in]       end_implicit            If the document end indicator is
+ *                                          implicit.
  *
  * @returns @c 1 if the function succeeded, @c 0 on error.
  */
 
 YAML_DECLARE(int)
-yaml_scalar_node_initialize(yaml_node_t *node,
+yaml_document_initialize(yaml_document_t *document,
+        yaml_version_directive_t *version_directive,
+        yaml_tag_directive_t *tag_directives_start,
+        yaml_tag_directive_t *tag_directives_end,
+        int start_implicit, int end_implicit);
+
+/**
+ * Delete a YAML document and all its nodes.
+ *
+ * @param[in,out]   document        A document object.
+ */
+
+YAML_DECLARE(void)
+yaml_document_delete(yaml_document_t *document);
+
+/**
+ * Get a node of a YAML document.
+ *
+ * The pointer returned by this function is valid until any of the functions
+ * modifying the documents are called.
+ *
+ * @param[in]       document        A document object.
+ * @param[in]       node            The node id.
+ *
+ * @returns the node objct or @c NULL if @c node_id is out of range.
+ */
+
+YAML_DECLARE(yaml_node_t *)
+yaml_document_get_node(yaml_document_t *document, int node_id);
+
+/**
+ * Get the root of a YAML document node.
+ *
+ * The root object is the first object added to the document.
+ *
+ * The pointer returned by this function is valid until any of the functions
+ * modifying the documents are called.
+ *
+ * An empty document produced by the parser signifies the end of a YAML
+ * stream.
+ *
+ * @param[in]       document        A document object.
+ *
+ * @returns the node object or @c NULL if the document is empty.
+ */
+
+YAML_DECLARE(yaml_node_t *)
+yaml_document_get_root_node(yaml_document_t *document);
+
+/**
+ * Create a SCALAR node and attach it to the document.
+ *
+ * The @a style argument may be ignored by the emitter.
+ *
+ * @param[in,out]   document        A document object.
+ * @param[in]       tag             The scalar tag.
+ * @param[in]       value           The scalar value.
+ * @param[in]       length          The length of the scalar value.
+ * @param[in]       style           The scalar style.
+ *
+ * @returns the node id or @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_document_add_scalar(yaml_document_t *document,
         yaml_char_t *tag, yaml_char_t *value, int length,
         yaml_scalar_style_t style);
 
 /**
- * Create a SEQUENCE node.
+ * Create a SEQUENCE node and attach it to the document.
  *
  * The @a style argument may be ignored by the emitter.
  *
- * @param[out]  node        An empty node object.
- * @param[in]   tag         The sequence tag.
- * @param[in]   style       The sequence style.
+ * @param[in,out]   document    A document object.
+ * @param[in]       tag         The sequence tag.
+ * @param[in]       style       The sequence style.
  *
- * @returns @c 1 if the function succeeded, @c 0 on error.
+ * @returns the node id or @c 0 on error.
  */
 
 YAML_DECLARE(int)
-yaml_sequence_node_initialize(yaml_node_t *node,
+yaml_document_add_sequence(yaml_document_t *document,
         yaml_char_t *tag, yaml_sequence_style_t style);
 
 /**
- * Add an item to a SEQUENCE node
+ * Create a MAPPING node and attach it to the document.
  *
- * @param[out]  node        A sequence node.
- * @param[in]   item        An item node.
+ * The @a style argument may be ignored by the emitter.
+ *
+ * @param[in,out]   document    A document object.
+ * @param[in]       tag         The sequence tag.
+ * @param[in]       style       The sequence style.
+ *
+ * @returns the node id or @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_document_add_mapping(yaml_document_t *document,
+        yaml_char_t *tag, yaml_mapping_style_t style);
+
+/**
+ * Add an item to a SEQUENCE node.
+ *
+ * @param[in,out]   document    A document object.
+ * @param[in]       sequence    The sequence node id.
+ * @param[in]       item        The item node id.
 *
  * @returns @c 1 if the function succeeded, @c 0 on error.
  */
 
 YAML_DECLARE(int)
-yaml_sequence_node_add_item(yaml_node_t *node, yaml_node_t *item)
+yaml_document_append_sequence_item(yaml_document_t *document,
+        int sequence, int item);
 
 /**
- * Create a SCALAR node and add it to a SEQUENCE node.
+ * Add a pair of a key and a value to a MAPPING node.
  *
- * @param[out]  node        A sequence node.
- * @param[in]   tag         The scalar tag.
- * @param[in]   value       The scalar value.
- * @param[in]   length      The length of the scalar value.
- * @param[in]   style       The scalar style.
- *
+ * @param[in,out]   document    A document object.
+ * @param[in]       mapping     The mapping node id.
+ * @param[in]       key         The key node id.
+ * @param[in]       value       The value node id.
+*
  * @returns @c 1 if the function succeeded, @c 0 on error.
  */
 
 YAML_DECLARE(int)
-yaml_sequence_node_add_scalar_item(yaml_node_t *node,
-        yaml_char_t *tag, yaml_char_t *value, int length,
-        yaml_scalar_style_t style);
-
-/**
- * Get the number of subnodes of a SEQUENCE node.
- *
- * @param[in]  node         A sequence node.
- *
- * @returns the number of subnodes.
- */
-
-YAML_DECLARE(size_t)
-yaml_sequence_node_get_length(yaml_node_t *node);
-
-/**
- * Get a subnode of a SEQUENCE node.
- *
- * @param[in]   node        A sequence node.
- * @param[in]   index       The index of a subnode.
- * @param[out]  item        A subnode.
- */
-
-YAML_DECLARE(void)
-yaml_sequence_node_get_item(yaml_node_t *node, size_t index,
-        yaml_node_t *item);
-
-/**
- * Create a MAPPING node.
- *
- * The @a style argument may be ignored by the emitter.
- *
- * @param[out]  node        An empty node object.
- * @param[in]   tag         The mapping tag.
- * @param[in]   style       The mapping style.
- *
- * @returns @c 1 if the function succeeded, @c 0 on error.
- */
-
-YAML_DECLARE(int)
-yaml_mapping_node_initialize(yaml_node_t *node,
-        yaml_char_t *tag, yaml_mapping_style_t style);
-
-/**
- * Add a key/value pair of nodes to a MAPPING node.
- *
- * @param[out]  node        A mapping node.
- * @param[in]   key         A key node.
- * @param[in]   value       A value node.
- *
- * @returns @c 1 if the function succeeded, @c 0 on error.
- */
-
-YAML_DECLARE(int)
-yaml_mapping_node_add_pair(yaml_node_t *node,
-        yaml_node_t *key, yaml_node_t *value)
-
-/**
- * Create a scalar key and add the key/value pair to a MAPPING node.
- *
- * @param[out]  node        A mapping node.
- * @param[in]   key_tag     The key node tag.
- * @param[in]   key_value   The key node value.
- * @param[in]   key_length  The length of the key node value.
- * @param[in]   key_style   The key node style.
- * @param[in]   value       A value node.
- *
- * @returns @c 1 if the function succeeded, @c 0 on error.
- */
-
-YAML_DECLARE(int)
-yaml_sequence_node_add_scalar_key_pair(yaml_node_t *node,
-        yaml_char_t *key_tag, yaml_char_t *key_value, int key_length,
-        yaml_scalar_style_t key_style,
-        yaml_node_t *value);
-
-/**
- * Create a scalar key/value nodes and add the pair to a MAPPING node.
- *
- * @param[out]  node            A mapping node.
- * @param[in]   key_tag         The key node tag.
- * @param[in]   key_value       The key node value.
- * @param[in]   key_length      The length of the key node value.
- * @param[in]   key_style       The key node style.
- * @param[in]   value_tag       The value node tag.
- * @param[in]   value_value     The value node value.
- * @param[in]   value_length    The length of the value node value.
- * @param[in]   value_style     The value node style.
- *
- * @returns @c 1 if the function succeeded, @c 0 on error.
- */
-
-YAML_DECLARE(int)
-yaml_sequence_node_add_scalar_pair(yaml_node_t *node,
-        yaml_char_t *key_tag, yaml_char_t *key_value, int key_length,
-        yaml_scalar_style_t key_style,
-        yaml_char_t *value_tag, yaml_char_t *value_value, int value_length,
-        yaml_scalar_style_t value_style);
-
-/**
- * Get the number of subnode pairs of a MAPPING node.
- *
- * @param[in]  node         A mapping node.
- *
- * @returns the number of pairs.
- */
-
-YAML_DECLARE(size_t)
-yaml_mapping_node_get_length(yaml_node_t *node);
-
-/**
- * Get a subnode of a SEQUENCE node.
- *
- * @param[in]   node        A sequence node.
- * @param[in]   index       The index of a subnode.
- * @param[out]  key         The key subnode.
- * @param[out]  value       The value subnode.
- */
-
-YAML_DECLARE(void)
-yaml_mapping_node_get_pair(yaml_node_t *node, size_t index,
-        yaml_node_t *key, yaml_node_t *value);
-
-/**
- * Delete a node and its subnodes.
- *
- * @param[out]  node    A node object.
- */
-
-YAML_DECLARE(void)
-yaml_node_delete(yaml_node_t *node);
-
-#endif
+yaml_document_append_mapping_pair(yaml_document_t *document,
+        int mapping, int key, int value);
 
 /** @} */
 
  * This structure holds information about a potential simple key.
  */
 
-typedef struct {
+typedef struct yaml_simple_key_s {
     /** Is a simple key possible? */
     int possible;
 
 /**
  * The states of the parser.
  */
-typedef enum {
+typedef enum yaml_parser_state_e {
     YAML_PARSE_STREAM_START_STATE,
     YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE,
     YAML_PARSE_DOCUMENT_START_STATE,
 } yaml_parser_state_t;
 
 /**
+ * This structure holds aliases data.
+ */
+
+typedef struct yaml_alias_data_s {
+    /** The anchor. */
+    yaml_char_t *anchor;
+    /** The node id. */
+    int index;
+    /** The anchor mark. */
+    yaml_mark_t mark;
+} yaml_alias_data_t;
+
+/**
  * The parser structure.
  *
  * All members are internal.  Manage the structure using the @c yaml_parser_
  * family of functions.
  */
 
-typedef struct {
+typedef struct yaml_parser_s {
 
     /**
      * @name Error handling
      * @}
      */
 
+    /**
+     * @name Dumper stuff
+     * @{
+     */
+
+    /** The alias data. */
+    struct {
+        /** The beginning of the list. */
+        yaml_alias_data_t *start;
+        /** The end of the list. */
+        yaml_alias_data_t *end;
+        /** The top of the list. */
+        yaml_alias_data_t *top;
+    } aliases;
+
+    /** The currently parsed document. */
+    yaml_document_t *document;
+
+    /**
+     * @}
+     */
+
 } yaml_parser_t;
 
 /**
  * This function creates a new parser object.  An application is responsible
  * for destroying the object using the yaml_parser_delete() function.
  *
- * @param[out]  parser  An empty parser object.
+ * @param[out]      parser  An empty parser object.
  *
  * @returns @c 1 if the function succeeded, @c 0 on error.
  */
  * produced token object using the @c yaml_token_delete function.
  *
  * An application must not alternate the calls of yaml_parser_scan() with the
- * calls of yaml_parser_parse(). Doing this will break the parser.
+ * calls of yaml_parser_parse() or yaml_parser_load(). Doing this will break
+ * the parser.
  *
  * @param[in,out]   parser      A parser object.
  * @param[out]      token       An empty token object.
  * An application is responsible for freeing any buffers associated with the
  * produced event object using the yaml_event_delete() function.
  *
- * An application must not alternate the calls of yaml_parser_scan() with the
- * calls of yaml_parser_parse(). Doing this will break the parser.
+ * An application must not alternate the calls of yaml_parser_parse() with the
+ * calls of yaml_parser_scan() or yaml_parser_load(). Doing this will break the
+ * parser.
  *
  * @param[in,out]   parser      A parser object.
  * @param[out]      event       An empty event object.
 YAML_DECLARE(int)
 yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event);
 
+/**
+ * Parse the input stream and produce the next YAML document.
+ *
+ * Call this function subsequently to produce a sequence of documents
+ * constituting the input stream.
+ *
+ * If the produced document has no root node, it means that the document
+ * end has been reached.
+ *
+ * An application is responsible for freeing any data associated with the
+ * produced document object using the yaml_document_delete() function.
+ *
+ * An application must not alternate the calls of yaml_parser_load() with the
+ * calls of yaml_parser_scan() or yaml_parser_parse(). Doing this will break
+ * the parser.
+ *
+ * @param[in,out]   parser      A parser object.
+ * @param[out]      document    An empty document object.
+ *
+ * @return @c 1 if the function succeeded, @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document);
+
 /** @} */
 
 /**
 typedef int yaml_write_handler_t(void *data, unsigned char *buffer, size_t size);
 
 /** The emitter states. */
-typedef enum {
+typedef enum yaml_emitter_state_e {
     YAML_EMIT_STREAM_START_STATE,
     YAML_EMIT_FIRST_DOCUMENT_START_STATE,
     YAML_EMIT_DOCUMENT_START_STATE,
  * family of functions.
  */
 
-typedef struct {
+typedef struct yaml_emitter_s {
 
     /**
      * @name Error handling
      * @}
      */
 
+    /**
+     * @name Dumper stuff
+     * @{
+     */
+
+    /** If the stream was already opened? */
+    int opened;
+    /** If the stream was already closed? */
+    int closed;
+
+    /** The information associated with the document nodes. */
+    struct {
+        /** The number of references. */
+        int references;
+        /** The anchor id. */
+        int anchor;
+        /** If the node has been emitted? */
+        int serialized;
+    } *anchors;
+
+    /** The last assigned anchor id. */
+    int last_anchor_id;
+
+    /** The currently emitted document. */
+    yaml_document_t *document;
+
+    /**
+     * @}
+     */
+
 } yaml_emitter_t;
 
 /**
 YAML_DECLARE(int)
 yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event);
 
+/*
+ * Start a YAML stream.
+ *
+ * This function should be used before yaml_emitter_dump() is called.
+ *
+ * @param[in,out]   emitter     An emitter object.
+ *
+ * @returns @c 1 if the function succeeded, @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_open(yaml_emitter_t *emitter);
+
+/*
+ * Finish a YAML stream.
+ *
+ * This function should be used after yaml_emitter_dump() is called.
+ *
+ * @param[in,out]   emitter     An emitter object.
+ *
+ * @returns @c 1 if the function succeeded, @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_close(yaml_emitter_t *emitter);
+
+/*
+ * Emit a YAML document.
+ *
+ * The documen object may be generated using the yaml_parser_load() function
+ * or the yaml_document_initialize() function.  The emitter takes the
+ * responsibility for the document object and destoys its content after
+ * it is emitted. The document object is destroyedeven if the function fails.
+ *
+ * @param[in,out]   emitter     An emitter object.
+ * @param[in,out]   document    A document object.
+ *
+ * @returns @c 1 if the function succeeded, @c 0 on error.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document);
+
 /**
  * Flush the accumulated characters to the output.
  *
 AM_CPPFLAGS = -I$(top_srcdir)/include
 lib_LTLIBRARIES = libyaml.la
-libyaml_la_SOURCES = yaml_private.h api.c reader.c scanner.c parser.c writer.c emitter.c
+libyaml_la_SOURCES = yaml_private.h api.c reader.c scanner.c parser.c loader.c writer.c emitter.c dumper.c
 libyaml_la_LDFLAGS = -release $(YAML_LT_RELEASE) -version-info $(YAML_LT_CURRENT):$(YAML_LT_REVISION):$(YAML_LT_AGE)
         yaml_free(tag_directive.prefix);
     }
     STACK_DEL(emitter, emitter->tag_directives);
+    yaml_free(emitter->anchors);
 
     memset(emitter, 0, sizeof(yaml_emitter_t));
 }
     memset(event, 0, sizeof(yaml_event_t));
 }
 
-#if 0
-
 /*
- * Create a SCALAR node.
+ * Create a document object.
  */
 
 YAML_DECLARE(int)
-yaml_scalar_node_initialize(yaml_node_t *node,
+yaml_document_initialize(yaml_document_t *document,
+        yaml_version_directive_t *version_directive,
+        yaml_tag_directive_t *tag_directives_start,
+        yaml_tag_directive_t *tag_directives_end,
+        int start_implicit, int end_implicit)
+{
+    struct {
+        yaml_error_type_t error;
+    } context;
+    struct {
+        yaml_node_t *start;
+        yaml_node_t *end;
+        yaml_node_t *top;
+    } nodes = { NULL, NULL, NULL };
+    yaml_version_directive_t *version_directive_copy = NULL;
+    struct {
+        yaml_tag_directive_t *start;
+        yaml_tag_directive_t *end;
+        yaml_tag_directive_t *top;
+    } tag_directives_copy = { NULL, NULL, NULL };
+    yaml_tag_directive_t value = { NULL, NULL };
+    yaml_mark_t mark = { 0, 0, 0 };
+
+    assert(document);       /* Non-NULL document object is expected. */
+    assert((tag_directives_start && tag_directives_end) ||
+            (tag_directives_start == tag_directives_end));
+                            /* Valid tag directives are expected. */
+
+    if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error;
+
+    if (version_directive) {
+        version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t));
+        if (!version_directive_copy) goto error;
+        version_directive_copy->major = version_directive->major;
+        version_directive_copy->minor = version_directive->minor;
+    }
+
+    if (tag_directives_start != tag_directives_end) {
+        yaml_tag_directive_t *tag_directive;
+        if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
+            goto error;
+        for (tag_directive = tag_directives_start;
+                tag_directive != tag_directives_end; tag_directive ++) {
+            assert(tag_directive->handle);
+            assert(tag_directive->prefix);
+            if (!yaml_check_utf8(tag_directive->handle,
+                        strlen((char *)tag_directive->handle)))
+                goto error;
+            if (!yaml_check_utf8(tag_directive->prefix,
+                        strlen((char *)tag_directive->prefix)))
+                goto error;
+            value.handle = yaml_strdup(tag_directive->handle);
+            value.prefix = yaml_strdup(tag_directive->prefix);
+            if (!value.handle || !value.prefix) goto error;
+            if (!PUSH(&context, tag_directives_copy, value))
+                goto error;
+            value.handle = NULL;
+            value.prefix = NULL;
+        }
+    }
+
+    DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy,
+            tag_directives_copy.start, tag_directives_copy.top,
+            start_implicit, end_implicit, mark, mark);
+
+    return 1;
+
+error:
+    STACK_DEL(&context, nodes);
+    yaml_free(version_directive_copy);
+    while (!STACK_EMPTY(&context, tag_directives_copy)) {
+        yaml_tag_directive_t value = POP(&context, tag_directives_copy);
+        yaml_free(value.handle);
+        yaml_free(value.prefix);
+    }
+    STACK_DEL(&context, tag_directives_copy);
+    yaml_free(value.handle);
+    yaml_free(value.prefix);
+
+    return 0;
+}
+
+/*
+ * Destroy a document object.
+ */
+
+YAML_DECLARE(void)
+yaml_document_delete(yaml_document_t *document)
+{
+    struct {
+        yaml_error_type_t error;
+    } context;
+    yaml_tag_directive_t *tag_directive;
+
+    assert(document);   /* Non-NULL document object is expected. */
+
+    while (!STACK_EMPTY(&context, document->nodes)) {
+        yaml_node_t node = POP(&context, document->nodes);
+        yaml_free(node.tag);
+        switch (node.type) {
+            case YAML_SCALAR_NODE:
+                yaml_free(node.data.scalar.value);
+                break;
+            case YAML_SEQUENCE_NODE:
+                STACK_DEL(&context, node.data.sequence.items);
+                break;
+            case YAML_MAPPING_NODE:
+                STACK_DEL(&context, node.data.mapping.pairs);
+                break;
+            default:
+                assert(0);  /* Should not happen. */
+        }
+    }
+    STACK_DEL(&context, document->nodes);
+
+    yaml_free(document->version_directive);
+    for (tag_directive = document->tag_directives.start;
+            tag_directive != document->tag_directives.end;
+            tag_directive++) {
+        yaml_free(tag_directive->handle);
+        yaml_free(tag_directive->prefix);
+    }
+    yaml_free(document->tag_directives.start);
+
+    memset(document, 0, sizeof(yaml_document_t));
+}
+
+/**
+ * Get a document node.
+ */
+
+YAML_DECLARE(yaml_node_t *)
+yaml_document_get_node(yaml_document_t *document, int node)
+{
+    assert(document);   /* Non-NULL document object is expected. */
+
+    if (node > 0 && document->nodes.start + node <= document->nodes.top) {
+        return document->nodes.start + node - 1;
+    }
+    return NULL;
+}
+
+/**
+ * Get the root object.
+ */
+
+YAML_DECLARE(yaml_node_t *)
+yaml_document_get_root_node(yaml_document_t *document)
+{
+    assert(document);   /* Non-NULL document object is expected. */
+
+    if (document->nodes.top != document->nodes.start) {
+        return document->nodes.start;
+    }
+    return NULL;
+}
+
+/*
+ * Add a scalar node to a document.
+ */
+
+YAML_DECLARE(int)
+yaml_document_add_scalar(yaml_document_t *document,
         yaml_char_t *tag, yaml_char_t *value, int length,
         yaml_scalar_style_t style)
 {
+    struct {
+        yaml_error_type_t error;
+    } context;
     yaml_mark_t mark = { 0, 0, 0 };
     yaml_char_t *tag_copy = NULL;
     yaml_char_t *value_copy = NULL;
+    yaml_node_t node;
 
-    assert(node);       /* Non-NULL node object is expected. */
-    assert(value);      /* Non-NULL anchor is expected. */
+    assert(document);   /* Non-NULL document object is expected. */
+    assert(value);      /* Non-NULL value is expected. */
 
     if (!tag) {
         tag = YAML_DEFAULT_SCALAR_TAG;
     memcpy(value_copy, value, length);
     value_copy[length] = '\0';
 
-    SCALAR_NODE_INIT(*node, tag_copy, value_copy, length, style, mark, mark);
+    SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark);
+    if (!PUSH(&context, document->nodes, node)) goto error;
 
-    return 1;
+    return document->nodes.top - document->nodes.start;
 
 error:
     yaml_free(tag_copy);
 }
 
 /*
- * Create a SEQUENCE node.
+ * Add a sequence node to a document.
  */
 
 YAML_DECLARE(int)
-yaml_sequence_node_initialize(yaml_node_t *node,
+yaml_document_add_sequence(yaml_document_t *document,
         yaml_char_t *tag, yaml_sequence_style_t style)
 {
     struct {
         yaml_node_item_t *end;
         yaml_node_item_t *top;
     } items = { NULL, NULL, NULL };
+    yaml_node_t node;
 
-    assert(node);   /* Non-NULL node object is expected. */
+    assert(document);   /* Non-NULL document object is expected. */
 
     if (!tag) {
         tag = YAML_DEFAULT_SEQUENCE_TAG;
     }
 
-    if (tag) {
-        if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
-        tag_copy = yaml_strdup(tag);
-        if (!tag_copy) goto error;
-    }
+    if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
+    tag_copy = yaml_strdup(tag);
+    if (!tag_copy) goto error;
 
-    if (!STACK_INIT(context, items, INITIAL_STACK_SIZE)) goto error;
+    if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error;
 
-    SEQUENCE_NODE_INIT(*node, tag_copy, items.start, item.end, style,
-            mark, mark);
+    SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end,
+            style, mark, mark);
+    if (!PUSH(&context, document->nodes, node)) goto error;
 
-    return 1;
+    return document->nodes.top - document->nodes.start;
 
 error:
+    STACK_DEL(&context, items);
     yaml_free(tag_copy);
-    STACK_DEL(context, items);
 
     return 0;
 }
 
 /*
- * Create a MAPPING node.
+ * Add a mapping node to a document.
  */
 
 YAML_DECLARE(int)
-yaml_mapping_node_initialize(yaml_node_t *node,
+yaml_document_add_mapping(yaml_document_t *document,
         yaml_char_t *tag, yaml_mapping_style_t style)
 {
     struct {
         yaml_node_pair_t *end;
         yaml_node_pair_t *top;
     } pairs = { NULL, NULL, NULL };
+    yaml_node_t node;
 
-    assert(node);   /* Non-NULL node object is expected. */
+    assert(document);   /* Non-NULL document object is expected. */
 
     if (!tag) {
         tag = YAML_DEFAULT_MAPPING_TAG;
     }
 
-    if (tag) {
-        if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
-        tag_copy = yaml_strdup(tag);
-        if (!tag_copy) goto error;
-    }
+    if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
+    tag_copy = yaml_strdup(tag);
+    if (!tag_copy) goto error;
 
-    if (!STACK_INIT(context, pairs, INITIAL_STACK_SIZE)) goto error;
+    if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error;
 
-    MAPPING_NODE_INIT(*node, tag_copy, pairs.start, pairs.end, style,
-            mark, mark);
+    MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end,
+            style, mark, mark);
+    if (!PUSH(&context, document->nodes, node)) goto error;
 
-    return 1;
+    return document->nodes.top - document->nodes.start;
 
 error:
+    STACK_DEL(&context, pairs);
     yaml_free(tag_copy);
-    STACK_DEL(context, pairs);
 
     return 0;
 }
 
 /*
- * Delete a node and its subnodes.
+ * Append an item to a sequence node.
  */
 
-YAML_DECLARE(void)
-yaml_node_delete(yaml_node_t *node)
+YAML_DECLARE(int)
+yaml_document_append_sequence_item(yaml_document_t *document,
+        int sequence, int item)
 {
     struct {
         yaml_error_type_t error;
     } context;
-    struct {
-        yaml_node_item_t *start;
-        yaml_node_item_t *end;
-        yaml_node_item_t *head;
-        yaml_node_item_t *tail;
-    } queue = { NULL, NULL, NULL, NULL };
 
-    assert(node);   /* Non-NULL node object is expected. */
+    assert(document);       /* Non-NULL document is required. */
+    assert(sequence > 0
+            && document->nodes.start + sequence <= document->nodes.top);
+                            /* Valid sequence id is required. */
+    assert(document->nodes.start[sequence-1].type == YAML_SEQUENCE_NODE);
+                            /* A sequence node is required. */
+    assert(item > 0 && document->nodes.start + item <= document->nodes.top);
+                            /* Valid item id is required. */
 
-    if (node->type == YAML_SCALAR_NODE) {
-        yaml_free(node->data.scalar.tag);
-        yaml_free(node->data.scalar.value);
-        memset(node, 0, sizeof(yaml_node_t));
-        return;
-    }
+    if (!PUSH(&context,
+                document->nodes.start[sequence-1].data.sequence.items, item))
+        return 0;
 
-    if (!QUEUE_INIT(context, queue, INITIAL_QUEUE_SIZE)) goto error;
-    if (!ENQUEUE(context, queue, node)) goto error;
-
-    while (!QUEUE_EMPTY(context, queue)) {
-        yaml_node_t node = DEQUEUE(context, queue);
-        if (node.type == YAML_SCALAR_NODE) {
-            if (!node->reference)
-        }
-        if (node->type == YAML_SEQUENCE_NODE) {
-            while (!STACK_EMPTY(context, node->data.sequence.items)) {
-                yaml_node_t *item = 
-            }
-        }
-    }
+    return 1;
 }
 
-#endif
+/*
+ * Append a pair of a key and a value to a mapping node.
+ */
 
+YAML_DECLARE(int)
+yaml_document_append_mapping_pair(yaml_document_t *document,
+        int mapping, int key, int value)
+{
+    struct {
+        yaml_error_type_t error;
+    } context;
+    yaml_node_pair_t pair = { key, value };
+
+    assert(document);       /* Non-NULL document is required. */
+    assert(mapping > 0
+            && document->nodes.start + mapping <= document->nodes.top);
+                            /* Valid mapping id is required. */
+    assert(document->nodes.start[mapping-1].type == YAML_MAPPING_NODE);
+                            /* A mapping node is required. */
+    assert(key > 0 && document->nodes.start + key <= document->nodes.top);
+                            /* Valid key id is required. */
+    assert(value > 0 && document->nodes.start + value <= document->nodes.top);
+                            /* Valid value id is required. */
+
+    if (!PUSH(&context,
+                document->nodes.start[mapping-1].data.mapping.pairs, pair))
+        return 0;
+
+    return 1;
+}
+
+
+#include "yaml_private.h"
+
+/*
+ * API functions.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_open(yaml_emitter_t *emitter);
+
+YAML_DECLARE(int)
+yaml_emitter_close(yaml_emitter_t *emitter);
+
+YAML_DECLARE(int)
+yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document);
+
+/*
+ * Clean up functions.
+ */
+
+static void
+yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter);
+
+/*
+ * Anchor functions.
+ */
+
+static void
+yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index);
+
+static yaml_char_t *
+yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id);
+
+
+/*
+ * Serialize functions.
+ */
+
+static int
+yaml_emitter_dump_node(yaml_emitter_t *emitter, int index);
+
+static int
+yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor);
+
+static int
+yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node,
+        yaml_char_t *anchor);
+
+static int
+yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node,
+        yaml_char_t *anchor);
+
+static int
+yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node,
+        yaml_char_t *anchor);
+
+/*
+ * Issue a STREAM-START event.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_open(yaml_emitter_t *emitter)
+{
+    yaml_event_t event;
+    yaml_mark_t mark = { 0, 0, 0 };
+
+    assert(emitter);            /* Non-NULL emitter object is required. */
+    assert(!emitter->opened);   /* Emitter should not be opened yet. */
+
+    STREAM_START_EVENT_INIT(event, YAML_ANY_ENCODING, mark, mark);
+
+    if (!yaml_emitter_emit(emitter, &event)) {
+        return 0;
+    }
+
+    emitter->opened = 1;
+
+    return 1;
+}
+
+/*
+ * Issue a STREAM-END event.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_close(yaml_emitter_t *emitter)
+{
+    yaml_event_t event;
+    yaml_mark_t mark = { 0, 0, 0 };
+
+    assert(emitter);            /* Non-NULL emitter object is required. */
+    assert(emitter->opened);    /* Emitter should be opened. */
+
+    if (emitter->closed) return 1;
+
+    STREAM_END_EVENT_INIT(event, mark, mark);
+
+    if (!yaml_emitter_emit(emitter, &event)) {
+        return 0;
+    }
+
+    emitter->closed = 1;
+
+    return 1;
+}
+
+/*
+ * Dump a YAML document.
+ */
+
+YAML_DECLARE(int)
+yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document)
+{
+    yaml_event_t event;
+    yaml_mark_t mark = { 0, 0, 0 };
+
+    assert(emitter);            /* Non-NULL emitter object is required. */
+    assert(document);           /* Non-NULL emitter object is expected. */
+
+    emitter->document = document;
+
+    if (!emitter->opened) {
+        if (!yaml_emitter_open(emitter)) goto error;
+    }
+
+    if (STACK_EMPTY(emitter, document->nodes)) {
+        if (!yaml_emitter_close(emitter)) goto error;
+        yaml_emitter_delete_document_and_anchors(emitter);
+        return 1;
+    }
+
+    assert(emitter->opened);    /* Emitter should be opened. */
+
+    emitter->anchors = yaml_malloc(sizeof(*(emitter->anchors))
+            * (document->nodes.top - document->nodes.start));
+    if (!emitter->anchors) goto error;
+    memset(emitter->anchors, 0, sizeof(*(emitter->anchors))
+            * (document->nodes.top - document->nodes.start));
+
+    DOCUMENT_START_EVENT_INIT(event, document->version_directive,
+            document->tag_directives.start, document->tag_directives.end,
+            document->start_implicit, mark, mark);
+    if (!yaml_emitter_emit(emitter, &event)) goto error;
+
+    yaml_emitter_anchor_node(emitter, 1);
+    if (!yaml_emitter_dump_node(emitter, 1)) goto error;
+
+    DOCUMENT_END_EVENT_INIT(event, document->end_implicit, mark, mark);
+    if (!yaml_emitter_emit(emitter, &event)) goto error;
+
+    yaml_emitter_delete_document_and_anchors(emitter);
+
+    return 1;
+
+error:
+
+    yaml_emitter_delete_document_and_anchors(emitter);
+
+    return 0;
+}
+
+/*
+ * Clean up the emitter object after a document is dumped.
+ */
+
+static void
+yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter)
+{
+    int index;
+
+    if (!emitter->anchors) {
+        yaml_document_delete(emitter->document);
+        emitter->document = NULL;
+        return;
+    }
+
+    for (index = 0; emitter->document->nodes.start + index
+            < emitter->document->nodes.top; index ++) {
+        yaml_node_t node = emitter->document->nodes.start[index];
+        if (!emitter->anchors[index].serialized) {
+            yaml_free(node.tag);
+            if (node.type == YAML_SCALAR_NODE) {
+                yaml_free(node.data.scalar.value);
+            }
+        }
+        if (node.type == YAML_SEQUENCE_NODE) {
+            STACK_DEL(emitter, node.data.sequence.items);
+        }
+        if (node.type == YAML_MAPPING_NODE) {
+            STACK_DEL(emitter, node.data.mapping.pairs);
+        }
+    }
+
+    STACK_DEL(emitter, emitter->document->nodes);
+    yaml_free(emitter->anchors);
+
+    emitter->anchors = NULL;
+    emitter->last_anchor_id = 0;
+    emitter->document = NULL;
+}
+
+/*
+ * Check the references of a node and assign the anchor id if needed.
+ */
+
+static void
+yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index)
+{
+    yaml_node_t *node = emitter->document->nodes.start + index - 1;
+    yaml_node_item_t *item;
+    yaml_node_pair_t *pair;
+
+    emitter->anchors[index-1].references ++;
+
+    if (emitter->anchors[index-1].references == 1) {
+        switch (node->type) {
+            case YAML_SEQUENCE_NODE:
+                for (item = node->data.sequence.items.start;
+                        item < node->data.sequence.items.top; item ++) {
+                    yaml_emitter_anchor_node(emitter, *item);
+                }
+                break;
+            case YAML_MAPPING_NODE:
+                for (pair = node->data.mapping.pairs.start;
+                        pair < node->data.mapping.pairs.top; pair ++) {
+                    yaml_emitter_anchor_node(emitter, pair->key);
+                    yaml_emitter_anchor_node(emitter, pair->value);
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    else if (emitter->anchors[index-1].references == 2) {
+        emitter->anchors[index-1].anchor = (++ emitter->last_anchor_id);
+    }
+}
+
+/*
+ * Generate a textual representation for an anchor.
+ */
+
+#define ANCHOR_TEMPLATE         "id%03d"
+#define ANCHOR_TEMPLATE_LENGTH  16
+
+static yaml_char_t *
+yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id)
+{
+    yaml_char_t *anchor = yaml_malloc(ANCHOR_TEMPLATE_LENGTH);
+
+    if (!anchor) return NULL;
+
+    sprintf((char *)anchor, ANCHOR_TEMPLATE, anchor_id);
+
+    return anchor;
+}
+
+/*
+ * Serialize a node.
+ */
+
+static int
+yaml_emitter_dump_node(yaml_emitter_t *emitter, int index)
+{
+    yaml_node_t *node = emitter->document->nodes.start + index - 1;
+    int anchor_id = emitter->anchors[index-1].anchor;
+    yaml_char_t *anchor = NULL;
+
+    if (anchor_id) {
+        anchor = yaml_emitter_generate_anchor(emitter, anchor_id);
+        if (!anchor) return 0;
+    }
+
+    if (emitter->anchors[index-1].serialized) {
+        return yaml_emitter_dump_alias(emitter, anchor);
+    }
+
+    emitter->anchors[index-1].serialized = 1;
+
+    switch (node->type) {
+        case YAML_SCALAR_NODE:
+            return yaml_emitter_dump_scalar(emitter, node, anchor);
+        case YAML_SEQUENCE_NODE:
+            return yaml_emitter_dump_sequence(emitter, node, anchor);
+        case YAML_MAPPING_NODE:
+            return yaml_emitter_dump_mapping(emitter, node, anchor);
+        default:
+            assert(0);      /* Could not happen. */
+            break;
+    }
+
+    return 0;       /* Could not happen. */
+}
+
+/*
+ * Serialize an alias.
+ */
+
+static int
+yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor)
+{
+    yaml_event_t event;
+    yaml_mark_t mark  = { 0, 0, 0 };
+
+    ALIAS_EVENT_INIT(event, anchor, mark, mark);
+
+    return yaml_emitter_emit(emitter, &event);
+}
+
+/*
+ * Serialize a scalar.
+ */
+
+static int
+yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node,
+        yaml_char_t *anchor)
+{
+    yaml_event_t event;
+    yaml_mark_t mark  = { 0, 0, 0 };
+
+    int plain_implicit = (strcmp((char *)node->tag,
+                YAML_DEFAULT_SCALAR_TAG) == 0);
+    int quoted_implicit = (strcmp((char *)node->tag,
+                YAML_DEFAULT_SCALAR_TAG) == 0);
+
+    SCALAR_EVENT_INIT(event, anchor, node->tag, node->data.scalar.value,
+            node->data.scalar.length, plain_implicit, quoted_implicit,
+            node->data.scalar.style, mark, mark);
+
+    return yaml_emitter_emit(emitter, &event);
+}
+
+/*
+ * Serialize a sequence.
+ */
+
+static int
+yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node,
+        yaml_char_t *anchor)
+{
+    yaml_event_t event;
+    yaml_mark_t mark  = { 0, 0, 0 };
+
+    int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_SEQUENCE_TAG) == 0);
+
+    yaml_node_item_t *item;
+
+    SEQUENCE_START_EVENT_INIT(event, anchor, node->tag, implicit,
+            node->data.sequence.style, mark, mark);
+    if (!yaml_emitter_emit(emitter, &event)) return 0;
+
+    for (item = node->data.sequence.items.start;
+            item < node->data.sequence.items.top; item ++) {
+        if (!yaml_emitter_dump_node(emitter, *item)) return 0;
+    }
+
+    SEQUENCE_END_EVENT_INIT(event, mark, mark);
+    if (!yaml_emitter_emit(emitter, &event)) return 0;
+
+    return 1;
+}
+
+/*
+ * Serialize a mapping.
+ */
+
+static int
+yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node,
+        yaml_char_t *anchor)
+{
+    yaml_event_t event;
+    yaml_mark_t mark  = { 0, 0, 0 };
+
+    int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_MAPPING_TAG) == 0);
+
+    yaml_node_pair_t *pair;
+
+    MAPPING_START_EVENT_INIT(event, anchor, node->tag, implicit,
+            node->data.mapping.style, mark, mark);
+    if (!yaml_emitter_emit(emitter, &event)) return 0;
+
+    for (pair = node->data.mapping.pairs.start;
+            pair < node->data.mapping.pairs.top; pair ++) {
+        if (!yaml_emitter_dump_node(emitter, pair->key)) return 0;
+        if (!yaml_emitter_dump_node(emitter, pair->value)) return 0;
+    }
+
+    MAPPING_END_EVENT_INIT(event, mark, mark);
+    if (!yaml_emitter_emit(emitter, &event)) return 0;
+
+    return 1;
+}
+
 yaml_emitter_select_scalar_style(yaml_emitter_t *emitter, yaml_event_t *event)
 {
     yaml_scalar_style_t style = event->data.scalar.style;
+    int no_tag = (!emitter->tag_data.handle && !emitter->tag_data.suffix);
+
+    if (no_tag && !event->data.scalar.plain_implicit
+            && !event->data.scalar.quoted_implicit) {
+        return yaml_emitter_set_emitter_error(emitter,
+                "neither tag nor implicit flags are specified");
+    }
 
     if (style == YAML_ANY_SCALAR_STYLE)
         style = YAML_PLAIN_SCALAR_STYLE;
         if (!emitter->scalar_data.length
                 && (emitter->flow_level || emitter->simple_key_context))
             style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
-        if (!event->data.scalar.plain_implicit
-                && !emitter->tag_data.handle && !emitter->tag_data.suffix)
+        if (no_tag && !event->data.scalar.plain_implicit)
             style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
     }
 
             style = YAML_DOUBLE_QUOTED_SCALAR_STYLE;
     }
 
-    if (!emitter->tag_data.handle && !emitter->tag_data.suffix)
+    if (no_tag && !event->data.scalar.quoted_implicit
+            && style != YAML_PLAIN_SCALAR_STYLE)
     {
-        if (!event->data.scalar.plain_implicit
-                && !event->data.scalar.quoted_implicit) {
-            return yaml_emitter_set_emitter_error(emitter,
-                    "neither tag nor implicit flags are specified");
-        }
-
-        if (event->data.scalar.plain_implicit
-                && style != YAML_PLAIN_SCALAR_STYLE) {
-            emitter->tag_data.handle = (yaml_char_t *)"!";
-            emitter->tag_data.handle_length = 1;
-        }
+        emitter->tag_data.handle = (yaml_char_t *)"!";
+        emitter->tag_data.handle_length = 1;
     }
 
     emitter->scalar_data.style = style;
+
+#include "yaml_private.h"
+
+/*
+ * API functions.
+ */
+
+YAML_DECLARE(int)
+yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document);
+
+/*
+ * Error handling.
+ */
+
+static int
+yaml_parser_set_parser_error(yaml_parser_t *parser,
+        const char *problem, yaml_mark_t problem_mark);
+
+static int
+yaml_parser_set_parser_error_context(yaml_parser_t *parser,
+        const char *context, yaml_mark_t context_mark,
+        const char *problem, yaml_mark_t problem_mark);
+
+
+/*
+ * Alias handling.
+ */
+
+static int
+yaml_parser_register_anchor(yaml_parser_t *parser,
+        int index, yaml_char_t *anchor);
+
+/*
+ * Clean up functions.
+ */
+
+static void
+yaml_parser_delete_aliases(yaml_parser_t *parser);
+
+/*
+ * Composer functions.
+ */
+
+static int
+yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *first_event);
+
+static int
+yaml_parser_load_node(yaml_parser_t *parser, yaml_event_t *first_event);
+
+static int
+yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *first_event);
+
+static int
+yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *first_event);
+
+static int
+yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *first_event);
+
+static int
+yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *first_event);
+
+/*
+ * Load the next document of the stream.
+ */
+
+YAML_DECLARE(int)
+yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document)
+{
+    yaml_event_t event;
+
+    assert(parser);     /* Non-NULL parser object is expected. */
+    assert(document);   /* Non-NULL document object is expected. */
+
+    memset(document, 0, sizeof(yaml_document_t));
+    if (!STACK_INIT(parser, document->nodes, INITIAL_STACK_SIZE))
+        goto error;
+
+    if (!parser->stream_start_produced) {
+        if (!yaml_parser_parse(parser, &event)) goto error;
+        assert(event.type == YAML_STREAM_START_EVENT);
+                        /* STREAM-START is expected. */
+    }
+
+    if (parser->stream_end_produced) {
+        return 1;
+    }
+
+    if (!yaml_parser_parse(parser, &event)) goto error;
+    if (event.type == YAML_STREAM_END_EVENT) {
+        return 1;
+    }
+
+    if (!STACK_INIT(parser, parser->aliases, INITIAL_STACK_SIZE))
+        goto error;
+
+    parser->document = document;
+
+    if (!yaml_parser_load_document(parser, &event)) goto error;
+
+    yaml_parser_delete_aliases(parser);
+    parser->document = NULL;
+
+    return 1;
+
+error:
+
+    yaml_parser_delete_aliases(parser);
+    yaml_document_delete(document);
+    parser->document = NULL;
+
+    return 0;
+}
+
+/*
+ * Set composer error.
+ */
+
+static int
+yaml_parser_set_composer_error(yaml_parser_t *parser,
+        const char *problem, yaml_mark_t problem_mark)
+{
+    parser->error = YAML_COMPOSER_ERROR;
+    parser->problem = problem;
+    parser->problem_mark = problem_mark;
+
+    return 0;
+}
+
+/*
+ * Set composer error with context.
+ */
+
+static int
+yaml_parser_set_composer_error_context(yaml_parser_t *parser,
+        const char *context, yaml_mark_t context_mark,
+        const char *problem, yaml_mark_t problem_mark)
+{
+    parser->error = YAML_COMPOSER_ERROR;
+    parser->context = context;
+    parser->context_mark = context_mark;
+    parser->problem = problem;
+    parser->problem_mark = problem_mark;
+
+    return 0;
+}
+
+/*
+ * Delete the stack of aliases.
+ */
+
+static void
+yaml_parser_delete_aliases(yaml_parser_t *parser)
+{
+    while (!STACK_EMPTY(parser, parser->aliases)) {
+        yaml_free(POP(parser, parser->aliases).anchor);
+    }
+    STACK_DEL(parser, parser->aliases);
+}
+
+/*
+ * Compose a document object.
+ */
+
+static int
+yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *first_event)
+{
+    yaml_event_t event;
+
+    assert(first_event->type == YAML_DOCUMENT_START_EVENT);
+                        /* DOCUMENT-START is expected. */
+
+    parser->document->version_directive
+        = first_event->data.document_start.version_directive;
+    parser->document->tag_directives.start
+        = first_event->data.document_start.tag_directives.start;
+    parser->document->tag_directives.end
+        = first_event->data.document_start.tag_directives.end;
+    parser->document->start_implicit
+        = first_event->data.document_start.implicit;
+    parser->document->start_mark = first_event->start_mark;
+
+    if (!yaml_parser_parse(parser, &event)) return 0;
+
+    if (!yaml_parser_load_node(parser, &event)) return 0;
+
+    if (!yaml_parser_parse(parser, &event)) return 0;
+    assert(event.type == YAML_DOCUMENT_END_EVENT);
+                        /* DOCUMENT-END is expected. */
+
+    parser->document->end_implicit = event.data.document_end.implicit;
+    parser->document->end_mark = event.end_mark;
+
+    return 1;
+}
+
+/*
+ * Compose a node.
+ */
+
+static int
+yaml_parser_load_node(yaml_parser_t *parser, yaml_event_t *first_event)
+{
+    switch (first_event->type) {
+        case YAML_ALIAS_EVENT:
+            return yaml_parser_load_alias(parser, first_event);
+        case YAML_SCALAR_EVENT:
+            return yaml_parser_load_scalar(parser, first_event);
+        case YAML_SEQUENCE_START_EVENT:
+            return yaml_parser_load_sequence(parser, first_event);
+        case YAML_MAPPING_START_EVENT:
+            return yaml_parser_load_mapping(parser, first_event);
+        default:
+            assert(0);  /* Could not happen. */
+            return 0;
+    }
+
+    return 0;
+}
+
+/*
+ * Add an anchor.
+ */
+
+static int
+yaml_parser_register_anchor(yaml_parser_t *parser,
+        int index, yaml_char_t *anchor)
+{
+    yaml_alias_data_t data = { anchor, index,
+        parser->document->nodes.start[index-1].start_mark };
+    yaml_alias_data_t *alias_data;
+
+    if (!anchor) return 1;
+
+    for (alias_data = parser->aliases.start;
+            alias_data != parser->aliases.top; alias_data ++) {
+        if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) {
+            yaml_free(anchor);
+            return yaml_parser_set_composer_error_context(parser,
+                    "found duplicate anchor; first occurence",
+                    alias_data->mark, "second occurence", data.mark);
+        }
+    }
+
+    if (!PUSH(parser, parser->aliases, data)) {
+        yaml_free(anchor);
+        return 0;
+    }
+
+    return 1;
+}
+
+/*
+ * Compose a node corresponding to an alias.
+ */
+
+static int
+yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *first_event)
+{
+    yaml_char_t *anchor = first_event->data.alias.anchor;
+    yaml_alias_data_t *alias_data;
+
+    for (alias_data = parser->aliases.start;
+            alias_data != parser->aliases.top; alias_data ++) {
+        if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) {
+            yaml_free(anchor);
+            return alias_data->index;
+        }
+    }
+
+    yaml_free(anchor);
+    return yaml_parser_set_composer_error(parser, "found undefined alias",
+            first_event->start_mark);
+}
+
+/*
+ * Compose a scalar node.
+ */
+
+static int
+yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *first_event)
+{
+    yaml_node_t node;
+    int index;
+    yaml_char_t *tag = first_event->data.scalar.tag;
+
+    if (!tag || strcmp((char *)tag, "!") == 0) {
+        yaml_free(tag);
+        tag = yaml_strdup(YAML_DEFAULT_SCALAR_TAG);
+        if (!tag) goto error;
+    }
+
+    SCALAR_NODE_INIT(node, tag, first_event->data.scalar.value,
+            first_event->data.scalar.length, first_event->data.scalar.style,
+            first_event->start_mark, first_event->end_mark);
+
+    if (!PUSH(parser, parser->document->nodes, node)) goto error;
+
+    index = parser->document->nodes.top - parser->document->nodes.start;
+
+    if (!yaml_parser_register_anchor(parser, index,
+                first_event->data.scalar.anchor)) return 0;
+
+    return index;
+
+error:
+    yaml_free(tag);
+    yaml_free(first_event->data.scalar.anchor);
+    yaml_free(first_event->data.scalar.value);
+    return 0;
+}
+
+/*
+ * Compose a sequence node.
+ */
+
+static int
+yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *first_event)
+{
+    yaml_event_t event;
+    yaml_node_t node;
+    struct {
+        yaml_node_item_t *start;
+        yaml_node_item_t *end;
+        yaml_node_item_t *top;
+    } items = { NULL, NULL, NULL };
+    int index, item_index;
+    yaml_char_t *tag = first_event->data.sequence_start.tag;
+
+    if (!tag || strcmp((char *)tag, "!") == 0) {
+        yaml_free(tag);
+        tag = yaml_strdup(YAML_DEFAULT_SEQUENCE_TAG);
+        if (!tag) goto error;
+    }
+
+    if (!STACK_INIT(parser, items, INITIAL_STACK_SIZE)) goto error;
+
+    SEQUENCE_NODE_INIT(node, tag, items.start, items.end,
+            first_event->data.sequence_start.style,
+            first_event->start_mark, first_event->end_mark);
+
+    if (!PUSH(parser, parser->document->nodes, node)) goto error;
+
+    index = parser->document->nodes.top - parser->document->nodes.start;
+
+    if (!yaml_parser_register_anchor(parser, index,
+                first_event->data.sequence_start.anchor)) return 0;
+
+    if (!yaml_parser_parse(parser, &event)) return 0;
+
+    while (event.type != YAML_SEQUENCE_END_EVENT) {
+        item_index = yaml_parser_load_node(parser, &event);
+        if (!item_index) return 0;
+        if (!PUSH(parser,
+                    parser->document->nodes.start[index-1].data.sequence.items,
+                    item_index)) return 0;
+        if (!yaml_parser_parse(parser, &event)) return 0;
+    }
+
+    parser->document->nodes.start[index-1].end_mark = event.end_mark;
+
+    return index;
+
+error:
+    yaml_free(tag);
+    yaml_free(first_event->data.sequence_start.anchor);
+    return 0;
+}
+
+/*
+ * Compose a mapping node.
+ */
+
+static int
+yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *first_event)
+{
+    yaml_event_t event;
+    yaml_node_t node;
+    struct {
+        yaml_node_pair_t *start;
+        yaml_node_pair_t *end;
+        yaml_node_pair_t *top;
+    } pairs = { NULL, NULL, NULL };
+    int index;
+    yaml_node_pair_t pair;
+    yaml_char_t *tag = first_event->data.mapping_start.tag;
+
+    if (!tag || strcmp((char *)tag, "!") == 0) {
+        yaml_free(tag);
+        tag = yaml_strdup(YAML_DEFAULT_MAPPING_TAG);
+        if (!tag) goto error;
+    }
+
+    if (!STACK_INIT(parser, pairs, INITIAL_STACK_SIZE)) goto error;
+
+    MAPPING_NODE_INIT(node, tag, pairs.start, pairs.end,
+            first_event->data.mapping_start.style,
+            first_event->start_mark, first_event->end_mark);
+
+    if (!PUSH(parser, parser->document->nodes, node)) goto error;
+
+    index = parser->document->nodes.top - parser->document->nodes.start;
+
+    if (!yaml_parser_register_anchor(parser, index,
+                first_event->data.mapping_start.anchor)) return 0;
+
+    if (!yaml_parser_parse(parser, &event)) return 0;
+
+    while (event.type != YAML_MAPPING_END_EVENT) {
+        pair.key = yaml_parser_load_node(parser, &event);
+        if (!pair.key) return 0;
+        if (!yaml_parser_parse(parser, &event)) return 0;
+        pair.value = yaml_parser_load_node(parser, &event);
+        if (!pair.value) return 0;
+        if (!PUSH(parser,
+                    parser->document->nodes.start[index-1].data.mapping.pairs,
+                    pair)) return 0;
+        if (!yaml_parser_parse(parser, &event)) return 0;
+    }
+
+    parser->document->nodes.start[index-1].end_mark = event.end_mark;
+
+    return index;
+
+error:
+    yaml_free(tag);
+    yaml_free(first_event->data.mapping_start.anchor);
+    return 0;
+}
+

src/yaml_private.h

     (EVENT_INIT((event),YAML_MAPPING_END_EVENT,(start_mark),(end_mark)))
 
 /*
+ * Document initializer.
+ */
+
+#define DOCUMENT_INIT(document,document_nodes_start,document_nodes_end,         \
+        document_version_directive,document_tag_directives_start,               \
+        document_tag_directives_end,document_start_implicit,                    \
+        document_end_implicit,start_mark,end_mark)                              \
+    (memset(&(document), 0, sizeof(yaml_document_t)),                           \
+     (document).nodes.start = (document_nodes_start),                           \
+     (document).nodes.end = (document_nodes_end),                               \
+     (document).nodes.top = (document_nodes_start),                             \
+     (document).version_directive = (document_version_directive),               \
+     (document).tag_directives.start = (document_tag_directives_start),         \
+     (document).tag_directives.end = (document_tag_directives_end),             \
+     (document).start_implicit = (document_start_implicit),                     \
+     (document).end_implicit = (document_end_implicit))
+
+/*
  * Node initializers.
  */
 
-#define NODE_INIT(node,node_type,node_start_mark,node_end_mark)                 \
+#define NODE_INIT(node,node_type,node_tag,node_start_mark,node_end_mark)        \
     (memset(&(node), 0, sizeof(yaml_node_t)),                                   \
      (node).type = (node_type),                                                 \
+     (node).tag = (node_tag),                                                   \
      (node).start_mark = (node_start_mark),                                     \
      (node).end_mark = (node_end_mark))
 
 #define SCALAR_NODE_INIT(node,node_tag,node_value,node_length,                  \
         node_style,start_mark,end_mark)                                         \
-    (EVENT_INIT((node),YAML_SCALAR_NODE,(start_mark),(end_mark)),               \
-     (node).data.scalar.tag = (node_tag),                                       \
+    (NODE_INIT((node),YAML_SCALAR_NODE,(node_tag),(start_mark),(end_mark)),     \
      (node).data.scalar.value = (node_value),                                   \
      (node).data.scalar.length = (node_length),                                 \
      (node).data.scalar.style = (node_style))
 
 #define SEQUENCE_NODE_INIT(node,node_tag,node_items_start,node_items_end,       \
         node_style,start_mark,end_mark)                                         \
-    (NODE_INIT((node),YAML_SEQUENCE_NODE,(start_mark),(end_mark)),             \
-     (node).data.sequence.tag = (node_tag),                                     \
+    (NODE_INIT((node),YAML_SEQUENCE_NODE,(node_tag),(start_mark),(end_mark)),   \
      (node).data.sequence.items.start = (node_items_start),                     \
      (node).data.sequence.items.end = (node_items_end),                         \
      (node).data.sequence.items.top = (node_items_start),                       \
 
 #define MAPPING_NODE_INIT(node,node_tag,node_pairs_start,node_pairs_end,        \
         node_style,start_mark,end_mark)                                         \
-    (NODE_INIT((node),YAML_MAPPING_NODE,(start_mark),(end_mark)),               \
-     (node).data.mapping.tag = (node_tag),                                      \
+    (NODE_INIT((node),YAML_MAPPING_NODE,(node_tag),(start_mark),(end_mark)),    \
      (node).data.mapping.pairs.start = (node_pairs_start),                      \
      (node).data.mapping.pairs.end = (node_pairs_end),                          \
      (node).data.mapping.pairs.top = (node_pairs_start),                        \

tests/Makefile.am

 LDADD = $(top_builddir)/src/libyaml.la
 TESTS = test-version test-reader
 check_PROGRAMS = test-version test-reader
-noinst_PROGRAMS = run-scanner run-parser run-emitter example-reformatter example-deconstructor