]> andersk Git - libyaml.git/blobdiff - src/scanner.c
Add yaml_emitter_emit_* set of functions.
[libyaml.git] / src / scanner.c
index e701aa52323406eb94184209579c6b5ec8a434f6..bb811276cdb901a4b7423d9be5037082139b85aa 100644 (file)
  *      BLOCK-END
  */
 
-#if HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <yaml/yaml.h>
-
-#include <assert.h>
+#include "yaml_private.h"
 
 /*
  * Ensure that the buffer contains the required number of characters.
  * Return 1 on success, 0 on failure (reader error or memory error).
  */
 
-#define UPDATE(parser,length)   \
-    (parser->unread >= (length) \
-        ? 1                     \
+#define CACHE(parser,length)                                                    \
+    (parser->unread >= (length)                                                 \
+        ? 1                                                                     \
         : yaml_parser_update_buffer(parser, (length)))
 
 /*
  * Check the octet at the specified position.
  */
 
-#define CHECK_AT(parser,octet,offset)   \
-    (parser->pointer[offset] == (yaml_char_t)(octet))
+#define CHECK_AT(parser,octet,offset)                                           \
+    (parser->buffer.pointer[offset] == (yaml_char_t)(octet))
 
 /*
  * Check the current octet in the buffer.
  * character, a digit, '_', or '-'.
  */
 
-#define IS_ALPHA_AT(parser,offset)  \
-     ((parser->pointer[offset] >= (yaml_char_t) '0' &&      \
-       parser->pointer[offset] <= (yaml_char_t) '9') ||     \
-      (parser->pointer[offset] >= (yaml_char_t) 'A' &&      \
-       parser->pointer[offset] <= (yaml_char_t) 'Z') ||     \
-      (parser->pointer[offset] >= (yaml_char_t) 'a' &&      \
-       parser->pointer[offset] <= (yaml_char_t) 'z') ||     \
-      parser->pointer[offset] == '_' ||                     \
-      parser->pointer[offset] == '-')
+#define IS_ALPHA_AT(parser,offset)                                              \
+     ((parser->buffer.pointer[offset] >= (yaml_char_t) '0' &&                   \
+       parser->buffer.pointer[offset] <= (yaml_char_t) '9') ||                  \
+      (parser->buffer.pointer[offset] >= (yaml_char_t) 'A' &&                   \
+       parser->buffer.pointer[offset] <= (yaml_char_t) 'Z') ||                  \
+      (parser->buffer.pointer[offset] >= (yaml_char_t) 'a' &&                   \
+       parser->buffer.pointer[offset] <= (yaml_char_t) 'z') ||                  \
+      parser->buffer.pointer[offset] == '_' ||                                  \
+      parser->buffer.pointer[offset] == '-')
 
 #define IS_ALPHA(parser)    IS_ALPHA_AT(parser,0)
 
  * Check if the character at the specified position is a digit.
  */
 
-#define IS_DIGIT_AT(parser,offset)  \
-     ((parser->pointer[offset] >= (yaml_char_t) '0' &&      \
-       parser->pointer[offset] <= (yaml_char_t) '9'))
+#define IS_DIGIT_AT(parser,offset)                                              \
+     ((parser->buffer.pointer[offset] >= (yaml_char_t) '0' &&                   \
+       parser->buffer.pointer[offset] <= (yaml_char_t) '9'))
 
 #define IS_DIGIT(parser)    IS_DIGIT_AT(parser,0)
 
  * Get the value of a digit.
  */
 
-#define AS_DIGIT_AT(parser,offset)  \
-     (parser->pointer[offset] - (yaml_char_t) '0')
+#define AS_DIGIT_AT(parser,offset)                                              \
+     (parser->buffer.pointer[offset] - (yaml_char_t) '0')
 
 #define AS_DIGIT(parser)    AS_DIGIT_AT(parser,0)
 
  * Check if the character at the specified position is a hex-digit.
  */
 
-#define IS_HEX_AT(parser,offset)    \
-     ((parser->pointer[offset] >= (yaml_char_t) '0' &&      \
-       parser->pointer[offset] <= (yaml_char_t) '9') ||     \
-      (parser->pointer[offset] >= (yaml_char_t) 'A' &&      \
-       parser->pointer[offset] <= (yaml_char_t) 'F') ||     \
-      (parser->pointer[offset] >= (yaml_char_t) 'a' &&      \
-       parser->pointer[offset] <= (yaml_char_t) 'f'))
+#define IS_HEX_AT(parser,offset)                                                \
+     ((parser->buffer.pointer[offset] >= (yaml_char_t) '0' &&                   \
+       parser->buffer.pointer[offset] <= (yaml_char_t) '9') ||                  \
+      (parser->buffer.pointer[offset] >= (yaml_char_t) 'A' &&                   \
+       parser->buffer.pointer[offset] <= (yaml_char_t) 'F') ||                  \
+      (parser->buffer.pointer[offset] >= (yaml_char_t) 'a' &&                   \
+       parser->buffer.pointer[offset] <= (yaml_char_t) 'f'))
 
 #define IS_HEX(parser)    IS_HEX_AT(parser,0)
 
  * Get the value of a hex-digit.
  */
 
-#define AS_HEX_AT(parser,offset)    \
-      ((parser->pointer[offset] >= (yaml_char_t) 'A' &&     \
-        parser->pointer[offset] <= (yaml_char_t) 'F') ?     \
-       (parser->pointer[offset] - (yaml_char_t) 'A' + 10) : \
-       (parser->pointer[offset] >= (yaml_char_t) 'a' &&     \
-        parser->pointer[offset] <= (yaml_char_t) 'f') ?     \
-       (parser->pointer[offset] - (yaml_char_t) 'a' + 10) : \
-       (parser->pointer[offset] - (yaml_char_t) '0'))
+#define AS_HEX_AT(parser,offset)                                                \
+      ((parser->buffer.pointer[offset] >= (yaml_char_t) 'A' &&                  \
+        parser->buffer.pointer[offset] <= (yaml_char_t) 'F') ?                  \
+       (parser->buffer.pointer[offset] - (yaml_char_t) 'A' + 10) :              \
+       (parser->buffer.pointer[offset] >= (yaml_char_t) 'a' &&                  \
+        parser->buffer.pointer[offset] <= (yaml_char_t) 'f') ?                  \
+       (parser->buffer.pointer[offset] - (yaml_char_t) 'a' + 10) :              \
+       (parser->buffer.pointer[offset] - (yaml_char_t) '0'))
  
 #define AS_HEX(parser)  AS_HEX_AT(parser,0)
  
  * Check if the character at the specified position is BOM.
  */
 
-#define IS_BOM_AT(parser,offset)                                    \
-     (CHECK_AT(parser,'\xEF',(offset))                              \
-      && CHECK_AT(parser,'\xBB',(offset)+1)                         \
+#define IS_BOM_AT(parser,offset)                                                \
+     (CHECK_AT(parser,'\xEF',(offset))                                          \
+      && CHECK_AT(parser,'\xBB',(offset)+1)                                     \
       && CHECK_AT(parser,'\xBF',(offset)+1))    /* BOM (#xFEFF) */
 
 #define IS_BOM(parser)  IS_BOM_AT(parser,0)
  * Check if the character at the specified position is a line break.
  */
 
-#define IS_BREAK_AT(parser,offset)                                      \
-    (CHECK_AT(parser,'\r',(offset))                 /* CR (#xD)*/       \
-     || CHECK_AT(parser,'\n',(offset))              /* LF (#xA) */      \
-     || (CHECK_AT(parser,'\xC2',(offset))                               \
-         && CHECK_AT(parser,'\x85',(offset)+1))     /* NEL (#x85) */    \
-     || (CHECK_AT(parser,'\xE2',(offset))                               \
-         && CHECK_AT(parser,'\x80',(offset)+1)                          \
-         && CHECK_AT(parser,'\xA8',(offset)+2))     /* LS (#x2028) */   \
-     || (CHECK_AT(parser,'\xE2',(offset))                               \
-         && CHECK_AT(parser,'\x80',(offset)+1)                          \
+#define IS_BREAK_AT(parser,offset)                                              \
+    (CHECK_AT(parser,'\r',(offset))                 /* CR (#xD)*/               \
+     || CHECK_AT(parser,'\n',(offset))              /* LF (#xA) */              \
+     || (CHECK_AT(parser,'\xC2',(offset))                                       \
+         && CHECK_AT(parser,'\x85',(offset)+1))     /* NEL (#x85) */            \
+     || (CHECK_AT(parser,'\xE2',(offset))                                       \
+         && CHECK_AT(parser,'\x80',(offset)+1)                                  \
+         && CHECK_AT(parser,'\xA8',(offset)+2))     /* LS (#x2028) */           \
+     || (CHECK_AT(parser,'\xE2',(offset))                                       \
+         && CHECK_AT(parser,'\x80',(offset)+1)                                  \
          && CHECK_AT(parser,'\xA9',(offset)+2)))    /* PS (#x2029) */
 
 #define IS_BREAK(parser)    IS_BREAK_AT(parser,0)
 
-#define IS_CRLF_AT(parser,offset) \
+#define IS_CRLF_AT(parser,offset)                                               \
      (CHECK_AT(parser,'\r',(offset)) && CHECK_AT(parser,'\n',(offset)+1))
 
 #define IS_CRLF(parser) IS_CRLF_AT(parser,0)
  * Check if the character is a line break or NUL.
  */
 
-#define IS_BREAKZ_AT(parser,offset) \
+#define IS_BREAKZ_AT(parser,offset)                                             \
     (IS_BREAK_AT(parser,(offset)) || IS_Z_AT(parser,(offset)))
 
 #define IS_BREAKZ(parser)   IS_BREAKZ_AT(parser,0)
  * Check if the character is a line break, space, or NUL.
  */
 
-#define IS_SPACEZ_AT(parser,offset) \
+#define IS_SPACEZ_AT(parser,offset)                                             \
     (IS_SPACE_AT(parser,(offset)) || IS_BREAKZ_AT(parser,(offset)))
 
 #define IS_SPACEZ(parser)   IS_SPACEZ_AT(parser,0)
  * Check if the character is a line break, space, tab, or NUL.
  */
 
-#define IS_BLANKZ_AT(parser,offset) \
+#define IS_BLANKZ_AT(parser,offset)                                             \
     (IS_BLANK_AT(parser,(offset)) || IS_BREAKZ_AT(parser,(offset)))
 
 #define IS_BLANKZ(parser)   IS_BLANKZ_AT(parser,0)
  * Determine the width of the character.
  */
 
-#define WIDTH_AT(parser,offset)                         \
-     ((parser->pointer[(offset)] & 0x80) == 0x00 ? 1 :  \
-      (parser->pointer[(offset)] & 0xE0) == 0xC0 ? 2 :  \
-      (parser->pointer[(offset)] & 0xF0) == 0xE0 ? 3 :  \
-      (parser->pointer[(offset)] & 0xF8) == 0xF0 ? 4 : 0)
+#define WIDTH_AT(parser,offset)                                                 \
+     ((parser->buffer.pointer[offset] & 0x80) == 0x00 ? 1 :                     \
+      (parser->buffer.pointer[offset] & 0xE0) == 0xC0 ? 2 :                     \
+      (parser->buffer.pointer[offset] & 0xF0) == 0xE0 ? 3 :                     \
+      (parser->buffer.pointer[offset] & 0xF8) == 0xF0 ? 4 : 0)
 
 #define WIDTH(parser)   WIDTH_AT(parser,0)
 
  * Advance the buffer pointer.
  */
 
-#define FORWARD(parser)                             \
-     (parser->index ++,                             \
-      parser->column ++,                            \
-      parser->unread --,                            \
-      parser->pointer += WIDTH(parser))
-
-#define FORWARD_LINE(parser)                        \
-     (IS_CRLF(parser) ?                             \
-      (parser->index += 2,                          \
-       parser->column = 0,                          \
-       parser->line ++,                             \
-       parser->unread -= 2,                         \
-       parser->pointer += 2) :                      \
-      IS_BREAK(parser) ?                            \
-      (parser->index ++,                            \
-       parser->column = 0,                          \
-       parser->line ++,                             \
-       parser->unread --,                           \
-       parser->pointer += WIDTH(parser)) : 0)
-
-/*
- * Resize a string if needed.
- */
+#define SKIP(parser)                                                            \
+     (parser->mark.index ++,                                                    \
+      parser->mark.column ++,                                                   \
+      parser->unread --,                                                        \
+      parser->buffer.pointer += WIDTH(parser))
 
-#define RESIZE(parser,string)   \
-    ((string).pointer-(string).buffer+5 < (string).size ? 1 :   \
-     yaml_parser_resize_string(parser, &(string)))
+#define SKIP_LINE(parser)                                                       \
+     (IS_CRLF(parser) ?                                                         \
+      (parser->mark.index += 2,                                                 \
+       parser->mark.column = 0,                                                 \
+       parser->mark.line ++,                                                    \
+       parser->unread -= 2,                                                     \
+       parser->buffer.pointer += 2) :                                           \
+      IS_BREAK(parser) ?                                                        \
+      (parser->mark.index ++,                                                   \
+       parser->mark.column = 0,                                                 \
+       parser->mark.line ++,                                                    \
+       parser->unread --,                                                       \
+       parser->buffer.pointer += WIDTH(parser)) : 0)
 
 /*
  * Copy a character to a string buffer and advance pointers.
  */
 
-#define COPY(parser,string)     \
-     (((*parser->pointer & 0x80) == 0x00 ?                  \
-       (*((string).pointer++) = *(parser->pointer++)) :     \
-       (*parser->pointer & 0xE0) == 0xC0 ?                  \
-       (*((string).pointer++) = *(parser->pointer++),       \
-        *((string).pointer++) = *(parser->pointer++)) :     \
-       (*parser->pointer & 0xF0) == 0xE0 ?                  \
-       (*((string).pointer++) = *(parser->pointer++),       \
-        *((string).pointer++) = *(parser->pointer++),       \
-        *((string).pointer++) = *(parser->pointer++)) :     \
-       (*parser->pointer & 0xF8) == 0xF0 ?                  \
-       (*((string).pointer++) = *(parser->pointer++),       \
-        *((string).pointer++) = *(parser->pointer++),       \
-        *((string).pointer++) = *(parser->pointer++),       \
-        *((string).pointer++) = *(parser->pointer++)) : 0), \
-      parser->index ++,                                     \
-      parser->column ++,                                    \
-      parser->unread --)
+#define READ(parser,string)                                                     \
+     (STRING_EXTEND(parser,string) ?                                            \
+         (((*parser->buffer.pointer & 0x80) == 0x00 ?                           \
+           (*((string).pointer++) = *(parser->buffer.pointer++)) :              \
+           (*parser->buffer.pointer & 0xE0) == 0xC0 ?                           \
+           (*((string).pointer++) = *(parser->buffer.pointer++),                \
+            *((string).pointer++) = *(parser->buffer.pointer++)) :              \
+           (*parser->buffer.pointer & 0xF0) == 0xE0 ?                           \
+           (*((string).pointer++) = *(parser->buffer.pointer++),                \
+            *((string).pointer++) = *(parser->buffer.pointer++),                \
+            *((string).pointer++) = *(parser->buffer.pointer++)) :              \
+           (*parser->buffer.pointer & 0xF8) == 0xF0 ?                           \
+           (*((string).pointer++) = *(parser->buffer.pointer++),                \
+            *((string).pointer++) = *(parser->buffer.pointer++),                \
+            *((string).pointer++) = *(parser->buffer.pointer++),                \
+            *((string).pointer++) = *(parser->buffer.pointer++)) : 0),          \
+          parser->mark.index ++,                                                \
+          parser->mark.column ++,                                               \
+          parser->unread --,                                                    \
+          1) : 0)
 
 /*
  * Copy a line break character to a string buffer and advance pointers.
  */
 
-#define COPY_LINE(parser,string)    \
-    ((CHECK_AT(parser,'\r',0) && CHECK_AT(parser,'\n',1)) ? /* CR LF -> LF */   \
+#define READ_LINE(parser,string)                                                \
+    (STRING_EXTEND(parser,string) ?                                             \
+    (((CHECK_AT(parser,'\r',0) && CHECK_AT(parser,'\n',1)) ? /* CR LF -> LF */  \
      (*((string).pointer++) = (yaml_char_t) '\n',                               \
-      parser->pointer += 2,                                                     \
-      parser->index += 2,                                                       \
-      parser->column = 0,                                                       \
-      parser->line ++,                                                          \
+      parser->buffer.pointer += 2,                                              \
+      parser->mark.index += 2,                                                  \
+      parser->mark.column = 0,                                                  \
+      parser->mark.line ++,                                                     \
       parser->unread -= 2) :                                                    \
      (CHECK_AT(parser,'\r',0) || CHECK_AT(parser,'\n',0)) ? /* CR|LF -> LF */   \
      (*((string).pointer++) = (yaml_char_t) '\n',                               \
-      parser->pointer ++,                                                       \
-      parser->index ++,                                                         \
-      parser->column = 0,                                                       \
-      parser->line ++,                                                          \
+      parser->buffer.pointer ++,                                                \
+      parser->mark.index ++,                                                    \
+      parser->mark.column = 0,                                                  \
+      parser->mark.line ++,                                                     \
       parser->unread --) :                                                      \
      (CHECK_AT(parser,'\xC2',0) && CHECK_AT(parser,'\x85',1)) ? /* NEL -> LF */ \
      (*((string).pointer++) = (yaml_char_t) '\n',                               \
-      parser->pointer += 2,                                                     \
-      parser->index ++,                                                         \
-      parser->column = 0,                                                       \
-      parser->line ++,                                                          \
+      parser->buffer.pointer += 2,                                              \
+      parser->mark.index ++,                                                    \
+      parser->mark.column = 0,                                                  \
+      parser->mark.line ++,                                                     \
       parser->unread --) :                                                      \
      (CHECK_AT(parser,'\xE2',0) &&                                              \
       CHECK_AT(parser,'\x80',1) &&                                              \
       (CHECK_AT(parser,'\xA8',2) ||                                             \
        CHECK_AT(parser,'\xA9',2))) ?                    /* LS|PS -> LS|PS */    \
-     (*((string).pointer++) = *(parser->pointer++),                             \
-      *((string).pointer++) = *(parser->pointer++),                             \
-      *((string).pointer++) = *(parser->pointer++),                             \
-      parser->index ++,                                                         \
-      parser->column = 0,                                                       \
-      parser->line ++,                                                          \
-      parser->unread --) : 0)
-
-/*
- * Append a string to another string and clear the former string.
- */
-
-#define JOIN(parser,head_string,tail_string)    \
-    (yaml_parser_join_string(parser, &(head_string), &(tail_string)) && \
-     yaml_parser_clear_string(parser, &(tail_string)))
+     (*((string).pointer++) = *(parser->buffer.pointer++),                      \
+      *((string).pointer++) = *(parser->buffer.pointer++),                      \
+      *((string).pointer++) = *(parser->buffer.pointer++),                      \
+      parser->mark.index ++,                                                    \
+      parser->mark.column = 0,                                                  \
+      parser->mark.line ++,                                                     \
+      parser->unread --) : 0),                                                  \
+    1) : 0)
 
 /*
  * Public API declarations.
  */
 
-YAML_DECLARE(yaml_token_t *)
-yaml_parser_get_token(yaml_parser_t *parser);
-
-YAML_DECLARE(yaml_token_t *)
-yaml_parser_peek_token(yaml_parser_t *parser);
+YAML_DECLARE(int)
+yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token);
 
 /*
  * Error handling.
@@ -796,41 +775,11 @@ static int
 yaml_parser_set_scanner_error(yaml_parser_t *parser, const char *context,
         yaml_mark_t context_mark, const char *problem);
 
-static yaml_mark_t
-yaml_parser_get_mark(yaml_parser_t *parser);
-
-/*
- * Buffers and lists.
- */
-
-typedef struct {
-    yaml_char_t *buffer;
-    yaml_char_t *pointer;
-    size_t size;
-} yaml_string_t;
-
-static yaml_string_t
-yaml_parser_new_string(yaml_parser_t *parser);
-
-static int
-yaml_parser_resize_string(yaml_parser_t *parser, yaml_string_t *string);
-
-static int
-yaml_parser_join_string(yaml_parser_t *parser,
-        yaml_string_t *string1, yaml_string_t *string2);
-
-static int
-yaml_parser_clear_string(yaml_parser_t *parser, yaml_string_t *string);
-
-static int
-yaml_parser_resize_list(yaml_parser_t *parser, void **buffer, size_t *size,
-        size_t item_size);
-
 /*
  * High-level token API.
  */
 
-static int
+YAML_DECLARE(int)
 yaml_parser_fetch_more_tokens(yaml_parser_t *parser);
 
 static int
@@ -855,17 +804,6 @@ yaml_parser_increase_flow_level(yaml_parser_t *parser);
 static int
 yaml_parser_decrease_flow_level(yaml_parser_t *parser);
 
-/*
- * Token manipulation.
- */
-
-static int
-yaml_parser_append_token(yaml_parser_t *parser, yaml_token_t *token);
-
-static int
-yaml_parser_insert_token(yaml_parser_t *parser,
-        int number, yaml_token_t *token);
-
 /*
  * Indentation treatment.
  */
@@ -936,8 +874,8 @@ yaml_parser_fetch_plain_scalar(yaml_parser_t *parser);
 static int
 yaml_parser_scan_to_next_token(yaml_parser_t *parser);
 
-static yaml_token_t *
-yaml_parser_scan_directive(yaml_parser_t *parser);
+static int
+yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token);
 
 static int
 yaml_parser_scan_directive_name(yaml_parser_t *parser,
@@ -955,12 +893,12 @@ static int
 yaml_parser_scan_tag_directive_value(yaml_parser_t *parser,
         yaml_mark_t mark, yaml_char_t **handle, yaml_char_t **prefix);
 
-static yaml_token_t *
-yaml_parser_scan_anchor(yaml_parser_t *parser,
+static int
+yaml_parser_scan_anchor(yaml_parser_t *parser, yaml_token_t *token,
         yaml_token_type_t type);
 
-static yaml_token_t *
-yaml_parser_scan_tag(yaml_parser_t *parser);
+static int
+yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token);
 
 static int
 yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive,
@@ -974,175 +912,57 @@ static int
 yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive,
         yaml_mark_t start_mark, yaml_string_t *string);
 
-static yaml_token_t *
-yaml_parser_scan_block_scalar(yaml_parser_t *parser, int literal);
+static int
+yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token,
+        int literal);
 
 static int
 yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser,
         int *indent, yaml_string_t *breaks,
         yaml_mark_t start_mark, yaml_mark_t *end_mark);
 
-static yaml_token_t *
-yaml_parser_scan_flow_scalar(yaml_parser_t *parser, int single);
-
-static yaml_token_t *
-yaml_parser_scan_plain_scalar(yaml_parser_t *parser);
-
-/*
- * Get the next token and remove it from the tokens queue.
- */
-
-YAML_DECLARE(yaml_token_t *)
-yaml_parser_get_token(yaml_parser_t *parser)
-{
-    yaml_token_t *token;
-
-    assert(parser); /* Non-NULL parser object is expected. */
-    assert(!parser->stream_end_produced);   /* No tokens after STREAM-END. */
-
-    /* Ensure that the tokens queue contains enough tokens. */
-
-    if (!yaml_parser_fetch_more_tokens(parser)) return NULL;
-
-    /* Fetch the next token from the queue. */
-
-    token = parser->tokens[parser->tokens_head];
-
-    /* Move the queue head. */
-
-    parser->tokens[parser->tokens_head++] = NULL;
-    if (parser->tokens_head == parser->tokens_size)
-        parser->tokens_head = 0;
-
-    parser->tokens_parsed++;
+static int
+yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token,
+        int single);
 
-    return token;
-}
+static int
+yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token);
 
 /*
- * Get the next token, but don't remove it from the queue.
+ * Get the next token.
  */
 
-YAML_DECLARE(yaml_token_t *)
-yaml_parser_peek_token(yaml_parser_t *parser)
+YAML_DECLARE(int)
+yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token)
 {
     assert(parser); /* Non-NULL parser object is expected. */
-    assert(!parser->stream_end_produced);   /* No tokens after STREAM-END. */
-
-    /* Ensure that the tokens queue contains enough tokens. */
-
-    if (!yaml_parser_fetch_more_tokens(parser)) return NULL;
-
-    /* Fetch the next token from the queue. */
-
-    return parser->tokens[parser->tokens_head];
-}
-
-/*
- * Create a new string.
- */
-
-static yaml_string_t
-yaml_parser_new_string(yaml_parser_t *parser)
-{
-    yaml_string_t string = { NULL, NULL, 0 };
-
-    string.buffer = yaml_malloc(YAML_DEFAULT_SIZE);
-    if (!string.buffer) {
-        parser->error = YAML_MEMORY_ERROR;
-        return string;
-    }
+    assert(token);  /* Non-NULL token object is expected. */
 
-    memset(string.buffer, 0, YAML_DEFAULT_SIZE);
-    string.pointer = string.buffer;
-    string.size = YAML_DEFAULT_SIZE;
+    /* No tokens after STREAM-END or error. */
 
-    return string;
-}
+    if (parser->stream_end_produced || parser->error) {
+        memset(token, 0, sizeof(yaml_token_t));
 
-/*
- * Double the size of a string.
- */
-
-static int
-yaml_parser_resize_string(yaml_parser_t *parser, yaml_string_t *string)
-{
-    yaml_char_t *new_buffer = yaml_realloc(string->buffer, string->size*2);
-
-    if (!new_buffer) {
-        yaml_free(string->buffer);
-        string->buffer = NULL;
-        string->pointer = NULL;
-        string->size = 0;
-        parser->error = YAML_MEMORY_ERROR;
-        return 0;
+        return 1;
     }
 
-    memset(new_buffer+string->size, 0, string->size);
-
-    string->pointer = new_buffer + (string->buffer-string->pointer);
-    string->buffer = new_buffer;
-    string->size *= 2;
-
-    return 1;
-}
-
-/*
- * Append a string to another string.
- */
-
-static int
-yaml_parser_join_string(yaml_parser_t *parser,
-        yaml_string_t *string1, yaml_string_t *string2)
-{
-    if (string2->buffer == string2->pointer) return 1;
+    /* Ensure that the tokens queue contains enough tokens. */
 
-    while (string1->pointer - string1->buffer + string2->pointer - string2->buffer + 1
-            > string1->size) {
-        if (!yaml_parser_resize_string(parser, string1)) return 0;
+    if (!parser->token_available) {
+        if (!yaml_parser_fetch_more_tokens(parser))
+            return 0;
     }
 
-    memcpy(string1->pointer, string2->buffer, string2->pointer-string2->buffer);
-
-    return 1;
-}
-
-/*
- * Fill the string with NULs and move the pointer to the beginning.
- */
-
-static int
-yaml_parser_clear_string(yaml_parser_t *parser, yaml_string_t *string)
-{
-    if (string->buffer == string->pointer) return 1;
-
-    memset(string->buffer, 0, string->pointer-string->buffer);
-
-    string->pointer = string->buffer;
-
-    return 1;
-}
-
-/*
- * Double a list.
- */
-
-static int
-yaml_parser_resize_list(yaml_parser_t *parser, void **buffer, size_t *size,
-        size_t item_size)
-{
-    void *new_buffer = yaml_realloc(*buffer, item_size*(*size)*2);
+    /* Fetch the next token from the queue. */
+    
+    *token = DEQUEUE(parser, parser->tokens);
+    parser->token_available = 0;
+    parser->tokens_parsed ++;
 
-    if (!new_buffer) {
-        parser->error = YAML_MEMORY_ERROR;
-        return 0;
+    if (token->type == YAML_STREAM_END_TOKEN) {
+        parser->stream_end_produced = 1;
     }
 
-    memset(new_buffer+(*size), 0, item_size*(*size));
-
-    *buffer = new_buffer;
-    *size *= 2;
-
     return 1;
 }
 
@@ -1158,32 +978,20 @@ yaml_parser_set_scanner_error(yaml_parser_t *parser, const char *context,
     parser->context = context;
     parser->context_mark = context_mark;
     parser->problem = problem;
-    parser->problem_mark = yaml_parser_get_mark(parser);
-}
-
-/*
- * Get the mark for the current buffer position.
- */
+    parser->problem_mark = parser->mark;
 
-static yaml_mark_t
-yaml_parser_get_mark(yaml_parser_t *parser)
-{
-    yaml_mark_t mark = { parser->index, parser->line, parser->column };
-
-    return mark;
+    return 0;
 }
 
-
 /*
  * Ensure that the tokens queue contains at least one token which can be
  * returned to the Parser.
  */
 
-static int
+YAML_DECLARE(int)
 yaml_parser_fetch_more_tokens(yaml_parser_t *parser)
 {
     int need_more_tokens;
-    int k;
 
     /* While we need more tokens to fetch, do it. */
 
@@ -1195,7 +1003,7 @@ yaml_parser_fetch_more_tokens(yaml_parser_t *parser)
 
         need_more_tokens = 0;
 
-        if (parser->tokens_head == parser->tokens_tail)
+        if (parser->tokens.head == parser->tokens.tail)
         {
             /* Queue is empty. */
 
@@ -1203,12 +1011,17 @@ yaml_parser_fetch_more_tokens(yaml_parser_t *parser)
         }
         else
         {
+            yaml_simple_key_t *simple_key;
+
             /* Check if any potential simple key may occupy the head position. */
 
-            for (k = 0; k <= parser->flow_level; k++) {
-                yaml_simple_key_t *simple_key = parser->simple_keys[k];
-                if (simple_key
-                        && (simple_key->token_number == parser->tokens_parsed)) {
+            if (!yaml_parser_stale_simple_keys(parser))
+                return 0;
+
+            for (simple_key = parser->simple_keys.start;
+                    simple_key != parser->simple_keys.top; simple_key++) {
+                if (simple_key->possible
+                        && simple_key->token_number == parser->tokens_parsed) {
                     need_more_tokens = 1;
                     break;
                 }
@@ -1226,6 +1039,8 @@ yaml_parser_fetch_more_tokens(yaml_parser_t *parser)
             return 0;
     }
 
+    parser->token_available = 1;
+
     return 1;
 }
 
@@ -1238,7 +1053,7 @@ yaml_parser_fetch_next_token(yaml_parser_t *parser)
 {
     /* Ensure that the buffer is initialized. */
 
-    if (!UPDATE(parser, 1))
+    if (!CACHE(parser, 1))
         return 0;
 
     /* Check if we just started scanning.  Fetch STREAM-START then. */
@@ -1251,9 +1066,14 @@ yaml_parser_fetch_next_token(yaml_parser_t *parser)
     if (!yaml_parser_scan_to_next_token(parser))
         return 0;
 
+    /* Remove obsolete potential simple keys. */
+
+    if (!yaml_parser_stale_simple_keys(parser))
+        return 0;
+
     /* Check the indentation level against the current column. */
 
-    if (!yaml_parser_unroll_indent(parser, parser->column))
+    if (!yaml_parser_unroll_indent(parser, parser->mark.column))
         return 0;
 
     /*
@@ -1261,7 +1081,7 @@ yaml_parser_fetch_next_token(yaml_parser_t *parser)
      * of the longest indicators ('--- ' and '... ').
      */
 
-    if (!UPDATE(parser, 4))
+    if (!CACHE(parser, 4))
         return 0;
 
     /* Is it the end of the stream? */
@@ -1271,12 +1091,12 @@ yaml_parser_fetch_next_token(yaml_parser_t *parser)
 
     /* Is it a directive? */
 
-    if (parser->column == 0 && CHECK(parser, '%'))
+    if (parser->mark.column == 0 && CHECK(parser, '%'))
         return yaml_parser_fetch_directive(parser);
 
     /* Is it the document start indicator? */
 
-    if (parser->column == 0
+    if (parser->mark.column == 0
             && CHECK_AT(parser, '-', 0)
             && CHECK_AT(parser, '-', 1)
             && CHECK_AT(parser, '-', 2)
@@ -1286,7 +1106,7 @@ yaml_parser_fetch_next_token(yaml_parser_t *parser)
 
     /* Is it the document end indicator? */
 
-    if (parser->column == 0
+    if (parser->mark.column == 0
             && CHECK_AT(parser, '.', 0)
             && CHECK_AT(parser, '.', 1)
             && CHECK_AT(parser, '.', 2)
@@ -1330,12 +1150,12 @@ yaml_parser_fetch_next_token(yaml_parser_t *parser)
 
     /* Is it the key indicator? */
 
-    if (CHECK(parser, '?') && (!parser->flow_level || IS_BLANKZ_AT(parser, 1)))
+    if (CHECK(parser, '?') && (parser->flow_level || IS_BLANKZ_AT(parser, 1)))
         return yaml_parser_fetch_key(parser);
 
     /* Is it the value indicator? */
 
-    if (CHECK(parser, ':') && (!parser->flow_level || IS_BLANKZ_AT(parser, 1)))
+    if (CHECK(parser, ':') && (parser->flow_level || IS_BLANKZ_AT(parser, 1)))
         return yaml_parser_fetch_value(parser);
 
     /* Is it an alias? */
@@ -1382,7 +1202,8 @@ yaml_parser_fetch_next_token(yaml_parser_t *parser)
      *      '#', '&', '*', '!', '|', '>', '\'', '\"',
      *      '%', '@', '`'.
      *
-     * In the block context, it may also start with the characters
+     * In the block context (and, for the '-' indicator, in the flow context
+     * too), it may also start with the characters
      *
      *      '-', '?', ':'
      *
@@ -1398,17 +1219,18 @@ yaml_parser_fetch_next_token(yaml_parser_t *parser)
                 || CHECK(parser, '!') || CHECK(parser, '|') || CHECK(parser, '>')
                 || CHECK(parser, '\'') || CHECK(parser, '"') || CHECK(parser, '%')
                 || CHECK(parser, '@') || CHECK(parser, '`')) ||
+            (CHECK(parser, '-') && !IS_BLANK_AT(parser, 1)) ||
             (!parser->flow_level &&
-             (CHECK(parser, '-') || CHECK(parser, '?') || CHECK(parser, ':')) &&
-             IS_BLANKZ_AT(parser, 1)))
+             (CHECK(parser, '?') || CHECK(parser, ':')) && !IS_BLANKZ_AT(parser, 1)))
         return yaml_parser_fetch_plain_scalar(parser);
 
     /*
      * If we don't determine the token type so far, it is an error.
      */
 
-    return yaml_parser_set_scanner_error(parser, "while scanning for the next token",
-            yaml_parser_get_mark(parser), "found character that cannot start any token");
+    return yaml_parser_set_scanner_error(parser,
+            "while scanning for the next token", parser->mark,
+            "found character that cannot start any token");
 }
 
 /*
@@ -1419,14 +1241,13 @@ yaml_parser_fetch_next_token(yaml_parser_t *parser)
 static int
 yaml_parser_stale_simple_keys(yaml_parser_t *parser)
 {
-    int level;
+    yaml_simple_key_t *simple_key;
 
     /* Check for a potential simple key for each flow level. */
 
-    for (level = 0; level <= parser->flow_level; level++)
+    for (simple_key = parser->simple_keys.start;
+            simple_key != parser->simple_keys.top; simple_key ++)
     {
-        yaml_simple_key_t *simple_key = parser->simple_keys[level];
-
         /*
          * The specification requires that a simple key
          *
@@ -1434,8 +1255,9 @@ yaml_parser_stale_simple_keys(yaml_parser_t *parser)
          *  - is shorter than 1024 characters.
          */
 
-        if (simple_key && (simple_key->line < parser->line ||
-                    simple_key->index < parser->index+1024)) {
+        if (simple_key->possible
+                && (simple_key->mark.line < parser->mark.line
+                    || simple_key->mark.index+1024 < parser->mark.index)) {
 
             /* Check if the potential simple key to be removed is required. */
 
@@ -1445,8 +1267,7 @@ yaml_parser_stale_simple_keys(yaml_parser_t *parser)
                         "could not found expected ':'");
             }
 
-            yaml_free(simple_key);
-            parser->simple_keys[level] = NULL;
+            simple_key->possible = 0;
         }
     }
 
@@ -1467,7 +1288,8 @@ yaml_parser_save_simple_key(yaml_parser_t *parser)
      * level.
      */
 
-    int required = (!parser->flow_level && parser->indent == parser->column);
+    int required = (!parser->flow_level
+            && parser->indent == parser->mark.column);
 
     /*
      * A simple key is required only when it is the first token in the current
@@ -1482,21 +1304,13 @@ yaml_parser_save_simple_key(yaml_parser_t *parser)
 
     if (parser->simple_key_allowed)
     {
-        yaml_simple_key_t simple_key = { required,
-            parser->tokens_parsed + parser->tokens_tail - parser->tokens_head,
-            parser->index, parser->line, parser->column,
-            yaml_parser_get_mark(parser) };
+        yaml_simple_key_t simple_key = { 1, required,
+            parser->tokens_parsed + parser->tokens.tail - parser->tokens.head,
+            parser->mark };
 
         if (!yaml_parser_remove_simple_key(parser)) return 0;
 
-        parser->simple_keys[parser->flow_level] =
-            yaml_malloc(sizeof(yaml_simple_key_t));
-        if (!parser->simple_keys[parser->flow_level]) {
-            parser->error = YAML_MEMORY_ERROR;
-            return 0;
-        }
-
-        *(parser->simple_keys[parser->flow_level]) = simple_key;
+        *(parser->simple_keys.top-1) = simple_key;
     }
 
     return 1;
@@ -1509,9 +1323,9 @@ yaml_parser_save_simple_key(yaml_parser_t *parser)
 static int
 yaml_parser_remove_simple_key(yaml_parser_t *parser)
 {
-    yaml_simple_key_t *simple_key = parser->simple_keys[parser->flow_level];
+    yaml_simple_key_t *simple_key = parser->simple_keys.top-1;
 
-    if (simple_key)
+    if (simple_key->possible)
     {
         /* If the key is required, it is an error. */
 
@@ -1520,12 +1334,11 @@ yaml_parser_remove_simple_key(yaml_parser_t *parser)
                     "while scanning a simple key", simple_key->mark,
                     "could not found expected ':'");
         }
+    }
 
-        /* Remove the key from the list. */
+    /* Remove the key from the stack. */
 
-        yaml_free(simple_key);
-        parser->simple_keys[parser->flow_level] = NULL;
-    }
+    simple_key->possible = 0;
 
     return 1;
 }
@@ -1537,17 +1350,16 @@ yaml_parser_remove_simple_key(yaml_parser_t *parser)
 static int
 yaml_parser_increase_flow_level(yaml_parser_t *parser)
 {
-    /* Check if we need to resize the list. */
+    yaml_simple_key_t empty_simple_key = { 0, 0, 0, { 0, 0, 0 } };
 
-    if (parser->flow_level == parser->simple_keys_size-1) {
-        if (!yaml_parser_resize_list(parser, (void **)&parser->simple_keys,
-                    &parser->simple_keys_size, sizeof(yaml_simple_key_t *)))
-            return 0;
-    }
+    /* Reset the simple key on the next level. */
+
+    if (!PUSH(parser, parser->simple_keys, empty_simple_key))
+        return 0;
 
-    /* Increase the flow level and reset the simple key. */
+    /* Increase the flow level. */
 
-    parser->simple_keys[++parser->flow_level] = NULL;
+    parser->flow_level++;
 
     return 1;
 }
@@ -1559,75 +1371,11 @@ yaml_parser_increase_flow_level(yaml_parser_t *parser)
 static int
 yaml_parser_decrease_flow_level(yaml_parser_t *parser)
 {
-    assert(parser->flow_level);                         /* Greater than 0. */
-    assert(!parser->simple_keys[parser->flow_level]);   /* Must be removed. */
-
-    parser->flow_level --;
-
-    return 1;
-}
-
-/*
- * Add a token to the tail of the tokens queue.
- */
-
-static int
-yaml_parser_append_token(yaml_parser_t *parser, yaml_token_t *token)
-{
-    return yaml_parser_insert_token(parser, -1, token);
-}
-
-/*
- * Insert the token into the tokens queue.  The number parameter is the
- * ordinal number of the token.  If the number is equal to -1, add the token
- * to the tail of the queue.
- */
-
-static int
-yaml_parser_insert_token(yaml_parser_t *parser,
-        int number, yaml_token_t *token)
-{
-    /* The index of the token in the queue. */
-
-    int index = (number == -1)
-            ? parser->tokens_tail - parser->tokens_head
-            : number - parser->tokens_parsed;
-
-    assert(index >= 0 && index <= (parser->tokens_tail-parser->tokens_head));
-
-    /* Check if we need to resize the queue. */
-
-    if (parser->tokens_head == 0 && parser->tokens_tail == parser->tokens_size) {
-        if (!yaml_parser_resize_list(parser, (void **)&parser->tokens,
-                    &parser->tokens_size, sizeof(yaml_token_t *)))
-            return 0;
-    }
-
-    /* Check if we need to move the queue to the beginning of the buffer. */
-
-    if (parser->tokens_tail == parser->tokens_size)
-    {
-        if (parser->tokens_head < parser->tokens_tail) {
-            memmove(parser->tokens, parser->tokens+parser->tokens_head,
-                    sizeof(yaml_token_t *)*(parser->tokens_tail-parser->tokens_head));
-        }
-        parser->tokens_tail -= parser->tokens_head;
-        parser->tokens_head = 0;
-    }
-
-    /* Check if we need to free space within the queue. */
-
-    if (index < (parser->tokens_tail-parser->tokens_head)) {
-        memmove(parser->tokens+parser->tokens_head+index+1,
-                parser->tokens+parser->tokens_head+index,
-                sizeof(yaml_token_t *)*(parser->tokens_tail-parser->tokens_head-index));
+    if (parser->flow_level) {
+        parser->flow_level --;
+        POP(parser, parser->simple_keys);
     }
 
-    /* Insert the token. */
-
-    parser->tokens[parser->tokens_head+index] = token;
-    parser->tokens_tail ++;
-
     return 1;
 }
 
@@ -1642,7 +1390,7 @@ static int
 yaml_parser_roll_indent(yaml_parser_t *parser, int column,
         int number, yaml_token_type_t type, yaml_mark_t mark)
 {
-    yaml_token_t *token;
+    yaml_token_t token;
 
     /* In the flow context, do nothing. */
 
@@ -1651,35 +1399,28 @@ yaml_parser_roll_indent(yaml_parser_t *parser, int column,
 
     if (parser->indent < column)
     {
-        /* Check if we need to expand the indents stack. */
-
-        if (parser->indents_length == parser->indents_size) {
-            if (!yaml_parser_resize_list(parser, (void **)&parser->indents,
-                        &parser->indents_size, sizeof(int)))
-                return 0;
-        }
-
         /*
          * Push the current indentation level to the stack and set the new
          * indentation level.
          */
 
-        parser->indents[parser->indents_length++] = parser->indent;
+        if (!PUSH(parser, parser->indents, parser->indent))
+            return 0;
+
         parser->indent = column;
 
-        /* Create a token. */
+        /* Create a token and insert it into the queue. */
 
-        token = yaml_token_new(type, mark, mark);
-        if (!token) {
-            parser->error = YAML_MEMORY_ERROR;
-            return 0;
-        }
-
-        /* Insert the token into the queue. */
+        TOKEN_INIT(token, type, mark, mark);
 
-        if (!yaml_parser_insert_token(parser, number, token)) {
-            yaml_token_delete(token);
-            return 0;
+        if (number == -1) {
+            if (!ENQUEUE(parser, parser->tokens, token))
+                return 0;
+        }
+        else {
+            if (!QUEUE_INSERT(parser,
+                        parser->tokens, number - parser->tokens_parsed, token))
+                return 0;
         }
     }
 
@@ -1696,7 +1437,7 @@ yaml_parser_roll_indent(yaml_parser_t *parser, int column,
 static int
 yaml_parser_unroll_indent(yaml_parser_t *parser, int column)
 {
-    yaml_token_t *token;
+    yaml_token_t token;
 
     /* In the flow context, do nothing. */
 
@@ -1707,28 +1448,16 @@ yaml_parser_unroll_indent(yaml_parser_t *parser, int column)
 
     while (parser->indent > column)
     {
-        yaml_mark_t mark = yaml_parser_get_mark(parser);
-
-        /* Create a token. */
-
-        token = yaml_token_new(YAML_BLOCK_END_TOKEN, mark, mark);
-        if (!token) {
-            parser->error = YAML_MEMORY_ERROR;
-            return 0;
-        }
+        /* Create a token and append it to the queue. */
 
-        /* Append the token to the queue. */
+        TOKEN_INIT(token, YAML_BLOCK_END_TOKEN, parser->mark, parser->mark);
 
-        if (!yaml_parser_append_token(parser, token)) {
-            yaml_token_delete(token);
+        if (!ENQUEUE(parser, parser->tokens, token))
             return 0;
-        }
 
         /* Pop the indentation level. */
 
-        assert(parser->indents_length);     /* Non-empty stack expected. */
-
-        parser->indent = parser->indents[--parser->indents_length];
+        parser->indent = POP(parser, parser->indents);
     }
 
     return 1;
@@ -1741,13 +1470,18 @@ yaml_parser_unroll_indent(yaml_parser_t *parser, int column)
 static int
 yaml_parser_fetch_stream_start(yaml_parser_t *parser)
 {
-    yaml_mark_t mark = yaml_parser_get_mark(parser);
-    yaml_token_t *token;
+    yaml_simple_key_t simple_key = { 0, 0, 0, { 0, 0, 0 } };
+    yaml_token_t token;
 
     /* Set the initial indentation. */
 
     parser->indent = -1;
 
+    /* Initialize the simple key stack. */
+
+    if (!PUSH(parser, parser->simple_keys, simple_key))
+        return 0;
+
     /* A simple key is allowed at the beginning of the stream. */
 
     parser->simple_key_allowed = 1;
@@ -1756,20 +1490,13 @@ yaml_parser_fetch_stream_start(yaml_parser_t *parser)
 
     parser->stream_start_produced = 1;
 
-    /* Create the STREAM-START token. */
+    /* Create the STREAM-START token and append it to the queue. */
 
-    token = yaml_stream_start_token_new(parser->encoding, mark, mark);
-    if (!token) {
-        parser->error = YAML_MEMORY_ERROR;
-        return 0;
-    }
+    STREAM_START_TOKEN_INIT(token, parser->encoding,
+            parser->mark, parser->mark);
 
-    /* Append the token to the queue. */
-
-    if (!yaml_parser_append_token(parser, token)) {
-        yaml_token_delete(token);
+    if (!ENQUEUE(parser, parser->tokens, token))
         return 0;
-    }
 
     return 1;
 }
@@ -1781,44 +1508,38 @@ yaml_parser_fetch_stream_start(yaml_parser_t *parser)
 static int
 yaml_parser_fetch_stream_end(yaml_parser_t *parser)
 {
-    yaml_mark_t mark = yaml_parser_get_mark(parser);
-    yaml_token_t *token;
+    yaml_token_t token;
 
     /* Reset the indentation level. */
 
     if (!yaml_parser_unroll_indent(parser, -1))
         return 0;
 
-    /* We have finished. */
+    /* Reset simple keys. */
 
-    parser->stream_end_produced = 1;
+    if (!yaml_parser_remove_simple_key(parser))
+        return 0;
 
-    /* Create the STREAM-END token. */
+    parser->simple_key_allowed = 0;
 
-    token = yaml_stream_end_token_new(mark, mark);
-    if (!token) {
-        parser->error = YAML_MEMORY_ERROR;
-        return 0;
-    }
+    /* Create the STREAM-END token and append it to the queue. */
 
-    /* Append the token to the queue. */
+    STREAM_END_TOKEN_INIT(token, parser->mark, parser->mark);
 
-    if (!yaml_parser_append_token(parser, token)) {
-        yaml_token_delete(token);
+    if (!ENQUEUE(parser, parser->tokens, token))
         return 0;
-    }
 
     return 1;
 }
 
 /*
- * Produce the YAML-DIRECTIVE or TAG-DIRECTIVE token.
+ * Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token.
  */
 
 static int
 yaml_parser_fetch_directive(yaml_parser_t *parser)
 {
-    yaml_token_t *token;
+    yaml_token_t token;
 
     /* Reset the indentation level. */
 
@@ -1834,13 +1555,13 @@ yaml_parser_fetch_directive(yaml_parser_t *parser)
 
     /* Create the YAML-DIRECTIVE or TAG-DIRECTIVE token. */
 
-    token = yaml_parser_scan_directive(parser);
-    if (!token) return 0;
+    if (!yaml_parser_scan_directive(parser, &token))
+        return 0;
 
     /* Append the token to the queue. */
 
-    if (!yaml_parser_append_token(parser, token)) {
-        yaml_token_delete(token);
+    if (!ENQUEUE(parser, parser->tokens, token)) {
+        yaml_token_delete(&token);
         return 0;
     }
 
@@ -1856,7 +1577,7 @@ yaml_parser_fetch_document_indicator(yaml_parser_t *parser,
         yaml_token_type_t type)
 {
     yaml_mark_t start_mark, end_mark;
-    yaml_token_t *token;
+    yaml_token_t token;
 
     /* Reset the indentation level. */
 
@@ -1872,28 +1593,22 @@ yaml_parser_fetch_document_indicator(yaml_parser_t *parser,
 
     /* Consume the token. */
 
-    start_mark = yaml_parser_get_mark(parser);
+    start_mark = parser->mark;
 
-    FORWARD(parser);
-    FORWARD(parser);
-    FORWARD(parser);
+    SKIP(parser);
+    SKIP(parser);
+    SKIP(parser);
 
-    end_mark = yaml_parser_get_mark(parser);
+    end_mark = parser->mark;
 
     /* Create the DOCUMENT-START or DOCUMENT-END token. */
 
-    token = yaml_token_new(type, start_mark, end_mark);
-    if (!token) {
-        parser->error = YAML_MEMORY_ERROR;
-        return 0;
-    }
+    TOKEN_INIT(token, type, start_mark, end_mark);
 
     /* Append the token to the queue. */
 
-    if (!yaml_parser_append_token(parser, token)) {
-        yaml_token_delete(token);
+    if (!ENQUEUE(parser, parser->tokens, token))
         return 0;
-    }
 
     return 1;
 }
@@ -1907,7 +1622,7 @@ yaml_parser_fetch_flow_collection_start(yaml_parser_t *parser,
         yaml_token_type_t type)
 {
     yaml_mark_t start_mark, end_mark;
-    yaml_token_t *token;
+    yaml_token_t token;
 
     /* The indicators '[' and '{' may start a simple key. */
 
@@ -1925,24 +1640,18 @@ yaml_parser_fetch_flow_collection_start(yaml_parser_t *parser,
 
     /* Consume the token. */
 
-    start_mark = yaml_parser_get_mark(parser);
-    FORWARD(parser);
-    end_mark = yaml_parser_get_mark(parser);
+    start_mark = parser->mark;
+    SKIP(parser);
+    end_mark = parser->mark;
 
     /* Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token. */
 
-    token = yaml_token_new(type, start_mark, end_mark);
-    if (!token) {
-        parser->error = YAML_MEMORY_ERROR;
-        return 0;
-    }
+    TOKEN_INIT(token, type, start_mark, end_mark);
 
     /* Append the token to the queue. */
 
-    if (!yaml_parser_append_token(parser, token)) {
-        yaml_token_delete(token);
+    if (!ENQUEUE(parser, parser->tokens, token))
         return 0;
-    }
 
     return 1;
 }
@@ -1956,7 +1665,7 @@ yaml_parser_fetch_flow_collection_end(yaml_parser_t *parser,
         yaml_token_type_t type)
 {
     yaml_mark_t start_mark, end_mark;
-    yaml_token_t *token;
+    yaml_token_t token;
 
     /* Reset any potential simple key on the current flow level. */
 
@@ -1974,24 +1683,18 @@ yaml_parser_fetch_flow_collection_end(yaml_parser_t *parser,
 
     /* Consume the token. */
 
-    start_mark = yaml_parser_get_mark(parser);
-    FORWARD(parser);
-    end_mark = yaml_parser_get_mark(parser);
+    start_mark = parser->mark;
+    SKIP(parser);
+    end_mark = parser->mark;
 
     /* Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token. */
 
-    token = yaml_token_new(type, start_mark, end_mark);
-    if (!token) {
-        parser->error = YAML_MEMORY_ERROR;
-        return 0;
-    }
+    TOKEN_INIT(token, type, start_mark, end_mark);
 
     /* Append the token to the queue. */
 
-    if (!yaml_parser_append_token(parser, token)) {
-        yaml_token_delete(token);
+    if (!ENQUEUE(parser, parser->tokens, token))
         return 0;
-    }
 
     return 1;
 }
@@ -2004,7 +1707,7 @@ static int
 yaml_parser_fetch_flow_entry(yaml_parser_t *parser)
 {
     yaml_mark_t start_mark, end_mark;
-    yaml_token_t *token;
+    yaml_token_t token;
 
     /* Reset any potential simple keys on the current flow level. */
 
@@ -2017,24 +1720,16 @@ yaml_parser_fetch_flow_entry(yaml_parser_t *parser)
 
     /* Consume the token. */
 
-    start_mark = yaml_parser_get_mark(parser);
-    FORWARD(parser);
-    end_mark = yaml_parser_get_mark(parser);
+    start_mark = parser->mark;
+    SKIP(parser);
+    end_mark = parser->mark;
 
-    /* Create the FLOW-ENTRY token. */
+    /* Create the FLOW-ENTRY token and append it to the queue. */
 
-    token = yaml_token_new(YAML_FLOW_ENTRY_TOKEN, start_mark, end_mark);
-    if (!token) {
-        parser->error = YAML_MEMORY_ERROR;
-        return 0;
-    }
+    TOKEN_INIT(token, YAML_FLOW_ENTRY_TOKEN, start_mark, end_mark);
 
-    /* Append the token to the queue. */
-
-    if (!yaml_parser_append_token(parser, token)) {
-        yaml_token_delete(token);
+    if (!ENQUEUE(parser, parser->tokens, token))
         return 0;
-    }
 
     return 1;
 }
@@ -2047,7 +1742,7 @@ static int
 yaml_parser_fetch_block_entry(yaml_parser_t *parser)
 {
     yaml_mark_t start_mark, end_mark;
-    yaml_token_t *token;
+    yaml_token_t token;
 
     /* Check if the scanner is in the block context. */
 
@@ -2056,15 +1751,14 @@ yaml_parser_fetch_block_entry(yaml_parser_t *parser)
         /* Check if we are allowed to start a new entry. */
 
         if (!parser->simple_key_allowed) {
-            return yaml_parser_set_scanner_error(parser, NULL,
-                    yaml_parser_get_mark(parser),
+            return yaml_parser_set_scanner_error(parser, NULL, parser->mark,
                     "block sequence entries are not allowed in this context");
         }
 
         /* Add the BLOCK-SEQUENCE-START token if needed. */
 
-        if (!yaml_parser_roll_indent(parser, parser->column, -1,
-                    YAML_BLOCK_SEQUENCE_START_TOKEN, yaml_parser_get_mark(parser)))
+        if (!yaml_parser_roll_indent(parser, parser->mark.column, -1,
+                    YAML_BLOCK_SEQUENCE_START_TOKEN, parser->mark))
             return 0;
     }
     else
@@ -2087,24 +1781,16 @@ yaml_parser_fetch_block_entry(yaml_parser_t *parser)
 
     /* Consume the token. */
 
-    start_mark = yaml_parser_get_mark(parser);
-    FORWARD(parser);
-    end_mark = yaml_parser_get_mark(parser);
+    start_mark = parser->mark;
+    SKIP(parser);
+    end_mark = parser->mark;
 
-    /* Create the BLOCK-ENTRY token. */
+    /* Create the BLOCK-ENTRY token and append it to the queue. */
 
-    token = yaml_token_new(YAML_BLOCK_ENTRY_TOKEN, start_mark, end_mark);
-    if (!token) {
-        parser->error = YAML_MEMORY_ERROR;
-        return 0;
-    }
+    TOKEN_INIT(token, YAML_BLOCK_ENTRY_TOKEN, start_mark, end_mark);
 
-    /* Append the token to the queue. */
-
-    if (!yaml_parser_append_token(parser, token)) {
-        yaml_token_delete(token);
+    if (!ENQUEUE(parser, parser->tokens, token))
         return 0;
-    }
 
     return 1;
 }
@@ -2117,7 +1803,7 @@ static int
 yaml_parser_fetch_key(yaml_parser_t *parser)
 {
     yaml_mark_t start_mark, end_mark;
-    yaml_token_t *token;
+    yaml_token_t token;
 
     /* In the block context, additional checks are required. */
 
@@ -2126,15 +1812,14 @@ yaml_parser_fetch_key(yaml_parser_t *parser)
         /* Check if we are allowed to start a new key (not nessesary simple). */
 
         if (!parser->simple_key_allowed) {
-            return yaml_parser_set_scanner_error(parser, NULL,
-                    yaml_parser_get_mark(parser),
+            return yaml_parser_set_scanner_error(parser, NULL, parser->mark,
                     "mapping keys are not allowed in this context");
         }
 
         /* Add the BLOCK-MAPPING-START token if needed. */
 
-        if (!yaml_parser_roll_indent(parser, parser->column, -1,
-                    YAML_BLOCK_MAPPING_START_TOKEN, yaml_parser_get_mark(parser)))
+        if (!yaml_parser_roll_indent(parser, parser->mark.column, -1,
+                    YAML_BLOCK_MAPPING_START_TOKEN, parser->mark))
             return 0;
     }
 
@@ -2149,24 +1834,16 @@ yaml_parser_fetch_key(yaml_parser_t *parser)
 
     /* Consume the token. */
 
-    start_mark = yaml_parser_get_mark(parser);
-    FORWARD(parser);
-    end_mark = yaml_parser_get_mark(parser);
+    start_mark = parser->mark;
+    SKIP(parser);
+    end_mark = parser->mark;
 
-    /* Create the KEY token. */
+    /* Create the KEY token and append it to the queue. */
 
-    token = yaml_token_new(YAML_KEY_TOKEN, start_mark, end_mark);
-    if (!token) {
-        parser->error = YAML_MEMORY_ERROR;
-        return 0;
-    }
+    TOKEN_INIT(token, YAML_KEY_TOKEN, start_mark, end_mark);
 
-    /* Append the token to the queue. */
-
-    if (!yaml_parser_append_token(parser, token)) {
-        yaml_token_delete(token);
+    if (!ENQUEUE(parser, parser->tokens, token))
         return 0;
-    }
 
     return 1;
 }
@@ -2179,40 +1856,32 @@ static int
 yaml_parser_fetch_value(yaml_parser_t *parser)
 {
     yaml_mark_t start_mark, end_mark;
-    yaml_token_t *token;
+    yaml_token_t token;
+    yaml_simple_key_t *simple_key = parser->simple_keys.top-1;
 
     /* Have we found a simple key? */
 
-    if (parser->simple_keys[parser->flow_level])
+    if (simple_key->possible)
     {
-        yaml_simple_key_t *simple_key = parser->simple_keys[parser->flow_level];
 
-        /* Create the KEY token. */
+        /* Create the KEY token and insert it into the queue. */
 
-        token = yaml_token_new(YAML_KEY_TOKEN, simple_key->mark, simple_key->mark);
-        if (!token) {
-            parser->error = YAML_MEMORY_ERROR;
-            return 0;
-        }
+        TOKEN_INIT(token, YAML_KEY_TOKEN, simple_key->mark, simple_key->mark);
 
-        /* Insert the token into the queue. */
-
-        if (!yaml_parser_insert_token(parser, simple_key->token_number, token)) {
-            yaml_token_delete(token);
+        if (!QUEUE_INSERT(parser, parser->tokens,
+                    simple_key->token_number - parser->tokens_parsed, token))
             return 0;
-        }
 
         /* In the block context, we may need to add the BLOCK-MAPPING-START token. */
 
-        if (!yaml_parser_roll_indent(parser, parser->column,
+        if (!yaml_parser_roll_indent(parser, simple_key->mark.column,
                     simple_key->token_number,
                     YAML_BLOCK_MAPPING_START_TOKEN, simple_key->mark))
             return 0;
 
-        /* Remove the simple key from the list. */
+        /* Remove the simple key. */
 
-        yaml_free(simple_key);
-        parser->simple_keys[parser->flow_level] = NULL;
+        simple_key->possible = 0;
 
         /* A simple key cannot follow another simple key. */
 
@@ -2229,15 +1898,14 @@ yaml_parser_fetch_value(yaml_parser_t *parser)
             /* Check if we are allowed to start a complex value. */
 
             if (!parser->simple_key_allowed) {
-                return yaml_parser_set_scanner_error(parser, NULL,
-                        yaml_parser_get_mark(parser),
+                return yaml_parser_set_scanner_error(parser, NULL, parser->mark,
                         "mapping values are not allowed in this context");
             }
 
             /* Add the BLOCK-MAPPING-START token if needed. */
 
-            if (!yaml_parser_roll_indent(parser, parser->column, -1,
-                        YAML_BLOCK_MAPPING_START_TOKEN, yaml_parser_get_mark(parser)))
+            if (!yaml_parser_roll_indent(parser, parser->mark.column, -1,
+                        YAML_BLOCK_MAPPING_START_TOKEN, parser->mark))
                 return 0;
         }
 
@@ -2248,24 +1916,16 @@ yaml_parser_fetch_value(yaml_parser_t *parser)
 
     /* Consume the token. */
 
-    start_mark = yaml_parser_get_mark(parser);
-    FORWARD(parser);
-    end_mark = yaml_parser_get_mark(parser);
+    start_mark = parser->mark;
+    SKIP(parser);
+    end_mark = parser->mark;
 
-    /* Create the VALUE token. */
+    /* Create the VALUE token and append it to the queue. */
 
-    token = yaml_token_new(YAML_VALUE_TOKEN, start_mark, end_mark);
-    if (!token) {
-        parser->error = YAML_MEMORY_ERROR;
-        return 0;
-    }
-
-    /* Append the token to the queue. */
+    TOKEN_INIT(token, YAML_VALUE_TOKEN, start_mark, end_mark);
 
-    if (!yaml_parser_append_token(parser, token)) {
-        yaml_token_delete(token);
+    if (!ENQUEUE(parser, parser->tokens, token))
         return 0;
-    }
 
     return 1;
 }
@@ -2277,7 +1937,7 @@ yaml_parser_fetch_value(yaml_parser_t *parser)
 static int
 yaml_parser_fetch_anchor(yaml_parser_t *parser, yaml_token_type_t type)
 {
-    yaml_token_t *token;
+    yaml_token_t token;
 
     /* An anchor or an alias could be a simple key. */
 
@@ -2288,18 +1948,15 @@ yaml_parser_fetch_anchor(yaml_parser_t *parser, yaml_token_type_t type)
 
     parser->simple_key_allowed = 0;
 
-    /* Create the ALIAS or ANCHOR token. */
-
-    token = yaml_parser_scan_anchor(parser, type);
-    if (!token) return 0;
+    /* Create the ALIAS or ANCHOR token and append it to the queue. */
 
-    /* Append the token to the queue. */
+    if (!yaml_parser_scan_anchor(parser, &token, type))
+        return 0;
 
-    if (!yaml_parser_append_token(parser, token)) {
-        yaml_token_delete(token);
+    if (!ENQUEUE(parser, parser->tokens, token)) {
+        yaml_token_delete(&token);
         return 0;
     }
-
     return 1;
 }
 
@@ -2310,7 +1967,7 @@ yaml_parser_fetch_anchor(yaml_parser_t *parser, yaml_token_type_t type)
 static int
 yaml_parser_fetch_tag(yaml_parser_t *parser)
 {
-    yaml_token_t *token;
+    yaml_token_t token;
 
     /* A tag could be a simple key. */
 
@@ -2321,15 +1978,13 @@ yaml_parser_fetch_tag(yaml_parser_t *parser)
 
     parser->simple_key_allowed = 0;
 
-    /* Create the TAG token. */
+    /* Create the TAG token and append it to the queue. */
 
-    token = yaml_parser_scan_tag(parser);
-    if (!token) return 0;
-
-    /* Append the token to the queue. */
+    if (!yaml_parser_scan_tag(parser, &token))
+        return 0;
 
-    if (!yaml_parser_append_token(parser, token)) {
-        yaml_token_delete(token);
+    if (!ENQUEUE(parser, parser->tokens, token)) {
+        yaml_token_delete(&token);
         return 0;
     }
 
@@ -2343,7 +1998,7 @@ yaml_parser_fetch_tag(yaml_parser_t *parser)
 static int
 yaml_parser_fetch_block_scalar(yaml_parser_t *parser, int literal)
 {
-    yaml_token_t *token;
+    yaml_token_t token;
 
     /* Remove any potential simple keys. */
 
@@ -2354,15 +2009,13 @@ yaml_parser_fetch_block_scalar(yaml_parser_t *parser, int literal)
 
     parser->simple_key_allowed = 1;
 
-    /* Create the SCALAR token. */
-
-    token = yaml_parser_scan_block_scalar(parser, literal);
-    if (!token) return 0;
+    /* Create the SCALAR token and append it to the queue. */
 
-    /* Append the token to the queue. */
+    if (!yaml_parser_scan_block_scalar(parser, &token, literal))
+        return 0;
 
-    if (!yaml_parser_append_token(parser, token)) {
-        yaml_token_delete(token);
+    if (!ENQUEUE(parser, parser->tokens, token)) {
+        yaml_token_delete(&token);
         return 0;
     }
 
@@ -2376,7 +2029,7 @@ yaml_parser_fetch_block_scalar(yaml_parser_t *parser, int literal)
 static int
 yaml_parser_fetch_flow_scalar(yaml_parser_t *parser, int single)
 {
-    yaml_token_t *token;
+    yaml_token_t token;
 
     /* A plain scalar could be a simple key. */
 
@@ -2387,15 +2040,13 @@ yaml_parser_fetch_flow_scalar(yaml_parser_t *parser, int single)
 
     parser->simple_key_allowed = 0;
 
-    /* Create the SCALAR token. */
-
-    token = yaml_parser_scan_flow_scalar(parser, single);
-    if (!token) return 0;
+    /* Create the SCALAR token and append it to the queue. */
 
-    /* Append the token to the queue. */
+    if (!yaml_parser_scan_flow_scalar(parser, &token, single))
+        return 0;
 
-    if (!yaml_parser_append_token(parser, token)) {
-        yaml_token_delete(token);
+    if (!ENQUEUE(parser, parser->tokens, token)) {
+        yaml_token_delete(&token);
         return 0;
     }
 
@@ -2409,7 +2060,7 @@ yaml_parser_fetch_flow_scalar(yaml_parser_t *parser, int single)
 static int
 yaml_parser_fetch_plain_scalar(yaml_parser_t *parser)
 {
-    yaml_token_t *token;
+    yaml_token_t token;
 
     /* A plain scalar could be a simple key. */
 
@@ -2420,15 +2071,13 @@ yaml_parser_fetch_plain_scalar(yaml_parser_t *parser)
 
     parser->simple_key_allowed = 0;
 
-    /* Create the SCALAR token. */
-
-    token = yaml_parser_scan_plain_scalar(parser);
-    if (!token) return 0;
+    /* Create the SCALAR token and append it to the queue. */
 
-    /* Append the token to the queue. */
+    if (!yaml_parser_scan_plain_scalar(parser, &token))
+        return 0;
 
-    if (!yaml_parser_append_token(parser, token)) {
-        yaml_token_delete(token);
+    if (!ENQUEUE(parser, parser->tokens, token)) {
+        yaml_token_delete(&token);
         return 0;
     }
 
@@ -2448,10 +2097,10 @@ yaml_parser_scan_to_next_token(yaml_parser_t *parser)
     {
         /* Allow the BOM mark to start a line. */
 
-        if (!UPDATE(parser, 1)) return 0;
+        if (!CACHE(parser, 1)) return 0;
 
-        if (parser->column == 0 && IS_BOM(parser))
-            FORWARD(parser);
+        if (parser->mark.column == 0 && IS_BOM(parser))
+            SKIP(parser);
 
         /*
          * Eat whitespaces.
@@ -2463,21 +2112,21 @@ yaml_parser_scan_to_next_token(yaml_parser_t *parser)
          *  after '-', '?', or ':' (complex value).  
          */
 
-        if (!UPDATE(parser, 1)) return 0;
+        if (!CACHE(parser, 1)) return 0;
 
         while (CHECK(parser,' ') ||
                 ((parser->flow_level || !parser->simple_key_allowed) &&
                  CHECK(parser, '\t'))) {
-            FORWARD(parser);
-            if (!UPDATE(parser, 1)) return 0;
+            SKIP(parser);
+            if (!CACHE(parser, 1)) return 0;
         }
 
         /* Eat a comment until a line break. */
 
         if (CHECK(parser, '#')) {
             while (!IS_BREAKZ(parser)) {
-                FORWARD(parser);
-                if (!UPDATE(parser, 1)) return 0;
+                SKIP(parser);
+                if (!CACHE(parser, 1)) return 0;
             }
         }
 
@@ -2485,8 +2134,8 @@ yaml_parser_scan_to_next_token(yaml_parser_t *parser)
 
         if (IS_BREAK(parser))
         {
-            if (!UPDATE(parser, 2)) return 0;
-            FORWARD_LINE(parser);
+            if (!CACHE(parser, 2)) return 0;
+            SKIP_LINE(parser);
 
             /* In the block context, a new line may start a simple key. */
 
@@ -2515,20 +2164,19 @@ yaml_parser_scan_to_next_token(yaml_parser_t *parser)
  *      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  */
 
-static yaml_token_t *
-yaml_parser_scan_directive(yaml_parser_t *parser)
+int
+yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token)
 {
     yaml_mark_t start_mark, end_mark;
     yaml_char_t *name = NULL;
     int major, minor;
     yaml_char_t *handle = NULL, *prefix = NULL;
-    yaml_token_t *token = NULL;
 
     /* Eat '%'. */
 
-    start_mark = yaml_parser_get_mark(parser);
+    start_mark = parser->mark;
 
-    FORWARD(parser);
+    SKIP(parser);
 
     /* Scan the directive name. */
 
@@ -2545,16 +2193,12 @@ yaml_parser_scan_directive(yaml_parser_t *parser)
                     &major, &minor))
             goto error;
 
-        end_mark = yaml_parser_get_mark(parser);
+        end_mark = parser->mark;
 
         /* Create a VERSION-DIRECTIVE token. */
 
-        token = yaml_version_directive_token_new(major, minor,
+        VERSION_DIRECTIVE_TOKEN_INIT(*token, major, minor,
                 start_mark, end_mark);
-        if (!token) {
-            parser->error = YAML_MEMORY_ERROR;
-            return 0;
-        }
     }
 
     /* Is it a TAG directive? */
@@ -2567,16 +2211,12 @@ yaml_parser_scan_directive(yaml_parser_t *parser)
                     &handle, &prefix))
             goto error;
 
-        end_mark = yaml_parser_get_mark(parser);
+        end_mark = parser->mark;
 
         /* Create a TAG-DIRECTIVE token. */
 
-        token = yaml_tag_directive_token_new(handle, prefix,
+        TAG_DIRECTIVE_TOKEN_INIT(*token, handle, prefix,
                 start_mark, end_mark);
-        if (!token) {
-            parser->error = YAML_MEMORY_ERROR;
-            return 0;
-        }
     }
 
     /* Unknown directive. */
@@ -2590,15 +2230,17 @@ yaml_parser_scan_directive(yaml_parser_t *parser)
 
     /* Eat the rest of the line including any comments. */
 
+    if (!CACHE(parser, 1)) goto error;
+
     while (IS_BLANK(parser)) {
-        FORWARD(parser);
-        if (!UPDATE(parser, 1)) goto error;
+        SKIP(parser);
+        if (!CACHE(parser, 1)) goto error;
     }
 
     if (CHECK(parser, '#')) {
         while (!IS_BREAKZ(parser)) {
-            FORWARD(parser);
-            if (!UPDATE(parser, 1)) goto error;
+            SKIP(parser);
+            if (!CACHE(parser, 1)) goto error;
         }
     }
 
@@ -2613,20 +2255,19 @@ yaml_parser_scan_directive(yaml_parser_t *parser)
     /* Eat a line break. */
 
     if (IS_BREAK(parser)) {
-        if (!UPDATE(parser, 2)) goto error;
-        FORWARD_LINE(parser);
+        if (!CACHE(parser, 2)) goto error;
+        SKIP_LINE(parser);
     }
 
     yaml_free(name);
 
-    return token;
+    return 1;
 
 error:
-    yaml_free(token);
     yaml_free(prefix);
     yaml_free(handle);
     yaml_free(name);
-    return NULL;
+    return 0;
 }
 
 /*
@@ -2643,24 +2284,23 @@ static int
 yaml_parser_scan_directive_name(yaml_parser_t *parser,
         yaml_mark_t start_mark, yaml_char_t **name)
 {
-    yaml_string_t string = yaml_parser_new_string(parser);
+    yaml_string_t string = NULL_STRING;
 
-    if (!string.buffer) goto error;
+    if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
 
     /* Consume the directive name. */
 
-    if (!UPDATE(parser, 1)) goto error;
+    if (!CACHE(parser, 1)) goto error;
 
     while (IS_ALPHA(parser))
     {
-        if (!RESIZE(parser, string)) goto error;
-        COPY(parser, string);
-        if (!UPDATE(parser, 1)) goto error;
+        if (!READ(parser, string)) goto error;
+        if (!CACHE(parser, 1)) goto error;
     }
 
     /* Check if the name is empty. */
 
-    if (string.buffer == string.pointer) {
+    if (string.start == string.pointer) {
         yaml_parser_set_scanner_error(parser, "while scanning a directive",
                 start_mark, "cannot found expected directive name");
         goto error;
@@ -2674,12 +2314,12 @@ yaml_parser_scan_directive_name(yaml_parser_t *parser,
         goto error;
     }
 
-    *name = string.buffer;
+    *name = string.start;
 
     return 1;
 
 error:
-    yaml_free(string.buffer);
+    STRING_DEL(parser, string);
     return 0;
 }
 
@@ -2697,11 +2337,11 @@ yaml_parser_scan_version_directive_value(yaml_parser_t *parser,
 {
     /* Eat whitespaces. */
 
-    if (!UPDATE(parser, 1)) return 0;
+    if (!CACHE(parser, 1)) return 0;
 
     while (IS_BLANK(parser)) {
-        FORWARD(parser);
-        if (!UPDATE(parser, 1)) return 0;
+        SKIP(parser);
+        if (!CACHE(parser, 1)) return 0;
     }
 
     /* Consume the major version number. */
@@ -2716,12 +2356,14 @@ yaml_parser_scan_version_directive_value(yaml_parser_t *parser,
                 start_mark, "did not find expected digit or '.' character");
     }
 
-    FORWARD(parser);
+    SKIP(parser);
 
     /* Consume the minor version number. */
 
     if (!yaml_parser_scan_version_directive_number(parser, start_mark, minor))
         return 0;
+
+    return 1;
 }
 
 #define MAX_NUMBER_LENGTH   9
@@ -2745,7 +2387,7 @@ yaml_parser_scan_version_directive_number(yaml_parser_t *parser,
 
     /* Repeat while the next character is digit. */
 
-    if (!UPDATE(parser, 1)) return 0;
+    if (!CACHE(parser, 1)) return 0;
 
     while (IS_DIGIT(parser))
     {
@@ -2758,9 +2400,9 @@ yaml_parser_scan_version_directive_number(yaml_parser_t *parser,
 
         value = value*10 + AS_DIGIT(parser);
 
-        FORWARD(parser);
+        SKIP(parser);
 
-        if (!UPDATE(parser, 1)) return 0;
+        if (!CACHE(parser, 1)) return 0;
     }
 
     /* Check if the number was present. */
@@ -2792,11 +2434,11 @@ yaml_parser_scan_tag_directive_value(yaml_parser_t *parser,
 
     /* Eat whitespaces. */
 
-    if (!UPDATE(parser, 1)) goto error;
+    if (!CACHE(parser, 1)) goto error;
 
     while (IS_BLANK(parser)) {
-        FORWARD(parser);
-        if (!UPDATE(parser, 1)) goto error;
+        SKIP(parser);
+        if (!CACHE(parser, 1)) goto error;
     }
 
     /* Scan a handle. */
@@ -2806,7 +2448,7 @@ yaml_parser_scan_tag_directive_value(yaml_parser_t *parser,
 
     /* Expect a whitespace. */
 
-    if (!UPDATE(parser, 1)) goto error;
+    if (!CACHE(parser, 1)) goto error;
 
     if (!IS_BLANK(parser)) {
         yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
@@ -2817,8 +2459,8 @@ yaml_parser_scan_tag_directive_value(yaml_parser_t *parser,
     /* Eat whitespaces. */
 
     while (IS_BLANK(parser)) {
-        FORWARD(parser);
-        if (!UPDATE(parser, 1)) goto error;
+        SKIP(parser);
+        if (!CACHE(parser, 1)) goto error;
     }
 
     /* Scan a prefix. */
@@ -2828,7 +2470,7 @@ yaml_parser_scan_tag_directive_value(yaml_parser_t *parser,
 
     /* Expect a whitespace or line break. */
 
-    if (!UPDATE(parser, 1)) goto error;
+    if (!CACHE(parser, 1)) goto error;
 
     if (!IS_BLANKZ(parser)) {
         yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
@@ -2847,35 +2489,33 @@ error:
     return 0;
 }
 
-static yaml_token_t *
-yaml_parser_scan_anchor(yaml_parser_t *parser,
+static int
+yaml_parser_scan_anchor(yaml_parser_t *parser, yaml_token_t *token,
         yaml_token_type_t type)
 {
     int length = 0;
     yaml_mark_t start_mark, end_mark;
-    yaml_token_t *token = NULL;
-    yaml_string_t string = yaml_parser_new_string(parser);
+    yaml_string_t string = NULL_STRING;
 
-    if (!string.buffer) goto error;
+    if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
 
     /* Eat the indicator character. */
 
-    start_mark = yaml_parser_get_mark(parser);
+    start_mark = parser->mark;
 
-    FORWARD(parser);
+    SKIP(parser);
 
     /* Consume the value. */
 
-    if (!UPDATE(parser, 1)) goto error;
+    if (!CACHE(parser, 1)) goto error;
 
     while (IS_ALPHA(parser)) {
-        if (!RESIZE(parser, string)) goto error;
-        COPY(parser, string);
-        if (!UPDATE(parser, 1)) goto error;
+        if (!READ(parser, string)) goto error;
+        if (!CACHE(parser, 1)) goto error;
         length ++;
     }
 
-    end_mark = yaml_parser_get_mark(parser);
+    end_mark = parser->mark;
 
     /*
      * Check if length of the anchor is greater than 0 and it is followed by
@@ -2895,19 +2535,17 @@ yaml_parser_scan_anchor(yaml_parser_t *parser,
 
     /* Create a token. */
 
-    token = type == YAML_ANCHOR_TOKEN ?
-        yaml_anchor_token_new(string.buffer, start_mark, end_mark) :
-        yaml_alias_token_new(string.buffer, start_mark, end_mark);
-    if (!token) {
-        parser->error = YAML_MEMORY_ERROR;
-        return 0;
+    if (type == YAML_ANCHOR_TOKEN) {
+        ANCHOR_TOKEN_INIT(*token, string.start, start_mark, end_mark);
+    }
+    else {
+        ALIAS_TOKEN_INIT(*token, string.start, start_mark, end_mark);
     }
 
-    return token;
+    return 1;
 
 error:
-    yaml_free(string.buffer);
-    yaml_free(token);
+    STRING_DEL(parser, string);
     return 0;
 }
 
@@ -2915,19 +2553,18 @@ error:
  * Scan a TAG token.
  */
 
-static yaml_token_t *
-yaml_parser_scan_tag(yaml_parser_t *parser)
+static int
+yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token)
 {
     yaml_char_t *handle = NULL;
     yaml_char_t *suffix = NULL;
-    yaml_token_t *token = NULL;
     yaml_mark_t start_mark, end_mark;
 
-    start_mark = yaml_parser_get_mark(parser);
+    start_mark = parser->mark;
 
     /* Check if the tag is in the canonical form. */
 
-    if (!UPDATE(parser, 2)) goto error;
+    if (!CACHE(parser, 2)) goto error;
 
     if (CHECK_AT(parser, '<', 1))
     {
@@ -2939,8 +2576,8 @@ yaml_parser_scan_tag(yaml_parser_t *parser)
 
         /* Eat '!<' */
 
-        FORWARD(parser);
-        FORWARD(parser);
+        SKIP(parser);
+        SKIP(parser);
 
         /* Consume the tag value. */
 
@@ -2955,7 +2592,7 @@ yaml_parser_scan_tag(yaml_parser_t *parser)
             goto error;
         }
 
-        FORWARD(parser);
+        SKIP(parser);
     }
     else
     {
@@ -2989,12 +2626,23 @@ yaml_parser_scan_tag(yaml_parser_t *parser)
             if (!handle) goto error;
             handle[0] = '!';
             handle[1] = '\0';
+
+            /*
+             * A special case: the '!' tag.  Set the handle to '' and the
+             * suffix to '!'.
+             */
+
+            if (suffix[0] == '\0') {
+                yaml_char_t *tmp = handle;
+                handle = suffix;
+                suffix = tmp;
+            }
         }
     }
 
     /* Check the character which ends the tag. */
 
-    if (!UPDATE(parser, 1)) goto error;
+    if (!CACHE(parser, 1)) goto error;
 
     if (!IS_BLANKZ(parser)) {
         yaml_parser_set_scanner_error(parser, "while scanning a tag",
@@ -3002,22 +2650,18 @@ yaml_parser_scan_tag(yaml_parser_t *parser)
         goto error;
     }
 
-    end_mark = yaml_parser_get_mark(parser);
+    end_mark = parser->mark;
 
     /* Create a token. */
 
-    token = yaml_tag_token_new(handle, suffix, start_mark, end_mark);
-    if (!token) {
-        parser->error = YAML_MEMORY_ERROR;
-        return 0;
-    }
+    TAG_TOKEN_INIT(*token, handle, suffix, start_mark, end_mark);
 
-    return token;
+    return 1;
 
 error:
     yaml_free(handle);
     yaml_free(suffix);
-    return NULL;
+    return 0;
 }
 
 /*
@@ -3028,13 +2672,13 @@ static int
 yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive,
         yaml_mark_t start_mark, yaml_char_t **handle)
 {
-    yaml_string_t string = yaml_parser_new_string(parser);
+    yaml_string_t string = NULL_STRING;
 
-    if (!string.buffer) goto error;
+    if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
 
     /* Check the initial '!' character. */
 
-    if (!UPDATE(parser, 1)) goto error;
+    if (!CACHE(parser, 1)) goto error;
 
     if (!CHECK(parser, '!')) {
         yaml_parser_set_scanner_error(parser, directive ?
@@ -3045,46 +2689,45 @@ yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive,
 
     /* Copy the '!' character. */
 
-    COPY(parser, string);
+    if (!READ(parser, string)) goto error;
 
     /* Copy all subsequent alphabetical and numerical characters. */
 
-    if (!UPDATE(parser, 1)) goto error;
+    if (!CACHE(parser, 1)) goto error;
 
     while (IS_ALPHA(parser))
     {
-        if (!RESIZE(parser, string)) goto error;
-        COPY(parser, string);
-        if (!UPDATE(parser, 1)) goto error;
+        if (!READ(parser, string)) goto error;
+        if (!CACHE(parser, 1)) goto error;
     }
 
     /* Check if the trailing character is '!' and copy it. */
 
     if (CHECK(parser, '!'))
     {
-        if (!RESIZE(parser, string)) goto error;
-        COPY(parser, string);
+        if (!READ(parser, string)) goto error;
     }
     else
     {
         /*
-         * It's not really a tag handle.  If it's a %TAG directive, it's an
-         * error.  If it's a tag token, it must be a part of URI.
+         * It's either the '!' tag or not really a tag handle.  If it's a %TAG
+         * directive, it's an error.  If it's a tag token, it must be a part of
+         * URI.
          */
 
-        if (directive) {
-            yaml_parser_set_scanner_error(parser, "while parsing a directive",
+        if (directive && !(string.start[0] == '!' && string.start[1] == '\0')) {
+            yaml_parser_set_scanner_error(parser, "while parsing a tag directive",
                     start_mark, "did not find expected '!'");
             goto error;
         }
     }
 
-    *handle = string.buffer;
+    *handle = string.start;
 
     return 1;
 
 error:
-    yaml_free(string.buffer);
+    STRING_DEL(parser, string);
     return 0;
 }
 
@@ -3097,26 +2740,33 @@ yaml_parser_scan_tag_uri(yaml_parser_t *parser, int directive,
         yaml_char_t *head, yaml_mark_t start_mark, yaml_char_t **uri)
 {
     size_t length = head ? strlen((char *)head) : 0;
-    yaml_string_t string = yaml_parser_new_string(parser);
+    yaml_string_t string = NULL_STRING;
 
-    if (!string.buffer) goto error;
+    if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
 
     /* Resize the string to include the head. */
 
-    while (string.size <= length) {
-        if (!yaml_parser_resize_string(parser, &string)) goto error;
+    while (string.end - string.start <= length) {
+        if (!yaml_string_extend(&string.start, &string.pointer, &string.end)) {
+            parser->error = YAML_MEMORY_ERROR;
+            goto error;
+        }
     }
 
-    /* Copy the head if needed. */
+    /*
+     * Copy the head if needed.
+     *
+     * Note that we don't copy the leading '!' character.
+     */
 
-    if (length) {
-        memcpy(string.buffer, head, length);
-        string.pointer += length;
+    if (length > 1) {
+        memcpy(string.start, head+1, length-1);
+        string.pointer += length-1;
     }
 
     /* Scan the tag. */
 
-    if (!UPDATE(parser, 1)) goto error;
+    if (!CACHE(parser, 1)) goto error;
 
     /*
      * The set of characters that may appear in URI is as follows:
@@ -3134,8 +2784,6 @@ yaml_parser_scan_tag_uri(yaml_parser_t *parser, int directive,
             CHECK(parser, '\'') || CHECK(parser, '(') || CHECK(parser, ')') ||
             CHECK(parser, '[') || CHECK(parser, ']') || CHECK(parser, '%'))
     {
-        if (!RESIZE(parser, string)) goto error;
-
         /* Check if it is a URI-escape sequence. */
 
         if (CHECK(parser, '%')) {
@@ -3143,28 +2791,31 @@ yaml_parser_scan_tag_uri(yaml_parser_t *parser, int directive,
                         directive, start_mark, &string)) goto error;
         }
         else {
-            COPY(parser, string);
+            if (!READ(parser, string)) goto error;
         }
 
         length ++;
-        if (!UPDATE(parser, 1)) goto error;
+        if (!CACHE(parser, 1)) goto error;
     }
 
     /* Check if the tag is non-empty. */
 
     if (!length) {
+        if (!STRING_EXTEND(parser, string))
+            goto error;
+
         yaml_parser_set_scanner_error(parser, directive ?
                 "while parsing a %TAG directive" : "while parsing a tag",
                 start_mark, "did not find expected tag URI");
         goto error;
     }
 
-    *uri = string.buffer;
+    *uri = string.start;
 
     return 1;
 
 error:
-    yaml_free(string.buffer);
+    STRING_DEL(parser, string);
     return 0;
 }
 
@@ -3186,7 +2837,7 @@ yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive,
 
         /* Check for a URI-escaped octet. */
 
-        if (!UPDATE(parser, 3)) return 0;
+        if (!CACHE(parser, 3)) return 0;
 
         if (!(CHECK(parser, '%') && IS_HEX_AT(parser, 1) && IS_HEX_AT(parser, 2))) {
             return yaml_parser_set_scanner_error(parser, directive ?
@@ -3226,9 +2877,9 @@ yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive,
         /* Copy the octet and move the pointers. */
 
         *(string->pointer++) = octet;
-        FORWARD(parser);
-        FORWARD(parser);
-        FORWARD(parser);
+        SKIP(parser);
+        SKIP(parser);
+        SKIP(parser);
 
     } while (--width);
 
@@ -3239,34 +2890,34 @@ yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive,
  * Scan a block scalar.
  */
 
-static yaml_token_t *
-yaml_parser_scan_block_scalar(yaml_parser_t *parser, int literal)
+static int
+yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token,
+        int literal)
 {
     yaml_mark_t start_mark;
     yaml_mark_t end_mark;
-    yaml_string_t string = yaml_parser_new_string(parser);
-    yaml_string_t leading_break = yaml_parser_new_string(parser);
-    yaml_string_t trailing_breaks = yaml_parser_new_string(parser);
-    yaml_token_t *token = NULL;
+    yaml_string_t string = NULL_STRING;
+    yaml_string_t leading_break = NULL_STRING;
+    yaml_string_t trailing_breaks = NULL_STRING;
     int chomping = 0;
     int increment = 0;
     int indent = 0;
     int leading_blank = 0;
     int trailing_blank = 0;
 
-    if (!string.buffer) goto error;
-    if (!leading_break.buffer) goto error;
-    if (!trailing_breaks.buffer) goto error;
+    if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
+    if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error;
+    if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error;
 
     /* Eat the indicator '|' or '>'. */
 
-    start_mark = yaml_parser_get_mark(parser);
+    start_mark = parser->mark;
 
-    FORWARD(parser);
+    SKIP(parser);
 
     /* Scan the additional block scalar indicators. */
 
-    if (!UPDATE(parser, 1)) goto error;
+    if (!CACHE(parser, 1)) goto error;
 
     /* Check for a chomping indicator. */
 
@@ -3276,11 +2927,11 @@ yaml_parser_scan_block_scalar(yaml_parser_t *parser, int literal)
 
         chomping = CHECK(parser, '+') ? +1 : -1;
 
-        FORWARD(parser);
+        SKIP(parser);
 
         /* Check for an indentation indicator. */
 
-        if (!UPDATE(parser, 1)) goto error;
+        if (!CACHE(parser, 1)) goto error;
 
         if (IS_DIGIT(parser))
         {
@@ -3296,7 +2947,7 @@ yaml_parser_scan_block_scalar(yaml_parser_t *parser, int literal)
 
             increment = AS_DIGIT(parser);
 
-            FORWARD(parser);
+            SKIP(parser);
         }
     }
 
@@ -3312,29 +2963,30 @@ yaml_parser_scan_block_scalar(yaml_parser_t *parser, int literal)
 
         increment = AS_DIGIT(parser);
 
-        FORWARD(parser);
+        SKIP(parser);
 
-        if (!UPDATE(parser, 1)) goto error;
+        if (!CACHE(parser, 1)) goto error;
 
         if (CHECK(parser, '+') || CHECK(parser, '-')) {
             chomping = CHECK(parser, '+') ? +1 : -1;
-            FORWARD(parser);
+
+            SKIP(parser);
         }
     }
 
     /* Eat whitespaces and comments to the end of the line. */
 
-    if (!UPDATE(parser, 1)) goto error;
+    if (!CACHE(parser, 1)) goto error;
 
     while (IS_BLANK(parser)) {
-        FORWARD(parser);
-        if (!UPDATE(parser, 1)) goto error;
+        SKIP(parser);
+        if (!CACHE(parser, 1)) goto error;
     }
 
     if (CHECK(parser, '#')) {
         while (!IS_BREAKZ(parser)) {
-            FORWARD(parser);
-            if (!UPDATE(parser, 1)) goto error;
+            SKIP(parser);
+            if (!CACHE(parser, 1)) goto error;
         }
     }
 
@@ -3349,11 +3001,11 @@ yaml_parser_scan_block_scalar(yaml_parser_t *parser, int literal)
     /* Eat a line break. */
 
     if (IS_BREAK(parser)) {
-        if (!UPDATE(parser, 2)) goto error;
-        FORWARD_LINE(parser);
+        if (!CACHE(parser, 2)) goto error;
+        SKIP_LINE(parser);
     }
 
-    end_mark = yaml_parser_get_mark(parser);
+    end_mark = parser->mark;
 
     /* Set the intendation level if it was specified. */
 
@@ -3368,9 +3020,9 @@ yaml_parser_scan_block_scalar(yaml_parser_t *parser, int literal)
 
     /* Scan the block scalar content. */
 
-    if (!UPDATE(parser, 1)) goto error;
+    if (!CACHE(parser, 1)) goto error;
 
-    while (parser->column == indent && !IS_Z(parser))
+    while (parser->mark.column == indent && !IS_Z(parser))
     {
         /*
          * We are at the beginning of a non-empty line.
@@ -3382,25 +3034,27 @@ yaml_parser_scan_block_scalar(yaml_parser_t *parser, int literal)
 
         /* Check if we need to fold the leading line break. */
 
-        if (!literal && (*leading_break.buffer == '\n')
+        if (!literal && (*leading_break.start == '\n')
                 && !leading_blank && !trailing_blank)
         {
             /* Do we need to join the lines by space? */
 
-            if (*trailing_breaks.buffer == '\0') {
-                if (!RESIZE(parser, string)) goto error;
+            if (*trailing_breaks.start == '\0') {
+                if (!STRING_EXTEND(parser, string)) goto error;
                 *(string.pointer ++) = ' ';
             }
 
-            yaml_parser_clear_string(parser, &leading_break);
+            CLEAR(parser, leading_break);
         }
         else {
             if (!JOIN(parser, string, leading_break)) goto error;
+            CLEAR(parser, leading_break);
         }
 
         /* Append the remaining line breaks. */
 
         if (!JOIN(parser, string, trailing_breaks)) goto error;
+        CLEAR(parser, trailing_breaks);
 
         /* Is it a leading whitespace? */
 
@@ -3409,16 +3063,15 @@ yaml_parser_scan_block_scalar(yaml_parser_t *parser, int literal)
         /* Consume the current line. */
 
         while (!IS_BREAKZ(parser)) {
-            if (!RESIZE(parser, string)) goto error;
-            COPY(parser, string);
-            if (!UPDATE(parser, 1)) goto error;
+            if (!READ(parser, string)) goto error;
+            if (!CACHE(parser, 1)) goto error;
         }
 
         /* Consume the line break. */
 
-        if (!UPDATE(parser, 2)) goto error;
+        if (!CACHE(parser, 2)) goto error;
 
-        COPY_LINE(parser, leading_break);
+        if (!READ_LINE(parser, leading_break)) goto error;
 
         /* Eat the following intendation spaces and line breaks. */
 
@@ -3437,25 +3090,21 @@ yaml_parser_scan_block_scalar(yaml_parser_t *parser, int literal)
 
     /* Create a token. */
 
-    token = yaml_scalar_token_new(string.buffer, string.pointer-string.buffer,
+    SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start,
             literal ? YAML_LITERAL_SCALAR_STYLE : YAML_FOLDED_SCALAR_STYLE,
             start_mark, end_mark);
-    if (!token) {
-        parser->error = YAML_MEMORY_ERROR;
-        return 0;
-    }
 
-    yaml_free(leading_break.buffer);
-    yaml_free(trailing_breaks.buffer);
+    STRING_DEL(parser, leading_break);
+    STRING_DEL(parser, trailing_breaks);
 
-    return token;
+    return 1;
 
 error:
-    yaml_free(string.buffer);
-    yaml_free(leading_break.buffer);
-    yaml_free(trailing_breaks.buffer);
+    STRING_DEL(parser, string);
+    STRING_DEL(parser, leading_break);
+    STRING_DEL(parser, trailing_breaks);
 
-    return NULL;
+    return 0;
 }
 
 /*
@@ -3470,7 +3119,7 @@ yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser,
 {
     int max_indent = 0;
 
-    *end_mark = yaml_parser_get_mark(parser);
+    *end_mark = parser->mark;
 
     /* Eat the intendation spaces and line breaks. */
 
@@ -3478,19 +3127,19 @@ yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser,
     {
         /* Eat the intendation spaces. */
 
-        if (!UPDATE(parser, 1)) return 0;
+        if (!CACHE(parser, 1)) return 0;
 
-        while ((!*indent || parser->column < *indent) && IS_SPACE(parser)) {
-            FORWARD(parser);
-            if (!UPDATE(parser, 1)) return 0;
+        while ((!*indent || parser->mark.column < *indent) && IS_SPACE(parser)) {
+            SKIP(parser);
+            if (!CACHE(parser, 1)) return 0;
         }
 
-        if (parser->column > max_indent)
-            max_indent = parser->column;
+        if (parser->mark.column > max_indent)
+            max_indent = parser->mark.column;
 
         /* Check for a tab character messing the intendation. */
 
-        if ((!*indent || parser->column < *indent) && IS_TAB(parser)) {
+        if ((!*indent || parser->mark.column < *indent) && IS_TAB(parser)) {
             return yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
                     start_mark, "found a tab character where an intendation space is expected");
         }
@@ -3501,10 +3150,9 @@ yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser,
 
         /* Consume the line break. */
 
-        if (!UPDATE(parser, 2)) return 0;
-        if (!RESIZE(parser, *breaks)) return 0;
-        COPY_LINE(parser, *breaks);
-        *end_mark = yaml_parser_get_mark(parser);
+        if (!CACHE(parser, 2)) return 0;
+        if (!READ_LINE(parser, *breaks)) return 0;
+        *end_mark = parser->mark;
     }
 
     /* Determine the indentation level if needed. */
@@ -3524,28 +3172,28 @@ yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser,
  * Scan a quoted scalar.
  */
 
-static yaml_token_t *
-yaml_parser_scan_flow_scalar(yaml_parser_t *parser, int single)
+static int
+yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token,
+        int single)
 {
     yaml_mark_t start_mark;
     yaml_mark_t end_mark;
-    yaml_string_t string = yaml_parser_new_string(parser);
-    yaml_string_t leading_break = yaml_parser_new_string(parser);
-    yaml_string_t trailing_breaks = yaml_parser_new_string(parser);
-    yaml_string_t whitespaces = yaml_parser_new_string(parser);
-    yaml_token_t *token = NULL;
+    yaml_string_t string = NULL_STRING;
+    yaml_string_t leading_break = NULL_STRING;
+    yaml_string_t trailing_breaks = NULL_STRING;
+    yaml_string_t whitespaces = NULL_STRING;
     int leading_blanks;
 
-    if (!string.buffer) goto error;
-    if (!leading_break.buffer) goto error;
-    if (!trailing_breaks.buffer) goto error;
-    if (!whitespaces.buffer) goto error;
+    if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
+    if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error;
+    if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error;
+    if (!STRING_INIT(parser, whitespaces, INITIAL_STRING_SIZE)) goto error;
 
     /* Eat the left quote. */
 
-    start_mark = yaml_parser_get_mark(parser);
+    start_mark = parser->mark;
 
-    FORWARD(parser);
+    SKIP(parser);
 
     /* Consume the content of the quoted scalar. */
 
@@ -3553,9 +3201,9 @@ yaml_parser_scan_flow_scalar(yaml_parser_t *parser, int single)
     {
         /* Check that there are no document indicators at the beginning of the line. */
 
-        if (!UPDATE(parser, 4)) goto error;
+        if (!CACHE(parser, 4)) goto error;
 
-        if (parser->column == 0 &&
+        if (parser->mark.column == 0 &&
             ((CHECK_AT(parser, '-', 0) &&
               CHECK_AT(parser, '-', 1) &&
               CHECK_AT(parser, '-', 2)) ||
@@ -3579,8 +3227,7 @@ yaml_parser_scan_flow_scalar(yaml_parser_t *parser, int single)
 
         /* Consume non-blank characters. */
 
-        if (!UPDATE(parser, 2)) goto error;
-        if (!RESIZE(parser, string)) goto error;
+        if (!CACHE(parser, 2)) goto error;
 
         leading_blanks = 0;
 
@@ -3590,9 +3237,10 @@ yaml_parser_scan_flow_scalar(yaml_parser_t *parser, int single)
 
             if (single && CHECK_AT(parser, '\'', 0) && CHECK_AT(parser, '\'', 1))
             {
+                if (!STRING_EXTEND(parser, string)) goto error;
                 *(string.pointer++) = '\'';
-                FORWARD(parser);
-                FORWARD(parser);
+                SKIP(parser);
+                SKIP(parser);
             }
 
             /* Check for the right quote. */
@@ -3606,9 +3254,9 @@ yaml_parser_scan_flow_scalar(yaml_parser_t *parser, int single)
 
             else if (!single && CHECK(parser, '\\') && IS_BREAK_AT(parser, 1))
             {
-                if (!UPDATE(parser, 3)) goto error;
-                FORWARD(parser);
-                FORWARD_LINE(parser);
+                if (!CACHE(parser, 3)) goto error;
+                SKIP(parser);
+                SKIP_LINE(parser);
                 leading_blanks = 1;
                 break;
             }
@@ -3619,9 +3267,11 @@ yaml_parser_scan_flow_scalar(yaml_parser_t *parser, int single)
             {
                 int code_length = 0;
 
+                if (!STRING_EXTEND(parser, string)) goto error;
+
                 /* Check the escape character. */
 
-                switch (parser->pointer[1])
+                switch (parser->buffer.pointer[1])
                 {
                     case '0':
                         *(string.pointer++) = '\0';
@@ -3672,6 +3322,10 @@ yaml_parser_scan_flow_scalar(yaml_parser_t *parser, int single)
                         *(string.pointer++) = '\'';
                         break;
 
+                    case '\\':
+                        *(string.pointer++) = '\\';
+                        break;
+
                     case 'N':   /* NEL (#x85) */
                         *(string.pointer++) = '\xC2';
                         *(string.pointer++) = '\x85';
@@ -3691,7 +3345,7 @@ yaml_parser_scan_flow_scalar(yaml_parser_t *parser, int single)
                     case 'P':   /* PS (#x2029) */
                         *(string.pointer++) = '\xE2';
                         *(string.pointer++) = '\x80';
-                        *(string.pointer++) = '\xA8';
+                        *(string.pointer++) = '\xA9';
                         break;
 
                     case 'x':
@@ -3712,8 +3366,8 @@ yaml_parser_scan_flow_scalar(yaml_parser_t *parser, int single)
                         goto error;
                 }
 
-                FORWARD(parser);
-                FORWARD(parser);
+                SKIP(parser);
+                SKIP(parser);
 
                 /* Consume an arbitrary escape code. */
 
@@ -3724,7 +3378,7 @@ yaml_parser_scan_flow_scalar(yaml_parser_t *parser, int single)
 
                     /* Scan the character value. */
 
-                    if (!UPDATE(parser, code_length)) goto error;
+                    if (!CACHE(parser, code_length)) goto error;
 
                     for (k = 0; k < code_length; k ++) {
                         if (!IS_HEX_AT(parser, k)) {
@@ -3765,7 +3419,7 @@ yaml_parser_scan_flow_scalar(yaml_parser_t *parser, int single)
                     /* Advance the pointer. */
 
                     for (k = 0; k < code_length; k ++) {
-                        FORWARD(parser);
+                        SKIP(parser);
                     }
                 }
             }
@@ -3774,11 +3428,10 @@ yaml_parser_scan_flow_scalar(yaml_parser_t *parser, int single)
             {
                 /* It is a non-escaped non-blank character. */
 
-                COPY(parser, string);
+                if (!READ(parser, string)) goto error;
             }
 
-            if (!UPDATE(parser, 2)) goto error;
-            if (!RESIZE(parser, string)) goto error;
+            if (!CACHE(parser, 2)) goto error;
         }
 
         /* Check if we are at the end of the scalar. */
@@ -3788,7 +3441,7 @@ yaml_parser_scan_flow_scalar(yaml_parser_t *parser, int single)
 
         /* Consume blank characters. */
 
-        if (!UPDATE(parser, 1)) goto error;
+        if (!CACHE(parser, 1)) goto error;
 
         while (IS_BLANK(parser) || IS_BREAK(parser))
         {
@@ -3797,113 +3450,112 @@ yaml_parser_scan_flow_scalar(yaml_parser_t *parser, int single)
                 /* Consume a space or a tab character. */
 
                 if (!leading_blanks) {
-                    if (!RESIZE(parser, whitespaces)) goto error;
-                    COPY(parser, whitespaces);
+                    if (!READ(parser, whitespaces)) goto error;
+                }
+                else {
+                    SKIP(parser);
                 }
             }
             else
             {
-                if (!UPDATE(parser, 2)) goto error;
+                if (!CACHE(parser, 2)) goto error;
 
                 /* Check if it is a first line break. */
 
                 if (!leading_blanks)
                 {
-                    yaml_parser_clear_string(parser, &whitespaces);
-                    COPY_LINE(parser, leading_break);
+                    CLEAR(parser, whitespaces);
+                    if (!READ_LINE(parser, leading_break)) goto error;
                     leading_blanks = 1;
                 }
                 else
                 {
-                    if (!RESIZE(parser, trailing_breaks)) goto error;
-                    COPY_LINE(parser, trailing_breaks);
+                    if (!READ_LINE(parser, trailing_breaks)) goto error;
                 }
             }
-            if (!UPDATE(parser, 1)) goto error;
+            if (!CACHE(parser, 1)) goto error;
         }
 
         /* Join the whitespaces or fold line breaks. */
 
-        if (!RESIZE(parser, string)) goto error;
-
         if (leading_blanks)
         {
             /* Do we need to fold line breaks? */
 
-            if (leading_break.buffer[0] == '\n') {
-                if (trailing_breaks.buffer[0] == '\0') {
+            if (leading_break.start[0] == '\n') {
+                if (trailing_breaks.start[0] == '\0') {
+                    if (!STRING_EXTEND(parser, string)) goto error;
                     *(string.pointer++) = ' ';
                 }
                 else {
                     if (!JOIN(parser, string, trailing_breaks)) goto error;
+                    CLEAR(parser, trailing_breaks);
                 }
-                yaml_parser_clear_string(parser, &leading_break);
+                CLEAR(parser, leading_break);
             }
             else {
                 if (!JOIN(parser, string, leading_break)) goto error;
                 if (!JOIN(parser, string, trailing_breaks)) goto error;
+                CLEAR(parser, leading_break);
+                CLEAR(parser, trailing_breaks);
             }
         }
         else
         {
             if (!JOIN(parser, string, whitespaces)) goto error;
+            CLEAR(parser, whitespaces);
         }
     }
 
     /* Eat the right quote. */
 
-    FORWARD(parser);
+    SKIP(parser);
 
-    end_mark = yaml_parser_get_mark(parser);
+    end_mark = parser->mark;
 
     /* Create a token. */
 
-    token = yaml_scalar_token_new(string.buffer, string.pointer-string.buffer,
+    SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start,
             single ? YAML_SINGLE_QUOTED_SCALAR_STYLE : YAML_DOUBLE_QUOTED_SCALAR_STYLE,
             start_mark, end_mark);
-    if (!token) {
-        parser->error = YAML_MEMORY_ERROR;
-        return 0;
-    }
 
-    yaml_free(leading_break.buffer);
-    yaml_free(trailing_breaks.buffer);
-    yaml_free(whitespaces.buffer);
+    STRING_DEL(parser, leading_break);
+    STRING_DEL(parser, trailing_breaks);
+    STRING_DEL(parser, whitespaces);
 
-    return token;
+    return 1;
 
 error:
-    yaml_free(string.buffer);
-    yaml_free(leading_break.buffer);
-    yaml_free(trailing_breaks.buffer);
-    yaml_free(whitespaces.buffer);
+    STRING_DEL(parser, string);
+    STRING_DEL(parser, leading_break);
+    STRING_DEL(parser, trailing_breaks);
+    STRING_DEL(parser, whitespaces);
 
-    return NULL;
+    return 0;
 }
 
 /*
  * Scan a plain scalar.
  */
 
-static yaml_token_t *
-yaml_parser_scan_plain_scalar(yaml_parser_t *parser)
+static int
+yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token)
 {
     yaml_mark_t start_mark;
     yaml_mark_t end_mark;
-    yaml_string_t string = yaml_parser_new_string(parser);
-    yaml_string_t leading_break = yaml_parser_new_string(parser);
-    yaml_string_t trailing_breaks = yaml_parser_new_string(parser);
-    yaml_string_t whitespaces = yaml_parser_new_string(parser);
-    yaml_token_t *token = NULL;
+    yaml_string_t string = NULL_STRING;
+    yaml_string_t leading_break = NULL_STRING;
+    yaml_string_t trailing_breaks = NULL_STRING;
+    yaml_string_t whitespaces = NULL_STRING;
     int leading_blanks = 0;
     int indent = parser->indent+1;
 
-    if (!string.buffer) goto error;
-    if (!leading_break.buffer) goto error;
-    if (!trailing_breaks.buffer) goto error;
-    if (!whitespaces.buffer) goto error;
+    if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
+    if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error;
+    if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error;
+    if (!STRING_INIT(parser, whitespaces, INITIAL_STRING_SIZE)) goto error;
 
-    start_mark = yaml_parser_get_mark(parser);
+    start_mark = end_mark = parser->mark;
 
     /* Consume the content of the plain scalar. */
 
@@ -3911,9 +3563,9 @@ yaml_parser_scan_plain_scalar(yaml_parser_t *parser)
     {
         /* Check for a document indicator. */
 
-        if (!UPDATE(parser, 4)) goto error;
+        if (!CACHE(parser, 4)) goto error;
 
-        if (parser->column == 0 &&
+        if (parser->mark.column == 0 &&
             ((CHECK_AT(parser, '-', 0) &&
               CHECK_AT(parser, '-', 1) &&
               CHECK_AT(parser, '-', 2)) ||
@@ -3931,7 +3583,7 @@ yaml_parser_scan_plain_scalar(yaml_parser_t *parser)
 
         while (!IS_BLANKZ(parser))
         {
-            /* Check for 'x:x' in the flow context. */
+            /* Check for 'x:x' in the flow context. TODO: Fix the test "spec-08-13". */
 
             if (parser->flow_level && CHECK(parser, ':') && !IS_BLANKZ_AT(parser, 1)) {
                 yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
@@ -3951,26 +3603,28 @@ yaml_parser_scan_plain_scalar(yaml_parser_t *parser)
 
             /* Check if we need to join whitespaces and breaks. */
 
-            if (leading_blanks || whitespaces.buffer != whitespaces.pointer)
+            if (leading_blanks || whitespaces.start != whitespaces.pointer)
             {
-                if (!RESIZE(parser, string)) goto error;
-
                 if (leading_blanks)
                 {
                     /* Do we need to fold line breaks? */
 
-                    if (leading_break.buffer[0] == '\n') {
-                        if (trailing_breaks.buffer[0] == '\0') {
+                    if (leading_break.start[0] == '\n') {
+                        if (trailing_breaks.start[0] == '\0') {
+                            if (!STRING_EXTEND(parser, string)) goto error;
                             *(string.pointer++) = ' ';
                         }
                         else {
                             if (!JOIN(parser, string, trailing_breaks)) goto error;
+                            CLEAR(parser, trailing_breaks);
                         }
-                        yaml_parser_clear_string(parser, &leading_break);
+                        CLEAR(parser, leading_break);
                     }
                     else {
                         if (!JOIN(parser, string, leading_break)) goto error;
                         if (!JOIN(parser, string, trailing_breaks)) goto error;
+                        CLEAR(parser, leading_break);
+                        CLEAR(parser, trailing_breaks);
                     }
 
                     leading_blanks = 0;
@@ -3978,18 +3632,17 @@ yaml_parser_scan_plain_scalar(yaml_parser_t *parser)
                 else
                 {
                     if (!JOIN(parser, string, whitespaces)) goto error;
+                    CLEAR(parser, whitespaces);
                 }
             }
 
             /* Copy the character. */
 
-            if (!RESIZE(parser, string)) goto error;
-
-            COPY(parser, string);
+            if (!READ(parser, string)) goto error;
 
-            end_mark = yaml_parser_get_mark(parser);
+            end_mark = parser->mark;
 
-            if (!UPDATE(parser, 2)) goto error;
+            if (!CACHE(parser, 2)) goto error;
         }
 
         /* Is it the end? */
@@ -3999,7 +3652,7 @@ yaml_parser_scan_plain_scalar(yaml_parser_t *parser)
 
         /* Consume blank characters. */
 
-        if (!UPDATE(parser, 1)) goto error;
+        if (!CACHE(parser, 1)) goto error;
 
         while (IS_BLANK(parser) || IS_BREAK(parser))
         {
@@ -4007,54 +3660,51 @@ yaml_parser_scan_plain_scalar(yaml_parser_t *parser)
             {
                 /* Check for tab character that abuse intendation. */
 
-                if (leading_blanks && parser->column < indent && IS_TAB(parser)) {
+                if (leading_blanks && parser->mark.column < indent && IS_TAB(parser)) {
                     yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
                             start_mark, "found a tab character that violate intendation");
-                    break;
+                    goto error;
                 }
 
                 /* Consume a space or a tab character. */
 
                 if (!leading_blanks) {
-                    if (!RESIZE(parser, whitespaces)) goto error;
-                    COPY(parser, whitespaces);
+                    if (!READ(parser, whitespaces)) goto error;
+                }
+                else {
+                    SKIP(parser);
                 }
             }
             else
             {
-                if (!UPDATE(parser, 2)) goto error;
+                if (!CACHE(parser, 2)) goto error;
 
                 /* Check if it is a first line break. */
 
                 if (!leading_blanks)
                 {
-                    yaml_parser_clear_string(parser, &whitespaces);
-                    COPY_LINE(parser, leading_break);
+                    CLEAR(parser, whitespaces);
+                    if (!READ_LINE(parser, leading_break)) goto error;
                     leading_blanks = 1;
                 }
                 else
                 {
-                    if (!RESIZE(parser, trailing_breaks)) goto error;
-                    COPY_LINE(parser, trailing_breaks);
+                    if (!READ_LINE(parser, trailing_breaks)) goto error;
                 }
             }
-            if (!UPDATE(parser, 1)) goto error;
+            if (!CACHE(parser, 1)) goto error;
         }
 
         /* Check intendation level. */
 
-        if (parser->column < indent)
+        if (!parser->flow_level && parser->mark.column < indent)
             break;
     }
 
     /* Create a token. */
 
-    token = yaml_scalar_token_new(string.buffer, string.pointer-string.buffer,
+    SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start,
             YAML_PLAIN_SCALAR_STYLE, start_mark, end_mark);
-    if (!token) {
-        parser->error = YAML_MEMORY_ERROR;
-        return 0;
-    }
 
     /* Note that we change the 'simple_key_allowed' flag. */
 
@@ -4062,18 +3712,18 @@ yaml_parser_scan_plain_scalar(yaml_parser_t *parser)
         parser->simple_key_allowed = 1;
     }
 
-    yaml_free(leading_break.buffer);
-    yaml_free(trailing_breaks.buffer);
-    yaml_free(whitespaces.buffer);
+    STRING_DEL(parser, leading_break);
+    STRING_DEL(parser, trailing_breaks);
+    STRING_DEL(parser, whitespaces);
 
-    return token;
+    return 1;
 
 error:
-    yaml_free(string.buffer);
-    yaml_free(leading_break.buffer);
-    yaml_free(trailing_breaks.buffer);
-    yaml_free(whitespaces.buffer);
+    STRING_DEL(parser, string);
+    STRING_DEL(parser, leading_break);
+    STRING_DEL(parser, trailing_breaks);
+    STRING_DEL(parser, whitespaces);
 
-    return NULL;
+    return 0;
 }
 
This page took 0.193152 seconds and 4 git commands to generate.