summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxi <xi@18f92427-320e-0410-9341-c67f048884a3>2006-07-04 19:39:56 +0000
committerxi <xi@18f92427-320e-0410-9341-c67f048884a3>2006-07-04 19:39:56 +0000
commit8b81b5f5a9f5a6be43a7a4ddaa75438960ac8b10 (patch)
treeadc2933c9bf226249db99176f82c668a9047ed14
parentb1c94e4d6ddea05c2bce31ae9607072824613944 (diff)
downloadlibyaml-8b81b5f5a9f5a6be43a7a4ddaa75438960ac8b10.tar.gz
Start working on the parser.
git-svn-id: http://svn.pyyaml.org/libyaml/trunk@201 18f92427-320e-0410-9341-c67f048884a3
-rw-r--r--include/yaml.h103
-rw-r--r--src/Makefile.am2
-rw-r--r--src/api.c24
-rw-r--r--src/parser.c237
4 files changed, 365 insertions, 1 deletions
diff --git a/include/yaml.h b/include/yaml.h
index 7ca4a9b..0a2bab0 100644
--- a/include/yaml.h
+++ b/include/yaml.h
@@ -790,6 +790,36 @@ typedef struct {
} yaml_simple_key_t;
/**
+ * The states of the parser.
+ */
+typedef enum {
+ YAML_PARSE_END_STATE,
+ YAML_PARSE_STREAM_START_STATE,
+ YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE,
+ YAML_PARSE_DOCUMENT_START_STATE,
+ YAML_PARSE_DOCUMENT_CONTENT_STATE,
+ YAML_PARSE_DOCUMENT_END_STATE,
+ YAML_PARSE_BLOCK_NODE_STATE,
+ YAML_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE,
+ YAML_PARSE_FLOW_NODE_STATE,
+ YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE,
+ YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE,
+ YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE,
+ YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE,
+ YAML_PARSE_BLOCK_MAPPING_KEY_STATE,
+ YAML_PARSE_BLOCK_MAPPING_VALUE_STATE,
+ YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE,
+ YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE,
+ YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE,
+ YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE,
+ YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE,
+ YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE,
+ YAML_PARSE_FLOW_MAPPING_KEY_STATE,
+ YAML_PARSE_FLOW_MAPPING_VALUE_STATE,
+ YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE
+} yaml_parser_state_t;
+
+/**
* The parser structure.
*
* All members are internal. Manage the structure using the @c yaml_parser_
@@ -939,6 +969,51 @@ typedef struct {
* @}
*/
+ /**
+ * @name Parser stuff
+ * @{
+ */
+
+ /** The parser states stack. */
+ yaml_parser_state_t *states;
+
+ /** The size of the parser states stack. */
+ size_t states_size;
+
+ /** The number of items in the parser states stack. */
+ size_t states_length;
+
+ /** The current parser state. */
+ yaml_parser_state_t state;
+
+ /** The stack of marks. */
+ yaml_mark_t *marks;
+
+ /** The size of the marks stack. */
+ size_t marks_size;
+
+ /** The number of items in the marks stack. */
+ size_t marks_length;
+
+ /** The current event. */
+ yaml_event_t *current_event;
+
+ /** The YAML version directive. */
+ yaml_version_directive_t *version_directive;
+
+ /** The list of TAG directives. */
+ yaml_tag_directive_t **tag_directives;
+
+ /** The size of the TAG directives list. */
+ size_t tag_directives_size;
+
+ /** The number of items in the TAG directives list. */
+ size_t tag_directives_length;
+
+ /**
+ * @}
+ */
+
} yaml_parser_t;
/**
@@ -1044,6 +1119,34 @@ yaml_parser_get_token(yaml_parser_t *parser);
YAML_DECLARE(yaml_token_t *)
yaml_parser_peek_token(yaml_parser_t *parser);
+/**
+ * Get the next event.
+ *
+ * The application is responsible for destroing the event object.
+ *
+ * @param[in] parser A parser object.
+ *
+ * @returns An event object, or @c NULL on error.
+ */
+
+YAML_DECLARE(yaml_event_t *)
+yaml_parser_get_event(yaml_parser_t *parser);
+
+/**
+ * Peek the next event.
+ *
+ * The event will be returned again on a subsequent call of
+ * @c yaml_parser_get_event or @c yaml_parser_peek_event. The application
+ * should not destroy the event object.
+ *
+ * @param[in] parser A parser object.
+ *
+ * @returns An event object, or @c NULL on error.
+ */
+
+YAML_DECLARE(yaml_event_t *)
+yaml_parser_peek_event(yaml_parser_t *parser);
+
/** @} */
/*
diff --git a/src/Makefile.am b/src/Makefile.am
index c8797dc..c7f6da2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,4 +1,4 @@
AM_CPPFLAGS = -I$(top_srcdir)/include
lib_LTLIBRARIES = libyaml.la
-libyaml_la_SOURCES = api.c reader.c scanner.c
+libyaml_la_SOURCES = api.c reader.c scanner.c parser.c
libyaml_la_LDFLAGS = -release $(YAML_LT_RELEASE) -version-info $(YAML_LT_CURRENT):$(YAML_LT_REVISION):$(YAML_LT_AGE)
diff --git a/src/api.c b/src/api.c
index 3047753..51a1b31 100644
--- a/src/api.c
+++ b/src/api.c
@@ -114,6 +114,26 @@ yaml_parser_new(void)
parser->simple_keys_size = YAML_DEFAULT_SIZE;
+ /* Allocate the stack of parser states. */
+
+ parser->states = yaml_malloc(YAML_DEFAULT_SIZE*sizeof(yaml_parser_state_t));
+ if (!parser->states) goto error;
+ memset(parser->states, 0, YAML_DEFAULT_SIZE*sizeof(yaml_parser_state_t));
+
+ parser->states_size = YAML_DEFAULT_SIZE;
+
+ /* Set the initial state. */
+
+ parser->state = YAML_PARSE_STREAM_START_STATE;
+
+ /* Allocate the list of TAG directives. */
+
+ parser->tag_directives = yaml_malloc(YAML_DEFAULT_SIZE*sizeof(yaml_tag_directive_t *));
+ if (!parser->tag_directives) goto error;
+ memset(parser->tag_directives, 0, YAML_DEFAULT_SIZE*sizeof(yaml_tag_directive_t *));
+
+ parser->tag_directives_size = YAML_DEFAULT_SIZE;
+
/* Done. */
return parser;
@@ -124,6 +144,8 @@ error:
if (!parser) return NULL;
+ yaml_free(parser->tag_directives);
+ yaml_free(parser->states);
yaml_free(parser->simple_keys);
yaml_free(parser->indents);
yaml_free(parser->tokens);
@@ -144,6 +166,8 @@ yaml_parser_delete(yaml_parser_t *parser)
{
assert(parser); /* Non-NULL parser object expected. */
+ yaml_free(parser->tag_directives);
+ yaml_free(parser->states);
yaml_free(parser->simple_keys);
yaml_free(parser->indents);
yaml_free(parser->tokens);
diff --git a/src/parser.c b/src/parser.c
new file mode 100644
index 0000000..6928193
--- /dev/null
+++ b/src/parser.c
@@ -0,0 +1,237 @@
+
+/*
+ * The parser implements the following grammar:
+ *
+ * stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
+ * implicit_document ::= block_node DOCUMENT-END*
+ * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
+ * block_node_or_indentless_sequence ::=
+ * ALIAS
+ * | properties (block_content | indentless_block_sequence)?
+ * | block_content
+ * | indentless_block_sequence
+ * block_node ::= ALIAS
+ * | properties block_content?
+ * | block_content
+ * flow_node ::= ALIAS
+ * | properties flow_content?
+ * | flow_content
+ * properties ::= TAG ANCHOR? | ANCHOR TAG?
+ * block_content ::= block_collection | flow_collection | SCALAR
+ * flow_content ::= flow_collection | SCALAR
+ * block_collection ::= block_sequence | block_mapping
+ * flow_collection ::= flow_sequence | flow_mapping
+ * block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
+ * indentless_sequence ::= (BLOCK-ENTRY block_node?)+
+ * block_mapping ::= BLOCK-MAPPING_START
+ * ((KEY block_node_or_indentless_sequence?)?
+ * (VALUE block_node_or_indentless_sequence?)?)*
+ * BLOCK-END
+ * flow_sequence ::= FLOW-SEQUENCE-START
+ * (flow_sequence_entry FLOW-ENTRY)*
+ * flow_sequence_entry?
+ * FLOW-SEQUENCE-END
+ * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+ * flow_mapping ::= FLOW-MAPPING-START
+ * (flow_mapping_entry FLOW-ENTRY)*
+ * flow_mapping_entry?
+ * FLOW-MAPPING-END
+ * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <yaml.h>
+
+#include <assert.h>
+
+/*
+ * Public API declarations.
+ */
+
+YAML_DECLARE(yaml_event_t *)
+yaml_parser_get_event(yaml_parser_t *parser);
+
+YAML_DECLARE(yaml_event_t *)
+yaml_parser_peek_event(yaml_parser_t *parser);
+
+/*
+ * State functions.
+ */
+
+static yaml_event_t *
+yaml_parser_state_machine(yaml_parser_t *parser);
+
+static yaml_event_t *
+yaml_parser_parse_stream_start(yaml_parser_t *parser);
+
+static yaml_event_t *
+yaml_parser_parse_document_start(yaml_parser_t *parser, int implicit);
+
+static yaml_event_t *
+yaml_parser_parse_document_content(yaml_parser_t *parser);
+
+static yaml_event_t *
+yaml_parser_parse_document_end(yaml_parser_t *parser);
+
+static yaml_event_t *
+yaml_parser_parse_node(yaml_parser_t *parser,
+ int block, int indentless_sequence);
+
+static yaml_event_t *
+yaml_parser_parse_block_sequence_entry(yaml_parser_t *parser, int first);
+
+static yaml_event_t *
+yaml_parser_parse_indentless_sequence_entry(yaml_parser_t *parser);
+
+static yaml_event_t *
+yaml_parser_parse_block_mapping_key(yaml_parser_t *parser, int first);
+
+static yaml_event_t *
+yaml_parser_parse_block_mapping_value(yaml_parser_t *parser);
+
+static yaml_event_t *
+yaml_parser_parse_flow_sequence_entry(yaml_parser_t *parser, int first);
+
+static yaml_event_t *
+yaml_parser_parse_flow_sequence_entry_mapping_key(yaml_parser_t *parser);
+
+static yaml_event_t *
+yaml_parser_parse_flow_sequence_entry_mapping_value(yaml_parser_t *parser);
+
+static yaml_event_t *
+yaml_parser_parse_flow_sequence_entry_mapping_end(yaml_parser_t *parser);
+
+static yaml_event_t *
+yaml_parser_parse_flow_mapping_key(yaml_parser_t *parser, int first);
+
+static yaml_event_t *
+yaml_parser_parse_flow_mapping_value(yaml_parser_t *parser, int empty);
+
+/*
+ * Get the next event and advance the parser.
+ */
+
+YAML_DECLARE(yaml_event_t *)
+yaml_parser_get_event(yaml_parser_t *parser)
+{
+ yaml_event_t *value;
+
+ /* Update the current event if needed. */
+
+ if (!parser->current_event) {
+ parser->current_event = yaml_parser_state_machine(parser);
+ }
+
+ /* Return and clear the current event. */
+
+ value = parser->current_event;
+ parser->current_event = NULL;
+ return value;
+}
+
+/*
+ * Peek the next event.
+ */
+
+YAML_DECLARE(yaml_event_t *)
+yaml_parser_peek_event(yaml_parser_t *parser)
+{
+ yaml_event_t *value;
+
+ /* Update the current event if needed. */
+
+ if (!parser->current_event) {
+ parser->current_event = yaml_parser_state_machine(parser);
+ }
+
+ /* Return the current event. */
+
+ return parser->current_event;
+}
+
+/*
+ * State dispatcher.
+ */
+
+static yaml_event_t *
+yaml_parser_state_machine(yaml_parser_t *parser)
+{
+ assert (parser->state != YAML_PARSE_END_STATE);
+
+ switch (parser->state)
+ {
+ case YAML_PARSE_STREAM_START_STATE:
+ return yaml_parser_parse_stream_start(parser);
+
+ case YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE:
+ return yaml_parser_parse_document_start(parser, 1);
+
+ case YAML_PARSE_DOCUMENT_START_STATE:
+ return yaml_parser_parse_document_start(parser, 0);
+
+ case YAML_PARSE_DOCUMENT_CONTENT_STATE:
+ return yaml_parser_parse_document_content(parser);
+
+ case YAML_PARSE_DOCUMENT_END_STATE:
+ return yaml_parser_parse_document_end(parser);
+
+ case YAML_PARSE_BLOCK_NODE_STATE:
+ return yaml_parser_parse_node(parser, 1, 0);
+
+ case YAML_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE:
+ return yaml_parser_parse_node(parser, 1, 1);
+
+ case YAML_PARSE_FLOW_NODE_STATE:
+ return yaml_parser_parse_node(parser, 0, 0);
+
+ case YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE:
+ return yaml_parser_parse_block_sequence_entry(parser, 1);
+
+ case YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE:
+ return yaml_parser_parse_block_sequence_entry(parser, 0);
+
+ case YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE:
+ return yaml_parser_parse_indentless_sequence_entry(parser);
+
+ case YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE:
+ return yaml_parser_parse_block_mapping_key(parser, 1);
+
+ case YAML_PARSE_BLOCK_MAPPING_KEY_STATE:
+ return yaml_parser_parse_block_mapping_key(parser, 0);
+
+ case YAML_PARSE_BLOCK_MAPPING_VALUE_STATE:
+ return yaml_parser_parse_block_mapping_value(parser);
+
+ case YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE:
+ return yaml_parser_parse_flow_sequence_entry(parser, 1);
+
+ case YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE:
+ return yaml_parser_parse_flow_sequence_entry(parser, 0);
+
+ case YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE:
+ return yaml_parser_parse_flow_sequence_entry_mapping_key(parser);
+
+ case YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE:
+ return yaml_parser_parse_flow_sequence_entry_mapping_value(parser);
+
+ case YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE:
+ return yaml_parser_parse_flow_sequence_entry_mapping_end(parser);
+
+ case YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE:
+ return yaml_parser_parse_flow_mapping_key(parser, 1);
+
+ case YAML_PARSE_FLOW_MAPPING_KEY_STATE:
+ return yaml_parser_parse_flow_mapping_key(parser, 0);
+
+ case YAML_PARSE_FLOW_MAPPING_VALUE_STATE:
+ return yaml_parser_parse_flow_mapping_value(parser, 0);
+
+ case YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE:
+ return yaml_parser_parse_flow_mapping_value(parser, 1);
+ }
+ assert(1);
+}
+