parser.cpp
/* Parse a complete typename.
 * for single-variables (ie. function parameters or typedefs) storebase should be nullptr
 * but when parsing variables separated by comma
 * 'storebase' should point to where the base-type should be kept.
 * The base type makes up every bit of type information which comes *before* the
 * variable name.
 *
 * NOTE: The value must either be named, have a nullptr name, or a name starting
 *       with '<'. In the first case, this will be the actual variable or type
 *       name, in the other cases it is assumed that the name will appear
 *       later, and an error is generated otherwise.
 *
 * The following will be parsed in its entirety:
 *     void() foo()
 * The 'basetype' in this case is 'void()'
 * and if there's a comma after it, say:
 *     void() foo(), bar
 * then the type-information 'void()' can be stored in 'storebase'
 */
Parse a complete typename.
for single-variables  storebase should be nullptr
but when parsing variables separated by comma
'storebase' should point to where the base-type should be kept.
The base type makes up every bit of type information which comes *before* the
variable name.

The value must either be named, have a nullptr name, or a name starting
with '<'. In the first case, this will be the actual variable or type
name, in the other cases it is assumed that the name will appear
later, and an error is generated otherwise.


Parse a complete typename . for single - variables storebase should be nullptr but when parsing variables separated by comma ' storebase ' should point to where the base - type should be kept . The base type makes up every bit of type information which comes * before * the variable name . The value must either be named have a nullptr name or a name starting with ' < ' . In the first case this will be the actual variable or type name in the other cases it is assumed that the name will appear later and an error is generated otherwise .
static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef, bool *is_vararg)
{
    ast_value *var, *tmp;
    lex_ctx_t    ctx;
    const char *name = nullptr;
    bool        isfield  = false;
    bool        wasarray = false;
    size_t      morefields = 0;
    bool        vararg = (parser->tok == TOKEN_DOTS);
    ctx = parser_ctx(parser);
    if (parser->tok == '.' || parser->tok == TOKEN_DOTS) {
        isfield = true;
        if (parser->tok == TOKEN_DOTS)
            morefields += 2;
        if (!parser_next(parser)) {
            parseerror(parser, "expected typename for field definition");
            return nullptr;
        }
        while (true) {
            if (parser->tok == '.')
                ++morefields;
            else if (parser->tok == TOKEN_DOTS)
                morefields += 3;
            else
                break;
            vararg = false;
            if (!parser_next(parser)) {
                parseerror(parser, "expected typename for field definition");
                return nullptr;
            }
        }
    }
    if (parser->tok == TOKEN_IDENT)
        cached_typedef = parser_find_typedef(parser, parser_tokval(parser), 0);
    if (!cached_typedef && parser->tok != TOKEN_TYPENAME) {
        if (vararg && is_vararg) {
            *is_vararg = true;
            return nullptr;
        }
        parseerror(parser, "expected typename");
        return nullptr;
    }
    if (cached_typedef) {
        var = new ast_value(ast_copy_type, *cached_typedef);
        var->m_name = "<type(from_def)>";
    } else
        var = new ast_value(ctx, "<type>", parser_token(parser)->constval.t);
    for (; morefields; --morefields) {
        tmp = new ast_value(ctx, "<.type>", TYPE_FIELD);
        tmp->m_next = var;
        var = tmp;
    }
    if (!parser_next(parser)) {
        delete var;
        parseerror(parser, "parse error after typename");
        return nullptr;
    }
    if (parser->tok == '(') {
        var = parse_parameter_list(parser, var);
        if (!var)
            return nullptr;
    }
    if (storebase) {
        *storebase = new ast_value(ast_copy_type, *var);
        if (isfield) {
            tmp = new ast_value(ctx, "<type:f>", TYPE_FIELD);
            tmp->m_next = *storebase;
            *storebase = tmp;
        }
    }
    if (parser->tok == TOKEN_IDENT || parser->tok == TOKEN_KEYWORD) {
        if (!strcmp(parser_tokval(parser), "break"))
            (void)!parsewarning(parser, WARN_BREAKDEF, "break definition ignored (suggest removing it)");
        else if (parser->tok == TOKEN_KEYWORD)
            goto leave;
        name = util_strdup(parser_tokval(parser));
        if (!parser_next(parser)) {
            delete var;
            mem_d(name);
            parseerror(parser, "error after variable or field declaration");
            return nullptr;
        }
    }
    leave:
    if (parser->tok == '[') {
        wasarray = true;
        var = parse_arraysize(parser, var);
        if (!var) {
            if (name) mem_d(name);
            return nullptr;
        }
    }
    if (isfield) {
        tmp = new ast_value(ctx, "<type:f>", TYPE_FIELD);
        tmp->m_next = var;
        var = tmp;
    }
    if (parser->tok == '(' && OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC)
        parseerror(parser, "C-style function syntax is not allowed in -std=qcc");
    if (parser->tok == '(' && wasarray)
        parseerror(parser, "arrays as part of a return type is not supported");
    while (parser->tok == '(') {
        var = parse_parameter_list(parser, var);
        if (!var) {
            if (name) mem_d(name);
            return nullptr;
        }
    }
    if (name) {
        var->m_name = name;
        mem_d(name);
    }
    return var;
}
static ast_value * parse_typename ( parser_t * parser , ast_value * * storebase , ast_value * cached_typedef , bool * is_vararg ) { ast_value * var , * tmp ; lex_ctx_t ctx ; const char * name = nullptr ; bool isfield = false ; bool wasarray = false ; size_t morefields = 0 ; bool vararg = ( parser -> tok == TOKEN_DOTS ) ; ctx = parser_ctx ( parser ) ; if ( parser -> tok == ' ' || parser -> tok == TOKEN_DOTS ) { isfield = true ; if ( parser -> tok == TOKEN_DOTS ) morefields += 2 ; if ( ! parser_next ( parser ) ) { parseerror ( parser , " " ) ; return nullptr ; } while ( true ) { if ( parser -> tok == ' ' ) ++ morefields ; else if ( parser -> tok == TOKEN_DOTS ) morefields += 3 ; else break ; vararg = false ; if ( ! parser_next ( parser ) ) { parseerror ( parser , " " ) ; return nullptr ; } } } if ( parser -> tok == TOKEN_IDENT ) cached_typedef = parser_find_typedef ( parser , parser_tokval ( parser ) , 0 ) ; if ( ! cached_typedef && parser -> tok != TOKEN_TYPENAME ) { if ( vararg && is_vararg ) { * is_vararg = true ; return nullptr ; } parseerror ( parser , " " ) ; return nullptr ; } if ( cached_typedef ) { var = new ast_value ( ast_copy_type , * cached_typedef ) ; var -> m_name = " " ; } else var = new ast_value ( ctx , " " , parser_token ( parser ) -> constval . t ) ; for ( ; morefields ; -- morefields ) { tmp = new ast_value ( ctx , " " , TYPE_FIELD ) ; tmp -> m_next = var ; var = tmp ; } if ( ! parser_next ( parser ) ) { delete var ; parseerror ( parser , " " ) ; return nullptr ; } if ( parser -> tok == ' ' ) { var = parse_parameter_list ( parser , var ) ; if ( ! var ) return nullptr ; } if ( storebase ) { * storebase = new ast_value ( ast_copy_type , * var ) ; if ( isfield ) { tmp = new ast_value ( ctx , " " , TYPE_FIELD ) ; tmp -> m_next = * storebase ; * storebase = tmp ; } } if ( parser -> tok == TOKEN_IDENT || parser -> tok == TOKEN_KEYWORD ) { if ( ! strcmp ( parser_tokval ( parser ) , " " ) ) ( void ) ! parsewarning ( parser , WARN_BREAKDEF , " " ) ; else if ( parser -> tok == TOKEN_KEYWORD ) goto leave ; name = util_strdup ( parser_tokval ( parser ) ) ; if ( ! parser_next ( parser ) ) { delete var ; mem_d ( name ) ; parseerror ( parser , " " ) ; return nullptr ; } } leave : if ( parser -> tok == ' ' ) { wasarray = true ; var = parse_arraysize ( parser , var ) ; if ( ! var ) { if ( name ) mem_d ( name ) ; return nullptr ; } } if ( isfield ) { tmp = new ast_value ( ctx , " " , TYPE_FIELD ) ; tmp -> m_next = var ; var = tmp ; } if ( parser -> tok == ' ' && OPTS_OPTION_U32 ( OPTION_STANDARD ) == COMPILER_QCC ) parseerror ( parser , " " ) ; if ( parser -> tok == ' ' && wasarray ) parseerror ( parser , " " ) ; while ( parser -> tok == ' ' ) { var = parse_parameter_list ( parser , var ) ; if ( ! var ) { if ( name ) mem_d ( name ) ; return nullptr ; } } if ( name ) { var -> m_name = name ; mem_d ( name ) ; } return var ; }
Parse a complete typename.
Parse a complete typename .
/* types may start with a dot */ /* if we parsed a dot we need a typename now */ /* Further dots are handled seperately because they won't be part of the
         * basetype
         */ /* generate the basic type value */ /* do not yet turn into a field - remember:
     * .void() foo; is a field too
     * .void()() foo; is a function
     */ /* parse on */ /* an opening paren now starts the parameter-list of a function
     * this is where original-QC has parameter lists.
     * We allow a single parameter list here.
     * Much like fteqcc we don't allow `float()() x`
     */ /* store the base if requested */ /* there may be a name now */ /* parse on */ /* now this may be an array */ /* This is the point where we can turn it into a field */ /* turn it into a field if desired */ /* now there may be function parens again */ /* finally name it */ // free the name, ast_value_set_name duplicates