/* `union` must already be matched. */ static void parse_union_decl(fb_parser_t *P, fb_compound_type_t *ct) { fb_token_t *t0; fb_member_t *member; fb_ref_t *ref; if (!(ct->symbol.ident = match(P, LEX_TOK_ID, "union declaration expected identifier"))) { goto fail; } ct->metadata = parse_metadata(P); if (!((t0 = match(P, '{', "union declaration expected '{'")))) { goto fail; } for (;;) { if (P->token->id != LEX_TOK_ID) { error_tok(P, P->token, "union expects an identifier"); goto fail; } if (P->failed >= FLATCC_MAX_ERRORS) { goto fail; } member = fb_add_member(P, &ct->members); parse_ref(P, &ref); member->type.ref = ref; member->type.type = vt_type_ref; while (ref->link) { ref = ref->link; } /* The union member is the unqualified reference. */ member->symbol.ident = ref->ident; if (optional(P, '=')) { parse_value(P, &member->value, 0, "integral constant expected"); /* Leave detailed type (e.g. no floats) and range checking to a later stage. */ } if (!optional(P, ',') || P->token->id == '}') { break; } P->doc = 0; } advance(P, '}', "union missing closing '}' to match", t0); revert_symbols(&ct->members); /* Add implicit `NONE` member first in the list. */ member = fb_add_member(P, &ct->members); member->symbol.ident = &P->t_none; return; fail: recover2(P, ';', 1, '}', 0); }
/* `struct` or `table` must already be matched. */ static void parse_compound_type(fb_parser_t *P, fb_compound_type_t *ct) { fb_token_t *t = 0; if (!(t = match(P, LEX_TOK_ID, "Declaration expected an identifier"))) { goto fail; } ct->symbol.ident = t; ct->metadata = parse_metadata(P); if (!(match(P, '{', "Declaration expected '{'"))) { goto fail; } t = P->token; /* Allow empty tables and structs. */ #if 0 if (P->token->id == '}') { error_tok(P, t, "table / struct declaration cannot be empty"); } #endif while (P->token->id != '}') { parse_field(P, fb_add_member(P, &ct->members)); if (P->failed >= FLATCC_MAX_ERRORS) { goto fail; } } if (!optional(P, '}') && t) { error_tok_2(P, P->token, "Declaration missing closing '}' to match", t); } revert_symbols(&ct->members); return; fail: recover(P, '}', 1); }
/* `enum` must already be matched. */ static void parse_enum_decl(fb_parser_t *P, fb_compound_type_t *ct) { fb_token_t *t, *t0; fb_member_t *member; if (!(ct->symbol.ident = match(P, LEX_TOK_ID, "enum declaration expected identifier"))) { goto fail; } if (optional(P, ':')) { parse_type(P, &ct->type); if (ct->type.type != vt_scalar_type) { error_tok(P, ct->type.t, "integral type expected"); } else { switch (ct->type.t->id) { case tok_kw_float: case tok_kw_double: error_tok(P, ct->type.t, "integral type expected"); default: break; } } } ct->metadata = parse_metadata(P); if (!((t0 = match(P, '{', "enum declaration expected '{'")))) { goto fail; } for (;;) { if (!(t = match(P, LEX_TOK_ID, "member identifier expected"))) { goto fail; } if (P->failed >= FLATCC_MAX_ERRORS) { goto fail; } member = fb_add_member(P, &ct->members); member->symbol.ident = t; if (optional(P, '=')) { t = P->token; parse_value(P, &member->value, 0, "integral constant expected"); /* Leave detailed type (e.g. no floats) and range checking to a later stage. */ } /* * Trailing comma is optional in flatc but not in grammar, we * follow flatc. */ if (!optional(P, ',') || P->token->id == '}') { break; } P->doc = 0; } if (t0) { advance(P, '}', "enum missing closing '}' to match", t0); } revert_symbols(&ct->members); return; fail: recover(P, '}', 1); }