home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Games / NetHack 3.1.3 / source / sys / unix / cpp3.shr < prev    next >
Encoding:
Text File  |  1993-08-01  |  50.6 KB  |  1,902 lines  |  [TEXT/R*ch]

  1. # This is a shell archive.  Save it in a file, remove anything before
  2. # this line, and then unpack it by entering "sh file".  Note, it may
  3. # create directories; files and directories will be owned by you and
  4. # have default permissions.
  5. #
  6. # This archive contains:
  7. #
  8. #    cpp5.c
  9. #    cpp6.c
  10. #
  11. echo x - cpp5.c
  12. sed 's/^X//' >cpp5.c << 'END-of-cpp5.c'
  13. X/*
  14. X *                C P P 5 . C
  15. X *        E x p r e s s i o n   E v a l u a t i o n
  16. X *
  17. X * Edit History
  18. X * 31-Aug-84    MM    USENET net.sources release
  19. X * 04-Oct-84    MM    __LINE__ and __FILE__ must call ungetstring()
  20. X *            so they work correctly with token concatenation.
  21. X *            Added string formal recognition.
  22. X * 25-Oct-84    MM    "Short-circuit" evaluate #if's so that we
  23. X *            don't print unnecessary error messages for
  24. X *            #if !defined(FOO) && FOO != 0 && 10 / FOO ...
  25. X * 31-Oct-84    ado/MM    Added token concatenation
  26. X *  6-Nov-84    MM    Split from #define stuff, added sizeof stuff
  27. X * 19-Nov-84    ado    #if error returns TRUE for (sigh) compatibility
  28. X */
  29. X
  30. X#include    <stdio.h>
  31. X#include    <ctype.h>
  32. X#include    "cppdef.h"
  33. X#include    "cpp.h"
  34. X
  35. X/*
  36. X * Evaluate an #if expression.
  37. X */
  38. X
  39. Xstatic char    *opname[] = {        /* For debug and error messages    */
  40. X"end of expression", "val", "id",
  41. X  "+",   "-",  "*",  "/",  "%",
  42. X  "<<", ">>",  "&",  "|",  "^",
  43. X  "==", "!=",  "<", "<=", ">=",  ">",
  44. X  "&&", "||",  "?",  ":",  ",",
  45. X  "unary +", "unary -", "~", "!",  "(",  ")", "(none)",
  46. X};
  47. X
  48. X/*
  49. X * opdope[] has the operator precedence:
  50. X *     Bits
  51. X *      7    Unused (so the value is always positive)
  52. X *    6-2    Precedence (000x .. 017x)
  53. X *    1-0    Binary op. flags:
  54. X *        01    The binop flag should be set/cleared when this op is seen.
  55. X *        10    The new value of the binop flag.
  56. X * Note:  Expected, New binop
  57. X * constant    0    1    Binop, end, or ) should follow constants
  58. X * End of line    1    0    End may not be preceeded by an operator
  59. X * binary    1    0    Binary op follows a value, value follows.
  60. X * unary    0    0    Unary op doesn't follow a value, value follows
  61. X *   (        0    0    Doesn't follow value, value or unop follows
  62. X *   )        1    1    Follows value.  Op follows.
  63. X */
  64. X
  65. Xstatic char    opdope[OP_MAX] = {
  66. X  0001,                    /* End of expression        */
  67. X  0002,                    /* Digit            */
  68. X  0000,                    /* Letter (identifier)        */
  69. X  0141, 0141, 0151, 0151, 0151,        /* ADD, SUB, MUL, DIV, MOD    */
  70. X  0131, 0131, 0101, 0071, 0071,        /* ASL, ASR, AND,  OR, XOR    */
  71. X  0111, 0111, 0121, 0121, 0121,    0121,    /*  EQ,  NE,  LT,  LE,  GE,  GT    */
  72. X  0061, 0051, 0041, 0041, 0031,        /* ANA, ORO, QUE, COL, CMA    */
  73. X/*
  74. X * Unary op's follow
  75. X */
  76. X  0160, 0160, 0160, 0160,        /* NEG, PLU, COM, NOT        */
  77. X  0170, 0013, 0023,            /* LPA, RPA, END        */
  78. X};
  79. X/*
  80. X * OP_QUE and OP_RPA have alternate precedences:
  81. X */
  82. X#define    OP_RPA_PREC    0013
  83. X#define OP_QUE_PREC    0034
  84. X
  85. X/*
  86. X * S_ANDOR and S_QUEST signal "short-circuit" boolean evaluation, so that
  87. X *    #if FOO != 0 && 10 / FOO ...
  88. X * doesn't generate an error message.  They are stored in optab.skip.
  89. X */
  90. X#define S_ANDOR        2
  91. X#define S_QUEST        1
  92. X
  93. Xtypedef struct optab {
  94. X    char    op;            /* Operator            */
  95. X    char    prec;            /* Its precedence        */
  96. X    char    skip;            /* Short-circuit: TRUE to skip    */
  97. X} OPTAB;
  98. Xstatic int    evalue;            /* Current value from evallex()    */
  99. X
  100. X#ifdef    nomacargs
  101. XFILE_LOCAL int
  102. Xisbinary(op)
  103. Xregister int    op;
  104. X{
  105. X    return (op >= FIRST_BINOP && op <= LAST_BINOP);
  106. X}
  107. X
  108. XFILE_LOCAL int
  109. Xisunary(op)
  110. Xregister int    op;
  111. X{
  112. X    return (op >= FIRST_UNOP && op <= LAST_UNOP);
  113. X}
  114. X#else
  115. X#define    isbinary(op)    (op >= FIRST_BINOP && op <= LAST_BINOP)
  116. X#define    isunary(op)    (op >= FIRST_UNOP  && op <= LAST_UNOP)
  117. X#endif
  118. X
  119. X/*
  120. X * The following definitions are used to specify basic variable sizes.
  121. X */
  122. X
  123. X#ifndef    S_CHAR
  124. X#define    S_CHAR        (sizeof (char))
  125. X#endif
  126. X#ifndef    S_SINT
  127. X#define    S_SINT        (sizeof (short int))
  128. X#endif
  129. X#ifndef    S_INT
  130. X#define    S_INT        (sizeof (int))
  131. X#endif
  132. X#ifndef    S_LINT
  133. X#define    S_LINT        (sizeof (long int))
  134. X#endif
  135. X#ifndef    S_FLOAT
  136. X#define    S_FLOAT        (sizeof (float))
  137. X#endif
  138. X#ifndef    S_DOUBLE
  139. X#define    S_DOUBLE    (sizeof (double))
  140. X#endif
  141. X#ifndef    S_PCHAR
  142. X#define    S_PCHAR        (sizeof (char *))
  143. X#endif
  144. X#ifndef    S_PSINT
  145. X#define    S_PSINT        (sizeof (short int *))
  146. X#endif
  147. X#ifndef    S_PINT
  148. X#define    S_PINT        (sizeof (int *))
  149. X#endif
  150. X#ifndef    S_PLINT
  151. X#define    S_PLINT        (sizeof (long int *))
  152. X#endif
  153. X#ifndef    S_PFLOAT
  154. X#define    S_PFLOAT    (sizeof (float *))
  155. X#endif
  156. X#ifndef    S_PDOUBLE
  157. X#define    S_PDOUBLE    (sizeof (double *))
  158. X#endif
  159. X#ifndef    S_PFPTR
  160. X#define S_PFPTR        (sizeof (int (*)()))
  161. X#endif
  162. X
  163. Xtypedef struct types {
  164. X    short    type;            /* This is the bit if        */
  165. X    char    *name;            /* this is the token word    */
  166. X} TYPES;
  167. X
  168. Xstatic TYPES basic_types[] = {
  169. X    { T_CHAR,    "char",        },
  170. X    { T_INT,    "int",        },
  171. X    { T_FLOAT,    "float",    },
  172. X    { T_DOUBLE,    "double",    },
  173. X    { T_SHORT,    "short",    },
  174. X    { T_LONG,    "long",        },
  175. X    { T_SIGNED,    "signed",    },
  176. X    { T_UNSIGNED,    "unsigned",    },
  177. X    { 0,        NULL,        },    /* Signal end        */
  178. X};
  179. X
  180. X/*
  181. X * Test_table[] is used to test for illegal combinations.
  182. X */
  183. Xstatic short test_table[] = {
  184. X    T_FLOAT | T_DOUBLE | T_LONG | T_SHORT,
  185. X    T_FLOAT | T_DOUBLE | T_CHAR | T_INT,
  186. X    T_FLOAT | T_DOUBLE | T_SIGNED | T_UNSIGNED,
  187. X    T_LONG  | T_SHORT  | T_CHAR,
  188. X    0                        /* end marker    */
  189. X};
  190. X
  191. X/*
  192. X * The order of this table is important -- it is also referenced by
  193. X * the command line processor to allow run-time overriding of the
  194. X * built-in size values.  The order must not be changed:
  195. X *    char, short, int, long, float, double (func pointer)
  196. X */
  197. XSIZES size_table[] = {
  198. X    { T_CHAR,    S_CHAR,        S_PCHAR        },    /* char        */
  199. X    { T_SHORT,    S_SINT,        S_PSINT        },    /* short int    */
  200. X    { T_INT,    S_INT,        S_PINT        },    /* int        */
  201. X    { T_LONG,    S_LINT,        S_PLINT        },    /* long        */
  202. X    { T_FLOAT,    S_FLOAT,    S_PFLOAT    },    /* float    */
  203. X    { T_DOUBLE,    S_DOUBLE,    S_PDOUBLE    },    /* double    */
  204. X    { T_FPTR,    0,        S_PFPTR        },    /* int (*())     */
  205. X    { 0,    0,        0        },    /* End of table    */
  206. X};
  207. X
  208. Xint
  209. Xeval()
  210. X/*
  211. X * Evaluate an expression.  Straight-forward operator precedence.
  212. X * This is called from control() on encountering an #if statement.
  213. X * It calls the following routines:
  214. X * evallex    Lexical analyser -- returns the type and value of
  215. X *        the next input token.
  216. X * evaleval    Evaluate the current operator, given the values on
  217. X *        the value stack.  Returns a pointer to the (new)
  218. X *        value stack.
  219. X * For compatiblity with older cpp's, this return returns 1 (TRUE)
  220. X * if a syntax error is detected.
  221. X */
  222. X{
  223. X    register int    op;        /* Current operator        */
  224. X    register int    *valp;        /* -> value vector        */
  225. X    register OPTAB    *opp;        /* Operator stack        */
  226. X    int        prec;        /* Op precedence        */
  227. X    int        binop;        /* Set if binary op. needed    */
  228. X    int        op1;        /* Operand from stack        */
  229. X    int        skip;        /* For short-circuit testing    */
  230. X    int        value[NEXP];    /* Value stack            */
  231. X    OPTAB        opstack[NEXP];    /* Operand stack        */
  232. X    extern int    *evaleval();    /* Does actual evaluation    */
  233. X
  234. X    valp = value;
  235. X    opp = opstack;
  236. X    opp->op = OP_END;        /* Mark bottom of stack        */
  237. X    opp->prec = opdope[OP_END];    /* And its precedence        */
  238. X    opp->skip = 0;            /* Not skipping now        */
  239. X    binop = 0;
  240. Xagain:    ;
  241. X#ifdef    DEBUG_EVAL
  242. X    printf("In #if at again: skip = %d, binop = %d, line is: %s",
  243. X        opp->skip, binop, infile->bptr);
  244. X#endif
  245. X    if ((op = evallex(opp->skip)) == OP_SUB && binop == 0)
  246. X        op = OP_NEG;            /* Unary minus        */
  247. X    else if (op == OP_ADD && binop == 0)
  248. X        op = OP_PLU;            /* Unary plus        */
  249. X    else if (op == OP_FAIL)
  250. X        return (1);                /* Error in evallex    */
  251. X#ifdef    DEBUG_EVAL
  252. X    printf("op = %s, opdope = %03o, binop = %d, skip = %d\n",
  253. X        opname[op], opdope[op], binop, opp->skip);
  254. X#endif
  255. X    if (op == DIG) {            /* Value?        */
  256. X        if (binop != 0) {
  257. X        cerror("misplaced constant in #if", NULLST);
  258. X        return (1);
  259. X        }
  260. X        else if (valp >= &value[NEXP-1]) {
  261. X        cerror("#if value stack overflow", NULLST);
  262. X        return (1);
  263. X        }
  264. X        else {
  265. X#ifdef    DEBUG_EVAL
  266. X        printf("pushing %d onto value stack[%d]\n",
  267. X            evalue, valp - value);
  268. X#endif
  269. X        *valp++ = evalue;
  270. X        binop = 1;
  271. X        }
  272. X        goto again;
  273. X    }
  274. X    else if (op > OP_END) {
  275. X        cerror("Illegal #if line", NULLST);
  276. X        return (1);
  277. X    }
  278. X    prec = opdope[op];
  279. X    if (binop != (prec & 1)) {
  280. X        cerror("Operator %s in incorrect context", opname[op]);
  281. X        return (1);
  282. X    }
  283. X    binop = (prec & 2) >> 1;
  284. X    for (;;) {
  285. X#ifdef    DEBUG_EVAL
  286. X        printf("op %s, prec %d., stacked op %s, prec %d, skip %d\n",
  287. X        opname[op], prec, opname[opp->op], opp->prec, opp->skip);
  288. X#endif
  289. X        if (prec > opp->prec) {
  290. X        if (op == OP_LPA)
  291. X            prec = OP_RPA_PREC;
  292. X        else if (op == OP_QUE)
  293. X            prec = OP_QUE_PREC;
  294. X        op1 = opp->skip;        /* Save skip for test    */
  295. X        /*
  296. X         * Push operator onto op. stack.
  297. X         */
  298. X        opp++;
  299. X        if (opp >= &opstack[NEXP]) {
  300. X            cerror("expression stack overflow at op \"%s\"",
  301. X            opname[op]);
  302. X            return (1);
  303. X        }
  304. X        opp->op = op;
  305. X        opp->prec = prec;
  306. X        skip = (valp[-1] != 0);        /* Short-circuit tester    */
  307. X        /*
  308. X         * Do the short-circuit stuff here.  Short-circuiting
  309. X         * stops automagically when operators are evaluated.
  310. X         */
  311. X        if ((op == OP_ANA && !skip)
  312. X         || (op == OP_ORO && skip))
  313. X            opp->skip = S_ANDOR;    /* And/or skip starts    */
  314. X        else if (op == OP_QUE)        /* Start of ?: operator    */
  315. X            opp->skip = (op1 & S_ANDOR) | ((!skip) ? S_QUEST : 0);
  316. X        else if (op == OP_COL) {    /* : inverts S_QUEST    */
  317. X            opp->skip = (op1 & S_ANDOR)
  318. X                  | (((op1 & S_QUEST) != 0) ? 0 : S_QUEST);
  319. X        }
  320. X        else {                /* Other ops leave    */
  321. X            opp->skip = op1;        /*  skipping unchanged.    */
  322. X        }
  323. X#ifdef    DEBUG_EVAL
  324. X        printf("stacking %s, valp[-1] == %d at %s",
  325. X            opname[op], valp[-1], infile->bptr);
  326. X        dumpstack(opstack, opp, value, valp);
  327. X#endif
  328. X        goto again;
  329. X        }
  330. X        /*
  331. X         * Pop operator from op. stack and evaluate it.
  332. X         * End of stack and '(' are specials.
  333. X         */
  334. X        skip = opp->skip;            /* Remember skip value    */
  335. X        switch ((op1 = opp->op)) {        /* Look at stacked op    */
  336. X        case OP_END:            /* Stack end marker    */
  337. X        if (op == OP_EOE)
  338. X            return (valp[-1]);        /* Finished ok.        */
  339. X        goto again;            /* Read another op.    */
  340. X
  341. X        case OP_LPA:            /* ( on stack        */
  342. X        if (op != OP_RPA) {        /* Matches ) on input    */
  343. X            cerror("unbalanced paren's, op is \"%s\"", opname[op]);
  344. X            return (1);
  345. X        }
  346. X        opp--;                /* Unstack it        */
  347. X        /* goto again;            -- Fall through        */
  348. X
  349. X        case OP_QUE:
  350. X        goto again;            /* Evaluate true expr.    */
  351. X
  352. X        case OP_COL:            /* : on stack.        */
  353. X        opp--;                /* Unstack :        */
  354. X        if (opp->op != OP_QUE) {    /* Matches ? on stack?    */
  355. X            cerror("Misplaced '?' or ':', previous operator is %s",
  356. X            opname[opp->op]);
  357. X            return (1);
  358. X        }
  359. X        /*
  360. X         * Evaluate op1.
  361. X         */
  362. X        default:                /* Others:        */
  363. X        opp--;                /* Unstack the operator    */
  364. X#ifdef    DEBUG_EVAL
  365. X        printf("Stack before evaluation of %s\n", opname[op1]);
  366. X        dumpstack(opstack, opp, value, valp);
  367. X#endif
  368. X        valp = evaleval(valp, op1, skip);
  369. X#ifdef    DEBUG_EVAL
  370. X        printf("Stack after evaluation\n");
  371. X        dumpstack(opstack, opp, value, valp);
  372. X#endif
  373. X        }                    /* op1 switch end    */
  374. X    }                    /* Stack unwind loop    */
  375. X}
  376. X
  377. XFILE_LOCAL int
  378. Xevallex(skip)
  379. Xint        skip;        /* TRUE if short-circuit evaluation    */
  380. X/*
  381. X * Return next eval operator or value.  Called from eval().  It
  382. X * calls a special-purpose routines for 'char' strings and
  383. X * numeric values:
  384. X * evalchar    called to evaluate 'x'
  385. X * evalnum    called to evaluate numbers.
  386. X */
  387. X{
  388. X    register int    c, c1, t;
  389. X
  390. Xagain:  do {                    /* Collect the token    */
  391. X        c = skipws();
  392. X        if ((c = macroid(c)) == EOF_CHAR || c == '\n') {
  393. X        unget();
  394. X        return (OP_EOE);        /* End of expression    */
  395. X        }
  396. X    } while ((t = type[c]) == LET && catenate());
  397. X    if (t == INV) {                /* Total nonsense    */
  398. X        if (!skip) {
  399. X        if (isascii(c) && isprint(c))
  400. X            cierror("illegal character '%c' in #if", c);
  401. X        else
  402. X            cierror("illegal character (%d decimal) in #if", c);
  403. X        }
  404. X        return (OP_FAIL);
  405. X    }
  406. X    else if (t == QUO) {            /* ' or "        */
  407. X        if (c == '\'') {            /* Character constant    */
  408. X        evalue = evalchar(skip);    /* Somewhat messy    */
  409. X#ifdef    DEBUG_EVAL
  410. X        printf("evalchar returns %d.\n", evalue);
  411. X#endif
  412. X        return (DIG);            /* Return a value    */
  413. X        }
  414. X        cerror("Can't use a string in an #if", NULLST);
  415. X        return (OP_FAIL);
  416. X    }
  417. X    else if (t == LET) {            /* ID must be a macro    */
  418. X        if (streq(token, "defined")) {    /* Or defined name    */
  419. X        c1 = c = skipws();
  420. X        if (c == '(')            /* Allow defined(name)    */
  421. X            c = skipws();
  422. X        if (type[c] == LET) {
  423. X            evalue = (lookid(c) != NULL);
  424. X            if (c1 != '('        /* Need to balance    */
  425. X             || skipws() == ')')    /* Did we balance?    */
  426. X            return (DIG);        /* Parsed ok        */
  427. X        }
  428. X        cerror("Bad #if ... defined() syntax", NULLST);
  429. X        return (OP_FAIL);
  430. X        }
  431. X        else if (streq(token, "sizeof"))    /* New sizeof hackery    */
  432. X        return (dosizeof());        /* Gets own routine    */
  433. X        /*
  434. X         * The Draft ANSI C Standard says that an undefined symbol
  435. X         * in an #if has the value zero.  We are a bit pickier,
  436. X         * warning except where the programmer was careful to write
  437. X         *         #if defined(foo) ? foo : 0
  438. X         */
  439. X#ifdef VERBOSE
  440. X         if (!skip)
  441. X          cwarn("undefined symbol \"%s\" in #if, 0 used", token);
  442. X#endif
  443. X        evalue = 0;
  444. X        return (DIG);
  445. X    }
  446. X    else if (t == DIG) {            /* Numbers are harder    */
  447. X        evalue = evalnum(c);
  448. X#ifdef    DEBUG_EVAL
  449. X        printf("evalnum returns %d.\n", evalue);
  450. X#endif
  451. X    }
  452. X    else if (strchr("!=<>&|\\", c) != NULL) {
  453. X        /*
  454. X         * Process a possible multi-byte lexeme.
  455. X         */
  456. X        c1 = cget();            /* Peek at next char    */
  457. X        switch (c) {
  458. X        case '!':
  459. X        if (c1 == '=')
  460. X            return (OP_NE);
  461. X        break;
  462. X
  463. X        case '=':
  464. X        if (c1 != '=') {        /* Can't say a=b in #if    */
  465. X            unget();
  466. X            cerror("= not allowed in #if", NULLST);
  467. X            return (OP_FAIL);
  468. X        }
  469. X        return (OP_EQ);
  470. X
  471. X        case '>':
  472. X        case '<':
  473. X        if (c1 == c)
  474. X            return ((c == '<') ? OP_ASL : OP_ASR);
  475. X        else if (c1 == '=')
  476. X            return ((c == '<') ? OP_LE  : OP_GE);
  477. X        break;
  478. X
  479. X        case '|':
  480. X        case '&':
  481. X        if (c1 == c)
  482. X            return ((c == '|') ? OP_ORO : OP_ANA);
  483. X        break;
  484. X
  485. X        case '\\':
  486. X        if (c1 == '\n')            /* Multi-line if    */
  487. X            goto again;
  488. X        cerror("Unexpected \\ in #if", NULLST);
  489. X        return (OP_FAIL);
  490. X        }
  491. X        unget();
  492. X    }
  493. X    return (t);
  494. X}
  495. X
  496. XFILE_LOCAL int
  497. Xdosizeof()
  498. X/*
  499. X * Process the sizeof (basic type) operation in an #if string.
  500. X * Sets evalue to the size and returns
  501. X *    DIG        success
  502. X *    OP_FAIL        bad parse or something.
  503. X */
  504. X{
  505. X    register int    c;
  506. X    register TYPES    *tp;
  507. X    register SIZES    *sizp;
  508. X    register short    *testp;
  509. X    short        typecode;
  510. X
  511. X    if ((c = skipws()) != '(')
  512. X        goto nogood;
  513. X    /*
  514. X     * Scan off the tokens.
  515. X     */
  516. X    typecode = 0;
  517. X    while ((c = skipws())) {
  518. X        if ((c = macroid(c)) == EOF_CHAR || c == '\n')
  519. X        goto nogood;            /* End of line is a bug    */
  520. X        else if (c == '(') {        /* thing (*)() func ptr    */
  521. X        if (skipws() == '*'
  522. X         && skipws() == ')') {        /* We found (*)        */
  523. X            if (skipws() != '(')    /* Let () be optional    */
  524. X            unget();
  525. X            else if (skipws() != ')')
  526. X            goto nogood;
  527. X            typecode |= T_FPTR;        /* Function pointer    */
  528. X        }
  529. X        else {                /* Junk is a bug    */
  530. X            goto nogood;
  531. X        }
  532. X        }
  533. X        else if (type[c] != LET)        /* Exit if not a type    */
  534. X        break;
  535. X        else if (!catenate()) {        /* Maybe combine tokens    */
  536. X        /*
  537. X         * Look for this unexpandable token in basic_types.
  538. X         * The code accepts "int long" as well as "long int"
  539. X         * which is a minor bug as bugs go (and one shared with
  540. X         * a lot of C compilers).
  541. X         */
  542. X        for (tp = basic_types; tp->name != NULLST; tp++) {
  543. X            if (streq(token, tp->name))
  544. X            break;
  545. X        }
  546. X        if (tp->name == NULLST) {
  547. X            cerror("#if sizeof, unknown type \"%s\"", token);
  548. X            return (OP_FAIL);
  549. X        }
  550. X        typecode |= tp->type;        /* Or in the type bit    */
  551. X        }
  552. X    }
  553. X    /*
  554. X     * We are at the end of the type scan.  Chew off '*' if necessary.
  555. X     */
  556. X    if (c == '*') {
  557. X        typecode |= T_PTR;
  558. X        c = skipws();
  559. X    }
  560. X    if (c == ')') {                /* Last syntax check    */
  561. X        for (testp = test_table; *testp != 0; testp++) {
  562. X        if (!bittest(typecode & *testp)) {
  563. X            cerror("#if ... sizeof: illegal type combination", NULLST);
  564. X            return (OP_FAIL);
  565. X        }
  566. X        }
  567. X        /*
  568. X         * We assume that all function pointers are the same size:
  569. X         *        sizeof (int (*)()) == sizeof (float (*)())
  570. X         * We assume that signed and unsigned don't change the size:
  571. X         *        sizeof (signed int) == (sizeof unsigned int)
  572. X         */
  573. X        if ((typecode & T_FPTR) != 0)    /* Function pointer    */
  574. X        typecode = T_FPTR | T_PTR;
  575. X        else {                /* Var or var * datum    */
  576. X        typecode &= ~(T_SIGNED | T_UNSIGNED);
  577. X        if ((typecode & (T_SHORT | T_LONG)) != 0)
  578. X            typecode &= ~T_INT;
  579. X        }
  580. X        if ((typecode & ~T_PTR) == 0) {
  581. X        cerror("#if sizeof() error, no type specified", NULLST);
  582. X        return (OP_FAIL);
  583. X        }
  584. X        /*
  585. X         * Exactly one bit (and possibly T_PTR) may be set.
  586. X         */
  587. X        for (sizp = size_table; sizp->bits != 0; sizp++) {
  588. X        if ((typecode & ~T_PTR) == sizp->bits) {
  589. X            evalue = ((typecode & T_PTR) != 0)
  590. X            ? sizp->psize : sizp->size;
  591. X            return (DIG);
  592. X        }
  593. X        }                    /* We shouldn't fail    */
  594. X        cierror("#if ... sizeof: bug, unknown type code 0x%x", typecode);
  595. X        return (OP_FAIL);
  596. X    }
  597. X
  598. Xnogood:    unget();
  599. X    cerror("#if ... sizeof() syntax error", NULLST);
  600. X    return (OP_FAIL);
  601. X}
  602. X
  603. XFILE_LOCAL int
  604. Xbittest(value)
  605. X/*
  606. X * TRUE if value is zero or exactly one bit is set in value.
  607. X */
  608. X{
  609. X#if (4096 & ~(-4096)) == 0
  610. X    return ((value & ~(-value)) == 0);
  611. X#else
  612. X    /*
  613. X     * Do it the hard way (for non 2's complement machines)
  614. X     */
  615. X    return (value == 0 || value ^ (value - 1) == (value * 2 - 1));
  616. X#endif
  617. X}
  618. X
  619. XFILE_LOCAL int
  620. Xevalnum(c)
  621. Xregister int    c;
  622. X/*
  623. X * Expand number for #if lexical analysis.  Note: evalnum recognizes
  624. X * the unsigned suffix, but only returns a signed int value.
  625. X */
  626. X{
  627. X    register int    value;
  628. X    register int    base;
  629. X    register int    c1;
  630. X
  631. X    if (c != '0')
  632. X        base = 10;
  633. X    else if ((c = cget()) == 'x' || c == 'X') {
  634. X        base = 16;
  635. X        c = cget();
  636. X    }
  637. X    else base = 8;
  638. X    value = 0;
  639. X    for (;;) {
  640. X        c1 = c;
  641. X        if (isascii(c) && isupper(c1))
  642. X        c1 = tolower(c1);
  643. X        if (c1 >= 'a')
  644. X        c1 -= ('a' - 10);
  645. X        else c1 -= '0';
  646. X        if (c1 < 0 || c1 >= base)
  647. X        break;
  648. X        value *= base;
  649. X        value += c1;
  650. X        c = cget();
  651. X    }
  652. X    if (c == 'u' || c == 'U')    /* Unsigned nonsense        */
  653. X        c = cget();
  654. X    unget();
  655. X    return (value);
  656. X}
  657. X
  658. XFILE_LOCAL int
  659. Xevalchar(skip)
  660. Xint        skip;        /* TRUE if short-circuit evaluation    */
  661. X/*
  662. X * Get a character constant
  663. X */
  664. X{
  665. X    register int    c;
  666. X    register int    value;
  667. X    register int    count;
  668. X
  669. X    instring = TRUE;
  670. X    if ((c = cget()) == '\\') {
  671. X        switch ((c = cget())) {
  672. X        case 'a':                /* New in Standard    */
  673. X#if ('a' == '\a' || '\a' == ALERT)
  674. X        value = ALERT;            /* Use predefined value    */
  675. X#else
  676. X        value = '\a';            /* Use compiler's value    */
  677. X#endif
  678. X        break;
  679. X
  680. X        case 'b':
  681. X        value = '\b';
  682. X        break;
  683. X
  684. X        case 'f':
  685. X        value = '\f';
  686. X        break;
  687. X
  688. X        case 'n':
  689. X        value = '\n';
  690. X        break;
  691. X
  692. X        case 'r':
  693. X        value = '\r';
  694. X        break;
  695. X
  696. X        case 't':
  697. X        value = '\t';
  698. X        break;
  699. X
  700. X        case 'v':                /* New in Standard    */
  701. X#if ('v' == '\v' || '\v' == VT)
  702. X        value = VT;            /* Use predefined value    */
  703. X#else
  704. X        value = '\v';            /* Use compiler's value    */
  705. X#endif
  706. X        break;
  707. X
  708. X        case 'x':                /* '\xFF'        */
  709. X        count = 3;
  710. X        value = 0;
  711. X        while ((((c = get()) >= '0' && c <= '9')
  712. X             || (c >= 'a' && c <= 'f')
  713. X             || (c >= 'A' && c <= 'F'))
  714. X            && (--count >= 0)) {
  715. X            value *= 16;
  716. X            value += (c <= '9') ? (c - '0') : ((c & 0xF) + 9);
  717. X        }
  718. X        unget();
  719. X        break;
  720. X
  721. X        default:
  722. X        if (c >= '0' && c <= '7') {
  723. X            count = 3;
  724. X            value = 0;
  725. X            while (c >= '0' && c <= '7' && --count >= 0) {
  726. X            value *= 8;
  727. X            value += (c - '0');
  728. X            c = get();
  729. X            }
  730. X            unget();
  731. X        }
  732. X        else value = c;
  733. X        break;
  734. X        }
  735. X    }
  736. X    else if (c == '\'')
  737. X        value = 0;
  738. X    else value = c;
  739. X    /*
  740. X     * We warn on multi-byte constants and try to hack
  741. X     * (big|little)endian machines.
  742. X     */
  743. X#if BIG_ENDIAN
  744. X    count = 0;
  745. X#endif
  746. X    while ((c = get()) != '\'' && c != EOF_CHAR && c != '\n') {
  747. X        if (!skip)
  748. X        ciwarn("multi-byte constant '%c' isn't portable", c);
  749. X#if BIG_ENDIAN
  750. X        count += BITS_CHAR;
  751. X        value += (c << count);
  752. X#else
  753. X        value <<= BITS_CHAR;
  754. X        value += c;
  755. X#endif
  756. X    }
  757. X    instring = FALSE;
  758. X    return (value);
  759. X}
  760. X
  761. XFILE_LOCAL int *
  762. Xevaleval(valp, op, skip)
  763. Xregister int    *valp;
  764. Xint        op;
  765. Xint        skip;        /* TRUE if short-circuit evaluation    */
  766. X/*
  767. X * Apply the argument operator to the data on the value stack.
  768. X * One or two values are popped from the value stack and the result
  769. X * is pushed onto the value stack.
  770. X *
  771. X * OP_COL is a special case.
  772. X *
  773. X * evaleval() returns the new pointer to the top of the value stack.
  774. X */
  775. X{
  776. X    register int    v1, v2;
  777. X
  778. X    if (isbinary(op))
  779. X        v2 = *--valp;
  780. X    v1 = *--valp;
  781. X#ifdef    DEBUG_EVAL
  782. X    printf("%s op %s", (isbinary(op)) ? "binary" : "unary",
  783. X        opname[op]);
  784. X    if (isbinary(op))
  785. X        printf(", v2 = %d.", v2);
  786. X    printf(", v1 = %d.\n", v1);
  787. X#endif
  788. X    switch (op) {
  789. X    case OP_EOE:
  790. X         break;
  791. X
  792. X    case OP_ADD:
  793. X        v1 += v2;
  794. X        break;
  795. X
  796. X    case OP_SUB:
  797. X        v1 -= v2;
  798. X        break;
  799. X
  800. X    case OP_MUL:
  801. X        v1 *= v2;
  802. X        break;
  803. X
  804. X    case OP_DIV:
  805. X    case OP_MOD:
  806. X        if (v2 == 0) {
  807. X        if (!skip) {
  808. X            cwarn("%s by zero in #if, zero result assumed",
  809. X            (op == OP_DIV) ? "divide" : "mod");
  810. X        }
  811. X        v1 = 0;
  812. X        }
  813. X        else if (op == OP_DIV)
  814. X        v1 /= v2;
  815. X        else
  816. X        v1 %= v2;
  817. X        break;
  818. X
  819. X    case OP_ASL:
  820. X        v1 <<= v2;
  821. X        break;
  822. X
  823. X    case OP_ASR:
  824. X        v1 >>= v2;
  825. X        break;
  826. X
  827. X    case OP_AND:
  828. X        v1 &= v2;
  829. X        break;
  830. X
  831. X    case OP_OR:
  832. X        v1 |= v2;
  833. X        break;
  834. X
  835. X    case OP_XOR:
  836. X        v1 ^= v2;
  837. X        break;
  838. X
  839. X    case OP_EQ:
  840. X        v1 = (v1 == v2);
  841. X        break;
  842. X
  843. X    case OP_NE:
  844. X        v1 = (v1 != v2);
  845. X        break;
  846. X
  847. X    case OP_LT:
  848. X        v1 = (v1 < v2);
  849. X        break;
  850. X
  851. X    case OP_LE:
  852. X        v1 = (v1 <= v2);
  853. X        break;
  854. X
  855. X    case OP_GE:
  856. X        v1 = (v1 >= v2);
  857. X        break;
  858. X
  859. X    case OP_GT:
  860. X        v1 = (v1 > v2);
  861. X        break;
  862. X
  863. X    case OP_ANA:
  864. X        v1 = (v1 && v2);
  865. X        break;
  866. X
  867. X    case OP_ORO:
  868. X        v1 = (v1 || v2);
  869. X        break;
  870. X
  871. X    case OP_COL:
  872. X        /*
  873. X         * v1 has the "true" value, v2 the "false" value.
  874. X         * The top of the value stack has the test.
  875. X         */
  876. X        v1 = (*--valp) ? v1 : v2;
  877. X        break;
  878. X
  879. X    case OP_NEG:
  880. X        v1 = (-v1);
  881. X        break;
  882. X
  883. X    case OP_PLU:
  884. X        break;
  885. X
  886. X    case OP_COM:
  887. X        v1 = ~v1;
  888. X        break;
  889. X
  890. X    case OP_NOT:
  891. X        v1 = !v1;
  892. X        break;
  893. X
  894. X    default:
  895. X        cierror("#if bug, operand = %d.", op);
  896. X        v1 = 0;
  897. X    }
  898. X    *valp++ = v1;
  899. X    return (valp);
  900. X}
  901. X
  902. X#ifdef    DEBUG_EVAL
  903. Xdumpstack(opstack, opp, value, valp)
  904. XOPTAB        opstack[NEXP];    /* Operand stack        */
  905. Xregister OPTAB    *opp;        /* Operator stack        */
  906. Xint        value[NEXP];    /* Value stack            */
  907. Xregister int    *valp;        /* -> value vector        */
  908. X{
  909. X    printf("index op prec skip name -- op stack at %s", infile->bptr);
  910. X    while (opp > opstack) {
  911. X        printf(" [%2d] %2d  %03o    %d %s\n", opp - opstack,
  912. X        opp->op, opp->prec, opp->skip, opname[opp->op]);
  913. X        opp--;
  914. X    }
  915. X    while (--valp >= value) {
  916. X        printf("value[%d] = %d\n", (valp - value), *valp);
  917. X    }
  918. X}
  919. X#endif
  920. X
  921. END-of-cpp5.c
  922. echo x - cpp6.c
  923. sed 's/^X//' >cpp6.c << 'END-of-cpp6.c'
  924. X/*
  925. X *                C P P 6 . C
  926. X *        S u p p o r t   R o u t i n e s
  927. X *
  928. X * Edit History
  929. X * 25-May-84 MM        Added 8-bit support to type table.
  930. X * 30-May-84 ARF    sharp() should output filename in quotes
  931. X * 02-Aug-84 MM        Newline and #line hacking.  sharp() now in cpp1.c
  932. X * 31-Aug-84 MM        USENET net.sources release
  933. X * 11-Sep-84 ado/MM    Keepcomments, also line number pathological
  934. X * 12-Sep-84 ado/MM    bug if comment changes to space and we unget later.
  935. X * 03-Oct-84 gkr/MM    Fixed scannumber bug for '.e' (as in struct.element).
  936. X * 04-Oct-84 MM        Added ungetstring() for token concatenation
  937. X * 08-Oct-84 MM        Yet another attack on number scanning
  938. X * 31-Oct-84 ado    Parameterized $ in identifiers
  939. X *  2-Nov-84 MM        Token concatenation is messier than I thought
  940. X *  6-Dec-84 MM        \<nl> is everywhere invisible.
  941. X */
  942. X
  943. X#include    <stdio.h>
  944. X#include    <ctype.h>
  945. X#include    "cppdef.h"
  946. X#include    "cpp.h"
  947. X
  948. X/*
  949. X * skipnl()    skips over input text to the end of the line.
  950. X * skipws()    skips over "whitespace" (spaces or tabs), but
  951. X *        not skip over the end of the line.  It skips over
  952. X *        TOK_SEP, however (though that shouldn't happen).
  953. X * scanid()    reads the next token (C identifier) into token[].
  954. X *        The caller has already read the first character of
  955. X *        the identifier.  Unlike macroid(), the token is
  956. X *        never expanded.
  957. X * macroid()    reads the next token (C identifier) into token[].
  958. X *        If it is a #defined macro, it is expanded, and
  959. X *        macroid() returns TRUE, otherwise, FALSE.
  960. X * catenate()    Does the dirty work of token concatenation, TRUE if it did.
  961. X * scanstring()    Reads a string from the input stream, calling
  962. X *        a user-supplied function for each character.
  963. X *        This function may be output() to write the
  964. X *        string to the output file, or save() to save
  965. X *        the string in the work buffer.
  966. X * scannumber()    Reads a C numeric constant from the input stream,
  967. X *        calling the user-supplied function for each
  968. X *        character.  (output() or save() as noted above.)
  969. X * save()    Save one character in the work[] buffer.
  970. X * savestring()    Saves a string in malloc() memory.
  971. X * getfile()    Initialize a new FILEINFO structure, called when
  972. X *        #include opens a new file, or a macro is to be
  973. X *        expanded.
  974. X * getmem()    Get a specified number of bytes from malloc memory.
  975. X * output()    Write one character to stdout (calling putchar) --
  976. X *        implemented as a function so its address may be
  977. X *        passed to scanstring() and scannumber().
  978. X * lookid()    Scans the next token (identifier) from the input
  979. X *        stream.  Looks for it in the #defined symbol table.
  980. X *        Returns a pointer to the definition, if found, or NULL
  981. X *        if not present.  The identifier is stored in token[].
  982. X * defnedel()    Define enter/delete subroutine.  Updates the
  983. X *        symbol table.
  984. X * get()    Read the next byte from the current input stream,
  985. X *        handling end of (macro/file) input and embedded
  986. X *        comments appropriately.  Note that the global
  987. X *        instring is -- essentially -- a parameter to get().
  988. X * cget()    Like get(), but skip over TOK_SEP.
  989. X * unget()    Push last gotten character back on the input stream.
  990. X * cerror(), cwarn(), cfatal(), cierror(), ciwarn()
  991. X *        These routines format an print messages to the user.
  992. X *        cerror & cwarn take a format and a single string argument.
  993. X *        cierror & ciwarn take a format and a single int (char) argument.
  994. X *        cfatal takes a format and a single string argument.
  995. X */
  996. X
  997. X/*
  998. X * This table must be rewritten for a non-Ascii machine.
  999. X *
  1000. X * Note that several "non-visible" characters have special meaning:
  1001. X * Hex 1D DEF_MAGIC -- a flag to prevent #define recursion.
  1002. X * Hex 1E TOK_SEP   -- a delimiter for token concatenation
  1003. X * Hex 1F COM_SEP   -- a zero-width whitespace for comment concatenation
  1004. X */
  1005. X#if TOK_SEP != 0x1E || COM_SEP != 0x1F || DEF_MAGIC != 0x1D
  1006. X    << error type table isn't correct >>
  1007. X#endif
  1008. X
  1009. X#if OK_DOLLAR
  1010. X#define    DOL    LET
  1011. X#else
  1012. X#define    DOL    000
  1013. X#endif
  1014. X
  1015. Xchar type[256] = {        /* Character type codes    Hex        */
  1016. X   END,   000,   000,   000,   000,   000,   000,   000, /* 00        */
  1017. X   000,   SPA,   000,   000,   000,   000,   000,   000, /* 08        */
  1018. X   000,   000,   000,   000,   000,   000,   000,   000, /* 10        */
  1019. X   000,   000,   000,   000,   000,   LET,   000,   SPA, /* 18        */
  1020. X   SPA,OP_NOT,   QUO,   000,   DOL,OP_MOD,OP_AND,   QUO, /* 20  !"#$%&'    */
  1021. XOP_LPA,OP_RPA,OP_MUL,OP_ADD,   000,OP_SUB,   DOT,OP_DIV, /* 28 ()*+,-./    */
  1022. X   DIG,   DIG,   DIG,   DIG,   DIG,   DIG,   DIG,   DIG, /* 30 01234567    */
  1023. X   DIG,   DIG,OP_COL,   000, OP_LT, OP_EQ, OP_GT,OP_QUE, /* 38 89:;<=>?    */
  1024. X   000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 40 @ABCDEFG    */
  1025. X   LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 48 HIJKLMNO    */
  1026. X   LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 50 PQRSTUVW    */
  1027. X   LET,   LET,   LET,   000,   BSH,   000,OP_XOR,   LET, /* 58 XYZ[\]^_    */
  1028. X   000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 60 `abcdefg    */
  1029. X   LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 68 hijklmno    */
  1030. X   LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 70 pqrstuvw    */
  1031. X   LET,   LET,   LET,   000, OP_OR,   000,OP_NOT,   000, /* 78 xyz{|}~    */
  1032. X   000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF    */
  1033. X   000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF    */
  1034. X   000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF    */
  1035. X   000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF    */
  1036. X   000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF    */
  1037. X   000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF    */
  1038. X   000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF    */
  1039. X   000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF    */
  1040. X};
  1041. X
  1042. Xskipnl()
  1043. X/*
  1044. X * Skip to the end of the current input line.
  1045. X */
  1046. X{
  1047. X    register int        c;
  1048. X
  1049. X    do {                /* Skip to newline    */
  1050. X        c = get();
  1051. X    } while (c != '\n' && c != EOF_CHAR);
  1052. X}
  1053. X
  1054. Xint
  1055. Xskipws()
  1056. X/*
  1057. X * Skip over whitespace
  1058. X */
  1059. X{
  1060. X    register int        c;
  1061. X
  1062. X    do {                /* Skip whitespace    */
  1063. X        c = get();
  1064. X#if COMMENT_INVISIBLE
  1065. X    } while (type[c] == SPA || c == COM_SEP);
  1066. X#else
  1067. X    } while (type[c] == SPA);
  1068. X#endif
  1069. X    return (c);
  1070. X}
  1071. X
  1072. Xscanid(c)
  1073. Xregister int    c;                /* First char of id    */
  1074. X/*
  1075. X * Get the next token (an id) into the token buffer.
  1076. X * Note: this code is duplicated in lookid().
  1077. X * Change one, change both.
  1078. X */
  1079. X{
  1080. X    register char    *bp;
  1081. X
  1082. X    if (c == DEF_MAGIC)            /* Eat the magic token    */
  1083. X        c = get();                /* undefiner.        */
  1084. X    bp = token;
  1085. X    do {
  1086. X        if (bp < &token[IDMAX])        /* token dim is IDMAX+1    */
  1087. X        *bp++ = c;
  1088. X        c = get();
  1089. X    } while (type[c] == LET || type[c] == DIG);
  1090. X    unget();
  1091. X    *bp = EOS;
  1092. X}
  1093. X
  1094. Xint
  1095. Xmacroid(c)
  1096. Xregister int        c;
  1097. X/*
  1098. X * If c is a letter, scan the id.  if it's #defined, expand it and scan
  1099. X * the next character and try again.
  1100. X *
  1101. X * Else, return the character.  If type[c] is a LET, the token is in token.
  1102. X */
  1103. X{
  1104. X    register DEFBUF    *dp;
  1105. X
  1106. X    if (infile != NULL && infile->fp != NULL)
  1107. X        recursion = 0;
  1108. X    while (type[c] == LET && (dp = lookid(c)) != NULL) {
  1109. X        expand(dp);
  1110. X        c = get();
  1111. X    }
  1112. X    return (c);
  1113. X}
  1114. X
  1115. Xint
  1116. Xcatenate()
  1117. X/*
  1118. X * A token was just read (via macroid).
  1119. X * If the next character is TOK_SEP, concatenate the next token
  1120. X * return TRUE -- which should recall macroid after refreshing
  1121. X * macroid's argument.  If it is not TOK_SEP, unget() the character
  1122. X * and return FALSE.
  1123. X */
  1124. X{
  1125. X    register int        c;
  1126. X    register char        *token1;
  1127. X
  1128. X#if OK_CONCAT
  1129. X    if (get() != TOK_SEP) {            /* Token concatenation    */
  1130. X        unget();
  1131. X        return (FALSE);
  1132. X    }
  1133. X    else {
  1134. X        token1 = savestring(token);        /* Save first token    */
  1135. X        c = macroid(get());            /* Scan next token    */
  1136. X        switch(type[c]) {            /* What was it?        */
  1137. X        case LET:                /* An identifier, ...    */
  1138. X        if (strlen(token1) + strlen(token) >= NWORK)
  1139. X            cfatal("work buffer overflow doing %s #", token1);
  1140. X        sprintf(work, "%s%s", token1, token);
  1141. X        break;
  1142. X
  1143. X        case DIG:                /* A digit string    */
  1144. X        strcpy(work, token1);
  1145. X        workp = work + strlen(work);
  1146. X        do {
  1147. X            save(c);
  1148. X        } while ((c = get()) != TOK_SEP);
  1149. X        /*
  1150. X         * The trailing TOK_SEP is no longer needed.
  1151. X         */
  1152. X        save(EOS);
  1153. X        break;
  1154. X
  1155. X        default:                /* An error, ...    */
  1156. X        if (isprint(c))
  1157. X            cierror("Strange character '%c' after #", c);
  1158. X        else
  1159. X            cierror("Strange character (%d.) after #", c);
  1160. X        strcpy(work, token1);
  1161. X        unget();
  1162. X        break;
  1163. X        }
  1164. X        /*
  1165. X         * work has the concatenated token and token1 has
  1166. X         * the first token (no longer needed).  Unget the
  1167. X         * new (concatenated) token after freeing token1.
  1168. X         * Finally, setup to read the new token.
  1169. X         */
  1170. X        free(token1);            /* Free up memory    */
  1171. X        ungetstring(work);            /* Unget the new thing,    */
  1172. X        return (TRUE);
  1173. X    }
  1174. X#else
  1175. X    return (FALSE);                /* Not supported    */
  1176. X#endif
  1177. X}
  1178. X
  1179. Xint
  1180. Xscanstring(delim, outfun)
  1181. Xregister int    delim;            /* ' or "            */
  1182. Xint        (*outfun)();        /* Output function        */
  1183. X/*
  1184. X * Scan off a string.  Warning if terminated by newline or EOF.
  1185. X * outfun() outputs the character -- to a buffer if in a macro.
  1186. X * TRUE if ok, FALSE if error.
  1187. X */
  1188. X{
  1189. X    register int        c;
  1190. X
  1191. X    instring = TRUE;        /* Don't strip comments        */
  1192. X    (*outfun)(delim);
  1193. X    while ((c = get()) != delim
  1194. X         && c != '\n'
  1195. X         && c != EOF_CHAR) {
  1196. X        (*outfun)(c);
  1197. X        if (c == '\\')
  1198. X        (*outfun)(get());
  1199. X    }
  1200. X    instring = FALSE;
  1201. X    if (c == delim) {
  1202. X        (*outfun)(c);
  1203. X        return (TRUE);
  1204. X    }
  1205. X    else {
  1206. X        cerror("Unterminated string", NULLST);
  1207. X        unget();
  1208. X        return (FALSE);
  1209. X    }
  1210. X}
  1211. X
  1212. Xscannumber(c, outfun)
  1213. Xregister int    c;                /* First char of number    */
  1214. Xregister int    (*outfun)();            /* Output/store func    */
  1215. X/*
  1216. X * Process a number.  We know that c is from 0 to 9 or dot.
  1217. X * Algorithm from Dave Conroy's Decus C.
  1218. X */
  1219. X{
  1220. X    register int    radix;            /* 8, 10, or 16        */
  1221. X    int        expseen;        /* 'e' seen in floater    */
  1222. X    int        signseen;        /* '+' or '-' seen    */
  1223. X    int        octal89;        /* For bad octal test    */
  1224. X    int        dotflag;        /* TRUE if '.' was seen    */
  1225. X
  1226. X    expseen = FALSE;            /* No exponent seen yet    */
  1227. X    signseen = TRUE;            /* No +/- allowed yet    */
  1228. X    octal89 = FALSE;            /* No bad octal yet    */
  1229. X    radix = 10;                /* Assume decimal    */
  1230. X    if ((dotflag = (c == '.')) != FALSE) {    /* . something?        */
  1231. X        (*outfun)('.');            /* Always out the dot    */
  1232. X        if (type[(c = get())] != DIG) {    /* If not a float numb,    */
  1233. X        unget();            /* Rescan strange char    */
  1234. X        return;                /* All done for now    */
  1235. X        }
  1236. X    }                    /* End of float test    */
  1237. X    else if (c == '0') {            /* Octal or hex?    */
  1238. X        (*outfun)(c);            /* Stuff initial zero    */
  1239. X        radix = 8;                /* Assume it's octal    */
  1240. X        c = get();                /* Look for an 'x'    */
  1241. X        if (c == 'x' || c == 'X') {        /* Did we get one?    */
  1242. X        radix = 16;            /* Remember new radix    */
  1243. X        (*outfun)(c);            /* Stuff the 'x'    */
  1244. X        c = get();            /* Get next character    */
  1245. X        }
  1246. X    }
  1247. X    for (;;) {                /* Process curr. char.    */
  1248. X        /*
  1249. X         * Note that this algorithm accepts "012e4" and "03.4"
  1250. X         * as legitimate floating-point numbers.
  1251. X         */
  1252. X        if (radix != 16 && (c == 'e' || c == 'E')) {
  1253. X        if (expseen)            /* Already saw 'E'?    */
  1254. X            break;            /* Exit loop, bad nbr.    */
  1255. X        expseen = TRUE;            /* Set exponent seen    */
  1256. X        signseen = FALSE;        /* We can read '+' now    */
  1257. X        radix = 10;            /* Decimal exponent    */
  1258. X        }
  1259. X        else if (radix != 16 && c == '.') {
  1260. X        if (dotflag)            /* Saw dot already?    */
  1261. X            break;            /* Exit loop, two dots    */
  1262. X        dotflag = TRUE;            /* Remember the dot    */
  1263. X        radix = 10;            /* Decimal fraction    */
  1264. X        }
  1265. X        else if (c == '+' || c == '-') {    /* 1.0e+10        */
  1266. X        if (signseen)            /* Sign in wrong place?    */
  1267. X            break;            /* Exit loop, not nbr.    */
  1268. X        /* signseen = TRUE; */        /* Remember we saw it    */
  1269. X        }
  1270. X        else {                /* Check the digit    */
  1271. X        switch (c) {
  1272. X        case '8': case '9':        /* Sometimes wrong    */
  1273. X            octal89 = TRUE;        /* Do check later    */
  1274. X        case '0': case '1': case '2': case '3':
  1275. X        case '4': case '5': case '6': case '7':
  1276. X            break;            /* Always ok        */
  1277. X
  1278. X        case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  1279. X        case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  1280. X            if (radix == 16)        /* Alpha's are ok only     */
  1281. X            break;            /* if reading hex.    */
  1282. X        default:            /* At number end    */
  1283. X            goto done;            /* Break from for loop    */
  1284. X        }                /* End of switch    */
  1285. X        }                    /* End general case    */
  1286. X        (*outfun)(c);            /* Accept the character    */
  1287. X        signseen = TRUE;            /* Don't read sign now    */
  1288. X        c = get();                /* Read another char    */
  1289. X    }                    /* End of scan loop    */
  1290. X    /*
  1291. X     * When we break out of the scan loop, c contains the first
  1292. X     * character (maybe) not in the number.  If the number is an
  1293. X     * integer, allow a trailing 'L' for long and/or a trailing 'U'
  1294. X     * for unsigned.  If not those, push the trailing character back
  1295. X     * on the input stream.  Floating point numbers accept a trailing
  1296. X     * 'L' for "long double".
  1297. X     */
  1298. Xdone:    if (dotflag || expseen) {        /* Floating point?    */
  1299. X        if (c == 'l' || c == 'L') {
  1300. X        (*outfun)(c);
  1301. X        c = get();            /* Ungotten later    */
  1302. X        }
  1303. X    }
  1304. X    else {                    /* Else it's an integer    */
  1305. X        /*
  1306. X         * We know that dotflag and expseen are both zero, now:
  1307. X         * dotflag signals "saw 'L'", and
  1308. X         * expseen signals "saw 'U'".
  1309. X         */
  1310. X        for (;;) {
  1311. X        switch (c) {
  1312. X        case 'l':
  1313. X        case 'L':
  1314. X            if (dotflag)
  1315. X            goto nomore;
  1316. X            dotflag = TRUE;
  1317. X            break;
  1318. X
  1319. X        case 'u':
  1320. X        case 'U':
  1321. X            if (expseen)
  1322. X            goto nomore;
  1323. X            expseen = TRUE;
  1324. X            break;
  1325. X
  1326. X        default:
  1327. X            goto nomore;
  1328. X        }
  1329. X        (*outfun)(c);            /* Got 'L' or 'U'.    */
  1330. X        c = get();            /* Look at next, too.    */
  1331. X        }
  1332. X    }
  1333. Xnomore:    unget();                /* Not part of a number    */
  1334. X    if (octal89 && radix == 8)
  1335. X        cwarn("Illegal digit in octal number", NULLST);
  1336. X}
  1337. X
  1338. Xsave(c)
  1339. Xregister int    c;
  1340. X{
  1341. X    if (workp >= &work[NWORK])
  1342. X        cfatal("Work buffer overflow", NULLST);
  1343. X    else *workp++ = c;
  1344. X}
  1345. X
  1346. Xchar *
  1347. Xsavestring(text)
  1348. Xchar        *text;
  1349. X/*
  1350. X * Store a string into free memory.
  1351. X */
  1352. X{
  1353. X    register char    *result;
  1354. X
  1355. X    result = getmem(strlen(text) + 1);
  1356. X    strcpy(result, text);
  1357. X    return (result);
  1358. X}
  1359. X
  1360. XFILEINFO    *
  1361. Xgetfile(bufsize, name)
  1362. Xint        bufsize;        /* Line or define buffer size    */
  1363. Xchar        *name;            /* File or macro name string    */
  1364. X/*
  1365. X * Common FILEINFO buffer initialization for a new file or macro.
  1366. X */
  1367. X{
  1368. X    register FILEINFO    *file;
  1369. X    register int        size;
  1370. X
  1371. X    size = strlen(name);            /* File/macro name    */
  1372. X    file = (FILEINFO *) getmem(sizeof (FILEINFO) + bufsize + size);
  1373. X    file->parent = infile;            /* Chain files together    */
  1374. X    file->fp = NULL;            /* No file yet        */
  1375. X    file->filename = savestring(name);    /* Save file/macro name    */
  1376. X    file->progname = NULL;            /* No #line seen yet    */
  1377. X    file->unrecur = 0;            /* No macro fixup    */
  1378. X    file->bptr = file->buffer;        /* Initialize line ptr    */
  1379. X    file->buffer[0] = EOS;            /* Force first read    */
  1380. X    file->line = 0;                /* (Not used just yet)    */
  1381. X    if (infile != NULL)            /* If #include file    */
  1382. X        infile->line = line;        /* Save current line    */
  1383. X    infile = file;                /* New current file    */
  1384. X    line = 1;                /* Note first line    */
  1385. X    return (file);                /* All done.        */
  1386. X}
  1387. X
  1388. Xchar *
  1389. Xgetmem(size)
  1390. Xint        size;
  1391. X/*
  1392. X * Get a block of free memory.
  1393. X */
  1394. X{
  1395. X    register char    *result;
  1396. X    extern char    *malloc();
  1397. X
  1398. X    if ((result = malloc((unsigned) size)) == NULL)
  1399. X        cfatal("Out of memory", NULLST);
  1400. X    return (result);
  1401. X}
  1402. X
  1403. X/*
  1404. X *            C P P   S y m b o l   T a b l e s
  1405. X */
  1406. X
  1407. X/*
  1408. X * SBSIZE defines the number of hash-table slots for the symbol table.
  1409. X * It must be a power of 2.
  1410. X */
  1411. X#ifndef    SBSIZE
  1412. X#define    SBSIZE    64
  1413. X#endif
  1414. X#define    SBMASK    (SBSIZE - 1)
  1415. X#if (SBSIZE ^ SBMASK) != ((SBSIZE * 2) - 1)
  1416. X    << error, SBSIZE must be a power of 2 >>
  1417. X#endif
  1418. X
  1419. Xstatic DEFBUF    *symtab[SBSIZE];    /* Symbol table queue headers    */
  1420. X
  1421. XDEFBUF *
  1422. Xlookid(c)
  1423. Xint    c;                /* First character of token    */
  1424. X/*
  1425. X * Look for the next token in the symbol table.  Returns token in "token".
  1426. X * If found, returns the table pointer;  Else returns NULL.
  1427. X */
  1428. X{
  1429. X    register int        nhash;
  1430. X    register DEFBUF        *dp;
  1431. X    register char        *np;
  1432. X    int            temp;
  1433. X    int            isrecurse;    /* For #define foo foo    */
  1434. X
  1435. X    np = token;
  1436. X    nhash = 0;
  1437. X    if ((isrecurse = (c == DEF_MAGIC)))    /* If recursive macro    */
  1438. X        c = get();                /* hack, skip DEF_MAGIC    */
  1439. X    do {
  1440. X        if (np < &token[IDMAX]) {        /* token dim is IDMAX+1    */
  1441. X        *np++ = c;            /* Store token byte    */
  1442. X        nhash += c;            /* Update hash value    */
  1443. X        }
  1444. X        c = get();                /* And get another byte    */
  1445. X    } while (type[c] == LET || type[c] == DIG);
  1446. X    unget();                /* Rescan terminator    */
  1447. X    *np = EOS;                /* Terminate token    */
  1448. X    if (isrecurse)                /* Recursive definition    */
  1449. X        return (NULL);            /* undefined just now    */
  1450. X    nhash += (np - token);            /* Fix hash value    */
  1451. X    dp = symtab[nhash & SBMASK];        /* Starting bucket    */
  1452. X    while (dp != (DEFBUF *) NULL) {        /* Search symbol table    */
  1453. X        if (dp->hash == nhash        /* Fast precheck    */
  1454. X         && (temp = strcmp(dp->name, token)) >= 0)
  1455. X        break;
  1456. X        dp = dp->link;            /* Nope, try next one    */
  1457. X    }
  1458. X    return ((temp == 0) ? dp : NULL);
  1459. X}
  1460. X
  1461. XDEFBUF *
  1462. Xdefendel(name, delete)
  1463. Xchar        *name;
  1464. Xint        delete;            /* TRUE to delete a symbol    */
  1465. X/*
  1466. X * Enter this name in the lookup table (delete = FALSE)
  1467. X * or delete this name (delete = TRUE).
  1468. X * Returns a pointer to the define block (delete = FALSE)
  1469. X * Returns NULL if the symbol wasn't defined (delete = TRUE).
  1470. X */
  1471. X{
  1472. X    register DEFBUF        *dp;
  1473. X    register DEFBUF        **prevp;
  1474. X    register char        *np;
  1475. X    int            nhash;
  1476. X    int            temp;
  1477. X    int            size;
  1478. X
  1479. X    for (nhash = 0, np = name; *np != EOS;)
  1480. X        nhash += *np++;
  1481. X    size = (np - name);
  1482. X    nhash += size;
  1483. X    prevp = &symtab[nhash & SBMASK];
  1484. X    while ((dp = *prevp) != (DEFBUF *) NULL) {
  1485. X        if (dp->hash == nhash
  1486. X         && (temp = strcmp(dp->name, name)) >= 0) {
  1487. X        if (temp > 0)
  1488. X            dp = NULL;            /* Not found        */
  1489. X        else {
  1490. X            *prevp = dp->link;        /* Found, unlink and    */
  1491. X            if (dp->repl != NULL)    /* Free the replacement    */
  1492. X            free(dp->repl);        /* if any, and then    */
  1493. X            free((char *) dp);        /* Free the symbol    */
  1494. X        }
  1495. X        break;
  1496. X        }
  1497. X        prevp = &dp->link;
  1498. X    }
  1499. X    if (!delete) {
  1500. X        dp = (DEFBUF *) getmem(sizeof (DEFBUF) + size);
  1501. X        dp->link = *prevp;
  1502. X        *prevp = dp;
  1503. X        dp->hash = nhash;
  1504. X        dp->repl = NULL;
  1505. X        dp->nargs = 0;
  1506. X        strcpy(dp->name, name);
  1507. X    }
  1508. X    return (dp);
  1509. X}
  1510. X
  1511. X#if DEBUG
  1512. X
  1513. Xdumpdef(why)
  1514. Xchar        *why;
  1515. X{
  1516. X    register DEFBUF        *dp;
  1517. X    register DEFBUF        **syp;
  1518. X
  1519. X    printf("CPP symbol table dump %s\n", why);
  1520. X    for (syp = symtab; syp < &symtab[SBSIZE]; syp++) {
  1521. X        if ((dp = *syp) != (DEFBUF *) NULL) {
  1522. X        printf("symtab[%d]\n", (syp - symtab));
  1523. X        do {
  1524. X            dumpadef((char *) NULL, dp);
  1525. X        } while ((dp = dp->link) != (DEFBUF *) NULL);
  1526. X        }
  1527. X    }
  1528. X}
  1529. X
  1530. Xdumpadef(why, dp)
  1531. Xchar        *why;            /* Notation            */
  1532. Xregister DEFBUF    *dp;
  1533. X{
  1534. X    register char        *cp;
  1535. X    register int        c;
  1536. X
  1537. X    printf(" \"%s\" [%d]", dp->name, dp->nargs);
  1538. X    if (why != NULL)
  1539. X        printf(" (%s)", why);
  1540. X    if (dp->repl != NULL) {
  1541. X        printf(" => ");
  1542. X        for (cp = dp->repl; (c = *cp++ & 0xFF) != EOS;) {
  1543. X        if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC))
  1544. X            printf("<%d>", c - MAC_PARM);
  1545. X        else if (isprint(c) || c == '\n' || c == '\t')
  1546. X            putchar(c);
  1547. X        else if (c < ' ')
  1548. X            printf("<^%c>", c + '@');
  1549. X        else
  1550. X            printf("<\\0%o>", c);
  1551. X        }
  1552. X    }
  1553. X    else {
  1554. X        printf(", no replacement.");
  1555. X    }
  1556. X    putchar('\n');
  1557. X}
  1558. X#endif
  1559. X
  1560. X/*
  1561. X *            G E T
  1562. X */
  1563. X
  1564. Xint
  1565. Xget()
  1566. X/*
  1567. X * Return the next character from a macro or the current file.
  1568. X * Handle end of file from #include files.
  1569. X */
  1570. X{
  1571. X    register int        c;
  1572. X    register FILEINFO    *file;
  1573. X    register int        popped;        /* Recursion fixup    */
  1574. X
  1575. X    popped = 0;
  1576. Xget_from_file:
  1577. X    if ((file = infile) == NULL)
  1578. X        return (EOF_CHAR);
  1579. Xnewline:
  1580. X#if 0
  1581. X    printf("get(%s), recursion %d, line %d, bptr = %d, buffer \"%s\"\n",
  1582. X        file->filename, recursion, line,
  1583. X        file->bptr - file->buffer, file->buffer);
  1584. X#endif
  1585. X    /*
  1586. X     * Read a character from the current input line or macro.
  1587. X     * At EOS, either finish the current macro (freeing temp.
  1588. X     * storage) or read another line from the current input file.
  1589. X     * At EOF, exit the current file (#include) or, at EOF from
  1590. X     * the cpp input file, return EOF_CHAR to finish processing.
  1591. X     */
  1592. X    if ((c = *file->bptr++ & 0xFF) == EOS) {
  1593. X        /*
  1594. X         * Nothing in current line or macro.  Get next line (if
  1595. X         * input from a file), or do end of file/macro processing.
  1596. X         * In the latter case, jump back to restart from the top.
  1597. X         */
  1598. X        if (file->fp == NULL) {        /* NULL if macro    */
  1599. X        popped++;
  1600. X        recursion -= file->unrecur;
  1601. X        if (recursion < 0)
  1602. X            recursion = 0;
  1603. X        infile = file->parent;        /* Unwind file chain    */
  1604. X        }
  1605. X        else {                /* Else get from a file    */
  1606. X        if ((file->bptr = fgets(file->buffer, NBUFF, file->fp))
  1607. X            != NULL) {
  1608. X#if DEBUG
  1609. X            if (debug > 1) {        /* Dump it to stdout    */
  1610. X            printf("\n#line %d (%s), %s",
  1611. X                line, file->filename, file->buffer);
  1612. X            }
  1613. X#endif
  1614. X            goto newline;        /* process the line    */
  1615. X        }
  1616. X        else {
  1617. X            fclose(file->fp);        /* Close finished file    */
  1618. X            if ((infile = file->parent) != NULL) {
  1619. X            /*
  1620. X             * There is an "ungotten" newline in the current
  1621. X             * infile buffer (set there by doinclude() in
  1622. X             * cpp1.c).  Thus, we know that the mainline code
  1623. X             * is skipping over blank lines and will do a
  1624. X             * #line at its convenience.
  1625. X             */
  1626. X            wrongline = TRUE;    /* Need a #line now    */
  1627. X            }
  1628. X        }
  1629. X        }
  1630. X        /*
  1631. X         * Free up space used by the (finished) file or macro and
  1632. X         * restart input from the parent file/macro, if any.
  1633. X         */
  1634. X        free(file->filename);        /* Free name and    */
  1635. X        if (file->progname != NULL)        /* if a #line was seen,    */
  1636. X        free(file->progname);        /* free it, too.    */
  1637. X        free((char *) file);        /* Free file space    */
  1638. X        if (infile == NULL)            /* If at end of file    */
  1639. X        return (EOF_CHAR);        /* Return end of file    */
  1640. X        line = infile->line;         /* Reset line number    */
  1641. X        goto get_from_file;            /* Get from the top.    */
  1642. X    }
  1643. X    /*
  1644. X     * Common processing for the new character.
  1645. X     */
  1646. X    if (c == DEF_MAGIC && file->fp != NULL)    /* Don't allow delete    */
  1647. X        goto newline;            /* from a file        */
  1648. X    if (file->parent != NULL) {        /* Macro or #include    */
  1649. X        if (popped != 0)
  1650. X        file->parent->unrecur += popped;
  1651. X        else {
  1652. X        recursion -= file->parent->unrecur;
  1653. X        if (recursion < 0)
  1654. X            recursion = 0;
  1655. X        file->parent->unrecur = 0;
  1656. X        }
  1657. X    }
  1658. X    if (c == '\n')                /* Maintain current    */
  1659. X        ++line;                /* line counter        */
  1660. X    if (instring)                /* Strings just return    */
  1661. X        return (c);                /* the character.    */
  1662. X    else if (c == '/') {            /* Comment?        */
  1663. X        instring = TRUE;            /* So get() won't loop    */
  1664. X        if ((c = get()) != '*') {        /* Next byte '*'?    */
  1665. X        instring = FALSE;        /* Nope, no comment    */
  1666. X        unget();            /* Push the char. back    */
  1667. X        return ('/');            /* Return the slash    */
  1668. X        }
  1669. X        if (keepcomments) {            /* If writing comments    */
  1670. X        putchar('/');            /* Write out the    */
  1671. X        putchar('*');            /*   initializer    */
  1672. X        }
  1673. X        for (;;) {                /* Eat a comment    */
  1674. X        c = get();
  1675. Xtest:        if (keepcomments && c != EOF_CHAR)
  1676. X            cput(c);
  1677. X        switch (c) {
  1678. X        case EOF_CHAR:
  1679. X            cerror("EOF in comment", NULLST);
  1680. X            return (EOF_CHAR);
  1681. X
  1682. X        case '/':
  1683. X            if ((c = get()) != '*')    /* Don't let comments    */
  1684. X            goto test;        /* Nest.        */
  1685. X#ifdef VERBOSE
  1686. X            cwarn("Nested comments", NULLST);
  1687. X#endif
  1688. X                        /* Fall into * stuff    */
  1689. X        case '*':
  1690. X            if ((c = get()) != '/')    /* If comment doesn't    */
  1691. X            goto test;        /* end, look at next    */
  1692. X            instring = FALSE;        /* End of comment,    */
  1693. X            if (keepcomments) {        /* Put out the comment    */
  1694. X            cput(c);        /* terminator, too    */
  1695. X            }
  1696. X            /*
  1697. X             * A comment is syntactically "whitespace" --
  1698. X             * however, there are certain strange sequences
  1699. X             * such as
  1700. X             *        #define foo(x)    (something)
  1701. X             *            foo|* comment *|(123)
  1702. X             *       these are '/' ^           ^
  1703. X             * where just returning space (or COM_SEP) will cause
  1704. X             * problems.  This can be "fixed" by overwriting the
  1705. X             * '/' in the input line buffer with ' ' (or COM_SEP)
  1706. X             * but that may mess up an error message.
  1707. X             * So, we peek ahead -- if the next character is
  1708. X             * "whitespace" we just get another character, if not,
  1709. X             * we modify the buffer.  All in the name of purity.
  1710. X             */
  1711. X            if (*file->bptr == '\n'
  1712. X             || type[*file->bptr & 0xFF] == SPA)
  1713. X            goto newline;
  1714. X#if COMMENT_INVISIBLE
  1715. X            /*
  1716. X             * Return magic (old-fashioned) syntactic space.
  1717. X             */
  1718. X            return ((file->bptr[-1] = COM_SEP));
  1719. X#else
  1720. X            return ((file->bptr[-1] = ' '));
  1721. X#endif
  1722. X
  1723. X        case '\n':            /* we'll need a #line    */
  1724. X            if (!keepcomments)
  1725. X            wrongline = TRUE;    /* later...        */
  1726. X        default:            /* Anything else is    */
  1727. X            break;            /* Just a character    */
  1728. X        }                /* End switch        */
  1729. X        }                    /* End comment loop    */
  1730. X    }                    /* End if in comment    */
  1731. X    else if (!inmacro && c == '\\') {    /* If backslash, peek     */
  1732. X        if ((c = get()) == '\n') {        /* for a <nl>.  If so,    */
  1733. X        wrongline = TRUE;
  1734. X        goto newline;
  1735. X        }
  1736. X        else {                /* Backslash anything    */
  1737. X        unget();            /* Get it later        */
  1738. X        return ('\\');            /* Return the backslash    */
  1739. X        }
  1740. X    }
  1741. X    else if (c == '\f' || c == VT)        /* Form Feed, Vertical    */
  1742. X        c = ' ';                /* Tab are whitespace    */
  1743. X    return (c);                /* Just return the char    */
  1744. X}
  1745. X
  1746. Xunget()
  1747. X/*
  1748. X * Backup the pointer to reread the last character.  Fatal error
  1749. X * (code bug) if we backup too far.  unget() may be called,
  1750. X * without problems, at end of file.  Only one character may
  1751. X * be ungotten.  If you need to unget more, call ungetstring().
  1752. X */
  1753. X{
  1754. X    register FILEINFO    *file;
  1755. X
  1756. X    if ((file = infile) == NULL)
  1757. X        return;            /* Unget after EOF        */
  1758. X    if (--file->bptr < file->buffer)
  1759. X        cfatal("Too much pushback", NULLST);
  1760. X    if (*file->bptr == '\n')    /* Ungetting a newline?        */
  1761. X        --line;            /* Unget the line number, too    */
  1762. X}
  1763. X
  1764. Xungetstring(text)
  1765. Xchar        *text;
  1766. X/*
  1767. X * Push a string back on the input stream.  This is done by treating
  1768. X * the text as if it were a macro.
  1769. X */
  1770. X{
  1771. X    register FILEINFO    *file;
  1772. X    extern FILEINFO        *getfile();
  1773. X
  1774. X    file = getfile(strlen(text) + 1, "");
  1775. X    strcpy(file->buffer, text);
  1776. X}
  1777. X
  1778. Xint
  1779. Xcget()
  1780. X/*
  1781. X * Get one character, absorb "funny space" after comments or
  1782. X * token concatenation
  1783. X */
  1784. X{
  1785. X    register int    c;
  1786. X
  1787. X    do {
  1788. X        c = get();
  1789. X#if COMMENT_INVISIBLE
  1790. X    } while (c == TOK_SEP || c == COM_SEP);
  1791. X#else
  1792. X    } while (c == TOK_SEP);
  1793. X#endif
  1794. X    return (c);
  1795. X}
  1796. X
  1797. X/*
  1798. X * Error messages and other hacks.  The first byte of severity
  1799. X * is 'S' for string arguments and 'I' for int arguments.  This
  1800. X * is needed for portability with machines that have int's that
  1801. X * are shorter than  char *'s.
  1802. X */
  1803. X
  1804. Xstatic
  1805. Xdomsg(severity, format, arg)
  1806. Xchar        *severity;        /* "Error", "Warning", "Fatal"    */
  1807. Xchar        *format;        /* Format for the error message    */
  1808. Xchar        *arg;            /* Something for the message    */
  1809. X/*
  1810. X * Print filenames, macro names, and line numbers for error messages.
  1811. X */
  1812. X{
  1813. X    register char        *tp;
  1814. X    register FILEINFO    *file;
  1815. X
  1816. X    fprintf(stderr, "%sline %d, %s: ", MSG_PREFIX, line, &severity[1]);
  1817. X    if (*severity == 'S')
  1818. X        fprintf(stderr, format, arg);
  1819. X    else
  1820. X        fprintf(stderr, format, (int) arg);
  1821. X    putc('\n', stderr);
  1822. X    if ((file = infile) == NULL)
  1823. X        return;                /* At end of file    */
  1824. X    if (file->fp != NULL) {
  1825. X        tp = file->buffer;            /* Print current file    */
  1826. X        fprintf(stderr, "%s", tp);        /* name, making sure    */
  1827. X        if (tp[strlen(tp) - 1] != '\n')    /* there's a newline    */
  1828. X        putc('\n', stderr);
  1829. X    }
  1830. X    while ((file = file->parent) != NULL) {    /* Print #includes, too    */
  1831. X        if (file->fp == NULL)
  1832. X        fprintf(stderr, "from macro %s\n", file->filename);
  1833. X        else {
  1834. X        tp = file->buffer;
  1835. X        fprintf(stderr, "from file %s, line %d:\n%s",
  1836. X            (file->progname != NULL)
  1837. X            ? file->progname : file->filename,
  1838. X            file->line, tp);
  1839. X        if (tp[strlen(tp) - 1] != '\n')
  1840. X            putc('\n', stderr);
  1841. X        }
  1842. X    }
  1843. X}
  1844. X
  1845. Xcerror(format, sarg)
  1846. Xchar        *format;
  1847. Xchar        *sarg;        /* Single string argument        */
  1848. X/*
  1849. X * Print a normal error message, string argument.
  1850. X */
  1851. X{
  1852. X    domsg("SError", format, sarg);
  1853. X    errors++;
  1854. X}
  1855. X
  1856. Xcierror(format, narg)
  1857. Xchar        *format;
  1858. Xint        narg;        /* Single numeric argument        */
  1859. X/*
  1860. X * Print a normal error message, numeric argument.
  1861. X */
  1862. X{
  1863. X    domsg("IError", format, (char *) narg);
  1864. X    errors++;
  1865. X}
  1866. X
  1867. Xcfatal(format, sarg)
  1868. Xchar        *format;
  1869. Xchar        *sarg;            /* Single string argument    */
  1870. X/*
  1871. X * A real disaster
  1872. X */
  1873. X{
  1874. X    domsg("SFatal error", format, sarg);
  1875. X    exit(IO_ERROR);
  1876. X}
  1877. X
  1878. Xcwarn(format, sarg)
  1879. Xchar        *format;
  1880. Xchar        *sarg;            /* Single string argument    */
  1881. X/*
  1882. X * A non-fatal error, string argument.
  1883. X */
  1884. X{
  1885. X    domsg("SWarning", format, sarg);
  1886. X}
  1887. X
  1888. Xciwarn(format, narg)
  1889. Xchar        *format;
  1890. Xint        narg;            /* Single numeric argument    */
  1891. X/*
  1892. X * A non-fatal error, numeric argument.
  1893. X */
  1894. X{
  1895. X    domsg("IWarning", format, (char *) narg);
  1896. X}
  1897. X
  1898. X
  1899. X
  1900. END-of-cpp6.c
  1901. exit
  1902.