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 )