1 1.1 dholland /*- 2 1.1 dholland * Copyright (c) 2010, 2013 The NetBSD Foundation, Inc. 3 1.1 dholland * All rights reserved. 4 1.1 dholland * 5 1.1 dholland * This code is derived from software contributed to The NetBSD Foundation 6 1.1 dholland * by David A. Holland. 7 1.1 dholland * 8 1.1 dholland * Redistribution and use in source and binary forms, with or without 9 1.1 dholland * modification, are permitted provided that the following conditions 10 1.1 dholland * are met: 11 1.1 dholland * 1. Redistributions of source code must retain the above copyright 12 1.1 dholland * notice, this list of conditions and the following disclaimer. 13 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 dholland * notice, this list of conditions and the following disclaimer in the 15 1.1 dholland * documentation and/or other materials provided with the distribution. 16 1.1 dholland * 17 1.1 dholland * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 1.1 dholland * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 1.1 dholland * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 1.1 dholland * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 1.1 dholland * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 1.1 dholland * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 1.1 dholland * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 1.1 dholland * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 1.1 dholland * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 1.1 dholland * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 1.1 dholland * POSSIBILITY OF SUCH DAMAGE. 28 1.1 dholland */ 29 1.1 dholland 30 1.1 dholland #include <stdint.h> 31 1.1 dholland #include <stdio.h> 32 1.1 dholland #include <stdlib.h> 33 1.1 dholland #include <string.h> 34 1.1 dholland 35 1.1 dholland #include "union.h" 36 1.1 dholland #include "array.h" 37 1.1 dholland #include "mode.h" 38 1.1 dholland #include "place.h" 39 1.1 dholland #include "macro.h" 40 1.1 dholland #include "output.h" 41 1.1 dholland 42 1.1 dholland struct expansionitem { 43 1.1 dholland enum { EI_STRING, EI_PARAM, EI_FILE, EI_LINE } itemtype; 44 1.1 dholland union { 45 1.1 dholland char *ei_string; /* for EI_STRING */ 46 1.1 dholland unsigned ei_param; /* for EI_PARAM */ 47 1.1 dholland } UN; 48 1.1 dholland }; 49 1.1 dholland DECLARRAY(expansionitem, static UNUSED); 50 1.1 dholland DEFARRAY(expansionitem, static); 51 1.1 dholland 52 1.1 dholland #ifdef NEED_UNION_ACCESSORS 53 1.1 dholland #define ei_string un.ei_string 54 1.1 dholland #define ei_param un.ei_param 55 1.1 dholland #endif 56 1.1 dholland 57 1.1 dholland 58 1.1 dholland struct macro { 59 1.1 dholland struct place defplace; 60 1.1 dholland struct place expansionplace; 61 1.1 dholland unsigned hash; 62 1.1 dholland char *name; 63 1.1 dholland bool hasparams; 64 1.1 dholland struct stringarray params; 65 1.1 dholland struct expansionitemarray expansion; 66 1.1 dholland bool inuse; 67 1.1 dholland }; 68 1.1 dholland DECLARRAY(macro, static UNUSED); 69 1.1 dholland DEFARRAY(macro, static); 70 1.1 dholland DECLARRAY(macroarray, static UNUSED); 71 1.1 dholland DEFARRAY(macroarray, static); 72 1.1 dholland 73 1.1 dholland static struct macroarrayarray macros; 74 1.1 dholland static unsigned total_macros; 75 1.1 dholland static unsigned hashmask; 76 1.1 dholland 77 1.1 dholland //////////////////////////////////////////////////////////// 78 1.1 dholland // macro structure ops 79 1.1 dholland 80 1.1 dholland static 81 1.1 dholland struct expansionitem * 82 1.1 dholland expansionitem_create_string(const char *string) 83 1.1 dholland { 84 1.1 dholland struct expansionitem *ei; 85 1.1 dholland 86 1.1 dholland ei = domalloc(sizeof(*ei)); 87 1.1 dholland ei->itemtype = EI_STRING; 88 1.1 dholland ei->ei_string = dostrdup(string); 89 1.1 dholland return ei; 90 1.1 dholland } 91 1.1 dholland 92 1.1 dholland static 93 1.1 dholland struct expansionitem * 94 1.1 dholland expansionitem_create_stringlen(const char *string, size_t len) 95 1.1 dholland { 96 1.1 dholland struct expansionitem *ei; 97 1.1 dholland 98 1.1 dholland ei = domalloc(sizeof(*ei)); 99 1.1 dholland ei->itemtype = EI_STRING; 100 1.1 dholland ei->ei_string = dostrndup(string, len); 101 1.1 dholland return ei; 102 1.1 dholland } 103 1.1 dholland 104 1.1 dholland static 105 1.1 dholland struct expansionitem * 106 1.1 dholland expansionitem_create_param(unsigned param) 107 1.1 dholland { 108 1.1 dholland struct expansionitem *ei; 109 1.1 dholland 110 1.1 dholland ei = domalloc(sizeof(*ei)); 111 1.1 dholland ei->itemtype = EI_PARAM; 112 1.1 dholland ei->ei_param = param; 113 1.1 dholland return ei; 114 1.1 dholland } 115 1.1 dholland 116 1.1 dholland static 117 1.1 dholland struct expansionitem * 118 1.1 dholland expansionitem_create_file(void) 119 1.1 dholland { 120 1.1 dholland struct expansionitem *ei; 121 1.1 dholland 122 1.1 dholland ei = domalloc(sizeof(*ei)); 123 1.1 dholland ei->itemtype = EI_FILE; 124 1.1 dholland return ei; 125 1.1 dholland } 126 1.1 dholland 127 1.1 dholland static 128 1.1 dholland struct expansionitem * 129 1.1 dholland expansionitem_create_line(void) 130 1.1 dholland { 131 1.1 dholland struct expansionitem *ei; 132 1.1 dholland 133 1.1 dholland ei = domalloc(sizeof(*ei)); 134 1.1 dholland ei->itemtype = EI_LINE; 135 1.1 dholland return ei; 136 1.1 dholland } 137 1.1 dholland 138 1.1 dholland static 139 1.1 dholland void 140 1.1 dholland expansionitem_destroy(struct expansionitem *ei) 141 1.1 dholland { 142 1.1 dholland switch (ei->itemtype) { 143 1.1 dholland case EI_STRING: 144 1.1 dholland dostrfree(ei->ei_string); 145 1.1 dholland break; 146 1.1 dholland case EI_PARAM: 147 1.1 dholland case EI_FILE: 148 1.1 dholland case EI_LINE: 149 1.1 dholland break; 150 1.1 dholland } 151 1.1 dholland dofree(ei, sizeof(*ei)); 152 1.1 dholland } 153 1.1 dholland 154 1.1 dholland static 155 1.1 dholland bool 156 1.1 dholland expansionitem_eq(const struct expansionitem *ei1, 157 1.1 dholland const struct expansionitem *ei2) 158 1.1 dholland { 159 1.1 dholland if (ei1->itemtype != ei2->itemtype) { 160 1.1 dholland return false; 161 1.1 dholland } 162 1.1 dholland switch (ei1->itemtype) { 163 1.1 dholland case EI_STRING: 164 1.1 dholland if (strcmp(ei1->ei_string, ei2->ei_string) != 0) { 165 1.1 dholland return false; 166 1.1 dholland } 167 1.1 dholland break; 168 1.1 dholland case EI_PARAM: 169 1.1 dholland if (ei1->ei_param != ei2->ei_param) { 170 1.1 dholland return false; 171 1.1 dholland } 172 1.1 dholland break; 173 1.1 dholland case EI_FILE: 174 1.1 dholland case EI_LINE: 175 1.1 dholland break; 176 1.1 dholland } 177 1.1 dholland return true; 178 1.1 dholland } 179 1.1 dholland 180 1.1 dholland static 181 1.1 dholland struct macro * 182 1.1 dholland macro_create(struct place *p1, const char *name, unsigned hash, 183 1.1 dholland struct place *p2) 184 1.1 dholland { 185 1.1 dholland struct macro *m; 186 1.1 dholland 187 1.1 dholland m = domalloc(sizeof(*m)); 188 1.1 dholland m->defplace = *p1; 189 1.1 dholland m->expansionplace = *p2; 190 1.1 dholland m->hash = hash; 191 1.1 dholland m->name = dostrdup(name); 192 1.1 dholland m->hasparams = false; 193 1.1 dholland stringarray_init(&m->params); 194 1.1 dholland expansionitemarray_init(&m->expansion); 195 1.1 dholland m->inuse = false; 196 1.1 dholland return m; 197 1.1 dholland } 198 1.1 dholland 199 1.1 dholland DESTROYALL_ARRAY(expansionitem, ); 200 1.1 dholland 201 1.1 dholland static 202 1.1 dholland void 203 1.1 dholland macro_destroy(struct macro *m) 204 1.1 dholland { 205 1.1 dholland expansionitemarray_destroyall(&m->expansion); 206 1.1 dholland expansionitemarray_cleanup(&m->expansion); 207 1.1 dholland dostrfree(m->name); 208 1.1 dholland dofree(m, sizeof(*m)); 209 1.1 dholland } 210 1.1 dholland 211 1.1 dholland static 212 1.1 dholland bool 213 1.1 dholland macro_eq(const struct macro *m1, const struct macro *m2) 214 1.1 dholland { 215 1.1 dholland unsigned num1, num2, i; 216 1.1 dholland struct expansionitem *ei1, *ei2; 217 1.1 dholland const char *p1, *p2; 218 1.1 dholland 219 1.1 dholland if (strcmp(m1->name, m2->name) != 0) { 220 1.1 dholland return false; 221 1.1 dholland } 222 1.1 dholland 223 1.1 dholland if (m1->hasparams != m2->hasparams) { 224 1.1 dholland return false; 225 1.1 dholland } 226 1.1 dholland 227 1.1 dholland num1 = expansionitemarray_num(&m1->expansion); 228 1.1 dholland num2 = expansionitemarray_num(&m2->expansion); 229 1.1 dholland if (num1 != num2) { 230 1.1 dholland return false; 231 1.1 dholland } 232 1.1 dholland 233 1.1 dholland for (i=0; i<num1; i++) { 234 1.1 dholland ei1 = expansionitemarray_get(&m1->expansion, i); 235 1.1 dholland ei2 = expansionitemarray_get(&m2->expansion, i); 236 1.1 dholland if (!expansionitem_eq(ei1, ei2)) { 237 1.1 dholland return false; 238 1.1 dholland } 239 1.1 dholland } 240 1.1 dholland 241 1.1 dholland num1 = stringarray_num(&m1->params); 242 1.1 dholland num2 = stringarray_num(&m2->params); 243 1.1 dholland if (num1 != num2) { 244 1.1 dholland return false; 245 1.1 dholland } 246 1.1 dholland 247 1.1 dholland for (i=0; i<num1; i++) { 248 1.1 dholland p1 = stringarray_get(&m1->params, i); 249 1.1 dholland p2 = stringarray_get(&m2->params, i); 250 1.1 dholland if (strcmp(p1, p2) != 0) { 251 1.1 dholland return false; 252 1.1 dholland } 253 1.1 dholland } 254 1.1 dholland return true; 255 1.1 dholland } 256 1.1 dholland 257 1.1 dholland //////////////////////////////////////////////////////////// 258 1.1 dholland // macro table 259 1.1 dholland 260 1.1 dholland /* 261 1.1 dholland * Unless I've screwed up, this is something called Fletcher's Checksum 262 1.1 dholland * that showed up in Dr. Dobbs in, according to my notes, May 1992. The 263 1.1 dholland * implementation is new. 264 1.1 dholland */ 265 1.1 dholland static 266 1.1 dholland unsigned 267 1.1 dholland hashfunc(const char *s, size_t len) 268 1.1 dholland { 269 1.1 dholland uint16_t x1, x2, a; 270 1.1 dholland size_t i; 271 1.1 dholland 272 1.1 dholland x1 = (uint16_t) (len >> 16); 273 1.1 dholland x2 = (uint16_t) (len); 274 1.1 dholland if (x1==0) { 275 1.1 dholland x1++; 276 1.1 dholland } 277 1.1 dholland if (x2==0) { 278 1.1 dholland x2++; 279 1.1 dholland } 280 1.1 dholland 281 1.1 dholland for (i=0; i<len; i+=2) { 282 1.1 dholland if (i==len-1) { 283 1.1 dholland a = (unsigned char)s[i]; 284 1.1 dholland /* don't run off the end of the array */ 285 1.1 dholland } 286 1.1 dholland else { 287 1.1 dholland a = (unsigned char)s[i] + 288 1.1 dholland ((uint16_t)(unsigned char)s[i+1] << 8); 289 1.1 dholland } 290 1.1 dholland x1 += a; 291 1.1 dholland if (x1 < a) { 292 1.1 dholland x1++; 293 1.1 dholland } 294 1.1 dholland x2 += x1; 295 1.1 dholland if (x2 < x1) { 296 1.1 dholland x2++; 297 1.1 dholland } 298 1.1 dholland } 299 1.1 dholland 300 1.1 dholland x1 ^= 0xffff; 301 1.1 dholland x2 ^= 0xffff; 302 1.1 dholland return ((uint32_t)x2)*65535U + x1; 303 1.1 dholland } 304 1.1 dholland 305 1.1 dholland static 306 1.1 dholland void 307 1.1 dholland macrotable_init(void) 308 1.1 dholland { 309 1.1 dholland unsigned i; 310 1.1 dholland 311 1.1 dholland macroarrayarray_init(¯os); 312 1.1 dholland macroarrayarray_setsize(¯os, 4); 313 1.1 dholland for (i=0; i<4; i++) { 314 1.1 dholland macroarrayarray_set(¯os, i, NULL); 315 1.1 dholland } 316 1.1 dholland total_macros = 0; 317 1.1 dholland hashmask = 0x3; 318 1.1 dholland } 319 1.1 dholland 320 1.1 dholland DESTROYALL_ARRAY(macro, ); 321 1.1 dholland 322 1.1 dholland static 323 1.1 dholland void 324 1.1 dholland macrotable_cleanup(void) 325 1.1 dholland { 326 1.1 dholland struct macroarray *bucket; 327 1.1 dholland unsigned numbuckets, i; 328 1.1 dholland 329 1.1 dholland numbuckets = macroarrayarray_num(¯os); 330 1.1 dholland for (i=0; i<numbuckets; i++) { 331 1.1 dholland bucket = macroarrayarray_get(¯os, i); 332 1.1 dholland if (bucket != NULL) { 333 1.1 dholland macroarray_destroyall(bucket); 334 1.1 dholland macroarray_destroy(bucket); 335 1.1 dholland } 336 1.1 dholland } 337 1.1 dholland macroarrayarray_setsize(¯os, 0); 338 1.1 dholland macroarrayarray_cleanup(¯os); 339 1.1 dholland } 340 1.1 dholland 341 1.1 dholland static 342 1.1 dholland struct macro * 343 1.1 dholland macrotable_findlen(const char *name, size_t len, bool remove_it) 344 1.1 dholland { 345 1.1 dholland unsigned hash; 346 1.1 dholland struct macroarray *bucket; 347 1.1 dholland struct macro *m, *m2; 348 1.1 dholland unsigned i, num; 349 1.1 dholland size_t mlen; 350 1.1 dholland 351 1.1 dholland hash = hashfunc(name, len); 352 1.1 dholland bucket = macroarrayarray_get(¯os, hash & hashmask); 353 1.1 dholland if (bucket == NULL) { 354 1.1 dholland return NULL; 355 1.1 dholland } 356 1.1 dholland num = macroarray_num(bucket); 357 1.1 dholland for (i=0; i<num; i++) { 358 1.1 dholland m = macroarray_get(bucket, i); 359 1.1 dholland if (hash != m->hash) { 360 1.1 dholland continue; 361 1.1 dholland } 362 1.1 dholland mlen = strlen(m->name); 363 1.1 dholland if (len == mlen && !memcmp(name, m->name, len)) { 364 1.1 dholland if (remove_it) { 365 1.1 dholland if (i < num-1) { 366 1.1 dholland m2 = macroarray_get(bucket, num-1); 367 1.1 dholland macroarray_set(bucket, i, m2); 368 1.1 dholland } 369 1.1 dholland macroarray_setsize(bucket, num-1); 370 1.1 dholland total_macros--; 371 1.1 dholland } 372 1.1 dholland return m; 373 1.1 dholland } 374 1.1 dholland } 375 1.1 dholland return NULL; 376 1.1 dholland } 377 1.1 dholland 378 1.1 dholland static 379 1.1 dholland struct macro * 380 1.1 dholland macrotable_find(const char *name, bool remove_it) 381 1.1 dholland { 382 1.1 dholland return macrotable_findlen(name, strlen(name), remove_it); 383 1.1 dholland } 384 1.1 dholland 385 1.1 dholland static 386 1.1 dholland void 387 1.1 dholland macrotable_rehash(void) 388 1.1 dholland { 389 1.1 dholland struct macroarray *newbucket, *oldbucket; 390 1.1 dholland struct macro *m; 391 1.1 dholland unsigned newmask, tossbit; 392 1.1 dholland unsigned numbuckets, i; 393 1.1 dholland unsigned oldnum, j, k; 394 1.1 dholland 395 1.1 dholland numbuckets = macroarrayarray_num(¯os); 396 1.1 dholland macroarrayarray_setsize(¯os, numbuckets*2); 397 1.1 dholland 398 1.1 dholland assert(hashmask == numbuckets - 1); 399 1.1 dholland newmask = (hashmask << 1) | 1U; 400 1.1 dholland tossbit = newmask & ~hashmask; 401 1.1 dholland hashmask = newmask; 402 1.1 dholland 403 1.1 dholland for (i=0; i<numbuckets; i++) { 404 1.1 dholland newbucket = NULL; 405 1.1 dholland oldbucket = macroarrayarray_get(¯os, i); 406 1.1 dholland if (oldbucket == NULL) { 407 1.1 dholland macroarrayarray_set(¯os, numbuckets + i, NULL); 408 1.1 dholland continue; 409 1.1 dholland } 410 1.1 dholland oldnum = macroarray_num(oldbucket); 411 1.1 dholland for (j=0; j<oldnum; j++) { 412 1.1 dholland m = macroarray_get(oldbucket, j); 413 1.1 dholland if (m->hash & tossbit) { 414 1.1 dholland if (newbucket == NULL) { 415 1.1 dholland newbucket = macroarray_create(); 416 1.1 dholland } 417 1.1 dholland macroarray_set(oldbucket, j, NULL); 418 1.1 dholland macroarray_add(newbucket, m, NULL); 419 1.1 dholland } 420 1.1 dholland } 421 1.1 dholland for (j=k=0; j<oldnum; j++) { 422 1.1 dholland m = macroarray_get(oldbucket, j); 423 1.1 dholland if (m != NULL) { 424 1.1 dholland if (k < j) { 425 1.1 dholland macroarray_set(oldbucket, k, m); 426 1.1 dholland } 427 1.1 dholland k++; 428 1.1 dholland } 429 1.1 dholland } 430 1.1 dholland macroarray_setsize(oldbucket, k); 431 1.1 dholland macroarrayarray_set(¯os, numbuckets + i, newbucket); 432 1.1 dholland } 433 1.1 dholland } 434 1.1 dholland 435 1.1 dholland static 436 1.1 dholland void 437 1.1 dholland macrotable_add(struct macro *m) 438 1.1 dholland { 439 1.1 dholland unsigned hash; 440 1.1 dholland struct macroarray *bucket; 441 1.1 dholland unsigned numbuckets; 442 1.1 dholland 443 1.1 dholland numbuckets = macroarrayarray_num(¯os); 444 1.1 dholland if (total_macros > 0 && total_macros / numbuckets > 9) { 445 1.1 dholland macrotable_rehash(); 446 1.1 dholland } 447 1.1 dholland 448 1.1 dholland hash = hashfunc(m->name, strlen(m->name)); 449 1.1 dholland bucket = macroarrayarray_get(¯os, hash & hashmask); 450 1.1 dholland if (bucket == NULL) { 451 1.1 dholland bucket = macroarray_create(); 452 1.1 dholland macroarrayarray_set(¯os, hash & hashmask, bucket); 453 1.1 dholland } 454 1.1 dholland macroarray_add(bucket, m, NULL); 455 1.1 dholland total_macros++; 456 1.1 dholland } 457 1.1 dholland 458 1.1 dholland //////////////////////////////////////////////////////////// 459 1.1 dholland // external macro definition interface 460 1.1 dholland 461 1.1 dholland static 462 1.1 dholland struct macro * 463 1.1 dholland macro_define_common_start(struct place *p1, const char *macro, 464 1.1 dholland struct place *p2) 465 1.1 dholland { 466 1.1 dholland struct macro *m; 467 1.1 dholland unsigned hash; 468 1.1 dholland 469 1.1 dholland if (!is_identifier(macro)) { 470 1.1 dholland complain(p1, "Invalid macro name %s", macro); 471 1.1 dholland complain_fail(); 472 1.1 dholland } 473 1.1 dholland 474 1.1 dholland hash = hashfunc(macro, strlen(macro)); 475 1.1 dholland m = macro_create(p1, macro, hash, p2); 476 1.1 dholland return m; 477 1.1 dholland } 478 1.1 dholland 479 1.1 dholland static 480 1.1 dholland void 481 1.1 dholland macro_define_common_end(struct macro *m) 482 1.1 dholland { 483 1.1 dholland struct macro *oldm; 484 1.1 dholland bool ok; 485 1.1 dholland 486 1.1 dholland oldm = macrotable_find(m->name, false); 487 1.1 dholland if (oldm != NULL) { 488 1.1 dholland ok = macro_eq(m, oldm); 489 1.1 dholland if (ok) { 490 1.1 dholland /* in traditional cpp this is silent */ 491 1.1 dholland //complain(&m->defplace, 492 1.1 dholland // "Warning: redefinition of %s", m->name); 493 1.1 dholland //complain(&oldm->defplace, 494 1.1 dholland // "Previous definition was here"); 495 1.1 dholland //if (mode.werror) { 496 1.1 dholland // complain_fail(); 497 1.1 dholland //} 498 1.1 dholland } else { 499 1.1 dholland complain(&m->defplace, 500 1.1 dholland "Warning: non-identical redefinition of %s", 501 1.1 dholland m->name); 502 1.1 dholland complain(&oldm->defplace, 503 1.1 dholland "Previous definition was here"); 504 1.1 dholland /* in traditional cpp this is not fatal */ 505 1.1 dholland if (mode.werror) { 506 1.1 dholland complain_fail(); 507 1.1 dholland } 508 1.1 dholland } 509 1.1 dholland macro_destroy(m); 510 1.1 dholland return; 511 1.1 dholland } 512 1.1 dholland macrotable_add(m); 513 1.1 dholland } 514 1.1 dholland 515 1.1 dholland static 516 1.1 dholland void 517 1.1 dholland macro_parse_parameters(struct macro *m, struct place *p, const char *params) 518 1.1 dholland { 519 1.1 dholland size_t len; 520 1.1 dholland const char *s; 521 1.1 dholland char *param; 522 1.1 dholland 523 1.1 dholland while (params != NULL) { 524 1.1 dholland len = strspn(params, ws); 525 1.1 dholland params += len; 526 1.1 dholland place_addcolumns(p, len); 527 1.1 dholland s = strchr(params, ','); 528 1.1 dholland if (s) { 529 1.1 dholland len = s-params; 530 1.1 dholland param = dostrndup(params, len); 531 1.1 dholland s++; 532 1.1 dholland } else { 533 1.1 dholland len = strlen(params); 534 1.1 dholland param = dostrndup(params, len); 535 1.1 dholland } 536 1.1 dholland notrailingws(param, strlen(param)); 537 1.1 dholland if (!is_identifier(param)) { 538 1.1 dholland complain(p, "Invalid macro parameter name %s", param); 539 1.1 dholland complain_fail(); 540 1.1 dholland } else { 541 1.1 dholland stringarray_add(&m->params, param, NULL); 542 1.1 dholland } 543 1.1 dholland params = s; 544 1.1 dholland place_addcolumns(p, len); 545 1.1 dholland } 546 1.1 dholland } 547 1.1 dholland 548 1.1 dholland static 549 1.1 dholland bool 550 1.1 dholland isparam(struct macro *m, const char *name, size_t len, unsigned *num_ret) 551 1.1 dholland { 552 1.1 dholland unsigned num, i; 553 1.1 dholland const char *param; 554 1.1 dholland 555 1.1 dholland num = stringarray_num(&m->params); 556 1.1 dholland for (i=0; i<num; i++) { 557 1.1 dholland param = stringarray_get(&m->params, i); 558 1.1 dholland if (strlen(param) == len && !memcmp(name, param, len)) { 559 1.1 dholland *num_ret = i; 560 1.1 dholland return true; 561 1.1 dholland } 562 1.1 dholland } 563 1.1 dholland return false; 564 1.1 dholland } 565 1.1 dholland 566 1.1 dholland static 567 1.1 dholland void 568 1.1 dholland macro_parse_expansion(struct macro *m, const char *buf) 569 1.1 dholland { 570 1.1 dholland size_t blockstart, wordstart, pos; 571 1.1 dholland struct expansionitem *ei; 572 1.1 dholland unsigned param; 573 1.1 dholland 574 1.1 dholland pos = blockstart = 0; 575 1.1 dholland while (buf[pos] != '\0') { 576 1.1 dholland pos += strspn(buf+pos, ws); 577 1.1 dholland if (strchr(alnum, buf[pos])) { 578 1.1 dholland wordstart = pos; 579 1.1 dholland pos += strspn(buf+pos, alnum); 580 1.1 dholland if (isparam(m, buf+wordstart, pos-wordstart, ¶m)) { 581 1.1 dholland if (wordstart > blockstart) { 582 1.1 dholland ei = expansionitem_create_stringlen( 583 1.1 dholland buf + blockstart, 584 1.1 dholland wordstart - blockstart); 585 1.1 dholland expansionitemarray_add(&m->expansion, 586 1.1 dholland ei, NULL); 587 1.1 dholland } 588 1.1 dholland ei = expansionitem_create_param(param); 589 1.1 dholland expansionitemarray_add(&m->expansion, ei,NULL); 590 1.1 dholland blockstart = pos; 591 1.1 dholland continue; 592 1.1 dholland } 593 1.1 dholland continue; 594 1.1 dholland } 595 1.1 dholland pos++; 596 1.1 dholland } 597 1.1 dholland if (pos > blockstart) { 598 1.1 dholland ei = expansionitem_create_stringlen(buf + blockstart, 599 1.1 dholland pos - blockstart); 600 1.1 dholland expansionitemarray_add(&m->expansion, ei, NULL); 601 1.1 dholland } 602 1.1 dholland } 603 1.1 dholland 604 1.1 dholland void 605 1.1 dholland macro_define_plain(struct place *p1, const char *macro, 606 1.1 dholland struct place *p2, const char *expansion) 607 1.1 dholland { 608 1.1 dholland struct macro *m; 609 1.1 dholland struct expansionitem *ei; 610 1.1 dholland 611 1.1 dholland m = macro_define_common_start(p1, macro, p2); 612 1.1 dholland ei = expansionitem_create_string(expansion); 613 1.1 dholland expansionitemarray_add(&m->expansion, ei, NULL); 614 1.1 dholland macro_define_common_end(m); 615 1.1 dholland } 616 1.1 dholland 617 1.1 dholland void 618 1.1 dholland macro_define_params(struct place *p1, const char *macro, 619 1.1 dholland struct place *p2, const char *params, 620 1.1 dholland struct place *p3, const char *expansion) 621 1.1 dholland { 622 1.1 dholland struct macro *m; 623 1.1 dholland 624 1.1 dholland m = macro_define_common_start(p1, macro, p3); 625 1.1 dholland m->hasparams = true; 626 1.1 dholland macro_parse_parameters(m, p2, params); 627 1.1 dholland macro_parse_expansion(m, expansion); 628 1.1 dholland macro_define_common_end(m); 629 1.1 dholland } 630 1.1 dholland 631 1.1 dholland void 632 1.1 dholland macro_define_magic(struct place *p, const char *macro) 633 1.1 dholland { 634 1.1 dholland struct macro *m; 635 1.1 dholland struct expansionitem *ei; 636 1.1 dholland 637 1.1 dholland m = macro_define_common_start(p, macro, p); 638 1.1 dholland if (!strcmp(macro, "__FILE__")) { 639 1.1 dholland ei = expansionitem_create_file(); 640 1.1 dholland } 641 1.1 dholland else { 642 1.1 dholland assert(!strcmp(macro, "__LINE__")); 643 1.1 dholland ei = expansionitem_create_line(); 644 1.1 dholland } 645 1.1 dholland expansionitemarray_add(&m->expansion, ei, NULL); 646 1.1 dholland macro_define_common_end(m); 647 1.1 dholland } 648 1.1 dholland 649 1.1 dholland void 650 1.1 dholland macro_undef(const char *macro) 651 1.1 dholland { 652 1.1 dholland struct macro *m; 653 1.1 dholland 654 1.1 dholland m = macrotable_find(macro, true); 655 1.1 dholland if (m) { 656 1.1 dholland macro_destroy(m); 657 1.1 dholland } 658 1.1 dholland } 659 1.1 dholland 660 1.1 dholland bool 661 1.1 dholland macro_isdefined(const char *macro) 662 1.1 dholland { 663 1.1 dholland struct macro *m; 664 1.1 dholland 665 1.1 dholland m = macrotable_find(macro, false); 666 1.1 dholland return m != NULL; 667 1.1 dholland } 668 1.1 dholland 669 1.1 dholland //////////////////////////////////////////////////////////// 670 1.1 dholland // macro expansion 671 1.1 dholland 672 1.1 dholland struct expstate { 673 1.1 dholland bool honordefined; 674 1.1 dholland enum { ES_NORMAL, ES_WANTLPAREN, ES_NOARG, ES_HAVEARG } state; 675 1.1 dholland struct macro *curmacro; 676 1.1 dholland struct stringarray args; 677 1.1 dholland unsigned argparens; 678 1.1 dholland 679 1.1 dholland bool tobuf; 680 1.1 dholland char *buf; 681 1.1 dholland size_t bufpos, bufmax; 682 1.1 dholland }; 683 1.1 dholland 684 1.1 dholland static struct expstate mainstate; 685 1.1 dholland 686 1.1 dholland static void doexpand(struct expstate *es, struct place *p, 687 1.1 dholland const char *buf, size_t len); 688 1.1 dholland 689 1.1 dholland static 690 1.1 dholland void 691 1.1 dholland expstate_init(struct expstate *es, bool tobuf, bool honordefined) 692 1.1 dholland { 693 1.1 dholland es->honordefined = honordefined; 694 1.1 dholland es->state = ES_NORMAL; 695 1.1 dholland es->curmacro = NULL; 696 1.1 dholland stringarray_init(&es->args); 697 1.1 dholland es->argparens = 0; 698 1.1 dholland es->tobuf = tobuf; 699 1.1 dholland es->buf = NULL; 700 1.1 dholland es->bufpos = 0; 701 1.1 dholland es->bufmax = 0; 702 1.1 dholland } 703 1.1 dholland 704 1.1 dholland static 705 1.1 dholland void 706 1.1 dholland expstate_cleanup(struct expstate *es) 707 1.1 dholland { 708 1.1 dholland assert(es->state == ES_NORMAL); 709 1.1 dholland stringarray_cleanup(&es->args); 710 1.1 dholland if (es->buf) { 711 1.1 dholland dofree(es->buf, es->bufmax); 712 1.1 dholland } 713 1.1 dholland } 714 1.1 dholland 715 1.1 dholland static 716 1.1 dholland void 717 1.1 dholland expstate_destroyargs(struct expstate *es) 718 1.1 dholland { 719 1.1 dholland unsigned i, num; 720 1.1 dholland 721 1.1 dholland num = stringarray_num(&es->args); 722 1.1 dholland for (i=0; i<num; i++) { 723 1.1 dholland dostrfree(stringarray_get(&es->args, i)); 724 1.1 dholland } 725 1.1 dholland stringarray_setsize(&es->args, 0); 726 1.1 dholland } 727 1.1 dholland 728 1.1 dholland static 729 1.1 dholland void 730 1.1 dholland expand_send(struct expstate *es, struct place *p, const char *buf, size_t len) 731 1.1 dholland { 732 1.1 dholland size_t oldmax; 733 1.1 dholland 734 1.1 dholland if (es->tobuf) { 735 1.1 dholland assert(es->bufpos <= es->bufmax); 736 1.1 dholland if (es->bufpos + len > es->bufmax) { 737 1.1 dholland oldmax = es->bufmax; 738 1.1 dholland if (es->bufmax == 0) { 739 1.1 dholland es->bufmax = 64; 740 1.1 dholland } 741 1.1 dholland while (es->bufpos + len > es->bufmax) { 742 1.1 dholland es->bufmax *= 2; 743 1.1 dholland } 744 1.1 dholland es->buf = dorealloc(es->buf, oldmax, es->bufmax); 745 1.1 dholland } 746 1.1 dholland memcpy(es->buf + es->bufpos, buf, len); 747 1.1 dholland es->bufpos += len; 748 1.1 dholland assert(es->bufpos <= es->bufmax); 749 1.1 dholland } else { 750 1.1 dholland output(p, buf, len); 751 1.1 dholland } 752 1.1 dholland } 753 1.1 dholland 754 1.1 dholland static 755 1.1 dholland void 756 1.1 dholland expand_send_eof(struct expstate *es, struct place *p) 757 1.1 dholland { 758 1.1 dholland if (es->tobuf) { 759 1.1 dholland expand_send(es, p, "", 1); 760 1.1 dholland es->bufpos--; 761 1.1 dholland } else { 762 1.1 dholland output_eof(); 763 1.1 dholland } 764 1.1 dholland } 765 1.1 dholland 766 1.1 dholland static 767 1.1 dholland void 768 1.1 dholland expand_newarg(struct expstate *es, const char *buf, size_t len) 769 1.1 dholland { 770 1.1 dholland char *text; 771 1.1 dholland 772 1.1 dholland text = dostrndup(buf, len); 773 1.1 dholland stringarray_add(&es->args, text, NULL); 774 1.1 dholland } 775 1.1 dholland 776 1.1 dholland static 777 1.1 dholland void 778 1.1 dholland expand_appendarg(struct expstate *es, const char *buf, size_t len) 779 1.1 dholland { 780 1.1 dholland unsigned num; 781 1.1 dholland char *text; 782 1.1 dholland size_t oldlen; 783 1.1 dholland 784 1.1 dholland num = stringarray_num(&es->args); 785 1.1 dholland assert(num > 0); 786 1.1 dholland 787 1.1 dholland text = stringarray_get(&es->args, num - 1); 788 1.1 dholland oldlen = strlen(text); 789 1.1 dholland text = dorealloc(text, oldlen + 1, oldlen + len + 1); 790 1.1 dholland memcpy(text + oldlen, buf, len); 791 1.1 dholland text[oldlen+len] = '\0'; 792 1.1 dholland stringarray_set(&es->args, num - 1, text); 793 1.1 dholland } 794 1.1 dholland 795 1.1 dholland static 796 1.1 dholland char * 797 1.1 dholland expand_substitute(struct place *p, struct expstate *es) 798 1.1 dholland { 799 1.1 dholland struct expansionitem *ei; 800 1.1 dholland unsigned i, num; 801 1.1 dholland size_t len; 802 1.1 dholland char *arg; 803 1.1 dholland char *ret; 804 1.1 dholland unsigned numargs, numparams; 805 1.1 dholland char numbuf[64]; 806 1.1 dholland 807 1.1 dholland numargs = stringarray_num(&es->args); 808 1.1 dholland numparams = stringarray_num(&es->curmacro->params); 809 1.1 dholland 810 1.1 dholland if (numargs == 0 && numparams == 1) { 811 1.1 dholland /* no arguments <=> one empty argument */ 812 1.1 dholland stringarray_add(&es->args, dostrdup(""), NULL); 813 1.1 dholland numargs++; 814 1.1 dholland } 815 1.1 dholland if (numargs != numparams) { 816 1.1 dholland complain(p, "Wrong number of arguments for macro %s; " 817 1.1 dholland "found %u, expected %u", 818 1.1 dholland es->curmacro->name, numargs, numparams); 819 1.1 dholland complain_fail(); 820 1.1 dholland while (numargs < numparams) { 821 1.1 dholland stringarray_add(&es->args, dostrdup(""), NULL); 822 1.1 dholland numargs++; 823 1.1 dholland } 824 1.1 dholland } 825 1.1 dholland 826 1.1 dholland len = 0; 827 1.1 dholland num = expansionitemarray_num(&es->curmacro->expansion); 828 1.1 dholland for (i=0; i<num; i++) { 829 1.1 dholland ei = expansionitemarray_get(&es->curmacro->expansion, i); 830 1.1 dholland switch (ei->itemtype) { 831 1.1 dholland case EI_STRING: 832 1.1 dholland len += strlen(ei->ei_string); 833 1.1 dholland break; 834 1.1 dholland case EI_PARAM: 835 1.1 dholland arg = stringarray_get(&es->args, ei->ei_param); 836 1.1 dholland len += strlen(arg); 837 1.1 dholland break; 838 1.1 dholland case EI_FILE: 839 1.1 dholland len += strlen(place_getname(p)) + 2; 840 1.1 dholland break; 841 1.1 dholland case EI_LINE: 842 1.1 dholland len += snprintf(numbuf, sizeof(numbuf), "%u", p->line); 843 1.1 dholland break; 844 1.1 dholland } 845 1.1 dholland } 846 1.1 dholland 847 1.1 dholland ret = domalloc(len+1); 848 1.1 dholland *ret = '\0'; 849 1.1 dholland for (i=0; i<num; i++) { 850 1.1 dholland ei = expansionitemarray_get(&es->curmacro->expansion, i); 851 1.1 dholland switch (ei->itemtype) { 852 1.1 dholland case EI_STRING: 853 1.1 dholland strcat(ret, ei->ei_string); 854 1.1 dholland break; 855 1.1 dholland case EI_PARAM: 856 1.1 dholland arg = stringarray_get(&es->args, ei->ei_param); 857 1.1 dholland strcat(ret, arg); 858 1.1 dholland break; 859 1.1 dholland case EI_FILE: 860 1.1 dholland strcat(ret, "\""); 861 1.1 dholland strcat(ret, place_getname(p)); 862 1.1 dholland strcat(ret, "\""); 863 1.1 dholland break; 864 1.1 dholland case EI_LINE: 865 1.1 dholland snprintf(numbuf, sizeof(numbuf), "%u", p->line); 866 1.1 dholland strcat(ret, numbuf); 867 1.1 dholland break; 868 1.1 dholland } 869 1.1 dholland } 870 1.1 dholland 871 1.1 dholland return ret; 872 1.1 dholland } 873 1.1 dholland 874 1.1 dholland static 875 1.1 dholland void 876 1.1 dholland expand_domacro(struct expstate *es, struct place *p) 877 1.1 dholland { 878 1.1 dholland struct macro *m; 879 1.1 dholland const char *name, *val; 880 1.1 dholland char *newbuf, *newbuf2; 881 1.1 dholland 882 1.1 dholland if (es->curmacro == NULL) { 883 1.1 dholland /* defined() */ 884 1.1 dholland if (stringarray_num(&es->args) != 1) { 885 1.1 dholland complain(p, "Too many arguments for defined()"); 886 1.1 dholland complain_fail(); 887 1.1 dholland expand_send(es, p, "0", 1); 888 1.1 dholland return; 889 1.1 dholland } 890 1.1 dholland name = stringarray_get(&es->args, 0); 891 1.1 dholland m = macrotable_find(name, false); 892 1.1 dholland val = (m != NULL) ? "1" : "0"; 893 1.1 dholland debuglog(p, "defined(%s): %s", name, val); 894 1.1 dholland expand_send(es, p, val, 1); 895 1.1 dholland expstate_destroyargs(es); 896 1.1 dholland return; 897 1.1 dholland } 898 1.1 dholland 899 1.1 dholland m = es->curmacro; 900 1.1 dholland assert(m->inuse == false); 901 1.1 dholland m->inuse = true; 902 1.1 dholland 903 1.1 dholland debuglog(p, "Expanding macro %s", m->name); 904 1.1 dholland newbuf = expand_substitute(p, es); 905 1.1 dholland debuglog(p, "Substituting for %s: %s", m->name, newbuf); 906 1.1 dholland 907 1.1 dholland newbuf2 = macroexpand(p, newbuf, strlen(newbuf), false); 908 1.1 dholland dostrfree(newbuf); 909 1.1 dholland expstate_destroyargs(es); 910 1.1 dholland debuglog(p, "Complete expansion for %s: %s", m->name, newbuf2); 911 1.1 dholland 912 1.1 dholland doexpand(es, p, newbuf2, strlen(newbuf2)); 913 1.1 dholland dostrfree(newbuf2); 914 1.1 dholland 915 1.1 dholland m->inuse = false; 916 1.1 dholland } 917 1.1 dholland 918 1.1 dholland /* 919 1.1 dholland * The traditional behavior if a function-like macro appears without 920 1.1 dholland * arguments is to pretend it isn't a macro; that is, just emit its 921 1.1 dholland * name. 922 1.1 dholland */ 923 1.1 dholland static 924 1.1 dholland void 925 1.1 dholland expand_missingargs(struct expstate *es, struct place *p, bool needspace) 926 1.1 dholland { 927 1.1 dholland if (es->curmacro == NULL) { 928 1.1 dholland /* defined */ 929 1.1 dholland expand_send(es, p, "defined", 7); 930 1.1 dholland return; 931 1.1 dholland } 932 1.1 dholland expand_send(es, p, es->curmacro->name, strlen(es->curmacro->name)); 933 1.1 dholland /* send a space in case we ate whitespace after the macro name */ 934 1.1 dholland if (needspace) { 935 1.1 dholland expand_send(es, p, " ", 1); 936 1.1 dholland } 937 1.1 dholland } 938 1.1 dholland 939 1.1 dholland static 940 1.1 dholland void 941 1.1 dholland expand_got_ws(struct expstate *es, struct place *p, 942 1.1 dholland const char *buf, size_t len) 943 1.1 dholland { 944 1.1 dholland switch (es->state) { 945 1.1 dholland case ES_NORMAL: 946 1.1 dholland expand_send(es, p, buf, len); 947 1.1 dholland break; 948 1.1 dholland case ES_WANTLPAREN: 949 1.1 dholland /* XXX notyet */ 950 1.1 dholland //expand_send(es, p, buf, len); 951 1.1 dholland break; 952 1.1 dholland case ES_NOARG: 953 1.1 dholland expand_newarg(es, buf, len); 954 1.1 dholland es->state = ES_HAVEARG; 955 1.1 dholland break; 956 1.1 dholland case ES_HAVEARG: 957 1.1 dholland expand_appendarg(es, buf, len); 958 1.1 dholland break; 959 1.1 dholland } 960 1.1 dholland } 961 1.1 dholland 962 1.1 dholland static 963 1.1 dholland void 964 1.1 dholland expand_got_word(struct expstate *es, struct place *p, 965 1.1 dholland const char *buf, size_t len) 966 1.1 dholland { 967 1.1 dholland struct macro *m; 968 1.1 dholland 969 1.1 dholland switch (es->state) { 970 1.1 dholland case ES_NORMAL: 971 1.1 dholland if (es->honordefined && 972 1.1 dholland len == 7 && !memcmp(buf, "defined", 7)) { 973 1.1 dholland es->curmacro = NULL; 974 1.1 dholland es->state = ES_WANTLPAREN; 975 1.1 dholland break; 976 1.1 dholland } 977 1.1 dholland m = macrotable_findlen(buf, len, false); 978 1.1 dholland if (m == NULL || m->inuse) { 979 1.1 dholland expand_send(es, p, buf, len); 980 1.1 dholland } else if (!m->hasparams) { 981 1.1 dholland es->curmacro = m; 982 1.1 dholland expand_domacro(es, p); 983 1.1 dholland } else { 984 1.1 dholland es->curmacro = m; 985 1.1 dholland es->state = ES_WANTLPAREN; 986 1.1 dholland } 987 1.1 dholland break; 988 1.1 dholland case ES_WANTLPAREN: 989 1.1 dholland if (es->curmacro != NULL) { 990 1.1 dholland expand_missingargs(es, p, true); 991 1.1 dholland es->state = ES_NORMAL; 992 1.1 dholland /* try again */ 993 1.1 dholland expand_got_word(es, p, buf, len); 994 1.1 dholland } else { 995 1.1 dholland /* "defined foo" means "defined(foo)" */ 996 1.1 dholland expand_newarg(es, buf, len); 997 1.1 dholland es->state = ES_NORMAL; 998 1.1 dholland expand_domacro(es, p); 999 1.1 dholland } 1000 1.1 dholland break; 1001 1.1 dholland case ES_NOARG: 1002 1.1 dholland expand_newarg(es, buf, len); 1003 1.1 dholland es->state = ES_HAVEARG; 1004 1.1 dholland break; 1005 1.1 dholland case ES_HAVEARG: 1006 1.1 dholland expand_appendarg(es, buf, len); 1007 1.1 dholland break; 1008 1.1 dholland } 1009 1.1 dholland } 1010 1.1 dholland 1011 1.1 dholland static 1012 1.1 dholland void 1013 1.1 dholland expand_got_lparen(struct expstate *es, struct place *p, 1014 1.1 dholland const char *buf, size_t len) 1015 1.1 dholland { 1016 1.1 dholland switch (es->state) { 1017 1.1 dholland case ES_NORMAL: 1018 1.1 dholland expand_send(es, p, buf, len); 1019 1.1 dholland break; 1020 1.1 dholland case ES_WANTLPAREN: 1021 1.1 dholland es->state = ES_NOARG; 1022 1.1 dholland break; 1023 1.1 dholland case ES_NOARG: 1024 1.1 dholland expand_newarg(es, buf, len); 1025 1.1 dholland es->state = ES_HAVEARG; 1026 1.1 dholland es->argparens++; 1027 1.1 dholland break; 1028 1.1 dholland case ES_HAVEARG: 1029 1.1 dholland expand_appendarg(es, buf, len); 1030 1.1 dholland es->argparens++; 1031 1.1 dholland break; 1032 1.1 dholland } 1033 1.1 dholland } 1034 1.1 dholland 1035 1.1 dholland static 1036 1.1 dholland void 1037 1.1 dholland expand_got_rparen(struct expstate *es, struct place *p, 1038 1.1 dholland const char *buf, size_t len) 1039 1.1 dholland { 1040 1.1 dholland switch (es->state) { 1041 1.1 dholland case ES_NORMAL: 1042 1.1 dholland expand_send(es, p, buf, len); 1043 1.1 dholland break; 1044 1.1 dholland case ES_WANTLPAREN: 1045 1.1 dholland expand_missingargs(es, p, false); 1046 1.1 dholland es->state = ES_NORMAL; 1047 1.1 dholland /* try again */ 1048 1.1 dholland expand_got_rparen(es, p, buf, len); 1049 1.1 dholland break; 1050 1.1 dholland case ES_NOARG: 1051 1.1 dholland assert(es->argparens == 0); 1052 1.1 dholland if (stringarray_num(&es->args) > 0) { 1053 1.1 dholland /* we are after a comma; enter an empty argument */ 1054 1.1 dholland expand_newarg(es, buf, 0); 1055 1.1 dholland } 1056 1.1 dholland es->state = ES_NORMAL; 1057 1.1 dholland expand_domacro(es, p); 1058 1.1 dholland break; 1059 1.1 dholland case ES_HAVEARG: 1060 1.1 dholland if (es->argparens > 0) { 1061 1.1 dholland es->argparens--; 1062 1.1 dholland expand_appendarg(es, buf, len); 1063 1.1 dholland } else { 1064 1.1 dholland es->state = ES_NORMAL; 1065 1.1 dholland expand_domacro(es, p); 1066 1.1 dholland } 1067 1.1 dholland break; 1068 1.1 dholland } 1069 1.1 dholland } 1070 1.1 dholland 1071 1.1 dholland static 1072 1.1 dholland void 1073 1.1 dholland expand_got_comma(struct expstate *es, struct place *p, 1074 1.1 dholland const char *buf, size_t len) 1075 1.1 dholland { 1076 1.1 dholland switch (es->state) { 1077 1.1 dholland case ES_NORMAL: 1078 1.1 dholland expand_send(es, p, buf, len); 1079 1.1 dholland break; 1080 1.1 dholland case ES_WANTLPAREN: 1081 1.1 dholland expand_missingargs(es, p, false); 1082 1.1 dholland es->state = ES_NORMAL; 1083 1.1 dholland /* try again */ 1084 1.1 dholland expand_got_comma(es, p, buf, len); 1085 1.1 dholland break; 1086 1.1 dholland case ES_NOARG: 1087 1.1 dholland assert(es->argparens == 0); 1088 1.1 dholland expand_newarg(es, buf, 0); 1089 1.1 dholland break; 1090 1.1 dholland case ES_HAVEARG: 1091 1.1 dholland if (es->argparens > 0) { 1092 1.1 dholland expand_appendarg(es, buf, len); 1093 1.1 dholland } else { 1094 1.1 dholland es->state = ES_NOARG; 1095 1.1 dholland } 1096 1.1 dholland break; 1097 1.1 dholland } 1098 1.1 dholland } 1099 1.1 dholland 1100 1.1 dholland static 1101 1.1 dholland void 1102 1.1 dholland expand_got_other(struct expstate *es, struct place *p, 1103 1.1 dholland const char *buf, size_t len) 1104 1.1 dholland { 1105 1.1 dholland switch (es->state) { 1106 1.1 dholland case ES_NORMAL: 1107 1.1 dholland expand_send(es, p, buf, len); 1108 1.1 dholland break; 1109 1.1 dholland case ES_WANTLPAREN: 1110 1.1 dholland expand_missingargs(es, p, false); 1111 1.1 dholland es->state = ES_NORMAL; 1112 1.1 dholland /* try again */ 1113 1.1 dholland expand_got_other(es, p, buf, len); 1114 1.1 dholland break; 1115 1.1 dholland case ES_NOARG: 1116 1.1 dholland expand_newarg(es, buf, len); 1117 1.1 dholland es->state = ES_HAVEARG; 1118 1.1 dholland break; 1119 1.1 dholland case ES_HAVEARG: 1120 1.1 dholland expand_appendarg(es, buf, len); 1121 1.1 dholland break; 1122 1.1 dholland } 1123 1.1 dholland } 1124 1.1 dholland 1125 1.1 dholland static 1126 1.1 dholland void 1127 1.1 dholland expand_got_eof(struct expstate *es, struct place *p) 1128 1.1 dholland { 1129 1.1 dholland switch (es->state) { 1130 1.1 dholland case ES_NORMAL: 1131 1.1 dholland break; 1132 1.1 dholland case ES_WANTLPAREN: 1133 1.1 dholland expand_missingargs(es, p, false); 1134 1.1 dholland break; 1135 1.1 dholland case ES_NOARG: 1136 1.1 dholland case ES_HAVEARG: 1137 1.1 dholland if (es->curmacro) { 1138 1.1 dholland complain(p, "Unclosed argument list for macro %s", 1139 1.1 dholland es->curmacro->name); 1140 1.1 dholland } else { 1141 1.1 dholland complain(p, "Unclosed argument list for defined()"); 1142 1.1 dholland } 1143 1.1 dholland complain_fail(); 1144 1.1 dholland expstate_destroyargs(es); 1145 1.1 dholland break; 1146 1.1 dholland } 1147 1.1 dholland expand_send_eof(es, p); 1148 1.1 dholland es->state = ES_NORMAL; 1149 1.1 dholland es->curmacro = NULL; 1150 1.1 dholland es->argparens = 0; 1151 1.1 dholland } 1152 1.1 dholland 1153 1.1 dholland static 1154 1.1 dholland void 1155 1.1 dholland doexpand(struct expstate *es, struct place *p, const char *buf, size_t len) 1156 1.1 dholland { 1157 1.1 dholland char *s; 1158 1.1 dholland size_t x; 1159 1.1 dholland bool inquote = false; 1160 1.1 dholland char quote = '\0'; 1161 1.1 dholland 1162 1.1 dholland while (len > 0) { 1163 1.1 dholland x = strspn(buf, ws); 1164 1.1 dholland if (x > len) { 1165 1.1 dholland /* XXX gross, need strnspn */ 1166 1.1 dholland x = len; 1167 1.1 dholland } 1168 1.1 dholland 1169 1.1 dholland if (x > 0) { 1170 1.1 dholland expand_got_ws(es, p, buf, x); 1171 1.1 dholland buf += x; 1172 1.1 dholland len -= x; 1173 1.1 dholland continue; 1174 1.1 dholland } 1175 1.1 dholland 1176 1.1 dholland x = strspn(buf, alnum); 1177 1.1 dholland if (x > len) { 1178 1.1 dholland /* XXX gross, need strnspn */ 1179 1.1 dholland x = len; 1180 1.1 dholland } 1181 1.1 dholland 1182 1.1 dholland if (!inquote && x > 0) { 1183 1.1 dholland expand_got_word(es, p, buf, x); 1184 1.1 dholland buf += x; 1185 1.1 dholland len -= x; 1186 1.1 dholland continue; 1187 1.1 dholland } 1188 1.1 dholland 1189 1.1 dholland if (!inquote && len > 1 && buf[0] == '/' && buf[1] == '*') { 1190 1.1 dholland s = strstr(buf, "*/"); 1191 1.1 dholland if (s) { 1192 1.1 dholland x = s - buf; 1193 1.1 dholland } else { 1194 1.1 dholland x = len; 1195 1.1 dholland } 1196 1.1 dholland expand_got_ws(es, p, buf, x); 1197 1.1 dholland buf += x; 1198 1.1 dholland len -= x; 1199 1.1 dholland continue; 1200 1.1 dholland } 1201 1.1 dholland 1202 1.1 dholland if (!inquote && buf[0] == '(') { 1203 1.1 dholland expand_got_lparen(es, p, buf, 1); 1204 1.1 dholland buf++; 1205 1.1 dholland len--; 1206 1.1 dholland continue; 1207 1.1 dholland } 1208 1.1 dholland 1209 1.1 dholland if (!inquote && buf[0] == ')') { 1210 1.1 dholland expand_got_rparen(es, p, buf, 1); 1211 1.1 dholland buf++; 1212 1.1 dholland len--; 1213 1.1 dholland continue; 1214 1.1 dholland } 1215 1.1 dholland 1216 1.1 dholland if (!inquote && buf[0] == ',') { 1217 1.1 dholland expand_got_comma(es, p, buf, 1); 1218 1.1 dholland buf++; 1219 1.1 dholland len--; 1220 1.1 dholland continue; 1221 1.1 dholland } 1222 1.1 dholland 1223 1.1 dholland if (len > 1 && buf[0] == '\\' && 1224 1.1 dholland (buf[1] == '"' || buf[1] == '\'')) { 1225 1.1 dholland expand_got_other(es, p, buf, 2); 1226 1.1 dholland buf += 2; 1227 1.1 dholland len -= 2; 1228 1.1 dholland continue; 1229 1.1 dholland } 1230 1.1 dholland if (!inquote && (buf[0] == '"' || buf[0] == '\'')) { 1231 1.1 dholland inquote = true; 1232 1.1 dholland quote = buf[0]; 1233 1.1 dholland } else if (inquote && buf[0] == quote) { 1234 1.1 dholland inquote = false; 1235 1.1 dholland } 1236 1.1 dholland 1237 1.1 dholland expand_got_other(es, p, buf, 1); 1238 1.1 dholland buf++; 1239 1.1 dholland len--; 1240 1.1 dholland } 1241 1.1 dholland } 1242 1.1 dholland 1243 1.1 dholland char * 1244 1.1 dholland macroexpand(struct place *p, const char *buf, size_t len, bool honordefined) 1245 1.1 dholland { 1246 1.1 dholland struct expstate es; 1247 1.1 dholland char *ret; 1248 1.1 dholland 1249 1.1 dholland expstate_init(&es, true, honordefined); 1250 1.1 dholland doexpand(&es, p, buf, len); 1251 1.1 dholland expand_got_eof(&es, p); 1252 1.1 dholland 1253 1.1 dholland /* trim to fit, so the malloc debugging won't complain */ 1254 1.1 dholland es.buf = dorealloc(es.buf, es.bufmax, strlen(es.buf) + 1); 1255 1.1 dholland 1256 1.1 dholland ret = es.buf; 1257 1.1 dholland es.buf = NULL; 1258 1.1 dholland es.bufpos = es.bufmax = 0; 1259 1.1 dholland 1260 1.1 dholland expstate_cleanup(&es); 1261 1.1 dholland 1262 1.1 dholland return ret; 1263 1.1 dholland } 1264 1.1 dholland 1265 1.1 dholland void 1266 1.1 dholland macro_sendline(struct place *p, const char *buf, size_t len) 1267 1.1 dholland { 1268 1.1 dholland doexpand(&mainstate, p, buf, len); 1269 1.1 dholland switch (mainstate.state) { 1270 1.1 dholland case ES_NORMAL: 1271 1.1 dholland /* 1272 1.1 dholland * If we were sent a blank line, don't emit a newline 1273 1.1 dholland * for it. This matches the prior behavior of tradcpp. 1274 1.1 dholland */ 1275 1.1 dholland if (len > 0) { 1276 1.1 dholland output(p, "\n", 1); 1277 1.1 dholland } 1278 1.1 dholland break; 1279 1.1 dholland case ES_WANTLPAREN: 1280 1.1 dholland case ES_NOARG: 1281 1.1 dholland case ES_HAVEARG: 1282 1.1 dholland /* 1283 1.1 dholland * Apparently to match gcc's -traditional behavior we 1284 1.1 dholland * need to emit a space for each newline that appears 1285 1.1 dholland * while processing macro args. 1286 1.1 dholland */ 1287 1.1 dholland expand_got_ws(&mainstate, p, " ", 1); 1288 1.1 dholland break; 1289 1.1 dholland } 1290 1.1 dholland } 1291 1.1 dholland 1292 1.1 dholland void 1293 1.1 dholland macro_sendeof(struct place *p) 1294 1.1 dholland { 1295 1.1 dholland expand_got_eof(&mainstate, p); 1296 1.1 dholland } 1297 1.1 dholland 1298 1.1 dholland //////////////////////////////////////////////////////////// 1299 1.1 dholland // module initialization 1300 1.1 dholland 1301 1.1 dholland void 1302 1.1 dholland macros_init(void) 1303 1.1 dholland { 1304 1.1 dholland macrotable_init(); 1305 1.1 dholland expstate_init(&mainstate, false, false); 1306 1.1 dholland } 1307 1.1 dholland 1308 1.1 dholland void 1309 1.1 dholland macros_cleanup(void) 1310 1.1 dholland { 1311 1.1 dholland expstate_cleanup(&mainstate); 1312 1.1 dholland macrotable_cleanup(); 1313 1.1 dholland } 1314