/*************************************************************************/ /* */ /* Language Technologies Institute */ /* Carnegie Mellon University */ /* Copyright (c) 2001 */ /* All Rights Reserved. */ /* */ /* Permission is hereby granted, free of charge, to use and distribute */ /* this software and its documentation without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of this work, and to */ /* permit persons to whom this work is furnished to do so, subject to */ /* the following conditions: */ /* 1. The code must retain the above copyright notice, this list of */ /* conditions and the following disclaimer. */ /* 2. Any modifications must be clearly marked as such. */ /* 3. Original authors' names are not deleted. */ /* 4. The authors' names are not used to endorse or promote products */ /* derived from this software without specific prior written */ /* permission. */ /* */ /* CARNEGIE MELLON UNIVERSITY AND THE CONTRIBUTORS TO THIS WORK */ /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */ /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */ /* SHALL CARNEGIE MELLON UNIVERSITY NOR THE CONTRIBUTORS BE LIABLE */ /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */ /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */ /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */ /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */ /* THIS SOFTWARE. */ /* */ /*************************************************************************/ /* Author: Alan W Black (awb@cs.cmu.edu) */ /* Date: January 2001 */ /*************************************************************************/ /* */ /* Const Vals, and macros to define them */ /* */ /* Before you give up in disgust bear with me on this. Every single */ /* line in this file has been *very* carefully decided on after much */ /* thought, experimentation and reading more specs of the C language */ /* than most people even thought existed. However inspite of that, the */ /* result is still unsatisfying from an elegance point of view but the */ /* given all the constraints this is probably the best compromise. */ /* */ /* This file offers macros for defining const cst_vals. I know many */ /* are already laughing at me for wanting runtime types on objects and */ /* will use this code as exemplars of why this should be done in C++, I */ /* say good luck to them with their 4M footprint while I go for my */ /* 50K footprint. But I *will* do cst_vals in 8 bytes and I *will* */ /* have them defined const so they are in the text segment */ /* */ /* The problem here is that there is not yet a standard way to do */ /* initialization of unions. There is one in the C99 standard and GCC */ /* already supports it, but other compilers do not so I can't use that */ /* */ /* So I need a way to make an object that will have the right 8 bytes */ /* for ints, floats, strings and cons cells that will work on any C */ /* compiler and will be of type const cst_val. That unfortunately */ /* isn't trivial. */ /* */ /* For the time being ignoring byte order, and address size, which */ /* will be ignored in the particular discuss (though dealt with below) */ /* I'd like to do something like */ /* */ /* const cst_val fredi = { CST_VAL_TYPE_INT,-1, 42 }; */ /* const cst_val fredf = { CST_VAL_TYPE_FLOAT,-1, 4.2 }; */ /* const cst_val freds = { CST_VAL_TYPE_STRING,-1, "42" }; */ /* */ /* Even if you accept warnings this isn't going to work, if you add */ /* extra {} you can get rid of some warnings but the fval/ival/ *vval */ /* part isn't going to work, the compiler *may* try to take the value */ /* and assign it using the type of the first field defined in the */ /* union. This could be made to work for ints and void* as pointers */ /* can be used as ints (even of 64 bit architectures) but the float */ /* isn't going to work. Casting will cause the float to be changed to */ /* an int by CPP which isn't what you want, what you want is that the */ /* four byte region gets filled with the four bytes that represent the */ /* float itself. Now you could get the four byte represention of the */ /* float and pretend that is an int (0xbfff9a4 for 4.2 on intel), that */ /* would work but that doesn't seem satifying and I'd need to have a */ /* preprocessor that could convert that. You could make atoms always */ /* have a pointer to another piece of memory, but that would take up */ /* another 4 bytes not just for these constants but all other cst_vals */ /* create */ /* */ /* So you could do */ /* */ /* const cst_val_int fredi = { CST_VAL_TYPE_INT,-1, 42 }; */ /* const cst_val_float fredf = { CST_VAL_TYPE_FLOAT,-1, 4.2 }; */ /* const cst_val_string freds = { CST_VAL_TYPE_STRING,-1, "42" }; */ /* */ /* Though that's a slippery slope I don't want to have these explicit */ /* new types, the first short defines the type perfectly adequately */ /* and the whole point of runtime types is that there is one object */ /* type. */ /* */ /* Well just initialize them at runtime, but, that isn't thread safe, */ /* slows down startup, requires a instance implicitly in the code and */ /* on the heap. As these are const, they should go in ROM. */ /* */ /* At this moment, I think the second version is the least problematic */ /* though it makes defining val_consts more unpleasant than they should */ /* be and forces changes elsewhere in the code even when the compiler */ /* does support initialization of unions */ /* */ /* */ /*************************************************************************/ #ifndef _CST_VAL_CONSTS_H__ #define _CST_VAL_CONSTS_H__ #include "cst_val_defs.h" #include /* There is built-in int to string conversions here for numbers */ /* up to 20, note if you make this bigger you have to hand change */ /* other things too */ #define CST_CONST_INT_MAX 19 #ifndef NO_UNION_INITIALIZATION /* This is the simple way when initialization of unions is supported */ #define DEF_CONST_VAL_INT(N,V) const cst_val N = {{.a={.type=CST_VAL_TYPE_INT,.ref_count=-1,.v={.ival=V}}}} #define DEF_CONST_VAL_STRING(N,S) const cst_val N = {{.a={.type=CST_VAL_TYPE_STRING,.ref_count=-1,.v={.vval= (void *)S}}}} #define DEF_CONST_VAL_FLOAT(N,F) const cst_val N = {{.a={.type=CST_VAL_TYPE_FLOAT,.ref_count=-1,.v={.fval=F}}}} #define DEF_CONST_VAL_CONS(N,A,D) const cst_val N = {{.cc={.car=(cst_val *)A,.cdr=(cst_val *)D }}} extern const cst_val val_int_0; extern const cst_val val_int_1; extern const cst_val val_int_2; extern const cst_val val_int_3; extern const cst_val val_int_4; extern const cst_val val_int_5; extern const cst_val val_int_6; extern const cst_val val_int_7; extern const cst_val val_int_8; extern const cst_val val_int_9; extern const cst_val val_int_10; extern const cst_val val_int_11; extern const cst_val val_int_12; extern const cst_val val_int_13; extern const cst_val val_int_14; extern const cst_val val_int_15; extern const cst_val val_int_16; extern const cst_val val_int_17; extern const cst_val val_int_18; extern const cst_val val_int_19; extern const cst_val val_int_20; extern const cst_val val_int_21; extern const cst_val val_int_22; extern const cst_val val_int_23; extern const cst_val val_int_24; extern const cst_val val_string_0; extern const cst_val val_string_1; extern const cst_val val_string_2; extern const cst_val val_string_3; extern const cst_val val_string_4; extern const cst_val val_string_5; extern const cst_val val_string_6; extern const cst_val val_string_7; extern const cst_val val_string_8; extern const cst_val val_string_9; extern const cst_val val_string_10; extern const cst_val val_string_11; extern const cst_val val_string_12; extern const cst_val val_string_13; extern const cst_val val_string_14; extern const cst_val val_string_15; extern const cst_val val_string_16; extern const cst_val val_string_17; extern const cst_val val_string_18; extern const cst_val val_string_19; extern const cst_val val_string_20; extern const cst_val val_string_21; extern const cst_val val_string_22; extern const cst_val val_string_23; extern const cst_val val_string_24; #else /* Only GCC seems to currently support the C99 standard for giving */ /* explicit names for fields for initializing unions, because we want */ /* things to be const, and to be small structures this is really useful */ /* thus for compilers not supporting no_union_initization we use other */ /* structure that we know (hope ?) are the same size and use agressive */ /* casting. The goal here is wholly justified but the method here isn't */ /* pretty */ /* These structures are defined *solely* to get round initialization */ /* problems if you need to use these in any code you are using, you are */ /* unquestionably doing the wrong thing */ typedef struct cst_val_atom_struct_float { #ifdef WORDS_BIGENDIAN #if UINTPTR_MAX > 0xfffffffful int ref_count; int type; /* order is here important */ #else short ref_count; short type; /* order is here important */ #endif #else #if UINTPTR_MAX > 0xfffffffful int type; /* order is here important */ int ref_count; #else short type; /* order is here important */ short ref_count; #endif #endif #if UINTPTR_MAX > 0xfffffffful double fval; #else float fval; #endif } cst_val_float; typedef struct cst_val_atom_struct_int { #ifdef WORDS_BIGENDIAN #if UINTPTR_MAX > 0xfffffffful int ref_count; int type; /* order is here important (and unintuitive) */ #else short ref_count; short type; /* order is here important (and unintuitive) */ #endif #else #if UINTPTR_MAX > 0xfffffffful int type; /* order is here important */ int ref_count; #else short type; /* order is here important */ short ref_count; #endif #endif #if UINTPTR_MAX > 0xfffffffful long long ival; #else int ival; #endif } cst_val_int; typedef struct cst_val_atom_struct_void { #ifdef WORDS_BIGENDIAN #if UINTPTR_MAX > 0xfffffffful int ref_count; int type; /* order is here important */ #else short ref_count; short type; /* order is here important */ #endif #else #if UINTPTR_MAX > 0xfffffffful int type; /* order is here important */ int ref_count; #else short type; /* order is here important */ short ref_count; #endif #endif void *vval; } cst_val_void; #ifdef WORDS_BIGENDIAN #define DEF_CONST_VAL_INT(N,V) const cst_val_int N={-1, CST_VAL_TYPE_INT, V} #define DEF_CONST_VAL_STRING(N,S) const cst_val_void N={-1,CST_VAL_TYPE_STRING,(void *)S} #define DEF_CONST_VAL_FLOAT(N,F) const cst_val_float N={-1,CST_VAL_TYPE_FLOAT,(float)F} #else #define DEF_CONST_VAL_INT(N,V) const cst_val_int N={CST_VAL_TYPE_INT,-1,V} #define DEF_CONST_VAL_STRING(N,S) const cst_val_void N={CST_VAL_TYPE_STRING,-1,(void *)S} #define DEF_CONST_VAL_FLOAT(N,F) const cst_val_float N={CST_VAL_TYPE_FLOAT,-1,(float)F} #endif #define DEF_CONST_VAL_CONS(N,A,D) const cst_val_cons N={A,D} /* in the non-union intialization version we these consts have to be */ /* more typed than need, we'll cast the back later */ extern const cst_val_int val_int_0; extern const cst_val_int val_int_1; extern const cst_val_int val_int_2; extern const cst_val_int val_int_3; extern const cst_val_int val_int_4; extern const cst_val_int val_int_5; extern const cst_val_int val_int_6; extern const cst_val_int val_int_7; extern const cst_val_int val_int_8; extern const cst_val_int val_int_9; extern const cst_val_int val_int_10; extern const cst_val_int val_int_11; extern const cst_val_int val_int_12; extern const cst_val_int val_int_13; extern const cst_val_int val_int_14; extern const cst_val_int val_int_15; extern const cst_val_int val_int_16; extern const cst_val_int val_int_17; extern const cst_val_int val_int_18; extern const cst_val_int val_int_19; extern const cst_val_int val_int_20; extern const cst_val_int val_int_21; extern const cst_val_int val_int_22; extern const cst_val_int val_int_23; extern const cst_val_int val_int_24; extern const cst_val_void val_string_0; extern const cst_val_void val_string_1; extern const cst_val_void val_string_2; extern const cst_val_void val_string_3; extern const cst_val_void val_string_4; extern const cst_val_void val_string_5; extern const cst_val_void val_string_6; extern const cst_val_void val_string_7; extern const cst_val_void val_string_8; extern const cst_val_void val_string_9; extern const cst_val_void val_string_10; extern const cst_val_void val_string_11; extern const cst_val_void val_string_12; extern const cst_val_void val_string_13; extern const cst_val_void val_string_14; extern const cst_val_void val_string_15; extern const cst_val_void val_string_16; extern const cst_val_void val_string_17; extern const cst_val_void val_string_18; extern const cst_val_void val_string_19; extern const cst_val_void val_string_20; extern const cst_val_void val_string_21; extern const cst_val_void val_string_22; extern const cst_val_void val_string_23; extern const cst_val_void val_string_24; #endif #define DEF_STATIC_CONST_VAL_INT(N,V) static DEF_CONST_VAL_INT(N,V) #define DEF_STATIC_CONST_VAL_STRING(N,S) static DEF_CONST_VAL_STRING(N,S) #define DEF_STATIC_CONST_VAL_FLOAT(N,F) static DEF_CONST_VAL_FLOAT(N,F) #define DEF_STATIC_CONST_VAL_CONS(N,A,D) static DEF_CONST_VAL_CONS(N,A,D) /* Some actual val consts */ /* The have casts as in the non-union intialize case the casts are necessary */ /* but in the union initial case these casts are harmless */ #define VAL_INT_0 (cst_val *)&val_int_0 #define VAL_INT_1 (cst_val *)&val_int_1 #define VAL_INT_2 (cst_val *)&val_int_2 #define VAL_INT_3 (cst_val *)&val_int_3 #define VAL_INT_4 (cst_val *)&val_int_4 #define VAL_INT_5 (cst_val *)&val_int_5 #define VAL_INT_6 (cst_val *)&val_int_6 #define VAL_INT_7 (cst_val *)&val_int_7 #define VAL_INT_8 (cst_val *)&val_int_8 #define VAL_INT_9 (cst_val *)&val_int_9 #define VAL_INT_10 (cst_val *)&val_int_10 #define VAL_INT_11 (cst_val *)&val_int_11 #define VAL_INT_12 (cst_val *)&val_int_12 #define VAL_INT_13 (cst_val *)&val_int_13 #define VAL_INT_14 (cst_val *)&val_int_14 #define VAL_INT_15 (cst_val *)&val_int_15 #define VAL_INT_16 (cst_val *)&val_int_16 #define VAL_INT_17 (cst_val *)&val_int_17 #define VAL_INT_18 (cst_val *)&val_int_18 #define VAL_INT_19 (cst_val *)&val_int_19 #define VAL_INT_20 (cst_val *)&val_int_20 #define VAL_INT_21 (cst_val *)&val_int_21 #define VAL_INT_22 (cst_val *)&val_int_22 #define VAL_INT_23 (cst_val *)&val_int_23 #define VAL_INT_24 (cst_val *)&val_int_24 const cst_val *val_int_n(int n); #define VAL_STRING_0 (cst_val *)&val_string_0 #define VAL_STRING_1 (cst_val *)&val_string_1 #define VAL_STRING_2 (cst_val *)&val_string_2 #define VAL_STRING_3 (cst_val *)&val_string_3 #define VAL_STRING_4 (cst_val *)&val_string_4 #define VAL_STRING_5 (cst_val *)&val_string_5 #define VAL_STRING_6 (cst_val *)&val_string_6 #define VAL_STRING_7 (cst_val *)&val_string_7 #define VAL_STRING_8 (cst_val *)&val_string_8 #define VAL_STRING_9 (cst_val *)&val_string_9 #define VAL_STRING_10 (cst_val *)&val_string_10 #define VAL_STRING_11 (cst_val *)&val_string_11 #define VAL_STRING_12 (cst_val *)&val_string_12 #define VAL_STRING_13 (cst_val *)&val_string_13 #define VAL_STRING_14 (cst_val *)&val_string_14 #define VAL_STRING_15 (cst_val *)&val_string_15 #define VAL_STRING_16 (cst_val *)&val_string_16 #define VAL_STRING_17 (cst_val *)&val_string_17 #define VAL_STRING_18 (cst_val *)&val_string_18 #define VAL_STRING_19 (cst_val *)&val_string_19 #define VAL_STRING_20 (cst_val *)&val_string_20 #define VAL_STRING_21 (cst_val *)&val_string_21 #define VAL_STRING_22 (cst_val *)&val_string_22 #define VAL_STRING_23 (cst_val *)&val_string_23 #define VAL_STRING_24 (cst_val *)&val_string_24 const cst_val *val_string_n(int n); #endif