Alien-TinyCCx

 view release on metacpan or  search on metacpan

src/tccexsymtab.c  view on Meta::CPAN

    /* delegate to the symtab's trie */
    return (TokenSym*)(*token_string_hash_get_ref(symtab->tsh, name));
}

LIBTCCAPI void * tcc_get_extended_symbol(extended_symtab * symtab, const char * name)
{
    TokenSym * ts = tcc_get_extended_tokensym(symtab, name);
    if (ts == NULL) return NULL;
    return (void*) ts->hash_next;
}

/******************************************************************************/
/*                            extended symtab copy                            */
/******************************************************************************/

/* The user may want fine-grained control over the order of symbol table lookup.
 * Thus, I provide a set of callbacks to look for names, add symbols to compiler
 * contexts, and prep the compiler state before things get started. */

LIBTCCAPI void tcc_set_extended_symtab_callbacks (
    TCCState * s,
    extended_symtab_lookup_by_name_callback new_name_callback,
    extended_symtab_sym_used_callback new_sym_used_callback,
    extended_symtab_prep_callback new_prep_callback,
    void * data
) {
    s->symtab_name_callback = new_name_callback;
    s->symtab_sym_used_callback = new_sym_used_callback;
    s->symtab_prep_callback = new_prep_callback;
    s->symtab_callback_data = data;
}

LIBTCCAPI void tcc_save_extended_symtab(TCCState * s) {
    if (s->exsymtab == NULL) s->exsymtab = (extended_symtab*)1;
}

Sym * get_new_symtab_pointer (Sym * old, ram_hash * rh)
{
    void ** Sym_ref;
    Sym * to_return;
    int btype;

    /* Handle the null case up-front */
    if (old == NULL) return NULL;

    /* Check the global symbol stack. */
    Sym_ref = ram_hash_get_ref(rh, old);
    to_return = *Sym_ref;
    if (NULL != to_return) return to_return;

    /* Create new sym. Note that mallocz sets lots of things to null
     * for me. :-) */
    to_return = *Sym_ref = tcc_mallocz(sizeof(Sym));

    /* See tcc.h around line 425 for descriptions of some of the fields.
     * See also tccgen.c line 5987 to see what needs to happen for function
     * declarations to work properly (and, in turn, line 446 for how to
     * push a forward reference). */

    /* Copy the v value (token id). This will not be copied later, so keep
     * things simple for now and simply strip out the extended flag. */
    to_return->v = old->v & ~SYM_EXTENDED;
 
    /* Copy the assembler label token id. Just like the v field, we copy
     * this unmodified. */
    /* XXX do we need to strip out SYM_EXTENDED? It seems unlikely. */
    to_return->asm_label = old->asm_label;

    /* associated register. For variables, I believe that the low bits
     * specify the register size that can hold the value while high bits
     * indicate storage details (VT_SYM, VT_LVAL, etc). For function types,
     * however, this gets cast as an AttributeDef and queried for function
     * attributes; so far, I have only seen the .r field queried for the
     * FUNC_CALL field. It matters little; copying the whole long is easy
     * and it seems that everything works fine when it is the same for
     * consuming contexts as for the original compilation context. */
    to_return->r = old->r;

    /* Set the type. Judging by the constants in tcc.h and code that
     * uses this field, I'm pretty sure that the low bits in the .t field
     * tells tcc how to load the data into a register. The high bits seem to
     * indicate storage details, such as VT_EXTERN. Since that is not
     * something that can be extended at runtime, I should be able to copy
     * the value as-is and add an extern flag for variables and functions. */
    to_return->type.t = old->type.t;

    /* After compilation, functions and global variables point to hard
     * locations in memory. Consuming contexts should think of these as
     * having external storage, which is reflected in the VT_EXTERN bit of
     * the type.t field. */
    btype = old->type.t & VT_BTYPE;
    if (btype == VT_FUNC || to_return->r & (VT_SYM | VT_LVAL))
        to_return->type.t |= VT_EXTERN;

    /* Remove static indicator from functions */
    if ((btype == VT_FUNC) && (old->type.t & VT_STATIC))
        to_return->type.t &= ~VT_STATIC;

    /* Static inline functions are the exception to this rule, so undo
     * the above work for them. */
    if ((old->type.t & (VT_INLINE | VT_STATIC)) == (VT_INLINE | VT_STATIC))
        to_return->type.t = old->type.t;

    /* The type.ref field contains something useful only if the basic type
     * is a pointer, struct, enum, or function. See code from tccgen's
     * compare_types for details. */
    if (btype == VT_PTR || btype == VT_STRUCT || btype == VT_ENUM || btype == VT_FUNC) {
        to_return->type.ref = get_new_symtab_pointer(old->type.ref, rh);
    }

    /* Copy the c field, the "associated number." According to tcc-doc.texi
     * as well as the comments just above the definition of put_extern_sym2,
     * the c field will (for some Syms) point to an external symbol in an
     * associated section. But this is not true for all Syms. For structs,
     * this is the size (in bytes), and for struct members it is the byte
     * offset of the member, according to the end of struct_decl(). For
     * variable length arrays, this is "the location on the stack that holds
     * the runtime sizeof for the type." For functions, I believe this is
     * one of FUNC_NEW, FUNC_OLD, or FUNC_ELLIPSIS. At any rate, everything
     * seems to work if I simply set it to zero for functions and global
     * variables and copy it otherwise, so I'm going with that. This probably
     * needs to be more nuanced. */
    if (btype == VT_FUNC || to_return->r & (VT_SYM | VT_LVAL))
        to_return->c = 0;
    else
        to_return->c = old->c;

    /* Copy the next symbol field. Labels and gotos are tracked in a
     * separate stack, so for these Symbols we focus on next, not
     * jnext. The next field (I seem to recall) is used in storing
     * argument lists, so it needs to be copied for function
     * types. I believe it can be copied anonymously. */
    to_return->next = get_new_symtab_pointer(old->next, rh);

    return to_return;
}

Sym * get_new_deftab_pointer (Sym * old, ram_hash * rh)
{
    void ** Sym_ref;
    Sym * to_return;

    /* Handle the null case up-front */
    if (old == NULL) return NULL;

src/tccexsymtab.c  view on Meta::CPAN

        tcc_free(*ts_to_delete);
        ts_to_delete++;
    }

    /* Clear out the inline functions */
    if (symtab->inline_funcs) {
        int i;
        for (i = 0; i < symtab->N_inline_funcs; i++) {
            tcc_free(symtab->inline_funcs[i]->FUNC_STR);
            tcc_free(symtab->inline_funcs[i]->func_str);
            tcc_free(symtab->inline_funcs[i]);
        }
        tcc_free(symtab->inline_funcs);
    }

    /* Clear out the full memory allocation. */
    tcc_free(symtab);
}

/* A function that performs a number of tests for me. I only export a single
 * function to avoid cluttering up the TCC API. */
enum {
    TS_TEST_GET_TOK,
    TS_TEST_HAS_DEFINE,
    TS_TEST_HAS_STRUCT,
    TS_TEST_HAS_IDENTIFIER
};

LIBTCCAPI int tcc_extended_symtab_test(extended_symtab_p symtab, int to_test, const char * name)
{
    TokenSym * ts;

    /* Get the tokenSym by the given name */
    ts = *token_string_hash_get_ref(symtab->tsh, name);
    if (ts == NULL) return 0;

    /* Perform the requested test */
    switch(to_test) {
        case TS_TEST_GET_TOK:
            return ts->tok;
        case TS_TEST_HAS_DEFINE:
            return ts->sym_define != NULL;
        case TS_TEST_HAS_IDENTIFIER:
            return ts->sym_identifier != NULL;
        case TS_TEST_HAS_STRUCT:
            return ts->sym_struct != NULL;
    }
    return 0;
}

/*****************************************************************************/
/*                      Pre-compilation TokenSym Prep                        */
/*****************************************************************************/

LIBTCCAPI void tcc_prep_tokensym_list(extended_symtab * symtab)
{
    int i;
    for (i = 0; i < symtab->tok_start_offset; i++)
    {
        TokenSym * ext_ts = symtab->tokenSym_list[i];
        int flagless_tok = ext_ts->tok & ~(SYM_STRUCT | SYM_FIELD | SYM_EXTENDED | SYM_FIRST_ANOM);
        TokenSym * local_ts = table_ident[flagless_tok - TOK_IDENT];

        /* Skip if we've already copied something for this TokenSym from another
         * extended symbol table, since it'll never get looked up in this
         * extended symbol table. */

        if (local_ts->sym_struct || local_ts->sym_identifier || local_ts->sym_define) continue;

        /* Copy */
        copy_extended_tokensym(symtab, ext_ts, local_ts);
    }
}

/*****************************************************************************/
/*                      copy extended symbol into local                      */
/*****************************************************************************/

/* Provide a mechanism for turning the local_stack off and back on outside of
 * the current static file scope. */

ST_DATA Sym * local_stack_backup;
void local_stack_off() {
    local_stack_backup = local_stack;
    local_stack = NULL;
}
void local_stack_on() {
    local_stack = local_stack_backup;
}

/* The define token stream is a series of bytes. They are collections of
 * integer => data pairs, where the integer indicates the type (and thus size)
 * of the data that follows. For example, if we encounter types TOK_PPNUM,
 * TOK_STR, or TOK_LSTR, then the next few bytes are a CString struct (mostly
 * filled with NULLs) followed by the associated character string. It gets
 * complicated, but has only a handful of special cases to handle. The formats
 * of the stream are codified in tok_str_add2, which is defined in tccpp.c.
 * 
 * This function returns the length of a tokenstream, including the final
 * null. If it is given a target tokenstream, it assumes that the
 * contents of the original have already been copied to the target
 * using memcpy, in which case it updates the token ids for arbitrary
 * tokens (function names, variable names, etc). Using the macro for
 * tokenstream_len defined in tccexsymtab.h, proper usage is:
 * 
 *   int len = tokenstream_len (stream_to_copy); // implicitly calls tokenstream_copy
 *   int * new = malloc(len * sizeof(int));
 *   memcpy(new, stream_to_copy, len * sizeof(int));
 *   tokenstream_copy(stream_to_copy, new, symtab);
 * 
 * Note that the final symtab pointer is the symtab associated with the
 * input stream, not the output stream.
 */

int tokenstream_copy (int * stream, int * to_stream, extended_symtab * symtab)
{
    int len;

    /* handle dumb user edge cases: either both to_stream and symtab
     * are null, or they are both specified. */

    if (to_stream == 0) symtab = 0;

src/tccexsymtab.c  view on Meta::CPAN

                    CString *cstr = (CString *)(stream + len);
                    len += 1 + (cstr->size + sizeof(int) - 1) / sizeof(int);

                    /* If copying, then one might naively expect that I
                     * should set up cstr to be usable for later
                     * preprocessor expansions. See tok_str_add2 in
                     * tccpp.c for details. However, the memcpy that was
                     * presumably performed prior to calling this
                     * function already did that! So I'm done. */
                }
                break;

            case TOK_CDOUBLE: case TOK_CLLONG: case TOK_CULLONG:
            #if LDOUBLE_SIZE == 8
            case TOK_CLDOUBLE:
            #endif
                len += 2;
                break;

            #if LDOUBLE_SIZE == 12
            case TOK_CLDOUBLE:
                len += 3;
            #elif LDOUBLE_SIZE == 16
            case TOK_CLDOUBLE:
                len += 4;
            #elif LDOUBLE_SIZE != 8
                #error add long double size support
            #endif
                break;

            default:
                if (to_stream && stream[len-1] >= symtab->tok_start)
                {
                    /* This is the case for an arbitrary token. Get a local
                     * token and replace the token stream's value with the
                     * local token's tok id. */

                    int from_tok = stream[len-1] & ~SYM_EXTENDED;
                    to_stream[len-1] = get_local_tok_for_extended_tok(from_tok, symtab);
                }

                /* Any token value less than tok_start refers to a value in
                 * the symbol table that is pre-defined, such as the C
                 * language key words (struct, case) and the ASCII letters. */

                /* Default is a single token (integer), which doesn't require
                 * any additional bytes. So do nothing. */

                break;
        }
    }

    /* add one for the zero byte */
    return len + 1;
}

/* Figures out the local token id for a given extended token id. If the given
 * token id is below tok_start, then it is known to exist in all compiler
 * contexts and so it is simply returned. If the token id is equal to or above
 * tok_start, this obtains a pointer to a local TokenSym and returns that
 * TokenSym's token id, together with the flags of the origina, extended token id. */

int get_local_tok_for_extended_tok(int orig_tok, extended_symtab* symtab)
{
    TokenSym* orig_ts;
    TokenSym* local_ts;
    int tok_start, tok_start_offset, orig_tok_no_fields, orig_tok_offset;

    /* Remove SYM_EXTEDED bit */
    orig_tok &= ~SYM_EXTENDED;
    /* Calculate the original token id without fields, storing them for
     * later re-application */
    tok_start = symtab->tok_start;
    orig_tok_no_fields = orig_tok & ~(SYM_STRUCT | SYM_FIELD); /* strip flags  */

    /* special case for ordinary tokens that exist in all compiler contexts,
     * including "data", "string", and others. */

    if (orig_tok_no_fields < tok_start) return orig_tok;

    /* figure out the offset of the extended tokensym */
    tok_start_offset = symtab->tok_start_offset;
    orig_tok_offset = orig_tok_no_fields - tok_start + tok_start_offset;

    orig_ts = symtab->tokenSym_list[orig_tok_offset];         /* get ext   ts */
    local_ts = get_local_ts_for_extended_ts(orig_ts, symtab); /* get local ts */

    return local_ts->tok | (orig_tok & (SYM_STRUCT | SYM_FIELD)); /* add flags */
}

/* Figures out the local TokenSym for a given extended token id. Uses
 * get_local_ts_for_extended_ts to generate a new local TokenSym if necessary. */

TokenSym * get_local_tokensym_for_extended_tok(int tok, extended_symtab * symtab)
{
    int tok_start;

    /* Clear out extraneous flags */
    tok &= ~(SYM_STRUCT | SYM_FIELD | SYM_EXTENDED);

    tok_start = symtab->tok_start;
    if (tok >= tok_start)
    {
        /* This is easy because (1) we know exactly how to compute the TokenSym's
         * array offset and (2) we have a function that'll create a local TokenSym
         * if one isn't already available. */

        TokenSym * from_ts = symtab->tokenSym_list[tok - tok_start + symtab->tok_start_offset];
        return get_local_ts_for_extended_ts(from_ts, symtab);
    }

    /* And if it's earlier than tok_start, we can directly access the table_ident. */
    return table_ident[tok - TOK_IDENT];
}

void copy_extended_tokensym (extended_symtab * symtab, TokenSym * from, TokenSym * to)
{
    /* Mark this token as extended. This will cause a symbol-used callback to be
     * fired the first time this token is used in reference to a symbol (at
     * which point the extended flag will be cleared). */

    to->tok |= SYM_EXTENDED;

    /* We need to copy over the following fields:
     *  - sym_define
     *  - sym_struct
     *  - sym_identifier
     * These fields are OK as they are:
     *  - str has already been allocated and copied
     *  - len has already been set to the string's length
     *  - sym_label should already be null
     *  - hash_next is probably null, and ought not be modified
     */

    /***** sym_struct and sym_identifier copy *****/

    to->sym_struct = copy_extended_sym(symtab, from->sym_struct, to->tok);
    to->sym_identifier = copy_extended_sym(symtab, from->sym_identifier, to->tok);

    /***** token stream if it's an inline function *****/
    if (from->sym_identifier && (from->sym_identifier->type.t & VT_INLINE))
    {
        int i;
        InlineFunc* new_func;
        InlineFunc* old_func;

        /* Find the associated inline func, copy its contents, add to
         * current context's collection of inline functions */

        for (i = 0; i < symtab->N_inline_funcs; i++)
        {
            int ts_len;

            old_func = symtab->inline_funcs[i];
            if (old_func->sym != from->sym_identifier) continue;

            new_func = tcc_malloc(sizeof *new_func + strlen(old_func->filename));
            strcpy(new_func->filename, old_func->filename);
            new_func->sym = to->sym_identifier;

            /* Copy the token stream, WITH replacement (see copy_extended_symtab
             * for contrast) */

            ts_len = tokenstream_len(old_func->FUNC_STR);
            new_func->func_str = tcc_malloc(sizeof(TokenString));
            new_func->FUNC_STR = tcc_malloc(ts_len * sizeof(int));
            memcpy(new_func->FUNC_STR, old_func->FUNC_STR, ts_len * sizeof(int));
            tokenstream_copy(old_func->FUNC_STR, new_func->FUNC_STR, symtab);

            /* Add to the list */
            dynarray_add((void ***)&tcc_state->inline_fns, &tcc_state->nb_inline_fns, new_func);
        }
    }

    /***** sym_define copy *****/

    /* There may be no sym_define, or it may have been undef'd. Note that
     * something which is just defined (and subsequently used in #ifdef
     * statements) have a non-null d field, which points to an int string that
     * only contains a single zero-valued int. */

src/tccexsymtab.c  view on Meta::CPAN

        {
            /* Get local TokenSym associated with curr_from_arg */
            TokenSym * local_ts = get_local_tokensym_for_extended_tok(curr_from_arg->v, symtab);

            /* Add the argument to the local define stack and move the chains */
            newest_arg = sym_push2(&define_stack, local_ts->tok | SYM_FIELD,
                curr_from_arg->type.t, 0);
            *p_curr_arg = newest_arg;
            p_curr_arg = &newest_arg->next;
        }

        /* Now that we have all the moving parts, add the preprocessor to the
         * current compilation context. */

        #ifdef BEFORE_hash_opt
          define_push     (to->tok, from->sym_define->type.t, to_stream, first_arg); /* sym_define is now set */
        #else
          define_push_old (to->tok, from->sym_define->type.t, to_stream, first_arg); /* sym_define is now set */
        #endif
    }
}

/* Copy the CType information from an extended sym into a local CType. The hard
 * part here is finding the local tokensym associated with the type.ref field.
 * In principle this is only an issue if the type is a pointer, struct, enum,
 * or function, but at this point checking non-null is sufficient. */

#define copy_ctype(to_type, from, symtab) do { \
    int btype = from->type.t & VT_BTYPE; \
    to_type.t = from->type.t; \
    if (from->type.ref != NULL) { \
        /* Get the from->type.ref's token and look for it here */ \
        if (from->type.ref->v & SYM_FIRST_ANOM) { \
            /* Anonymous symbol; just copy it. */ \
            to_type.ref = copy_extended_sym(symtab, from->type.ref, \
            /* ??? */ anon_sym++ | (from->type.ref->v & (SYM_STRUCT | SYM_FIELD))); \
        } \
        else if (from->type.ref->v == SYM_FIELD) { \
            /* Anonymous symbol; just copy it. */ \
            to_type.ref = copy_extended_sym(symtab, from->type.ref, SYM_FIELD); \
        } \
        else { \
            /* Not anonymous: get the tokensym */ \
            TokenSym* local_ts = get_local_tokensym_for_extended_tok(from->type.ref->v, symtab); \
            if (btype == VT_STRUCT) to_type.ref = local_ts->sym_struct; \
            else to_type.ref = local_ts->sym_identifier; \
        } \
    } \
    else to_type.ref = NULL; \
} while(0)

Sym * copy_extended_sym (extended_symtab * symtab, Sym * from, int to_tok)
{
    CType to_type;
    Sym * s;
    Sym * from_next;
    Sym **psnext;

    if (from == NULL) return NULL;

    /* Copy the flags and CType from the "from" sym and push on the symbol stack */
    to_tok |= from->v & (SYM_STRUCT | SYM_FIELD | SYM_FIRST_ANOM);
    copy_ctype(to_type, from, symtab);
    s = sym_push(to_tok, &to_type, from->r, from->c);

    /* Copy the assembler label, if present */
	s->asm_label = get_local_tok_for_extended_tok(from->asm_label, symtab);

    /* All done unless we have a next field to copy as well. */
    if (from->next == NULL) return s;

    /* Copy the linked list started in the next field. Much of this code
     * resembles copy_ctype, unfortunately. */

    from_next = from->next;
    psnext = &s->next;
    while (from_next)
    {
        CType new_next_type;
        int new_tok;

        if (from_next->v & SYM_FIRST_ANOM)
        {
            /* Anonymous symbol; not attached to a TokenSym, so just copy it. */
            *psnext = copy_extended_sym(symtab, from_next,
                anon_sym++ | (from_next->v & (SYM_STRUCT | SYM_FIELD)));

            /* copy_extended_sym is a recursive function call which copied the
             * remaining elements of the next chain. Thus, we're done. */
            return s;
        }
        else if (from_next->v == SYM_FIELD)
        {
            /* This is an anonymous symbol associated with pointers, arrays, and
             * function declarations (tccgen.c in post_type). As above, just
             * copy it. */

            *psnext = copy_extended_sym(symtab, from_next, SYM_FIELD);

            /* copy_extended_sym is a recursive function call which copied the
             * remaining elements of the next chain. Thus, we're done. */
            return s;
        }

        /* Push a copy of the Sym to the local symbol stack. */
        copy_ctype(new_next_type, from_next, symtab);
        new_tok = get_local_tok_for_extended_tok(from_next->v, symtab);
        *psnext = sym_push(new_tok, &new_next_type, from_next->r, from_next->c);

        /* Cycle the pointers. */
        from_next = from_next->next;
        psnext = &((*psnext)->next);
    }
    return s;
}

/*****************************************************************************/
/*                      Extended Symbol Table Caching                        */
/*****************************************************************************/

LIBTCCAPI int tcc_set_extended_symbol(extended_symtab * symtab, const char * name, const void * pointer)



( run in 1.021 second using v1.01-cache-2.11-cpan-5735350b133 )