coan 4.2.4
evaluator.c
Go to the documentation of this file.
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*/
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines