/* Copyright 2006 Garrett Rooney. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "etl_data.h" #include "lexer.h" #include "common.h" static void destroy_tok(void *tok, void *baton) { etl_ddl_token_destroy(tok); } static etl_error_t * ddl_parse(etl_hash_t **data, etl_resolver_t *resolver, etl_stream_t *in) { etl_array_t *tokens = etl_array_create(100); etl_hash_t *d = etl_hash_create(); etl_ddl_parser_state_t state; etl_ddl_parser_t *parser; etl_ddl_lexer_t *lexer; etl_error_t *err; etl_token_t *tok; lexer = etl_ddl_lexer_create(in); parser = etl_ddl_parser_alloc(malloc); state.vars = d; state.spare_entries = NULL; state.err = ETL_SUCCESS; state.resolver = resolver; #if 0 etl_ddl_parser_trace(stderr, "parser:"); #endif while ((err = etl_ddl_lexer_scan(&tok, lexer)) == ETL_SUCCESS) { etl_array_push(tokens, tok); if (tok->type != ETL_DDL_TOK_EOI) { etl_ddl_parser_parse(parser, tok->type, tok, &state); } else { etl_ddl_parser_parse(parser, 0, tok, &state); break; } } { etl_list_entry_t *itr = state.spare_entries; while (itr) { etl_list_entry_t *prev = itr; itr = itr->next; free(prev); } } etl_array_destroy(tokens, destroy_tok, NULL); etl_ddl_lexer_destroy(lexer); etl_ddl_parser_free(parser, free); /* XXX It seems likely that there are situations where our parser will * fail after having allocated memory but before having inserted a * variable into the data hash. We need to worry about this, but * for now we just take the easy way out and clean up the hash... */ if (err) { etl_error_clear(state.err); etl_ddl_destroy(d); return err; } if (state.err) { etl_ddl_destroy(d); return state.err; } *data = d; return ETL_SUCCESS; } etl_error_t * etl_ddl_parse(etl_hash_t **data, etl_resolver_t *resolver, etl_stream_t *in) { return ddl_parse(data, resolver, in); } etl_error_t * etl_ddl_parse_file(etl_hash_t **data, etl_resolver_t *resolver, const char *filename) { etl_stream_t *in; ETL_ERR(etl_stream_file_open(&in, filename, etl_stream_open_read)); return ddl_parse(data, resolver, in); } static void destroy_var(void *var, void *baton) { etl_variable_destroy(var); } void etl_ddl_destroy(etl_hash_t *hash) { if (! hash) return; etl_hash_destroy(hash, destroy_var, NULL); }