From 8b81b5f5a9f5a6be43a7a4ddaa75438960ac8b10 Mon Sep 17 00:00:00 2001 From: xi Date: Tue, 4 Jul 2006 19:39:56 +0000 Subject: Start working on the parser. git-svn-id: http://svn.pyyaml.org/libyaml/trunk@201 18f92427-320e-0410-9341-c67f048884a3 --- include/yaml.h | 103 ++++++++++++++++++++++++ src/Makefile.am | 2 +- src/api.c | 24 ++++++ src/parser.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 365 insertions(+), 1 deletion(-) create mode 100644 src/parser.c diff --git a/include/yaml.h b/include/yaml.h index 7ca4a9b..0a2bab0 100644 --- a/include/yaml.h +++ b/include/yaml.h @@ -789,6 +789,36 @@ typedef struct { yaml_mark_t mark; } 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. * @@ -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 +#endif + +#include + +#include + +/* + * 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); +} + -- cgit v1.2.1