home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / games / volume16 / nethck31 / part08 < prev    next >
Encoding:
Internet Message Format  |  1993-01-31  |  58.6 KB

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