coan 4.2.4
symbol.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2007-2011 Mike Kinghan, imk@strudl.org                  *
00003  *   All rights reserved.                                                  *
00004  *   Contributed originally by Mike Kinghan, imk@strudl.org                *
00005  *                                                                         *
00006  *   Redistribution and use in source and binary forms, with or without    *
00007  *   modification, are permitted provided that the following conditions    *
00008  *   are met:                                                              *
00009  *                                                                         *
00010  *   Redistributions of source code must retain the above copyright        *
00011  *   notice, this list of conditions and the following disclaimer.         *
00012  *                                                                         *
00013  *   Redistributions in binary form must reproduce the above copyright     *
00014  *   notice, this list of conditions and the following disclaimer in the   *
00015  *   documentation and/or other materials provided with the distribution.  *
00016  *                                                                         *
00017  *   Neither the name of Symbian Software Ltd. nor the names of its        *
00018  *   contributors may be used to endorse or promote products derived from  *
00019  *   this software without specific prior written permission.              *
00020  *                                                                         *
00021  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   *
00022  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     *
00023  *   LIMITED TO, THE IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS    *
00024  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE        *
00025  *   COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,   *
00026  *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,  *
00027  *   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS *
00028  *   OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED    *
00029  *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,*
00030  *   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF *
00031  *   THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH  *
00032  *   DAMAGE.                                                               *
00033  *                                                                         *
00034  **************************************************************************/
00035 
00036 #include "report.h"
00037 #include "chew.h"
00038 #include "evaluator.h"
00039 #include "configured_symbols.h"
00040 #include "io.h"
00041 #include "contradiction.h"
00042 #include "args.h"
00043 #include "swiss_army.h"
00044 #include "line_select.h"
00045 #include "if_control.h"
00046 
00054 
00061 static void
00062 symbol_init(symbol_h sym, char const *name, size_t namelen)
00063 {
00064     eval_result_clear(sym);
00065     sym->sym_name = clone(name,namelen);
00066 }
00067 
00075 static void
00076 symbol_copy_init(symbol_h dest, symbol_const_h src)
00077 {
00078     dest->sym_name = clone(src->sym_name,0);
00079     if (src->sym_def) {
00080         dest->sym_def = canonical_string_copy(src->sym_def);
00081     } else {
00082         dest->sym_def = src->sym_def;
00083     }
00084     if (src->most_resolved) {
00085         dest->most_resolved = canonical_string_copy(src->most_resolved);
00086     } else {
00087         dest->most_resolved = src->most_resolved;
00088     }
00089     dest->flags = src->flags;
00090     dest->value = src->value;
00091 }
00092 
00100 static int
00101 symbol_name_compare(symbol_const_h sym, char const *name, size_t namelen)
00102 {
00103     char const *sym_name;
00104     int comp;
00105     assert(sym);
00106     assert(name);
00107     sym_name = symbol_name(sym);
00108     comp = strncmp(sym_name,name,namelen);
00109     if (comp <= 0) {    /* Symbol name compares lesser.*/
00110         if (comp == 0) { /* Initial match*/
00111             if (sym_name[namelen] != '\0') {
00112                 /* Symbol name is longer than `name'*/
00113                 comp = 1;
00114             }
00115             /* Otherwise full match*/
00116         }
00117     }
00118     return comp;
00119 }
00120 
00122 static void
00123 report_symbol_configuration(bool define, int gripe, symbol_const_h sym,
00124                             canonical_string_const_h old_def,
00125                             canonical_string_const_h new_def,
00126                             char const *tail)
00127 {
00128     if (!gripe) {
00129         return;
00130     }
00131     if (define) {
00132         switch(gripe) {
00133         case GRIPE_INSOURCE_FUNCTION_LIKE_MACRO_DEFINITION:
00134             report(GRIPE_INSOURCE_FUNCTION_LIKE_MACRO_DEFINITION,NULL,
00135                    "Sorry. Function-like macro definition is not supported, ignored: \"#define %s%s\"",
00136                     symbol_name(sym),tail);
00137             break;
00138         case GRIPE_GLOBAL_FUNCTION_LIKE_MACRO_DEFINITION:
00139             bail(GRIPE_GLOBAL_FUNCTION_LIKE_MACRO_DEFINITION,
00140                    "Sorry. Function-like macro definition is not supported: \"-D%s%s\"",
00141                     symbol_name(sym),tail);
00142             break;
00143         case GRIPE_GARBAGE_ARG:
00144             bail(GRIPE_GARBAGE_ARG,"Garbage in \"-D%s%s\"",
00145                 symbol_name(sym),tail);
00146             break;
00147         case GRIPE_DIFFERING_REDEF:
00148             report(GRIPE_DIFFERING_REDEF,NULL,
00149                    "Differently redefining \"%s=%s\", after \"%s=%s\" at line %d",
00150                    symbol_name(sym),
00151                    canonical_string_text(new_def),
00152                    symbol_name(sym),
00153                    canonical_string_text(old_def),
00154                    sym->line);
00155             break;
00156         case GRIPE_DUPLICATE_ARGS:
00157             report(GRIPE_DUPLICATE_ARGS,NULL,
00158                    "Duplicated \"-D%s=%s\" ignored",
00159                    symbol_name(sym),
00160                    canonical_string_text(new_def));
00161             break;
00162         case GRIPE_TRANSIENT_SYMBOL_ADDED:
00163             report(GRIPE_TRANSIENT_SYMBOL_ADDED,NULL,
00164                    "\"-D%s=%s\" has been assumed for the current file",
00165                    symbol_name(sym),
00166                    canonical_string_text(new_def));
00167             break;
00168         case GRIPE_INVALID_ARGS:
00169             if (old_def) {
00170                 bail(GRIPE_INVALID_ARGS,
00171                     "\"-D%s=%s\" contradicts prior \"-D%s=%s\"",
00172                      symbol_name(sym),
00173                      canonical_string_text(new_def),
00174                      symbol_name(sym),
00175                      canonical_string_text(old_def));
00176             }
00177             else {
00178                 bail(GRIPE_INVALID_ARGS,
00179                     "\"-D%s=%s\" contradicts prior \"-U%s\"",
00180                      symbol_name(sym),
00181                      canonical_string_text(new_def),
00182                      symbol_name(sym));
00183             }
00184             break;
00185         default:
00186             assert(false);
00187         }
00188     }
00189     else {
00190         switch(gripe) {
00191         case GRIPE_GARBAGE_ARG:
00192             bail(GRIPE_GARBAGE_ARG,"Garbage in \"-U%s%s\"",
00193                 symbol_name(sym),tail);
00194             break;
00195         case GRIPE_UNDEFING_DEFINED:
00196             report(GRIPE_UNDEFING_DEFINED,NULL,
00197                 "undefining %s, after defining %s=%s at line %d",
00198                 symbol_name(sym),
00199                 symbol_name(sym),
00200                 canonical_string_text(old_def),
00201                 sym->line);
00202             break;
00203         case GRIPE_INVALID_ARGS:
00204             bail(GRIPE_INVALID_ARGS,
00205                 "\"-U%s\" contradicts prior \"-D%s=%s\"",
00206                 symbol_name(sym),
00207                 symbol_name(sym),
00208                 canonical_string_text(old_def));
00209             break;
00210         case GRIPE_DUPLICATE_ARGS:
00211             report(GRIPE_DUPLICATE_ARGS,NULL,
00212                    "Duplicated \"-U%s\" ignored",
00213                    symbol_name(sym));
00214             break;
00215         case GRIPE_TRANSIENT_SYMBOL_ADDED:
00216             report(GRIPE_TRANSIENT_SYMBOL_ADDED,NULL,
00217                    "\"-U%s\" has been assumed for the current file",
00218                    symbol_name(sym));
00219             break;
00220         default:
00221             assert(false);
00222         }
00223     }
00224 }
00225 
00238 static canonical_string_h
00239 symbol_definition_resolve(symbol_const_h sym, ptr_vector_h history)
00240 {
00241     canonical_string_h resolved = canonical_string_copy(symbol_definition(sym));
00242     size_t offset = 0;
00243     symbol_h sy;
00244     for ( ;(sy = configured_symbol_find(resolved,&offset)) != NULL; offset = 0) {
00245         char const *symname = symbol_name(sy);
00246         char const *text = canonical_string_text(resolved);
00247         char const *cut_start = text + offset;
00248         char const *cut_end = cut_start + strlen(symname);
00249         size_t cut_len;
00250         canonical_string_const_h val = symbol_resolve(sy,history);
00251         cut_len = cut_end - cut_start;
00252         if (!val) {
00253             /* sym has circular definition */
00254             canonical_string_dispose(resolved);
00255             resolved = NULL;
00256             break;
00257         }
00258         canonical_string_replace(resolved,offset,cut_len,val);
00259     }
00260     return resolved;
00261 }
00262 
00265 /* API*/
00266 
00267 symbol_h
00268 symbol_new(char const *name, size_t namelen)
00269 {
00270     symbol_h sym;
00271     assert(name);
00272     assert(namelen);
00273     sym = zallocate(sizeof(eval_result_t));
00274     symbol_init(sym,name,namelen);
00275     return sym;
00276 }
00277 
00278 void
00279 symbol_dispose(symbol_h sym)
00280 {
00281     if (sym) {
00282         eval_result_clear(sym);
00283         free(sym);
00284     }
00285 }
00286 
00287 symbol_h
00288 symbol_copy(symbol_const_h src)
00289 {
00290     symbol_h dest;
00291     assert(src);
00292     dest = zallocate(sizeof(eval_result_t));
00293     symbol_copy_init(dest,src);
00294     return dest;
00295 }
00296 
00297 void
00298 symbol_swap(symbol_h lhs, symbol_h rhs)
00299 {
00300     assert(lhs);
00301     assert(rhs);
00302     PODSWAP(char *,&lhs->sym_name,&rhs->sym_name);
00303     canonical_string_swap(lhs->sym_def,rhs->sym_def);
00304     canonical_string_swap(lhs->most_resolved,rhs->most_resolved);
00305     PODSWAP(int_spec_t,&lhs->value,&lhs->value);
00306     PODSWAP(int,&lhs->flags,&lhs->flags);
00307 }
00308 
00309 void
00310 symbol_assign(symbol_h dest, symbol_const_h src)
00311 {
00312     if (dest != src) {
00313         symbol_h tmp = symbol_copy(src);
00314         symbol_swap(dest,tmp);
00315         symbol_dispose(tmp);
00316     }
00317 }
00318 
00319 bool
00320 symbol_equal(symbol_const_h lhs,symbol_const_h rhs)
00321 {
00322     bool eq = lhs == rhs;
00323     if (!eq) {
00324         eq = symbol_compare(lhs,rhs,0);
00325         if (eq) {
00326             eq = canonical_string_equal(symbol_definition(lhs),
00327                                         symbol_definition(rhs));
00328         }
00329     }
00330     return eq;
00331 }
00332 
00333 line_type_t
00334 symbol_define(symbol_h sym, char const *tail, char const **pend)
00335 {
00336     canonical_string_h new_def = NULL;
00337     canonical_string_const_h old_def = NULL;
00338     line_type_t retval = LT_DIRECTIVE_KEEP;
00339     bool update = true;
00340     int gripe = 0;
00341     assert(sym);
00342     if (*tail == '(') { /* Macro arguments */
00343         if (INSOURCE) {
00344             gripe = GRIPE_INSOURCE_FUNCTION_LIKE_MACRO_DEFINITION;
00345         }
00346         else {
00347             gripe = GRIPE_GLOBAL_FUNCTION_LIKE_MACRO_DEFINITION;
00348         }
00349         update = false;
00350         goto conclusion;
00351     }
00352     if (!INSOURCE) {
00353         if (*tail == '=') {
00354             ++tail;
00355         }
00356         else if (*tail) {
00357             gripe = GRIPE_GARBAGE_ARG;
00358             goto conclusion;
00359         }
00360     }
00361     if (*tail) {
00362         new_def = canonical_string_new(tail,0,&tail);
00363     }
00364     else {
00365         new_def = canonical_string_new(NULL,0,NULL);
00366     }
00367     old_def = symbol_definition(sym);
00368     if (symbol_is_configured(sym)) {
00369         /* This is a re-configuration of an already configured symbol */
00370         if (old_def) { /* Symbol is already defined */
00371             if (!canonical_string_equal(old_def,new_def)) { /* Definitions differ */
00372                 if (!symbol_is_global(sym)) { /* Differing #define constradicts prior #define */
00373                     gripe = GRIPE_DIFFERING_REDEF;
00374                 }
00375                 else if (INSOURCE) { /* Differing #define contradicts -D option */
00376                     retval = LT_DIRECTIVE_DROP;
00377                     update = false;
00378                     flush_contradiction();
00379                     insert_contradiction("\"%.*s\" differently redefines -D "
00380                                          "symbol");
00381                 }
00382                 /* Differing -D contradicts prior -D option */
00383                 else {
00384                     gripe = GRIPE_INVALID_ARGS;
00385                 }
00386             }
00387             /* Definitions the same */
00388             else if (!symbol_is_global(sym)) {  /* #define duplicating #define */
00389                 update = false;
00390             }
00391             else if (INSOURCE) { /* #define duplicating -D option */
00392                 retval = LT_DIRECTIVE_DROP;
00393                 update = false;
00394                 if (sym == GET_PUBLIC(contradiction,last_contradictory_undef)) {
00395                     forget_contradiction();
00396                 }
00397             }
00398             /* -D duplicating -D option */
00399             else {
00400                 gripe = GRIPE_DUPLICATE_ARGS;
00401                 update = false;
00402             }
00403         }
00404         /* Symbol is already undefined. */
00405         else if (symbol_is_global(sym)) { /* Defining contradicts -U option */
00406             update = false;
00407             if (INSOURCE) { /* #define contradicts -U option */
00408                 retval = LT_DIRECTIVE_DROP;
00409                 insert_contradiction("\"%.*s\" contradicts -U or --implicit");
00410             }
00411             /* -D option contradicts -U option */
00412             else {
00413                 gripe = GRIPE_INVALID_ARGS;
00414             }
00415         }
00416         //* Else #define countervails #undef */
00417     }
00418     /* Symbol not yet configured */
00419     else if (INSOURCE) {
00420         gripe = GRIPE_TRANSIENT_SYMBOL_ADDED;
00421     }
00422 conclusion:
00423     if (pend) {
00424         *pend = tail;
00425     }
00426     if (is_unconditional_line() || !INSOURCE) {
00427         report_symbol_configuration(true,gripe,sym,old_def,new_def,tail);
00428         if(update) {
00429             canonical_string_dispose(sym->sym_def);
00430             sym->sym_def = new_def;
00431             canonical_string_dispose(sym->most_resolved);
00432             sym->most_resolved = NULL;
00433             sym->line = GET_PUBLIC(io,line_num);
00434             if (!INSOURCE) {
00435                 SET_GLOBAL_SYM(*sym);
00436             }
00437             else {
00438                 SET_INSOURCE_SYM(*sym);
00439             }
00440         }
00441         else {
00442             canonical_string_dispose(new_def);
00443         }
00444     }
00445     return retval;
00446 }
00447 
00448 line_type_t
00449 symbol_undefine(symbol_h sym, char const *tail, char const **pend)
00450 {
00451     line_type_t retval = LT_DIRECTIVE_KEEP;
00452     bool update = true;
00453     int gripe = 0;
00454     canonical_string_const_h old_def = NULL;
00455     assert(sym);
00456     if (!INSOURCE) {
00457         if (*tail) {
00458             gripe = GRIPE_GARBAGE_ARG;
00459             update = false;
00460             goto conclusion;
00461         }
00462     }
00463     old_def = symbol_definition(sym);
00464     if (symbol_is_configured(sym)) {
00465         /* This is a re-configuration of an already configured symbol */
00466         if (old_def) { /* Symbol is already defined */
00467             if (!symbol_is_global(sym)) {
00468                 gripe = GRIPE_UNDEFING_DEFINED;
00469             }
00470             else if (INSOURCE) { /* #undef contradicting -D option */
00471                 retval = LT_DIRECTIVE_DROP;
00472                 update = false;
00473                 if (GET_PUBLIC(contradiction,last_contradictory_undef) != sym) {
00474                     flush_contradiction();
00475                     SET_PUBLIC(contradiction,last_contradictory_undef) = sym;
00476                     save_contradiction("\"%.*s\" contradicts -D symbol");
00477                 }
00478             }
00479                         else { /* -U contradicting prior -D */
00480                                 gripe = GRIPE_INVALID_ARGS;
00481                         }
00482         }
00483         /* Symbol is already undefined. */
00484         else if (symbol_is_global(sym)) {
00485             update = false;
00486             if (INSOURCE) {
00487                 retval = LT_DIRECTIVE_DROP;
00488             }
00489             else {
00490                 gripe = GRIPE_DUPLICATE_ARGS;
00491             }
00492         }
00493         else {
00494             update = false;
00495         }
00496     }
00497     else if (INSOURCE) {
00498         gripe = GRIPE_TRANSIENT_SYMBOL_ADDED;
00499     }
00500 conclusion:
00501     if (pend) {
00502         *pend = tail;
00503     }
00504     if (is_unconditional_line() || !INSOURCE) {
00505         report_symbol_configuration(false,gripe,sym,old_def,NULL,tail);
00506 
00507         if (update) {
00508             canonical_string_dispose(sym->sym_def);
00509             sym->sym_def = NULL;
00510             canonical_string_dispose(sym->most_resolved);
00511             sym->most_resolved = NULL;
00512             eval_result_set_value(sym,&int_spec_false);
00513             sym->line = GET_PUBLIC(io,line_num);
00514             if (!INSOURCE) {
00515                 SET_GLOBAL_SYM(*sym);
00516             }
00517             else {
00518                 SET_INSOURCE_SYM(*sym);
00519             }
00520         }
00521     }
00522     return retval;
00523 }
00524 
00525 char const *
00526 symbol_name(symbol_const_h sym)
00527 {
00528     assert(sym);
00529     return sym->sym_name;
00530 }
00531 
00532 canonical_string_const_h
00533 symbol_definition(symbol_const_h sym)
00534 {
00535     assert(sym);
00536     return sym->sym_def;
00537 }
00538 
00539 int
00540 symbol_compare(symbol_const_h lhs, void const * rhs, size_t len)
00541 {
00542     assert(lhs);
00543     assert(rhs);
00544     if (len) {
00545         return symbol_name_compare(lhs,rhs,len);
00546     } else {
00547         symbol_const_h other = rhs;
00548         return strcmp(lhs->sym_name,other->sym_name);
00549     }
00550 }
00551 
00552 bool
00553 symbol_is_legal(char const *tok, size_t toklen)
00554 {
00555     if (!is_symbol_start_char(*tok) || toklen < 1) {
00556         return false;
00557     }
00558     for (--toklen; toklen; --toklen,++tok) {
00559         if (!is_symbol_inner_char(*tok)) {
00560             return false;
00561         }
00562     }
00563     return true;
00564 }
00565 
00566 bool
00567 symbol_is_configured(symbol_const_h sym)
00568 {
00569     assert(sym);
00570     return GLOBAL_SYM(*sym) || INSOURCE_SYM(*sym);
00571 }
00572 
00573 bool
00574 symbol_is_global(symbol_const_h sym)
00575 {
00576     assert(sym);
00577     return GLOBAL_SYM(*sym);
00578 }
00579 
00580 bool
00581 is_symbol_start_char(char cp)
00582 {
00583     return isalpha(cp) || cp == '_';
00584 }
00585 
00586 bool
00587 is_symbol_inner_char(char cp)
00588 {
00589     return isalnum(cp) || cp == '_';
00590 }
00591 
00592 bool
00593 symbol_reported(symbol_const_h sym)
00594 {
00595     assert(sym);
00596     return REPORTED(*sym);
00597 }
00598 
00599 canonical_string_const_h
00600 symbol_resolve(symbol_h sym, ptr_vector_h history)
00601 {
00602     canonical_string_h resolved = NULL;
00603     bool outermost = true;
00604     if (history) {
00605         symbol_const_h * begin = (symbol_const_h *)ptr_vector_begin_const(history);
00606         symbol_const_h * end = (symbol_const_h *)ptr_vector_end_const(history);
00607         outermost = false;
00608         for (   ;begin != end; ++begin) {
00609             if (*begin == sym) {
00610                 report(GRIPE_CIRCULAR_SYM_DEF,NULL,
00611                     "Symbol \"%s\" has a circular definition",
00612                     symbol_name(sym));
00613                 canonical_string_dispose(sym->most_resolved);
00614                 sym->most_resolved = NULL;
00615                 return sym->most_resolved;
00616             }
00617         }
00618     }
00619     else {
00620         history = ptr_vector_new(NULL,NULL);
00621         ptr_vector_append(history,sym);
00622     }
00623     if (symbol_is_configured(sym)) {
00624         if (symbol_definition(sym)) {
00625             resolved = symbol_definition_resolve(sym,history);
00626         }
00627         else {
00628             resolved = canonical_string_new("0",0,NULL);
00629         }
00630     }
00631     else {
00632         resolved = canonical_string_new(symbol_name(sym),0,NULL);
00633     }
00634     canonical_string_dispose(sym->most_resolved);
00635     if (!resolved) {
00636         /* Sym has circular definition */
00637         if (outermost) {
00638             SET_KEEP(*sym);
00639             sym->most_resolved = canonical_string_new(symbol_name(sym),0,NULL);
00640         }
00641         else {
00642             sym->most_resolved = resolved;
00643         }
00644     }
00645     else {
00646         char const *pc = clone(canonical_string_text(resolved),0);
00647         char const *def_text = pc;
00648         eval_result_t er;
00649         er = eval_definition_text(&pc);
00650         if (*pc == 0 && RESOLVED(er)) {
00651             eval_result_set_value(sym,&er.value);
00652             sym->most_resolved = canonical_numeral(&er.value);
00653         }
00654         else {
00655             sym->most_resolved = resolved;
00656         }
00657         eval_result_clear(&er);
00658         free((char *)def_text);
00659     }
00660     if (outermost) {
00661         ptr_vector_drop(history);
00662     }
00663     return sym->most_resolved;
00664 }
00665 
00666 line_type_t
00667 symbol_evaluate_status(bool define, char const *symstart, const char *tail, const char **pend)
00668 {
00669     line_type_t retval = LT_DIRECTIVE_KEEP;
00670     symbol_h sym;
00671     size_t namelen;
00672     assert(symstart);
00673     if (!tail) {
00674         assert(!INSOURCE);
00675         tail = chew_symbol(symstart);
00676         namelen = tail - symstart;
00677     }
00678     else {
00679         assert(INSOURCE);
00680         namelen = strlen(symstart);
00681     }
00682     sym = configured_symbol_match(symstart,namelen);
00683     if (!sym) {
00684         sym = symbol_new(symstart,namelen);
00685     }
00686     if (!dropping_line()) {
00687         retval = configured_symbol_add(define,sym,tail,pend);
00688     }
00689     if (INSOURCE && ((define && eligible_line(CMD_SYMBOLS,HASH_DEFINE)) ||
00690                     (!define && eligible_line(CMD_SYMBOLS,HASH_UNDEF)))) {
00691         report_symbol(sym);
00692     }
00693     if (!symbol_is_configured(sym)) {
00694         symbol_dispose(sym);
00695     }
00696     return retval;
00697 }
00698 /* EOF*/
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines