/* Copyright 2005-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 #include #include "etl_data.h" #include "common.h" #include "parser.h" #include "lexer.h" static void append_items(etl_variable_t *arr, etl_list_entry_t *le, etl_ddl_parser_state_t *state) { if (le) { append_items(arr, le->next, state); etl_variable_array_push(arr, le->value); le->next = state->spare_entries; state->spare_entries = le->next; } } static etl_list_entry_t * get_entry(etl_ddl_parser_state_t *state) { if (state->spare_entries) { etl_list_entry_t *le = state->spare_entries; state->spare_entries = le->next; le->next = NULL; return le; } else { return calloc(1, sizeof(etl_list_entry_t)); } } static void set_var(const char *key, void *val, void *baton) { etl_hash_set(baton, key, val); } static void hash_set_var(const char *key, void *val, void *baton) { etl_variable_hash_set(baton, key, val); } } %name etl_ddl_parser_parse %token_prefix ETL_DDL_TOK_ %token_type { etl_token_t * } %extra_argument { etl_ddl_parser_state_t *state } %type hash { etl_variable_t * } %type array { etl_variable_t * } %type hash_element { etl_list_entry_t * } %type hash_elements { etl_list_entry_t * } %type array_element { etl_list_entry_t * } %type array_elements { etl_list_entry_t * } %type element { etl_variable_t * } %syntax_error { if (! state->err) { state->err = etl_error_createf(ETL_EINVAL, "Syntax error near line %d", TOKEN->line); } } data ::= assignment_list. assignment_list ::= assignment_list assignment. assignment_list ::= assignment. assignment ::= INCLUDE STRING(S). { if (state->resolver) { etl_stream_t *stream; etl_error_t *err = etl_resolver_resolve(&stream, state->resolver, S->data); if (! err) { etl_hash_t *data = NULL; err = etl_ddl_parse(&data, state->resolver, stream); if (! err) { etl_hash_traverse(data, set_var, state->vars); /* XXX destroy hash? */ } } if (err && ! state->err) state->err = err; else etl_error_clear(err); } else { state->err = etl_error_create(ETL_EINVAL, "Can't use %include without a resolver"); } } assignment ::= VAR(V) EQUALS INCLUDE STRING(S). { if (state->resolver) { etl_stream_t *stream; etl_error_t *err = etl_resolver_resolve(&stream, state->resolver, S->data); if (! err) { etl_hash_t *data = NULL; err = etl_ddl_parse(&data, state->resolver, stream); if (! err) { etl_variable_t *var = etl_variable_make_hash(); etl_hash_traverse(data, hash_set_var, var); etl_hash_set(state->vars, V->data, var); } } if (err && ! state->err) state->err = err; else etl_error_clear(err); } else { state->err = etl_error_create(ETL_EINVAL, "Can't use %include without a resolver"); } } assignment ::= VAR(V) EQUALS element(E). { etl_hash_set(state->vars, V->data, E); } hash(H) ::= STARTHASH hash_elements(E) ENDHASH. { etl_list_entry_t *le = E; H = etl_variable_make_hash(); while (le) { etl_list_entry_t *spare; etl_variable_hash_set(H, le->key, le->value); spare = le; le = le->next; spare->next = state->spare_entries; state->spare_entries = spare; } } hash_elements(E1) ::= hash_elements(E2) hash_element(E3). { E3->next = E2; E1 = E3; } hash_elements(E) ::= hash_element(HE). { E = HE; } hash_element(E) ::= STRING(K) EQUALS element(V) COMMA. { E = get_entry(state); E->key = K->data; E->value = V; } hash_element(E) ::= VAR(K) EQUALS element(V) COMMA. { E = get_entry(state); E->key = K->data; E->value = V; } hash_element(E) ::= STRING(K) EQUALS element(V). { E = get_entry(state); E->key = K->data; E->value = V; } hash_element(E) ::= VAR(K) EQUALS element(V). { E = get_entry(state); E->key = K->data; E->value = V; } array(A) ::= STARTARRAY array_elements(E) ENDARRAY. { A = etl_variable_make_array(10); append_items(A, E, state); } array_elements(AE1) ::= array_elements(AE2) array_element(AE3). { AE3->next = AE2; AE1 = AE3; } array_elements(E) ::= array_element(A). { E = A; } array_element(A) ::= element(E) COMMA. { A = get_entry(state); A->value = E; } array_element(A) ::= element(E). { A = get_entry(state); A->value = E; } element(E) ::= STRING(S). { E = etl_variable_make_str(S->data); } element(E) ::= INT(I). { char *i = I->data; E = etl_variable_make_int(atoi(i)); } element(E) ::= hash(H). { E = H; } element(E) ::= array(A). { E = A; }