00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <string.h>
00004 #include "cpp.h"
00005
00006
00007
00008
00009 void
00010 dodefine(Tokenrow *trp)
00011 {
00012 Token *tp;
00013 Nlist *np;
00014 Tokenrow *def, *args;
00015
00016 tp = trp->tp+1;
00017 if (tp>=trp->lp || tp->type!=NAME) {
00018 error(ERROR, "#defined token is not a name");
00019 return;
00020 }
00021 np = lookup(tp, 1);
00022 if (np->flag&ISUNCHANGE) {
00023 error(ERROR, "#defined token %t can't be redefined", tp);
00024 return;
00025 }
00026
00027 tp += 1;
00028 args = NULL;
00029 if (tp<trp->lp && tp->type==LP && tp->wslen==0) {
00030
00031 int narg = 0;
00032 tp += 1;
00033 args = new(Tokenrow);
00034 maketokenrow(2, args);
00035 if (tp->type!=RP) {
00036 int err = 0;
00037 for (;;) {
00038 Token *atp;
00039 if (tp->type!=NAME) {
00040 err++;
00041 break;
00042 }
00043 if (narg>=args->max)
00044 growtokenrow(args);
00045 for (atp=args->bp; atp<args->lp; atp++)
00046 if (atp->len==tp->len
00047 && strncmp((char*)atp->t, (char*)tp->t, tp->len)==0)
00048 error(ERROR, "Duplicate macro argument");
00049 *args->lp++ = *tp;
00050 narg++;
00051 tp += 1;
00052 if (tp->type==RP)
00053 break;
00054 if (tp->type!=COMMA) {
00055 err++;
00056 break;
00057 }
00058 tp += 1;
00059 }
00060 if (err) {
00061 error(ERROR, "Syntax error in macro parameters");
00062 return;
00063 }
00064 }
00065 tp += 1;
00066 }
00067 trp->tp = tp;
00068 if (((trp->lp)-1)->type==NL)
00069 trp->lp -= 1;
00070 def = normtokenrow(trp);
00071 if (np->flag&ISDEFINED) {
00072 if (comparetokens(def, np->vp)
00073 || (np->ap==NULL) != (args==NULL)
00074 || np->ap && comparetokens(args, np->ap))
00075 error(ERROR, "Macro redefinition of %t", trp->bp+2);
00076 }
00077 if (args) {
00078 Tokenrow *tap;
00079 tap = normtokenrow(args);
00080 dofree(args->bp);
00081 args = tap;
00082 }
00083 np->ap = args;
00084 np->vp = def;
00085 np->flag |= ISDEFINED;
00086 }
00087
00088
00089
00090
00091 void
00092 doadefine(Tokenrow *trp, int type)
00093 {
00094 Nlist *np;
00095 static Token onetoken[1] = {{ NUMBER, 0, 0, 0, 1, (uchar*)"1" }};
00096 static Tokenrow onetr = { onetoken, onetoken, onetoken+1, 1 };
00097
00098 trp->tp = trp->bp;
00099 if (type=='U') {
00100 if (trp->lp-trp->tp != 2 || trp->tp->type!=NAME)
00101 goto syntax;
00102 if ((np = lookup(trp->tp, 0)) == NULL)
00103 return;
00104 np->flag &= ~ISDEFINED;
00105 return;
00106 }
00107 if (trp->tp >= trp->lp || trp->tp->type!=NAME)
00108 goto syntax;
00109 np = lookup(trp->tp, 1);
00110 np->flag |= ISDEFINED;
00111 trp->tp += 1;
00112 if (trp->tp >= trp->lp || trp->tp->type==END) {
00113 np->vp = &onetr;
00114 return;
00115 }
00116 if (trp->tp->type!=ASGN)
00117 goto syntax;
00118 trp->tp += 1;
00119 if ((trp->lp-1)->type == END)
00120 trp->lp -= 1;
00121 np->vp = normtokenrow(trp);
00122 return;
00123 syntax:
00124 error(FATAL, "Illegal -D or -U argument %r", trp);
00125 }
00126
00127
00128
00129
00130
00131 void
00132 expandrow(Tokenrow *trp, char *flag)
00133 {
00134 Token *tp;
00135 Nlist *np;
00136
00137 if (flag)
00138 setsource(flag, -1, "");
00139 for (tp = trp->tp; tp<trp->lp; ) {
00140 if (tp->type!=NAME
00141 || quicklook(tp->t[0], tp->len>1?tp->t[1]:0)==0
00142 || (np = lookup(tp, 0))==NULL
00143 || (np->flag&(ISDEFINED|ISMAC))==0
00144 || tp->hideset && checkhideset(tp->hideset, np)) {
00145 tp++;
00146 continue;
00147 }
00148 trp->tp = tp;
00149 if (np->val==KDEFINED) {
00150 tp->type = DEFINED;
00151 if ((tp+1)<trp->lp && (tp+1)->type==NAME)
00152 (tp+1)->type = NAME1;
00153 else if ((tp+3)<trp->lp && (tp+1)->type==LP
00154 && (tp+2)->type==NAME && (tp+3)->type==RP)
00155 (tp+2)->type = NAME1;
00156 else
00157 error(ERROR, "Incorrect syntax for `defined'");
00158 tp++;
00159 continue;
00160 }
00161 if (np->flag&ISMAC)
00162 builtin(trp, np->val);
00163 else {
00164 expand(trp, np);
00165 }
00166 tp = trp->tp;
00167 }
00168 if (flag)
00169 unsetsource();
00170 }
00171
00172
00173
00174
00175
00176
00177 void
00178 expand(Tokenrow *trp, Nlist *np)
00179 {
00180 Tokenrow ntr;
00181 int ntokc, narg, i;
00182 Token *tp;
00183 Tokenrow *atr[NARG+1];
00184 int hs;
00185
00186 copytokenrow(&ntr, np->vp);
00187 if (np->ap==NULL)
00188 ntokc = 1;
00189 else {
00190 ntokc = gatherargs(trp, atr, &narg);
00191 if (narg<0) {
00192 trp->tp++;
00193 return;
00194 }
00195 if (narg != rowlen(np->ap)) {
00196 error(ERROR, "Disagreement in number of macro arguments");
00197 trp->tp->hideset = newhideset(trp->tp->hideset, np);
00198 trp->tp += ntokc;
00199 return;
00200 }
00201 substargs(np, &ntr, atr);
00202 for (i=0; i<narg; i++) {
00203 dofree(atr[i]->bp);
00204 dofree(atr[i]);
00205 }
00206 }
00207 doconcat(&ntr);
00208 hs = newhideset(trp->tp->hideset, np);
00209 for (tp=ntr.bp; tp<ntr.lp; tp++) {
00210 if (tp->type==NAME) {
00211 if (tp->hideset==0)
00212 tp->hideset = hs;
00213 else
00214 tp->hideset = unionhideset(tp->hideset, hs);
00215 }
00216 }
00217 ntr.tp = ntr.bp;
00218 insertrow(trp, ntokc, &ntr);
00219 trp->tp -= rowlen(&ntr);
00220 dofree(ntr.bp);
00221 return;
00222 }
00223
00224
00225
00226
00227
00228
00229 int
00230 gatherargs(Tokenrow *trp, Tokenrow **atr, int *narg)
00231 {
00232 int parens = 1;
00233 int ntok = 0;
00234 Token *bp, *lp;
00235 Tokenrow ttr;
00236 int ntokp;
00237 int needspace;
00238
00239 *narg = -1;
00240
00241 for (;;) {
00242 trp->tp++;
00243 ntok++;
00244 if (trp->tp >= trp->lp) {
00245 gettokens(trp, 0);
00246 if ((trp->lp-1)->type==END) {
00247 trp->lp -= 1;
00248 trp->tp -= ntok;
00249 return ntok;
00250 }
00251 }
00252 if (trp->tp->type==LP)
00253 break;
00254 if (trp->tp->type!=NL)
00255 return ntok;
00256 }
00257 *narg = 0;
00258 ntok++;
00259 ntokp = ntok;
00260 trp->tp++;
00261
00262 needspace = 0;
00263 while (parens>0) {
00264 if (trp->tp >= trp->lp)
00265 gettokens(trp, 0);
00266 if (needspace) {
00267 needspace = 0;
00268 makespace(trp);
00269 }
00270 if (trp->tp->type==END) {
00271 trp->lp -= 1;
00272 trp->tp -= ntok;
00273 error(ERROR, "EOF in macro arglist");
00274 return ntok;
00275 }
00276 if (trp->tp->type==NL) {
00277 trp->tp += 1;
00278 adjustrow(trp, -1);
00279 trp->tp -= 1;
00280 makespace(trp);
00281 needspace = 1;
00282 continue;
00283 }
00284 if (trp->tp->type==LP)
00285 parens++;
00286 else if (trp->tp->type==RP)
00287 parens--;
00288 trp->tp++;
00289 ntok++;
00290 }
00291 trp->tp -= ntok;
00292
00293 lp = bp = trp->tp+ntokp;
00294 for (; parens>=0; lp++) {
00295 if (lp->type == LP) {
00296 parens++;
00297 continue;
00298 }
00299 if (lp->type==RP)
00300 parens--;
00301 if (lp->type==DSHARP)
00302 lp->type = DSHARP1;
00303 if (lp->type==COMMA && parens==0 || parens<0 && (lp-1)->type!=LP) {
00304 if (*narg>=NARG-1)
00305 error(FATAL, "Sorry, too many macro arguments");
00306 ttr.bp = ttr.tp = bp;
00307 ttr.lp = lp;
00308 atr[(*narg)++] = normtokenrow(&ttr);
00309 bp = lp+1;
00310 }
00311 }
00312 return ntok;
00313 }
00314
00315
00316
00317
00318
00319 void
00320 substargs(Nlist *np, Tokenrow *rtr, Tokenrow **atr)
00321 {
00322 Tokenrow tatr;
00323 Token *tp;
00324 int ntok, argno;
00325
00326 for (rtr->tp=rtr->bp; rtr->tp<rtr->lp; ) {
00327 if (rtr->tp->type==SHARP) {
00328 tp = rtr->tp;
00329 rtr->tp += 1;
00330 if ((argno = lookuparg(np, rtr->tp))<0) {
00331 error(ERROR, "# not followed by macro parameter");
00332 continue;
00333 }
00334 ntok = 1 + (rtr->tp - tp);
00335 rtr->tp = tp;
00336 insertrow(rtr, ntok, stringify(atr[argno]));
00337 continue;
00338 }
00339 if (rtr->tp->type==NAME
00340 && (argno = lookuparg(np, rtr->tp)) >= 0) {
00341 if ((rtr->tp+1)->type==DSHARP
00342 || rtr->tp!=rtr->bp && (rtr->tp-1)->type==DSHARP)
00343 insertrow(rtr, 1, atr[argno]);
00344 else {
00345 copytokenrow(&tatr, atr[argno]);
00346 expandrow(&tatr, "<macro>");
00347 insertrow(rtr, 1, &tatr);
00348 dofree(tatr.bp);
00349 }
00350 continue;
00351 }
00352 rtr->tp++;
00353 }
00354 }
00355
00356
00357
00358
00359 void
00360 doconcat(Tokenrow *trp)
00361 {
00362 Token *ltp, *ntp;
00363 Tokenrow ntr;
00364 int len;
00365
00366 for (trp->tp=trp->bp; trp->tp<trp->lp; trp->tp++) {
00367 if (trp->tp->type==DSHARP1)
00368 trp->tp->type = DSHARP;
00369 else if (trp->tp->type==DSHARP) {
00370 char tt[128];
00371 ltp = trp->tp-1;
00372 ntp = trp->tp+1;
00373 if (ltp<trp->bp || ntp>=trp->lp) {
00374 error(ERROR, "## occurs at border of replacement");
00375 continue;
00376 }
00377 len = ltp->len + ntp->len;
00378 strncpy((char*)tt, (char*)ltp->t, ltp->len);
00379 strncpy((char*)tt+ltp->len, (char*)ntp->t, ntp->len);
00380 tt[len] = '\0';
00381 setsource("<##>", -1, tt);
00382 maketokenrow(3, &ntr);
00383 gettokens(&ntr, 1);
00384 unsetsource();
00385 if (ntr.lp-ntr.bp!=2 || ntr.bp->type==UNCLASS)
00386 error(WARNING, "Bad token %r produced by ##", &ntr);
00387 ntr.lp = ntr.bp+1;
00388 trp->tp = ltp;
00389 makespace(&ntr);
00390 insertrow(trp, (ntp-ltp)+1, &ntr);
00391 dofree(ntr.bp);
00392 trp->tp--;
00393 }
00394 }
00395 }
00396
00397
00398
00399
00400
00401
00402 int
00403 lookuparg(Nlist *mac, Token *tp)
00404 {
00405 Token *ap;
00406
00407 if (tp->type!=NAME || mac->ap==NULL)
00408 return -1;
00409 for (ap=mac->ap->bp; ap<mac->ap->lp; ap++) {
00410 if (ap->len==tp->len && strncmp((char*)ap->t,(char*)tp->t,ap->len)==0)
00411 return ap - mac->ap->bp;
00412 }
00413 return -1;
00414 }
00415
00416
00417
00418
00419 #define STRLEN 512
00420 Tokenrow *
00421 stringify(Tokenrow *vp)
00422 {
00423 static Token t = { STRING };
00424 static Tokenrow tr = { &t, &t, &t+1, 1 };
00425 Token *tp;
00426 uchar s[STRLEN];
00427 uchar *sp = s, *cp;
00428 int i, instring;
00429
00430 *sp++ = '"';
00431 for (tp = vp->bp; tp < vp->lp; tp++) {
00432 instring = tp->type==STRING || tp->type==CCON;
00433 if (sp+2*tp->len >= &s[STRLEN-10]) {
00434 error(ERROR, "Stringified macro arg is too long");
00435 break;
00436 }
00437 if (tp->wslen && (tp->flag&XPWS)==0)
00438 *sp++ = ' ';
00439 for (i=0, cp=tp->t; i<tp->len; i++) {
00440 if (instring && (*cp=='"' || *cp=='\\'))
00441 *sp++ = '\\';
00442 *sp++ = *cp++;
00443 }
00444 }
00445 *sp++ = '"';
00446 *sp = '\0';
00447 sp = s;
00448 t.len = strlen((char*)sp);
00449 t.t = newstring(sp, t.len, 0);
00450 return &tr;
00451 }
00452
00453
00454
00455
00456 void
00457 builtin(Tokenrow *trp, int biname)
00458 {
00459 char *op;
00460 Token *tp;
00461 Source *s;
00462
00463 tp = trp->tp;
00464 trp->tp++;
00465
00466 s = cursource;
00467 while (s && s->fd==-1)
00468 s = s->next;
00469 if (s==NULL)
00470 s = cursource;
00471
00472 tp->type = STRING;
00473 if (tp->wslen) {
00474 *outp++ = ' ';
00475 tp->wslen = 1;
00476 }
00477 op = outp;
00478 *op++ = '"';
00479 switch (biname) {
00480
00481 case KLINENO:
00482 tp->type = NUMBER;
00483 op = outnum(op-1, s->line);
00484 break;
00485
00486 case KFILE: {
00487 char *src = s->filename;
00488 while ((*op++ = *src++) != 0)
00489 if (src[-1] == '\\')
00490 *op++ = '\\';
00491 op--;
00492 break;
00493 }
00494
00495 case KDATE:
00496 strncpy(op, curtime+4, 7);
00497 strncpy(op+7, curtime+20, 4);
00498 op += 11;
00499 break;
00500
00501 case KTIME:
00502 strncpy(op, curtime+11, 8);
00503 op += 8;
00504 break;
00505
00506 default:
00507 error(ERROR, "cpp botch: unknown internal macro");
00508 return;
00509 }
00510 if (tp->type==STRING)
00511 *op++ = '"';
00512 tp->t = (uchar*)outp;
00513 tp->len = op - outp;
00514 outp = op;
00515 }