aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-01-23 23:42:06 +0900
committernsfisis <nsfisis@gmail.com>2026-01-24 00:17:02 +0900
commite6565082b66a9e4b2c5286d9487ef731fcd5e33a (patch)
tree6111b7460e46c63e9959322c9650f33138f3de6f
parent52df9f8ce8abf17bf6ca70c174a48f41e5ad31d5 (diff)
downloadducc-e6565082b66a9e4b2c5286d9487ef731fcd5e33a.tar.gz
ducc-e6565082b66a9e4b2c5286d9487ef731fcd5e33a.tar.zst
ducc-e6565082b66a9e4b2c5286d9487ef731fcd5e33a.zip
docs: add docs/c_grammar.md
-rw-r--r--docs/c_grammar.md443
-rw-r--r--src/parse.c1694
-rw-r--r--src/parse.h2
-rw-r--r--src/preprocess.c18
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 = &params->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 = &params->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) {