diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-01-23 23:42:06 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-01-24 00:17:02 +0900 |
| commit | e6565082b66a9e4b2c5286d9487ef731fcd5e33a (patch) | |
| tree | 6111b7460e46c63e9959322c9650f33138f3de6f | |
| parent | 52df9f8ce8abf17bf6ca70c174a48f41e5ad31d5 (diff) | |
| download | ducc-e6565082b66a9e4b2c5286d9487ef731fcd5e33a.tar.gz ducc-e6565082b66a9e4b2c5286d9487ef731fcd5e33a.tar.zst ducc-e6565082b66a9e4b2c5286d9487ef731fcd5e33a.zip | |
docs: add docs/c_grammar.md
| -rw-r--r-- | docs/c_grammar.md | 443 | ||||
| -rw-r--r-- | src/parse.c | 1694 | ||||
| -rw-r--r-- | src/parse.h | 2 | ||||
| -rw-r--r-- | src/preprocess.c | 18 |
4 files changed, 1376 insertions, 781 deletions
diff --git a/docs/c_grammar.md b/docs/c_grammar.md new file mode 100644 index 0000000..6529b2b --- /dev/null +++ b/docs/c_grammar.md @@ -0,0 +1,443 @@ +# C Grammar + + +## Notation + +* `'A'`: Terminal symbol +* `A`: Non-terminal symbol +* `A / B`: A or B +* `A?`: Optional A +* `{ A }+`: 1 or more repetitions of A +* `{ A }*`: 0 or more repetitions of A +* `{ A | S }`: Repetition of A separated by S + * Note that trailing S is not allowed. +* `( A )`: Grouping +* `# ...`: Additional constraints + + +## Expressions + +``` +primary-expr: + identifier + constant + string-literal + '(' expr ')' + generic-selection + +generic-selection: + '_Generic' '(' assignment-expr ',' generic-assoc-list ')' + +generic-assoc-list: + { generic-association | ',' }* + +generic-association: + type-name ':' assignment-expr + 'default' ':' assignment-expr + +postfix-expr: + postfix-expr-stem { postfix-expr-postfix }* + +postfix-expr-stem: + primary-expr + compound-literal + +postfix-expr-postfix: + '[' expr ']' + '(' argument-expr-list? ')' + '.' identifier + '->' identifier + '++' + '--' + +argument-expr-list: + { assignment-expr | ',' }+ + +compound-literal: + '(' storage-class-specifiers? type-name ')' braced-initializer + +storage-class-specifiers: + { storage-class-specifier }+ + +unary-expr: + postfix-expr + '++' unary-expr + '--' unary-expr + unary-operator cast-expr + 'sizeof' unary-expr + 'sizeof' '(' type-name ')' + 'alignof' '(' type-name ')' + +unary-operator: + '&' + '*' + '+' + '-' + '~' + '!' + +cast-expr: + unary-expr + '(' type-name ')' cast-expr + +multiplicative-expr: + cast-expr { ( '*' / '/' / '%' ) cast-expr }* + +additive-expr: + multiplicative-expr { ( '+' / '-' ) multiplicative-expr }* + +shift-expr: + additive-expr { ( '<<' / '>>' ) additive-expr }* + +relational-expr: + shift-expr { ( '<' / '>' / '<=' / '>=' ) shift-expr }* + +equality-expr: + relational-expr { ( '==' / '!=' ) relational-expr }* + +bitwise-and-expr: + equality-expr { '&' equality-expr }* + +bitwise-xor-expr: + bitwise-and-expr { '^' bitwise-and-expr }* + +bitwise-or-expr: + bitwise-xor-expr { '|' bitwise-xor-expr }* + +logical-and-expr: + bitwise-or-expr { '&&' bitwise-or-expr }* + +logical-or-expr: + logical-and-expr { '||' logical-and-expr }* + +conditional-expr: + logical-or-expr ( '?' expr ':' conditional-expr )? + +assignment-expr: + conditional-expr + unary-expr assignment-operator assignment-expr + +assignment-operator: + '=' + '*=' + '/=' + '%=' + '+=' + '-=' + '<<=' + '>>=' + '&=' + '^=' + '|=' + +expr: + assignment-expr { ',' assignment-expr }* + +constant-expr: + conditional-expr +``` + +## Declarations + +``` +declaration: + static_assert-declaration + attribute-specifier-sequence ';' + attribute-specifier-sequence declaration-specifiers init-declarator-list ';' + declaration-specifiers init-declarator-list ';' + +declaration-specifiers: + { declaration-specifier }+ attribute-specifier-sequence? + +declaration-specifier: + storage-class-specifier + type-specifier-qualifier + function-specifier + +init-declarator-list: + { init-declarator | ',' }+ + +init-declarator: + declarator ( '=' initializer )? + +storage-class-specifier: + 'auto' + 'constexpr' + 'extern' + 'register' + 'static' + 'thread_local' + 'typedef' + +type-specifier: + 'void' + 'char' + 'short' + 'int' + 'long' + 'float' + 'double' + 'signed' + 'unsigned' + '_BitInt' '(' constant-expr ')' + 'bool' + '_Complex' + '_Decimal32' + '_Decimal64' + '_Decimal128' + atomic-type-specifier + struct-or-union-specifier + enum-specifier + typeof-specifier + typedef-name + +struct-or-union-specifier: + struct-or-union attribute-specifier-sequence? identifier? '{' member-declaration-list '}' + struct-or-union attribute-specifier-sequence? identifier + +struct-or-union: + 'struct' + 'union' + +member-declaration-list: + { member-declaration }+ + +member-declaration: + attribute-specifier-sequence? specifier-qualifier-list member-declaration-list? ';' + static_assert-declaration + +specifier-qualifier-list: + { type-specifier-qualifier }+ attribute-specifier-sequence? + +type-specifier-qualifier: + type-specifier + type-qualifier + alignment-specifier + +member-declarator-list: + { member-declarator | ',' }+ + +member-declarator: + declarator + declarator? ':' constant-expr + +enum-specifier: + 'enum' attribute-specifier-sequence? identifier? enum-type-specifier? '{' enumerator-list ','? '}' + 'enum' identifier enum-type-specifier? + +enumerator-list: + { enumerator | ',' }+ + +enumerator: + enumeration-constant attribute-specifier-sequence? ( '=' constant-expr )? + +enum-type-specifier: + ':' specifier-qualifier-list + +atomic-type-specifier: + '_Atomic' '(' type-name ')' + +typeof-specifier: + ( 'typeof' / 'typeof_unqual' ) '(' typeof-specifier-argument ')' + +typeof-specifier-argument: + expr + type-name + +type-qualifier: + 'const' + 'restrict' + 'volatile' + '_Atomic' + +function-specifier: + 'inline' + '_Noreturn' + +alignment-specifier: + 'alignas' '(' ( type-name / constant-expr ) ')' + +declarator: + pointer? direct-declarator + +direct-declarator: + identifier attribute-specifier-sequence? + '(' declarator ')' + array-declarator attribute-specifier-sequence? + function-declarator attribute-specifier-sequence? + +array-declarator: + direct-declarator '[' type-qualifier-list? assignment-expr? ']' + direct-declarator '[' 'static' type-qualifier-list? assignment-expr ']' + direct-declarator '[' type-qualifier-list 'static' assignment-expr ']' + direct-declarator '[' type-qualifier-list? '*' ']' + +function-declarator: + direct-declarator '(' parameter-type-list? ')' + +pointer: + { '*' attribute-specifier-sequence? type-qualifier-list? }+ + +type-qualifier-list: + { type-qualifier }+ + +parameter-type-list: + parameter-list + parameter-list ',' '...' + '...' + +parameter-list: + { parameter-declaration | ',' }+ + +parameter-declaration: + attribute-specifier-sequence? declaration-specifiers ( declarator / abstract-declarator? ) + +type-name: + specifier-qualifier-list abstract-declarator? + +abstract-declarator: + pointer + pointer? direct-abstract-declarator + +direct-abstract-declarator: + '(' abstract-declarator ')' + array-abstract-declarator attribute-specifier-sequence? + function-abstract-declarator attribute-specifier-sequence? + +array-abstract-declarator: + direct-abstract-declarator? '[' type-qualifier-list? assignment-expr? ']' + direct-abstract-declarator? '[' 'static' type-qualifier-list? assignment-expr ']' + direct-abstract-declarator? '[' type-qualifier-list 'static' assignment-expr ']' + direct-abstract-declarator? '[' '*' ']' + +function-abstract-declarator: + direct-abstract-declarator? '(' parameter-type-list? ')' + +typedef-name: + identifier + +braced-initializer: + '{' ( initializer-list ','? )? '}' + +initializer: + assignment-expr + braced-initializer + +initializer-list: + { designation? initializer | ',' }+ + +designation: + designator-list '=' + +designator-list: + { designator }+ + +designator: + '[' constant-expr ']' + '.' identifier + +static_assert-declaration: + 'static_assert' '(' constant-expr ( ',' string-literal )? ')' ';' + +attribute-specifier-sequence: + { attribute-specifier }+ + +attribute-specifier: + '[' '[' attribute-list ']' ']' + +attribute-list: + { attribute? | ',' } + +attribute: + attribute-token attribute-argument-clause? + +attribute-token: + identifier ( '::' identifier )? + +attribute-argument-clause: + '(' balanced-token-sequence ')' + +balanced-token-sequence: + { balanced-token }+ + +balanced-token: + '(' balanced-token-sequence? ')' + '[' balanced-token-sequence? ']' + '{' balanced-token-sequence? '}' + any token other than a parenthesis, a bracket, or a brace +``` + + +## Statements + +``` +stmt: + labeled-stmt + unlabaled-stmt + +unlabaled-stmt: + expr-stmt + attribute-specifier-sequence? ( primary-block / jump-stmt ) + +primary-block: + compound-stmt + selection-stmt + iteration-stmt + +label: + attribute-specifier-sequence? identifier ':' + attribute-specifier-sequence? 'case' constant-expr ':' + attribute-specifier-sequence? 'default' ':' + +labeled-stmt: + label stmt + +compound-stmt: + '{' block-item-list? '}' + +block-item-list: + { block-item }+ + +expr-stmt: + attribute-specifier-sequence? expr? ';' + +selection-stmt: + 'if' '(' expr ')' stmt ( 'else' stmt )? + 'switch' '(' expr ')' stmt + +iteration-stmt: + 'while' '(' expr ')' stmt + 'do' stmt 'while' '(' expr ')' ';' + 'for' '(' expr? ';' expr? ';' expr? ')' stmt + 'for' '(' declaration expr? ';' expr? ')' stmt + +jump-stmt: + 'goto' identifier ';' + 'continue' ';' + 'break' ';' + 'return' expr? ';' +``` + + +## External definitions + +``` +translation-unit: + { external-declaration }+ + +external-declaration: + function-definition + declaration + +external-declaration: + static_assert-declaration + attribute-specifier-sequence ';' + attribute-specifier-sequence function-definition-or-declaration-rest + function-definition-or-declaration-rest + +function-definition-or-declaration-rest: + declaration-specifiers init-declarator-list ';' + declaration-specifiers init-declarator-list compound-stmt + # Each item of init-declarator-list must not have initializer. + # The length of init-declarator-list must be one. +``` diff --git a/src/parse.c b/src/parse.c index 59ca219..4828061 100644 --- a/src/parse.c +++ b/src/parse.c @@ -348,9 +348,69 @@ static void leave_func(Parser* p) { leave_scope(p); } -static AstNode* parse_assignment_expr(Parser* p); -static AstNode* parse_expr(Parser* p); -static AstNode* parse_stmt(Parser* p); +static Token* parse_ident(Parser*); +static AstNode* parse_primary_expr(Parser*); +static AstNode* parse_postfix_expr(Parser*); +static AstNode* parse_argument_expr_list(Parser*); +static AstNode* parse_prefix_expr(Parser*); +static AstNode* parse_cast_expr(Parser*); +static AstNode* parse_multiplicative_expr(Parser*); +static AstNode* parse_additive_expr(Parser*); +static AstNode* parse_shift_expr(Parser*); +static AstNode* parse_relational_expr(Parser*); +static AstNode* parse_equality_expr(Parser*); +static AstNode* parse_bitwise_and_expr(Parser*); +static AstNode* parse_bitwise_xor_expr(Parser*); +static AstNode* parse_bitwise_or_expr(Parser*); +static AstNode* parse_logical_and_expr(Parser*); +static AstNode* parse_logical_or_expr(Parser*); +static AstNode* parse_conditional_expr(Parser*); +static AstNode* parse_assignment_expr(Parser*); +static AstNode* parse_expr(Parser*); +static AstNode* parse_constant_expr(Parser*); +static Type* parse_pointer_opt(Parser*, Type*); +static void parse_type_qualifier_list_opt(Parser*); +static AstNode* parse_declarator_or_abstract_declarator_opt(Parser*, Type*); +static AstNode* parse_parameter_type_list(Parser*); +static AstNode* parse_parameter_list(Parser*); +static AstNode* parse_parameter_declaration(Parser*); +static Type* parse_array_declarator_suffix(Parser*, Type*); +static Type* parse_function_declarator_suffix(Parser*, Type*); +static AstNode* parse_direct_declarator(Parser*, Type*); +static AstNode* parse_declarator(Parser*, Type*); +static AstNode* parse_init_declarator_list(Parser*, Type*); +static AstNode* parse_var_decl(Parser*); +static AstNode* parse_func_def(Parser*, AstNode*); +static Type* parse_declaration_specifiers(Parser*); +static AstNode* parse_init_declarator(Parser*, Type*); +static Type* parse_struct_specifier(Parser*); +static Type* parse_union_specifier(Parser*); +static AstNode* parse_member_declaration_list(Parser*); +static AstNode* parse_member_declaration(Parser*); +static Type* parse_specifier_qualifier_list(Parser*); +static AstNode* parse_member_declarator_list(Parser*, Type*); +static AstNode* parse_member_declarator(Parser*, Type*); +static Type* parse_enum_specifier(Parser*); +static void parse_enum_members(Parser*, int); +static AstNode* parse_enum_member(Parser*, int); +static Type* parse_type_name(Parser*); +static Type* parse_abstract_declarator_opt(Parser*, Type*); +static AstNode* parse_initializer(Parser*); +static AstNode* parse_stmt(Parser*); +static AstNode* parse_empty_stmt(Parser*); +static AstNode* parse_block_stmt(Parser*); +static AstNode* parse_expr_stmt(Parser*); +static AstNode* parse_if_stmt(Parser*); +static AstNode* parse_switch_stmt(Parser*); +static AstNode* parse_while_stmt(Parser*); +static AstNode* parse_do_while_stmt(Parser*); +static AstNode* parse_for_stmt(Parser*); +static AstNode* parse_continue_stmt(Parser*); +static AstNode* parse_break_stmt(Parser*); +static AstNode* parse_return_stmt(Parser*); +static AstNode* parse_external_declaration(Parser*); +static int eval(AstNode*); +static void declare_func_or_var(Parser*, AstNode*); static Token* parse_ident(Parser* p) { return expect(p, TokenKind_ident); @@ -360,6 +420,198 @@ static int register_str_literal(Parser* p, const char* s) { return strings_push(&p->str_literals, s); } +static void register_params(Parser* p, AstNode* params) { + int gp_regs = 6; + int pass_by_reg_offset = 8; + int pass_by_stack_offset = -16; + for (int i = 0; i < params->as.list->len; ++i) { + AstNode* param = ¶ms->as.list->items[i]; + int ty_size = type_sizeof(param->ty); + int required_gp_regs; + if (ty_size <= 8) { + required_gp_regs = 1; + } else if (ty_size <= 16) { + required_gp_regs = 2; + } else { + required_gp_regs = 0; + } + if (required_gp_regs <= gp_regs) { + gp_regs -= required_gp_regs; + } else { + required_gp_regs = 0; + } + int stack_offset; + if (required_gp_regs == 0) { + stack_offset = pass_by_stack_offset; + pass_by_stack_offset -= to_aligned(ty_size, 8); + } else { + stack_offset = pass_by_reg_offset; + pass_by_reg_offset += to_aligned(ty_size, 8); + } + const char* name = param->as.declarator->name; + param->kind = AstNodeKind_param; + param->as.param = calloc(1, sizeof(ParamNode)); + param->as.param->name = name; + param->as.param->stack_offset = stack_offset; + add_lvar(p, name, param->ty, stack_offset); + } +} + +static void register_func(Parser* p, const char* name, Type* ty) { + Func* func = funcs_push_new(&p->funcs); + func->name = name; + func->ty = ty; +} + +typedef enum { + TypeSpecifierMask_void = 1 << 0, + TypeSpecifierMask_char = 1 << 1, + TypeSpecifierMask_short = 1 << 2, + TypeSpecifierMask_int = 1 << 3, + TypeSpecifierMask_long = 1 << 4, + // 1 << 5 is used for second 'long'. + TypeSpecifierMask_float = 1 << 6, + TypeSpecifierMask_double = 1 << 7, + TypeSpecifierMask_signed = 1 << 8, + TypeSpecifierMask_unsigned = 1 << 9, + TypeSpecifierMask__BitInt = 1 << 10, + TypeSpecifierMask_bool = 1 << 11, + TypeSpecifierMask__Complex = 1 << 12, + TypeSpecifierMask__Decimal32 = 1 << 13, + TypeSpecifierMask__Decimal64 = 1 << 14, + TypeSpecifierMask__Decimal128 = 1 << 15, + TypeSpecifierMask__Atomic = 1 << 16, + TypeSpecifierMask_struct = 1 << 17, + TypeSpecifierMask_union = 1 << 18, + TypeSpecifierMask_enum = 1 << 19, + TypeSpecifierMask_typeof = 1 << 20, + TypeSpecifierMask_typeof_unqual = 1 << 21, + TypeSpecifierMask_typedef_name = 1 << 22, +} TypeSpecifierMask; + +static Type* distinguish_type_from_type_specifiers(int type_specifiers) { + if (type_specifiers == TypeSpecifierMask_void) + return type_new(TypeKind_void); + else if (type_specifiers == TypeSpecifierMask_char) + return type_new(TypeKind_char); + else if (type_specifiers == (TypeSpecifierMask_signed + TypeSpecifierMask_char)) + return type_new(TypeKind_schar); + else if (type_specifiers == (TypeSpecifierMask_unsigned + TypeSpecifierMask_char)) + return type_new(TypeKind_uchar); + else if (type_specifiers == TypeSpecifierMask_short || + type_specifiers == (TypeSpecifierMask_signed + TypeSpecifierMask_short) || + type_specifiers == (TypeSpecifierMask_short + TypeSpecifierMask_int) || + type_specifiers == (TypeSpecifierMask_signed + TypeSpecifierMask_short + TypeSpecifierMask_int)) + return type_new(TypeKind_short); + else if (type_specifiers == (TypeSpecifierMask_unsigned + TypeSpecifierMask_short) || + type_specifiers == (TypeSpecifierMask_unsigned + TypeSpecifierMask_short + TypeSpecifierMask_int)) + return type_new(TypeKind_ushort); + else if (type_specifiers == TypeSpecifierMask_int || type_specifiers == TypeSpecifierMask_signed || + type_specifiers == (TypeSpecifierMask_signed + TypeSpecifierMask_int)) + return type_new(TypeKind_int); + else if (type_specifiers == TypeSpecifierMask_unsigned || + type_specifiers == (TypeSpecifierMask_unsigned + TypeSpecifierMask_int)) + return type_new(TypeKind_uint); + else if (type_specifiers == TypeSpecifierMask_long || + type_specifiers == (TypeSpecifierMask_signed + TypeSpecifierMask_long) || + type_specifiers == (TypeSpecifierMask_long + TypeSpecifierMask_int) || + type_specifiers == (TypeSpecifierMask_signed + TypeSpecifierMask_long + TypeSpecifierMask_int)) + return type_new(TypeKind_long); + else if (type_specifiers == (TypeSpecifierMask_unsigned + TypeSpecifierMask_long) || + type_specifiers == (TypeSpecifierMask_unsigned + TypeSpecifierMask_long + TypeSpecifierMask_int)) + return type_new(TypeKind_ulong); + else if (type_specifiers == (TypeSpecifierMask_long + TypeSpecifierMask_long) || + type_specifiers == (TypeSpecifierMask_signed + TypeSpecifierMask_long + TypeSpecifierMask_long) || + type_specifiers == (TypeSpecifierMask_long + TypeSpecifierMask_long + TypeSpecifierMask_int) || + type_specifiers == + (TypeSpecifierMask_signed + TypeSpecifierMask_long + TypeSpecifierMask_long + TypeSpecifierMask_int)) + return type_new(TypeKind_llong); + else if (type_specifiers == (TypeSpecifierMask_unsigned + TypeSpecifierMask_long + TypeSpecifierMask_long) || + type_specifiers == + (TypeSpecifierMask_unsigned + TypeSpecifierMask_long + TypeSpecifierMask_long + TypeSpecifierMask_int)) + return type_new(TypeKind_ullong); + else if (type_specifiers == TypeSpecifierMask_float) + return type_new(TypeKind_float); + else if (type_specifiers == TypeSpecifierMask_double) + return type_new(TypeKind_double); + else if (type_specifiers == TypeSpecifierMask_long + TypeSpecifierMask_double) + return type_new(TypeKind_ldouble); + else if (type_specifiers == TypeSpecifierMask_bool) + return type_new(TypeKind_bool); + else if (type_specifiers == TypeSpecifierMask_struct) + return NULL; + else if (type_specifiers == TypeSpecifierMask_union) + return NULL; + else if (type_specifiers == TypeSpecifierMask_enum) + return NULL; + else if (type_specifiers == TypeSpecifierMask_typedef_name) + return NULL; + else if (type_specifiers == 0) + return NULL; + else + unimplemented(); +} + +// e++ +// tmp1 = &e; tmp2 = *tmp1; *tmp1 += 1; tmp2 +// e-- +// tmp1 = &e; tmp2 = *tmp1; *tmp1 -= 1; tmp2 +static AstNode* create_new_postfix_inc_or_dec(Parser* p, AstNode* e, TokenKind op) { + AstNode* tmp1_lvar = generate_temporary_lvar(p, type_new_ptr(e->ty)); + AstNode* tmp2_lvar = generate_temporary_lvar(p, e->ty); + + AstNode* expr1 = ast_new_assign_expr(TokenKind_assign, tmp1_lvar, ast_new_ref_expr(e)); + AstNode* expr2 = ast_new_assign_expr(TokenKind_assign, tmp2_lvar, ast_new_deref_expr(tmp1_lvar)); + AstNode* expr3; + if (op == TokenKind_plusplus) { + expr3 = ast_new_assign_add_expr(ast_new_deref_expr(tmp1_lvar), ast_new_int(1)); + } else { + expr3 = ast_new_assign_sub_expr(ast_new_deref_expr(tmp1_lvar), ast_new_int(1)); + } + AstNode* expr4 = tmp2_lvar; + + AstNode* ret = ast_new_list(4); + ast_append(ret, expr1); + ast_append(ret, expr2); + ast_append(ret, expr3); + ast_append(ret, expr4); + ret->ty = expr4->ty; + return ret; +} + +static bool is_typedef_name(Parser* p, Token* tok) { + return tok->kind == TokenKind_ident && find_typedef(p, tok->value.string) != -1; +} + +static bool is_type_token(Parser* p, Token* tok) { + if (tok->kind == TokenKind_keyword_void || tok->kind == TokenKind_keyword_char || + tok->kind == TokenKind_keyword_short || tok->kind == TokenKind_keyword_int || + tok->kind == TokenKind_keyword_long || tok->kind == TokenKind_keyword_float || + tok->kind == TokenKind_keyword_double || tok->kind == TokenKind_keyword_signed || + tok->kind == TokenKind_keyword_unsigned || tok->kind == TokenKind_keyword__BitInt || + tok->kind == TokenKind_keyword_bool || tok->kind == TokenKind_keyword__Complex || + tok->kind == TokenKind_keyword__Decimal32 || tok->kind == TokenKind_keyword__Decimal64 || + tok->kind == TokenKind_keyword__Decimal128 || tok->kind == TokenKind_keyword__Atomic || + tok->kind == TokenKind_keyword_struct || tok->kind == TokenKind_keyword_union || + tok->kind == TokenKind_keyword_enum || tok->kind == TokenKind_keyword_typeof || + tok->kind == TokenKind_keyword_typeof_unqual || tok->kind == TokenKind_keyword_const || + tok->kind == TokenKind_keyword_restrict || tok->kind == TokenKind_keyword_volatile || + tok->kind == TokenKind_keyword__Atomic || tok->kind == TokenKind_keyword_alignas || + tok->kind == TokenKind_keyword_inline || tok->kind == TokenKind_keyword__Noreturn) { + return true; + } + if (tok->kind != TokenKind_ident) { + return false; + } + return find_typedef(p, tok->value.string) != -1; +} + +// primary-expr: +// identifier +// constant +// string-literal +// '(' expr ')' +// TODO generic-selection static AstNode* parse_primary_expr(Parser* p) { Token* t = next_token(p); if (t->kind == TokenKind_literal_int) { @@ -416,50 +668,25 @@ static AstNode* parse_primary_expr(Parser* p) { } } -static AstNode* parse_arg_list(Parser* p) { - AstNode* list = ast_new_list(6); - while (peek_token(p)->kind != TokenKind_paren_r) { - AstNode* arg = parse_assignment_expr(p); - ast_append(list, arg); - if (!consume_token_if(p, TokenKind_comma)) { - break; - } - } - return list; -} - -// e++ -// tmp1 = &e; tmp2 = *tmp1; *tmp1 += 1; tmp2 -// e-- -// tmp1 = &e; tmp2 = *tmp1; *tmp1 -= 1; tmp2 -static AstNode* create_new_postfix_inc_or_dec(Parser* p, AstNode* e, TokenKind op) { - AstNode* tmp1_lvar = generate_temporary_lvar(p, type_new_ptr(e->ty)); - AstNode* tmp2_lvar = generate_temporary_lvar(p, e->ty); - - AstNode* expr1 = ast_new_assign_expr(TokenKind_assign, tmp1_lvar, ast_new_ref_expr(e)); - AstNode* expr2 = ast_new_assign_expr(TokenKind_assign, tmp2_lvar, ast_new_deref_expr(tmp1_lvar)); - AstNode* expr3; - if (op == TokenKind_plusplus) { - expr3 = ast_new_assign_add_expr(ast_new_deref_expr(tmp1_lvar), ast_new_int(1)); - } else { - expr3 = ast_new_assign_sub_expr(ast_new_deref_expr(tmp1_lvar), ast_new_int(1)); - } - AstNode* expr4 = tmp2_lvar; - - AstNode* ret = ast_new_list(4); - ast_append(ret, expr1); - ast_append(ret, expr2); - ast_append(ret, expr3); - ast_append(ret, expr4); - ret->ty = expr4->ty; - return ret; -} - +// postfix-expr: +// postfix-expr-stem { postfix-expr-postfix }* +// +// postfix-expr-stem: +// primary-expr +// TODO compound-literal +// +// postfix-expr-postfix: +// '[' expr ']' +// '(' argument-expr-list? ')' +// '.' identifier +// '->' identifier +// '++' +// '--' static AstNode* parse_postfix_expr(Parser* p) { AstNode* ret = parse_primary_expr(p); while (1) { if (consume_token_if(p, TokenKind_paren_l)) { - AstNode* args = parse_arg_list(p); + AstNode* args = parse_argument_expr_list(p); expect(p, TokenKind_paren_r); ret->as.func_call->args = args; } else if (consume_token_if(p, TokenKind_bracket_l)) { @@ -484,36 +711,28 @@ static AstNode* parse_postfix_expr(Parser* p) { return ret; } -static bool is_typedef_name(Parser* p, Token* tok) { - return tok->kind == TokenKind_ident && find_typedef(p, tok->value.string) != -1; -} - -static bool is_type_token(Parser* p, Token* tok) { - if (tok->kind == TokenKind_keyword_void || tok->kind == TokenKind_keyword_char || - tok->kind == TokenKind_keyword_short || tok->kind == TokenKind_keyword_int || - tok->kind == TokenKind_keyword_long || tok->kind == TokenKind_keyword_float || - tok->kind == TokenKind_keyword_double || tok->kind == TokenKind_keyword_signed || - tok->kind == TokenKind_keyword_unsigned || tok->kind == TokenKind_keyword__BitInt || - tok->kind == TokenKind_keyword_bool || tok->kind == TokenKind_keyword__Complex || - tok->kind == TokenKind_keyword__Decimal32 || tok->kind == TokenKind_keyword__Decimal64 || - tok->kind == TokenKind_keyword__Decimal128 || tok->kind == TokenKind_keyword__Atomic || - tok->kind == TokenKind_keyword_struct || tok->kind == TokenKind_keyword_union || - tok->kind == TokenKind_keyword_enum || tok->kind == TokenKind_keyword_typeof || - tok->kind == TokenKind_keyword_typeof_unqual || tok->kind == TokenKind_keyword_const || - tok->kind == TokenKind_keyword_restrict || tok->kind == TokenKind_keyword_volatile || - tok->kind == TokenKind_keyword__Atomic || tok->kind == TokenKind_keyword_alignas || - tok->kind == TokenKind_keyword_inline || tok->kind == TokenKind_keyword__Noreturn) { - return true; - } - if (tok->kind != TokenKind_ident) { - return false; +// argument-expr-list: +// { assignment-expr | ',' }+ +static AstNode* parse_argument_expr_list(Parser* p) { + AstNode* list = ast_new_list(6); + while (peek_token(p)->kind != TokenKind_paren_r) { + AstNode* arg = parse_assignment_expr(p); + ast_append(list, arg); + if (!consume_token_if(p, TokenKind_comma)) { + break; + } } - return find_typedef(p, tok->value.string) != -1; + return list; } -static Type* parse_type_name(Parser* p); -static AstNode* parse_cast_expr(Parser* p); - +// unary-expr: +// postfix-expr +// '++' unary-expr +// '--' unary-expr +// unary-operator cast-expr +// 'sizeof' unary-expr +// 'sizeof' '(' type-name ')' +// TODO 'alignof' '(' type-name ')' static AstNode* parse_prefix_expr(Parser* p) { TokenKind op = peek_token(p)->kind; if (consume_token_if(p, TokenKind_minus)) { @@ -562,6 +781,9 @@ static AstNode* parse_prefix_expr(Parser* p) { return parse_postfix_expr(p); } +// cast-expr: +// unary-expr +// '(' type-name ')' cast-expr static AstNode* parse_cast_expr(Parser* p) { if (peek_token(p)->kind == TokenKind_paren_l && is_type_token(p, peek_token2(p))) { next_token(p); @@ -575,6 +797,8 @@ static AstNode* parse_cast_expr(Parser* p) { return parse_prefix_expr(p); } +// multiplicative-expr: +// cast-expr { ( '*' / '/' / '%' ) cast-expr }* static AstNode* parse_multiplicative_expr(Parser* p) { AstNode* lhs = parse_cast_expr(p); while (1) { @@ -590,6 +814,8 @@ static AstNode* parse_multiplicative_expr(Parser* p) { return lhs; } +// additive-expr: +// multiplicative-expr { ( '+' / '-' ) multiplicative-expr }* static AstNode* parse_additive_expr(Parser* p) { AstNode* lhs = parse_multiplicative_expr(p); while (1) { @@ -629,6 +855,8 @@ static AstNode* parse_additive_expr(Parser* p) { return lhs; } +// shift-expr: +// additive-expr { ( '<<' / '>>' ) additive-expr }* static AstNode* parse_shift_expr(Parser* p) { AstNode* lhs = parse_additive_expr(p); while (1) { @@ -644,6 +872,8 @@ static AstNode* parse_shift_expr(Parser* p) { return lhs; } +// relational-expr: +// shift-expr { ( '<' / '>' / '<=' / '>=' ) shift-expr }* static AstNode* parse_relational_expr(Parser* p) { AstNode* lhs = parse_shift_expr(p); while (1) { @@ -665,6 +895,8 @@ static AstNode* parse_relational_expr(Parser* p) { return lhs; } +// equality-expr: +// relational-expr { ( '==' / '!=' ) relational-expr }* static AstNode* parse_equality_expr(Parser* p) { AstNode* lhs = parse_relational_expr(p); while (1) { @@ -680,6 +912,8 @@ static AstNode* parse_equality_expr(Parser* p) { return lhs; } +// bitwise-and-expr: +// equality-expr { '&' equality-expr }* static AstNode* parse_bitwise_and_expr(Parser* p) { AstNode* lhs = parse_equality_expr(p); while (1) { @@ -694,6 +928,8 @@ static AstNode* parse_bitwise_and_expr(Parser* p) { return lhs; } +// bitwise-xor-expr: +// bitwise-and-expr { '^' bitwise-and-expr }* static AstNode* parse_bitwise_xor_expr(Parser* p) { AstNode* lhs = parse_bitwise_and_expr(p); while (1) { @@ -708,6 +944,8 @@ static AstNode* parse_bitwise_xor_expr(Parser* p) { return lhs; } +// bitwise-or-expr: +// bitwise-xor-expr { '|' bitwise-xor-expr }* static AstNode* parse_bitwise_or_expr(Parser* p) { AstNode* lhs = parse_bitwise_xor_expr(p); while (1) { @@ -722,6 +960,8 @@ static AstNode* parse_bitwise_or_expr(Parser* p) { return lhs; } +// logical-and-expr: +// bitwise-or-expr { '&&' bitwise-or-expr }* static AstNode* parse_logical_and_expr(Parser* p) { AstNode* lhs = parse_bitwise_or_expr(p); while (1) { @@ -735,6 +975,8 @@ static AstNode* parse_logical_and_expr(Parser* p) { return lhs; } +// logical-or-expr: +// logical-and-expr { '||' logical-and-expr }* static AstNode* parse_logical_or_expr(Parser* p) { AstNode* lhs = parse_logical_and_expr(p); while (1) { @@ -748,6 +990,8 @@ static AstNode* parse_logical_or_expr(Parser* p) { return lhs; } +// conditional-expr: +// logical-or-expr ( '?' expr ':' conditional-expr )? static AstNode* parse_conditional_expr(Parser* p) { AstNode* e = parse_logical_or_expr(p); if (consume_token_if(p, TokenKind_question)) { @@ -760,12 +1004,9 @@ static AstNode* parse_conditional_expr(Parser* p) { } } -// constant-expression: -// conditional-expression -static AstNode* parse_constant_expression(Parser* p) { - return parse_conditional_expr(p); -} - +// assignment-expr: +// conditional-expr +// unary-expr assignment-operator assignment-expr static AstNode* parse_assignment_expr(Parser* p) { AstNode* lhs = parse_conditional_expr(p); while (1) { @@ -790,7 +1031,9 @@ static AstNode* parse_assignment_expr(Parser* p) { return lhs; } -static AstNode* parse_comma_expr(Parser* p) { +// expr: +// assignment-expr { ',' assignment-expr }* +static AstNode* parse_expr(Parser* p) { AstNode* lhs = parse_assignment_expr(p); while (1) { if (consume_token_if(p, TokenKind_comma)) { @@ -807,33 +1050,21 @@ static AstNode* parse_comma_expr(Parser* p) { return lhs; } -static AstNode* parse_expr(Parser* p) { - return parse_comma_expr(p); -} - -static AstNode* parse_return_stmt(Parser* p) { - expect(p, TokenKind_keyword_return); - if (consume_token_if(p, TokenKind_semicolon)) { - return ast_new_return_stmt(NULL); - } - - AstNode* expr = parse_expr(p); - expect(p, TokenKind_semicolon); - return ast_new_return_stmt(expr); +// constant-expr: +// conditional-expr +static AstNode* parse_constant_expr(Parser* p) { + return parse_conditional_expr(p); } -static AstNode* parse_if_stmt(Parser* p) { - expect(p, TokenKind_keyword_if); - expect(p, TokenKind_paren_l); - AstNode* cond = parse_expr(p); - expect(p, TokenKind_paren_r); - AstNode* then_body = parse_stmt(p); - AstNode* else_body = NULL; - if (consume_token_if(p, TokenKind_keyword_else)) { - else_body = parse_stmt(p); +// pointer: +// { '*' TODO attribute-specifier-sequence? type-qualifier-list? }+ +static Type* parse_pointer_opt(Parser* p, Type* ty) { + while (peek_token(p)->kind == TokenKind_star) { + next_token(p); + ty = type_new_ptr(ty); + parse_type_qualifier_list_opt(p); } - - return ast_new_if_stmt(cond, then_body, else_body); + return ty; } // type-qualifier-list: @@ -851,20 +1082,6 @@ static void parse_type_qualifier_list_opt(Parser* p) { } } -// pointer: -// { '*' TODO attribute-specifier-sequence? type-qualifier-list? }+ -static Type* parse_pointer_opt(Parser* p, Type* ty) { - while (peek_token(p)->kind == TokenKind_star) { - next_token(p); - ty = type_new_ptr(ty); - parse_type_qualifier_list_opt(p); - } - return ty; -} - -static Type* parse_array_declarator_suffix(Parser* p, Type* ty); -static Type* parse_function_declarator_suffix(Parser* p, Type* ty); - // declarator | abstract-declarator?: // pointer? identifier TODO attribute-specifier-sequence? { direct-declarator-suffix }* // pointer? '(' declarator ')' { direct-declarator-suffix }* @@ -906,37 +1123,6 @@ static AstNode* parse_declarator_or_abstract_declarator_opt(Parser* p, Type* ty) return decl; } -static Type* parse_declaration_specifiers(Parser* p); - -// parameter-declaration: -// TODO attribute-specifier-sequence? declaration-specifiers declarator -// TODO attribute-specifier-sequence? declaration-specifiers abstract-declarator? -static AstNode* parse_parameter_declaration(Parser* p) { - if (consume_token_if(p, TokenKind_ellipsis)) { - return ast_new_declarator("...", NULL); - } - - Type* base_ty = parse_declaration_specifiers(p); - return parse_declarator_or_abstract_declarator_opt(p, base_ty); -} - -// parameter-list: -// { parameter-declaration | ',' } -static AstNode* parse_parameter_list(Parser* p) { - AstNode* params = ast_new_list(4); - - while (1) { - AstNode* param = parse_parameter_declaration(p); - ast_append(params, param); - - if (!consume_token_if(p, TokenKind_comma)) { - break; - } - } - - return params; -} - // parameter-type-list: // parameter-list // parameter-list ',' '...' @@ -967,12 +1153,39 @@ static AstNode* parse_parameter_type_list(Parser* p) { return params; } -static int eval(AstNode* e); +// parameter-list: +// { parameter-declaration | ',' } +static AstNode* parse_parameter_list(Parser* p) { + AstNode* params = ast_new_list(4); + + while (1) { + AstNode* param = parse_parameter_declaration(p); + ast_append(params, param); + + if (!consume_token_if(p, TokenKind_comma)) { + break; + } + } + + return params; +} + +// parameter-declaration: +// TODO attribute-specifier-sequence? declaration-specifiers declarator +// TODO attribute-specifier-sequence? declaration-specifiers abstract-declarator? +static AstNode* parse_parameter_declaration(Parser* p) { + if (consume_token_if(p, TokenKind_ellipsis)) { + return ast_new_declarator("...", NULL); + } + + Type* base_ty = parse_declaration_specifiers(p); + return parse_declarator_or_abstract_declarator_opt(p, base_ty); +} // array-declarator: -// direct-declarator '[' TODO type-qualifier-list? TODO assignment-expression? ']' -// TODO direct-declarator '[' 'static' type-qualifier-list? assignment-expression? ']' -// TODO direct-declarator '[' type-qualifier-list 'static' assignment-expression? ']' +// direct-declarator '[' TODO type-qualifier-list? TODO assignment-expr? ']' +// TODO direct-declarator '[' 'static' type-qualifier-list? assignment-expr? ']' +// TODO direct-declarator '[' type-qualifier-list 'static' assignment-expr? ']' // TODO direct-declarator '[' type-qualifier-list? '*' ']' static Type* parse_array_declarator_suffix(Parser* p, Type* ty) { next_token(p); // skip '[' @@ -1006,8 +1219,6 @@ static Type* parse_function_declarator_suffix(Parser* p, Type* ty) { return type_new_func(ty, params); } -static AstNode* parse_declarator(Parser* p, Type* ty); - // direct-declarator: // identifier TODO attribute-specifier-sequence? // '(' declarator ')' @@ -1045,26 +1256,6 @@ static AstNode* parse_declarator(Parser* p, Type* ty) { return parse_direct_declarator(p, ty); } -// initializer: -// assignment-expression -// TODO braced-initializer -static AstNode* parse_initializer(Parser* p) { - return parse_assignment_expr(p); -} - -// init-declarator: -// declarator -// declarator '=' initializer -static AstNode* parse_init_declarator(Parser* p, Type* ty) { - AstNode* decl = parse_declarator(p, ty); - if (consume_token_if(p, TokenKind_assign)) { - decl->as.declarator->init = parse_initializer(p); - } - return decl; -} - -static void declare_func_or_var(Parser* p, AstNode* decl); - // init-declarator-list: // init-declarator // init-declarator-list ',' init-declarator @@ -1087,6 +1278,8 @@ static AstNode* parse_init_declarator_list(Parser* p, Type* ty) { return list; } +// declaration: +// declaration-specifiers init-declarator-list ';' static AstNode* parse_var_decl(Parser* p) { Type* base_ty = parse_type_name(p); AstNode* decls = parse_init_declarator_list(p, base_ty); @@ -1095,231 +1288,6 @@ static AstNode* parse_var_decl(Parser* p) { return decls; } -static AstNode* parse_for_stmt(Parser* p) { - expect(p, TokenKind_keyword_for); - expect(p, TokenKind_paren_l); - AstNode* init = NULL; - AstNode* cond = NULL; - AstNode* update = NULL; - enter_scope(p); - if (peek_token(p)->kind != TokenKind_semicolon) { - if (is_type_token(p, peek_token(p))) { - AstNode* decls = parse_var_decl(p); - AstNode* initializers = ast_new_list(1); - for (int i = 0; i < decls->as.list->len; i++) { - AstNode* item = &decls->as.list->items[i]; - if (item->kind == AstNodeKind_expr_stmt) { - ast_append(initializers, item->as.expr_stmt->expr); - } - } - init = initializers; - } else { - init = parse_expr(p); - expect(p, TokenKind_semicolon); - } - } else { - expect(p, TokenKind_semicolon); - } - if (peek_token(p)->kind != TokenKind_semicolon) { - cond = parse_expr(p); - } else { - cond = ast_new_int(1); - } - expect(p, TokenKind_semicolon); - if (peek_token(p)->kind != TokenKind_paren_r) { - update = parse_expr(p); - } - expect(p, TokenKind_paren_r); - AstNode* body = parse_stmt(p); - leave_scope(p); - return ast_new_for_stmt(init, cond, update, body); -} - -static AstNode* parse_while_stmt(Parser* p) { - expect(p, TokenKind_keyword_while); - expect(p, TokenKind_paren_l); - AstNode* cond = parse_expr(p); - expect(p, TokenKind_paren_r); - AstNode* body = parse_stmt(p); - return ast_new_for_stmt(NULL, cond, NULL, body); -} - -static AstNode* parse_do_while_stmt(Parser* p) { - expect(p, TokenKind_keyword_do); - AstNode* body = parse_stmt(p); - expect(p, TokenKind_keyword_while); - expect(p, TokenKind_paren_l); - AstNode* cond = parse_expr(p); - expect(p, TokenKind_paren_r); - expect(p, TokenKind_semicolon); - - return ast_new_do_while_stmt(cond, body); -} - -static AstNode* parse_switch_stmt(Parser* p) { - expect(p, TokenKind_keyword_switch); - expect(p, TokenKind_paren_l); - AstNode* expr = parse_expr(p); - expect(p, TokenKind_paren_r); - - AstNode* tmp_var = generate_temporary_lvar(p, expr->ty); - AstNode* assignment = ast_new_assign_expr(TokenKind_assign, tmp_var, expr); - AstNode* assign_stmt = ast_new_expr_stmt(assignment); - - AstNode* switch_stmt = ast_new_switch_stmt(tmp_var); - - AstNode* prev_switch = p->current_switch; - p->current_switch = switch_stmt; - switch_stmt->as.switch_stmt->body = parse_stmt(p); - p->current_switch = prev_switch; - - AstNode* list = ast_new_list(2); - ast_append(list, assign_stmt); - ast_append(list, switch_stmt); - return list; -} - -static AstNode* parse_break_stmt(Parser* p) { - expect(p, TokenKind_keyword_break); - expect(p, TokenKind_semicolon); - return ast_new_break_stmt(); -} - -static AstNode* parse_continue_stmt(Parser* p) { - expect(p, TokenKind_keyword_continue); - expect(p, TokenKind_semicolon); - return ast_new_continue_stmt(); -} - -static AstNode* parse_expr_stmt(Parser* p) { - AstNode* e = parse_expr(p); - expect(p, TokenKind_semicolon); - return ast_new_expr_stmt(e); -} - -static AstNode* parse_block_stmt(Parser* p) { - AstNode* list = ast_new_list(4); - expect(p, TokenKind_brace_l); - enter_scope(p); - while (peek_token(p)->kind != TokenKind_brace_r) { - AstNode* stmt = parse_stmt(p); - ast_append(list, stmt); - } - leave_scope(p); - expect(p, TokenKind_brace_r); - return list; -} - -static AstNode* parse_empty_stmt(Parser* p) { - consume_token_if(p, TokenKind_semicolon); - return ast_new_nop(); -} - -static AstNode* parse_stmt(Parser* p) { - Token* t = peek_token(p); - - if (t->kind == TokenKind_keyword_case) { - if (!p->current_switch) { - fatal_error("%s:%d: 'case' label not within a switch statement", t->loc.filename, t->loc.line); - } - expect(p, TokenKind_keyword_case); - AstNode* value = parse_constant_expression(p); - expect(p, TokenKind_colon); - AstNode* stmt = parse_stmt(p); - - return ast_new_case_label(eval(value), stmt); - } else if (t->kind == TokenKind_keyword_default) { - if (!p->current_switch) { - fatal_error("%s:%d: 'default' label not within a switch statement", t->loc.filename, t->loc.line); - } - expect(p, TokenKind_keyword_default); - expect(p, TokenKind_colon); - AstNode* stmt = parse_stmt(p); - - return ast_new_default_label(stmt); - } else if (t->kind == TokenKind_keyword_return) { - return parse_return_stmt(p); - } else if (t->kind == TokenKind_keyword_if) { - return parse_if_stmt(p); - } else if (t->kind == TokenKind_keyword_switch) { - return parse_switch_stmt(p); - } else if (t->kind == TokenKind_keyword_for) { - return parse_for_stmt(p); - } else if (t->kind == TokenKind_keyword_while) { - return parse_while_stmt(p); - } else if (t->kind == TokenKind_keyword_do) { - return parse_do_while_stmt(p); - } else if (t->kind == TokenKind_keyword_break) { - return parse_break_stmt(p); - } else if (t->kind == TokenKind_keyword_continue) { - return parse_continue_stmt(p); - } else if (t->kind == TokenKind_keyword_goto) { - expect(p, TokenKind_keyword_goto); - Token* label_token = expect(p, TokenKind_ident); - expect(p, TokenKind_semicolon); - - return ast_new_goto_stmt(label_token->value.string); - } else if (t->kind == TokenKind_brace_l) { - return parse_block_stmt(p); - } else if (t->kind == TokenKind_semicolon) { - return parse_empty_stmt(p); - } else if (is_type_token(p, t)) { - return parse_var_decl(p); - } else if (t->kind == TokenKind_ident && peek_token2(p)->kind == TokenKind_colon) { - // Label statement - Token* label_token = expect(p, TokenKind_ident); - expect(p, TokenKind_colon); - AstNode* stmt = parse_stmt(p); - - return ast_new_label_stmt(label_token->value.string, stmt); - } else { - return parse_expr_stmt(p); - } -} - -static void register_params(Parser* p, AstNode* params) { - int gp_regs = 6; - int pass_by_reg_offset = 8; - int pass_by_stack_offset = -16; - for (int i = 0; i < params->as.list->len; ++i) { - AstNode* param = ¶ms->as.list->items[i]; - int ty_size = type_sizeof(param->ty); - int required_gp_regs; - if (ty_size <= 8) { - required_gp_regs = 1; - } else if (ty_size <= 16) { - required_gp_regs = 2; - } else { - required_gp_regs = 0; - } - if (required_gp_regs <= gp_regs) { - gp_regs -= required_gp_regs; - } else { - required_gp_regs = 0; - } - int stack_offset; - if (required_gp_regs == 0) { - stack_offset = pass_by_stack_offset; - pass_by_stack_offset -= to_aligned(ty_size, 8); - } else { - stack_offset = pass_by_reg_offset; - pass_by_reg_offset += to_aligned(ty_size, 8); - } - const char* name = param->as.declarator->name; - param->kind = AstNodeKind_param; - param->as.param = calloc(1, sizeof(ParamNode)); - param->as.param->name = name; - param->as.param->stack_offset = stack_offset; - add_lvar(p, name, param->ty, stack_offset); - } -} - -static void register_func(Parser* p, const char* name, Type* ty) { - Func* func = funcs_push_new(&p->funcs); - func->name = name; - func->ty = ty; -} - static void declare_func_or_var(Parser* p, AstNode* decl) { const char* name = decl->as.declarator->name; if (decl->ty->kind == TypeKind_func) { @@ -1409,97 +1377,6 @@ static AstNode* parse_func_def(Parser* p, AstNode* decls) { return ast_new_func_def(name, ty, params, body, stack_size); } -// member-declarator: -// declarator -// TODO declarator? ':' constant-expression -static AstNode* parse_member_declarator(Parser* p, Type* base_ty) { - return parse_declarator(p, base_ty); -} - -// member-declarator-list: -// { member-declarator | ',' }+ -static AstNode* parse_member_declarator_list(Parser* p, Type* base_ty) { - AstNode* list = ast_new_list(1); - while (1) { - AstNode* d = parse_member_declarator(p, base_ty); - ast_append(list, d); - if (!consume_token_if(p, TokenKind_comma)) { - break; - } - } - return list; -} - -static Type* parse_specifier_qualifier_list(Parser* p); - -// member-declaration: -// TODO attribute-specifier-sequence? specifier-qualifier-list member-declaration-list? ';' -// TODO static_assert-declaration -static AstNode* parse_member_declaration(Parser* p) { - Type* base_ty = parse_specifier_qualifier_list(p); - - AstNode* decls = NULL; - if (consume_token_if(p, TokenKind_semicolon)) { - unimplemented(); - } - decls = parse_member_declarator_list(p, base_ty); - - expect(p, TokenKind_semicolon); - - for (int i = 0; i < decls->as.list->len; i++) { - const char* member_name = decls->as.list->items[i].as.declarator->name; - decls->as.list->items[i].kind = AstNodeKind_struct_member; - decls->as.list->items[i].as.struct_member = calloc(1, sizeof(StructMemberNode)); - decls->as.list->items[i].as.struct_member->name = member_name; - } - return decls; -} - -// member-declaration-list: -// { member-declaration }+ -static AstNode* parse_member_declaration_list(Parser* p) { - AstNode* members = ast_new_list(4); - while (peek_token(p)->kind != TokenKind_brace_r) { - AstNode* decls = parse_member_declaration(p); - for (int i = 0; i < decls->as.list->len; i++) { - ast_append(members, &decls->as.list->items[i]); - } - } - return members; -} - -static AstNode* parse_enum_member(Parser* p, int next_value) { - const Token* name = parse_ident(p); - int value; - if (consume_token_if(p, TokenKind_assign)) { - AstNode* expr = parse_constant_expression(p); - value = eval(expr); - } else { - value = next_value; - } - return ast_new_enum_member(name->value.string, value); -} - -static void parse_enum_members(Parser* p, int enum_idx) { - int next_value = 0; - AstNode* list = ast_new_list(16); - - if (!p->enums->as.list->items[enum_idx].as.enum_def->members) { - p->enums->as.list->items[enum_idx].as.enum_def->members = list; - } - - while (peek_token(p)->kind != TokenKind_brace_r) { - AstNode* member = parse_enum_member(p, next_value); - next_value = member->as.enum_member->value + 1; - - ast_append(list, member); - - if (!consume_token_if(p, TokenKind_comma)) { - break; - } - } -} - void parse_typedef_decl(Parser* p, AstNode* decls) { expect(p, TokenKind_semicolon); for (int i = 0; i < decls->as.list->len; ++i) { @@ -1516,277 +1393,6 @@ static char* generate_new_anonymous_user_type_name(Parser* p) { return buf; } -// struct-specifier: -// 'struct' TODO attribute-specifier-sequence? identifier? '{' member-declaration-list '}' -// 'struct' TODO attribute-specifier-sequence? identifier -static Type* parse_struct_specifier(Parser* p) { - SourceLocation struct_kw_pos = peek_token(p)->loc; - next_token(p); - - const Token* name; - char* anonymous_name = NULL; - if (peek_token(p)->kind == TokenKind_brace_l) { - anonymous_name = generate_new_anonymous_user_type_name(p); - Token* anonymous_token = calloc(1, sizeof(Token)); - anonymous_token->kind = TokenKind_ident; - anonymous_token->value.string = anonymous_name; - anonymous_token->loc = struct_kw_pos; - name = anonymous_token; - } else { - name = parse_ident(p); - } - - if (!consume_token_if(p, TokenKind_brace_l)) { - int struct_idx = find_struct(p, name->value.string); - if (struct_idx != -1) { - Type* ty = type_new(TypeKind_struct); - ty->ref.defs = p->structs; - ty->ref.index = struct_idx; - return ty; - } else { - // TODO - AstNode* new_struct = ast_new_struct_def(name->value.string); - ast_append(p->structs, new_struct); - struct_idx = p->structs->as.list->len - 1; - - Type* ty = type_new(TypeKind_struct); - ty->ref.defs = p->structs; - ty->ref.index = struct_idx; - return ty; - } - } - - int struct_idx = find_struct(p, name->value.string); - if (struct_idx != -1 && p->structs->as.list->items[struct_idx].as.struct_def->members) { - fatal_error("%s:%d: struct %s redefined", name->loc.filename, name->loc.line, name->value.string); - } - - if (struct_idx == -1) { - AstNode* new_struct = ast_new_struct_def(name->value.string); - ast_append(p->structs, new_struct); - struct_idx = p->structs->as.list->len - 1; - } - - AstNode* members = parse_member_declaration_list(p); - expect(p, TokenKind_brace_r); - p->structs->as.list->items[struct_idx].as.struct_def->members = members; - - Type* ty = type_new(TypeKind_struct); - ty->ref.defs = p->structs; - ty->ref.index = struct_idx; - return ty; -} - -// union-specifier: -// 'union' TODO attribute-specifier-sequence? identifier? '{' member-declaration-list '}' -// 'union' TODO attribute-specifier-sequence? identifier -static Type* parse_union_specifier(Parser* p) { - SourceLocation union_kw_pos = peek_token(p)->loc; - next_token(p); - - const Token* name; - char* anonymous_name = NULL; - if (peek_token(p)->kind == TokenKind_brace_l) { - anonymous_name = generate_new_anonymous_user_type_name(p); - Token* anonymous_token = calloc(1, sizeof(Token)); - anonymous_token->kind = TokenKind_ident; - anonymous_token->value.string = anonymous_name; - anonymous_token->loc = union_kw_pos; - name = anonymous_token; - } else { - name = parse_ident(p); - } - - if (!consume_token_if(p, TokenKind_brace_l)) { - int union_idx = find_union(p, name->value.string); - if (union_idx != -1) { - Type* ty = type_new(TypeKind_union); - ty->ref.defs = p->unions; - ty->ref.index = union_idx; - return ty; - } else { - // TODO - AstNode* new_union = ast_new_union_def(name->value.string); - ast_append(p->unions, new_union); - union_idx = p->unions->as.list->len - 1; - - Type* ty = type_new(TypeKind_union); - ty->ref.defs = p->unions; - ty->ref.index = union_idx; - return ty; - } - } - - int union_idx = find_union(p, name->value.string); - if (union_idx != -1 && p->unions->as.list->items[union_idx].as.union_def->members) { - fatal_error("%s:%d: union %s redefined", name->loc.filename, name->loc.line, name->value.string); - } - - if (union_idx == -1) { - AstNode* new_union = ast_new_union_def(name->value.string); - ast_append(p->unions, new_union); - union_idx = p->unions->as.list->len - 1; - } - - AstNode* members = parse_member_declaration_list(p); - expect(p, TokenKind_brace_r); - p->unions->as.list->items[union_idx].as.union_def->members = members; - - Type* ty = type_new(TypeKind_union); - ty->ref.defs = p->unions; - ty->ref.index = union_idx; - return ty; -} - -// enum-specifier: -// 'enum' TODO attribute-specifier-sequence? identifier? TODO enum-type-specifier? '{' enumerator-list ','? '}' -// 'enum' identifier TODO enum-type-specifier? -static Type* parse_enum_specifier(Parser* p) { - SourceLocation enum_kw_pos = peek_token(p)->loc; - next_token(p); - - const Token* name; - char* anonymous_name = NULL; - if (peek_token(p)->kind == TokenKind_brace_l) { - anonymous_name = generate_new_anonymous_user_type_name(p); - Token* anonymous_token = calloc(1, sizeof(Token)); - anonymous_token->kind = TokenKind_ident; - anonymous_token->value.string = anonymous_name; - anonymous_token->loc = enum_kw_pos; - name = anonymous_token; - } else { - name = parse_ident(p); - } - - if (!consume_token_if(p, TokenKind_brace_l)) { - int enum_idx = find_enum(p, name->value.string); - if (enum_idx != -1) { - Type* ty = type_new(TypeKind_enum); - ty->ref.defs = p->enums; - ty->ref.index = enum_idx; - return ty; - } else { - // TODO - AstNode* new_enum = ast_new_enum_def(name->value.string); - ast_append(p->enums, new_enum); - enum_idx = p->enums->as.list->len - 1; - - Type* ty = type_new(TypeKind_enum); - ty->ref.defs = p->enums; - ty->ref.index = enum_idx; - return ty; - } - } - - int enum_idx = find_enum(p, name->value.string); - if (enum_idx != -1 && p->enums->as.list->items[enum_idx].as.enum_def->members) { - fatal_error("%s:%d: enum %s redefined", name->loc.filename, name->loc.line, name->value.string); - } - - if (enum_idx == -1) { - AstNode* new_enum = ast_new_enum_def(name->value.string); - ast_append(p->enums, new_enum); - enum_idx = p->enums->as.list->len - 1; - } - - parse_enum_members(p, enum_idx); - expect(p, TokenKind_brace_r); - - Type* ty = type_new(TypeKind_enum); - ty->ref.defs = p->enums; - ty->ref.index = enum_idx; - return ty; -} - -typedef enum { - TypeSpecifierMask_void = 1 << 0, - TypeSpecifierMask_char = 1 << 1, - TypeSpecifierMask_short = 1 << 2, - TypeSpecifierMask_int = 1 << 3, - TypeSpecifierMask_long = 1 << 4, - // 1 << 5 is used for second 'long'. - TypeSpecifierMask_float = 1 << 6, - TypeSpecifierMask_double = 1 << 7, - TypeSpecifierMask_signed = 1 << 8, - TypeSpecifierMask_unsigned = 1 << 9, - TypeSpecifierMask__BitInt = 1 << 10, - TypeSpecifierMask_bool = 1 << 11, - TypeSpecifierMask__Complex = 1 << 12, - TypeSpecifierMask__Decimal32 = 1 << 13, - TypeSpecifierMask__Decimal64 = 1 << 14, - TypeSpecifierMask__Decimal128 = 1 << 15, - TypeSpecifierMask__Atomic = 1 << 16, - TypeSpecifierMask_struct = 1 << 17, - TypeSpecifierMask_union = 1 << 18, - TypeSpecifierMask_enum = 1 << 19, - TypeSpecifierMask_typeof = 1 << 20, - TypeSpecifierMask_typeof_unqual = 1 << 21, - TypeSpecifierMask_typedef_name = 1 << 22, -} TypeSpecifierMask; - -static Type* distinguish_type_from_type_specifiers(int type_specifiers) { - if (type_specifiers == TypeSpecifierMask_void) - return type_new(TypeKind_void); - else if (type_specifiers == TypeSpecifierMask_char) - return type_new(TypeKind_char); - else if (type_specifiers == (TypeSpecifierMask_signed + TypeSpecifierMask_char)) - return type_new(TypeKind_schar); - else if (type_specifiers == (TypeSpecifierMask_unsigned + TypeSpecifierMask_char)) - return type_new(TypeKind_uchar); - else if (type_specifiers == TypeSpecifierMask_short || - type_specifiers == (TypeSpecifierMask_signed + TypeSpecifierMask_short) || - type_specifiers == (TypeSpecifierMask_short + TypeSpecifierMask_int) || - type_specifiers == (TypeSpecifierMask_signed + TypeSpecifierMask_short + TypeSpecifierMask_int)) - return type_new(TypeKind_short); - else if (type_specifiers == (TypeSpecifierMask_unsigned + TypeSpecifierMask_short) || - type_specifiers == (TypeSpecifierMask_unsigned + TypeSpecifierMask_short + TypeSpecifierMask_int)) - return type_new(TypeKind_ushort); - else if (type_specifiers == TypeSpecifierMask_int || type_specifiers == TypeSpecifierMask_signed || - type_specifiers == (TypeSpecifierMask_signed + TypeSpecifierMask_int)) - return type_new(TypeKind_int); - else if (type_specifiers == TypeSpecifierMask_unsigned || - type_specifiers == (TypeSpecifierMask_unsigned + TypeSpecifierMask_int)) - return type_new(TypeKind_uint); - else if (type_specifiers == TypeSpecifierMask_long || - type_specifiers == (TypeSpecifierMask_signed + TypeSpecifierMask_long) || - type_specifiers == (TypeSpecifierMask_long + TypeSpecifierMask_int) || - type_specifiers == (TypeSpecifierMask_signed + TypeSpecifierMask_long + TypeSpecifierMask_int)) - return type_new(TypeKind_long); - else if (type_specifiers == (TypeSpecifierMask_unsigned + TypeSpecifierMask_long) || - type_specifiers == (TypeSpecifierMask_unsigned + TypeSpecifierMask_long + TypeSpecifierMask_int)) - return type_new(TypeKind_ulong); - else if (type_specifiers == (TypeSpecifierMask_long + TypeSpecifierMask_long) || - type_specifiers == (TypeSpecifierMask_signed + TypeSpecifierMask_long + TypeSpecifierMask_long) || - type_specifiers == (TypeSpecifierMask_long + TypeSpecifierMask_long + TypeSpecifierMask_int) || - type_specifiers == - (TypeSpecifierMask_signed + TypeSpecifierMask_long + TypeSpecifierMask_long + TypeSpecifierMask_int)) - return type_new(TypeKind_llong); - else if (type_specifiers == (TypeSpecifierMask_unsigned + TypeSpecifierMask_long + TypeSpecifierMask_long) || - type_specifiers == - (TypeSpecifierMask_unsigned + TypeSpecifierMask_long + TypeSpecifierMask_long + TypeSpecifierMask_int)) - return type_new(TypeKind_ullong); - else if (type_specifiers == TypeSpecifierMask_float) - return type_new(TypeKind_float); - else if (type_specifiers == TypeSpecifierMask_double) - return type_new(TypeKind_double); - else if (type_specifiers == TypeSpecifierMask_long + TypeSpecifierMask_double) - return type_new(TypeKind_ldouble); - else if (type_specifiers == TypeSpecifierMask_bool) - return type_new(TypeKind_bool); - else if (type_specifiers == TypeSpecifierMask_struct) - return NULL; - else if (type_specifiers == TypeSpecifierMask_union) - return NULL; - else if (type_specifiers == TypeSpecifierMask_enum) - return NULL; - else if (type_specifiers == TypeSpecifierMask_typedef_name) - return NULL; - else if (type_specifiers == 0) - return NULL; - else - unimplemented(); -} - // declaration-specifiers: // { declaration-specifier }+ TODO attribute-specifier-sequence? // @@ -1823,7 +1429,7 @@ static Type* distinguish_type_from_type_specifiers(int type_specifiers) { // 'double' // 'signed' // 'unsigned' -// TODO '_BitInt' '(' constant-expression ')' +// TODO '_BitInt' '(' constant-expr ')' // 'bool' // '_Complex' // '_Decimal32' @@ -1843,7 +1449,7 @@ static Type* distinguish_type_from_type_specifiers(int type_specifiers) { // // alignment-specifier: // TODO 'alignas' '(' type-name ')' -// TODO 'alignas' '(' constant-expression ')' +// TODO 'alignas' '(' constant-expr ')' // // atomic-type-specifier: // TODO '_Atomic' '(' type-name ')' @@ -2057,6 +1663,175 @@ static Type* parse_declaration_specifiers(Parser* p) { return ty; } +// init-declarator: +// declarator +// declarator '=' initializer +static AstNode* parse_init_declarator(Parser* p, Type* ty) { + AstNode* decl = parse_declarator(p, ty); + if (consume_token_if(p, TokenKind_assign)) { + decl->as.declarator->init = parse_initializer(p); + } + return decl; +} + +// struct-specifier: +// 'struct' TODO attribute-specifier-sequence? identifier? '{' member-declaration-list '}' +// 'struct' TODO attribute-specifier-sequence? identifier +static Type* parse_struct_specifier(Parser* p) { + SourceLocation struct_kw_pos = peek_token(p)->loc; + next_token(p); + + const Token* name; + char* anonymous_name = NULL; + if (peek_token(p)->kind == TokenKind_brace_l) { + anonymous_name = generate_new_anonymous_user_type_name(p); + Token* anonymous_token = calloc(1, sizeof(Token)); + anonymous_token->kind = TokenKind_ident; + anonymous_token->value.string = anonymous_name; + anonymous_token->loc = struct_kw_pos; + name = anonymous_token; + } else { + name = parse_ident(p); + } + + if (!consume_token_if(p, TokenKind_brace_l)) { + int struct_idx = find_struct(p, name->value.string); + if (struct_idx != -1) { + Type* ty = type_new(TypeKind_struct); + ty->ref.defs = p->structs; + ty->ref.index = struct_idx; + return ty; + } else { + // TODO + AstNode* new_struct = ast_new_struct_def(name->value.string); + ast_append(p->structs, new_struct); + struct_idx = p->structs->as.list->len - 1; + + Type* ty = type_new(TypeKind_struct); + ty->ref.defs = p->structs; + ty->ref.index = struct_idx; + return ty; + } + } + + int struct_idx = find_struct(p, name->value.string); + if (struct_idx != -1 && p->structs->as.list->items[struct_idx].as.struct_def->members) { + fatal_error("%s:%d: struct %s redefined", name->loc.filename, name->loc.line, name->value.string); + } + + if (struct_idx == -1) { + AstNode* new_struct = ast_new_struct_def(name->value.string); + ast_append(p->structs, new_struct); + struct_idx = p->structs->as.list->len - 1; + } + + AstNode* members = parse_member_declaration_list(p); + expect(p, TokenKind_brace_r); + p->structs->as.list->items[struct_idx].as.struct_def->members = members; + + Type* ty = type_new(TypeKind_struct); + ty->ref.defs = p->structs; + ty->ref.index = struct_idx; + return ty; +} + +// union-specifier: +// 'union' TODO attribute-specifier-sequence? identifier? '{' member-declaration-list '}' +// 'union' TODO attribute-specifier-sequence? identifier +static Type* parse_union_specifier(Parser* p) { + SourceLocation union_kw_pos = peek_token(p)->loc; + next_token(p); + + const Token* name; + char* anonymous_name = NULL; + if (peek_token(p)->kind == TokenKind_brace_l) { + anonymous_name = generate_new_anonymous_user_type_name(p); + Token* anonymous_token = calloc(1, sizeof(Token)); + anonymous_token->kind = TokenKind_ident; + anonymous_token->value.string = anonymous_name; + anonymous_token->loc = union_kw_pos; + name = anonymous_token; + } else { + name = parse_ident(p); + } + + if (!consume_token_if(p, TokenKind_brace_l)) { + int union_idx = find_union(p, name->value.string); + if (union_idx != -1) { + Type* ty = type_new(TypeKind_union); + ty->ref.defs = p->unions; + ty->ref.index = union_idx; + return ty; + } else { + // TODO + AstNode* new_union = ast_new_union_def(name->value.string); + ast_append(p->unions, new_union); + union_idx = p->unions->as.list->len - 1; + + Type* ty = type_new(TypeKind_union); + ty->ref.defs = p->unions; + ty->ref.index = union_idx; + return ty; + } + } + + int union_idx = find_union(p, name->value.string); + if (union_idx != -1 && p->unions->as.list->items[union_idx].as.union_def->members) { + fatal_error("%s:%d: union %s redefined", name->loc.filename, name->loc.line, name->value.string); + } + + if (union_idx == -1) { + AstNode* new_union = ast_new_union_def(name->value.string); + ast_append(p->unions, new_union); + union_idx = p->unions->as.list->len - 1; + } + + AstNode* members = parse_member_declaration_list(p); + expect(p, TokenKind_brace_r); + p->unions->as.list->items[union_idx].as.union_def->members = members; + + Type* ty = type_new(TypeKind_union); + ty->ref.defs = p->unions; + ty->ref.index = union_idx; + return ty; +} + +// member-declaration-list: +// { member-declaration }+ +static AstNode* parse_member_declaration_list(Parser* p) { + AstNode* members = ast_new_list(4); + while (peek_token(p)->kind != TokenKind_brace_r) { + AstNode* decls = parse_member_declaration(p); + for (int i = 0; i < decls->as.list->len; i++) { + ast_append(members, &decls->as.list->items[i]); + } + } + return members; +} + +// member-declaration: +// TODO attribute-specifier-sequence? specifier-qualifier-list member-declaration-list? ';' +// TODO static_assert-declaration +static AstNode* parse_member_declaration(Parser* p) { + Type* base_ty = parse_specifier_qualifier_list(p); + + AstNode* decls = NULL; + if (consume_token_if(p, TokenKind_semicolon)) { + unimplemented(); + } + decls = parse_member_declarator_list(p, base_ty); + + expect(p, TokenKind_semicolon); + + for (int i = 0; i < decls->as.list->len; i++) { + const char* member_name = decls->as.list->items[i].as.declarator->name; + decls->as.list->items[i].kind = AstNodeKind_struct_member; + decls->as.list->items[i].as.struct_member = calloc(1, sizeof(StructMemberNode)); + decls->as.list->items[i].as.struct_member->name = member_name; + } + return decls; +} + // specifier-qualifier-list: // { type-specifier-qualifier }+ TODO attribute-specifier-sequence? static Type* parse_specifier_qualifier_list(Parser* p) { @@ -2222,6 +1997,131 @@ static Type* parse_specifier_qualifier_list(Parser* p) { return ty; } +// member-declarator-list: +// { member-declarator | ',' }+ +static AstNode* parse_member_declarator_list(Parser* p, Type* base_ty) { + AstNode* list = ast_new_list(1); + while (1) { + AstNode* d = parse_member_declarator(p, base_ty); + ast_append(list, d); + if (!consume_token_if(p, TokenKind_comma)) { + break; + } + } + return list; +} + +// member-declarator: +// declarator +// TODO declarator? ':' constant-expr +static AstNode* parse_member_declarator(Parser* p, Type* base_ty) { + return parse_declarator(p, base_ty); +} + +// enum-specifier: +// 'enum' TODO attribute-specifier-sequence? identifier? TODO enum-type-specifier? '{' enumerator-list ','? '}' +// 'enum' identifier TODO enum-type-specifier? +static Type* parse_enum_specifier(Parser* p) { + SourceLocation enum_kw_pos = peek_token(p)->loc; + next_token(p); + + const Token* name; + char* anonymous_name = NULL; + if (peek_token(p)->kind == TokenKind_brace_l) { + anonymous_name = generate_new_anonymous_user_type_name(p); + Token* anonymous_token = calloc(1, sizeof(Token)); + anonymous_token->kind = TokenKind_ident; + anonymous_token->value.string = anonymous_name; + anonymous_token->loc = enum_kw_pos; + name = anonymous_token; + } else { + name = parse_ident(p); + } + + if (!consume_token_if(p, TokenKind_brace_l)) { + int enum_idx = find_enum(p, name->value.string); + if (enum_idx != -1) { + Type* ty = type_new(TypeKind_enum); + ty->ref.defs = p->enums; + ty->ref.index = enum_idx; + return ty; + } else { + // TODO + AstNode* new_enum = ast_new_enum_def(name->value.string); + ast_append(p->enums, new_enum); + enum_idx = p->enums->as.list->len - 1; + + Type* ty = type_new(TypeKind_enum); + ty->ref.defs = p->enums; + ty->ref.index = enum_idx; + return ty; + } + } + + int enum_idx = find_enum(p, name->value.string); + if (enum_idx != -1 && p->enums->as.list->items[enum_idx].as.enum_def->members) { + fatal_error("%s:%d: enum %s redefined", name->loc.filename, name->loc.line, name->value.string); + } + + if (enum_idx == -1) { + AstNode* new_enum = ast_new_enum_def(name->value.string); + ast_append(p->enums, new_enum); + enum_idx = p->enums->as.list->len - 1; + } + + parse_enum_members(p, enum_idx); + expect(p, TokenKind_brace_r); + + Type* ty = type_new(TypeKind_enum); + ty->ref.defs = p->enums; + ty->ref.index = enum_idx; + return ty; +} + +// enumerator-list: +// { enumerator | ',' }+ +static void parse_enum_members(Parser* p, int enum_idx) { + int next_value = 0; + AstNode* list = ast_new_list(16); + + if (!p->enums->as.list->items[enum_idx].as.enum_def->members) { + p->enums->as.list->items[enum_idx].as.enum_def->members = list; + } + + while (peek_token(p)->kind != TokenKind_brace_r) { + AstNode* member = parse_enum_member(p, next_value); + next_value = member->as.enum_member->value + 1; + + ast_append(list, member); + + if (!consume_token_if(p, TokenKind_comma)) { + break; + } + } +} + +// enumerator: +// enumeration-constant TODO attribute-specifier-sequence? ( '=' constant-expr )? +static AstNode* parse_enum_member(Parser* p, int next_value) { + const Token* name = parse_ident(p); + int value; + if (consume_token_if(p, TokenKind_assign)) { + AstNode* expr = parse_constant_expr(p); + value = eval(expr); + } else { + value = next_value; + } + return ast_new_enum_member(name->value.string, value); +} + +// type-name: +// specifier-qualifier-list abstract-declarator? +static Type* parse_type_name(Parser* p) { + Type* ty = parse_specifier_qualifier_list(p); + ty = parse_abstract_declarator_opt(p, ty); + return ty; +} + // abstract-declarator: // pointer // pointer? TODO direct-abstract-declarator @@ -2232,15 +2132,265 @@ static Type* parse_abstract_declarator_opt(Parser* p, Type* ty) { return parse_pointer_opt(p, ty); } -// type-name: -// specifier-qualifier-list abstract-declarator? -static Type* parse_type_name(Parser* p) { - Type* ty = parse_specifier_qualifier_list(p); - ty = parse_abstract_declarator_opt(p, ty); - return ty; +// initializer: +// assignment-expr +// TODO braced-initializer +static AstNode* parse_initializer(Parser* p) { + return parse_assignment_expr(p); } -static AstNode* parse_toplevel(Parser* p) { +// stmt: +// labeled-stmt +// unlabeled-stmt +// +// labeled-stmt: +// label stmt +// +// label: +// TODO attribute-specifier-sequence? identifier ':' +// TODO attribute-specifier-sequence? 'case' constant-expr ':' +// TODO attribute-specifier-sequence? 'default' ':' +static AstNode* parse_stmt(Parser* p) { + Token* t = peek_token(p); + + if (t->kind == TokenKind_keyword_case) { + if (!p->current_switch) { + fatal_error("%s:%d: 'case' label not within a switch statement", t->loc.filename, t->loc.line); + } + expect(p, TokenKind_keyword_case); + AstNode* value = parse_constant_expr(p); + expect(p, TokenKind_colon); + AstNode* stmt = parse_stmt(p); + + return ast_new_case_label(eval(value), stmt); + } else if (t->kind == TokenKind_keyword_default) { + if (!p->current_switch) { + fatal_error("%s:%d: 'default' label not within a switch statement", t->loc.filename, t->loc.line); + } + expect(p, TokenKind_keyword_default); + expect(p, TokenKind_colon); + AstNode* stmt = parse_stmt(p); + + return ast_new_default_label(stmt); + } else if (t->kind == TokenKind_keyword_return) { + return parse_return_stmt(p); + } else if (t->kind == TokenKind_keyword_if) { + return parse_if_stmt(p); + } else if (t->kind == TokenKind_keyword_switch) { + return parse_switch_stmt(p); + } else if (t->kind == TokenKind_keyword_for) { + return parse_for_stmt(p); + } else if (t->kind == TokenKind_keyword_while) { + return parse_while_stmt(p); + } else if (t->kind == TokenKind_keyword_do) { + return parse_do_while_stmt(p); + } else if (t->kind == TokenKind_keyword_break) { + return parse_break_stmt(p); + } else if (t->kind == TokenKind_keyword_continue) { + return parse_continue_stmt(p); + } else if (t->kind == TokenKind_keyword_goto) { + expect(p, TokenKind_keyword_goto); + Token* label_token = expect(p, TokenKind_ident); + expect(p, TokenKind_semicolon); + + return ast_new_goto_stmt(label_token->value.string); + } else if (t->kind == TokenKind_brace_l) { + return parse_block_stmt(p); + } else if (t->kind == TokenKind_semicolon) { + return parse_empty_stmt(p); + } else if (is_type_token(p, t)) { + return parse_var_decl(p); + } else if (t->kind == TokenKind_ident && peek_token2(p)->kind == TokenKind_colon) { + // Label statement + Token* label_token = expect(p, TokenKind_ident); + expect(p, TokenKind_colon); + AstNode* stmt = parse_stmt(p); + + return ast_new_label_stmt(label_token->value.string, stmt); + } else { + return parse_expr_stmt(p); + } +} + +static AstNode* parse_empty_stmt(Parser* p) { + consume_token_if(p, TokenKind_semicolon); + return ast_new_nop(); +} + +// compound-stmt: +// '{' block-item-list? '}' +// +// block-item-list: +// { block-item }+ +static AstNode* parse_block_stmt(Parser* p) { + AstNode* list = ast_new_list(4); + expect(p, TokenKind_brace_l); + enter_scope(p); + while (peek_token(p)->kind != TokenKind_brace_r) { + AstNode* stmt = parse_stmt(p); + ast_append(list, stmt); + } + leave_scope(p); + expect(p, TokenKind_brace_r); + return list; +} + +// expr-stmt: +// TODO attribute-specifier-sequence? expr? ';' +static AstNode* parse_expr_stmt(Parser* p) { + AstNode* e = parse_expr(p); + expect(p, TokenKind_semicolon); + return ast_new_expr_stmt(e); +} + +// selection-stmt: +// 'if' '(' expr ')' stmt ( 'else' stmt )? +static AstNode* parse_if_stmt(Parser* p) { + expect(p, TokenKind_keyword_if); + expect(p, TokenKind_paren_l); + AstNode* cond = parse_expr(p); + expect(p, TokenKind_paren_r); + AstNode* then_body = parse_stmt(p); + AstNode* else_body = NULL; + if (consume_token_if(p, TokenKind_keyword_else)) { + else_body = parse_stmt(p); + } + + return ast_new_if_stmt(cond, then_body, else_body); +} + +// selection-stmt: +// 'switch' '(' expr ')' stmt +static AstNode* parse_switch_stmt(Parser* p) { + expect(p, TokenKind_keyword_switch); + expect(p, TokenKind_paren_l); + AstNode* expr = parse_expr(p); + expect(p, TokenKind_paren_r); + + AstNode* tmp_var = generate_temporary_lvar(p, expr->ty); + AstNode* assignment = ast_new_assign_expr(TokenKind_assign, tmp_var, expr); + AstNode* assign_stmt = ast_new_expr_stmt(assignment); + + AstNode* switch_stmt = ast_new_switch_stmt(tmp_var); + + AstNode* prev_switch = p->current_switch; + p->current_switch = switch_stmt; + switch_stmt->as.switch_stmt->body = parse_stmt(p); + p->current_switch = prev_switch; + + AstNode* list = ast_new_list(2); + ast_append(list, assign_stmt); + ast_append(list, switch_stmt); + return list; +} + +// iteration-stmt: +// 'while' '(' expr ')' stmt +static AstNode* parse_while_stmt(Parser* p) { + expect(p, TokenKind_keyword_while); + expect(p, TokenKind_paren_l); + AstNode* cond = parse_expr(p); + expect(p, TokenKind_paren_r); + AstNode* body = parse_stmt(p); + return ast_new_for_stmt(NULL, cond, NULL, body); +} + +// iteration-stmt: +// 'do' stmt 'while' '(' expr ')' ';' +static AstNode* parse_do_while_stmt(Parser* p) { + expect(p, TokenKind_keyword_do); + AstNode* body = parse_stmt(p); + expect(p, TokenKind_keyword_while); + expect(p, TokenKind_paren_l); + AstNode* cond = parse_expr(p); + expect(p, TokenKind_paren_r); + expect(p, TokenKind_semicolon); + + return ast_new_do_while_stmt(cond, body); +} + +// iteration-stmt: +// 'for' '(' expr? ';' expr? ';' expr? ')' stmt +// 'for' '(' declaration expr? ';' expr? ')' stmt +static AstNode* parse_for_stmt(Parser* p) { + expect(p, TokenKind_keyword_for); + expect(p, TokenKind_paren_l); + AstNode* init = NULL; + AstNode* cond = NULL; + AstNode* update = NULL; + enter_scope(p); + if (peek_token(p)->kind != TokenKind_semicolon) { + if (is_type_token(p, peek_token(p))) { + AstNode* decls = parse_var_decl(p); + AstNode* initializers = ast_new_list(1); + for (int i = 0; i < decls->as.list->len; i++) { + AstNode* item = &decls->as.list->items[i]; + if (item->kind == AstNodeKind_expr_stmt) { + ast_append(initializers, item->as.expr_stmt->expr); + } + } + init = initializers; + } else { + init = parse_expr(p); + expect(p, TokenKind_semicolon); + } + } else { + expect(p, TokenKind_semicolon); + } + if (peek_token(p)->kind != TokenKind_semicolon) { + cond = parse_expr(p); + } else { + cond = ast_new_int(1); + } + expect(p, TokenKind_semicolon); + if (peek_token(p)->kind != TokenKind_paren_r) { + update = parse_expr(p); + } + expect(p, TokenKind_paren_r); + AstNode* body = parse_stmt(p); + leave_scope(p); + return ast_new_for_stmt(init, cond, update, body); +} + +// jump-stmt: +// 'continue' ';' +static AstNode* parse_continue_stmt(Parser* p) { + expect(p, TokenKind_keyword_continue); + expect(p, TokenKind_semicolon); + return ast_new_continue_stmt(); +} + +// jump-stmt: +// 'break' ';' +static AstNode* parse_break_stmt(Parser* p) { + expect(p, TokenKind_keyword_break); + expect(p, TokenKind_semicolon); + return ast_new_break_stmt(); +} + +// jump-stmt: +// 'return' expr? ';' +static AstNode* parse_return_stmt(Parser* p) { + expect(p, TokenKind_keyword_return); + if (consume_token_if(p, TokenKind_semicolon)) { + return ast_new_return_stmt(NULL); + } + + AstNode* expr = parse_expr(p); + expect(p, TokenKind_semicolon); + return ast_new_return_stmt(expr); +} + +// external-declaration: +// TODO static_assert-declaration +// TODO attribute-specifier-sequence ';' +// TODO attribute-specifier-sequence function-definition-or-declaration-rest +// function-definition-or-declaration-rest +// +// function-definition-or-declaration-rest: +// declaration-specifiers init-declarator-list ';' +// declaration-specifiers init-declarator-list compound-stmt +static AstNode* parse_external_declaration(Parser* p) { Type* ty = parse_declaration_specifiers(p); if (consume_token_if(p, TokenKind_semicolon)) { // Type declaration. @@ -2263,12 +2413,14 @@ static AstNode* parse_toplevel(Parser* p) { } } +// translation-unit: +// { external-declaration }+ Program* parse(TokenArray* tokens) { Parser* p = parser_new(tokens); AstNode* funcs = ast_new_list(32); AstNode* vars = ast_new_list(16); while (eof(p)) { - AstNode* n = parse_toplevel(p); + AstNode* n = parse_external_declaration(p); if (!n) continue; if (n->kind == AstNodeKind_func_def) { @@ -2367,9 +2519,9 @@ static int eval(AstNode* e) { } } -bool pp_eval_constant_expression(TokenArray* pp_tokens) { +bool pp_eval_constant_expr(TokenArray* pp_tokens) { TokenArray* tokens = convert_pp_tokens_to_tokens(pp_tokens); Parser* p = parser_new(tokens); - AstNode* e = parse_constant_expression(p); + AstNode* e = parse_constant_expr(p); return eval(e) != 0; } diff --git a/src/parse.h b/src/parse.h index bda2999..7649575 100644 --- a/src/parse.h +++ b/src/parse.h @@ -5,6 +5,6 @@ #include "preprocess.h" Program* parse(TokenArray* tokens); -bool pp_eval_constant_expression(TokenArray* pp_tokens); +bool pp_eval_constant_expr(TokenArray* pp_tokens); #endif diff --git a/src/preprocess.c b/src/preprocess.c index 5ccf698..2dede0f 100644 --- a/src/preprocess.c +++ b/src/preprocess.c @@ -947,7 +947,7 @@ static bool preprocess_if_group_or_elif_group(Preprocessor* pp, bool did_include Token* directive = next_pp_token(pp); if (directive->kind == TokenKind_pp_directive_if || directive->kind == TokenKind_pp_directive_elif) { - int condition_expression_start_pos = pp->pos; + int condition_expr_start_pos = pp->pos; while (!pp_eof(pp)) { Token* tok = peek_pp_token(pp); @@ -987,7 +987,7 @@ static bool preprocess_if_group_or_elif_group(Preprocessor* pp, bool did_include // all remaining identifiers other than true (including those lexically identical to keywords such as false) are // replaced with the pp-number 0, true is replaced with pp-number 1, and then each preprocessing token is // converted into a token. - for (int pos = condition_expression_start_pos; pos < pp->pos; ++pos) { + for (int pos = condition_expr_start_pos; pos < pp->pos; ++pos) { Token* tok = pp_token_at(pp, pos); if (tok->kind == TokenKind_ident) { bool is_true = strcmp(tok->value.string, "true") == 0; @@ -996,17 +996,17 @@ static bool preprocess_if_group_or_elif_group(Preprocessor* pp, bool did_include } } - int condition_expression_tokens_len = pp->pos - condition_expression_start_pos; - TokenArray condition_expression_tokens; + int condition_expr_tokens_len = pp->pos - condition_expr_start_pos; + TokenArray condition_expr_tokens; // +1 to add EOF token at the end. - tokens_init(&condition_expression_tokens, condition_expression_tokens_len + 1); - for (int i = 0; i < condition_expression_tokens_len; ++i) { - *tokens_push_new(&condition_expression_tokens) = *pp_token_at(pp, condition_expression_start_pos + i); + tokens_init(&condition_expr_tokens, condition_expr_tokens_len + 1); + for (int i = 0; i < condition_expr_tokens_len; ++i) { + *tokens_push_new(&condition_expr_tokens) = *pp_token_at(pp, condition_expr_start_pos + i); } - Token* eof_tok = tokens_push_new(&condition_expression_tokens); + Token* eof_tok = tokens_push_new(&condition_expr_tokens); eof_tok->kind = TokenKind_eof; - bool do_include = pp_eval_constant_expression(&condition_expression_tokens) && !did_include; + bool do_include = pp_eval_constant_expr(&condition_expr_tokens) && !did_include; include_conditionally(pp, GroupDelimiterKind_after_if_directive, do_include); return do_include; } else if (directive->kind == TokenKind_pp_directive_ifdef || directive->kind == TokenKind_pp_directive_elifdef) { |
