coan 4.2.4
|
00001 /*************************************************************************** 00002 * Copyright (C) 2004, 2006 Symbian Software Ltd. * 00003 * All rights reserved. * 00004 * Copyright (C) 2002, 2003 Tony Finch <dot@dotat.at>. * 00005 * All rights reserved. * 00006 * Copyright (C) 1985, 1993 The Regents of the University of California. * 00007 * All rights reserved. * 00008 * Copyright (C) 2007-2011 Mike Kinghan, imk@strudl.org * 00009 * All rights reserved. * 00010 * * 00011 * Contributed by Mike Kinghan, imk@strudl.org, derived from the code * 00012 * of Tony Finch * 00013 * * 00014 * Redistribution and use in source and binary forms, with or without * 00015 * modification, are permitted provided that the following conditions * 00016 * are met: * 00017 * * 00018 * Redistributions of source code must retain the above copyright * 00019 * notice, this list of conditions and the following disclaimer. * 00020 * * 00021 * Redistributions in binary form must reproduce the above copyright * 00022 * notice, this list of conditions and the following disclaimer in the * 00023 * documentation and/or other materials provided with the distribution. * 00024 * * 00025 * Neither the name of Symbian Software Ltd. nor the names of its * 00026 * contributors may be used to endorse or promote products derived from * 00027 * this software without specific prior written permission. * 00028 * * 00029 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 00030 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * 00031 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * 00032 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * 00033 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * 00034 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 00035 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * 00036 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * 00037 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,* 00038 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * 00039 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * 00040 * DAMAGE. * 00041 * * 00042 **************************************************************************/ 00043 00044 #include "evaluator.h" 00045 #include "io.h" 00046 #include "line_edit.h" 00047 #include "chew.h" 00048 #include "args.h" 00049 #include "contradiction.h" 00050 #include "if_control.h" 00051 #include "configured_symbols.h" 00052 #include "unconfigured_symbols.h" 00053 #include "report.h" 00054 #include "includes_tally.h" 00055 #include "line_select.h" 00056 #include "directives_tally.h" 00057 #include "lexicon.h" 00058 00068 STATE_DEF(evaluator) 00069 { 00071 char const *ifpos; 00073 line_type_t line_type; 00079 int parsing_sym_def_depth; 00080 } 00081 STATE_T(evaluator); 00086 NO_PUBLIC_STATE(evaluator); 00087 00088 IMPLEMENT(evaluator,ZERO_INITABLE); 00093 00095 struct co_precedent_ops const * ops_tab; 00096 00097 /* Helpers ****************************************************************/ 00098 00110 static eval_result_t 00111 integer_binary_op( eval_result_t *lhs, 00112 eval_result_t *rhs, 00113 integer_bin_op_t op) 00114 { 00115 eval_result_t result = EVAL_RESULT_INITOR; 00116 if ((IS_CONST(*lhs) || RESOLVED(*lhs)) && 00117 (IS_CONST(*rhs) || RESOLVED(*rhs))) { 00118 int_spec_t int_spec = op(&lhs->value,&rhs->value); 00119 if (int_spec.type != INT_UNDEF) { 00120 eval_result_set_value(&result,&int_spec); 00121 } 00122 } 00123 return result; 00124 } 00125 00127 static eval_result_t 00128 op_lt(eval_result_t * lhs, eval_result_t * rhs) 00129 { 00130 return integer_binary_op(lhs,rhs,lt); 00131 } 00132 00134 static eval_result_t 00135 op_gt(eval_result_t *lhs, eval_result_t *rhs) 00136 { 00137 return integer_binary_op(lhs,rhs,gt); 00138 } 00139 00141 static eval_result_t 00142 op_le(eval_result_t *lhs, eval_result_t *rhs) 00143 { 00144 return integer_binary_op(lhs,rhs,le); 00145 } 00146 00148 static eval_result_t 00149 op_ge(eval_result_t *lhs, eval_result_t *rhs) 00150 { 00151 return integer_binary_op(lhs,rhs,ge); 00152 } 00153 00155 static eval_result_t 00156 op_eq(eval_result_t *lhs, eval_result_t *rhs) 00157 { 00158 return integer_binary_op(lhs,rhs,eq); 00159 } 00160 00162 static eval_result_t 00163 op_ne(eval_result_t *lhs, eval_result_t *rhs) 00164 { 00165 return integer_binary_op(lhs,rhs,ne); 00166 } 00167 00169 static eval_result_t 00170 op_or(eval_result_t *lhs, eval_result_t *rhs) 00171 { 00172 eval_result_t result = EVAL_RESULT_INITOR; 00173 if (IS_TRUE(*lhs) || IS_TRUE(*rhs)) { 00174 eval_result_set_value(&result,&int_spec_true); 00175 } else if (IS_FALSE(*lhs) && IS_FALSE(*rhs)) { 00176 eval_result_set_value(&result,&int_spec_false); 00177 } 00178 if (FLAGS_IN(*lhs,EVAL_RESOLVED) == FLAGS_IN(*rhs,EVAL_RESOLVED)) { 00179 SET_FLAGS_IF(KEEP_CONST(*lhs) | KEEP_CONST(*rhs), 00180 result,EVAL_KEEP_CONST); 00181 } else if (IS_TRUE(*lhs)) { 00182 SET_FLAGS_IF(KEEP_CONST(*lhs),result,EVAL_KEEP_CONST); 00183 CLEAR_FLAGS_IF(!KEEP_CONST(*rhs),*rhs,EVAL_KEEP); 00184 } else if (IS_TRUE(*rhs)) { 00185 SET_FLAGS_IF(KEEP_CONST(*rhs),result,EVAL_KEEP_CONST); 00186 CLEAR_FLAGS_IF(!KEEP_CONST(*lhs),*lhs,EVAL_KEEP); 00187 } else if (IS_FALSE(*lhs)) { 00188 SET_FLAGS_IF(KEEP_CONST(*rhs),result,EVAL_KEEP_CONST); 00189 } else if (IS_FALSE(*rhs)) { 00190 SET_FLAGS_IF(KEEP_CONST(*lhs),result,EVAL_KEEP_CONST); 00191 } 00192 return result; 00193 } 00194 00196 static eval_result_t 00197 op_and(eval_result_t *lhs, eval_result_t *rhs) 00198 { 00199 eval_result_t result = EVAL_RESULT_INITOR; 00200 if (IS_TRUE(*rhs) && IS_FALSE(*lhs)) { 00201 eval_result_set_value(&result,&int_spec_false); 00202 SET_FLAGS_IF(KEEP_CONST(*lhs),result,EVAL_KEEP_CONST); 00203 } else if (IS_TRUE(*lhs) && IS_FALSE(*rhs)) { 00204 eval_result_set_value(&result,&int_spec_false); 00205 SET_FLAGS_IF(KEEP_CONST(*rhs),result,EVAL_KEEP_CONST); 00206 } else if (UNRESOLVED(*lhs)) { 00207 if (IS_FALSE(*rhs)) { 00208 eval_result_set_value(&result,&int_spec_false); 00209 SET_FLAGS_IF(KEEP_CONST(*rhs),result,EVAL_KEEP_CONST); 00210 } else { 00211 SET_FLAGS_IF(KEEP_CONST(*lhs),result,EVAL_KEEP_CONST); 00212 } 00213 } else if (UNRESOLVED(*rhs)) { 00214 if (IS_FALSE(*lhs)) { 00215 eval_result_set_value(&result,&int_spec_false); 00216 SET_FLAGS_IF(KEEP_CONST(*lhs),result,EVAL_KEEP_CONST); 00217 } else { 00218 SET_FLAGS_IF(KEEP_CONST(*rhs),result,EVAL_KEEP_CONST); 00219 } 00220 } else { 00221 int_spec_t int_spec = boolean_and(&lhs->value,&rhs->value); 00222 eval_result_set_value(&result,&int_spec); 00223 SET_FLAGS_IF(KEEP_CONST(*rhs) | KEEP_CONST(*lhs), 00224 result,EVAL_KEEP_CONST); 00225 } 00226 return result; 00227 } 00228 00230 static eval_result_t 00231 op_bit_and(eval_result_t *lhs, eval_result_t *rhs) 00232 { 00233 return integer_binary_op(lhs,rhs,bit_and); 00234 } 00235 00237 static eval_result_t 00238 op_bit_or(eval_result_t *lhs, eval_result_t *rhs) 00239 { 00240 return integer_binary_op(lhs,rhs,bit_or); 00241 } 00242 00244 static eval_result_t 00245 op_bit_xor(eval_result_t *lhs, eval_result_t *rhs) 00246 { 00247 return integer_binary_op(lhs,rhs,bit_xor); 00248 } 00249 00251 static eval_result_t 00252 op_lshift(eval_result_t *lhs, eval_result_t *rhs) 00253 { 00254 return integer_binary_op(lhs,rhs,lshift); 00255 } 00256 00258 static eval_result_t 00259 op_rshift(eval_result_t *lhs, eval_result_t *rhs) 00260 { 00261 return integer_binary_op(lhs,rhs,rshift); 00262 } 00263 00265 static eval_result_t 00266 op_add(eval_result_t *lhs, eval_result_t *rhs) 00267 { 00268 return integer_binary_op(lhs,rhs,add); 00269 } 00270 00272 static eval_result_t 00273 op_subtract(eval_result_t *lhs, eval_result_t *rhs) 00274 { 00275 return integer_binary_op(lhs,rhs,subtract); 00276 } 00277 00279 static eval_result_t 00280 op_mult(eval_result_t *lhs, eval_result_t *rhs) 00281 { 00282 return integer_binary_op(lhs,rhs,multiply); 00283 } 00284 00286 static eval_result_t 00287 op_divide(eval_result_t *lhs, eval_result_t *rhs) 00288 { 00289 eval_result_t result = EVAL_RESULT_INITOR; 00290 if ((IS_CONST(*lhs) || RESOLVED(*lhs)) && 00291 (IS_CONST(*rhs) || RESOLVED(*rhs))) { 00292 if (!rhs->value.val.ull) { 00293 report(GRIPE_ZERO_DIVIDE,NULL, 00294 "Divide by zero"); 00295 } else { 00296 int_spec_t int_spec = divide(&lhs->value,&rhs->value); 00297 eval_result_set_value(&result,&int_spec); 00298 } 00299 } 00300 return result; 00301 } 00302 00304 static eval_result_t 00305 op_mod(eval_result_t *lhs, eval_result_t *rhs) 00306 { 00307 eval_result_t result = EVAL_RESULT_INITOR; 00308 if ((IS_CONST(*lhs) || RESOLVED(*lhs)) && 00309 (IS_CONST(*rhs) || RESOLVED(*rhs))) { 00310 if (!rhs->value.val.ull) { 00311 report(GRIPE_ZERO_DIVIDE,NULL, 00312 "Divide by zero"); 00313 } else { 00314 int_spec_t int_spec = modulus(&lhs->value,&rhs->value); 00315 eval_result_set_value(&result,&int_spec); 00316 } 00317 } 00318 return result; 00319 } 00320 00325 struct operation { 00327 const char *str; 00329 eval_result_t (*fn)(eval_result_t *, eval_result_t *); 00330 }; 00331 00349 typedef eval_result_t (evaluator_t)( 00350 struct co_precedent_ops const * ops, 00351 char const **, struct operation const **pbin_op); 00352 00371 static eval_result_t 00372 eval_unary(struct co_precedent_ops const * ops, char const **cpp, struct operation const **ignored); 00373 00374 00399 static eval_result_t 00400 eval_table(struct co_precedent_ops const *ops, char const **cpp, struct operation const **pbin_op); 00401 00402 00412 struct co_precedent_ops { 00414 evaluator_t *inner; 00417 struct operation op[5]; 00418 }; 00419 00420 00422 const struct co_precedent_ops eval_ops[] = { 00423 00424 { 00425 eval_table, 00426 { 00427 { BOOLEAN_OR, op_or } 00428 } 00429 }, 00430 { 00431 eval_table, 00432 { 00433 { BOOLEAN_AND, op_and } 00434 } 00435 }, 00436 { 00437 eval_table, 00438 { 00439 { BIT_OR, op_bit_or }, 00440 { BIT_XOR, op_bit_xor }, 00441 { BIT_AND, op_bit_and } 00442 } 00443 }, 00444 { 00445 eval_table, 00446 { 00447 { EQ, op_eq }, 00448 { NEQ, op_ne } 00449 } 00450 }, 00451 { 00452 eval_table, 00453 { 00454 { LE, op_le }, 00455 { GE, op_ge }, 00456 { LESS, op_lt }, 00457 { GREATER, op_gt } 00458 } 00459 }, 00460 { 00461 eval_table, 00462 { 00463 { LSHIFT, op_lshift }, 00464 { RSHIFT, op_rshift }, 00465 } 00466 }, 00467 { 00468 eval_table, 00469 { 00470 { ADD, op_add }, 00471 { SUBTRACT, op_subtract }, 00472 } 00473 }, 00474 { 00475 eval_unary, 00476 { 00477 { MULTIPLY, op_mult }, 00478 { DIV, op_divide }, 00479 { MOD, op_mod }, 00480 } 00481 }, 00482 }; 00483 00484 struct co_precedent_ops const * ops_tab = eval_ops; 00485 00500 static char const * 00501 short_circuit_and(char const *cp) 00502 { 00503 int balance = 0; 00504 for ( ; *(cp = chew_on(cp)); ++cp) { 00505 if (*cp == '(') { 00506 ++balance; 00507 } else if (*cp == ')') { 00508 --balance; 00509 } 00510 if (balance < 0) { 00511 break; 00512 } else if (balance == 0) { 00513 /* Check for another binary truth functor on same 00514 * level to respect precedence. 00515 */ 00516 if (cp[0] == cp[1] && cp[0] == '|') { 00517 break; 00518 } 00519 } 00520 } 00521 return cp; 00522 } 00523 00538 static char const * 00539 short_circuit_or(char const *cp) 00540 { 00541 int balance = 0; 00542 for ( ; *(cp = chew_on(cp)); ++cp) { 00543 if (*cp == '(') { 00544 ++balance; 00545 } else if (*cp == ')') { 00546 --balance; 00547 } 00548 if (balance < 0) { 00549 break; 00550 } 00551 } 00552 return cp; 00553 } 00554 00559 static int 00560 eval_if(char const **cpp); 00561 00571 static line_type_t 00572 eval_hash_define(char const **cpp) 00573 { 00574 canonical_string_h symname = NULL; 00575 char const * cp = *cpp; 00576 line_type_t retval; 00577 debug(DBG_13,line_len(*cpp),*cpp); 00578 cp = chew_on(cp); 00579 if (eligible_line(CMD_DEFS,HASH_DEFINE)) { 00580 canonical_string_h def_text = canonical_string_new(cp,0,NULL); 00581 directive_tally(def_text,HASH_DEFINE); 00582 } 00583 00584 symname = canonical_identifier(&cp); 00585 retval = symbol_evaluate_status(true,canonical_string_text(symname),cp,&cp); 00586 while(*cp) { /* Chew to a line end */ 00587 cp = chew_string(cp); 00588 cp = chew_on(cp); 00589 } 00590 canonical_string_dispose(symname); 00591 debug(DBG_14,line_len(*cpp),*cpp,retval); 00592 *cpp = cp; 00593 return retval; 00594 } 00595 00605 static line_type_t 00606 eval_hash_undef(char const **cpp) 00607 { 00608 canonical_string_h symname = NULL; 00609 char const *cp = *cpp; 00610 line_type_t retval = LT_DIRECTIVE_KEEP; 00611 debug(DBG_15,line_len(*cpp),*cpp); 00612 cp = chew_on(cp); 00613 symname = canonical_identifier(&cp); 00614 if (eligible_line(CMD_DEFS,HASH_UNDEF)) { 00615 directive_tally(canonical_string_copy(symname),HASH_UNDEF); 00616 } 00617 retval = symbol_evaluate_status(false,canonical_string_text(symname),cp,&cp); 00618 debug(DBG_16,line_len(*cpp),*cpp,retval); 00619 canonical_string_dispose(symname); 00620 *cpp = cp = chew_on(cp); 00621 return retval; 00622 } 00623 00639 static eval_result_t 00640 eval_possible_symbol(char const **cpp, directive_type_t context) 00641 { 00642 symbol_h sym; 00643 eval_result_t result = EVAL_RESULT_INITOR; 00644 char const *cp = *cpp; 00645 char const *arg_start = cp; 00646 char const *arg_end; 00647 canonical_string_const_h sym_def = NULL; 00648 canonical_string_h symname = canonical_identifier(&cp); 00649 assert(context == HASH_IF || context == HASH_INCLUDE); 00650 arg_end = chew_macro_call(arg_start); 00651 if (arg_end > cp) { 00652 report(GRIPE_FUNCTION_LIKE_MACRO_EXPANSION,NULL, 00653 "Sorry. Function-like macro expansion is not supported: \"%.*s\"",arg_end - arg_start,arg_start); 00654 } 00655 cp = arg_end; 00656 sym = configured_symbol_match(canonical_string_text(symname),0); 00657 if (!sym) { 00658 if (eligible_line(CMD_SYMBOLS,context) && 00659 GET_STATE(evaluator,parsing_sym_def_depth) == 0) { 00660 unconfigured_symbol_tally(canonical_string_text(symname), 00661 canonical_string_length(symname)); 00662 } 00663 if (GET_PUBLIC(args,implicit)) { 00664 eval_result_set_value(&result,&int_spec_false); 00665 } 00666 /* Unknown symbol*/ 00667 } else { 00668 if (eligible_line(CMD_SYMBOLS,context) && 00669 GET_STATE(evaluator,parsing_sym_def_depth) == 0) { 00670 report_symbol(sym); /* symbol is resolved in reporting */ 00671 } 00672 else { 00673 symbol_resolve(sym,NULL); 00674 } 00675 if (context == HASH_IF && (sym_def = symbol_definition(sym)) && !canonical_string_length(sym_def)) { 00676 if (GET_STATE(evaluator,parsing_sym_def_depth) == 0) { 00677 report(GRIPE_EMPTY_SYMBOL,NULL, 00678 "Empty symbol \"%s\" in expression",symbol_name(sym)); 00679 } 00680 } 00681 result = *sym; 00682 } 00683 *cpp = cp; 00684 return result; 00685 } 00686 00687 00688 #if 0 00689 00711 static char const * 00712 eval_hash_include(char const *cp) 00713 { 00714 static int recursions = 0; 00715 canonical_string_const_h resolved_val = NULL; 00716 char const *arg_start; 00717 size_t arg_len; 00718 eval_result_t result; 00719 SET_PUBLIC(chew,stop_at_quote) = true; 00720 arg_start = cp = chew_on(cp); 00721 if (!*cp) { 00722 report(GRIPE_INVALID_INCLUDE,NULL, 00723 "#include has no argument"); 00724 return cp; 00725 } 00726 if (is_symbol_start_char(*cp)) { 00727 result = eval_possible_symbol(&cp,HASH_INCLUDE); 00728 arg_len = cp - arg_start; 00729 if (result.most_resolved) { 00730 resolved_val = result.most_resolved; 00731 ++recursions; 00732 (void)eval_hash_include(canonical_string_text(resolved_val)); 00733 --recursions; 00734 } 00735 else { 00736 report(GRIPE_INVALID_INCLUDE,NULL, 00737 "\"#include %.*s\": #include requires header name or symbol evaluating to header name", 00738 arg_len,arg_start); 00739 } 00740 } 00741 else { 00742 bool invalid = false; 00743 cp = chew_header_name(arg_start); 00744 arg_len = cp - arg_start; 00745 if (!arg_len) { 00746 invalid = true; 00747 report(GRIPE_INVALID_INCLUDE,NULL,"\"#include %s\": bad header name",arg_start); 00748 } 00749 else if (*arg_start == '\"' || *arg_start == '<') { /* Looks like a header name */ 00750 if (*arg_start == '\"' && (cp[-1] != '\"' || arg_len < 3)) { 00751 invalid = true; 00752 report(GRIPE_INVALID_INCLUDE,NULL,"\"#include %.*s\": bad local header name",arg_len,arg_start); 00753 } else if (*arg_start == '<' && (cp[-1] != '>' || arg_len < 3)) { 00754 invalid = true; 00755 report(GRIPE_INVALID_INCLUDE,NULL,"\"#include %.*s\": bad system header name",arg_len,arg_start); 00756 } 00757 } 00758 if (invalid) { 00759 cp = chew_string(arg_start); 00760 arg_len = cp - arg_start; 00761 } 00762 } 00763 if (!recursions && eligible_line(CMD_INCLUDES,HASH_INCLUDE)) { 00764 /* Do the reporting for the \c includes command */ 00765 hash_include_tally(arg_start,arg_len,resolved_val); 00766 } 00767 return cp; 00768 } 00769 #endif 00770 00795 static line_type_t 00796 eval_hash_include(char const **cpp) 00797 { 00798 static int recursions = 0; 00799 char const *cp = *cpp; 00800 line_type_t retval = LT_DIRECTIVE_KEEP; 00801 canonical_string_const_h resolved_val = NULL; 00802 char const *arg_start; 00803 size_t arg_len; 00804 eval_result_t result; 00805 SET_PUBLIC(chew,stop_at_quote) = true; 00806 arg_start = cp = chew_on(cp); 00807 if (!*cp) { 00808 report(GRIPE_INVALID_INCLUDE,NULL, 00809 "#include has no argument"); 00810 goto conclusion; 00811 } 00812 if (is_symbol_start_char(*cp)) { 00813 result = eval_possible_symbol(&cp,HASH_INCLUDE); 00814 arg_len = cp - arg_start; 00815 if (result.most_resolved) { 00816 char const *ptext; 00817 resolved_val = result.most_resolved; 00818 ptext = canonical_string_text(resolved_val); 00819 ++recursions; 00820 retval = eval_hash_include(&ptext); 00821 --recursions; 00822 } 00823 else { 00824 report(GRIPE_INVALID_INCLUDE,NULL, 00825 "\"#include %.*s\": #include requires header name or symbol evaluating to header name", 00826 arg_len,arg_start); 00827 } 00828 } 00829 else { 00830 bool invalid = false; 00831 cp = chew_header_name(arg_start); 00832 arg_len = cp - arg_start; 00833 if (!arg_len) { 00834 invalid = true; 00835 report(GRIPE_INVALID_INCLUDE,NULL,"\"#include %s\": bad header name",arg_start); 00836 } 00837 else if (*arg_start == '\"' || *arg_start == '<') { /* Looks like a header name */ 00838 if (*arg_start == '\"' && (cp[-1] != '\"' || arg_len < 3)) { 00839 invalid = true; 00840 report(GRIPE_INVALID_INCLUDE,NULL,"\"#include %.*s\": bad local header name",arg_len,arg_start); 00841 } else if (*arg_start == '<' && (cp[-1] != '>' || arg_len < 3)) { 00842 invalid = true; 00843 report(GRIPE_INVALID_INCLUDE,NULL,"\"#include %.*s\": bad system header name",arg_len,arg_start); 00844 } 00845 } 00846 if (invalid) { 00847 cp = chew_string(arg_start); 00848 arg_len = cp - arg_start; 00849 } 00850 } 00851 if (!recursions && eligible_line(CMD_INCLUDES,HASH_INCLUDE)) { 00852 /* Do the reporting for the \c includes command */ 00853 hash_include_tally(arg_start,arg_len,resolved_val); 00854 } 00855 conclusion: 00856 *cpp = cp; 00857 if (dropping_line()) { 00858 retval = LT_DIRECTIVE_DROP; 00859 } 00860 return retval; 00861 } 00862 00869 static char const * 00870 eval_free_form_directive(char const *cp, directive_type_t directive_type) 00871 { 00872 canonical_string_h cs = canonical_string_new(cp,0,&cp); 00873 directive_tally(cs,directive_type); 00874 return cp; 00875 } 00876 00877 00878 static eval_result_t 00879 eval_table(struct co_precedent_ops const *ops, char const **cpp, struct operation const **pbin_op) 00880 { 00881 char const *start_cut = (debug(DBG_8, ops - eval_ops),*cpp); 00882 /* Evaluate the lhs...*/ 00883 struct operation const *lhs_bin_op = NULL; 00884 struct operation const *rhs_bin_op = NULL; 00885 eval_result_t lhs_result = ops->inner(ops+1,cpp,&lhs_bin_op); 00886 /* Assume lhs is all we've got...*/ 00887 eval_result_t result = lhs_result; 00888 char const * cp = *cpp; 00889 char const *start_lhs_cut = start_cut; 00890 char const *end_lhs_cut = cp; 00891 if (LEGAL(result)) { 00892 for (; *(cp = chew_on(cp)) && *cp != ')'; ) { 00893 const struct operation *op; 00894 eval_result_t rhs_result = EVAL_RESULT_INITOR; 00895 00896 end_lhs_cut = cp; 00897 /* Now look for binary op at current precedence...*/ 00898 for (op = ops->op; op->str != NULL && !match_op(&cp,op->str); op++) {} 00899 if (op->str == NULL) { 00900 /* No binary op at current precedence, skip rhs. */ 00901 if (ops == eval_ops) { 00902 /* No binary op at all. Illegal */ 00903 SET_ILLEGAL(result); 00904 } 00905 //IMK if (pbin_op) { 00906 // *pbin_op = NULL; 00907 //} 00908 break; 00909 } 00910 /* Got bin op - store it for return */ 00911 if (pbin_op) { 00912 *pbin_op = ops->op; 00913 } 00914 /* Assume we will not delete parentheses...*/ 00915 SET_KEEP_PAREN(result); 00916 if (RESOLVED(lhs_result) && !KEEP_CONST(lhs_result)) { 00917 /* ...Possibly can short-circuit*/ 00918 if (IS_TRUE(lhs_result) && op->fn == op_or) { 00919 /* Can shortcircuit on TRUE || <RHS>...*/ 00920 cp = short_circuit_or(cp); 00921 /* result == lhs_result. OK*/ 00922 break; 00923 } else if (IS_FALSE(lhs_result) && op->fn == op_and) { 00924 /* Can shortcircuit on FALSE && <RHS>...*/ 00925 cp = short_circuit_and(cp); 00926 /* result == lhs_result. OK*/ 00927 break; 00928 } else if ((IS_TRUE(lhs_result) && op->fn == op_and) || 00929 (IS_FALSE(lhs_result) && op->fn == op_or)) { 00930 /* Can delete TRUE &&, or FALSE ||...*/ 00931 cut_text(start_lhs_cut,cp); 00932 } 00933 } 00934 start_cut = end_lhs_cut; 00935 end_lhs_cut = cp; 00936 debug(DBG_9, ops - eval_ops, op->str); 00937 /* Evaluate rhs...*/ 00938 rhs_result = ops->inner(ops,&cp,&rhs_bin_op); 00939 result = op->fn(&lhs_result,&rhs_result); 00940 00941 if (KEEP(rhs_result) && KEEP(lhs_result)) { 00942 if (!DEL_PAREN(lhs_result) && DEL_PAREN(rhs_result) && (op != rhs_bin_op || op != lhs_bin_op)) { 00943 restore_paren(LINE_OFF(start_cut),LINE_OFF(cp)); 00944 } 00945 else if (DEL_PAREN(lhs_result) && !DEL_PAREN(rhs_result) && (op != rhs_bin_op || op != lhs_bin_op)) { 00946 restore_paren(LINE_OFF(start_lhs_cut),LINE_OFF(end_lhs_cut)); 00947 } 00948 } 00949 else { 00950 if (!KEEP(lhs_result)) { 00951 /* Cutting either operand makes parentheses superfluous*/ 00952 SET_DEL_PAREN(result); 00953 if (KEEP(rhs_result) && (op->fn == op_or || op->fn == op_and)) { 00954 cut_text(start_lhs_cut,end_lhs_cut); 00955 SET_KEEP(result); 00956 } 00957 00958 } 00959 if (!KEEP(rhs_result)) { 00960 SET_DEL_PAREN(result); 00961 if (KEEP(lhs_result) && (op->fn == op_or || op->fn == op_and)) { 00962 cut_text(start_cut,cp); 00963 SET_KEEP(result); 00964 } 00965 } 00966 } 00967 } 00968 if (DEL_PAREN(result)) { 00969 delete_paren(LINE_OFF(start_lhs_cut),LINE_OFF(end_lhs_cut));; 00970 } 00971 if (RESOLVED(result)) { 00972 debug(DBG_10, ops - eval_ops, result.value); 00973 } else { 00974 SET_KEEP(result); 00975 } 00976 } 00977 *cpp = cp; 00978 return result; 00979 } 00980 00981 static eval_result_t 00982 eval_unary(struct co_precedent_ops const *ops, char const **cpp, struct operation const **ignored) 00983 { 00984 char const *ep; 00985 eval_result_t result = EVAL_RESULT_INITOR; 00986 char const *cp; 00987 canonical_string_h symname = NULL; 00988 SET_DEL_PAREN(result); 00989 SET_PUBLIC(chew,stop_at_quote) = true; 00990 cp = chew_on(*cpp); 00991 SET_PUBLIC(chew,stop_at_quote) = false; 00992 do { 00993 00994 if (*cp == '!') { 00995 debug(DBG_1,ops - eval_ops); 00996 cp = chew_continuation(++cp); 00997 result = eval_unary(ops,&cp,NULL); 00998 if (UNRESOLVED(result)) { 00999 break; 01000 } 01001 result.value = negate(&result.value); 01002 FLIP_FLAGS(result,EVAL_RESOLVED); 01003 } else if (*cp == '~') { 01004 int_spec_t val; 01005 debug(DBG_22,ops - eval_ops); 01006 cp = chew_continuation(++cp); 01007 result = eval_unary(ops,&cp,NULL); 01008 if (UNRESOLVED(result)) { 01009 break; 01010 } 01011 val = complement(&result.value); 01012 eval_result_set_value(&result,&val); 01013 } else if (*cp == '(') { 01014 char const *start = cp; 01015 cp = chew_continuation(++cp); 01016 debug(DBG_2,ops - eval_ops); 01017 result = eval_table(eval_ops,&cp,NULL); 01018 cp = chew_on(cp); 01019 if (*cp != ')') { 01020 if (GET_STATE(evaluator,parsing_sym_def_depth) == 0) { 01021 /* Missing ')'*/ 01022 bail(GRIPE_UNBALANCED_PAREN, 01023 "Missing \")\" in \"%.*s\"", 01024 line_len(GET_PUBLIC(io,pristine_line)), 01025 GET_PUBLIC(io,pristine_line)); 01026 } else { 01027 SET_ILLEGAL(result); 01028 break; 01029 } 01030 } else if (DEL_PAREN(result)) { 01031 delete_paren(LINE_OFF(start),LINE_OFF(cp)); 01032 } 01033 cp = chew_continuation(++cp); 01034 } else if (*cp == '+') { 01035 debug(DBG_20,ops - eval_ops); 01036 cp = chew_continuation(++cp); 01037 result = eval_unary(ops,&cp,NULL); 01038 break; 01039 } else if (*cp == '-') { 01040 debug(DBG_21,ops - eval_ops); 01041 cp = chew_continuation(++cp); 01042 result = eval_unary(ops,&cp,NULL); 01043 result.value = minus(&result.value); 01044 } else if (isdigit((unsigned char)*cp)) { 01045 int_spec_t val; 01046 debug(DBG_3,ops - eval_ops); 01047 val = eval_numeral(cp,&ep); 01048 if (val.type != INT_TOO_BIG) { 01049 result.value = val; 01050 if (GET_STATE(evaluator,parsing_sym_def_depth) == 0) { 01051 SET_CONST(result); 01052 if (GET_PUBLIC(args,eval_consts)) { 01053 SET_FLAGS(result,result.value.val.ull ? EVAL_TRUE : EVAL_FALSE); 01054 } 01055 } else { 01056 SET_FLAGS(result,result.value.val.ull ? EVAL_TRUE : EVAL_FALSE); 01057 } 01058 } 01059 cp = (char *)ep; 01060 } else if (match_keyword(&cp,"defined")) { 01061 symbol_h sym; 01062 bool paren; 01063 cp = chew_on(cp); 01064 debug(DBG_4, ops - eval_ops); 01065 paren = *cp == '('; 01066 if (paren) { 01067 cp = chew_continuation(++cp); 01068 } 01069 cp = chew_on(cp); 01070 symname = canonical_identifier(&cp); 01071 sym = configured_symbol_match(canonical_string_text(symname),0); 01072 cp = chew_on(cp); 01073 if (paren) { 01074 if (*cp == ')') { 01075 cp = chew_continuation(++cp); 01076 } 01077 /* Missing ')'*/ 01078 else if (GET_STATE(evaluator,parsing_sym_def_depth) == 0) { 01079 bail(GRIPE_UNBALANCED_PAREN,NULL, 01080 "Missing \")\" in \"%.*s\"", 01081 line_len(GET_PUBLIC(io,pristine_line)), 01082 GET_PUBLIC(io,pristine_line)); 01083 } else { 01084 SET_ILLEGAL(result); 01085 break; 01086 } 01087 } 01088 if (!sym) { 01089 if (eligible_line(CMD_SYMBOLS,HASH_IF)) { 01090 unconfigured_symbol_tally(canonical_string_text(symname), 01091 canonical_string_length(symname)); 01092 } 01093 if (GET_PUBLIC(args,implicit)) { 01094 eval_result_set_value(&result,&int_spec_false); 01095 } 01096 break; 01097 } else if (eligible_line(CMD_SYMBOLS,HASH_IF)) { 01098 report_symbol(sym); 01099 } 01100 eval_result_set_value(&result,(symbol_definition(sym) != NULL) ? &int_spec_true : &int_spec_false ); 01101 } else if (*cp == '\'' || cp[0] == 'L' ) { /* Character constant */ 01102 int_spec_t val = eval_character_constant(&cp); 01103 if (val.type != INT_INSOLUBLE) { /* Got a character constant */ 01104 eval_result_set_value(&result,&val); 01105 } 01106 } else if (is_symbol_start_char(*cp)) { 01107 result = eval_possible_symbol(&cp,HASH_IF); 01108 cp = chew_on(cp); 01109 } else { 01110 SET_ILLEGAL(result); 01111 debug(DBG_6,ops - eval_ops); 01112 break; 01113 } 01114 } while(false); 01115 *cpp = cp; 01116 if (RESOLVED(result)) { 01117 debug(DBG_7,ops - eval_ops,result.value); 01118 } else { 01119 SET_KEEP(result); 01120 } 01121 canonical_string_dispose(symname); 01122 return result; 01123 } 01124 01125 01126 static int 01127 eval_if(char const **cpp) 01128 { 01129 eval_result_t result; 01130 char const *cp = *cpp; 01131 line_type_t lineval = LT_IF; 01132 debug(DBG_11, *cpp); 01133 cp = chew_on(cp); 01134 if (!*cp) { 01135 bail(GRIPE_IF_WITHOUT_COND,"#if/elif has no argument."); 01136 } 01137 result = eval_table(eval_ops,&cp,NULL); 01138 debug(DBG_12,result.value); 01139 01140 if (KEEP_CONST(result)) { 01141 lineval = LT_IF; 01142 } 01143 else if (IS_TRUE(result)) { 01144 lineval = LT_TRUE; 01145 } 01146 else if (IS_FALSE(result)) { 01147 lineval = LT_FALSE;; 01148 } 01149 *cpp = cp; 01150 return lineval; 01151 } 01152 01155 /* API **************************************************************/ 01156 01157 line_type_t 01158 eval_line(void) 01159 { 01160 char const *cp; 01161 symbol_h sym; 01162 size_t kwlen; 01163 line_type_t retval; 01164 comment_state_t wascomment; 01165 01166 if (!get_line()) { 01167 flush_contradiction(); 01168 transition(LT_EOF); 01169 return LT_EOF; 01170 } 01171 01172 SET_PUBLIC(line_edit,ops_cut) = false; 01173 SET_PUBLIC(line_edit,parens_deleted = 0); 01174 /* Assume no simplification possible*/ 01175 retval = LT_PLAIN; 01176 wascomment = GET_PUBLIC(chew,comment_state); 01177 cp = chew_on(GET_PUBLIC(io,line_start)); 01178 if (GET_PUBLIC(chew,line_state) == LS_NEUTER) { 01179 if (*cp == '#') { 01180 SET_PUBLIC(chew,line_state) = LS_DIRECTIVE; 01181 cp = chew_on(cp + 1); 01182 } else if (*cp != '\0') { 01183 SET_PUBLIC(chew,line_state) = LS_CODE; 01184 flush_contradiction(); 01185 } 01186 } 01187 if (GET_PUBLIC(chew,comment_state) == NO_COMMENT && 01188 GET_PUBLIC(chew,line_state) == LS_DIRECTIVE) { 01189 size_t kwoff = read_offset(cp); 01190 char *kwpos; 01191 directive_type_t directive; 01192 SET_PUBLIC(chew,stop_at_quote) = false; 01193 SET_PUBLIC(chew,must_balance_quotes) = true; 01194 SET_STATE(evaluator,parsing_sym_def_depth) = 0; 01195 kwpos = read_pos(kwoff); 01196 SET_PUBLIC(line_edit,keyword) = kwpos; 01197 directive = get_directive_type(&cp); 01198 kwlen = cp - kwpos; 01199 SET_PUBLIC(line_select,dropping_line) = dropping_line(); 01200 switch(directive) { 01201 case HASH_IF: 01202 SET_STATE(evaluator,ifpos) = cp; 01203 retval = eval_if(&cp); 01204 break; 01205 case HASH_IFDEF: 01206 case HASH_IFNDEF: { 01207 canonical_string_h symname = NULL; 01208 cp = chew_on(cp); 01209 symname = canonical_identifier(&cp); 01210 sym = configured_symbol_match(canonical_string_text(symname),0); 01211 retval = LT_IF; 01212 if (sym) { 01213 if (eligible_line(CMD_SYMBOLS,directive)) { 01214 report_symbol(sym); 01215 } 01216 if (symbol_definition(sym)) { 01217 /* symbol is -Ded*/ 01218 retval = directive == HASH_IFDEF ? LT_TRUE : LT_FALSE; 01219 } else { 01220 /* symbol is -Ued*/ 01221 retval = directive == HASH_IFNDEF ? LT_TRUE : LT_FALSE; 01222 } 01223 } else { 01224 if (eligible_line(CMD_SYMBOLS,directive)) { 01225 unconfigured_symbol_tally(canonical_string_text(symname), 01226 canonical_string_length(symname)); 01227 } 01228 if (GET_PUBLIC(args,implicit)) { 01229 retval = directive == HASH_IFDEF ? LT_FALSE : LT_TRUE; 01230 } 01231 } 01232 canonical_string_dispose(symname); 01233 } 01234 break; 01235 case HASH_ELSE: 01236 retval = LT_ELSE; 01237 break; 01238 case HASH_ELIF: 01239 retval = eval_if(&cp) - LT_IF + LT_ELIF; 01240 break; 01241 case HASH_ENDIF: 01242 retval = LT_ENDIF; 01243 break; 01244 case HASH_DEFINE: 01245 retval = eval_hash_define(&cp); 01246 break; 01247 case HASH_UNDEF: 01248 retval = eval_hash_undef(&cp); 01249 break; 01250 case HASH_INCLUDE: 01251 retval = eval_hash_include(&cp); 01252 break; 01253 case HASH_PRAGMA: 01254 SET_PUBLIC(chew,must_balance_quotes) = false; 01255 if (eligible_line(CMD_PRAGMAS,HASH_PRAGMA)) { 01256 cp = eval_free_form_directive(cp,HASH_PRAGMA); 01257 } 01258 break; 01259 case HASH_ERROR: 01260 SET_PUBLIC(chew,must_balance_quotes) = false; 01261 if (eligible_line(CMD_ERRORS,HASH_ERROR)) { 01262 cp = eval_free_form_directive(cp,HASH_ERROR); 01263 } 01264 if (!GET_PUBLIC(line_select,dropping_line)) { 01265 SET_PUBLIC(chew,last_comment_start_line) = 01266 GET_PUBLIC(io,line_num); 01267 if (is_unconditional_line()) { 01268 set_exit_flags(EVENT_SUMMARY_ERROR_OUTPUT,true); 01269 if (was_unconditional_line()) { 01270 report(GRIPE_UNCONDITIONAL_ERROR_INPUT,NULL, 01271 "An unconditional #error directive was input"); 01272 } else { 01273 report(GRIPE_UNCONDITIONAL_ERROR_INPUT,NULL, 01274 "An unconditional #error directive becomes operative"); 01275 } 01276 } 01277 } 01278 break; 01279 default: 01280 report(GRIPE_UNKNOWN_DIRECTIVE,NULL,"Unknown directive #%.*s", 01281 kwlen,kwpos); 01282 SET_PUBLIC(chew,line_state) = LS_CODE; 01283 retval = LT_PLAIN; 01284 }; 01285 cp = chew_on(cp); 01286 if (*cp) { 01287 SET_PUBLIC(chew,line_state) = LS_CODE; 01288 if (retval != LT_PLAIN) { 01289 if (*cp == ')') { 01290 bail(GRIPE_UNBALANCED_PAREN, 01291 "Missing \"(\" in \"%.*s\"", 01292 line_len(GET_PUBLIC(io,pristine_line)), 01293 GET_PUBLIC(io,pristine_line)); 01294 } else { 01295 report(GRIPE_GARBAGE_AFTER_DIRECTIVE,NULL, 01296 "Garbage following preprocessor directive in \"%.*s\"", 01297 line_len(GET_PUBLIC(io,pristine_line)), 01298 GET_PUBLIC(io,pristine_line)); 01299 } 01300 } 01301 } 01302 if (GET_PUBLIC(line_select,dropping_line)) { 01303 forget_contradiction(); 01304 } 01305 else if (directive != HASH_UNDEF) { 01306 flush_contradiction(); 01307 } 01308 } 01309 if (retval == LT_DIRECTIVE_KEEP) { 01310 /* A non-if directive is the same as a non-directive for if-control */ 01311 retval = LT_PLAIN; 01312 } 01313 if (GET_PUBLIC(chew,line_state) == LS_CODE) { 01314 while (*cp != '\0') { 01315 cp = chew_on(cp + 1); 01316 } 01317 } 01318 debug(DBG_17); 01319 return (retval); 01320 } 01321 01322 eval_result_t 01323 eval_definition_text(char const **pdef) 01324 { 01325 eval_result_t er; 01326 ++SET_STATE(evaluator,parsing_sym_def_depth); 01327 SET_PUBLIC(chew,in_source) = false; 01328 er = eval_table(eval_ops,pdef,NULL); 01329 SET_PUBLIC(chew,in_source) = true; 01330 /* Forget any unclosed quotation in symbol definition */ 01331 SET_PUBLIC(chew,in_double_quote) = false; 01332 --SET_STATE(evaluator,parsing_sym_def_depth); 01333 return er; 01334 } 01335 01336 /* EOF*/