diff --git a/build/clang/Makefile b/build/clang/Makefile index 1e21053..5b4448b 100644 --- a/build/clang/Makefile +++ b/build/clang/Makefile @@ -45,10 +45,10 @@ $(BINDIR_R)/examples/%: $(TMPDIR_R)/examples/%.c $(TMPDIR_R)/examples/%.h mkdir -p $(dir $@) && $(CC) $(CFLAGS_R) -I. -o $@ $< $(LDFLAGS_R) $(TMPDIR_D)/examples/%.c $(TMPDIR_D)/examples/%.h: $(EXDIR)/%.peg $(BINDIR_D)/packcc - mkdir -p $(dir $@) && $(BINDIR_D)/packcc -o $(basename $@) $< + mkdir -p $(dir $@) && $(BINDIR_D)/packcc -I$(ROOTDIR)/import -o $(basename $@) $< $(TMPDIR_R)/examples/%.c $(TMPDIR_R)/examples/%.h: $(EXDIR)/%.peg $(BINDIR_R)/packcc - mkdir -p $(dir $@) && $(BINDIR_R)/packcc -o $(basename $@) $< + mkdir -p $(dir $@) && $(BINDIR_R)/packcc -I$(ROOTDIR)/import -o $(basename $@) $< check: $(BINDIR_D)/packcc $(BINDIR_R)/packcc @echo "== Debug Version ==" && PACKCC=$$PWD/$(BINDIR_D)/packcc CC="$(CC) $(CFLAGS_D)" $(TESTDIR)/test.sh diff --git a/build/gcc/Makefile b/build/gcc/Makefile index e3a39c0..e80c685 100644 --- a/build/gcc/Makefile +++ b/build/gcc/Makefile @@ -45,10 +45,10 @@ $(BINDIR_R)/examples/%: $(TMPDIR_R)/examples/%.c $(TMPDIR_R)/examples/%.h mkdir -p $(dir $@) && $(CC) $(CFLAGS_R) -I. -o $@ $< $(LDFLAGS_R) $(TMPDIR_D)/examples/%.c $(TMPDIR_D)/examples/%.h: $(EXDIR)/%.peg $(BINDIR_D)/packcc - mkdir -p $(dir $@) && $(BINDIR_D)/packcc -o $(basename $@) $< + mkdir -p $(dir $@) && $(BINDIR_D)/packcc -I$(ROOTDIR)/import -o $(basename $@) $< $(TMPDIR_R)/examples/%.c $(TMPDIR_R)/examples/%.h: $(EXDIR)/%.peg $(BINDIR_R)/packcc - mkdir -p $(dir $@) && $(BINDIR_R)/packcc -o $(basename $@) $< + mkdir -p $(dir $@) && $(BINDIR_R)/packcc -I$(ROOTDIR)/import -o $(basename $@) $< check: $(BINDIR_D)/packcc $(BINDIR_R)/packcc @echo "== Debug Version ==" && PACKCC=$$PWD/$(BINDIR_D)/packcc CC="$(CC) $(CFLAGS_D)" $(TESTDIR)/test.sh diff --git a/build/mingw-clang/Makefile b/build/mingw-clang/Makefile index 8bf9691..31a721d 100644 --- a/build/mingw-clang/Makefile +++ b/build/mingw-clang/Makefile @@ -45,10 +45,10 @@ $(BINDIR_R)/examples/%: $(TMPDIR_R)/examples/%.c $(TMPDIR_R)/examples/%.h mkdir -p $(dir $@) && $(CC) $(CFLAGS_R) -I. -o $@ $< $(LDFLAGS_R) $(TMPDIR_D)/examples/%.c $(TMPDIR_D)/examples/%.h: $(EXDIR)/%.peg $(BINDIR_D)/packcc - mkdir -p $(dir $@) && $(BINDIR_D)/packcc -o $(basename $@) $< + mkdir -p $(dir $@) && $(BINDIR_D)/packcc -I$(ROOTDIR)/import -o $(basename $@) $< $(TMPDIR_R)/examples/%.c $(TMPDIR_R)/examples/%.h: $(EXDIR)/%.peg $(BINDIR_R)/packcc - mkdir -p $(dir $@) && $(BINDIR_R)/packcc -o $(basename $@) $< + mkdir -p $(dir $@) && $(BINDIR_R)/packcc -I$(ROOTDIR)/import -o $(basename $@) $< check: $(BINDIR_D)/packcc $(BINDIR_R)/packcc @echo "== Debug Version ==" && PACKCC=$$PWD/$(BINDIR_D)/packcc CC="$(CC) $(CFLAGS_D)" $(TESTDIR)/test.sh diff --git a/build/mingw-gcc/Makefile b/build/mingw-gcc/Makefile index 72bb7ed..bdbba39 100644 --- a/build/mingw-gcc/Makefile +++ b/build/mingw-gcc/Makefile @@ -45,10 +45,10 @@ $(BINDIR_R)/examples/%: $(TMPDIR_R)/examples/%.c $(TMPDIR_R)/examples/%.h mkdir -p $(dir $@) && $(CC) $(CFLAGS_R) -I. -o $@ $< $(LDFLAGS_R) $(TMPDIR_D)/examples/%.c $(TMPDIR_D)/examples/%.h: $(EXDIR)/%.peg $(BINDIR_D)/packcc - mkdir -p $(dir $@) && $(BINDIR_D)/packcc -o $(basename $@) $< + mkdir -p $(dir $@) && $(BINDIR_D)/packcc -I$(ROOTDIR)/import -o $(basename $@) $< $(TMPDIR_R)/examples/%.c $(TMPDIR_R)/examples/%.h: $(EXDIR)/%.peg $(BINDIR_R)/packcc - mkdir -p $(dir $@) && $(BINDIR_R)/packcc -o $(basename $@) $< + mkdir -p $(dir $@) && $(BINDIR_R)/packcc -I$(ROOTDIR)/import -o $(basename $@) $< check: $(BINDIR_D)/packcc $(BINDIR_R)/packcc @echo "== Debug Version ==" && PACKCC=$$PWD/$(BINDIR_D)/packcc CC="$(CC) $(CFLAGS_D)" $(TESTDIR)/test.sh diff --git a/examples/ast-calc.peg b/examples/ast-calc.peg new file mode 100644 index 0000000..9808a81 --- /dev/null +++ b/examples/ast-calc.peg @@ -0,0 +1,122 @@ +# This code is hereby placed in the public domain. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +%prefix "calc" + +%value "pcc_ast_node_t *" # <-- must be set + +%auxil "pcc_ast_manager_t *" # <-- must be set + +%header { +#define PCC_AST_NODE_CUSTOM_DATA_DEFINED /* <-- enables node custom data */ + +typedef struct text_data_tag { /* <-- node custom data type */ + char *text; +} pcc_ast_node_custom_data_t; +} + +%source { +#include +#include +} + +statement <- _ e:expression _ EOL { $$ = e; } + / ( !EOL . )* EOL { $$ = NULL; } + +expression <- e:term { $$ = e; } + +term <- l:term _ '+' _ r:factor { $$ = pcc_ast_node__create_2(l, r); $$->custom.text = strdup("+"); } + / l:term _ '-' _ r:factor { $$ = pcc_ast_node__create_2(l, r); $$->custom.text = strdup("-"); } + / e:factor { $$ = e; } + +factor <- l:factor _ '*' _ r:unary { $$ = pcc_ast_node__create_2(l, r); $$->custom.text = strdup("*"); } + / l:factor _ '/' _ r:unary { $$ = pcc_ast_node__create_2(l, r); $$->custom.text = strdup("/"); } + / e:unary { $$ = e; } + +unary <- '+' _ e:unary { $$ = pcc_ast_node__create_1(e); $$->custom.text = strdup("+"); } + / '-' _ e:unary { $$ = pcc_ast_node__create_1(e); $$->custom.text = strdup("-"); } + / e:primary { $$ = e; } + +primary <- < [0-9]+ > { $$ = pcc_ast_node__create_0(); $$->custom.text = strdup($1); } + / '(' _ e:expression _ ')' { $$ = e; } + +_ <- [ \t]* +EOL <- '\n' / '\r\n' / '\r' / ';' + +%import "code/pcc_ast.peg" # <-- provides AST build functions + +%% +void pcc_ast_node_custom_data__initialize(pcc_ast_node_custom_data_t *obj) { /* <-- must be implemented when enabling node custom data */ + obj->text = NULL; +} + +void pcc_ast_node_custom_data__finalize(pcc_ast_node_custom_data_t *obj) { /* <-- must be implemented when enabling node custom data */ + free(obj->text); +} + +static void dump_ast(const pcc_ast_node_t *obj, int depth) { + if (obj) { + switch (obj->type) { + case PCC_AST_NODE_TYPE_NULLARY: + printf("%*s%s: \"%s\"\n", 2 * depth, "", "nullary", obj->custom.text); + break; + case PCC_AST_NODE_TYPE_UNARY: + printf("%*s%s: \"%s\"\n", 2 * depth, "", "unary", obj->custom.text); + dump_ast(obj->data.unary.node, depth + 1); + break; + case PCC_AST_NODE_TYPE_BINARY: + printf("%*s%s: \"%s\"\n", 2 * depth, "", "binary", obj->custom.text); + dump_ast(obj->data.binary.node[0], depth + 1); + dump_ast(obj->data.binary.node[1], depth + 1); + break; + case PCC_AST_NODE_TYPE_TERNARY: + printf("%*s%s: \"%s\"\n", 2 * depth, "", "ternary", obj->custom.text); + dump_ast(obj->data.ternary.node[0], depth + 1); + dump_ast(obj->data.ternary.node[1], depth + 1); + dump_ast(obj->data.ternary.node[2], depth + 1); + break; + case PCC_AST_NODE_TYPE_VARIADIC: + printf("%*s%s: \"%s\"\n", 2 * depth, "", "variadic", obj->custom.text); + { + size_t i; + for (i = 0; i < obj->data.variadic.len; i++) { + dump_ast(obj->data.variadic.node[i], depth + 1); + } + } + break; + default: + printf("%*s%s: \"%s\"\n", 2 * depth, "", "(unknown)", obj->custom.text); + break; + } + } + else { + printf("%*s(null)\n", 2 * depth, ""); + } +} + +int main(int argc, char **argv) { + pcc_ast_manager_t mgr; + pcc_ast_manager__initialize(&mgr); + { + calc_context_t *ctx = calc_create(&mgr); + pcc_ast_node_t *ast = NULL; + while (calc_parse(ctx, &ast)) { + dump_ast(ast, 0); + pcc_ast_node__destroy(ast); + } + calc_destroy(ctx); + } + pcc_ast_manager__finalize(&mgr); + return 0; +} diff --git a/import/code/pcc_ast.peg b/import/code/pcc_ast.peg new file mode 100644 index 0000000..d775d4d --- /dev/null +++ b/import/code/pcc_ast.peg @@ -0,0 +1,413 @@ +# Copyright (c) 2024 Arihiro Yoshida. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# PackCC AST import file version: 1.0.0 + +%header { +#define pcc_ast_node__create_0() pcc_ast_node__create_nullary(auxil) +#define pcc_ast_node__create_1(node) pcc_ast_node__create_unary(auxil, node) +#define pcc_ast_node__create_2(node0, node1) pcc_ast_node__create_binary(auxil, node0, node1) +#define pcc_ast_node__create_3(node0, node1, node2) pcc_ast_node__create_ternary(auxil, node0, node1, node2) +#define pcc_ast_node__create_v() pcc_ast_node__create_variadic(auxil) + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pcc_ast_manager_tag pcc_ast_manager_t; +typedef struct pcc_ast_node_tag pcc_ast_node_t; + +typedef enum pcc_ast_node_type_tag { + PCC_AST_NODE_TYPE_NULLARY, + PCC_AST_NODE_TYPE_UNARY, + PCC_AST_NODE_TYPE_BINARY, + PCC_AST_NODE_TYPE_TERNARY, + PCC_AST_NODE_TYPE_VARIADIC +} pcc_ast_node_type_t; + +typedef struct pcc_ast_node_single_tag { + pcc_ast_node_t *node; +} pcc_ast_node_single_t; + +typedef struct pcc_ast_node_double_tag { + pcc_ast_node_t *node[2]; +} pcc_ast_node_double_t; + +typedef struct pcc_ast_node_triple_tag { + pcc_ast_node_t *node[3]; +} pcc_ast_node_triple_t; + +typedef struct pcc_ast_node_array_tag { + pcc_ast_node_t **node; + size_t max, len; +} pcc_ast_node_array_t; + +typedef union pcc_ast_node_data_tag { + pcc_ast_node_single_t unary; + pcc_ast_node_double_t binary; + pcc_ast_node_triple_t ternary; + pcc_ast_node_array_t variadic; +} pcc_ast_node_data_t; + +struct pcc_ast_node_tag { + pcc_ast_manager_t *manager; + pcc_ast_node_t *next; /* the next element in the doubly linked list of managed nodes */ + pcc_ast_node_t *prev; /* the previous element in the doubly linked list of managed nodes */ + pcc_ast_node_t *parent; + pcc_ast_node_type_t type; + pcc_ast_node_data_t data; +#ifdef PCC_AST_NODE_CUSTOM_DATA_DEFINED + pcc_ast_node_custom_data_t custom; +#endif +}; + +struct pcc_ast_manager_tag { + pcc_ast_node_t *first; /* the first element in the doubly linked list of managed nodes */ +#ifdef PCC_AST_MANAGER_CUSTOM_DATA_DEFINED + pcc_ast_manager_custom_data_t custom; +#endif +}; + +void pcc_ast_manager__initialize(pcc_ast_manager_t *obj); +void pcc_ast_manager__finalize(pcc_ast_manager_t *obj); + +void pcc_ast_node_array__initialize(pcc_ast_manager_t *mgr, pcc_ast_node_array_t *obj); +void pcc_ast_node_array__finalize(pcc_ast_manager_t *mgr, pcc_ast_node_array_t *obj); +void pcc_ast_node_array__add(pcc_ast_manager_t *mgr, pcc_ast_node_array_t *obj, pcc_ast_node_t *node); + +pcc_ast_node_t *pcc_ast_node__create_nullary(pcc_ast_manager_t *mgr); +pcc_ast_node_t *pcc_ast_node__create_unary(pcc_ast_manager_t *mgr, pcc_ast_node_t *node); +pcc_ast_node_t *pcc_ast_node__create_binary(pcc_ast_manager_t *mgr, pcc_ast_node_t *node0, pcc_ast_node_t *node1); +pcc_ast_node_t *pcc_ast_node__create_ternary(pcc_ast_manager_t *mgr, pcc_ast_node_t *node0, pcc_ast_node_t *node1, pcc_ast_node_t *node2); +pcc_ast_node_t *pcc_ast_node__create_variadic(pcc_ast_manager_t *mgr); +pcc_ast_node_t *pcc_ast_node__add_child(pcc_ast_node_t *obj, pcc_ast_node_t *node); /* for variadic node only */ +void pcc_ast_node__destroy(pcc_ast_node_t *obj); + +#ifdef PCC_AST_MANAGER_CUSTOM_DATA_DEFINED +void pcc_ast_manager_custom_data__initialize(pcc_ast_manager_custom_data_t *obj); +void pcc_ast_manager_custom_data__finalize(pcc_ast_manager_custom_data_t *obj); +#else +#define pcc_ast_manager_custom_data__initialize(obj) ((void)0) +#define pcc_ast_manager_custom_data__finalize(obj) ((void)0) +#endif + +#ifdef PCC_AST_NODE_CUSTOM_DATA_DEFINED +void pcc_ast_node_custom_data__initialize(pcc_ast_node_custom_data_t *obj); +void pcc_ast_node_custom_data__finalize(pcc_ast_node_custom_data_t *obj); +#else +#define pcc_ast_node_custom_data__initialize(obj) ((void)0) +#define pcc_ast_node_custom_data__finalize(obj) ((void)0) +#endif + +#ifdef __cplusplus +} +#endif +} + +%source { +#include +} + +%% +#ifndef PCC_AST_NODE_ARRAY_MIN_SIZE +#define PCC_AST_NODE_ARRAY_MIN_SIZE 4 +#endif + +#ifndef PCC_AST_MALLOC +#define PCC_AST_MALLOC(mgr, size) PCC_MALLOC(mgr, size) +#endif + +#ifndef PCC_AST_REALLOC +#define PCC_AST_REALLOC(mgr, ptr, size) PCC_REALLOC(mgr, ptr, size) +#endif + +#ifndef PCC_AST_FREE +#define PCC_AST_FREE(mgr, ptr) PCC_FREE(mgr, ptr) +#endif + +void pcc_ast_manager__initialize(pcc_ast_manager_t *obj) { + obj->first = NULL; + pcc_ast_manager_custom_data__initialize(&(obj->custom)); +} + +void pcc_ast_manager__finalize(pcc_ast_manager_t *obj) { + pcc_ast_manager_custom_data__finalize(&(obj->custom)); + while (obj->first) { + assert(obj->first->manager == obj); + pcc_ast_node__destroy(obj->first); + } +} + +void pcc_ast_node_array__initialize(pcc_ast_manager_t *mgr, pcc_ast_node_array_t *obj) { + obj->len = 0; + obj->max = 0; + obj->node = NULL; +} + +void pcc_ast_node_array__finalize(pcc_ast_manager_t *mgr, pcc_ast_node_array_t *obj) { + while (obj->len > 0) { + obj->len--; + pcc_ast_node__destroy(obj->node[obj->len]); + } + PCC_AST_FREE(mgr, obj->node); +} + +void pcc_ast_node_array__add(pcc_ast_manager_t *mgr, pcc_ast_node_array_t *obj, pcc_ast_node_t *node) { + if (obj->max <= obj->len) { + const size_t n = obj->len + 1; + size_t m = obj->max; + if (m == 0) m = PCC_AST_NODE_ARRAY_MIN_SIZE; + while (m < n && m != 0) m <<= 1; + if (m == 0) m = n; + obj->node = (pcc_ast_node_t **)PCC_AST_REALLOC(mgr, obj->node, sizeof(pcc_ast_node_t *) * m); + obj->max = m; + } + obj->node[obj->len++] = node; +} + +static void pcc_ast_node__unlink_parent_(pcc_ast_node_t *obj) { + if (obj->parent) { + switch (obj->parent->type) { + case PCC_AST_NODE_TYPE_NULLARY: + assert(((void)"Nullary node illegally linked as a parent", 0)); + break; + case PCC_AST_NODE_TYPE_UNARY: + if (obj->parent->data.unary.node == obj) + obj->parent->data.unary.node = NULL; + else + assert(((void)"parent node with no backward link", 0)); + break; + case PCC_AST_NODE_TYPE_BINARY: + { + size_t i; + for (i = 0; i < 2; i++) { + if (obj->parent->data.binary.node[i] == obj) break; + } + if (i < 2) + obj->parent->data.binary.node[i] = NULL; + else + assert(((void)"parent node with no backward link", 0)); + } + break; + case PCC_AST_NODE_TYPE_TERNARY: + { + size_t i; + for (i = 0; i < 3; i++) { + if (obj->parent->data.ternary.node[i] == obj) break; + } + if (i < 3) + obj->parent->data.ternary.node[i] = NULL; + else + assert(((void)"parent node with no backward link", 0)); + } + break; + case PCC_AST_NODE_TYPE_VARIADIC: + { + const size_t n = obj->parent->data.variadic.len; + size_t i; + for (i = 0; i < n; i++) { + if (obj->parent->data.variadic.node[i] == obj) break; + } + if (i < n) + obj->parent->data.variadic.node[i] = NULL; + else + assert(((void)"parent node with no backward link", 0)); + } + break; + default: + assert(((void)"Node type unknown", 0)); + break; + } + obj->parent = NULL; + } +} + +static pcc_ast_node_t *pcc_ast_node__create_(pcc_ast_manager_t *mgr) { + pcc_ast_node_t *const obj = (pcc_ast_node_t *)PCC_AST_MALLOC(mgr, sizeof(pcc_ast_node_t)); + obj->manager = mgr; + if (mgr->first) { + obj->next = mgr->first; + assert(((void)"Inconsistency in the doubly linked list of managed nodes", obj->next->prev == NULL)); + obj->next->prev = obj; + } + else { + obj->next = NULL; + } + obj->prev = NULL; + mgr->first = obj; + obj->parent = NULL; + return obj; +} + +pcc_ast_node_t *pcc_ast_node__create_nullary(pcc_ast_manager_t *mgr) { + pcc_ast_node_t *const obj = pcc_ast_node__create_(mgr); + obj->type = PCC_AST_NODE_TYPE_NULLARY; + pcc_ast_node_custom_data__initialize(&(obj->custom)); + return obj; +} + +pcc_ast_node_t *pcc_ast_node__create_unary(pcc_ast_manager_t *mgr, pcc_ast_node_t *node) { + pcc_ast_node_t *const obj = pcc_ast_node__create_(mgr); + obj->type = PCC_AST_NODE_TYPE_UNARY; + obj->data.unary.node = node; + if (node) { + pcc_ast_node__unlink_parent_(node); + node->parent = obj; + } + pcc_ast_node_custom_data__initialize(&(obj->custom)); + return obj; +} + +pcc_ast_node_t *pcc_ast_node__create_binary(pcc_ast_manager_t *mgr, pcc_ast_node_t *node0, pcc_ast_node_t *node1) { + pcc_ast_node_t *const obj = pcc_ast_node__create_(mgr); + obj->type = PCC_AST_NODE_TYPE_BINARY; + obj->data.binary.node[0] = node0; + obj->data.binary.node[1] = node1; + { + size_t i = 0; + for (i = 0; i < 2; i++) { + pcc_ast_node_t *const node = obj->data.binary.node[i]; + if (node) { + pcc_ast_node__unlink_parent_(node); + node->parent = obj; + } + } + } + pcc_ast_node_custom_data__initialize(&(obj->custom)); + return obj; +} + +pcc_ast_node_t *pcc_ast_node__create_ternary(pcc_ast_manager_t *mgr, pcc_ast_node_t *node0, pcc_ast_node_t *node1, pcc_ast_node_t *node2) { + pcc_ast_node_t *const obj = pcc_ast_node__create_(mgr); + obj->type = PCC_AST_NODE_TYPE_TERNARY; + obj->data.ternary.node[0] = node0; + obj->data.ternary.node[1] = node1; + obj->data.ternary.node[2] = node2; + { + size_t i = 0; + for (i = 0; i < 3; i++) { + pcc_ast_node_t *const node = obj->data.ternary.node[i]; + if (node) { + pcc_ast_node__unlink_parent_(node); + node->parent = obj; + } + } + } + pcc_ast_node_custom_data__initialize(&(obj->custom)); + return obj; +} + +pcc_ast_node_t *pcc_ast_node__create_variadic(pcc_ast_manager_t *mgr) { + pcc_ast_node_t *const obj = pcc_ast_node__create_(mgr); + obj->type = PCC_AST_NODE_TYPE_VARIADIC; + pcc_ast_node_array__initialize(mgr, &(obj->data.variadic)); + pcc_ast_node_custom_data__initialize(&(obj->custom)); + return obj; +} + +pcc_ast_node_t *pcc_ast_node__add_child(pcc_ast_node_t *obj, pcc_ast_node_t *node) { + if (obj->type == PCC_AST_NODE_TYPE_VARIADIC) { + pcc_ast_node_array__add(obj->manager, &(obj->data.variadic), node); + if (node) { + pcc_ast_node__unlink_parent_(node); + node->parent = obj; + } + } + else { + assert(((void)"Attempted to add node to non-variadic node", obj->next->prev == NULL)); + } + return obj; +} + +void pcc_ast_node__destroy(pcc_ast_node_t *obj) { + if (obj) { + pcc_ast_node_custom_data__finalize(&(obj->custom)); + switch (obj->type) { + case PCC_AST_NODE_TYPE_NULLARY: + break; + case PCC_AST_NODE_TYPE_UNARY: + { + pcc_ast_node_t *const node = obj->data.unary.node; + if (node) { + assert(node->parent == obj); + node->parent = NULL; + pcc_ast_node__destroy(node); + } + } + break; + case PCC_AST_NODE_TYPE_BINARY: + { + size_t i; + for (i = 0; i < 2; i++) { + pcc_ast_node_t *const node = obj->data.binary.node[i]; + if (node) { + assert(node->parent == obj); + node->parent = NULL; + pcc_ast_node__destroy(node); + } + } + } + break; + case PCC_AST_NODE_TYPE_TERNARY: + { + size_t i; + for (i = 0; i < 3; i++) { + pcc_ast_node_t *const node = obj->data.ternary.node[i]; + if (node) { + assert(node->parent == obj); + node->parent = NULL; + pcc_ast_node__destroy(node); + } + } + } + break; + case PCC_AST_NODE_TYPE_VARIADIC: + while (obj->data.variadic.len > 0) { + const size_t i = --obj->data.variadic.len; + pcc_ast_node_t *const node = obj->data.variadic.node[i]; + if (node) { + assert(node->parent == obj); + node->parent = NULL; + pcc_ast_node__destroy(node); + obj->data.variadic.node[i] = NULL; + } + } + pcc_ast_node_array__finalize(obj->manager, &(obj->data.variadic)); + break; + default: + assert(((void)"Node type unknown", 0)); + break; + } + pcc_ast_node__unlink_parent_(obj); + if (obj->prev) { + assert(obj->prev->next == obj); + obj->prev->next = obj->next; + } + else { + assert(obj->manager->first == obj); + obj->manager->first = obj->next; + } + if (obj->next) { + assert(obj->next->prev == obj); + obj->next->prev = obj->prev; + } + PCC_AST_FREE(obj->manager, obj); + } +}