X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=src%2Fplugins%2Fctf%2Fcommon%2Fmetadata%2Fparser.ypp;fp=src%2Fplugins%2Fctf%2Fcommon%2Fmetadata%2Fparser.ypp;h=b644b5d1ec68713f10bb68b5ac644d1748f8bc79;hb=087cd0f57f0f7d815a609a4e041d1200f380e4aa;hp=0000000000000000000000000000000000000000;hpb=516bf0a77e025cfccce2fa400b757e94dc0bf1d8;p=babeltrace.git diff --git a/src/plugins/ctf/common/metadata/parser.ypp b/src/plugins/ctf/common/metadata/parser.ypp new file mode 100644 index 00000000..b644b5d1 --- /dev/null +++ b/src/plugins/ctf/common/metadata/parser.ypp @@ -0,0 +1,2609 @@ +%{ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2010 - Mathieu Desnoyers + * + * Common Trace Format Metadata Grammar. + */ + +#define BT_LOG_OUTPUT_LEVEL ctf_plugin_metadata_log_level +#define BT_LOG_TAG "PLUGIN/CTF/META/PARSER" +#include "logging.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "common/list.h" +#include "common/assert.h" +#include "scanner.hpp" +#include "ast.hpp" +#include "objstack.hpp" + +#include "parser-wrap.hpp" + +/* Join two lists, put "add" at the end of "head". */ +static inline void +_bt_list_splice_tail (struct bt_list_head *add, struct bt_list_head *head) +{ + /* Do nothing if the list which gets added is empty. */ + if (add != add->next) { + add->next->prev = head->prev; + add->prev->next = head; + head->prev->next = add->next; + head->prev = add->prev; + } +} + +BT_HIDDEN +int yylex(union YYSTYPE *yyval, yyscan_t yyscanner); +BT_HIDDEN +int yylex_init_extra(struct ctf_scanner *scanner, yyscan_t * ptr_yy_globals); +BT_HIDDEN +int yylex_destroy(yyscan_t yyscanner); +BT_HIDDEN +void yyrestart(FILE * in_str, yyscan_t yyscanner); +BT_HIDDEN +int yyget_lineno(yyscan_t yyscanner); +BT_HIDDEN +char *yyget_text(yyscan_t yyscanner); + +/* + * Static node for out of memory errors. Only "type" is used. lineno is + * always left at 0. The rest of the node content can be overwritten, + * but is never used. + */ +static struct ctf_node error_node = { + .parent = nullptr, + .siblings = {}, + .tmp_head = {}, + .lineno = 0, + .visited = 0, + .type = NODE_ERROR, +}; + +BT_HIDDEN +const char *node_type(struct ctf_node *node) +{ + switch (node->type) { +#define ENTRY(S) case S: return #S; + FOREACH_CTF_NODES(ENTRY) +#undef ENTRY + }; + + bt_common_abort(); +} + +void setstring(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src) +{ + lvalp->s = (char *) objstack_alloc(scanner->objstack, strlen(src) + 1); + strcpy(lvalp->s, src); +} + +static +int str_check(size_t str_len, size_t offset, size_t len) +{ + /* check overflow */ + if (offset + len < offset) + return -1; + if (offset + len > str_len) + return -1; + return 0; +} + +static +int bt_isodigit(int c) +{ + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + return 1; + default: + return 0; + } +} + +static +int parse_base_sequence(const char *src, size_t len, size_t pos, + char *buffer, size_t *buf_len, int base) +{ + const size_t max_char = 3; + int nr_char = 0; + + while (!str_check(len, pos, 1) && nr_char < max_char) { + char c = src[pos++]; + + if (base == 8) { + if (bt_isodigit(c)) + buffer[nr_char++] = c; + else + break; + } else if (base == 16) { + if (isxdigit(c)) + buffer[nr_char++] = c; + else + break; + + } else { + /* Unsupported base */ + return -1; + } + } + BT_ASSERT_DBG(nr_char > 0); + buffer[nr_char] = '\0'; + *buf_len = nr_char; + return 0; +} + +static +int import_basic_string(struct ctf_scanner *scanner, YYSTYPE *lvalp, + size_t len, const char *src, char delim) +{ + size_t pos = 0, dpos = 0; + + if (str_check(len, pos, 1)) + return -1; + if (src[pos++] != delim) + return -1; + + while (src[pos] != delim) { + char c; + + if (str_check(len, pos, 1)) + return -1; + c = src[pos++]; + if (c == '\\') { + if (str_check(len, pos, 1)) + return -1; + c = src[pos++]; + + switch (c) { + case 'a': + c = '\a'; + break; + case 'b': + c = '\b'; + break; + case 'f': + c = '\f'; + break; + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case 't': + c = '\t'; + break; + case 'v': + c = '\v'; + break; + case '\\': + c = '\\'; + break; + case '\'': + c = '\''; + break; + case '\"': + c = '\"'; + break; + case '?': + c = '?'; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + char oct_buffer[4]; + size_t oct_len; + + if (parse_base_sequence(src, len, pos - 1, + oct_buffer, &oct_len, 8)) + return -1; + c = strtoul(&oct_buffer[0], NULL, 8); + pos += oct_len - 1; + break; + } + case 'x': + { + char hex_buffer[4]; + size_t hex_len; + + if (parse_base_sequence(src, len, pos, + hex_buffer, &hex_len, 16)) + return -1; + c = strtoul(&hex_buffer[0], NULL, 16); + pos += hex_len; + break; + } + default: + return -1; + } + } + if (str_check(len, dpos, 1)) + return -1; + lvalp->s[dpos++] = c; + } + + if (str_check(len, dpos, 1)) + return -1; + lvalp->s[dpos++] = '\0'; + + if (str_check(len, pos, 1)) + return -1; + if (src[pos++] != delim) + return -1; + + if (str_check(len, pos, 1)) + return -1; + if (src[pos] != '\0') + return -1; + return 0; +} + +int import_string(struct ctf_scanner *scanner, YYSTYPE *lvalp, + const char *src, char delim) +{ + size_t len; + + len = strlen(src) + 1; + lvalp->s = (char *) objstack_alloc(scanner->objstack, len); + if (src[0] == 'L') { + // TODO: import wide string + _BT_LOGE_APPEND_CAUSE_LINENO(yyget_lineno(scanner), + "wide characters are not supported as of this version: " + "scanner-addr=%p", scanner); + return -1; + } else { + return import_basic_string(scanner, lvalp, len, src, delim); + } +} + +static void init_scope(struct ctf_scanner_scope *scope, + struct ctf_scanner_scope *parent) +{ + scope->parent = parent; + scope->classes = g_hash_table_new_full(g_str_hash, g_str_equal, + NULL, NULL); +} + +static void finalize_scope(struct ctf_scanner_scope *scope) +{ + g_hash_table_destroy(scope->classes); +} + +static void push_scope(struct ctf_scanner *scanner) +{ + struct ctf_scanner_scope *ns; + + BT_LOGT("Pushing scope: scanner-addr=%p", scanner); + ns = (ctf_scanner_scope *) malloc(sizeof(struct ctf_scanner_scope)); + init_scope(ns, scanner->cs); + scanner->cs = ns; +} + +static void pop_scope(struct ctf_scanner *scanner) +{ + struct ctf_scanner_scope *os; + + BT_LOGT("Popping scope: scanner-addr=%p", scanner); + os = scanner->cs; + scanner->cs = os->parent; + finalize_scope(os); + free(os); +} + +static int lookup_type(struct ctf_scanner_scope *s, const char *id) +{ + int ret; + + ret = GPOINTER_TO_INT(g_hash_table_lookup(s->classes, id)); + BT_LOGT("Looked up type: scanner-addr=%p, id=\"%s\", ret=%d", + s, id, ret); + return ret; +} + +BT_HIDDEN +int is_type(struct ctf_scanner *scanner, const char *id) +{ + struct ctf_scanner_scope *it; + int ret = 0; + + for (it = scanner->cs; it; it = it->parent) { + if (lookup_type(it, id)) { + ret = 1; + break; + } + } + BT_LOGT("Found if ID is type: scanner-addr=%p, id=\"%s\", ret=%d", + scanner, id, ret); + return ret; +} + +static void add_type(struct ctf_scanner *scanner, char *id) +{ + BT_LOGT("Adding type: scanner-addr=%p, id=\"%s\"", + scanner, id); + if (lookup_type(scanner->cs, id)) + return; + g_hash_table_insert(scanner->cs->classes, id, id); +} + +static struct ctf_node *make_node(struct ctf_scanner *scanner, + enum node_type type) +{ + struct ctf_node *node; + + node = (ctf_node *) objstack_alloc(scanner->objstack, sizeof(*node)); + if (!node) { + _BT_LOGE_APPEND_CAUSE_LINENO(yyget_lineno(scanner->scanner), + "failed to allocate one stack entry: " + "scanner-addr=%p", scanner); + return &error_node; + } + node->type = type; + node->lineno = yyget_lineno(scanner->scanner); + BT_INIT_LIST_HEAD(&node->tmp_head); + bt_list_add(&node->siblings, &node->tmp_head); + + switch (type) { + case NODE_ROOT: + node->type = NODE_ERROR; + BT_LOGE("Trying to create root node: scanner-addr=%p", + scanner); + break; + case NODE_EVENT: + BT_INIT_LIST_HEAD(&node->u.event.declaration_list); + break; + case NODE_STREAM: + BT_INIT_LIST_HEAD(&node->u.stream.declaration_list); + break; + case NODE_ENV: + BT_INIT_LIST_HEAD(&node->u.env.declaration_list); + break; + case NODE_TRACE: + BT_INIT_LIST_HEAD(&node->u.trace.declaration_list); + break; + case NODE_CLOCK: + BT_INIT_LIST_HEAD(&node->u.clock.declaration_list); + break; + case NODE_CALLSITE: + BT_INIT_LIST_HEAD(&node->u.callsite.declaration_list); + break; + case NODE_CTF_EXPRESSION: + BT_INIT_LIST_HEAD(&node->u.ctf_expression.left); + BT_INIT_LIST_HEAD(&node->u.ctf_expression.right); + break; + case NODE_UNARY_EXPRESSION: + break; + case NODE_TYPEDEF: + BT_INIT_LIST_HEAD(&node->u.field_class_def.field_class_declarators); + break; + case NODE_TYPEALIAS_TARGET: + BT_INIT_LIST_HEAD(&node->u.field_class_alias_target.field_class_declarators); + break; + case NODE_TYPEALIAS_ALIAS: + BT_INIT_LIST_HEAD(&node->u.field_class_alias_name.field_class_declarators); + break; + case NODE_TYPEALIAS: + break; + case NODE_TYPE_SPECIFIER: + break; + case NODE_TYPE_SPECIFIER_LIST: + BT_INIT_LIST_HEAD(&node->u.field_class_specifier_list.head); + break; + case NODE_POINTER: + break; + case NODE_TYPE_DECLARATOR: + BT_INIT_LIST_HEAD(&node->u.field_class_declarator.pointers); + break; + case NODE_FLOATING_POINT: + BT_INIT_LIST_HEAD(&node->u.floating_point.expressions); + break; + case NODE_INTEGER: + BT_INIT_LIST_HEAD(&node->u.integer.expressions); + break; + case NODE_STRING: + BT_INIT_LIST_HEAD(&node->u.string.expressions); + break; + case NODE_ENUMERATOR: + BT_INIT_LIST_HEAD(&node->u.enumerator.values); + break; + case NODE_ENUM: + BT_INIT_LIST_HEAD(&node->u._enum.enumerator_list); + break; + case NODE_STRUCT_OR_VARIANT_DECLARATION: + BT_INIT_LIST_HEAD(&node->u.struct_or_variant_declaration.field_class_declarators); + break; + case NODE_VARIANT: + BT_INIT_LIST_HEAD(&node->u.variant.declaration_list); + break; + case NODE_STRUCT: + BT_INIT_LIST_HEAD(&node->u._struct.declaration_list); + BT_INIT_LIST_HEAD(&node->u._struct.min_align); + break; + case NODE_UNKNOWN: + default: + node->type = NODE_ERROR; + BT_LOGE("Unknown node type: scanner-addr=%p, node-type=%d", + scanner, type); + break; + } + + return node; +} + +static int reparent_ctf_expression(struct ctf_node *node, + struct ctf_node *parent) +{ + switch (parent->type) { + case NODE_EVENT: + _bt_list_splice_tail(&node->tmp_head, &parent->u.event.declaration_list); + break; + case NODE_STREAM: + _bt_list_splice_tail(&node->tmp_head, &parent->u.stream.declaration_list); + break; + case NODE_ENV: + _bt_list_splice_tail(&node->tmp_head, &parent->u.env.declaration_list); + break; + case NODE_TRACE: + _bt_list_splice_tail(&node->tmp_head, &parent->u.trace.declaration_list); + break; + case NODE_CLOCK: + _bt_list_splice_tail(&node->tmp_head, &parent->u.clock.declaration_list); + break; + case NODE_CALLSITE: + _bt_list_splice_tail(&node->tmp_head, &parent->u.callsite.declaration_list); + break; + case NODE_FLOATING_POINT: + _bt_list_splice_tail(&node->tmp_head, &parent->u.floating_point.expressions); + break; + case NODE_INTEGER: + _bt_list_splice_tail(&node->tmp_head, &parent->u.integer.expressions); + break; + case NODE_STRING: + _bt_list_splice_tail(&node->tmp_head, &parent->u.string.expressions); + break; + + case NODE_ROOT: + case NODE_CTF_EXPRESSION: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_TYPE_SPECIFIER_LIST: + case NODE_POINTER: + case NODE_TYPE_DECLARATOR: + case NODE_ENUMERATOR: + case NODE_ENUM: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + case NODE_VARIANT: + case NODE_STRUCT: + case NODE_UNARY_EXPRESSION: + return -EPERM; + + case NODE_UNKNOWN: + default: + BT_LOGE("Unknown node type: node-type=%d", parent->type); + return -EINVAL; + } + return 0; +} + +static int reparent_typedef(struct ctf_node *node, struct ctf_node *parent) +{ + switch (parent->type) { + case NODE_ROOT: + _bt_list_splice_tail(&node->tmp_head, &parent->u.root.declaration_list); + break; + case NODE_EVENT: + _bt_list_splice_tail(&node->tmp_head, &parent->u.event.declaration_list); + break; + case NODE_STREAM: + _bt_list_splice_tail(&node->tmp_head, &parent->u.stream.declaration_list); + break; + case NODE_ENV: + _bt_list_splice_tail(&node->tmp_head, &parent->u.env.declaration_list); + break; + case NODE_TRACE: + _bt_list_splice_tail(&node->tmp_head, &parent->u.trace.declaration_list); + break; + case NODE_CLOCK: + _bt_list_splice_tail(&node->tmp_head, &parent->u.clock.declaration_list); + break; + case NODE_CALLSITE: + _bt_list_splice_tail(&node->tmp_head, &parent->u.callsite.declaration_list); + break; + case NODE_VARIANT: + _bt_list_splice_tail(&node->tmp_head, &parent->u.variant.declaration_list); + break; + case NODE_STRUCT: + _bt_list_splice_tail(&node->tmp_head, &parent->u._struct.declaration_list); + break; + + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_CTF_EXPRESSION: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_TYPE_SPECIFIER_LIST: + case NODE_POINTER: + case NODE_TYPE_DECLARATOR: + case NODE_ENUMERATOR: + case NODE_ENUM: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + case NODE_UNARY_EXPRESSION: + return -EPERM; + + case NODE_UNKNOWN: + default: + BT_LOGE("Unknown node type: node-type=%d", parent->type); + return -EINVAL; + } + return 0; +} + +static int reparent_field_class_alias(struct ctf_node *node, struct ctf_node *parent) +{ + switch (parent->type) { + case NODE_ROOT: + _bt_list_splice_tail(&node->tmp_head, &parent->u.root.declaration_list); + break; + case NODE_EVENT: + _bt_list_splice_tail(&node->tmp_head, &parent->u.event.declaration_list); + break; + case NODE_STREAM: + _bt_list_splice_tail(&node->tmp_head, &parent->u.stream.declaration_list); + break; + case NODE_ENV: + _bt_list_splice_tail(&node->tmp_head, &parent->u.env.declaration_list); + break; + case NODE_TRACE: + _bt_list_splice_tail(&node->tmp_head, &parent->u.trace.declaration_list); + break; + case NODE_CLOCK: + _bt_list_splice_tail(&node->tmp_head, &parent->u.clock.declaration_list); + break; + case NODE_CALLSITE: + _bt_list_splice_tail(&node->tmp_head, &parent->u.callsite.declaration_list); + break; + case NODE_VARIANT: + _bt_list_splice_tail(&node->tmp_head, &parent->u.variant.declaration_list); + break; + case NODE_STRUCT: + _bt_list_splice_tail(&node->tmp_head, &parent->u._struct.declaration_list); + break; + + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_CTF_EXPRESSION: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_TYPEALIAS: + case NODE_TYPE_SPECIFIER: + case NODE_TYPE_SPECIFIER_LIST: + case NODE_POINTER: + case NODE_TYPE_DECLARATOR: + case NODE_ENUMERATOR: + case NODE_ENUM: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + case NODE_UNARY_EXPRESSION: + return -EPERM; + + case NODE_UNKNOWN: + default: + BT_LOGE("Unknown node type: node-type=%d", parent->type); + return -EINVAL; + } + return 0; +} + +static int reparent_field_class_specifier(struct ctf_node *node, + struct ctf_node *parent) +{ + switch (parent->type) { + case NODE_TYPE_SPECIFIER_LIST: + _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_specifier_list.head); + break; + + case NODE_TYPE_SPECIFIER: + case NODE_EVENT: + case NODE_STREAM: + case NODE_ENV: + case NODE_TRACE: + case NODE_CLOCK: + case NODE_CALLSITE: + case NODE_VARIANT: + case NODE_STRUCT: + case NODE_TYPEDEF: + case NODE_TYPEALIAS_TARGET: + case NODE_TYPEALIAS_ALIAS: + case NODE_TYPE_DECLARATOR: + case NODE_ENUM: + case NODE_STRUCT_OR_VARIANT_DECLARATION: + case NODE_TYPEALIAS: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_CTF_EXPRESSION: + case NODE_POINTER: + case NODE_ENUMERATOR: + case NODE_UNARY_EXPRESSION: + return -EPERM; + + case NODE_UNKNOWN: + default: + BT_LOGE("Unknown node type: node-type=%d", parent->type); + return -EINVAL; + } + return 0; +} + +static int reparent_field_class_specifier_list(struct ctf_node *node, + struct ctf_node *parent) +{ + switch (parent->type) { + case NODE_ROOT: + bt_list_add_tail(&node->siblings, &parent->u.root.declaration_list); + break; + case NODE_EVENT: + bt_list_add_tail(&node->siblings, &parent->u.event.declaration_list); + break; + case NODE_STREAM: + bt_list_add_tail(&node->siblings, &parent->u.stream.declaration_list); + break; + case NODE_ENV: + bt_list_add_tail(&node->siblings, &parent->u.env.declaration_list); + break; + case NODE_TRACE: + bt_list_add_tail(&node->siblings, &parent->u.trace.declaration_list); + break; + case NODE_CLOCK: + bt_list_add_tail(&node->siblings, &parent->u.clock.declaration_list); + break; + case NODE_CALLSITE: + bt_list_add_tail(&node->siblings, &parent->u.callsite.declaration_list); + break; + case NODE_VARIANT: + bt_list_add_tail(&node->siblings, &parent->u.variant.declaration_list); + break; + case NODE_STRUCT: + bt_list_add_tail(&node->siblings, &parent->u._struct.declaration_list); + break; + case NODE_TYPEDEF: + parent->u.field_class_def.field_class_specifier_list = node; + break; + case NODE_TYPEALIAS_TARGET: + parent->u.field_class_alias_target.field_class_specifier_list = node; + break; + case NODE_TYPEALIAS_ALIAS: + parent->u.field_class_alias_name.field_class_specifier_list = node; + break; + case NODE_ENUM: + parent->u._enum.container_field_class = node; + break; + case NODE_STRUCT_OR_VARIANT_DECLARATION: + parent->u.struct_or_variant_declaration.field_class_specifier_list = node; + break; + case NODE_TYPE_DECLARATOR: + case NODE_TYPE_SPECIFIER: + case NODE_TYPEALIAS: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_CTF_EXPRESSION: + case NODE_POINTER: + case NODE_ENUMERATOR: + case NODE_UNARY_EXPRESSION: + return -EPERM; + + case NODE_UNKNOWN: + default: + BT_LOGE("Unknown node type: node-type=%d", parent->type); + return -EINVAL; + } + return 0; +} + +static int reparent_field_class_declarator(struct ctf_node *node, + struct ctf_node *parent) +{ + switch (parent->type) { + case NODE_TYPE_DECLARATOR: + parent->u.field_class_declarator.type = TYPEDEC_NESTED; + parent->u.field_class_declarator.u.nested.field_class_declarator = node; + break; + case NODE_STRUCT_OR_VARIANT_DECLARATION: + _bt_list_splice_tail(&node->tmp_head, &parent->u.struct_or_variant_declaration.field_class_declarators); + break; + case NODE_TYPEDEF: + _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_def.field_class_declarators); + break; + case NODE_TYPEALIAS_TARGET: + _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_alias_target.field_class_declarators); + break; + case NODE_TYPEALIAS_ALIAS: + _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_alias_name.field_class_declarators); + break; + + case NODE_ROOT: + case NODE_EVENT: + case NODE_STREAM: + case NODE_ENV: + case NODE_TRACE: + case NODE_CLOCK: + case NODE_CALLSITE: + case NODE_VARIANT: + case NODE_STRUCT: + case NODE_TYPEALIAS: + case NODE_ENUM: + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_CTF_EXPRESSION: + case NODE_TYPE_SPECIFIER: + case NODE_TYPE_SPECIFIER_LIST: + case NODE_POINTER: + case NODE_ENUMERATOR: + case NODE_UNARY_EXPRESSION: + return -EPERM; + + case NODE_UNKNOWN: + default: + BT_LOGE("Unknown node type: node-type=%d", parent->type); + return -EINVAL; + } + return 0; +} + +/* + * set_parent_node + * + * Link node to parent. Returns 0 on success, -EPERM if it is not permitted to + * create the link declared by the input, -ENOENT if node or parent is NULL, + * -EINVAL if there is an internal structure problem. + */ +static int set_parent_node(struct ctf_node *node, + struct ctf_node *parent) +{ + if (!node || !parent) + return -ENOENT; + + /* Note: Linking to parent will be done only by an external visitor */ + + switch (node->type) { + case NODE_ROOT: + BT_LOGE_STR("Trying to reparent root node."); + return -EINVAL; + + case NODE_EVENT: + if (parent->type == NODE_ROOT) { + _bt_list_splice_tail(&node->tmp_head, &parent->u.root.event); + } else { + return -EPERM; + } + break; + case NODE_STREAM: + if (parent->type == NODE_ROOT) { + _bt_list_splice_tail(&node->tmp_head, &parent->u.root.stream); + } else { + return -EPERM; + } + break; + case NODE_ENV: + if (parent->type == NODE_ROOT) { + _bt_list_splice_tail(&node->tmp_head, &parent->u.root.env); + } else { + return -EPERM; + } + break; + case NODE_TRACE: + if (parent->type == NODE_ROOT) { + _bt_list_splice_tail(&node->tmp_head, &parent->u.root.trace); + } else { + return -EPERM; + } + break; + case NODE_CLOCK: + if (parent->type == NODE_ROOT) { + _bt_list_splice_tail(&node->tmp_head, &parent->u.root.clock); + } else { + return -EPERM; + } + break; + case NODE_CALLSITE: + if (parent->type == NODE_ROOT) { + _bt_list_splice_tail(&node->tmp_head, &parent->u.root.callsite); + } else { + return -EPERM; + } + break; + + case NODE_CTF_EXPRESSION: + return reparent_ctf_expression(node, parent); + case NODE_UNARY_EXPRESSION: + if (parent->type == NODE_TYPE_DECLARATOR) + parent->u.field_class_declarator.bitfield_len = node; + else + return -EPERM; + break; + + case NODE_TYPEDEF: + return reparent_typedef(node, parent); + case NODE_TYPEALIAS_TARGET: + if (parent->type == NODE_TYPEALIAS) + parent->u.field_class_alias.target = node; + else + return -EINVAL; + /* fall-through */ + case NODE_TYPEALIAS_ALIAS: + if (parent->type == NODE_TYPEALIAS) + parent->u.field_class_alias.alias = node; + else + return -EINVAL; + /* fall-through */ + case NODE_TYPEALIAS: + return reparent_field_class_alias(node, parent); + + case NODE_POINTER: + if (parent->type == NODE_TYPE_DECLARATOR) { + _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_declarator.pointers); + } else + return -EPERM; + break; + case NODE_TYPE_DECLARATOR: + return reparent_field_class_declarator(node, parent); + + case NODE_TYPE_SPECIFIER_LIST: + return reparent_field_class_specifier_list(node, parent); + + case NODE_TYPE_SPECIFIER: + return reparent_field_class_specifier(node, parent); + + case NODE_FLOATING_POINT: + case NODE_INTEGER: + case NODE_STRING: + case NODE_ENUM: + case NODE_VARIANT: + case NODE_STRUCT: + return -EINVAL; /* Dealt with internally within grammar */ + + case NODE_ENUMERATOR: + if (parent->type == NODE_ENUM) { + _bt_list_splice_tail(&node->tmp_head, &parent->u._enum.enumerator_list); + } else { + return -EPERM; + } + break; + case NODE_STRUCT_OR_VARIANT_DECLARATION: + switch (parent->type) { + case NODE_STRUCT: + _bt_list_splice_tail(&node->tmp_head, &parent->u._struct.declaration_list); + break; + case NODE_VARIANT: + _bt_list_splice_tail(&node->tmp_head, &parent->u.variant.declaration_list); + break; + default: + return -EINVAL; + } + break; + + case NODE_UNKNOWN: + default: + BT_LOGE("Unknown node type: node-type=%d", parent->type); + return -EINVAL; + } + return 0; +} + +static +void yyerror(struct ctf_scanner *scanner, yyscan_t yyscanner, const char *str) +{ + _BT_LOGE_APPEND_CAUSE_LINENO(yyget_lineno(scanner->scanner), + "%s: token=\"%s\"", str, yyget_text(scanner->scanner)); +} + +#define reparent_error(scanner, str) \ +do { \ + yyerror(scanner, scanner->scanner, YY_("reparent_error: " str)); \ + YYERROR; \ +} while (0) + +static struct ctf_ast *ctf_ast_alloc(struct ctf_scanner *scanner) +{ + struct ctf_ast *ast; + + ast = (ctf_ast *) objstack_alloc(scanner->objstack, sizeof(*ast)); + if (!ast) + return NULL; + ast->root.type = NODE_ROOT; + BT_INIT_LIST_HEAD(&ast->root.tmp_head); + BT_INIT_LIST_HEAD(&ast->root.u.root.declaration_list); + BT_INIT_LIST_HEAD(&ast->root.u.root.trace); + BT_INIT_LIST_HEAD(&ast->root.u.root.env); + BT_INIT_LIST_HEAD(&ast->root.u.root.stream); + BT_INIT_LIST_HEAD(&ast->root.u.root.event); + BT_INIT_LIST_HEAD(&ast->root.u.root.clock); + BT_INIT_LIST_HEAD(&ast->root.u.root.callsite); + return ast; +} + +int ctf_scanner_append_ast(struct ctf_scanner *scanner, FILE *input) +{ + /* Start processing new stream */ + yyrestart(input, scanner->scanner); + return yyparse(scanner, scanner->scanner); +} + +struct ctf_scanner *ctf_scanner_alloc(void) +{ + struct ctf_scanner *scanner; + int ret; + + scanner = (ctf_scanner *) malloc(sizeof(*scanner)); + if (!scanner) + return NULL; + memset(scanner, 0, sizeof(*scanner)); + ret = yylex_init_extra(scanner, &scanner->scanner); + if (ret) { + BT_LOGE("yylex_init_extra() failed: ret=%d", ret); + goto cleanup_scanner; + } + scanner->objstack = objstack_create(); + if (!scanner->objstack) + goto cleanup_lexer; + scanner->ast = ctf_ast_alloc(scanner); + if (!scanner->ast) + goto cleanup_objstack; + init_scope(&scanner->root_scope, NULL); + scanner->cs = &scanner->root_scope; + + return scanner; + +cleanup_objstack: + objstack_destroy(scanner->objstack); +cleanup_lexer: + ret = yylex_destroy(scanner->scanner); + if (!ret) + BT_LOGE("yylex_destroy() failed: scanner-addr=%p, ret=%d", + scanner, ret); +cleanup_scanner: + free(scanner); + return NULL; +} + +void ctf_scanner_free(struct ctf_scanner *scanner) +{ + int ret; + + if (!scanner) + return; + + struct ctf_scanner_scope *scope = scanner->cs; + + do { + struct ctf_scanner_scope *parent = scope->parent; + finalize_scope(scope); + + /* + * The root scope is allocated within the ctf_scanner structure, + * do doesn't need freeing. All others are allocated on their + * own. + */ + if (scope != &scanner->root_scope) + free(scope); + + scope = parent; + } while (scope); + + objstack_destroy(scanner->objstack); + ret = yylex_destroy(scanner->scanner); + if (ret) + BT_LOGE("yylex_destroy() failed: scanner-addr=%p, ret=%d", + scanner, ret); + free(scanner); +} + +/* + * The bison-provided version of strlen (yystrlen) generates a benign + * -Wnull-dereference warning. That version is used when building on cygwin, + * for example, but you can also enable it by hand (to test) by removing the + * preprocessor conditional around it. + * + * Define yystrlen such that it will always use strlen. As far as we know, + * strlen provided by all the platforms we use is reliable. + */ +#define yystrlen strlen + +%} + +/* + * This ends up in parser.h and makes sure those who want to include it pass + * through parser-wrap.h. + */ +%code requires { +#ifndef ALLOW_INCLUDE_PARSER_H +# error "Don't include parser.h directly, include parser-wrap.h instead." +#endif +} + +%code provides { + BT_HIDDEN + void setstring(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src); + + BT_HIDDEN + int import_string(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src, char delim); +} + +%define api.pure + /* %locations */ +%error-verbose +%parse-param {struct ctf_scanner *scanner} +%parse-param {yyscan_t yyscanner} +%lex-param {yyscan_t yyscanner} +/* + * Expect two shift-reduce conflicts. Caused by enum name-opt : type {} + * vs struct { int :value; } (unnamed bit-field). The default is to + * shift, so whenever we encounter an enumeration, we are doing the + * proper thing (shift). It is illegal to declare an enumeration + * "bit-field", so it is OK if this situation ends up in a parsing + * error. + */ +%expect 2 +%start file +%token CTF_INTEGER_LITERAL CTF_STRING_LITERAL CTF_CHARACTER_LITERAL CTF_LSBRAC CTF_RSBRAC CTF_LPAREN CTF_RPAREN CTF_LBRAC CTF_RBRAC CTF_RARROW CTF_STAR CTF_PLUS CTF_MINUS CTF_LT CTF_GT CTF_TYPEASSIGN CTF_COLON CTF_SEMICOLON CTF_DOTDOTDOT CTF_DOT CTF_EQUAL CTF_COMMA CTF_CONST CTF_CHAR CTF_DOUBLE CTF_ENUM CTF_ENV CTF_EVENT CTF_FLOATING_POINT CTF_FLOAT CTF_INTEGER CTF_INT CTF_LONG CTF_SHORT CTF_SIGNED CTF_STREAM CTF_STRING CTF_STRUCT CTF_TRACE CTF_CALLSITE CTF_CLOCK CTF_TYPEALIAS CTF_TYPEDEF CTF_UNSIGNED CTF_VARIANT CTF_VOID CTF_BOOL CTF_COMPLEX CTF_IMAGINARY CTF_TOK_ALIGN +%token IDENTIFIER ID_TYPE +%token CTF_ERROR +%union +{ + long long ll; + unsigned long long ull; + char c; + char *s; + struct ctf_node *n; +} + +%type CTF_STRING_LITERAL CTF_CHARACTER_LITERAL + +%type keywords + +%type CTF_INTEGER_LITERAL +%type postfix_expression unary_expression unary_expression_or_range + +%type declaration +%type event_declaration +%type stream_declaration +%type env_declaration +%type trace_declaration +%type clock_declaration +%type callsite_declaration +%type integer_declaration_specifiers +%type declaration_specifiers +%type alias_declaration_specifiers + +%type field_class_declarator_list +%type integer_field_class_specifier +%type field_class_specifier +%type struct_class_specifier +%type variant_field_class_specifier +%type enum_field_class_specifier +%type struct_or_variant_declaration_list +%type struct_or_variant_declaration +%type struct_or_variant_declarator_list +%type struct_or_variant_declarator +%type enumerator_list +%type enumerator +%type abstract_declarator_list +%type abstract_declarator +%type direct_abstract_declarator +%type alias_abstract_declarator_list +%type alias_abstract_declarator +%type direct_alias_abstract_declarator +%type declarator +%type direct_declarator +%type field_class_declarator +%type direct_field_class_declarator +%type pointer +%type ctf_assignment_expression_list +%type ctf_assignment_expression + +%% + +file: + declaration + { + if (set_parent_node($1, &ctf_scanner_get_ast(scanner)->root)) + reparent_error(scanner, "error reparenting to root"); + } + | file declaration + { + if (set_parent_node($2, &ctf_scanner_get_ast(scanner)->root)) + reparent_error(scanner, "error reparenting to root"); + } + ; + +keywords: + CTF_VOID + { $$ = yylval.s; } + | CTF_CHAR + { $$ = yylval.s; } + | CTF_SHORT + { $$ = yylval.s; } + | CTF_INT + { $$ = yylval.s; } + | CTF_LONG + { $$ = yylval.s; } + | CTF_FLOAT + { $$ = yylval.s; } + | CTF_DOUBLE + { $$ = yylval.s; } + | CTF_SIGNED + { $$ = yylval.s; } + | CTF_UNSIGNED + { $$ = yylval.s; } + | CTF_BOOL + { $$ = yylval.s; } + | CTF_COMPLEX + { $$ = yylval.s; } + | CTF_IMAGINARY + { $$ = yylval.s; } + | CTF_FLOATING_POINT + { $$ = yylval.s; } + | CTF_INTEGER + { $$ = yylval.s; } + | CTF_STRING + { $$ = yylval.s; } + | CTF_ENUM + { $$ = yylval.s; } + | CTF_VARIANT + { $$ = yylval.s; } + | CTF_STRUCT + { $$ = yylval.s; } + | CTF_CONST + { $$ = yylval.s; } + | CTF_TYPEDEF + { $$ = yylval.s; } + | CTF_EVENT + { $$ = yylval.s; } + | CTF_STREAM + { $$ = yylval.s; } + | CTF_ENV + { $$ = yylval.s; } + | CTF_TRACE + { $$ = yylval.s; } + | CTF_CLOCK + { $$ = yylval.s; } + | CTF_CALLSITE + { $$ = yylval.s; } + | CTF_TOK_ALIGN + { $$ = yylval.s; } + ; + + +/* 2: Phrase structure grammar */ + +postfix_expression: + IDENTIFIER + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_STRING; + $$->u.unary_expression.u.string = yylval.s; + } + | ID_TYPE + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_STRING; + $$->u.unary_expression.u.string = yylval.s; + } + | keywords + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_STRING; + $$->u.unary_expression.u.string = yylval.s; + } + | CTF_INTEGER_LITERAL + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_UNSIGNED_CONSTANT; + $$->u.unary_expression.u.unsigned_constant = $1; + } + | CTF_STRING_LITERAL + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_STRING; + $$->u.unary_expression.u.string = $1; + } + | CTF_CHARACTER_LITERAL + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_STRING; + $$->u.unary_expression.u.string = $1; + } + | CTF_LPAREN unary_expression CTF_RPAREN + { + $$ = $2; + } + | postfix_expression CTF_LSBRAC unary_expression CTF_RSBRAC + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_SBRAC; + $$->u.unary_expression.u.sbrac_exp = $3; + bt_list_splice(&($1)->tmp_head, &($$)->tmp_head); + bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); + } + | postfix_expression CTF_DOT IDENTIFIER + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_STRING; + $$->u.unary_expression.u.string = yylval.s; + $$->u.unary_expression.link = UNARY_DOTLINK; + bt_list_splice(&($1)->tmp_head, &($$)->tmp_head); + bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); + } + | postfix_expression CTF_DOT ID_TYPE + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_STRING; + $$->u.unary_expression.u.string = yylval.s; + $$->u.unary_expression.link = UNARY_DOTLINK; + bt_list_splice(&($1)->tmp_head, &($$)->tmp_head); + bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); + } + | postfix_expression CTF_DOT keywords + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_STRING; + $$->u.unary_expression.u.string = yylval.s; + $$->u.unary_expression.link = UNARY_DOTLINK; + bt_list_splice(&($1)->tmp_head, &($$)->tmp_head); + bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); + } + | postfix_expression CTF_RARROW IDENTIFIER + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_STRING; + $$->u.unary_expression.u.string = yylval.s; + $$->u.unary_expression.link = UNARY_ARROWLINK; + bt_list_splice(&($1)->tmp_head, &($$)->tmp_head); + bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); + } + | postfix_expression CTF_RARROW ID_TYPE + { + $$ = make_node(scanner, NODE_UNARY_EXPRESSION); + $$->u.unary_expression.type = UNARY_STRING; + $$->u.unary_expression.u.string = yylval.s; + $$->u.unary_expression.link = UNARY_ARROWLINK; + bt_list_splice(&($1)->tmp_head, &($$)->tmp_head); + bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); + } + ; + +unary_expression: + postfix_expression + { $$ = $1; } + | CTF_PLUS postfix_expression + { + $$ = $2; + if ($$->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT + && $$->u.unary_expression.type != UNARY_SIGNED_CONSTANT) { + reparent_error(scanner, "expecting numeric constant"); + } + } + | CTF_MINUS postfix_expression + { + $$ = $2; + if ($$->u.unary_expression.type == UNARY_UNSIGNED_CONSTANT) { + $$->u.unary_expression.type = UNARY_SIGNED_CONSTANT; + $$->u.unary_expression.u.signed_constant = + -($$->u.unary_expression.u.unsigned_constant); + } else if ($$->u.unary_expression.type == UNARY_SIGNED_CONSTANT) { + $$->u.unary_expression.u.signed_constant = + -($$->u.unary_expression.u.signed_constant); + } else { + reparent_error(scanner, "expecting numeric constant"); + } + } + ; + +unary_expression_or_range: + unary_expression CTF_DOTDOTDOT unary_expression + { + $$ = $1; + _bt_list_splice_tail(&($3)->tmp_head, &($$)->tmp_head); + $3->u.unary_expression.link = UNARY_DOTDOTDOT; + } + | unary_expression + { $$ = $1; } + ; + +/* 2.2: Declarations */ + +declaration: + declaration_specifiers CTF_SEMICOLON + { $$ = $1; } + | event_declaration + { $$ = $1; } + | stream_declaration + { $$ = $1; } + | env_declaration + { $$ = $1; } + | trace_declaration + { $$ = $1; } + | clock_declaration + { $$ = $1; } + | callsite_declaration + { $$ = $1; } + | declaration_specifiers CTF_TYPEDEF declaration_specifiers field_class_declarator_list CTF_SEMICOLON + { + struct ctf_node *list; + + $$ = make_node(scanner, NODE_TYPEDEF); + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_def.field_class_specifier_list = list; + _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($3)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($4)->tmp_head, &($$)->u.field_class_def.field_class_declarators); + } + | CTF_TYPEDEF declaration_specifiers field_class_declarator_list CTF_SEMICOLON + { + struct ctf_node *list; + + $$ = make_node(scanner, NODE_TYPEDEF); + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_def.field_class_specifier_list = list; + _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators); + } + | declaration_specifiers CTF_TYPEDEF field_class_declarator_list CTF_SEMICOLON + { + struct ctf_node *list; + + $$ = make_node(scanner, NODE_TYPEDEF); + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_def.field_class_specifier_list = list; + _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators); + } + | CTF_TYPEALIAS declaration_specifiers abstract_declarator_list CTF_TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list CTF_SEMICOLON + { + struct ctf_node *list; + + $$ = make_node(scanner, NODE_TYPEALIAS); + $$->u.field_class_alias.target = make_node(scanner, NODE_TYPEALIAS_TARGET); + $$->u.field_class_alias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS); + + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_alias.target->u.field_class_alias_target.field_class_specifier_list = list; + _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_alias.target->u.field_class_alias_target.field_class_declarators); + + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_alias.alias->u.field_class_alias_name.field_class_specifier_list = list; + _bt_list_splice_tail(&($5)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.field_class_alias.alias->u.field_class_alias_name.field_class_declarators); + } + ; + +event_declaration: + event_declaration_begin event_declaration_end + { + $$ = make_node(scanner, NODE_EVENT); + } + | event_declaration_begin ctf_assignment_expression_list event_declaration_end + { + $$ = make_node(scanner, NODE_EVENT); + if (set_parent_node($2, $$)) + reparent_error(scanner, "event_declaration"); + } + ; + +event_declaration_begin: + CTF_EVENT CTF_LBRAC + { push_scope(scanner); } + ; + +event_declaration_end: + CTF_RBRAC CTF_SEMICOLON + { pop_scope(scanner); } + ; + + +stream_declaration: + stream_declaration_begin stream_declaration_end + { + $$ = make_node(scanner, NODE_STREAM); + } + | stream_declaration_begin ctf_assignment_expression_list stream_declaration_end + { + $$ = make_node(scanner, NODE_STREAM); + if (set_parent_node($2, $$)) + reparent_error(scanner, "stream_declaration"); + } + ; + +stream_declaration_begin: + CTF_STREAM CTF_LBRAC + { push_scope(scanner); } + ; + +stream_declaration_end: + CTF_RBRAC CTF_SEMICOLON + { pop_scope(scanner); } + ; + +env_declaration: + env_declaration_begin env_declaration_end + { + $$ = make_node(scanner, NODE_ENV); + } + | env_declaration_begin ctf_assignment_expression_list env_declaration_end + { + $$ = make_node(scanner, NODE_ENV); + if (set_parent_node($2, $$)) + reparent_error(scanner, "env declaration"); + } + ; + +env_declaration_begin: + CTF_ENV CTF_LBRAC + { push_scope(scanner); } + ; + +env_declaration_end: + CTF_RBRAC CTF_SEMICOLON + { pop_scope(scanner); } + ; + +trace_declaration: + trace_declaration_begin trace_declaration_end + { + $$ = make_node(scanner, NODE_TRACE); + } + | trace_declaration_begin ctf_assignment_expression_list trace_declaration_end + { + $$ = make_node(scanner, NODE_TRACE); + if (set_parent_node($2, $$)) + reparent_error(scanner, "trace_declaration"); + } + ; + +trace_declaration_begin: + CTF_TRACE CTF_LBRAC + { push_scope(scanner); } + ; + +trace_declaration_end: + CTF_RBRAC CTF_SEMICOLON + { pop_scope(scanner); } + ; + +clock_declaration: + CTF_CLOCK clock_declaration_begin clock_declaration_end + { + $$ = make_node(scanner, NODE_CLOCK); + } + | CTF_CLOCK clock_declaration_begin ctf_assignment_expression_list clock_declaration_end + { + $$ = make_node(scanner, NODE_CLOCK); + if (set_parent_node($3, $$)) + reparent_error(scanner, "trace_declaration"); + } + ; + +clock_declaration_begin: + CTF_LBRAC + { push_scope(scanner); } + ; + +clock_declaration_end: + CTF_RBRAC CTF_SEMICOLON + { pop_scope(scanner); } + ; + +callsite_declaration: + CTF_CALLSITE callsite_declaration_begin callsite_declaration_end + { + $$ = make_node(scanner, NODE_CALLSITE); + } + | CTF_CALLSITE callsite_declaration_begin ctf_assignment_expression_list callsite_declaration_end + { + $$ = make_node(scanner, NODE_CALLSITE); + if (set_parent_node($3, $$)) + reparent_error(scanner, "trace_declaration"); + } + ; + +callsite_declaration_begin: + CTF_LBRAC + { push_scope(scanner); } + ; + +callsite_declaration_end: + CTF_RBRAC CTF_SEMICOLON + { pop_scope(scanner); } + ; + +integer_declaration_specifiers: + CTF_CONST + { + struct ctf_node *node; + + $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + node = make_node(scanner, NODE_TYPE_SPECIFIER); + node->u.field_class_specifier.type = TYPESPEC_CONST; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + | integer_field_class_specifier + { + struct ctf_node *node; + + $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + node = $1; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + | integer_declaration_specifiers CTF_CONST + { + struct ctf_node *node; + + $$ = $1; + node = make_node(scanner, NODE_TYPE_SPECIFIER); + node->u.field_class_specifier.type = TYPESPEC_CONST; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + | integer_declaration_specifiers integer_field_class_specifier + { + $$ = $1; + bt_list_add_tail(&($2)->siblings, &($$)->u.field_class_specifier_list.head); + } + ; + +declaration_specifiers: + CTF_CONST + { + struct ctf_node *node; + + $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + node = make_node(scanner, NODE_TYPE_SPECIFIER); + node->u.field_class_specifier.type = TYPESPEC_CONST; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + | field_class_specifier + { + struct ctf_node *node; + + $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + node = $1; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + | declaration_specifiers CTF_CONST + { + struct ctf_node *node; + + $$ = $1; + node = make_node(scanner, NODE_TYPE_SPECIFIER); + node->u.field_class_specifier.type = TYPESPEC_CONST; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + | declaration_specifiers field_class_specifier + { + $$ = $1; + bt_list_add_tail(&($2)->siblings, &($$)->u.field_class_specifier_list.head); + } + ; + +field_class_declarator_list: + field_class_declarator + { $$ = $1; } + | field_class_declarator_list CTF_COMMA field_class_declarator + { + $$ = $1; + bt_list_add_tail(&($3)->siblings, &($$)->tmp_head); + } + ; + +integer_field_class_specifier: + CTF_CHAR + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_CHAR; + } + | CTF_SHORT + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_SHORT; + } + | CTF_INT + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_INT; + } + | CTF_LONG + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_LONG; + } + | CTF_SIGNED + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_SIGNED; + } + | CTF_UNSIGNED + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_UNSIGNED; + } + | CTF_BOOL + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_BOOL; + } + | ID_TYPE + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_ID_TYPE; + $$->u.field_class_specifier.id_type = yylval.s; + } + | CTF_INTEGER CTF_LBRAC CTF_RBRAC + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_INTEGER; + $$->u.field_class_specifier.node = make_node(scanner, NODE_INTEGER); + } + | CTF_INTEGER CTF_LBRAC ctf_assignment_expression_list CTF_RBRAC + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_INTEGER; + $$->u.field_class_specifier.node = make_node(scanner, NODE_INTEGER); + if (set_parent_node($3, $$->u.field_class_specifier.node)) + reparent_error(scanner, "integer reparent error"); + } + ; + +field_class_specifier: + CTF_VOID + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_VOID; + } + | CTF_CHAR + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_CHAR; + } + | CTF_SHORT + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_SHORT; + } + | CTF_INT + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_INT; + } + | CTF_LONG + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_LONG; + } + | CTF_FLOAT + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_FLOAT; + } + | CTF_DOUBLE + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_DOUBLE; + } + | CTF_SIGNED + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_SIGNED; + } + | CTF_UNSIGNED + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_UNSIGNED; + } + | CTF_BOOL + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_BOOL; + } + | CTF_COMPLEX + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_COMPLEX; + } + | CTF_IMAGINARY + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_IMAGINARY; + } + | ID_TYPE + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_ID_TYPE; + $$->u.field_class_specifier.id_type = yylval.s; + } + | CTF_FLOATING_POINT CTF_LBRAC CTF_RBRAC + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_FLOATING_POINT; + $$->u.field_class_specifier.node = make_node(scanner, NODE_FLOATING_POINT); + } + | CTF_FLOATING_POINT CTF_LBRAC ctf_assignment_expression_list CTF_RBRAC + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_FLOATING_POINT; + $$->u.field_class_specifier.node = make_node(scanner, NODE_FLOATING_POINT); + if (set_parent_node($3, $$->u.field_class_specifier.node)) + reparent_error(scanner, "floating point reparent error"); + } + | CTF_INTEGER CTF_LBRAC CTF_RBRAC + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_INTEGER; + $$->u.field_class_specifier.node = make_node(scanner, NODE_INTEGER); + } + | CTF_INTEGER CTF_LBRAC ctf_assignment_expression_list CTF_RBRAC + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_INTEGER; + $$->u.field_class_specifier.node = make_node(scanner, NODE_INTEGER); + if (set_parent_node($3, $$->u.field_class_specifier.node)) + reparent_error(scanner, "integer reparent error"); + } + | CTF_STRING + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_STRING; + $$->u.field_class_specifier.node = make_node(scanner, NODE_STRING); + } + | CTF_STRING CTF_LBRAC CTF_RBRAC + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_STRING; + $$->u.field_class_specifier.node = make_node(scanner, NODE_STRING); + } + | CTF_STRING CTF_LBRAC ctf_assignment_expression_list CTF_RBRAC + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_STRING; + $$->u.field_class_specifier.node = make_node(scanner, NODE_STRING); + if (set_parent_node($3, $$->u.field_class_specifier.node)) + reparent_error(scanner, "string reparent error"); + } + | CTF_ENUM enum_field_class_specifier + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_ENUM; + $$->u.field_class_specifier.node = $2; + } + | CTF_VARIANT variant_field_class_specifier + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_VARIANT; + $$->u.field_class_specifier.node = $2; + } + | CTF_STRUCT struct_class_specifier + { + $$ = make_node(scanner, NODE_TYPE_SPECIFIER); + $$->u.field_class_specifier.type = TYPESPEC_STRUCT; + $$->u.field_class_specifier.node = $2; + } + ; + +struct_class_specifier: + struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end + { + $$ = make_node(scanner, NODE_STRUCT); + $$->u._struct.has_body = 1; + if ($2 && set_parent_node($2, $$)) + reparent_error(scanner, "struct reparent error"); + } + | IDENTIFIER struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end + { + $$ = make_node(scanner, NODE_STRUCT); + $$->u._struct.has_body = 1; + $$->u._struct.name = $1; + if ($3 && set_parent_node($3, $$)) + reparent_error(scanner, "struct reparent error"); + } + | ID_TYPE struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end + { + $$ = make_node(scanner, NODE_STRUCT); + $$->u._struct.has_body = 1; + $$->u._struct.name = $1; + if ($3 && set_parent_node($3, $$)) + reparent_error(scanner, "struct reparent error"); + } + | IDENTIFIER + { + $$ = make_node(scanner, NODE_STRUCT); + $$->u._struct.has_body = 0; + $$->u._struct.name = $1; + } + | ID_TYPE + { + $$ = make_node(scanner, NODE_STRUCT); + $$->u._struct.has_body = 0; + $$->u._struct.name = $1; + } + | struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end CTF_TOK_ALIGN CTF_LPAREN unary_expression CTF_RPAREN + { + $$ = make_node(scanner, NODE_STRUCT); + $$->u._struct.has_body = 1; + bt_list_add_tail(&($6)->siblings, &$$->u._struct.min_align); + if ($2 && set_parent_node($2, $$)) + reparent_error(scanner, "struct reparent error"); + } + | IDENTIFIER struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end CTF_TOK_ALIGN CTF_LPAREN unary_expression CTF_RPAREN + { + $$ = make_node(scanner, NODE_STRUCT); + $$->u._struct.has_body = 1; + $$->u._struct.name = $1; + bt_list_add_tail(&($7)->siblings, &$$->u._struct.min_align); + if ($3 && set_parent_node($3, $$)) + reparent_error(scanner, "struct reparent error"); + } + | ID_TYPE struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end CTF_TOK_ALIGN CTF_LPAREN unary_expression CTF_RPAREN + { + $$ = make_node(scanner, NODE_STRUCT); + $$->u._struct.has_body = 1; + $$->u._struct.name = $1; + bt_list_add_tail(&($7)->siblings, &$$->u._struct.min_align); + if ($3 && set_parent_node($3, $$)) + reparent_error(scanner, "struct reparent error"); + } + ; + +struct_declaration_begin: + CTF_LBRAC + { push_scope(scanner); } + ; + +struct_declaration_end: + CTF_RBRAC + { pop_scope(scanner); } + ; + +variant_field_class_specifier: + variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 1; + if ($2 && set_parent_node($2, $$)) + reparent_error(scanner, "variant reparent error"); + } + | CTF_LT IDENTIFIER CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 1; + $$->u.variant.choice = $2; + if ($5 && set_parent_node($5, $$)) + reparent_error(scanner, "variant reparent error"); + } + | CTF_LT ID_TYPE CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 1; + $$->u.variant.choice = $2; + if ($5 && set_parent_node($5, $$)) + reparent_error(scanner, "variant reparent error"); + } + | IDENTIFIER variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 1; + $$->u.variant.name = $1; + if ($3 && set_parent_node($3, $$)) + reparent_error(scanner, "variant reparent error"); + } + | IDENTIFIER CTF_LT IDENTIFIER CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 1; + $$->u.variant.name = $1; + $$->u.variant.choice = $3; + if ($6 && set_parent_node($6, $$)) + reparent_error(scanner, "variant reparent error"); + } + | IDENTIFIER CTF_LT IDENTIFIER CTF_GT + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 0; + $$->u.variant.name = $1; + $$->u.variant.choice = $3; + } + | IDENTIFIER CTF_LT ID_TYPE CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 1; + $$->u.variant.name = $1; + $$->u.variant.choice = $3; + if ($6 && set_parent_node($6, $$)) + reparent_error(scanner, "variant reparent error"); + } + | IDENTIFIER CTF_LT ID_TYPE CTF_GT + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 0; + $$->u.variant.name = $1; + $$->u.variant.choice = $3; + } + | ID_TYPE variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 1; + $$->u.variant.name = $1; + if ($3 && set_parent_node($3, $$)) + reparent_error(scanner, "variant reparent error"); + } + | ID_TYPE CTF_LT IDENTIFIER CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 1; + $$->u.variant.name = $1; + $$->u.variant.choice = $3; + if ($6 && set_parent_node($6, $$)) + reparent_error(scanner, "variant reparent error"); + } + | ID_TYPE CTF_LT IDENTIFIER CTF_GT + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 0; + $$->u.variant.name = $1; + $$->u.variant.choice = $3; + } + | ID_TYPE CTF_LT ID_TYPE CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 1; + $$->u.variant.name = $1; + $$->u.variant.choice = $3; + if ($6 && set_parent_node($6, $$)) + reparent_error(scanner, "variant reparent error"); + } + | ID_TYPE CTF_LT ID_TYPE CTF_GT + { + $$ = make_node(scanner, NODE_VARIANT); + $$->u.variant.has_body = 0; + $$->u.variant.name = $1; + $$->u.variant.choice = $3; + } + ; + +variant_declaration_begin: + CTF_LBRAC + { push_scope(scanner); } + ; + +variant_declaration_end: + CTF_RBRAC + { pop_scope(scanner); } + ; + +enum_field_class_specifier: + CTF_LBRAC enumerator_list CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + _bt_list_splice_tail(&($2)->tmp_head, &($$)->u._enum.enumerator_list); + } + | CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + ($$)->u._enum.container_field_class = $2; + _bt_list_splice_tail(&($4)->tmp_head, &($$)->u._enum.enumerator_list); + } + | IDENTIFIER CTF_LBRAC enumerator_list CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + $$->u._enum.enum_id = $1; + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._enum.enumerator_list); + } + | IDENTIFIER CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + $$->u._enum.enum_id = $1; + ($$)->u._enum.container_field_class = $3; + _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list); + } + | ID_TYPE CTF_LBRAC enumerator_list CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + $$->u._enum.enum_id = $1; + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._enum.enumerator_list); + } + | ID_TYPE CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + $$->u._enum.enum_id = $1; + ($$)->u._enum.container_field_class = $3; + _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list); + } + | CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + _bt_list_splice_tail(&($2)->tmp_head, &($$)->u._enum.enumerator_list); + } + | CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + ($$)->u._enum.container_field_class = $2; + _bt_list_splice_tail(&($4)->tmp_head, &($$)->u._enum.enumerator_list); + } + | IDENTIFIER CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + $$->u._enum.enum_id = $1; + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._enum.enumerator_list); + } + | IDENTIFIER CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + $$->u._enum.enum_id = $1; + ($$)->u._enum.container_field_class = $3; + _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list); + } + | IDENTIFIER + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 0; + $$->u._enum.enum_id = $1; + } + | ID_TYPE CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + $$->u._enum.enum_id = $1; + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._enum.enumerator_list); + } + | ID_TYPE CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 1; + $$->u._enum.enum_id = $1; + ($$)->u._enum.container_field_class = $3; + _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list); + } + | ID_TYPE + { + $$ = make_node(scanner, NODE_ENUM); + $$->u._enum.has_body = 0; + $$->u._enum.enum_id = $1; + } + ; + +struct_or_variant_declaration_list: + /* empty */ + { $$ = NULL; } + | struct_or_variant_declaration_list struct_or_variant_declaration + { + if ($1) { + $$ = $1; + bt_list_add_tail(&($2)->siblings, &($$)->tmp_head); + } else { + $$ = $2; + bt_list_add_tail(&($$)->siblings, &($$)->tmp_head); + } + } + ; + +struct_or_variant_declaration: + declaration_specifiers struct_or_variant_declarator_list CTF_SEMICOLON + { + struct ctf_node *list; + + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + $$ = make_node(scanner, NODE_STRUCT_OR_VARIANT_DECLARATION); + ($$)->u.struct_or_variant_declaration.field_class_specifier_list = list; + _bt_list_splice_tail(&($2)->tmp_head, &($$)->u.struct_or_variant_declaration.field_class_declarators); + } + | declaration_specifiers CTF_TYPEDEF declaration_specifiers field_class_declarator_list CTF_SEMICOLON + { + struct ctf_node *list; + + $$ = make_node(scanner, NODE_TYPEDEF); + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_def.field_class_specifier_list = list; + _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($3)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($4)->tmp_head, &($$)->u.field_class_def.field_class_declarators); + } + | CTF_TYPEDEF declaration_specifiers field_class_declarator_list CTF_SEMICOLON + { + struct ctf_node *list; + + $$ = make_node(scanner, NODE_TYPEDEF); + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_def.field_class_specifier_list = list; + _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators); + } + | declaration_specifiers CTF_TYPEDEF field_class_declarator_list CTF_SEMICOLON + { + struct ctf_node *list; + + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + $$ = make_node(scanner, NODE_TYPEDEF); + ($$)->u.struct_or_variant_declaration.field_class_specifier_list = list; + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators); + } + | CTF_TYPEALIAS declaration_specifiers abstract_declarator_list CTF_TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list CTF_SEMICOLON + { + struct ctf_node *list; + + $$ = make_node(scanner, NODE_TYPEALIAS); + $$->u.field_class_alias.target = make_node(scanner, NODE_TYPEALIAS_TARGET); + $$->u.field_class_alias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS); + + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_alias.target->u.field_class_alias_target.field_class_specifier_list = list; + _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_alias.target->u.field_class_alias_target.field_class_declarators); + + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_alias.alias->u.field_class_alias_name.field_class_specifier_list = list; + _bt_list_splice_tail(&($5)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.field_class_alias.alias->u.field_class_alias_name.field_class_declarators); + } + ; + +alias_declaration_specifiers: + CTF_CONST + { + struct ctf_node *node; + + $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + node = make_node(scanner, NODE_TYPE_SPECIFIER); + node->u.field_class_specifier.type = TYPESPEC_CONST; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + | field_class_specifier + { + struct ctf_node *node; + + $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + node = $1; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + | IDENTIFIER + { + struct ctf_node *node; + + add_type(scanner, $1); + $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + node = make_node(scanner, NODE_TYPE_SPECIFIER); + node->u.field_class_specifier.type = TYPESPEC_ID_TYPE; + node->u.field_class_specifier.id_type = yylval.s; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + | alias_declaration_specifiers CTF_CONST + { + struct ctf_node *node; + + $$ = $1; + node = make_node(scanner, NODE_TYPE_SPECIFIER); + node->u.field_class_specifier.type = TYPESPEC_CONST; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + | alias_declaration_specifiers field_class_specifier + { + $$ = $1; + bt_list_add_tail(&($2)->siblings, &($$)->u.field_class_specifier_list.head); + } + | alias_declaration_specifiers IDENTIFIER + { + struct ctf_node *node; + + add_type(scanner, $2); + $$ = $1; + node = make_node(scanner, NODE_TYPE_SPECIFIER); + node->u.field_class_specifier.type = TYPESPEC_ID_TYPE; + node->u.field_class_specifier.id_type = yylval.s; + bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head); + } + ; + +struct_or_variant_declarator_list: + struct_or_variant_declarator + { $$ = $1; } + | struct_or_variant_declarator_list CTF_COMMA struct_or_variant_declarator + { + $$ = $1; + bt_list_add_tail(&($3)->siblings, &($$)->tmp_head); + } + ; + +struct_or_variant_declarator: + declarator + { $$ = $1; } + | CTF_COLON unary_expression + { $$ = $2; } + | declarator CTF_COLON unary_expression + { + $$ = $1; + if (set_parent_node($3, $1)) + reparent_error(scanner, "struct_or_variant_declarator"); + } + ; + +enumerator_list: + enumerator + { $$ = $1; } + | enumerator_list CTF_COMMA enumerator + { + $$ = $1; + bt_list_add_tail(&($3)->siblings, &($$)->tmp_head); + } + ; + +enumerator: + IDENTIFIER + { + $$ = make_node(scanner, NODE_ENUMERATOR); + $$->u.enumerator.id = $1; + } + | ID_TYPE + { + $$ = make_node(scanner, NODE_ENUMERATOR); + $$->u.enumerator.id = $1; + } + | keywords + { + $$ = make_node(scanner, NODE_ENUMERATOR); + $$->u.enumerator.id = $1; + } + | CTF_STRING_LITERAL + { + $$ = make_node(scanner, NODE_ENUMERATOR); + $$->u.enumerator.id = $1; + } + | IDENTIFIER CTF_EQUAL unary_expression_or_range + { + $$ = make_node(scanner, NODE_ENUMERATOR); + $$->u.enumerator.id = $1; + bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values); + } + | ID_TYPE CTF_EQUAL unary_expression_or_range + { + $$ = make_node(scanner, NODE_ENUMERATOR); + $$->u.enumerator.id = $1; + bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values); + } + | keywords CTF_EQUAL unary_expression_or_range + { + $$ = make_node(scanner, NODE_ENUMERATOR); + $$->u.enumerator.id = $1; + bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values); + } + | CTF_STRING_LITERAL CTF_EQUAL unary_expression_or_range + { + $$ = make_node(scanner, NODE_ENUMERATOR); + $$->u.enumerator.id = $1; + bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values); + } + ; + +abstract_declarator_list: + abstract_declarator + { $$ = $1; } + | abstract_declarator_list CTF_COMMA abstract_declarator + { + $$ = $1; + bt_list_add_tail(&($3)->siblings, &($$)->tmp_head); + } + ; + +abstract_declarator: + direct_abstract_declarator + { $$ = $1; } + | pointer direct_abstract_declarator + { + $$ = $2; + bt_list_splice(&($1)->tmp_head, &($$)->u.field_class_declarator.pointers); + } + ; + +direct_abstract_declarator: + /* empty */ + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_ID; + /* id is NULL */ + } + | IDENTIFIER + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_ID; + $$->u.field_class_declarator.u.id = $1; + } + | CTF_LPAREN abstract_declarator CTF_RPAREN + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_NESTED; + $$->u.field_class_declarator.u.nested.field_class_declarator = $2; + } + | direct_abstract_declarator CTF_LSBRAC unary_expression CTF_RSBRAC + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_NESTED; + $$->u.field_class_declarator.u.nested.field_class_declarator = $1; + BT_INIT_LIST_HEAD(&($$)->u.field_class_declarator.u.nested.length); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_declarator.u.nested.length); + } + | direct_abstract_declarator CTF_LSBRAC CTF_RSBRAC + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_NESTED; + $$->u.field_class_declarator.u.nested.field_class_declarator = $1; + $$->u.field_class_declarator.u.nested.abstract_array = 1; + } + ; + +alias_abstract_declarator_list: + alias_abstract_declarator + { $$ = $1; } + | alias_abstract_declarator_list CTF_COMMA alias_abstract_declarator + { + $$ = $1; + bt_list_add_tail(&($3)->siblings, &($$)->tmp_head); + } + ; + +alias_abstract_declarator: + direct_alias_abstract_declarator + { $$ = $1; } + | pointer direct_alias_abstract_declarator + { + $$ = $2; + bt_list_splice(&($1)->tmp_head, &($$)->u.field_class_declarator.pointers); + } + ; + +direct_alias_abstract_declarator: + /* empty */ + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_ID; + /* id is NULL */ + } + | CTF_LPAREN alias_abstract_declarator CTF_RPAREN + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_NESTED; + $$->u.field_class_declarator.u.nested.field_class_declarator = $2; + } + | direct_alias_abstract_declarator CTF_LSBRAC unary_expression CTF_RSBRAC + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_NESTED; + $$->u.field_class_declarator.u.nested.field_class_declarator = $1; + BT_INIT_LIST_HEAD(&($$)->u.field_class_declarator.u.nested.length); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_declarator.u.nested.length); + } + | direct_alias_abstract_declarator CTF_LSBRAC CTF_RSBRAC + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_NESTED; + $$->u.field_class_declarator.u.nested.field_class_declarator = $1; + $$->u.field_class_declarator.u.nested.abstract_array = 1; + } + ; + +declarator: + direct_declarator + { $$ = $1; } + | pointer direct_declarator + { + $$ = $2; + bt_list_splice(&($1)->tmp_head, &($$)->u.field_class_declarator.pointers); + } + ; + +direct_declarator: + IDENTIFIER + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_ID; + $$->u.field_class_declarator.u.id = $1; + } + | CTF_LPAREN declarator CTF_RPAREN + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_NESTED; + $$->u.field_class_declarator.u.nested.field_class_declarator = $2; + } + | direct_declarator CTF_LSBRAC unary_expression CTF_RSBRAC + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_NESTED; + $$->u.field_class_declarator.u.nested.field_class_declarator = $1; + BT_INIT_LIST_HEAD(&($$)->u.field_class_declarator.u.nested.length); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_declarator.u.nested.length); + } + ; + +field_class_declarator: + direct_field_class_declarator + { $$ = $1; } + | pointer direct_field_class_declarator + { + $$ = $2; + bt_list_splice(&($1)->tmp_head, &($$)->u.field_class_declarator.pointers); + } + ; + +direct_field_class_declarator: + IDENTIFIER + { + add_type(scanner, $1); + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_ID; + $$->u.field_class_declarator.u.id = $1; + } + | CTF_LPAREN field_class_declarator CTF_RPAREN + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_NESTED; + $$->u.field_class_declarator.u.nested.field_class_declarator = $2; + } + | direct_field_class_declarator CTF_LSBRAC unary_expression CTF_RSBRAC + { + $$ = make_node(scanner, NODE_TYPE_DECLARATOR); + $$->u.field_class_declarator.type = TYPEDEC_NESTED; + $$->u.field_class_declarator.u.nested.field_class_declarator = $1; + BT_INIT_LIST_HEAD(&($$)->u.field_class_declarator.u.nested.length); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_declarator.u.nested.length); + } + ; + +pointer: + CTF_STAR + { + $$ = make_node(scanner, NODE_POINTER); + } + | CTF_STAR pointer + { + $$ = make_node(scanner, NODE_POINTER); + bt_list_splice(&($2)->tmp_head, &($$)->tmp_head); + } + | CTF_STAR type_qualifier_list pointer + { + $$ = make_node(scanner, NODE_POINTER); + $$->u.pointer.const_qualifier = 1; + bt_list_splice(&($3)->tmp_head, &($$)->tmp_head); + } + ; + +type_qualifier_list: + /* pointer assumes only const type qualifier */ + CTF_CONST + | type_qualifier_list CTF_CONST + ; + +/* 2.3: CTF-specific declarations */ + +ctf_assignment_expression_list: + ctf_assignment_expression CTF_SEMICOLON + { $$ = $1; } + | ctf_assignment_expression_list ctf_assignment_expression CTF_SEMICOLON + { + $$ = $1; + bt_list_add_tail(&($2)->siblings, &($$)->tmp_head); + } + ; + +ctf_assignment_expression: + unary_expression CTF_EQUAL unary_expression + { + /* + * Because we have left and right, cannot use + * set_parent_node. + */ + $$ = make_node(scanner, NODE_CTF_EXPRESSION); + _bt_list_splice_tail(&($1)->tmp_head, &($$)->u.ctf_expression.left); + if ($1->u.unary_expression.type != UNARY_STRING) + reparent_error(scanner, "ctf_assignment_expression left expects string"); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.ctf_expression.right); + } + | unary_expression CTF_TYPEASSIGN declaration_specifiers /* Only allow struct */ + { + /* + * Because we have left and right, cannot use + * set_parent_node. + */ + $$ = make_node(scanner, NODE_CTF_EXPRESSION); + _bt_list_splice_tail(&($1)->tmp_head, &($$)->u.ctf_expression.left); + if ($1->u.unary_expression.type != UNARY_STRING) + reparent_error(scanner, "ctf_assignment_expression left expects string"); + bt_list_add_tail(&($3)->siblings, &($$)->u.ctf_expression.right); + } + | declaration_specifiers CTF_TYPEDEF declaration_specifiers field_class_declarator_list + { + struct ctf_node *list; + + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($3)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + $$ = make_node(scanner, NODE_TYPEDEF); + ($$)->u.struct_or_variant_declaration.field_class_specifier_list = list; + _bt_list_splice_tail(&($4)->tmp_head, &($$)->u.field_class_def.field_class_declarators); + } + | CTF_TYPEDEF declaration_specifiers field_class_declarator_list + { + struct ctf_node *list; + + $$ = make_node(scanner, NODE_TYPEDEF); + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_def.field_class_specifier_list = list; + _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators); + } + | declaration_specifiers CTF_TYPEDEF field_class_declarator_list + { + struct ctf_node *list; + + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + $$ = make_node(scanner, NODE_TYPEDEF); + ($$)->u.struct_or_variant_declaration.field_class_specifier_list = list; + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators); + } + | CTF_TYPEALIAS declaration_specifiers abstract_declarator_list CTF_TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list + { + struct ctf_node *list; + + $$ = make_node(scanner, NODE_TYPEALIAS); + $$->u.field_class_alias.target = make_node(scanner, NODE_TYPEALIAS_TARGET); + $$->u.field_class_alias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS); + + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_alias.target->u.field_class_alias_target.field_class_specifier_list = list; + _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_alias.target->u.field_class_alias_target.field_class_declarators); + + list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST); + $$->u.field_class_alias.alias->u.field_class_alias_name.field_class_specifier_list = list; + _bt_list_splice_tail(&($5)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head); + _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.field_class_alias.alias->u.field_class_alias_name.field_class_declarators); + } + ;