1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <time.h> 26 #include <stdarg.h> 27 #include "cpp.h" 28 29 #define OUTS 16384 30 char outbuf[OUTS]; 31 char *outptr = outbuf; 32 Source *cursource; 33 int nerrs; 34 struct token nltoken = {NL, 0, 0, 1, (uchar *) "\n", 0}; 35 char *curtime; 36 int incdepth; 37 int ifdepth; 38 int ifsatisfied[NIF]; 39 int skipping; 40 41 char rcsid[] = "$Version 1.2 $ $Revision: 1.5 $ $Date: 2006-06-20 05:05:46 $"; 42 43 int 44 #ifdef _WIN32 45 __cdecl 46 #endif // _WIN32 47 main(int argc, char **argv) 48 { 49 50 Tokenrow tr; 51 time_t t; 52 char ebuf[BUFSIZ]; 53 54 setbuf(stderr, ebuf); 55 t = time(NULL); 56 curtime = ctime(&t); 57 maketokenrow(3, &tr); 58 expandlex(); 59 setup(argc, argv); 60 fixlex(); 61 if (!Pflag) 62 genline(); 63 process(&tr); 64 flushout(); 65 fflush(stderr); 66 exit(nerrs > 0); 67 } 68 69 void 70 process(Tokenrow * trp) 71 { 72 int anymacros = 0; 73 74 for (;;) 75 { 76 if (trp->tp >= trp->lp) 77 { 78 trp->tp = trp->lp = trp->bp; 79 outptr = outbuf; 80 anymacros |= gettokens(trp, 1); 81 trp->tp = trp->bp; 82 } 83 if (trp->tp->type == END) 84 { 85 if (--incdepth >= 0) 86 { 87 if (cursource->ifdepth) 88 error(ERROR, 89 "Unterminated conditional in #include"); 90 unsetsource(); 91 cursource->line += cursource->lineinc; 92 trp->tp = trp->lp; 93 if (!Pflag) 94 genline(); 95 continue; 96 } 97 if (ifdepth) 98 error(ERROR, "Unterminated #if/#ifdef/#ifndef"); 99 break; 100 } 101 if (trp->tp->type == SHARP) 102 { 103 trp->tp += 1; 104 control(trp); 105 } 106 else 107 if (!skipping && anymacros) 108 expandrow(trp, NULL); 109 if (skipping) 110 setempty(trp); 111 puttokens(trp); 112 anymacros = 0; 113 cursource->line += cursource->lineinc; 114 if (cursource->lineinc > 1) 115 { 116 if (!Pflag) 117 genline(); 118 } 119 } 120 } 121 122 void 123 control(Tokenrow * trp) 124 { 125 Nlist *np; 126 Token *tp; 127 128 tp = trp->tp; 129 if (tp->type != NAME) 130 { 131 if (tp->type == NUMBER) 132 goto kline; 133 if (tp->type != NL) 134 error(ERROR, "Unidentifiable control line"); 135 return; /* else empty line */ 136 } 137 if ((np = lookup(tp, 0)) == NULL || ((np->flag & ISKW) == 0 && !skipping)) 138 { 139 error(WARNING, "Unknown preprocessor control %t", tp); 140 return; 141 } 142 if (skipping) 143 { 144 switch (np->val) 145 { 146 case KENDIF: 147 if (--ifdepth < skipping) 148 skipping = 0; 149 --cursource->ifdepth; 150 setempty(trp); 151 return; 152 153 case KIFDEF: 154 case KIFNDEF: 155 case KIF: 156 if (++ifdepth >= NIF) 157 error(FATAL, "#if too deeply nested"); 158 ++cursource->ifdepth; 159 return; 160 161 case KELIF: 162 case KELSE: 163 if (ifdepth <= skipping) 164 break; 165 return; 166 167 default: 168 return; 169 } 170 } 171 switch (np->val) 172 { 173 case KDEFINE: 174 dodefine(trp); 175 break; 176 177 case KUNDEF: 178 tp += 1; 179 if (tp->type != NAME || trp->lp - trp->bp != 4) 180 { 181 error(ERROR, "Syntax error in #undef"); 182 break; 183 } 184 if ((np = lookup(tp, 0)) != NULL) 185 { 186 np->flag &= ~ISDEFINED; 187 188 if (Mflag) 189 { 190 if (np->ap) 191 error(INFO, "Macro deletion of %s(%r)", np->name, np->ap); 192 else 193 error(INFO, "Macro deletion of %s", np->name); 194 } 195 } 196 break; 197 198 case KPRAGMA: 199 case KIDENT: 200 for (tp = trp->tp - 1; ((tp->type != NL) && (tp < trp->lp)); tp++) 201 tp->type = UNCLASS; 202 return; 203 204 case KIFDEF: 205 case KIFNDEF: 206 case KIF: 207 if (++ifdepth >= NIF) 208 error(FATAL, "#if too deeply nested"); 209 ++cursource->ifdepth; 210 ifsatisfied[ifdepth] = 0; 211 if (eval(trp, np->val)) 212 ifsatisfied[ifdepth] = 1; 213 else 214 skipping = ifdepth; 215 break; 216 217 case KELIF: 218 if (ifdepth == 0) 219 { 220 error(ERROR, "#elif with no #if"); 221 return; 222 } 223 if (ifsatisfied[ifdepth] == 2) 224 error(ERROR, "#elif after #else"); 225 if (eval(trp, np->val)) 226 { 227 if (ifsatisfied[ifdepth]) 228 skipping = ifdepth; 229 else 230 { 231 skipping = 0; 232 ifsatisfied[ifdepth] = 1; 233 } 234 } 235 else 236 skipping = ifdepth; 237 break; 238 239 case KELSE: 240 if (ifdepth == 0 || cursource->ifdepth == 0) 241 { 242 error(ERROR, "#else with no #if"); 243 return; 244 } 245 if (ifsatisfied[ifdepth] == 2) 246 error(ERROR, "#else after #else"); 247 if (trp->lp - trp->bp != 3) 248 error(ERROR, "Syntax error in #else"); 249 skipping = ifsatisfied[ifdepth] ? ifdepth : 0; 250 ifsatisfied[ifdepth] = 2; 251 break; 252 253 case KENDIF: 254 if (ifdepth == 0 || cursource->ifdepth == 0) 255 { 256 error(ERROR, "#endif with no #if"); 257 return; 258 } 259 --ifdepth; 260 --cursource->ifdepth; 261 if (trp->lp - trp->bp != 3) 262 error(WARNING, "Syntax error in #endif"); 263 break; 264 265 case KERROR: 266 trp->tp = tp + 1; 267 error(WARNING, "#error directive: %r", trp); 268 break; 269 270 case KLINE: 271 trp->tp = tp + 1; 272 expandrow(trp, "<line>"); 273 tp = trp->bp + 2; 274 kline: 275 if (tp + 1 >= trp->lp || tp->type != NUMBER || tp + 3 < trp->lp 276 || (tp + 3 == trp->lp 277 && ((tp + 1)->type != STRING || *(tp + 1)->t == 'L'))) 278 { 279 error(ERROR, "Syntax error in #line"); 280 return; 281 } 282 cursource->line = atol((char *) tp->t) - 1; 283 if (cursource->line < 0 || cursource->line >= 32768) 284 error(WARNING, "#line specifies number out of range"); 285 tp = tp + 1; 286 if (tp + 1 < trp->lp) 287 cursource->filename = (char *) newstring(tp->t + 1, tp->len - 2, 0); 288 return; 289 290 case KDEFINED: 291 error(ERROR, "Bad syntax for control line"); 292 break; 293 294 case KIMPORT: 295 doinclude(trp, -1, 1); 296 trp->lp = trp->bp; 297 return; 298 299 case KINCLUDE: 300 doinclude(trp, -1, 0); 301 trp->lp = trp->bp; 302 return; 303 304 case KINCLUDENEXT: 305 doinclude(trp, cursource->pathdepth, 0); 306 trp->lp = trp->bp; 307 return; 308 309 case KEVAL: 310 eval(trp, np->val); 311 break; 312 313 default: 314 error(ERROR, "Preprocessor control `%t' not yet implemented", tp); 315 break; 316 } 317 setempty(trp); 318 return; 319 } 320 321 void * 322 domalloc(int size) 323 { 324 void *p = malloc(size); 325 326 if (p == NULL) 327 error(FATAL, "Out of memory from malloc"); 328 return p; 329 } 330 331 void 332 dofree(void *p) 333 { 334 free(p); 335 } 336 337 void 338 error(enum errtype type, char *string,...) 339 { 340 va_list ap; 341 char c, *cp, *ep; 342 Token *tp; 343 Tokenrow *trp; 344 Source *s; 345 int i; 346 347 fprintf(stderr, "cpp: "); 348 for (s = cursource; s; s = s->next) 349 if (*s->filename) 350 fprintf(stderr, "%s:%d ", s->filename, s->line); 351 va_start(ap, string); 352 for (ep = string; *ep; ep++) 353 { 354 if (*ep == '%') 355 { 356 switch (*++ep) 357 { 358 359 case 'c': 360 c = (char) va_arg(ap, int); 361 fprintf(stderr, "%c", c); 362 break; 363 364 case 's': 365 cp = va_arg(ap, char *); 366 fprintf(stderr, "%s", cp); 367 break; 368 369 case 'd': 370 i = va_arg(ap, int); 371 fprintf(stderr, "%d", i); 372 break; 373 374 case 't': 375 tp = va_arg(ap, Token *); 376 fprintf(stderr, "%.*s", (int)tp->len, tp->t); 377 break; 378 379 case 'r': 380 trp = va_arg(ap, Tokenrow *); 381 for (tp = trp->tp; tp < trp->lp && tp->type != NL; tp++) 382 { 383 if (tp > trp->tp && tp->wslen) 384 fputc(' ', stderr); 385 fprintf(stderr, "%.*s", (int)tp->len, tp->t); 386 } 387 break; 388 389 default: 390 fputc(*ep, stderr); 391 break; 392 } 393 } 394 else 395 fputc(*ep, stderr); 396 } 397 va_end(ap); 398 fputc('\n', stderr); 399 if (type == FATAL) 400 exit(1); 401 if (type != WARNING) 402 nerrs = 1; 403 fflush(stderr); 404 } 405