00001 /* 00002 * I.h - support for invariants (assertions) using C code. 00003 * 00004 * Copyright (c) 1997 Phil Maker 00005 * All rights reserved. 00006 * 00007 * Redistribution and use in source and binary forms, with or without 00008 * modification, are permitted provided that the following conditions 00009 * are met: 00010 * 1. Redistributions of source code must retain the above copyright 00011 * notice, this list of conditions and the following disclaimer. 00012 * 2. Redistributions in binary form must reproduce the above copyright 00013 * notice, this list of conditions and the following disclaimer in the 00014 * documentation and/or other materials provided with the distribution. 00015 * 00016 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 00017 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00018 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00019 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 00020 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00021 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00022 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00023 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00024 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00025 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00026 * SUCH DAMAGE. 00027 * 00028 * Id: I.h,v 1.1.1.1 1997/11/23 11:45:50 pjm Exp 00029 */ 00030 00031 #ifndef _I_h_ 00032 #define _I_h_ 1 00033 00034 #ifdef __cplusplus 00035 extern "C" { 00036 #endif 00037 00038 #ifndef WITHOUT_NANA 00039 00040 /* 00041 * nana-config.h - the system wide configuration file; we put the ifndef 00042 * around it to avoid the file 5 million times during a compile. 00043 */ 00044 00045 #ifndef _nana_config_h_ 00046 #include <nana-config.h> 00047 #endif 00048 00049 /* 00050 * I_LEVEL sets the level of invariant analogously to NDEBUG in assert.h 00051 * 00052 * I_LEVEL == 2: invariants are always evaluated. 00053 * I_LEVEL == 1: evaluate invariants iff they have a true GUARD. 00054 * I_LEVEL == 0: invariants are never evaluated. 00055 */ 00056 00057 #ifndef I_LEVEL /* define DEFAULT for I_LEVEL */ 00058 #define I_LEVEL 1 00059 #endif 00060 00061 00062 /* 00063 * I_DEFAULT_GUARD - the default guard expression; an invariant is checked 00064 * iff the guard is true. By default its always true. 00065 */ 00066 00067 #ifndef I_DEFAULT_GUARD 00068 #define I_DEFAULT_GUARD 1 00069 #endif 00070 00071 /* 00072 * I_DEFAULT_PARAMS - the default value to be passed as the second argument 00073 * to the handler macro when an invariant fails. 00074 */ 00075 00076 00077 #ifndef I_DEFAULT_PARAMS 00078 #define I_DEFAULT_PARAMS 0 /* nothing */ 00079 #endif 00080 00081 /* 00082 * I_DEFAULT_HANDLER(expr,file,line,param) - called when an error is detected. 00083 */ 00084 00085 #ifndef I_DEFAULT_HANDLER /* define default handler */ 00086 #define I_DEFAULT_HANDLER _I_default_handler 00087 00088 void _I_default_handler(char *expr, char *file, int line, void *parm); 00089 #endif /* I_DEFAULT_HANDLER */ 00090 00091 /* 00092 * _IGHPS(e,g,h,p,s) - implements the general case for invariant handling. 00093 * 00094 * e - expression to check 00095 * g - guard, check only if this is true (subject to I_DEFAULT_LEVEL) 00096 * h - handler, called when a failure is detected 00097 * p - parameter to pass off to the handler 00098 * s - string representation of the expression (e.g. "I(x>=i)") 00099 * 00100 * _ISD(e) - generates a data declaration for use in postconditions 00101 * _ISG(e,g) - generates a guarded assignment to a data declaration 00102 * for use in postconditions 00103 * 00104 * N.B. The two types are necessary since we cannot guard a C declaration 00105 * with an if statement. 00106 */ 00107 00108 00109 #if I_LEVEL == 2 /* always check the assertion */ 00110 #define _IGHPS(e,g,h,p,s) \ 00111 do { \ 00112 if(!(e)) { \ 00113 h (s, __FILE__, __LINE__, p); \ 00114 } \ 00115 } while(0) 00116 00117 #define _ID(e) e 00118 #define _ISG(e,g) e 00119 #elif I_LEVEL == 1 /* check it iff g is true */ 00120 00121 00122 inline void _IGHPS(bool e, bool g, void (*h)(char *expr, char *file, int line, void *parm), char *p, char *s) 00123 { 00124 if (g && !e) 00125 (*h)(s, __FILE__, __LINE__, p); 00126 } 00127 00128 #define _ID(e) e 00129 #define _ISG(e,g) \ 00130 do { \ 00131 if(g) { \ 00132 e; \ 00133 } \ 00134 } while(0) 00135 #elif I_LEVEL == 0 /* no assertions so just remove them */ 00136 #define _IGHPS(e,g,h,p,s) /* nothing */ 00137 #define _ID(e) /* nothing */ 00138 #define _ISG(e,g) /* nothing */ 00139 #endif /* I_LEVEL */ 00140 00141 /* 00142 * And all the user macros; these are used to put in the default arguments. 00143 * The name is used to determine the arguments; e.g. IGH takes an expression 00144 * to check; a guard and a handler as parameters. The letters in the names 00145 * are in ascending order (i.e. IGH(...) not IHG(...)). 00146 * 00147 * I[G][H][P] - it must be true (e) with an optional guard, handler and 00148 * parameter for the handler. 00149 * N[G][H][P] - as for I... except that (e) must never ever be true. 00150 */ 00151 00152 #define INVARIANT(e) \ 00153 _IGHPS(e,I_DEFAULT_GUARD,I_DEFAULT_HANDLER,I_DEFAULT_PARAMS,"I("#e")") 00154 #define IG(e,g) \ 00155 _IGHPS(e,g,I_DEFAULT_HANDLER,I_DEFAULT_PARAMS,"I("#e")") 00156 #define IH(e,h) \ 00157 _IGHPS(e,I_DEFAULT_GUARD,h,I_DEFAULT_PARAMS,"I("#e")") 00158 #define IP(e,p) \ 00159 _IGHPS(e,I_DEFAULT_GUARD,I_DEFAULT_HANDLER,p,"I("#e")") 00160 #define IGH(e,g,h) \ 00161 _IGHPS(e,g,h,I_DEFAULT_PARAMS,"I("#e")") 00162 #define IGP(e,g,p) \ 00163 _IGHPS(e,g,I_DEFAULT_HANDLER,p,"I("#e")") 00164 #define IHP(e,h,p) \ 00165 _IGHPS(e,I_DEFAULT_GUARD,h,p,"I("#e")") 00166 #define IGHP(e,g,h,p) \ 00167 _IGHPS(e,g,h,p,"I("#e")") 00168 00169 #define N(e) \ 00170 _IGHPS((!(e)),I_DEFAULT_GUARD,I_DEFAULT_HANDLER,I_DEFAULT_PARAMS,"N("#e")") 00171 #define NG(e,g) \ 00172 _IGHPS((!(e)),g,I_DEFAULT_HANDLER,I_DEFAULT_PARAMS,"N("#e")") 00173 #define NH(e,h) \ 00174 _IGHPS((!(e)),I_DEFAULT_GUARD,h,I_DEFAULT_PARAMS,"N("#e")") 00175 #define NP(e,p) \ 00176 _IGHPS((!(e)),I_DEFAULT_GUARD,I_DEFAULT_HANDLER,p,"N("#e")") 00177 #define NGH(e,g,h) \ 00178 _IGHPS((!(e)),g,h,I_DEFAULT_PARAMS,"N("#e")") 00179 #define NGP(e,g,p) \ 00180 _IGHPS((!(e)),g,I_DEFAULT_HANDLER,p,"N("#e")") 00181 #define NHP(e,h,p) \ 00182 _IGHPS((!(e)),I_DEFAULT_GUARD,h,p,"N("#e")") 00183 #define NGHP(e,g,h,p) \ 00184 _IGHPS((!(e)),g,h,p,"N("#e")") 00185 00186 /* 00187 * ID(e) - declares a variable to be used to store values for a postcondition. 00188 * This can include an initialiser. 00189 * Note this declaration is not disabled by I_DEFAULT_GUARD 00190 * IS(e) - an assignment to a variable. This statement is enabled by 00191 * I_DEFAULT_GUARD 00192 * ISG(e,g) - the guarded version of IS 00193 */ 00194 00195 #define ID(e) _ID(e) 00196 #define IS(e) _ISG(e,I_DEFAULT_GUARD) 00197 #define ISG(e,g) _ISG(e,g) 00198 00199 #else /* defined(WITHOUT_NANA) */ 00200 00201 #define I(e) /* empty */ 00202 #define IG(e,g) /* empty */ 00203 #define IH(e,h) /* empty */ 00204 #define IP(e,p) /* empty */ 00205 #define IGH(e,g,h) /* empty */ 00206 #define IGP(e,g,p) /* empty */ 00207 #define IHP(e,h,p) /* empty */ 00208 #define IGHP(e,g,h,p) /* empty */ 00209 00210 #define N(e) /* empty */ 00211 #define NG(e,g) /* empty */ 00212 #define NH(e,h) /* empty */ 00213 #define NP(e,p) /* empty */ 00214 #define NGH(e,g,h) /* empty */ 00215 #define NGP(e,g,p) /* empty */ 00216 #define NHP(e,h,p) /* empty */ 00217 #define NGHP(e,g,h,p) /* empty */ 00218 00219 #define ID(e) /* empty */ 00220 #define IS(e) /* empty */ 00221 #define ISG(e,g) /* empty */ 00222 00223 #endif /* !defined(WITHOUT_NANA) */ 00224 00225 #ifdef __cplusplus 00226 } 00227 #endif 00228 00229 #endif /* _I_h_ */ 00230 00231 00232
1.3.4