Quick Search:

Mode

Context

Displaying the whole file. None | Less | More | Full

Other Diffs

Ignore

Blank Lines Whitespace: Expand:

Diff

1.103
 
1.104
 
MAIN:plunky:20121108111136
 
token.c
_>11 /*      $Id$    */
 22 
 33 /*
 44  * Copyright (c) 2004,2009 Anders Magnusson. All rights reserved.
 55  *
 66  * Redistribution and use in source and binary forms, with or without
 77  * modification, are permitted provided that the following conditions
 88  * are met:
 99  * 1. Redistributions of source code must retain the above copyright
 1010  *    notice, this list of conditions and the following disclaimer.
 1111  * 2. Redistributions in binary form must reproduce the above copyright
 1212  *    notice, this list of conditions and the following disclaimer in the
 1313  *    documentation and/or other materials provided with the distribution.
 1414  *
 1515  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 1616  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 1717  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 1818  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 1919  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 2020  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 2121  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 2222  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 2323  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 2424  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 2525  */
 2626 
 2727 /*
 2828  * Tokenizer for the C preprocessor.
 2929  * There are three main routines:
 3030  *      - fastscan() loops over the input stream searching for magic
 3131  *              characters that may require actions.
 3232  *      - sloscan() tokenize the input stream and returns tokens.
 3333  *              It may recurse into itself during expansion.
 3434  *      - yylex() returns something from the input stream that
 3535  *              is suitable for yacc.
 3636  *
 3737  *      Other functions of common use:
 3838  *      - inpch() returns a raw character from the current input stream.
 3939  *      - inch() is like inpch but \\n and trigraphs are expanded.
 4040  *      - unch() pushes back a character to the input stream.
 4141  */
 4242 
 4343 #include "config.h"
 4444 
 4545 #include <stdlib.h>
 4646 #include <string.h>
 4747 #ifdef HAVE_UNISTD_H
 4848 #include <unistd.h>
 4949 #endif
 5050 #include <fcntl.h>
 5151 
 5252 #include "compat.h"
 5353 #include "cpp.h"
 5454 #include "cpy.h"
 5555 
 5656 static void cvtdig(int rad);
 5757 static int charcon(usch *);
 5858 static void elsestmt(void);
 5959 static void ifdefstmt(void);
 6060 static void ifndefstmt(void);
 6161 static void endifstmt(void);
 6262 static void ifstmt(void);
 6363 static void cpperror(void);
 6464 static void cppwarning(void);
 6565 static void undefstmt(void);
 6666 static void pragmastmt(void);
 6767 static void elifstmt(void);
 6868 
 6969 #define PUTCH(ch) if (!flslvl) putch(ch)
 7070 /* protection against recursion in #include */
 7171 #define MAX_INCLEVEL    100
 7272 static int inclevel;
 7373 
 7474 usch yytext[CPPBUF];
 7575 
 7676 struct includ *ifiles;
 7777 
 7878 /* some common special combos for init */
 7979 #define C_NL    (C_SPEC|C_WSNL)
 8080 #define C_DX    (C_SPEC|C_ID|C_DIGIT|C_HEX)
 8181 #define C_I     (C_SPEC|C_ID|C_ID0)
 8282 #define C_IP    (C_SPEC|C_ID|C_ID0|C_EP)
 8383 #define C_IX    (C_SPEC|C_ID|C_ID0|C_HEX)
 8484 #define C_IXE   (C_SPEC|C_ID|C_ID0|C_HEX|C_EP)
 8585 
 8686 usch spechr[256] = {
 8787         0,      0,      0,      0,      C_SPECC_SPEC0,      0,
 8888         0,      C_WSNLC_NL,   0,      0,      C_WSNL0,      0,
 8989         0,      0,      0,      0,      0,      0,      0,      0,
 9090         0,      0,      0,      0,      0,      0,      0,      0,
 9191 
 9292         C_WSNLC_2,    C_SPEC0,      0,      0,      C_2,    C_SPEC,
 9393         0,      0,      0,      C_2,    0,      C_2,    0,      C_SPEC|C_2,
 9494         C_DX,   C_DX,   C_DX,   C_DX,   C_DX,   C_DX,   C_DX,   C_DX,
 9595         C_DX,   C_DX,   0,      0,      C_2,    C_2,    C_2,    0,
 9696 
 9797         0,      C_IX,   C_IX,   C_IX,   C_IX,   C_IXE,  C_IX,   C_I,
 9898         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
 9999         C_IP,   C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
 100100         C_I,    C_I,    C_I,    0,      0,      0,      0,      C_I,
 101101 
 102102         0,      C_IX,   C_IX,   C_IX,   C_IX,   C_IXE,  C_IX,   C_I,
 103103         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
 104104         C_IP,   C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
 105105         C_I,    C_I,    C_I,    0,      C_2,    0,      0,      0,
 106106 };
 107107 
 108108 /*
 109109  * fill up the input buffer
 110110  */
 111111 static int
 112112 inpbuf(void)
 113113 {
 114114         int len;
 115115 
 116116         if (ifiles->infil == -1)
 117117                 return 0;
 118118         len = read(ifiles->infil, ifiles->buffer, CPPBUF);
 119119         if (len == -1)
 120120                 error("read error on file %s", ifiles->orgfn);
 121121         if (len > 0) {
 122122                 ifiles->buffer[len] = 0;
 123123                 ifiles->curptr = ifiles->buffer;
 124124                 ifiles->maxread = ifiles->buffer + len;
 125125         }
 126126         return len;
 127127 }
 128128 
 129129 /*
 130130  * return a raw character from the input stream
 131131  */
 132132 static inline int
 133133 inpch(void)
 134134 {
 135135 
 136136         do {
 137137                 if (ifiles->curptr < ifiles->maxread)
 138138                         return *ifiles->curptr++;
 139139         } while (inpbuf() > 0);
 140140 
 141141         return -1;
 142142 }
 143143 
 144144 /*
 145145  * push a character back to the input stream
 146146  */
 147147 static void
 148148 unch(int c)
 149149 {
 150150         if (c == -1)
 151151                 return;
 152152                 
 153153         ifiles->curptr--;
 154154         if (ifiles->curptr < ifiles->bbuf)
 155155                 error("pushback buffer full");
 156156         *ifiles->curptr = (usch)c;
 157157 }
 158158 
 159159 /*
 160160  * Check for (and convert) trigraphs.
 161161  */
 162162 static int
 163163 chktg(void)
 164164 {
 165165         int ch;
 166166 
 167167         if ((ch = inpch()) != '?') {
 168168                 unch(ch);
 169169                 return 0;
 170170         }
 171171 
 172172         switch (ch = inpch()) {
 173173         case '='return '#';
 174174         case '('return '[';
 175175         case ')'return ']';
 176176         case '<'return '{';
 177177         case '>'return '}';
 178178         case '/'return '\\';
 179179         case '\'': return '^';
 180180         case '!'return '|';
 181181         case '-'return '~';
 182182         }
 183183 
 184184         unch(ch);
 185185         unch('?');
 186186         return 0;
 187187 }
 188188 
 189189 /*
 190190  * check for (and eat) end-of-line
 191191  */
 192192 static int
 193193 chkeol(void)
 194194 {
 195195         int ch;
 196196 
 197197         ch = inpch();
 198198         if (ch == '\r') {
 199199                 ch = inpch();
 200200                 if (ch == '\n')
 201201                         return '\n';
 202202 
 203203                 unch(ch);
 204204                 unch('\r');
 205205                 return 0;
 206206         }
 207207         if (ch == '\n')
 208208                 return '\n';
 209209 
 210210         unch(ch);
 211211         return 0;
 212212 }
 213213 
 214214 /*
 215215  * return next char, after converting trigraphs and
 216216  * skipping escaped line endings
 217217  */
 218218 static inline int
 219219 inch(void)
 220220 {
 221221         int ch;
 222222 
 223223         for (;;) {
 224224                 ch = inpch();
 225225                 if (ch == '?' && (ch = chktg()) == 0)
 226226                         return '?';
 227227                 if (ch != '\\' || chkeol() == 0)
 228228                         return ch;
 229229                 ifiles->escln++;
 230230         }
 231231 }
 232232 
 233233 static void
 234234 eatcmnt(void)
 235235 {
 236236         int ch;
 237237 
 238238         if (Cflag) { PUTCH('/'); PUTCH('*'); }
 239239         for (;;) {
 240240                 ch = inch();
 241241                 if (ch == '\n') {
 242242                         ifiles->lineno++;
 243243                         putch('\n');
 244244                         continue;
 245245                 }
 246246                 if (ch == -1)
 247247                         break;
 248248                 if (ch == '*') {
 249249                         ch = inch();
 250250                         if (ch == '/') {
 251251                                 if (Cflag) {
 252252                                         PUTCH('*');
 253253                                         PUTCH('/');
 254254                                 } else
 255255                                         PUTCH(' ');
 256256                                 break;
 257257                         }
 258258                         unch(ch);
 259259                         ch = '*';
 260260                 }
 261261                 if (Cflag) PUTCH(ch);
 262262         }
 263263 }
 264264 
 265265 /*
 266266  * Scan quickly the input file searching for:
 267267  *      - '#' directives
 268268  *      - keywords (if not flslvl)
 269269  *      - comments
 270270  *
 271271  *      Handle strings, numbers and trigraphs with care.
 272272  *      Only data from pp files are scanned here, never any rescans.
 273273  *      TODO: Only print out strings before calling other functions.
 274274  */
 275275 static void
 276276 fastscan(void)
 277277 {
 278278         struct symtab *nl;
 279279         int ch, i;
 280280         usch *cp;
 281281 
 282282         goto run;
 283283         for (;;) {
 284284                 ch = inch();
 285285 xloop:          if (ch == -1)
 286286                         return;
 287287 #ifdef PCC_DEBUG
 288288                 if (dflag>1)
 289289                         printf("fastscan ch %d (%c)\n", ch, ch > 31 ? ch : '@');
 290290 #endif
 291291                 if ((spechr[ch] & C_SPEC) == 0) {
 292292                         PUTCH(ch);
 293293                         continue;
 294294                 }
 295295                 switch (ch) {
 296296                 case EBLOCK:
 297297                 case WARN:
 298298                 case CONC:
 299299                         error("bad char passed");
 300300                         break;
 301301 
 302302                 case '/': /* Comments */
 303303                         if ((ch = inch()) == '/') {
 304304 cppcmt:                         if (Cflag) { PUTCH(ch); } else { PUTCH(' '); }
 305305                                 do {
 306306                                         if (Cflag) PUTCH(ch);
 307307                                         ch = inch();
 308308                                 } while (ch != -1 && ch != '\n');
 309309                                 goto xloop;
 310310                         } else if (ch == '*') {
 311311                                 eatcmnt();
 312312                         } else {
 313313                                 PUTCH('/');
 314314                                 goto xloop;
 315315                         }
 316316                         break;
 317317 
 318318                 case '\n': /* newlines, for pp directives */
 319319                         i = ifiles->escln + 1;
 320320                         ifiles->lineno += i;
 321321                         ifiles->escln = 0;
 322322                         while (i-- > 0)
 323323                                 putch('\n');
 324324 run:                    for(;;) {
 325325                                 ch = inch();
 326326                                 if (ch == '/') {
 327327                                         ch = inch();
 328328                                         if (ch == '/')
 329329                                                 goto cppcmt;
 330330                                         if (ch == '*') {
 331331                                                 eatcmnt();
 332332                                                 continue;
 333333                                         }
 334334                                         unch(ch);
 335335                                         ch = '/';
 336336                                 }
 337337                                 if (ch != ' ' && ch != '\t')
 338338                                         break;
 339339                                 PUTCH(ch);
 340340                         }
 341341                         if (ch == '#') {
 342342                                 ppdir();
 343343                                 continue;
 344344                         } else if (ch == '%') {
 345345                                 ch = inch();
 346346                                 if (ch == ':') {
 347347                                         ppdir();
 348348                                         continue;
 349349                                 }
 350350                                 unch(ch);
 351351                                 ch = '%';
 352352                         }
 353353                         goto xloop;
 354354 
 355355                 case '\"': /* strings */
 356356 str:                    PUTCH(ch);
 357357                         while ((ch = inch()) != '\"') {
 358358                                 if (ch == '\\') {
 359359                                         PUTCH('\\');
 360360                                         ch = inch();
 361361                                 }
<>362 -                                if (ch == '\n')
  362+                                if (ch == '\n') {
  363+                                        warning("unterminated string literal");
363364                                         goto xloop;
<> 365+                                }
364366                                 if (ch == -1)
 365367                                         return;
 366368                                 PUTCH(ch);
 367369                         }
 368370                         PUTCH(ch);
 369371                         break;
 370372 
 371373                 case '.'/* for pp-number */
 372374                         PUTCH(ch);
 373375                         ch = inch();
 374376                         if (ch < '0' || ch > '9')
 375377                                 goto xloop;
 376378 
 377379                         /* FALLTHROUGH */
 378380                 case '0': case '1': case '2': case '3': case '4':
 379381                 case '5': case '6': case '7': case '8': case '9':
 380382                         do {
 381383 nxp:                            PUTCH(ch);
 382384                                 ch = inch();
 383385                                 if (ch == -1)
 384386                                         return;
 385387                                 if (spechr[ch] & C_EP) {
 386388                                         PUTCH(ch);
 387389                                         ch = inch();
 388390                                         if (ch == '-' || ch == '+')
 389391                                                 goto nxp;
 390392                                         if (ch == -1)
 391393                                                 return;
 392394                                 }
 393395                         } while ((spechr[ch] & C_ID) || (ch == '.'));
 394396                         goto xloop;
 395397 
<>396 -                case '\'': /* character literal */
  398+                case '\'': /* character constant */
397399 con:                    PUTCH(ch);
 398400                         if (tflag)
 399401                                 break; /* character constants ignored */
 400402                         while ((ch = inch()) != '\'') {
 401403                                 if (ch == '\\') {
 402404                                         PUTCH('\\');
 403405                                         ch = inch();
 404406                                 }
<>405 -                                if (ch == '\n')
  407+                                if (ch == '\n') {
  408+                                        warning("unterminated character constant");
406409                                         goto xloop;
<> 410+                                }
<_407411                                 if (ch == -1)
 408412                                         return;
 409413                                 PUTCH(ch);
 410414                         }
 411415                         PUTCH(ch);
 412416                         break;
 413417 
 414418                 case 'L':
 415419                         ch = inch();
 416420                         if (ch == '\"') {
 417421                                 PUTCH('L');
 418422                                 goto str;
 419423                         }
 420424                         if (ch == '\'') {
 421425                                 PUTCH('L');
 422426                                 goto con;
 423427                         }
 424428                         unch(ch);
 425429                         ch = 'L';
 426430 
 427431                         /* FALLTHROUGH */
 428432                 default:
 429433 #ifdef PCC_DEBUG
 430434                         if ((spechr[ch] & C_ID) == 0)
 431435                                 error("fastscan");
 432436 #endif
 433437                         i = 0;
 434438                         do {
 435439                                 yytext[i++] = (usch)ch;
 436440                                 ch = inch();
 437441                         } while (ch != -1 && (spechr[ch] & C_ID));
 438442 
 439443                         if (flslvl)
 440444                                 goto xloop;
 441445 
 442446                         yytext[i] = 0;
 443447                         unch(ch);
 444448 
 445449                         cp = stringbuf;
 446450                         if ((nl = lookup(yytext, FIND)) && kfind(nl)) {
 447451                                 putstr(stringbuf);
 448452                         } else
 449453                                 putstr(yytext);
 450454                         stringbuf = cp;
 451455 
 452456                         break;
 453457                 }
 454458         }
 455459 }
 456460 
 457461 int
 458462 sloscan(void)
 459463 {
 460464         int ch;
 461465         int yyp;
 462466 
 463467 zagain:
 464468         yyp = 0;
 465469         ch = inch();
 466470         yytext[yyp++] = (usch)ch;
 467471         switch (ch) {
 468472         case -1:
 469473                 return 0;
 470474         case '\n':
 471475                 /* sloscan() never passes \n, that's up to fastscan() */
 472476                 unch(ch);
 473477                 yytext[yyp] = 0;
 474478                 return ch;
 475479 
 476480         case '\r': /* Ignore CR's */
 477481                 yyp = 0;
 478482                 break;
 479483 
 480484         case '0': case '1': case '2': case '3': case '4': case '5':
 481485         case '6': case '7': case '8': case '9':
 482486                 /* readin a "pp-number" */
 483487 ppnum:          for (;;) {
 484488                         ch = inch();
 485489                         if (ch == -1)
 486490                                 break;
 487491                         if (spechr[ch] & C_EP) {
 488492                                 yytext[yyp++] = (usch)ch;
 489493                                 ch = inch();
 490494                                 if (ch == '-' || ch == '+') {
 491495                                         yytext[yyp++] = (usch)ch;
 492496                                 } else
 493497                                         unch(ch);
 494498                                 continue;
 495499                         }
 496500                         if ((spechr[ch] & C_ID) || ch == '.') {
 497501                                 yytext[yyp++] = (usch)ch;
 498502                                 continue;
 499503                         }
 500504                         break;
 501505                 }
 502506                 unch(ch);
 503507                 yytext[yyp] = 0;
 504508 
 505509                 return NUMBER;
 506510 
 507511         case '\'':
 508512 chlit:          
 509513                 for (;;) {
 510514                         if ((ch = inch()) == '\\') {
 511515                                 yytext[yyp++] = (usch)ch;
 512516                                 yytext[yyp++] = (usch)inch();
 513517                                 continue;
 514518                         } else if (ch == -1 || ch == '\n') {
 515519                                 /* not a constant */
 516520                                 while (yyp > 1)
 517521                                         unch(yytext[--yyp]);
 518522                                 ch = '\'';
 519523                                 goto any;
 520524                         } else
 521525                                 yytext[yyp++] = (usch)ch;
 522526                         if (ch == '\'')
 523527                                 break;
 524528                 }
 525529                 yytext[yyp] = 0;
 526530 
 527531                 return NUMBER;
 528532 
 529533         case ' ':
 530534         case '\t':
 531535                 while ((ch = inch()) == ' ' || ch == '\t')
 532536                         yytext[yyp++] = (usch)ch;
 533537                 unch(ch);
 534538                 yytext[yyp] = 0;
 535539                 return WSPACE;
 536540 
 537541         case '/':
 538542                 if ((ch = inch()) == '/') {
 539543                         do {
 540544                                 yytext[yyp++] = (usch)ch;
 541545                                 ch = inch();
 542546                         } while (ch != -1 && ch != '\n');
 543547                         yytext[yyp] = 0;
 544548                         unch(ch);
 545549                         goto zagain;
 546550                 } else if (ch == '*') {
 547551                         int c, wrn;
 548552                         extern int readmac;
 549553 
 550554                         if (Cflag && !flslvl && readmac) {
 551555                                 unch(ch);
 552556                                 yytext[yyp] = 0;
 553557                                 return CMNT;
 554558                         }
 555559 
 556560                         wrn = 0;
 557561                 more:   while ((c = inch()) != '*') {
 558562                                 if (c == -1)
 559563                                         return 0;       
 560564                                 if (c == '\n')
 561565                                         putch(c), ifiles->lineno++;
 562566                                 else if (c == EBLOCK) {
 563567                                         (void)inch();
 564568                                         (void)inch();
 565569                                 } else if (c == WARN)
 566570                                         wrn = 1;
 567571                         }
 568572                         if ((c = inch()) == -1)
 569573                                 return 0;
 570574                         if (c != '/') {
 571575                                 unch(c);
 572576                                 goto more;
 573577                         }
 574578                         if (!tflag && !Cflag && !flslvl)
 575579                                 unch(' ');
 576580                         if (wrn)
 577581                                 unch(WARN);
 578582                         goto zagain;
 579583                 }
 580584                 unch(ch);
 581585                 ch = '/';
 582586                 goto any;
 583587 
 584588         case '.':
 585589                 if ((ch = inch()) == -1)
 586590                         return 0;
 587591                 if ((spechr[ch] & C_DIGIT)) {
 588592                         yytext[yyp++] = (usch)ch;
 589593                         goto ppnum;
 590594                 } else {
 591595                         unch(ch);
 592596                         ch = '.';
 593597                 }
 594598                 goto any;
 595599 
 596600         case '\"':
 597601                 if (tflag && defining)
 598602                         goto any;
 599603         strng:
 600604                 for (;;) {
 601605                         if ((ch = inch()) == '\\') {
 602606                                 yytext[yyp++] = (usch)ch;
 603607                                 yytext[yyp++] = (usch)inch();
 604608                                 continue;
 605609                         } else if (ch == -1) {
 606610                                 break;
 607611                         } else
 608612                                 yytext[yyp++] = (usch)ch;
 609613                         if (ch == '\"')
 610614                                 break;
 611615                 }
 612616                 yytext[yyp] = 0;
 613617                 return STRING;
 614618 
 615619         case 'L':
 616620                 if ((ch = inch()) == '\"' && !tflag) {
 617621                         yytext[yyp++] = (usch)ch;
 618622                         goto strng;
 619623                 } else if (ch == '\'' && !tflag) {
 620624                         yytext[yyp++] = (usch)ch;
 621625                         goto chlit;
 622626                 }
 623627                 unch(ch);
 624628                 /* FALLTHROUGH */
 625629 
 626630         /* Yetch, all identifiers */
 627631         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
 628632         case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
 629633         case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
 630634         case 's': case 't': case 'u': case 'v': case 'w': case 'x':
 631635         case 'y': case 'z':
 632636         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
 633637         case 'G': case 'H': case 'I': case 'J': case 'K':
 634638         case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
 635639         case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
 636640         case 'Y': case 'Z':
 637641         case '_': /* {L}({L}|{D})* */
 638642 
 639643                 /* Special hacks */
 640644                 for (;;) { /* get chars */
 641645                         if ((ch = inch()) == -1)
 642646                                 break;
 643647                         if ((spechr[ch] & C_ID)) {
 644648                                 yytext[yyp++] = (usch)ch;
 645649                         } else {
 646650                                 unch(ch);
 647651                                 break;
 648652                         }
 649653                 }
 650654                 yytext[yyp] = 0; /* need already string */
 651655                 /* end special hacks */
 652656 
 653657                 return IDENT;
 654658         default:
 655659         any:
 656660                 yytext[yyp] = 0;
 657661                 return yytext[0];
 658662 
 659663         } /* endcase */
 660664         goto zagain;
 661665 }
 662666 
 663667 int
 664668 yylex(void)
 665669 {
 666670         static int ifdef, noex;
 667671         struct symtab *nl;
 668672         int ch, c2;
 669673 
 670674         while ((ch = sloscan()) == WSPACE)
 671675                 ;
 672676         if (ch < 128 && (spechr[ch] & C_2))
 673677                 c2 = inch();
 674678         else
 675679                 c2 = 0;
 676680 
 677681         switch (ch) {
 678682         case '=':
 679683                 if (c2 == '=') return EQ;
 680684                 break;
 681685         case '!':
 682686                 if (c2 == '=') return NE;
 683687                 break;
 684688         case '|':
 685689                 if (c2 == '|') return OROR;
 686690                 break;
 687691         case '&':
 688692                 if (c2 == '&') return ANDAND;
 689693                 break;
 690694         case '<':
 691695                 if (c2 == '<') return LS;
 692696                 if (c2 == '=') return LE;
 693697                 break;
 694698         case '>':
 695699                 if (c2 == '>') return RS;
 696700                 if (c2 == '=') return GE;
 697701                 break;
 698702         case '+':
 699703         case '-':
 700704                 if (ch == c2)
 701705                         error("invalid preprocessor operator %c%c", ch, c2);
 702706                 break;
 703707 
 704708         case '/':
 705709                 if (Cflag == 0 || c2 != '*')
 706710                         break;
 707711                 /* Found comment that need to be skipped */
 708712                 for (;;) {
 709713                         ch = inch();
 710714                 c1:     if (ch != '*')
 711715                                 continue;
 712716                         if ((ch = inch()) == '/')
 713717                                 break;
 714718                         goto c1;
 715719                 }
 716720                 return yylex();
 717721 
 718722         case NUMBER:
 719723                 if (yytext[0] == '\'') {
 720724                         yylval.node.op = NUMBER;
 721725                         yylval.node.nd_val = charcon(yytext);
 722726                 } else
 723727                         cvtdig(yytext[0] != '0' ? 10 :
 724728                             yytext[1] == 'x' || yytext[1] == 'X' ? 16 : 8);
 725729                 return NUMBER;
 726730 
 727731         case IDENT:
 728732                 if (strcmp((char *)yytext, "defined") == 0) {
 729733                         ifdef = 1;
 730734                         return DEFINED;
 731735                 }
 732736                 nl = lookup(yytext, FIND);
 733737                 if (ifdef) {
 734738                         yylval.node.nd_val = nl != NULL;
 735739                         ifdef = 0;
 736740                 } else if (nl && noex == 0) {
 737741                         usch *och = stringbuf;
 738742                         int i;
 739743 
 740744                         i = kfind(nl);
 741745                         unch(WARN);
 742746                         if (i)
 743747                                 unpstr(stringbuf);
 744748                         else
 745749                                 unpstr(nl->namep);
 746750                         stringbuf = och;
 747751                         noex = 1;
 748752                         return yylex();
 749753                 } else {
 750754                         yylval.node.nd_val = 0;
 751755                 }
 752756                 yylval.node.op = NUMBER;
 753757                 return NUMBER;
 754758         case WARN:
 755759                 noex = 0;
 756760                 /* FALLTHROUGH */
 757761         case PHOLD:
 758762                 return yylex();
 759763         default:
 760764                 return ch;
 761765         }
 762766         unch(c2);
 763767         return ch;
 764768 }
 765769 
 766770 /*
 767771  * Let the command-line args be faked defines at beginning of file.
 768772  */
 769773 static void
 770774 prinit(struct initar *it, struct includ *ic)
 771775 {
 772776         const char *pre, *post;
 773777         char *a;
 774778 
 775779         if (it->next)
 776780                 prinit(it->next, ic);
 777781         pre = post = NULL; /* XXX gcc */
 778782         switch (it->type) {
 779783         case 'D':
 780784                 pre = "#define ";
 781785                 if ((a = strchr(it->str, '=')) != NULL) {
 782786                         *a = ' ';
 783787                         post = "\n";
 784788                 } else
 785789                         post = " 1\n";
 786790                 break;
 787791         case 'U':
 788792                 pre = "#undef ";
 789793                 post = "\n";
 790794                 break;
 791795         case 'i':
 792796                 pre = "#include \"";
 793797                 post = "\"\n";
 794798                 break;
 795799         default:
 796800                 error("prinit");
 797801         }
 798802         strlcat((char *)ic->buffer, pre, CPPBUF+1);
 799803         strlcat((char *)ic->buffer, it->str, CPPBUF+1);
 800804         if (strlcat((char *)ic->buffer, post, CPPBUF+1) >= CPPBUF+1)
 801805                 error("line exceeds buffer size");
 802806 
 803807         ic->lineno--;
 804808         while (*ic->maxread)
 805809                 ic->maxread++;
 806810 }
 807811 
 808812 /*
 809813  * A new file included.
 810814  * If ifiles == NULL, this is the first file and already opened (stdin).
 811815  * Return 0 on success, -1 if file to be included is not found.
 812816  */
 813817 int
 814818 pushfile(const usch *file, const usch *fn, int idx, void *incs)
 815819 {
 816820         extern struct initar *initar;
 817821         struct includ ibuf;
 818822         struct includ *ic;
 819823         int otrulvl;
 820824 
 821825         ic = &ibuf;
 822826         ic->next = ifiles;
 823827 
 824828         if (file != NULL) {
 825829                 if ((ic->infil = open((const char *)file, O_RDONLY)) < 0)
 826830                         return -1;
 827831                 ic->orgfn = ic->fname = file;
 828832                 if (++inclevel > MAX_INCLEVEL)
 829833                         error("limit for nested includes exceeded");
 830834         } else {
 831835                 ic->infil = 0;
 832836                 ic->orgfn = ic->fname = (const usch *)"<stdin>";
 833837         }
 834838 #ifndef BUF_STACK
 835839         ic->bbuf = malloc(BBUFSZ);
 836840 #endif
 837841         ic->buffer = ic->bbuf+NAMEMAX;
 838842         ic->curptr = ic->buffer;
 839843         ifiles = ic;
 840844         ic->lineno = 1;
 841845         ic->escln = 0;
 842846         ic->maxread = ic->curptr;
 843847         ic->idx = idx;
 844848         ic->incs = incs;
 845849         ic->fn = fn;
 846850         prtline();
 847851         if (initar) {
 848852                 int oin = ic->infil;
 849853                 ic->infil = -1;
 850854                 *ic->maxread = 0;
 851855                 prinit(initar, ic);
 852856                 initar = NULL;
 853857                 if (dMflag)
 854858                         xwrite(ofd, ic->buffer, strlen((char *)ic->buffer));
 855859                 fastscan();
 856860                 prtline();
 857861                 ic->infil = oin;
 858862         }
 859863 
 860864         otrulvl = trulvl;
 861865 
 862866         fastscan();
 863867 
 864868         if (otrulvl != trulvl || flslvl)
 865869                 error("unterminated conditional");
 866870 
 867871 #ifndef BUF_STACK
 868872         free(ic->bbuf);
 869873 #endif
 870874         ifiles = ic->next;
 871875         close(ic->infil);
 872876         inclevel--;
 873877         return 0;
 874878 }
 875879 
 876880 /*
 877881  * Print current position to output file.
 878882  */
 879883 void
 880884 prtline(void)
 881885 {
 882886         usch *sb = stringbuf;
 883887 
 884888         if (Mflag) {
 885889                 if (dMflag)
 886890                         return; /* no output */
 887891                 if (ifiles->lineno == 1) {
 888892                         sheap("%s: %s\n", Mfile, ifiles->fname);
 889893                         if (MPflag &&
 890894                             strcmp((const char *)ifiles->fname, (char *)MPfile))
 891895                                 sheap("%s:\n", ifiles->fname);
 892896                         xwrite(ofd, sb, stringbuf - sb);
 893897                 }
 894898         } else if (!Pflag) {
 895899                 sheap("\n# %d \"%s\"", ifiles->lineno, ifiles->fname);
 896900                 if (ifiles->idx == SYSINC)
 897901                         sheap(" 3");
 898902                 sheap("\n");
 899903                 putstr(sb);
 900904         }
 901905         stringbuf = sb;
 902906 }
 903907 
 904908 void
 905909 cunput(int c)
 906910 {
 907911 #ifdef PCC_DEBUG
 908912 //      if (dflag)printf(": '%c'(%d)\n", c > 31 ? c : ' ', c);
 909913 #endif
 910914         unch(c);
 911915 }
 912916 
 913917 static int
 914918 dig2num(int c)
 915919 {
 916920         if (c >= 'a')
 917921                 c = c - 'a' + 10;
 918922         else if (c >= 'A')
 919923                 c = c - 'A' + 10;
 920924         else
 921925                 c = c - '0';
 922926         return c;
 923927 }
 924928 
 925929 /*
 926930  * Convert string numbers to unsigned long long and check overflow.
 927931  */
 928932 static void
 929933 cvtdig(int rad)
 930934 {
 931935         unsigned long long rv = 0;
 932936         unsigned long long rv2 = 0;
 933937         usch *y = yytext;
 934938         int c;
 935939 
 936940         c = *y++;
 937941         if (rad == 16)
 938942                 y++;
 939943         while ((spechr[c] & C_HEX)) {
 940944                 rv = rv * rad + dig2num(c);
 941945                 /* check overflow */
 942946                 if (rv / rad < rv2)
 943947                         error("constant \"%s\" is out of range", yytext);
 944948                 rv2 = rv;
 945949                 c = *y++;
 946950         }
 947951         y--;
 948952         while (*y == 'l' || *y == 'L')
 949953                 y++;
 950954         yylval.node.op = *y == 'u' || *y == 'U' ? UNUMBER : NUMBER;
 951955         yylval.node.nd_uval = rv;
 952956         if ((rad == 8 || rad == 16) && yylval.node.nd_val < 0)
 953957                 yylval.node.op = UNUMBER;
 954958         if (yylval.node.op == NUMBER && yylval.node.nd_val < 0)
 955959                 /* too large for signed, see 6.4.4.1 */
 956960                 error("constant \"%s\" is out of range", yytext);
 957961 }
 958962 
 959963 static int
 960964 charcon(usch *p)
 961965 {
 962966         int val, c;
 963967 
 964968         p++; /* skip first ' */
 965969         val = 0;
 966970         if (*p++ == '\\') {
 967971                 switch (*p++) {
 968972                 case 'a': val = '\a'; break;
 969973                 case 'b': val = '\b'; break;
 970974                 case 'f': val = '\f'; break;
 971975                 case 'n': val = '\n'; break;
 972976                 case 'r': val = '\r'; break;
 973977                 case 't': val = '\t'; break;
 974978                 case 'v': val = '\v'; break;
 975979                 case '\"': val = '\"'; break;
 976980                 case '\'': val = '\''; break;
 977981                 case '\\': val = '\\'; break;
 978982                 case 'x':
 979983                         while ((spechr[c = *p] & C_HEX)) {
 980984                                 val = val * 16 + dig2num(c);
 981985                                 p++;
 982986                         }
 983987                         break;
 984988                 case '0': case '1': case '2': case '3': case '4':
 985989                 case '5': case '6': case '7':
 986990                         p--;
 987991                         while ((spechr[c = *p] & C_DIGIT)) {
 988992                                 val = val * 8 + (c - '0');
 989993                                 p++;
 990994                         }
 991995                         break;
 992996                 default: val = p[-1];
 993997                 }
 994998 
 995999         } else
 9961000                 val = p[-1];
 9971001         return val;
 9981002 }
 9991003 
 10001004 static void
 10011005 chknl(int ignore)
 10021006 {
 10031007         int t;
 10041008 
 10051009         while ((t = sloscan()) == WSPACE)
 10061010                 ;
 10071011         if (t != '\n') {
 10081012                 if (t) {
 10091013                         if (ignore) {
 10101014                                 warning("newline expected, got \"%s\"", yytext);
 10111015                                 /* ignore rest of line */
 10121016                                 while ((t = sloscan()) && t != '\n')
 10131017                                         ;
 10141018                         }
 10151019                         else
 10161020                                 error("newline expected, got \"%s\"", yytext);
 10171021                 } else {
 10181022                         if (ignore)
 10191023                                 warning("no newline at end of file");
 10201024                         else
 10211025                                 error("no newline at end of file");
 10221026                 }
 10231027         }
 10241028 }
 10251029 
 10261030 static void
 10271031 elsestmt(void)
 10281032 {
 10291033         if (flslvl) {
 10301034                 if (elflvl > trulvl)
 10311035                         ;
 10321036                 else if (--flslvl!=0)
 10331037                         flslvl++;
 10341038                 else
 10351039                         trulvl++;
 10361040         } else if (trulvl) {
 10371041                 flslvl++;
 10381042                 trulvl--;
 10391043         } else
 10401044                 error("#else in non-conditional section");
 10411045         if (elslvl==trulvl+flslvl)
 10421046                 error("too many #else");
 10431047         elslvl=trulvl+flslvl;
 10441048         chknl(1);
 10451049 }
 10461050 
 10471051 static void
 10481052 skpln(void)
 10491053 {
 10501054         int ch;
 10511055 
 10521056         /* just ignore the rest of the line */
 10531057         while ((ch = inch()) != -1) {
 10541058                 if (ch == '\n') {
 10551059                         unch('\n');
 10561060                         break;
 10571061                 }
 10581062         }
 10591063 }
 10601064 
 10611065 static void
 10621066 ifdefstmt(void)         
 10631067 {
 10641068         int t;
 10651069 
 10661070         if (flslvl) {
 10671071                 flslvl++;
 10681072                 skpln();
 10691073                 return;
 10701074         }
 10711075         do
 10721076                 t = sloscan();
 10731077         while (t == WSPACE);
 10741078         if (t != IDENT)
 10751079                 error("bad #ifdef");
 10761080         if (lookup(yytext, FIND) == NULL)
 10771081                 flslvl++;
 10781082         else
 10791083                 trulvl++;
 10801084         chknl(0);
 10811085 }
 10821086 
 10831087 static void
 10841088 ifndefstmt(void)         
 10851089 {
 10861090         int t;
 10871091 
 10881092         if (flslvl) {
 10891093                 flslvl++;
 10901094                 skpln();
 10911095                 return;
 10921096         }
 10931097         do
 10941098                 t = sloscan();
 10951099         while (t == WSPACE);
 10961100         if (t != IDENT)
 10971101                 error("bad #ifndef");
 10981102         if (lookup(yytext, FIND) != NULL)
 10991103                 flslvl++;
 11001104         else
 11011105                 trulvl++;
 11021106         chknl(0);
 11031107 }
 11041108 
 11051109 static void
 11061110 endifstmt(void)         
 11071111 {
 11081112         if (flslvl)
 11091113                 flslvl--;
 11101114         else if (trulvl)
 11111115                 trulvl--;
 11121116         else
 11131117                 error("#endif in non-conditional section");
 11141118         if (flslvl == 0)
 11151119                 elflvl = 0;
 11161120         elslvl = 0;
 11171121         chknl(1);
 11181122 }
 11191123 
 11201124 static void
 11211125 ifstmt(void)
 11221126 {
 11231127         if (flslvl || yyparse() == 0)
 11241128                 flslvl++;
 11251129         else
 11261130                 trulvl++;
 11271131 }
 11281132 
 11291133 static void
 11301134 elifstmt(void)
 11311135 {
 11321136         if (flslvl == 0)
 11331137                 elflvl = trulvl;
 11341138         if (flslvl) {
 11351139                 if (elflvl > trulvl)
 11361140                         ;
 11371141                 else if (--flslvl!=0)
 11381142                         flslvl++;
 11391143                 else if (yyparse())
 11401144                         trulvl++;
 11411145                 else
 11421146                         flslvl++;
 11431147         } else if (trulvl) {
 11441148                 flslvl++;
 11451149                 trulvl--;
 11461150         } else
 11471151                 error("#elif in non-conditional section");
 11481152 }
 11491153 
 11501154 /* save line into stringbuf */
 11511155 static usch *
 11521156 savln(void)
 11531157 {
 11541158         int c;
 11551159         usch *cp = stringbuf;
 11561160 
 11571161         while ((c = inch()) != -1) {
 11581162                 if (c == '\n') {
 11591163                         unch(c);
 11601164                         break;
 11611165                 }
 11621166                 savch(c);
 11631167         }
 11641168         savch(0);
 11651169 
 11661170         return cp;
 11671171 }
 11681172 
 11691173 static void
 11701174 cpperror(void)
 11711175 {
 11721176         usch *cp;
 11731177         int c;
 11741178 
 11751179         if (flslvl)
 11761180                 return;
 11771181         c = sloscan();
 11781182         if (c != WSPACE && c != '\n')
 11791183                 error("bad #error");
 11801184         cp = savln();
 11811185         error("#error %s", cp);
 11821186 }
 11831187 
 11841188 static void
 11851189 cppwarning(void)
 11861190 {
 11871191         usch *cp;
 11881192         int c;
 11891193 
 11901194         if (flslvl)
 11911195                 return;
 11921196         c = sloscan();
 11931197         if (c != WSPACE && c != '\n')
 11941198                 error("bad #warning");
 11951199         cp = savln();
 11961200         warning("#warning %s", cp);
 11971201         stringbuf = cp;
 11981202 }
 11991203 
 12001204 static void
 12011205 undefstmt(void)
 12021206 {
 12031207         struct symtab *np;
 12041208 
 12051209         if (flslvl)
 12061210                 return;
 12071211         if (sloscan() != WSPACE || sloscan() != IDENT)
 12081212                 error("bad #undef");
 12091213         if ((np = lookup(yytext, FIND)) != NULL)
 12101214                 np->value = 0;
 12111215         chknl(0);
 12121216 }
 12131217 
 12141218 static void
 12151219 pragmastmt(void)
 12161220 {
 12171221         usch *sb;
 12181222 
 12191223         if (flslvl)
 12201224                 return;
 12211225         if (sloscan() != WSPACE)
 12221226                 error("bad #pragma");
 12231227         sb = stringbuf;
 12241228         savstr((const usch *)"#pragma ");
 12251229         savln();
 12261230         putstr(sb);
 12271231         stringbuf = sb;
 12281232 }
 12291233 
 12301234 int
 12311235 cinput(void)
 12321236 {
 12331237         return inch();
 12341238 }
 12351239 
 12361240 static struct {
 12371241         const char *name;
 12381242         void (*fun)(void);
 12391243 } ppd[] = {
 12401244         { "ifndef", ifndefstmt },
 12411245         { "ifdef", ifdefstmt },
 12421246         { "if", ifstmt },
 12431247         { "include", include },
 12441248         { "else", elsestmt },
 12451249         { "endif", endifstmt },
 12461250         { "error", cpperror },
 12471251         { "warning", cppwarning },
 12481252         { "define", define },
 12491253         { "undef", undefstmt },
 12501254         { "line", line },
 12511255         { "pragma", pragmastmt },
 12521256         { "elif", elifstmt },
 12531257 #ifdef GCC_COMPAT
 12541258         { "include_next", include_next },
 12551259 #endif
 12561260 };
 12571261 #define NPPD    (int)(sizeof(ppd) / sizeof(ppd[0]))
 12581262 
 12591263 /*
 12601264  * Handle a preprocessor directive.
 12611265  */
 12621266 void
 12631267 ppdir(void)
 12641268 {
 12651269         char bp[20];
 12661270         int ch, i;
 12671271 
 12681272 redo:   while ((ch = inch()) == ' ' || ch == '\t')
 12691273                 ;
 12701274         if (ch == '/') {
 12711275                 if ((ch = inch()) == '/') {
 12721276                         skpln();
 12731277                         return;
 12741278                 }
 12751279                 if (ch == '*') {
 12761280                         while ((ch = inch()) != -1) {
 12771281                                 if (ch == '*') {
 12781282                                         if ((ch = inch()) == '/')
 12791283                                                 goto redo;
 12801284                                         unch(ch);
 12811285                                 } else if (ch == '\n') {
 12821286                                         putch('\n');
 12831287                                         ifiles->lineno++;
 12841288                                 }
 12851289                         }
 12861290                 }
 12871291         }
 12881292         if (ch == '\n') { /* empty directive */
 12891293                 unch(ch);
 12901294                 return;
 12911295         }
 12921296         if (ch < 'a' || ch > 'z')
 12931297                 goto out; /* something else, ignore */
 12941298         i = 0;
 12951299         do {
 12961300                 bp[i++] = (usch)ch;
 12971301                 if (i == sizeof(bp)-1)
 12981302                         goto out; /* too long */
 12991303                 ch = inch();
 13001304         } while ((ch >= 'a' && ch <= 'z') || (ch == '_'));
 13011305         unch(ch);
 13021306         bp[i++] = 0;
 13031307 
 13041308         /* got keyword */
 13051309         for (i = 0; i < NPPD; i++) {
 13061310                 if (bp[0] == ppd[i].name[0] && strcmp(bp, ppd[i].name) == 0) {
 13071311                         (*ppd[i].fun)();
 13081312                         return;
 13091313                 }
 13101314         }
 13111315 
 13121316 out:    error("invalid preprocessor directive");
 13131317 }
FishEye: Open Source License registered to PCC.
Your maintenance has expired. You can renew your license at http://www.atlassian.com/fisheye/renew
Atlassian FishEye, CVS analysis. (Version:1.6.3 Build:build-336 2008-11-04) - Administration - Page generated 2014-09-19 21:52 +0200