diff options
| -rw-r--r-- | include/stdarg.h | 6 | ||||
| -rw-r--r-- | include/stddef.h | 3 | ||||
| -rw-r--r-- | src/ast.c | 72 | ||||
| -rw-r--r-- | src/ast.h | 15 | ||||
| -rw-r--r-- | src/parse.c | 312 | ||||
| -rw-r--r-- | tests/115.sh | 185 |
6 files changed, 521 insertions, 72 deletions
diff --git a/include/stdarg.h b/include/stdarg.h index 1d448f8..fdc0b80 100644 --- a/include/stdarg.h +++ b/include/stdarg.h @@ -7,10 +7,8 @@ // Version 1.0 // Figure 3.34: va_list Type Declaration struct __ducc_va_list { - // unsigned int gp_offset; - // unsigned int fp_offset; - int gp_offset; - int fp_offset; + unsigned int gp_offset; + unsigned int fp_offset; void* overflow_arg_area; void* reg_save_area; }; diff --git a/include/stddef.h b/include/stddef.h index 702d91a..07e49d3 100644 --- a/include/stddef.h +++ b/include/stddef.h @@ -3,8 +3,7 @@ #define NULL 0 -// TODO: unsigned -typedef long size_t; +typedef unsigned long size_t; // TODO: // - max_align_t (C11) @@ -5,26 +5,40 @@ const char* type_kind_stringify(TypeKind k) { if (k == TypeKind_unknown) return "<unknown>"; + else if (k == TypeKind_void) + return "void"; else if (k == TypeKind_char) return "char"; + else if (k == TypeKind_schar) + return "signed char"; + else if (k == TypeKind_uchar) + return "unsigned char"; else if (k == TypeKind_short) return "short"; + else if (k == TypeKind_ushort) + return "unsigned short"; else if (k == TypeKind_int) return "int"; + else if (k == TypeKind_uint) + return "unsigned int"; else if (k == TypeKind_long) return "long"; - else if (k == TypeKind_void) - return "void"; - else if (k == TypeKind_ptr) - return "<pointer>"; - else if (k == TypeKind_array) - return "<array>"; - else if (k == TypeKind_enum) - return "enum"; + else if (k == TypeKind_ulong) + return "unsigned long"; + else if (k == TypeKind_llong) + return "long long"; + else if (k == TypeKind_ullong) + return "unsigned long long"; else if (k == TypeKind_struct) return "struct"; else if (k == TypeKind_union) return "union"; + else if (k == TypeKind_enum) + return "enum"; + else if (k == TypeKind_ptr) + return "<pointer>"; + else if (k == TypeKind_array) + return "<array>"; else unreachable(); } @@ -71,24 +85,25 @@ int type_sizeof(Type* ty) { fatal_error("type_sizeof: type size cannot be determined"); } - if (ty->kind == TypeKind_ptr) - return 8; - else if (ty->kind == TypeKind_char) + if (ty->kind == TypeKind_char || ty->kind == TypeKind_schar || ty->kind == TypeKind_uchar) return 1; - else if (ty->kind == TypeKind_short) + else if (ty->kind == TypeKind_short || ty->kind == TypeKind_ushort) return 2; - else if (ty->kind == TypeKind_int) + else if (ty->kind == TypeKind_int || ty->kind == TypeKind_uint) return 4; - else if (ty->kind == TypeKind_long) + else if (ty->kind == TypeKind_long || ty->kind == TypeKind_ulong || ty->kind == TypeKind_llong || + ty->kind == TypeKind_ullong) return 8; - else if (ty->kind == TypeKind_enum) - return 4; - else if (ty->kind == TypeKind_array) - return type_sizeof(ty->base) * ty->array_size; else if (ty->kind == TypeKind_struct) return type_sizeof_struct(ty); else if (ty->kind == TypeKind_union) return type_sizeof_union(ty); + else if (ty->kind == TypeKind_enum) + return 4; + else if (ty->kind == TypeKind_ptr) + return 8; + else if (ty->kind == TypeKind_array) + return type_sizeof(ty->base) * ty->array_size; else unreachable(); } @@ -98,24 +113,25 @@ int type_alignof(Type* ty) { fatal_error("type_alignof: type size cannot be determined"); } - if (ty->kind == TypeKind_ptr) - return 8; - else if (ty->kind == TypeKind_char) + if (ty->kind == TypeKind_char || ty->kind == TypeKind_schar || ty->kind == TypeKind_uchar) return 1; - else if (ty->kind == TypeKind_short) + else if (ty->kind == TypeKind_short || ty->kind == TypeKind_ushort) return 2; - else if (ty->kind == TypeKind_int) + else if (ty->kind == TypeKind_int || ty->kind == TypeKind_uint) return 4; - else if (ty->kind == TypeKind_long) + else if (ty->kind == TypeKind_long || ty->kind == TypeKind_ulong || ty->kind == TypeKind_llong || + ty->kind == TypeKind_ullong) return 8; - else if (ty->kind == TypeKind_enum) - return 4; - else if (ty->kind == TypeKind_array) - return type_alignof(ty->base); else if (ty->kind == TypeKind_struct) return type_alignof_struct(ty); else if (ty->kind == TypeKind_union) return type_alignof_union(ty); + else if (ty->kind == TypeKind_enum) + return 4; + else if (ty->kind == TypeKind_ptr) + return 8; + else if (ty->kind == TypeKind_array) + return type_alignof(ty->base); else unreachable(); } @@ -18,16 +18,23 @@ typedef enum StorageClass StorageClass; enum TypeKind { TypeKind_unknown, + TypeKind_void, TypeKind_char, + TypeKind_schar, + TypeKind_uchar, TypeKind_short, + TypeKind_ushort, TypeKind_int, + TypeKind_uint, TypeKind_long, - TypeKind_void, - TypeKind_ptr, - TypeKind_array, - TypeKind_enum, + TypeKind_ulong, + TypeKind_llong, + TypeKind_ullong, TypeKind_struct, TypeKind_union, + TypeKind_enum, + TypeKind_ptr, + TypeKind_array, }; typedef enum TypeKind TypeKind; diff --git a/src/parse.c b/src/parse.c index 422cc64..e2466ad 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1377,7 +1377,6 @@ static Type* parse_struct_specifier(Parser* p) { AstNode* members = parse_struct_members(p); expect(p, TokenKind_brace_r); - expect(p, TokenKind_semicolon); p->structs->node_items[struct_idx].node_members = members; Type* ty = type_new(TypeKind_struct); @@ -1430,7 +1429,6 @@ static Type* parse_union_specifier(Parser* p) { AstNode* members = parse_union_members(p); expect(p, TokenKind_brace_r); - expect(p, TokenKind_semicolon); p->unions->node_items[union_idx].node_members = members; Type* ty = type_new(TypeKind_union); @@ -1491,6 +1489,90 @@ static Type* parse_enum_specifier(Parser* p) { return ty; } +enum TypeSpecifierMask { + // TODO: define these constants with shift operators once ducc supports it. + TypeSpecifierMask_void = 1, + TypeSpecifierMask_char = 2, + TypeSpecifierMask_short = 4, + TypeSpecifierMask_int = 8, + TypeSpecifierMask_long = 16, + // 1 << 5 is used for second 'long'. + TypeSpecifierMask_float = 64, + TypeSpecifierMask_double = 128, + TypeSpecifierMask_signed = 256, + TypeSpecifierMask_unsigned = 512, + TypeSpecifierMask__BitInt = 1024, + TypeSpecifierMask_bool = 2048, + TypeSpecifierMask__Complex = 4096, + TypeSpecifierMask__Decimal32 = 8192, + TypeSpecifierMask__Decimal64 = 16384, + TypeSpecifierMask__Decimal128 = 32768, + TypeSpecifierMask__Atomic = 65536, + TypeSpecifierMask_struct = 131072, + TypeSpecifierMask_union = 262144, + TypeSpecifierMask_enum = 524288, + TypeSpecifierMask_typeof = 1048576, + TypeSpecifierMask_typeof_unqual = 2097152, + TypeSpecifierMask_typedef_name = 4194304, +}; +typedef enum TypeSpecifierMask 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_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) { + fatal_error("no type specifiers"); + } else { + unimplemented(); + } +} + // declaration-specifiers: // { declaration-specifier }+ TODO attribute-specifier-sequence? // @@ -1567,6 +1649,7 @@ static Type* parse_enum_specifier(Parser* p) { // identifier static Type* parse_declaration_specifiers(Parser* p) { StorageClass storage_class = StorageClass_unspecified; + int type_specifiers = 0; Type* ty = NULL; while (1) { @@ -1593,56 +1676,131 @@ static Type* parse_declaration_specifiers(Parser* p) { } // type-specifier-qualifier > type-specifier else if (tok->kind == TokenKind_keyword_void) { + if (type_specifiers & TypeSpecifierMask_void) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } next_token(p); - ty = type_new(TypeKind_void); + type_specifiers += TypeSpecifierMask_void; } else if (tok->kind == TokenKind_keyword_char) { + if (type_specifiers & TypeSpecifierMask_char) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } next_token(p); - ty = type_new(TypeKind_char); + type_specifiers += TypeSpecifierMask_char; } else if (tok->kind == TokenKind_keyword_short) { + if (type_specifiers & TypeSpecifierMask_short) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } next_token(p); - ty = type_new(TypeKind_short); + type_specifiers += TypeSpecifierMask_short; } else if (tok->kind == TokenKind_keyword_int) { + if (type_specifiers & TypeSpecifierMask_int) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } next_token(p); - ty = type_new(TypeKind_int); + type_specifiers += TypeSpecifierMask_int; } else if (tok->kind == TokenKind_keyword_long) { + if (type_specifiers & (TypeSpecifierMask_long + TypeSpecifierMask_long)) { + fatal_error("%s:%d: too looong!", tok->loc.filename, tok->loc.line); + } next_token(p); - ty = type_new(TypeKind_long); + type_specifiers += TypeSpecifierMask_long; } else if (tok->kind == TokenKind_keyword_float) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask_float) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask_float; } else if (tok->kind == TokenKind_keyword_double) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask_double) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask_double; } else if (tok->kind == TokenKind_keyword_signed) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask_signed) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask_signed; } else if (tok->kind == TokenKind_keyword_unsigned) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask_unsigned) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask_unsigned; } else if (tok->kind == TokenKind_keyword__BitInt) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask__BitInt) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask__BitInt; } else if (tok->kind == TokenKind_keyword_bool) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask_bool) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask_bool; } else if (tok->kind == TokenKind_keyword__Complex) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask__Complex) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask__Complex; } else if (tok->kind == TokenKind_keyword__Decimal32) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask__Decimal32) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask__Decimal32; } else if (tok->kind == TokenKind_keyword__Decimal64) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask__Decimal64) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask__Decimal64; } else if (tok->kind == TokenKind_keyword__Decimal128) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask__Decimal128) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask__Decimal128; } else if (tok->kind == TokenKind_keyword__Atomic) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask__Atomic) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask__Atomic; } else if (tok->kind == TokenKind_keyword_struct) { + if (type_specifiers & TypeSpecifierMask_struct) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } ty = parse_struct_specifier(p); + type_specifiers += TypeSpecifierMask_struct; } else if (tok->kind == TokenKind_keyword_union) { + if (type_specifiers & TypeSpecifierMask_union) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } ty = parse_union_specifier(p); + type_specifiers += TypeSpecifierMask_union; } else if (tok->kind == TokenKind_keyword_enum) { + if (type_specifiers & TypeSpecifierMask_enum) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } ty = parse_enum_specifier(p); + type_specifiers += TypeSpecifierMask_enum; } else if (tok->kind == TokenKind_keyword_typeof) { unimplemented(); } else if (tok->kind == TokenKind_keyword_typeof_unqual) { unimplemented(); } else if (is_typedef_name(p, tok)) { + if (type_specifiers & TypeSpecifierMask_typedef_name) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } next_token(p); int typedef_idx = find_typedef(p, tok->value.string); ty = p->typedefs->node_items[typedef_idx].ty; + type_specifiers += TypeSpecifierMask_typedef_name; } // type-specifier-qualifier > type-qualifier else if (tok->kind == TokenKind_keyword_const) { @@ -1670,6 +1828,11 @@ static Type* parse_declaration_specifiers(Parser* p) { } } + Type* ty_ = distinguish_type_from_type_specifiers(type_specifiers); + if (ty_) { + ty = ty_; + } + ty->storage_class = storage_class; return ty; } @@ -1677,6 +1840,7 @@ static Type* parse_declaration_specifiers(Parser* p) { // specifier-qualifier-list: // { type-specifier-qualifier }+ TODO attribute-specifier-sequence? static Type* parse_specifier_qualifier_list(Parser* p) { + int type_specifiers = 0; Type* ty = NULL; while (1) { @@ -1684,56 +1848,131 @@ static Type* parse_specifier_qualifier_list(Parser* p) { // type-specifier-qualifier > type-specifier if (tok->kind == TokenKind_keyword_void) { + if (type_specifiers & TypeSpecifierMask_void) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } next_token(p); - ty = type_new(TypeKind_void); + type_specifiers += TypeSpecifierMask_void; } else if (tok->kind == TokenKind_keyword_char) { + if (type_specifiers & TypeSpecifierMask_char) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } next_token(p); - ty = type_new(TypeKind_char); + type_specifiers += TypeSpecifierMask_char; } else if (tok->kind == TokenKind_keyword_short) { + if (type_specifiers & TypeSpecifierMask_short) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } next_token(p); - ty = type_new(TypeKind_short); + type_specifiers += TypeSpecifierMask_short; } else if (tok->kind == TokenKind_keyword_int) { + if (type_specifiers & TypeSpecifierMask_int) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } next_token(p); - ty = type_new(TypeKind_int); + type_specifiers += TypeSpecifierMask_int; } else if (tok->kind == TokenKind_keyword_long) { + if (type_specifiers & (TypeSpecifierMask_long + TypeSpecifierMask_long)) { + fatal_error("%s:%d: too looong!", tok->loc.filename, tok->loc.line); + } next_token(p); - ty = type_new(TypeKind_long); + type_specifiers += TypeSpecifierMask_long; } else if (tok->kind == TokenKind_keyword_float) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask_float) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask_float; } else if (tok->kind == TokenKind_keyword_double) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask_double) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask_double; } else if (tok->kind == TokenKind_keyword_signed) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask_signed) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask_signed; } else if (tok->kind == TokenKind_keyword_unsigned) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask_unsigned) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask_unsigned; } else if (tok->kind == TokenKind_keyword__BitInt) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask__BitInt) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask__BitInt; } else if (tok->kind == TokenKind_keyword_bool) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask_bool) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask_bool; } else if (tok->kind == TokenKind_keyword__Complex) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask__Complex) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask__Complex; } else if (tok->kind == TokenKind_keyword__Decimal32) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask__Decimal32) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask__Decimal32; } else if (tok->kind == TokenKind_keyword__Decimal64) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask__Decimal64) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask__Decimal64; } else if (tok->kind == TokenKind_keyword__Decimal128) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask__Decimal128) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask__Decimal128; } else if (tok->kind == TokenKind_keyword__Atomic) { - unimplemented(); + if (type_specifiers & TypeSpecifierMask__Atomic) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } + next_token(p); + type_specifiers += TypeSpecifierMask__Atomic; } else if (tok->kind == TokenKind_keyword_struct) { + if (type_specifiers & TypeSpecifierMask_struct) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } ty = parse_struct_specifier(p); + type_specifiers += TypeSpecifierMask_struct; } else if (tok->kind == TokenKind_keyword_union) { + if (type_specifiers & TypeSpecifierMask_union) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } ty = parse_union_specifier(p); + type_specifiers += TypeSpecifierMask_union; } else if (tok->kind == TokenKind_keyword_enum) { + if (type_specifiers & TypeSpecifierMask_enum) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } ty = parse_enum_specifier(p); + type_specifiers += TypeSpecifierMask_enum; } else if (tok->kind == TokenKind_keyword_typeof) { unimplemented(); } else if (tok->kind == TokenKind_keyword_typeof_unqual) { unimplemented(); } else if (is_typedef_name(p, tok)) { + if (type_specifiers & TypeSpecifierMask_typedef_name) { + fatal_error("%s:%d: duplicate '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok)); + } next_token(p); int typedef_idx = find_typedef(p, tok->value.string); ty = p->typedefs->node_items[typedef_idx].ty; + type_specifiers += TypeSpecifierMask_typedef_name; } // type-specifier-qualifier > type-qualifier else if (tok->kind == TokenKind_keyword_const) { @@ -1754,6 +1993,11 @@ static Type* parse_specifier_qualifier_list(Parser* p) { } } + Type* ty_ = distinguish_type_from_type_specifiers(type_specifiers); + if (ty_) { + ty = ty_; + } + return ty; } diff --git a/tests/115.sh b/tests/115.sh new file mode 100644 index 0000000..ea7ca0b --- /dev/null +++ b/tests/115.sh @@ -0,0 +1,185 @@ +cat <<'EOF' > expected +1 +1 +1 +1 +1 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +4 +4 +4 +4 +4 +4 +4 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +EOF + +test_diff <<'EOF' +int printf(); + +int main() { + printf("%d\n", sizeof(char)); + printf("%d\n", sizeof(signed char)); + printf("%d\n", sizeof(char signed)); + printf("%d\n", sizeof(unsigned char)); + printf("%d\n", sizeof(char unsigned)); + + printf("%d\n", sizeof(short)); + printf("%d\n", sizeof(signed short)); + printf("%d\n", sizeof(short signed)); + printf("%d\n", sizeof(short int)); + printf("%d\n", sizeof(int short)); + printf("%d\n", sizeof(signed short int)); + printf("%d\n", sizeof(signed int short)); + printf("%d\n", sizeof(short signed int)); + printf("%d\n", sizeof(short int signed)); + printf("%d\n", sizeof(int short signed)); + printf("%d\n", sizeof(int signed short)); + + printf("%d\n", sizeof(unsigned short)); + printf("%d\n", sizeof(short unsigned)); + printf("%d\n", sizeof(unsigned short int)); + printf("%d\n", sizeof(unsigned int short)); + printf("%d\n", sizeof(short unsigned int)); + printf("%d\n", sizeof(short int unsigned)); + printf("%d\n", sizeof(int short unsigned)); + printf("%d\n", sizeof(int unsigned short)); + + printf("%d\n", sizeof(int)); + printf("%d\n", sizeof(signed)); + printf("%d\n", sizeof(signed int)); + printf("%d\n", sizeof(int signed)); + + printf("%d\n", sizeof(unsigned)); + printf("%d\n", sizeof(unsigned int)); + printf("%d\n", sizeof(int unsigned)); + + printf("%d\n", sizeof(long)); + printf("%d\n", sizeof(signed long)); + printf("%d\n", sizeof(long signed)); + printf("%d\n", sizeof(long int)); + printf("%d\n", sizeof(int long)); + printf("%d\n", sizeof(signed long int)); + printf("%d\n", sizeof(signed int long)); + printf("%d\n", sizeof(long signed int)); + printf("%d\n", sizeof(long int signed)); + printf("%d\n", sizeof(int long signed)); + printf("%d\n", sizeof(int signed long)); + + printf("%d\n", sizeof(unsigned long)); + printf("%d\n", sizeof(long unsigned)); + printf("%d\n", sizeof(unsigned long int)); + printf("%d\n", sizeof(unsigned int long)); + printf("%d\n", sizeof(long unsigned int)); + printf("%d\n", sizeof(long int unsigned)); + printf("%d\n", sizeof(int long unsigned)); + printf("%d\n", sizeof(int unsigned long)); + + printf("%d\n", sizeof(long long)); + printf("%d\n", sizeof(signed long long)); + printf("%d\n", sizeof(long signed long)); + printf("%d\n", sizeof(long long signed)); + printf("%d\n", sizeof(long long int)); + printf("%d\n", sizeof(long int long)); + printf("%d\n", sizeof(int long long)); + printf("%d\n", sizeof(signed long long int)); + printf("%d\n", sizeof(signed long int long)); + printf("%d\n", sizeof(signed int long long)); + printf("%d\n", sizeof(long signed long int)); + printf("%d\n", sizeof(long signed int long)); + printf("%d\n", sizeof(int signed long long)); + printf("%d\n", sizeof(long long signed int)); + printf("%d\n", sizeof(long int signed long)); + printf("%d\n", sizeof(int long signed long)); + printf("%d\n", sizeof(long long int signed)); + printf("%d\n", sizeof(long int long signed)); + printf("%d\n", sizeof(int long long signed)); + + printf("%d\n", sizeof(unsigned long long)); + printf("%d\n", sizeof(long unsigned long)); + printf("%d\n", sizeof(long long unsigned)); + printf("%d\n", sizeof(unsigned long long int)); + printf("%d\n", sizeof(unsigned long int long)); + printf("%d\n", sizeof(unsigned int long long)); + printf("%d\n", sizeof(long unsigned long int)); + printf("%d\n", sizeof(long unsigned int long)); + printf("%d\n", sizeof(int unsigned long long)); + printf("%d\n", sizeof(long long unsigned int)); + printf("%d\n", sizeof(long int unsigned long)); + printf("%d\n", sizeof(int long unsigned long)); + printf("%d\n", sizeof(long long int unsigned)); + printf("%d\n", sizeof(long int long unsigned)); + printf("%d\n", sizeof(int long long unsigned)); +} +EOF |
