added GNU complex keywords
[cparser] / parser.c
index bb48db2..8478953 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -53,7 +53,8 @@ struct declaration_specifiers_t {
        source_position_t  source_position;
        unsigned char      declared_storage_class;
        unsigned char      alignment;         /**< Alignment, 0 if not set. */
-       bool               is_inline;
+       unsigned int       is_inline : 1;
+       unsigned int       deprecated : 1;
        decl_modifiers_t   decl_modifiers;    /**< MS __declspec extended modifier mask */
        const char        *deprecated_string; /**< can be set if declaration was marked deprecated. */
        symbol_t          *get_property_sym;  /**< the name of the get property if set. */
@@ -145,7 +146,7 @@ static void semantic_comparison(binary_expression_t *expression);
        case T_restrict:        \
        case T_volatile:        \
        case T_inline:          \
-       case T_forceinline:
+       case T__forceinline:
 
 #ifdef PROVIDE_COMPLEX
 #define COMPLEX_SPECIFIERS  \
@@ -173,6 +174,7 @@ static void semantic_comparison(binary_expression_t *expression);
        case T_enum:              \
        case T___typeof__:        \
        case T___builtin_va_list: \
+       case T__declspec:         \
        COMPLEX_SPECIFIERS        \
        IMAGINARY_SPECIFIERS
 
@@ -282,7 +284,7 @@ static size_t get_expression_struct_size(expression_kind_t kind)
                [EXPR_CHARACTER_CONSTANT]      = sizeof(const_expression_t),
                [EXPR_WIDE_CHARACTER_CONSTANT] = sizeof(const_expression_t),
                [EXPR_STRING_LITERAL]          = sizeof(string_literal_expression_t),
-               [EXPR_WIDE_STRING_LITERAL]   = sizeof(wide_string_literal_expression_t),
+               [EXPR_WIDE_STRING_LITERAL]     = sizeof(wide_string_literal_expression_t),
                [EXPR_COMPOUND_LITERAL]        = sizeof(compound_literal_expression_t),
                [EXPR_CALL]                    = sizeof(call_expression_t),
                [EXPR_UNARY_FIRST]             = sizeof(unary_expression_t),
@@ -293,8 +295,7 @@ static size_t get_expression_struct_size(expression_kind_t kind)
                [EXPR_SIZEOF]                  = sizeof(typeprop_expression_t),
                [EXPR_ALIGNOF]                 = sizeof(typeprop_expression_t),
                [EXPR_CLASSIFY_TYPE]           = sizeof(classify_type_expression_t),
-               [EXPR_FUNCTION]                = sizeof(string_literal_expression_t),
-               [EXPR_PRETTY_FUNCTION]         = sizeof(string_literal_expression_t),
+               [EXPR_FUNCNAME]                = sizeof(funcname_expression_t),
                [EXPR_BUILTIN_SYMBOL]          = sizeof(builtin_symbol_expression_t),
                [EXPR_BUILTIN_CONSTANT_P]      = sizeof(builtin_constant_expression_t),
                [EXPR_BUILTIN_PREFETCH]        = sizeof(builtin_prefetch_expression_t),
@@ -938,32 +939,42 @@ static string_t parse_string_literals(void)
        return result;
 }
 
+/**
+ * Parse one GNU attribute.
+ */
+static void parse_gnu_attribute(void)
+{
+       eat(T___attribute__);
+       expect('(');
+       expect('(');
+       while(true) {
+               if(token.type != T_IDENTIFIER)
+                       break;
+               symbol_t *sym = token.v.symbol;
+               if(sym == sym_deprecated) {
+               }
+               next_token();
+               if(token.type == '(')
+                       eat_until_matching_token('(');
+               if(token.type != ',')
+                       break;
+               next_token();
+       }
+       expect(')');
+       expect(')');
+end_error:
+       return;
+}
+
+/**
+ * Parse GNU attributes.
+ */
 static void parse_attributes(void)
 {
        while(true) {
                switch(token.type) {
                case T___attribute__: {
-                       next_token();
-
-                       expect('(');
-                       int depth = 1;
-                       while(depth > 0) {
-                               switch(token.type) {
-                               case T_EOF:
-                                       errorf(HERE, "EOF while parsing attribute");
-                                       break;
-                               case '(':
-                                       next_token();
-                                       depth++;
-                                       break;
-                               case ')':
-                                       next_token();
-                                       depth--;
-                                       break;
-                               default:
-                                       next_token();
-                               }
-                       }
+                       parse_gnu_attribute();
                        break;
                }
                case T_asm:
@@ -1215,7 +1226,7 @@ static __attribute__((unused)) void debug_print_type_path(
                        }
                        fprintf(stderr, ".%s", entry->v.compound_entry->symbol->string);
                } else if(is_type_array(type)) {
-                       fprintf(stderr, "[%u]", entry->v.index);
+                       fprintf(stderr, "[%zd]", entry->v.index);
                } else {
                        fprintf(stderr, "-INVALID-");
                }
@@ -1995,9 +2006,14 @@ typedef enum {
        SPECIFIER_FLOAT     = 1 << 8,
        SPECIFIER_BOOL      = 1 << 9,
        SPECIFIER_VOID      = 1 << 10,
+       SPECIFIER_INT8      = 1 << 11,
+       SPECIFIER_INT16     = 1 << 12,
+       SPECIFIER_INT32     = 1 << 13,
+       SPECIFIER_INT64     = 1 << 14,
+       SPECIFIER_INT128    = 1 << 15,
 #ifdef PROVIDE_COMPLEX
-       SPECIFIER_COMPLEX   = 1 << 11,
-       SPECIFIER_IMAGINARY = 1 << 12,
+       SPECIFIER_COMPLEX   = 1 << 16,
+       SPECIFIER_IMAGINARY = 1 << 17,
 #endif
 } specifiers_t;
 
@@ -2157,8 +2173,10 @@ static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *spe
                        expect(')');
                } else if(symbol == sym_deprecated) {
                        next_token();
-                       DET_MOD(deprecated, DM_DEPRECATED);
-               if(token.type == '(') {
+                       if(specifiers->deprecated != 0)
+                               warningf(HERE, "deprecated used more than once");
+                       specifiers->deprecated = 1;
+                       if(token.type == '(') {
                                next_token();
                                if(token.type == T_STRING_LITERAL) {
                                        specifiers->deprecated_string = token.v.string.begin;
@@ -2213,7 +2231,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                MATCH_STORAGE_CLASS(T_auto,     STORAGE_CLASS_AUTO)
                MATCH_STORAGE_CLASS(T_register, STORAGE_CLASS_REGISTER)
 
-               case T_declspec:
+               case T__declspec:
                        next_token();
                        expect('(');
                        add_anchor_token(')');
@@ -2253,6 +2271,11 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                MATCH_TYPE_QUALIFIER(T_const,    TYPE_QUALIFIER_CONST);
                MATCH_TYPE_QUALIFIER(T_restrict, TYPE_QUALIFIER_RESTRICT);
                MATCH_TYPE_QUALIFIER(T_volatile, TYPE_QUALIFIER_VOLATILE);
+               MATCH_TYPE_QUALIFIER(T__w64,     TYPE_QUALIFIER_W64);
+               MATCH_TYPE_QUALIFIER(T___ptr32,  TYPE_QUALIFIER_PTR32);
+               MATCH_TYPE_QUALIFIER(T___ptr64,  TYPE_QUALIFIER_PTR64);
+               MATCH_TYPE_QUALIFIER(T___uptr,   TYPE_QUALIFIER_UPTR);
+               MATCH_TYPE_QUALIFIER(T___sptr,   TYPE_QUALIFIER_SPTR);
 
                case T___extension__:
                        /* TODO */
@@ -2279,11 +2302,16 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                MATCH_SPECIFIER(T_signed,     SPECIFIER_SIGNED,    "signed")
                MATCH_SPECIFIER(T_unsigned,   SPECIFIER_UNSIGNED,  "unsigned")
                MATCH_SPECIFIER(T__Bool,      SPECIFIER_BOOL,      "_Bool")
+               MATCH_SPECIFIER(T__int8,      SPECIFIER_INT8,      "_int8")
+               MATCH_SPECIFIER(T__int16,     SPECIFIER_INT16,     "_int16")
+               MATCH_SPECIFIER(T__int32,     SPECIFIER_INT32,     "_int32")
+               MATCH_SPECIFIER(T__int64,     SPECIFIER_INT64,     "_int64")
+               MATCH_SPECIFIER(T__int128,    SPECIFIER_INT128,    "_int128")
 #ifdef PROVIDE_COMPLEX
                MATCH_SPECIFIER(T__Complex,   SPECIFIER_COMPLEX,   "_Complex")
                MATCH_SPECIFIER(T__Imaginary, SPECIFIER_IMAGINARY, "_Imaginary")
 #endif
-               case T_forceinline:
+               case T__forceinline:
                        /* only in microsoft mode */
                        specifiers->decl_modifiers |= DM_FORCEINLINE;
 
@@ -2411,6 +2439,52 @@ finish_specifiers:
                        | SPECIFIER_INT:
                        atomic_type = ATOMIC_TYPE_ULONGLONG;
                        break;
+
+               case SPECIFIER_UNSIGNED | SPECIFIER_INT8:
+                       atomic_type = unsigned_int8_type_kind;
+                       break;
+
+               case SPECIFIER_UNSIGNED | SPECIFIER_INT16:
+                       atomic_type = unsigned_int16_type_kind;
+                       break;
+
+               case SPECIFIER_UNSIGNED | SPECIFIER_INT32:
+                       atomic_type = unsigned_int32_type_kind;
+                       break;
+
+               case SPECIFIER_UNSIGNED | SPECIFIER_INT64:
+                       atomic_type = unsigned_int64_type_kind;
+                       break;
+
+               case SPECIFIER_UNSIGNED | SPECIFIER_INT128:
+                       atomic_type = unsigned_int128_type_kind;
+                       break;
+
+               case SPECIFIER_INT8:
+               case SPECIFIER_SIGNED | SPECIFIER_INT8:
+                       atomic_type = int8_type_kind;
+                       break;
+
+               case SPECIFIER_INT16:
+               case SPECIFIER_SIGNED | SPECIFIER_INT16:
+                       atomic_type = int16_type_kind;
+                       break;
+
+               case SPECIFIER_INT32:
+               case SPECIFIER_SIGNED | SPECIFIER_INT32:
+                       atomic_type = int32_type_kind;
+                       break;
+
+               case SPECIFIER_INT64:
+               case SPECIFIER_SIGNED | SPECIFIER_INT64:
+                       atomic_type = int64_type_kind;
+                       break;
+
+               case SPECIFIER_INT128:
+               case SPECIFIER_SIGNED | SPECIFIER_INT128:
+                       atomic_type = int128_type_kind;
+                       break;
+
                case SPECIFIER_FLOAT:
                        atomic_type = ATOMIC_TYPE_FLOAT;
                        break;
@@ -2476,6 +2550,7 @@ finish_specifiers:
        }
 
        type->base.qualifiers = type_qualifiers;
+       /* FIXME: check type qualifiers here */
 
        type_t *result = typehash_insert(type);
        if(newtype && result != type) {
@@ -2497,6 +2572,12 @@ static type_qualifiers_t parse_type_qualifiers(void)
                MATCH_TYPE_QUALIFIER(T_const,    TYPE_QUALIFIER_CONST);
                MATCH_TYPE_QUALIFIER(T_restrict, TYPE_QUALIFIER_RESTRICT);
                MATCH_TYPE_QUALIFIER(T_volatile, TYPE_QUALIFIER_VOLATILE);
+               /* microsoft extended type modifiers */
+               MATCH_TYPE_QUALIFIER(T__w64,     TYPE_QUALIFIER_W64);
+               MATCH_TYPE_QUALIFIER(T___ptr32,  TYPE_QUALIFIER_PTR32);
+               MATCH_TYPE_QUALIFIER(T___ptr64,  TYPE_QUALIFIER_PTR64);
+               MATCH_TYPE_QUALIFIER(T___uptr,   TYPE_QUALIFIER_UPTR);
+               MATCH_TYPE_QUALIFIER(T___sptr,   TYPE_QUALIFIER_SPTR);
 
                default:
                        return type_qualifiers;
@@ -2953,6 +3034,7 @@ static declaration_t *parse_declarator(
        declaration_t *const declaration    = allocate_declaration_zero();
        declaration->declared_storage_class = specifiers->declared_storage_class;
        declaration->modifiers              = specifiers->decl_modifiers;
+       declaration->deprecated             = specifiers->deprecated;
        declaration->deprecated_string      = specifiers->deprecated_string;
        declaration->get_property_sym       = specifiers->get_property_sym;
        declaration->put_property_sym       = specifiers->put_property_sym;
@@ -4217,6 +4299,22 @@ static expression_t *parse_reference(void)
        /* this declaration is used */
        declaration->used = true;
 
+       /* check for deprecated functions */
+       if(declaration->deprecated != 0) {
+               const char *prefix = "";
+               if (is_type_function(declaration->type))
+                       prefix = "function ";
+
+               if (declaration->deprecated_string != NULL) {
+                       warningf(source_position,
+                               "%s'%Y' was declared 'deprecated(\"%s\")'", prefix, declaration->symbol,
+                               declaration->deprecated_string);
+               } else {
+                       warningf(source_position,
+                               "%s'%Y' was declared 'deprecated'", prefix, declaration->symbol);
+               }
+       }
+
        return expression;
 }
 
@@ -4350,8 +4448,9 @@ static expression_t *parse_function_keyword(void)
                errorf(HERE, "'__func__' used outside of a function");
        }
 
-       expression_t *expression = allocate_expression_zero(EXPR_FUNCTION);
-       expression->base.type    = type_char_ptr;
+       expression_t *expression  = allocate_expression_zero(EXPR_FUNCNAME);
+       expression->base.type     = type_char_ptr;
+       expression->funcname.kind = FUNCNAME_FUNCTION;
 
        return expression;
 }
@@ -4359,14 +4458,44 @@ static expression_t *parse_function_keyword(void)
 static expression_t *parse_pretty_function_keyword(void)
 {
        eat(T___PRETTY_FUNCTION__);
-       /* TODO */
 
        if (current_function == NULL) {
                errorf(HERE, "'__PRETTY_FUNCTION__' used outside of a function");
        }
 
-       expression_t *expression = allocate_expression_zero(EXPR_PRETTY_FUNCTION);
-       expression->base.type    = type_char_ptr;
+       expression_t *expression  = allocate_expression_zero(EXPR_FUNCNAME);
+       expression->base.type     = type_char_ptr;
+       expression->funcname.kind = FUNCNAME_PRETTY_FUNCTION;
+
+       return expression;
+}
+
+static expression_t *parse_funcsig_keyword(void)
+{
+       eat(T___FUNCSIG__);
+
+       if (current_function == NULL) {
+               errorf(HERE, "'__FUNCSIG__' used outside of a function");
+       }
+
+       expression_t *expression  = allocate_expression_zero(EXPR_FUNCNAME);
+       expression->base.type     = type_char_ptr;
+       expression->funcname.kind = FUNCNAME_FUNCSIG;
+
+       return expression;
+}
+
+static expression_t *parse_funcdname_keyword(void)
+{
+       eat(T___FUNCDNAME__);
+
+       if (current_function == NULL) {
+               errorf(HERE, "'__FUNCDNAME__' used outside of a function");
+       }
+
+       expression_t *expression  = allocate_expression_zero(EXPR_FUNCNAME);
+       expression->base.type     = type_char_ptr;
+       expression->funcname.kind = FUNCNAME_FUNCDNAME;
 
        return expression;
 }
@@ -4669,7 +4798,7 @@ end_error:
  * Parses a MS assume() expression.
  */
 static expression_t *parse_assume(void) {
-       eat(T_assume);
+       eat(T__assume);
 
        expression_t *expression
                = allocate_expression_zero(EXPR_UNARY_ASSUME);
@@ -4686,6 +4815,44 @@ end_error:
        return create_invalid_expression();
 }
 
+/**
+ * Parse a microsoft __noop expression.
+ */
+static expression_t *parse_noop_expression(void) {
+       source_position_t source_position = HERE;
+       eat(T___noop);
+
+       if (token.type == '(') {
+               /* parse arguments */
+               eat('(');
+               add_anchor_token(')');
+               add_anchor_token(',');
+
+               if(token.type != ')') {
+                       while(true) {
+                               (void)parse_assignment_expression();
+                               if(token.type != ',')
+                                       break;
+                               next_token();
+                       }
+               }
+       }
+       rem_anchor_token(',');
+       rem_anchor_token(')');
+       expect(')');
+
+       /* the result is a (int)0 */
+       expression_t *cnst         = allocate_expression_zero(EXPR_CONST);
+       cnst->base.source_position = source_position;
+       cnst->base.type            = type_int;
+       cnst->conste.v.int_value   = 0;
+
+       return cnst;
+
+end_error:
+       return create_invalid_expression();
+}
+
 /**
  * Parses a primary expression.
  */
@@ -4702,6 +4869,8 @@ static expression_t *parse_primary_expression(void)
                case T___FUNCTION__:
                case T___func__:                 return parse_function_keyword();
                case T___PRETTY_FUNCTION__:      return parse_pretty_function_keyword();
+               case T___FUNCSIG__:              return parse_funcsig_keyword();
+               case T___FUNCDNAME__:            return parse_funcdname_keyword();
                case T___builtin_offsetof:       return parse_offsetof();
                case T___builtin_va_start:       return parse_va_start();
                case T___builtin_va_arg:         return parse_va_arg();
@@ -4719,9 +4888,10 @@ static expression_t *parse_primary_expression(void)
                case T___builtin_isunordered:    return parse_compare_builtin();
                case T___builtin_constant_p:     return parse_builtin_constant();
                case T___builtin_prefetch:       return parse_builtin_prefetch();
-               case T_assume:                   return parse_assume();
+               case T__assume:                  return parse_assume();
 
                case '(':                        return parse_brace_expression();
+               case T___noop:                   return parse_noop_expression();
        }
 
        errorf(HERE, "unexpected token %K, expected an expression", &token);
@@ -4920,6 +5090,7 @@ static expression_t *parse_call_expression(unsigned precedence,
 {
        (void) precedence;
        expression_t *result = allocate_expression_zero(EXPR_CALL);
+       result->base.source_position = expression->base.source_position;
 
        call_expression_t *call = &result->call;
        call->function          = expression;
@@ -5693,8 +5864,7 @@ static bool expression_has_effect(const expression_t *const expr)
                case EXPR_CLASSIFY_TYPE:             return false;
                case EXPR_ALIGNOF:                   return false;
 
-               case EXPR_FUNCTION:                  return false;
-               case EXPR_PRETTY_FUNCTION:           return false;
+               case EXPR_FUNCNAME:                  return false;
                case EXPR_BUILTIN_SYMBOL:            break; /* handled in EXPR_CALL */
                case EXPR_BUILTIN_CONSTANT_P:        return false;
                case EXPR_BUILTIN_PREFETCH:          return true;