coan 4.2.4
|
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*/