Print this page
cpp: squash spaces correctly-ish whilst pasting macros
Sun cpp removes all leading and trailing space from a macro pasting, and
compress whitespace in the macro body to a single space character.
There is some deviation from this in the Sun implementation which we
don't duplicate.
1) The presence of comments in the macro body affect the minimization of
   runs of spaces.
2) When newlines are encountered in the parameter list of a macro
   invocation, Sun cpp inserts that many newlines prior to any of the
   pasted text, and then in the pasted text pastes those newlines as
   (minimized) spaces.  Escaped new-lines are de-escaped, and otherwise
   treated similarly (in effect, the \ is removed).


1185 
1186 static struct symtab *
1187 slookup(p1,p2,enterf) register char *p1,*p2; int enterf;{
1188         register char *p3; char c2,c3; struct symtab *np;
1189         c2= *p2; *p2='\0';      /* mark end of token */
1190         if ((p2-p1)>symlen)
1191                 p3=p1+symlen;
1192         else
1193                 p3=p2;
1194         c3= *p3; *p3='\0';      /* truncate to symlen chars or less */
1195         if (enterf==1)
1196                 p1=copy(p1);
1197         np=lookup(p1,enterf); *p3=c3; *p2=c2;
1198         if (np->value!=0 && flslvl==0)
1199                 newp=subst(p2,np);
1200         else
1201                 newp=0;
1202         return(np);
1203 }
1204 





1205 static char *
1206 subst(p,sp) register char *p; struct symtab *sp; {
1207         static char match[]="%s: argument mismatch";
1208         register char *ca,*vp; int params;
1209         char *actual[MAXFRM]; /* actual[n] is text of nth actual */
1210         char acttxt[BUFFERSIZ]; /* space for actuals */



1211 
1212         if (0==(vp=sp->value)) return(p);
1213         if ((p-macforw)<=macdam) {
1214                 if (++maclvl>symsiz && !rflag) {
1215                         pperror("%s: macro recursion",sp->name);
1216                         return(p);
1217                 }
1218         } else {
1219                 maclvl=0;       /* level decreased */
1220         }
1221         macforw=p; macdam=0;    /* new target for decrease in level */
1222         macnam=sp->name;

1223         dump();
1224         if (sp==ulnloc) {
1225                 vp=acttxt; *vp++='\0';
1226                 sprintf(vp,"%d",lineno[ifno]); while (*vp++);
1227         } else if (sp==uflloc) {
1228                 vp=acttxt; *vp++='\0';
1229                 sprintf(vp,"\"%s\"",fnames[ifno]); while (*vp++);
1230         }
1231         if (0!=(params= *--vp&0xFF)) {/* definition calls for params */
1232                 register char **pa;
1233                 ca=acttxt; pa=actual;
1234                 if (params==0xFF)
1235                         params=1;       /* #define foo() ... */
1236                 sloscan();
1237                 ++flslvl; /* no expansion during search for actuals */
1238                 plvl= -1;
1239                 do p=skipbl(p); while (*inp=='\n');     /* skip \n too */
1240                 if (*inp=='(') {
1241                         maclin=lineno[ifno]; macfil=fnames[ifno];
1242                         for (plvl=1; plvl!=0; ) {


1245                                         outp=inp=p; p=cotoken(p);
1246                                         if (*inp=='(') ++plvl;
1247                                         if (*inp==')' && --plvl==0) {
1248                                                 --params;
1249                                                 break;
1250                                         }
1251                                         if (plvl==1 && *inp==',') {
1252                                                 --params;
1253                                                 break;
1254                                         }
1255                                         while (inp<p) {
1256                                                 /*
1257                                                  * Sun cpp compatibility.
1258                                                  * Needed for kernel assembler
1259                                                  * preprocessing.
1260                                                  * Replace newlines in actual
1261                                                  * macro parameters by spaces.
1262                                                  * Keep escaped newlines, they
1263                                                  * are assumed to be inside a
1264                                                  * string.














1265                                                  */
1266                                                 if (*inp == '\n' &&
1267                                                     inp[-1] != '\\')
1268                                                         *inp = ' ';
1269                                                 *ca++= *inp++;
1270                                         }
1271                                         if (ca> &acttxt[BUFFERSIZ])
1272                                                 pperror("%s: actuals too long",
1273                                                     sp->name);
1274                                 }
1275                                 if (pa>= &actual[MAXFRM])
1276                                         ppwarn(match,sp->name);
1277                                 else
1278                                         *pa++=ca;
1279                         }
1280                 }
1281                 if (params!=0)
1282                         ppwarn(match,sp->name);
1283                 while (--params>=0)
1284                         *pa++=""+1;     /* null string for missing actuals */
1285                 --flslvl; fasscan();
1286         }

1287         for (;;) {/* push definition onto front of input stack */





1288                 while (!iswarn(*--vp)) {
1289                         if (bob(p)) {outp=inp=p; p=unfill(p);}























1290                         *--p= *vp;

1291                 }
1292                 if (*vp==warnc) {/* insert actual param */

1293                         ca=actual[*--vp-1];
1294                         while (*--ca) {
1295                                 if (bob(p)) {outp=inp=p; p=unfill(p);}
1296                                 *--p= *ca;











1297                         }
1298                 } else break;
1299         }
1300         outp=inp=p;
1301         return(p);
1302 }
1303 
1304 static char *
1305 trmdir(s) register char *s; {
1306         register char *p = s;
1307         while (*p++); --p; while (p>s && *--p!='/');
1308 # if unix
1309         if (p==s) *p++='.';
1310 # endif
1311         *p='\0';
1312         return(s);
1313 }
1314 
1315 static char *
1316 copy(s) register char *s; {
1317         register char *old;
1318 




1185 
1186 static struct symtab *
1187 slookup(p1,p2,enterf) register char *p1,*p2; int enterf;{
1188         register char *p3; char c2,c3; struct symtab *np;
1189         c2= *p2; *p2='\0';      /* mark end of token */
1190         if ((p2-p1)>symlen)
1191                 p3=p1+symlen;
1192         else
1193                 p3=p2;
1194         c3= *p3; *p3='\0';      /* truncate to symlen chars or less */
1195         if (enterf==1)
1196                 p1=copy(p1);
1197         np=lookup(p1,enterf); *p3=c3; *p2=c2;
1198         if (np->value!=0 && flslvl==0)
1199                 newp=subst(p2,np);
1200         else
1201                 newp=0;
1202         return(np);
1203 }
1204 
1205 /*
1206  * When a macro substitution must happen, arrange the input stack based on the
1207  * macro definition and any parameters such that the expanded macro is what is
1208  * next read by the preprocessor as if it were input
1209  */
1210 static char *
1211 subst(p,sp) register char *p; struct symtab *sp; {
1212         static char match[]="%s: argument mismatch";
1213         register char *ca,*vp; int params;
1214         char *actual[MAXFRM]; /* actual[n] is text of nth actual */
1215         char acttxt[BUFFERSIZ]; /* space for actuals */
1216         /* State while pasting, TRAIL is trailing space, INTRA is in the body */
1217         enum { TRAIL, INTRA } state = TRAIL;
1218         int pasted = 0;         /* # of character pasted */
1219 
1220         if (0==(vp=sp->value)) return(p);
1221         if ((p-macforw)<=macdam) {
1222                 if (++maclvl>symsiz && !rflag) {
1223                         pperror("%s: macro recursion",sp->name);
1224                         return(p);
1225                 }
1226         } else {
1227                 maclvl=0;       /* level decreased */
1228         }
1229         macforw=p; macdam=0;    /* new target for decrease in level */
1230         macnam=sp->name;
1231         /* flush all buffered output prior to the expansion */
1232         dump();
1233         if (sp==ulnloc) {
1234                 vp=acttxt; *vp++='\0';
1235                 sprintf(vp,"%d",lineno[ifno]); while (*vp++);
1236         } else if (sp==uflloc) {
1237                 vp=acttxt; *vp++='\0';
1238                 sprintf(vp,"\"%s\"",fnames[ifno]); while (*vp++);
1239         }
1240         if (0!=(params= *--vp&0xFF)) {/* definition calls for params */
1241                 register char **pa;
1242                 ca=acttxt; pa=actual;
1243                 if (params==0xFF)
1244                         params=1;       /* #define foo() ... */
1245                 sloscan();
1246                 ++flslvl; /* no expansion during search for actuals */
1247                 plvl= -1;
1248                 do p=skipbl(p); while (*inp=='\n');     /* skip \n too */
1249                 if (*inp=='(') {
1250                         maclin=lineno[ifno]; macfil=fnames[ifno];
1251                         for (plvl=1; plvl!=0; ) {


1254                                         outp=inp=p; p=cotoken(p);
1255                                         if (*inp=='(') ++plvl;
1256                                         if (*inp==')' && --plvl==0) {
1257                                                 --params;
1258                                                 break;
1259                                         }
1260                                         if (plvl==1 && *inp==',') {
1261                                                 --params;
1262                                                 break;
1263                                         }
1264                                         while (inp<p) {
1265                                                 /*
1266                                                  * Sun cpp compatibility.
1267                                                  * Needed for kernel assembler
1268                                                  * preprocessing.
1269                                                  * Replace newlines in actual
1270                                                  * macro parameters by spaces.
1271                                                  * Keep escaped newlines, they
1272                                                  * are assumed to be inside a
1273                                                  * string.
1274                                                  * 
1275                                                  * XXX: The above is actually
1276                                                  * false in a couple of ways.
1277                                                  *
1278                                                  * 1) Sun cpp turns newlines
1279                                                  * into spaces, but inserts an
1280                                                  * equal number of newlines
1281                                                  * prior to pasting the body.
1282                                                  *
1283                                                  * 2) Sun does _not_ preserved
1284                                                  * escaped newlines, the \ is
1285                                                  * removed, and the newline
1286                                                  * otherwise treated
1287                                                  * identically to in #1.
1288                                                  */
1289                                                 if (*inp == '\n' &&
1290                                                     inp[-1] != '\\')
1291                                                         *inp = ' ';
1292                                                 *ca++= *inp++;
1293                                         }
1294                                         if (ca> &acttxt[BUFFERSIZ])
1295                                                 pperror("%s: actuals too long",
1296                                                     sp->name);
1297                                 }
1298                                 if (pa>= &actual[MAXFRM])
1299                                         ppwarn(match,sp->name);
1300                                 else
1301                                         *pa++=ca;
1302                         }
1303                 }
1304                 if (params!=0)
1305                         ppwarn(match,sp->name);
1306                 while (--params>=0)
1307                         *pa++=""+1;     /* null string for missing actuals */
1308                 --flslvl; fasscan();
1309         }
1310 
1311         for (;;) {/* push definition onto front of input stack */
1312                 /*
1313                  * Loop until we hit the end of the macro, or a parameter
1314                  * placement.  Note that we expand the macro into the input
1315                  * backwards (so it replays forwards.)
1316                  */
1317                 while (!iswarn(*--vp)) {
1318                         if (bob(p)) {outp=inp=p; p=unfill(p);}
1319                                 
1320                         /* Unless we are mid-paste, swallow all spaces */
1321                         if (state == TRAIL) {
1322                                 while (isspace(*vp) && !iswarn(*vp))
1323                                         vp--;
1324                         } else {
1325                                 /*
1326                                  * If we're mid-paste, compress spaces to a
1327                                  * single space
1328                                  */
1329                                 while (isspace(*vp)) {
1330                                         if (!isspace(vp[1])) {
1331                                                 *vp = ' ';
1332                                                 break;
1333                                         } else {
1334                                                 vp--;
1335                                         }
1336                                 }
1337                         }
1338                         state = INTRA; /* Hit a non-space */
1339                         
1340                         if (iswarn(*vp))
1341                                 break;
1342                         *--p= *vp;
1343                         pasted++;
1344                 }
1345                 if (*vp==warnc) {/* insert actual param */
1346                         state = INTRA;
1347                         ca=actual[*--vp-1];
1348                         while (*--ca) {
1349                                 if (bob(p)) {outp=inp=p; p=unfill(p);}
1350                                 *--p= *ca;
1351                                 pasted++;
1352                         }
1353                 } else {
1354                         /*
1355                          * Trim leading spaces, but only those from our pasting
1356                          */
1357                         while (isspace(*p) && pasted > 0) {
1358                                 p++;
1359                                 pasted--;
1360                         }
1361                         break;
1362                 }

1363         }
1364         outp=inp=p;
1365         return(p);
1366 }
1367 
1368 static char *
1369 trmdir(s) register char *s; {
1370         register char *p = s;
1371         while (*p++); --p; while (p>s && *--p!='/');
1372 # if unix
1373         if (p==s) *p++='.';
1374 # endif
1375         *p='\0';
1376         return(s);
1377 }
1378 
1379 static char *
1380 copy(s) register char *s; {
1381         register char *old;
1382