/* A.2.2 Declarations (6.7) declaration: declaration-specifiers init-declarator-list(opt) ; (6.7) declaration-specifiers: storage-class-specifier declaration-specifiers(opt) type-specifier declaration-specifiers(opt) type-qualifier declaration-specifiers(opt) function-specifier declaration-specifiers(opt) (6.7) init-declarator-list: init-declarator init-declarator-list , init-declarator (6.7) init-declarator: declarator declarator = initializer (6.7.1) storage-class-specifier: typedef extern static auto register (6.7.2) type-specifier: void char short int long float double signed unsigned _Bool _Complex struct-or-union-specifier enum-specifier typedef-name (6.7.2.1) struct-or-union-specifier: struct-or-union identifier(opt) { struct-declaration-list } struct-or-union identifier (6.7.2.1) struct-or-union: struct union (6.7.2.1) struct-declaration-list: struct-declaration struct-declaration-list struct-declaration (6.7.2.1) struct-declaration: specifier-qualifier-list struct-declarator-list ; (6.7.2.1) specifier-qualifier-list: type-specifier specifier-qualifier-list(opt) type-qualifier specifier-qualifier-list(opt) (6.7.2.1) struct-declarator-list: struct-declarator struct-declarator-list , struct-declarator (6.7.2.1) struct-declarator: declarator declarator(opt) : constant-expression (6.7.2.2) enum-specifier: enum identifier(opt) { enumerator-list } enum identifier(opt) { enumerator-list , } enum identifier (6.7.2.2) enumerator-list: enumerator enumerator-list , enumerator (6.7.2.2) enumerator: enumeration-constant enumeration-constant = constant-expression (6.7.3) type-qualifier: const restrict volatile (6.7.4) function-specifier: inline (6.7.5) declarator: pointer(opt) direct-declarator (6.7.5) direct-declarator: identifier ( declarator ) direct-declarator [ type-qualifier-list(opt) assignment-expression(opt) ] direct-declarator [ static type-qualifier-list(opt) assignment-expression ] direct-declarator [ type-qualifier-list static assignment-expression ] direct-declarator [ type-qualifier-list(opt) * ] direct-declarator ( parameter-type-list ) direct-declarator ( identifier-list(opt) ) (6.7.5) pointer: * type-qualifier-list(opt) * type-qualifier-list(opt) pointer (6.7.5) type-qualifier-list: type-qualifier type-qualifier-list type-qualifier (6.7.5) parameter-type-list: parameter-list parameter-list , ... (6.7.5) parameter-list: parameter-declaration parameter-list , parameter-declaration (6.7.5) parameter-declaration: declaration-specifiers declarator declaration-specifiers abstract-declarator(opt) (6.7.5) identifier-list: identifier identifier-list , identifier (6.7.6) type-name: specifier-qualifier-list abstract-declarator(opt) (6.7.6) abstract-declarator: pointer pointer(opt) direct-abstract-declarator (6.7.6) direct-abstract-declarator: ( abstract-declarator ) direct-abstract-declarator(opt) [ type-qualifier-list (opt) assignment-expression(opt) ] direct-abstract-declarator(opt) [ static type-qualifier-list(opt) assignment-expression ] direct-abstract-declarator(opt) [ type-qualifier-list static assignment-expression ] direct-abstract-declarator(opt) [ * ] direct-abstract-declarator(opt) ( parameter-type-list(opt) ) (6.7.7) typedef-name: identifier (6.7.8) initializer: assignment-expression { initializer-list } { initializer-list , } (6.7.8) initializer-list: designation(opt) initializer initializer-list , designation(opt) initializer (6.7.8) designation: designator-list = (6.7.8) designator-list: designator designator-list designator (6.7.8) designator: [ constant-expression ] . identifier A.2.4 External definitions (6.9) translation-unit: external-declaration translation-unit external-declaration (6.9) external-declaration: function-definition declaration (6.9.1) function-definition: declaration-specifiers declarator declaration-list(opt) compound-statement (6.9.1) declaration-list: declaration declaration-list declaration */ #include #include #include scc_ast_expr_t *scc_parse_initializer(scc_parser_t *parser, scc_ast_expr_t *base) { /* initializer: assignment-expression { initializer-list } { initializer-list , } initializer-list: designation(opt) initializer initializer-list , designation(opt) initializer designation: designator-list = designator-list: designator designator-list designator designator: [ constant-expression ] . identifier */ const scc_lexer_tok_t *tok_ptr = nullptr; scc_lexer_tok_t tok = {0}; tok_ptr = scc_parser_peek(parser); scc_ast_expr_t *init = nullptr; if (!(tok_ptr && tok_ptr->type == SCC_TOK_L_BRACE)) { // TODO int a = 1, b = 1; init = scc_parse_assignment_expression(parser); return init; } scc_parser_next_consume(parser, &tok); scc_pos_t pos = tok.loc; scc_lexer_tok_drop(&tok); init = SCC_AST_ALLOC_EXPR(parser->ast_ctx); Assert(init != nullptr); scc_ast_expr_vec_t lhs_exprs; scc_vec_init(lhs_exprs); scc_ast_expr_vec_t rhs_exprs; scc_vec_init(rhs_exprs); scc_ast_expr_t *lhs = nullptr; scc_ast_expr_t *rhs = nullptr; scc_ast_expr_t *ptr = base; while (1) { tok_ptr = scc_parser_peek(parser); if (tok_ptr->type == SCC_TOK_DOT) { scc_parser_next_consume(parser, nullptr); tok_ptr = scc_parser_peek(parser); if (tok_ptr && tok_ptr->type == SCC_TOK_IDENT) { scc_parser_next_consume(parser, &tok); lhs = SCC_AST_ALLOC_EXPR(parser->ast_ctx); Assert(lhs != nullptr); scc_ast_expr_member_init(lhs, ptr, scc_str_as_cstr(&tok.lexeme), tok.loc); if (!scc_parser_consume_if(parser, SCC_TOK_ASSIGN)) { ptr = lhs; continue; } rhs = scc_parse_initializer(parser, lhs); if (rhs == nullptr) { SCC_ERROR(scc_parser_got_current_pos(parser), "Expected initializer"); Panic(); } scc_vec_push(lhs_exprs, lhs); scc_vec_push(rhs_exprs, rhs); ptr = base; } else { SCC_ERROR(scc_parser_got_current_pos(parser), "Expected 'identifier' after '.'"); } } else if (tok_ptr->type == SCC_TOK_L_BRACKET) { scc_parser_next_consume(parser, nullptr); scc_ast_expr_t *idx = scc_parser_constant_expression(parser); Assert(idx != nullptr); if (!scc_parser_consume_if(parser, SCC_TOK_R_BRACKET)) { SCC_ERROR(scc_parser_got_current_pos(parser), "Expected ']'"); } lhs = SCC_AST_ALLOC_EXPR(parser->ast_ctx); Assert(lhs != nullptr); scc_ast_expr_array_subscript_init(lhs, ptr, idx, tok_ptr->loc); if (!scc_parser_consume_if(parser, SCC_TOK_ASSIGN)) { ptr = lhs; continue; } rhs = scc_parse_initializer(parser, lhs); Assert(rhs != nullptr); scc_vec_push(lhs_exprs, lhs); scc_vec_push(rhs_exprs, rhs); ptr = base; } else if (tok_ptr->type == SCC_TOK_R_BRACE) { scc_parser_next_consume(parser, nullptr); break; } else if (tok_ptr->type == SCC_TOK_COMMA) { scc_parser_next_consume(parser, nullptr); continue; } else { // FIXME scc_ast_expr_t *expr = scc_parse_initializer(parser, base); scc_vec_push(lhs_exprs, nullptr); scc_vec_push(rhs_exprs, expr); } } scc_ast_expr_compound_init(init, base, &lhs_exprs, &rhs_exprs, pos); return init; } scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser) { const scc_lexer_tok_t *tok_ptr = nullptr; scc_ast_decl_t *decl_list = nullptr; scc_ast_decl_vec_t decl_list_vec; scc_vec_init(decl_list_vec); scc_ast_qual_type_t *type = scc_parse_declaration_specifiers(parser); if (type == nullptr) { return nullptr; } scc_ast_decl_specifier_t spec = type->quals; // FIXME drop typedef inline and ... type->quals.is_typedef = false; scc_ast_decl_t *decl = nullptr; CONTINUE: decl = scc_parse_declarator(parser, type); if (decl == nullptr) { return nullptr; } tok_ptr = scc_parser_peek(parser); if (tok_ptr->type == SCC_TOK_ASSIGN) { scc_parser_next_consume(parser, nullptr); // TODO maybe memory leak scc_ast_expr_t *lvalue = SCC_AST_ALLOC_EXPR(parser->ast_ctx); scc_ast_expr_lvalue_init(lvalue, decl->var.type, decl->base.loc); decl->var.init = scc_parse_initializer(parser, lvalue); } else if (tok_ptr->type == SCC_TOK_L_BRACE) { scc_parse_decl_sema(parser, decl); scc_sema_decl(parser, scc_ast_decl_t_BEGIN, nullptr); // FIXME hack struct scc_vec_foreach(decl->func.type->type->function.params, i) { scc_ast_decl_t *param = scc_vec_at(decl->func.type->type->function.params, i); // Add params to decl scc_parse_decl_sema(parser, param); } scc_ast_stmt_t *body = scc_parse_statement(parser); scc_sema_decl(parser, scc_ast_decl_t_END, nullptr); Assert(decl->base.type == SCC_AST_DECL_FUNC); decl->func.body = body; Assert(decl->func.type != nullptr); Assert(decl->func.type->base.type == SCC_AST_TYPE_FUNCTION); Assert(decl->func.body != nullptr); Assert(decl->func.body->base.type == SCC_AST_STMT_COMPOUND); goto RETURN; } tok_ptr = scc_parser_peek(parser); if (tok_ptr->type == SCC_TOK_SEMICOLON) { scc_parser_next_consume(parser, nullptr); if (decl_list) scc_vec_push(decl_list_vec, decl); if (spec.is_typedef) { if (decl_list) { scc_vec_foreach(decl_list_vec, i) { decl = scc_vec_at(decl_list_vec, i); scc_ast_decl_typedef_init(decl, decl->name, decl->var.type, decl->base.loc); } } else { scc_ast_decl_typedef_init(decl, decl->name, decl->var.type, decl->base.loc); } } if (decl_list != nullptr) { scc_vec_foreach(decl_list_vec, i) { decl = scc_vec_at(decl_list_vec, i); scc_parse_decl_sema(parser, decl); } // FIXME scc_ast_decl_list_init(decl_list, &decl_list_vec, scc_vec_at(decl_list_vec, 0)->base.loc); decl = decl_list; } else { scc_parse_decl_sema(parser, decl); } goto RETURN; } else if (tok_ptr->type == SCC_TOK_COMMA) { scc_parser_next_consume(parser, nullptr); if (decl_list == nullptr) { decl_list = SCC_AST_ALLOC_DECL(parser->ast_ctx); Assert(decl_list != nullptr); scc_vec_push(decl_list_vec, decl); } else { Assert(scc_vec_size(decl_list_vec) != 0); decl->var.type = scc_vec_at(decl_list_vec, 0)->var.type; scc_vec_push(decl_list_vec, decl); } goto CONTINUE; } else { SCC_ERROR(scc_parser_got_current_pos(parser), "Expected ';' or '=' or '{'"); // FIXME memory leak goto ERROR; } RETURN: return decl; ERROR: return nullptr; }