xref: /aoo4110/main/rsc/source/rscpp/cpp6.c (revision b1cdbd2c)
1*b1cdbd2cSJim Jagielski /**************************************************************
2*b1cdbd2cSJim Jagielski  *
3*b1cdbd2cSJim Jagielski  * Licensed to the Apache Software Foundation (ASF) under one
4*b1cdbd2cSJim Jagielski  * or more contributor license agreements.  See the NOTICE file
5*b1cdbd2cSJim Jagielski  * distributed with this work for additional information
6*b1cdbd2cSJim Jagielski  * regarding copyright ownership.  The ASF licenses this file
7*b1cdbd2cSJim Jagielski  * to you under the Apache License, Version 2.0 (the
8*b1cdbd2cSJim Jagielski  * "License"); you may not use this file except in compliance
9*b1cdbd2cSJim Jagielski  * with the License.  You may obtain a copy of the License at
10*b1cdbd2cSJim Jagielski  *
11*b1cdbd2cSJim Jagielski  *   http://www.apache.org/licenses/LICENSE-2.0
12*b1cdbd2cSJim Jagielski  *
13*b1cdbd2cSJim Jagielski  * Unless required by applicable law or agreed to in writing,
14*b1cdbd2cSJim Jagielski  * software distributed under the License is distributed on an
15*b1cdbd2cSJim Jagielski  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b1cdbd2cSJim Jagielski  * KIND, either express or implied.  See the License for the
17*b1cdbd2cSJim Jagielski  * specific language governing permissions and limitations
18*b1cdbd2cSJim Jagielski  * under the License.
19*b1cdbd2cSJim Jagielski  *
20*b1cdbd2cSJim Jagielski  *************************************************************/
21*b1cdbd2cSJim Jagielski 
22*b1cdbd2cSJim Jagielski 
23*b1cdbd2cSJim Jagielski 
24*b1cdbd2cSJim Jagielski #include        <stdio.h>
25*b1cdbd2cSJim Jagielski #include        <ctype.h>
26*b1cdbd2cSJim Jagielski #include        <string.h>
27*b1cdbd2cSJim Jagielski #include        "cppdef.h"
28*b1cdbd2cSJim Jagielski #include        "cpp.h"
29*b1cdbd2cSJim Jagielski 
30*b1cdbd2cSJim Jagielski /*ER evaluate macros to pDefOut */
31*b1cdbd2cSJim Jagielski 
32*b1cdbd2cSJim Jagielski /*
33*b1cdbd2cSJim Jagielski  * skipnl()     skips over input text to the end of the line.
34*b1cdbd2cSJim Jagielski  * skipws()     skips over "whitespace" (spaces or tabs), but
35*b1cdbd2cSJim Jagielski  *              not skip over the end of the line.  It skips over
36*b1cdbd2cSJim Jagielski  *              TOK_SEP, however (though that shouldn't happen).
37*b1cdbd2cSJim Jagielski  * scanid()     reads the next token (C identifier) into token[].
38*b1cdbd2cSJim Jagielski  *              The caller has already read the first character of
39*b1cdbd2cSJim Jagielski  *              the identifier.  Unlike macroid(), the token is
40*b1cdbd2cSJim Jagielski  *              never expanded.
41*b1cdbd2cSJim Jagielski  * macroid()    reads the next token (C identifier) into token[].
42*b1cdbd2cSJim Jagielski  *              If it is a #defined macro, it is expanded, and
43*b1cdbd2cSJim Jagielski  *              macroid() returns TRUE, otherwise, FALSE.
44*b1cdbd2cSJim Jagielski  * catenate()   Does the dirty work of token concatenation, TRUE if it did.
45*b1cdbd2cSJim Jagielski  * scanstring() Reads a string from the input stream, calling
46*b1cdbd2cSJim Jagielski  *              a user-supplied function for each character.
47*b1cdbd2cSJim Jagielski  *              This function may be output() to write the
48*b1cdbd2cSJim Jagielski  *              string to the output file, or save() to save
49*b1cdbd2cSJim Jagielski  *              the string in the work buffer.
50*b1cdbd2cSJim Jagielski  * scannumber() Reads a C numeric constant from the input stream,
51*b1cdbd2cSJim Jagielski  *              calling the user-supplied function for each
52*b1cdbd2cSJim Jagielski  *              character.  (output() or save() as noted above.)
53*b1cdbd2cSJim Jagielski  * save()       Save one character in the work[] buffer.
54*b1cdbd2cSJim Jagielski  * savestring() Saves a string in malloc() memory.
55*b1cdbd2cSJim Jagielski  * getfile()    Initialize a new FILEINFO structure, called when
56*b1cdbd2cSJim Jagielski  *              #include opens a new file, or a macro is to be
57*b1cdbd2cSJim Jagielski  *              expanded.
58*b1cdbd2cSJim Jagielski  * getmem()     Get a specified number of bytes from malloc memory.
59*b1cdbd2cSJim Jagielski  * output()     Write one character to stdout (calling PUTCHAR) --
60*b1cdbd2cSJim Jagielski  *              implemented as a function so its address may be
61*b1cdbd2cSJim Jagielski  *              passed to scanstring() and scannumber().
62*b1cdbd2cSJim Jagielski  * lookid()     Scans the next token (identifier) from the input
63*b1cdbd2cSJim Jagielski  *              stream.  Looks for it in the #defined symbol table.
64*b1cdbd2cSJim Jagielski  *              Returns a pointer to the definition, if found, or NULL
65*b1cdbd2cSJim Jagielski  *              if not present.  The identifier is stored in token[].
66*b1cdbd2cSJim Jagielski  * defnedel()   Define enter/delete subroutine.  Updates the
67*b1cdbd2cSJim Jagielski  *              symbol table.
68*b1cdbd2cSJim Jagielski  * get()        Read the next byte from the current input stream,
69*b1cdbd2cSJim Jagielski  *              handling end of (macro/file) input and embedded
70*b1cdbd2cSJim Jagielski  *              comments appropriately.  Note that the global
71*b1cdbd2cSJim Jagielski  *              instring is -- essentially -- a parameter to get().
72*b1cdbd2cSJim Jagielski  * cget()       Like get(), but skip over TOK_SEP.
73*b1cdbd2cSJim Jagielski  * unget()      Push last gotten character back on the input stream.
74*b1cdbd2cSJim Jagielski  * cerror(), cwarn(), cfatal(), cierror(), ciwarn()
75*b1cdbd2cSJim Jagielski  *              These routines format an print messages to the user.
76*b1cdbd2cSJim Jagielski  *              cerror & cwarn take a format and a single string argument.
77*b1cdbd2cSJim Jagielski  *              cierror & ciwarn take a format and a single int (char) argument.
78*b1cdbd2cSJim Jagielski  *              cfatal takes a format and a single string argument.
79*b1cdbd2cSJim Jagielski  */
80*b1cdbd2cSJim Jagielski 
81*b1cdbd2cSJim Jagielski /*
82*b1cdbd2cSJim Jagielski  * This table must be rewritten for a non-Ascii machine.
83*b1cdbd2cSJim Jagielski  *
84*b1cdbd2cSJim Jagielski  * Note that several "non-visible" characters have special meaning:
85*b1cdbd2cSJim Jagielski  * Hex 1D DEF_MAGIC -- a flag to prevent #define recursion.
86*b1cdbd2cSJim Jagielski  * Hex 1E TOK_SEP   -- a delimiter for token concatenation
87*b1cdbd2cSJim Jagielski  * Hex 1F COM_SEP   -- a zero-width whitespace for comment concatenation
88*b1cdbd2cSJim Jagielski  */
89*b1cdbd2cSJim Jagielski #if TOK_SEP != 0x1E || COM_SEP != 0x1F || DEF_MAGIC != 0x1D
90*b1cdbd2cSJim Jagielski         << error type table is not correct >>
91*b1cdbd2cSJim Jagielski #endif
92*b1cdbd2cSJim Jagielski 
93*b1cdbd2cSJim Jagielski #if OK_DOLLAR
94*b1cdbd2cSJim Jagielski #define DOL     LET
95*b1cdbd2cSJim Jagielski #else
96*b1cdbd2cSJim Jagielski #define DOL     000
97*b1cdbd2cSJim Jagielski #endif
98*b1cdbd2cSJim Jagielski 
99*b1cdbd2cSJim Jagielski #ifdef EBCDIC
100*b1cdbd2cSJim Jagielski 
101*b1cdbd2cSJim Jagielski char type[256] = {              /* Character type codes    Hex          */
102*b1cdbd2cSJim Jagielski    END,   000,   000,   000,   000,   SPA,   000,   000, /* 00          */
103*b1cdbd2cSJim Jagielski    000,   000,   000,   000,   000,   000,   000,   000, /* 08          */
104*b1cdbd2cSJim Jagielski    000,   000,   000,   000,   000,   000,   000,   000, /* 10          */
105*b1cdbd2cSJim Jagielski    000,   000,   000,   000,   000,   LET,   000,   SPA, /* 18          */
106*b1cdbd2cSJim Jagielski    000,   000,   000,   000,   000,   000,   000,   000, /* 20          */
107*b1cdbd2cSJim Jagielski    000,   000,   000,   000,   000,   000,   000,   000, /* 28          */
108*b1cdbd2cSJim Jagielski    000,   000,   000,   000,   000,   000,   000,   000, /* 30          */
109*b1cdbd2cSJim Jagielski    000,   000,   000,   000,   000,   000,   000,   000, /* 38          */
110*b1cdbd2cSJim Jagielski    SPA,   000,   000,   000,   000,   000,   000,   000, /* 40          */
111*b1cdbd2cSJim Jagielski    000,   000,   000,   DOT, OP_LT,OP_LPA,OP_ADD, OP_OR, /* 48    .<(+| */
112*b1cdbd2cSJim Jagielski OP_AND,   000,   000,   000,   000,   000,   000,   000, /* 50 &        */
113*b1cdbd2cSJim Jagielski    000,   000,OP_NOT,   DOL,OP_MUL,OP_RPA,   000,OP_XOR, /* 58   !$*);^ */
114*b1cdbd2cSJim Jagielski OP_SUB,OP_DIV,   000,   000,   000,   000,   000,   000, /* 60 -/       */
115*b1cdbd2cSJim Jagielski    000,   000,   000,   000,OP_MOD,   LET, OP_GT,OP_QUE, /* 68    ,%_>? */
116*b1cdbd2cSJim Jagielski    000,   000,   000,   000,   000,   000,   000,   000, /* 70          */
117*b1cdbd2cSJim Jagielski    000,   000,OP_COL,   000,   000,   QUO, OP_EQ,   QUO, /* 78  `:#@'=" */
118*b1cdbd2cSJim Jagielski    000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 80  abcdefg */
119*b1cdbd2cSJim Jagielski    LET,   LET,   000,   000,   000,   000,   000,   000, /* 88 hi       */
120*b1cdbd2cSJim Jagielski    000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 90  jklmnop */
121*b1cdbd2cSJim Jagielski    LET,   LET,   000,   000,   000,   000,   000,   000, /* 98 qr       */
122*b1cdbd2cSJim Jagielski    000,OP_NOT,   LET,   LET,   LET,   LET,   LET,   LET, /* A0  ~stuvwx */
123*b1cdbd2cSJim Jagielski    LET,   LET,   000,   000,   000,   000,   000,   000, /* A8 yz   [   */
124*b1cdbd2cSJim Jagielski    000,   000,   000,   000,   000,   000,   000,   000, /* B0          */
125*b1cdbd2cSJim Jagielski    000,   000,   000,   000,   000,   000,   000,   000, /* B8      ]   */
126*b1cdbd2cSJim Jagielski    000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* C0 {ABCDEFG */
127*b1cdbd2cSJim Jagielski    LET,   LET,   000,   000,   000,   000,   000,   000, /* C8 HI       */
128*b1cdbd2cSJim Jagielski    000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* D0 }JKLMNOP */
129*b1cdbd2cSJim Jagielski    LET,   LET,   000,   000,   000,   000,   000,   000, /* D8 QR       */
130*b1cdbd2cSJim Jagielski    BSH,   000,   LET,   LET,   LET,   LET,   LET,   LET, /* E0 \ STUVWX */
131*b1cdbd2cSJim Jagielski    LET,   LET,   000,   000,   000,   000,   000,   000, /* E8 YZ       */
132*b1cdbd2cSJim Jagielski    DIG,   DIG,   DIG,   DIG,   DIG,   DIG,   DIG,   DIG, /* F0 01234567 */
133*b1cdbd2cSJim Jagielski    DIG,   DIG,   000,   000,   000,   000,   000,   000, /* F8 89       */
134*b1cdbd2cSJim Jagielski };
135*b1cdbd2cSJim Jagielski 
136*b1cdbd2cSJim Jagielski #else
137*b1cdbd2cSJim Jagielski 
138*b1cdbd2cSJim Jagielski char type[256] = {              /* Character type codes    Hex          */
139*b1cdbd2cSJim Jagielski    END,   000,   000,   000,   000,   000,   000,   000, /* 00          */
140*b1cdbd2cSJim Jagielski    000,   SPA,   000,   000,   000,   000,   000,   000, /* 08          */
141*b1cdbd2cSJim Jagielski    000,   000,   000,   000,   000,   000,   000,   000, /* 10          */
142*b1cdbd2cSJim Jagielski    000,   000,   000,   000,   000,   LET,   000,   SPA, /* 18          */
143*b1cdbd2cSJim Jagielski    SPA,OP_NOT,   QUO,   000,   DOL,OP_MOD,OP_AND,   QUO, /* 20  !"#$%&' */
144*b1cdbd2cSJim Jagielski OP_LPA,OP_RPA,OP_MUL,OP_ADD,   000,OP_SUB,   DOT,OP_DIV, /* 28 ()*+,-./ */
145*b1cdbd2cSJim Jagielski    DIG,   DIG,   DIG,   DIG,   DIG,   DIG,   DIG,   DIG, /* 30 01234567 */
146*b1cdbd2cSJim Jagielski    DIG,   DIG,OP_COL,   000, OP_LT, OP_EQ, OP_GT,OP_QUE, /* 38 89:;<=>? */
147*b1cdbd2cSJim Jagielski    000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 40 @ABCDEFG */
148*b1cdbd2cSJim Jagielski    LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 48 HIJKLMNO */
149*b1cdbd2cSJim Jagielski    LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 50 PQRSTUVW */
150*b1cdbd2cSJim Jagielski    LET,   LET,   LET,   000,   BSH,   000,OP_XOR,   LET, /* 58 XYZ[\]^_ */
151*b1cdbd2cSJim Jagielski    000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 60 `abcdefg */
152*b1cdbd2cSJim Jagielski    LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 68 hijklmno */
153*b1cdbd2cSJim Jagielski    LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 70 pqrstuvw */
154*b1cdbd2cSJim Jagielski    LET,   LET,   LET,   000, OP_OR,   000,OP_NOT,   000, /* 78 xyz{|}~  */
155*b1cdbd2cSJim Jagielski    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
156*b1cdbd2cSJim Jagielski    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
157*b1cdbd2cSJim Jagielski    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
158*b1cdbd2cSJim Jagielski    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
159*b1cdbd2cSJim Jagielski    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
160*b1cdbd2cSJim Jagielski    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
161*b1cdbd2cSJim Jagielski    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
162*b1cdbd2cSJim Jagielski    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
163*b1cdbd2cSJim Jagielski };
164*b1cdbd2cSJim Jagielski 
165*b1cdbd2cSJim Jagielski #endif
166*b1cdbd2cSJim Jagielski 
167*b1cdbd2cSJim Jagielski 
168*b1cdbd2cSJim Jagielski /*
169*b1cdbd2cSJim Jagielski  *                      C P P   S y m b o l   T a b l e s
170*b1cdbd2cSJim Jagielski  */
171*b1cdbd2cSJim Jagielski 
172*b1cdbd2cSJim Jagielski /*
173*b1cdbd2cSJim Jagielski  * SBSIZE defines the number of hash-table slots for the symbol table.
174*b1cdbd2cSJim Jagielski  * It must be a power of 2.
175*b1cdbd2cSJim Jagielski  */
176*b1cdbd2cSJim Jagielski #ifndef SBSIZE
177*b1cdbd2cSJim Jagielski #define SBSIZE  64
178*b1cdbd2cSJim Jagielski #endif
179*b1cdbd2cSJim Jagielski #define SBMASK  (SBSIZE - 1)
180*b1cdbd2cSJim Jagielski #if (SBSIZE ^ SBMASK) != ((SBSIZE * 2) - 1)
181*b1cdbd2cSJim Jagielski         << error, SBSIZE must be a power of 2 >>
182*b1cdbd2cSJim Jagielski #endif
183*b1cdbd2cSJim Jagielski 
184*b1cdbd2cSJim Jagielski 
185*b1cdbd2cSJim Jagielski static DEFBUF   *symtab[SBSIZE];        /* Symbol table queue headers   */
186*b1cdbd2cSJim Jagielski 
InitCpp6()187*b1cdbd2cSJim Jagielski void InitCpp6()
188*b1cdbd2cSJim Jagielski {
189*b1cdbd2cSJim Jagielski     int i;
190*b1cdbd2cSJim Jagielski     for( i = 0; i < SBSIZE; i++ )
191*b1cdbd2cSJim Jagielski         symtab[ i ] = NULL;
192*b1cdbd2cSJim Jagielski }
193*b1cdbd2cSJim Jagielski 
194*b1cdbd2cSJim Jagielski 
195*b1cdbd2cSJim Jagielski 
skipnl()196*b1cdbd2cSJim Jagielski void skipnl()
197*b1cdbd2cSJim Jagielski /*
198*b1cdbd2cSJim Jagielski  * Skip to the end of the current input line.
199*b1cdbd2cSJim Jagielski  */
200*b1cdbd2cSJim Jagielski {
201*b1cdbd2cSJim Jagielski         register int            c;
202*b1cdbd2cSJim Jagielski 
203*b1cdbd2cSJim Jagielski         do {                            /* Skip to newline      */
204*b1cdbd2cSJim Jagielski             c = get();
205*b1cdbd2cSJim Jagielski         } while (c != '\n' && c != EOF_CHAR);
206*b1cdbd2cSJim Jagielski }
207*b1cdbd2cSJim Jagielski 
208*b1cdbd2cSJim Jagielski int
skipws()209*b1cdbd2cSJim Jagielski skipws()
210*b1cdbd2cSJim Jagielski /*
211*b1cdbd2cSJim Jagielski  * Skip over whitespace
212*b1cdbd2cSJim Jagielski  */
213*b1cdbd2cSJim Jagielski {
214*b1cdbd2cSJim Jagielski         register int            c;
215*b1cdbd2cSJim Jagielski 
216*b1cdbd2cSJim Jagielski         do {                            /* Skip whitespace      */
217*b1cdbd2cSJim Jagielski             c = get();
218*b1cdbd2cSJim Jagielski #if COMMENT_INVISIBLE
219*b1cdbd2cSJim Jagielski         } while (type[c] == SPA || c == COM_SEP);
220*b1cdbd2cSJim Jagielski #else
221*b1cdbd2cSJim Jagielski         } while (type[c] == SPA);
222*b1cdbd2cSJim Jagielski #endif
223*b1cdbd2cSJim Jagielski         return (c);
224*b1cdbd2cSJim Jagielski }
225*b1cdbd2cSJim Jagielski 
scanid(int c)226*b1cdbd2cSJim Jagielski void scanid(int c)
227*b1cdbd2cSJim Jagielski /*
228*b1cdbd2cSJim Jagielski  * Get the next token (an id) into the token buffer.
229*b1cdbd2cSJim Jagielski  * Note: this code is duplicated in lookid().
230*b1cdbd2cSJim Jagielski  * Change one, change both.
231*b1cdbd2cSJim Jagielski  */
232*b1cdbd2cSJim Jagielski {
233*b1cdbd2cSJim Jagielski         register char   *bp;
234*b1cdbd2cSJim Jagielski 
235*b1cdbd2cSJim Jagielski         if (c == DEF_MAGIC)                     /* Eat the magic token  */
236*b1cdbd2cSJim Jagielski             c = get();                          /* undefiner.           */
237*b1cdbd2cSJim Jagielski         bp = token;
238*b1cdbd2cSJim Jagielski         do {
239*b1cdbd2cSJim Jagielski             if (bp < &token[IDMAX])             /* token dim is IDMAX+1 */
240*b1cdbd2cSJim Jagielski                 *bp++ = (char)c;
241*b1cdbd2cSJim Jagielski             c = get();
242*b1cdbd2cSJim Jagielski         } while (type[c] == LET || type[c] == DIG);
243*b1cdbd2cSJim Jagielski         unget();
244*b1cdbd2cSJim Jagielski         *bp = EOS;
245*b1cdbd2cSJim Jagielski }
246*b1cdbd2cSJim Jagielski 
247*b1cdbd2cSJim Jagielski int
macroid(int c)248*b1cdbd2cSJim Jagielski macroid(int c)
249*b1cdbd2cSJim Jagielski /*
250*b1cdbd2cSJim Jagielski  * If c is a letter, scan the id.  if it's #defined, expand it and scan
251*b1cdbd2cSJim Jagielski  * the next character and try again.
252*b1cdbd2cSJim Jagielski  *
253*b1cdbd2cSJim Jagielski  * Else, return the character.  If type[c] is a LET, the token is in token.
254*b1cdbd2cSJim Jagielski  */
255*b1cdbd2cSJim Jagielski {
256*b1cdbd2cSJim Jagielski         register DEFBUF *dp;
257*b1cdbd2cSJim Jagielski 
258*b1cdbd2cSJim Jagielski         if (infile != NULL && infile->fp != NULL)
259*b1cdbd2cSJim Jagielski             recursion = 0;
260*b1cdbd2cSJim Jagielski         while (type[c] == LET && (dp = lookid(c)) != NULL) {
261*b1cdbd2cSJim Jagielski             expand(dp);
262*b1cdbd2cSJim Jagielski             c = get();
263*b1cdbd2cSJim Jagielski         }
264*b1cdbd2cSJim Jagielski         return (c);
265*b1cdbd2cSJim Jagielski }
266*b1cdbd2cSJim Jagielski 
267*b1cdbd2cSJim Jagielski int
catenate()268*b1cdbd2cSJim Jagielski catenate()
269*b1cdbd2cSJim Jagielski /*
270*b1cdbd2cSJim Jagielski  * A token was just read (via macroid).
271*b1cdbd2cSJim Jagielski  * If the next character is TOK_SEP, concatenate the next token
272*b1cdbd2cSJim Jagielski  * return TRUE -- which should recall macroid after refreshing
273*b1cdbd2cSJim Jagielski  * macroid's argument.  If it is not TOK_SEP, unget() the character
274*b1cdbd2cSJim Jagielski  * and return FALSE.
275*b1cdbd2cSJim Jagielski  */
276*b1cdbd2cSJim Jagielski {
277*b1cdbd2cSJim Jagielski         register int            c;
278*b1cdbd2cSJim Jagielski         register char           *token1;
279*b1cdbd2cSJim Jagielski 
280*b1cdbd2cSJim Jagielski #if OK_CONCAT
281*b1cdbd2cSJim Jagielski         if (get() != TOK_SEP) {                 /* Token concatenation  */
282*b1cdbd2cSJim Jagielski             unget();
283*b1cdbd2cSJim Jagielski             return (FALSE);
284*b1cdbd2cSJim Jagielski         }
285*b1cdbd2cSJim Jagielski         else {
286*b1cdbd2cSJim Jagielski             token1 = savestring(token);         /* Save first token     */
287*b1cdbd2cSJim Jagielski             c = macroid(get());                 /* Scan next token      */
288*b1cdbd2cSJim Jagielski             switch(type[c]) {                   /* What was it?         */
289*b1cdbd2cSJim Jagielski             case LET:                           /* An identifier, ...   */
290*b1cdbd2cSJim Jagielski                 if (strlen(token1) + strlen(token) >= NWORK)
291*b1cdbd2cSJim Jagielski                     cfatal("work buffer overflow doing %s #", token1);
292*b1cdbd2cSJim Jagielski                 sprintf(work, "%s%s", token1, token);
293*b1cdbd2cSJim Jagielski                 break;
294*b1cdbd2cSJim Jagielski 
295*b1cdbd2cSJim Jagielski             case DIG:                           /* A digit string       */
296*b1cdbd2cSJim Jagielski                 strcpy(work, token1);
297*b1cdbd2cSJim Jagielski                 workp = work + strlen(work);
298*b1cdbd2cSJim Jagielski                 do {
299*b1cdbd2cSJim Jagielski                     save(c);
300*b1cdbd2cSJim Jagielski                 } while ((c = get()) != TOK_SEP);
301*b1cdbd2cSJim Jagielski                 /*
302*b1cdbd2cSJim Jagielski                  * The trailing TOK_SEP is no longer needed.
303*b1cdbd2cSJim Jagielski                  */
304*b1cdbd2cSJim Jagielski                 save(EOS);
305*b1cdbd2cSJim Jagielski                 break;
306*b1cdbd2cSJim Jagielski 
307*b1cdbd2cSJim Jagielski             default:                            /* An error, ...        */
308*b1cdbd2cSJim Jagielski #if ! COMMENT_INVISIBLE
309*b1cdbd2cSJim Jagielski                 if (isprint(c))
310*b1cdbd2cSJim Jagielski                     cierror("Strange character '%c' after #", c);
311*b1cdbd2cSJim Jagielski                 else
312*b1cdbd2cSJim Jagielski                     cierror("Strange character (%d.) after #", c);
313*b1cdbd2cSJim Jagielski #endif
314*b1cdbd2cSJim Jagielski                 strcpy(work, token1);
315*b1cdbd2cSJim Jagielski                 unget();
316*b1cdbd2cSJim Jagielski                 break;
317*b1cdbd2cSJim Jagielski             }
318*b1cdbd2cSJim Jagielski             /*
319*b1cdbd2cSJim Jagielski              * work has the concatenated token and token1 has
320*b1cdbd2cSJim Jagielski              * the first token (no longer needed).  Unget the
321*b1cdbd2cSJim Jagielski              * new (concatenated) token after freeing token1.
322*b1cdbd2cSJim Jagielski              * Finally, setup to read the new token.
323*b1cdbd2cSJim Jagielski              */
324*b1cdbd2cSJim Jagielski             free(token1);                       /* Free up memory       */
325*b1cdbd2cSJim Jagielski             ungetstring(work);                  /* Unget the new thing, */
326*b1cdbd2cSJim Jagielski             return (TRUE);
327*b1cdbd2cSJim Jagielski         }
328*b1cdbd2cSJim Jagielski #else
329*b1cdbd2cSJim Jagielski         return (FALSE);                         /* Not supported        */
330*b1cdbd2cSJim Jagielski #endif
331*b1cdbd2cSJim Jagielski }
332*b1cdbd2cSJim Jagielski 
333*b1cdbd2cSJim Jagielski int
scanstring(int delim,void (* outfun)(int))334*b1cdbd2cSJim Jagielski scanstring(int delim,
335*b1cdbd2cSJim Jagielski #ifndef _NO_PROTO
336*b1cdbd2cSJim Jagielski void             (*outfun)( int ) /* BP */    /* Output function              */
337*b1cdbd2cSJim Jagielski #else
338*b1cdbd2cSJim Jagielski void         (*outfun)() /* BP */
339*b1cdbd2cSJim Jagielski #endif
340*b1cdbd2cSJim Jagielski )
341*b1cdbd2cSJim Jagielski /*
342*b1cdbd2cSJim Jagielski  * Scan off a string.  Warning if terminated by newline or EOF.
343*b1cdbd2cSJim Jagielski  * outfun() outputs the character -- to a buffer if in a macro.
344*b1cdbd2cSJim Jagielski  * TRUE if ok, FALSE if error.
345*b1cdbd2cSJim Jagielski  */
346*b1cdbd2cSJim Jagielski {
347*b1cdbd2cSJim Jagielski         register int            c;
348*b1cdbd2cSJim Jagielski 
349*b1cdbd2cSJim Jagielski         instring = TRUE;                /* Don't strip comments         */
350*b1cdbd2cSJim Jagielski         (*outfun)(delim);
351*b1cdbd2cSJim Jagielski         while ((c = get()) != delim
352*b1cdbd2cSJim Jagielski              && c != '\n'
353*b1cdbd2cSJim Jagielski              && c != EOF_CHAR) {
354*b1cdbd2cSJim Jagielski 
355*b1cdbd2cSJim Jagielski             if (c != DEF_MAGIC)
356*b1cdbd2cSJim Jagielski             (*outfun)(c);
357*b1cdbd2cSJim Jagielski             if (c == '\\')
358*b1cdbd2cSJim Jagielski                 (*outfun)(get());
359*b1cdbd2cSJim Jagielski         }
360*b1cdbd2cSJim Jagielski         instring = FALSE;
361*b1cdbd2cSJim Jagielski         if (c == delim) {
362*b1cdbd2cSJim Jagielski             (*outfun)(c);
363*b1cdbd2cSJim Jagielski             return (TRUE);
364*b1cdbd2cSJim Jagielski         }
365*b1cdbd2cSJim Jagielski         else {
366*b1cdbd2cSJim Jagielski             cerror("Unterminated string", NULLST);
367*b1cdbd2cSJim Jagielski             unget();
368*b1cdbd2cSJim Jagielski             return (FALSE);
369*b1cdbd2cSJim Jagielski         }
370*b1cdbd2cSJim Jagielski }
371*b1cdbd2cSJim Jagielski 
scannumber(int c,register void (* outfun)(int))372*b1cdbd2cSJim Jagielski void scannumber(int c,
373*b1cdbd2cSJim Jagielski #ifndef _NO_PROTO
374*b1cdbd2cSJim Jagielski register void    (*outfun)( int )  /* BP */    /* Output/store func    */
375*b1cdbd2cSJim Jagielski #else
376*b1cdbd2cSJim Jagielski register void    (*outfun)() /* BP */
377*b1cdbd2cSJim Jagielski #endif
378*b1cdbd2cSJim Jagielski )
379*b1cdbd2cSJim Jagielski /*
380*b1cdbd2cSJim Jagielski  * Process a number.  We know that c is from 0 to 9 or dot.
381*b1cdbd2cSJim Jagielski  * Algorithm from Dave Conroy's Decus C.
382*b1cdbd2cSJim Jagielski  */
383*b1cdbd2cSJim Jagielski {
384*b1cdbd2cSJim Jagielski         register int    radix;                  /* 8, 10, or 16         */
385*b1cdbd2cSJim Jagielski         int             expseen;                /* 'e' seen in floater  */
386*b1cdbd2cSJim Jagielski         int             signseen;               /* '+' or '-' seen      */
387*b1cdbd2cSJim Jagielski         int             octal89;                /* For bad octal test   */
388*b1cdbd2cSJim Jagielski         int             dotflag;                /* TRUE if '.' was seen */
389*b1cdbd2cSJim Jagielski 
390*b1cdbd2cSJim Jagielski         expseen = FALSE;                        /* No exponent seen yet */
391*b1cdbd2cSJim Jagielski         signseen = TRUE;                        /* No +/- allowed yet   */
392*b1cdbd2cSJim Jagielski         octal89 = FALSE;                        /* No bad octal yet     */
393*b1cdbd2cSJim Jagielski         radix = 10;                             /* Assume decimal       */
394*b1cdbd2cSJim Jagielski         if ((dotflag = (c == '.')) != FALSE) {  /* . something?         */
395*b1cdbd2cSJim Jagielski             (*outfun)('.');                     /* Always out the dot   */
396*b1cdbd2cSJim Jagielski             if (type[(c = get())] != DIG) {     /* If not a float numb, */
397*b1cdbd2cSJim Jagielski                 unget();                        /* Rescan strange char  */
398*b1cdbd2cSJim Jagielski                 return;                         /* All done for now     */
399*b1cdbd2cSJim Jagielski             }
400*b1cdbd2cSJim Jagielski         }                                       /* End of float test    */
401*b1cdbd2cSJim Jagielski         else if (c == '0') {                    /* Octal or hex?        */
402*b1cdbd2cSJim Jagielski             (*outfun)(c);                       /* Stuff initial zero   */
403*b1cdbd2cSJim Jagielski             radix = 8;                          /* Assume it's octal    */
404*b1cdbd2cSJim Jagielski             c = get();                          /* Look for an 'x'      */
405*b1cdbd2cSJim Jagielski             if (c == 'x' || c == 'X') {         /* Did we get one?      */
406*b1cdbd2cSJim Jagielski                 radix = 16;                     /* Remember new radix   */
407*b1cdbd2cSJim Jagielski                 (*outfun)(c);                   /* Stuff the 'x'        */
408*b1cdbd2cSJim Jagielski                 c = get();                      /* Get next character   */
409*b1cdbd2cSJim Jagielski             }
410*b1cdbd2cSJim Jagielski         }
411*b1cdbd2cSJim Jagielski         for (;;) {                              /* Process curr. char.  */
412*b1cdbd2cSJim Jagielski             /*
413*b1cdbd2cSJim Jagielski              * Note that this algorithm accepts "012e4" and "03.4"
414*b1cdbd2cSJim Jagielski              * as legitimate floating-point numbers.
415*b1cdbd2cSJim Jagielski              */
416*b1cdbd2cSJim Jagielski             if (radix != 16 && (c == 'e' || c == 'E')) {
417*b1cdbd2cSJim Jagielski                 if (expseen)                    /* Already saw 'E'?     */
418*b1cdbd2cSJim Jagielski                     break;                      /* Exit loop, bad nbr.  */
419*b1cdbd2cSJim Jagielski                 expseen = TRUE;                 /* Set exponent seen    */
420*b1cdbd2cSJim Jagielski                 signseen = FALSE;               /* We can read '+' now  */
421*b1cdbd2cSJim Jagielski                 radix = 10;                     /* Decimal exponent     */
422*b1cdbd2cSJim Jagielski             }
423*b1cdbd2cSJim Jagielski             else if (radix != 16 && c == '.') {
424*b1cdbd2cSJim Jagielski                 if (dotflag)                    /* Saw dot already?     */
425*b1cdbd2cSJim Jagielski                     break;                      /* Exit loop, two dots  */
426*b1cdbd2cSJim Jagielski                 dotflag = TRUE;                 /* Remember the dot     */
427*b1cdbd2cSJim Jagielski                 radix = 10;                     /* Decimal fraction     */
428*b1cdbd2cSJim Jagielski             }
429*b1cdbd2cSJim Jagielski             else if (c == '+' || c == '-') {    /* 1.0e+10              */
430*b1cdbd2cSJim Jagielski                 if (signseen)                   /* Sign in wrong place? */
431*b1cdbd2cSJim Jagielski                     break;                      /* Exit loop, not nbr.  */
432*b1cdbd2cSJim Jagielski                 /* signseen = TRUE; */          /* Remember we saw it   */
433*b1cdbd2cSJim Jagielski             }
434*b1cdbd2cSJim Jagielski             else {                              /* Check the digit      */
435*b1cdbd2cSJim Jagielski                 switch (c) {
436*b1cdbd2cSJim Jagielski                 case '8': case '9':             /* Sometimes wrong      */
437*b1cdbd2cSJim Jagielski                     octal89 = TRUE;             /* Do check later       */
438*b1cdbd2cSJim Jagielski                 case '0': case '1': case '2': case '3':
439*b1cdbd2cSJim Jagielski                 case '4': case '5': case '6': case '7':
440*b1cdbd2cSJim Jagielski                     break;                      /* Always ok            */
441*b1cdbd2cSJim Jagielski 
442*b1cdbd2cSJim Jagielski                 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
443*b1cdbd2cSJim Jagielski                 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
444*b1cdbd2cSJim Jagielski                     if (radix == 16)            /* Alpha's are ok only  */
445*b1cdbd2cSJim Jagielski                         break;                  /* if reading hex.      */
446*b1cdbd2cSJim Jagielski                 default:                        /* At number end        */
447*b1cdbd2cSJim Jagielski                     goto done;                  /* Break from for loop  */
448*b1cdbd2cSJim Jagielski                 }                               /* End of switch        */
449*b1cdbd2cSJim Jagielski             }                                   /* End general case     */
450*b1cdbd2cSJim Jagielski             (*outfun)(c);                       /* Accept the character */
451*b1cdbd2cSJim Jagielski             signseen = TRUE;                    /* Don't read sign now  */
452*b1cdbd2cSJim Jagielski             c = get();                          /* Read another char    */
453*b1cdbd2cSJim Jagielski         }                                       /* End of scan loop     */
454*b1cdbd2cSJim Jagielski         /*
455*b1cdbd2cSJim Jagielski          * When we break out of the scan loop, c contains the first
456*b1cdbd2cSJim Jagielski          * character (maybe) not in the number.  If the number is an
457*b1cdbd2cSJim Jagielski          * integer, allow a trailing 'L' for long and/or a trailing 'U'
458*b1cdbd2cSJim Jagielski          * for unsigned.  If not those, push the trailing character back
459*b1cdbd2cSJim Jagielski          * on the input stream.  Floating point numbers accept a trailing
460*b1cdbd2cSJim Jagielski          * 'L' for "long double".
461*b1cdbd2cSJim Jagielski          */
462*b1cdbd2cSJim Jagielski done:   if (dotflag || expseen) {               /* Floating point?      */
463*b1cdbd2cSJim Jagielski             if (c == 'l' || c == 'L') {
464*b1cdbd2cSJim Jagielski                 (*outfun)(c);
465*b1cdbd2cSJim Jagielski                 c = get();                      /* Ungotten later       */
466*b1cdbd2cSJim Jagielski             }
467*b1cdbd2cSJim Jagielski         }
468*b1cdbd2cSJim Jagielski         else {                                  /* Else it's an integer */
469*b1cdbd2cSJim Jagielski             /*
470*b1cdbd2cSJim Jagielski              * We know that dotflag and expseen are both zero, now:
471*b1cdbd2cSJim Jagielski              * dotflag signals "saw 'L'", and
472*b1cdbd2cSJim Jagielski              * expseen signals "saw 'U'".
473*b1cdbd2cSJim Jagielski              */
474*b1cdbd2cSJim Jagielski             for (;;) {
475*b1cdbd2cSJim Jagielski                 switch (c) {
476*b1cdbd2cSJim Jagielski                 case 'l':
477*b1cdbd2cSJim Jagielski                 case 'L':
478*b1cdbd2cSJim Jagielski                     if (dotflag)
479*b1cdbd2cSJim Jagielski                         goto nomore;
480*b1cdbd2cSJim Jagielski                     dotflag = TRUE;
481*b1cdbd2cSJim Jagielski                     break;
482*b1cdbd2cSJim Jagielski 
483*b1cdbd2cSJim Jagielski                 case 'u':
484*b1cdbd2cSJim Jagielski                 case 'U':
485*b1cdbd2cSJim Jagielski                     if (expseen)
486*b1cdbd2cSJim Jagielski                         goto nomore;
487*b1cdbd2cSJim Jagielski                     expseen = TRUE;
488*b1cdbd2cSJim Jagielski                     break;
489*b1cdbd2cSJim Jagielski 
490*b1cdbd2cSJim Jagielski                 default:
491*b1cdbd2cSJim Jagielski                     goto nomore;
492*b1cdbd2cSJim Jagielski                 }
493*b1cdbd2cSJim Jagielski                 (*outfun)(c);                   /* Got 'L' or 'U'.      */
494*b1cdbd2cSJim Jagielski                 c = get();                      /* Look at next, too.   */
495*b1cdbd2cSJim Jagielski             }
496*b1cdbd2cSJim Jagielski         }
497*b1cdbd2cSJim Jagielski nomore: unget();                                /* Not part of a number */
498*b1cdbd2cSJim Jagielski         if (octal89 && radix == 8)
499*b1cdbd2cSJim Jagielski             cwarn("Illegal digit in octal number", NULLST);
500*b1cdbd2cSJim Jagielski }
501*b1cdbd2cSJim Jagielski 
save(int c)502*b1cdbd2cSJim Jagielski void save(int c)
503*b1cdbd2cSJim Jagielski {
504*b1cdbd2cSJim Jagielski         if (workp >= &work[NWORK]) {
505*b1cdbd2cSJim Jagielski             work[NWORK-1] = '\0';
506*b1cdbd2cSJim Jagielski             cfatal("Work buffer overflow:  %s", work);
507*b1cdbd2cSJim Jagielski         }
508*b1cdbd2cSJim Jagielski         else *workp++ = (char)c;
509*b1cdbd2cSJim Jagielski }
510*b1cdbd2cSJim Jagielski 
511*b1cdbd2cSJim Jagielski char *
savestring(char * text)512*b1cdbd2cSJim Jagielski savestring(char* text)
513*b1cdbd2cSJim Jagielski /*
514*b1cdbd2cSJim Jagielski  * Store a string into free memory.
515*b1cdbd2cSJim Jagielski  */
516*b1cdbd2cSJim Jagielski {
517*b1cdbd2cSJim Jagielski         register char   *result;
518*b1cdbd2cSJim Jagielski 
519*b1cdbd2cSJim Jagielski         result = getmem(strlen(text) + 1);
520*b1cdbd2cSJim Jagielski         strcpy(result, text);
521*b1cdbd2cSJim Jagielski         return (result);
522*b1cdbd2cSJim Jagielski }
523*b1cdbd2cSJim Jagielski 
524*b1cdbd2cSJim Jagielski FILEINFO        *
getfile(int bufsize,char * name)525*b1cdbd2cSJim Jagielski getfile(int bufsize, char* name)
526*b1cdbd2cSJim Jagielski /*
527*b1cdbd2cSJim Jagielski  * Common FILEINFO buffer initialization for a new file or macro.
528*b1cdbd2cSJim Jagielski  */
529*b1cdbd2cSJim Jagielski {
530*b1cdbd2cSJim Jagielski         register FILEINFO       *file;
531*b1cdbd2cSJim Jagielski         register int            size;
532*b1cdbd2cSJim Jagielski 
533*b1cdbd2cSJim Jagielski         size = strlen(name);                    /* File/macro name      */
534*b1cdbd2cSJim Jagielski         file = (FILEINFO *) getmem(sizeof (FILEINFO) + bufsize + size);
535*b1cdbd2cSJim Jagielski         file->parent = infile;                  /* Chain files together */
536*b1cdbd2cSJim Jagielski         file->fp = NULL;                        /* No file yet          */
537*b1cdbd2cSJim Jagielski         file->filename = savestring(name);      /* Save file/macro name */
538*b1cdbd2cSJim Jagielski         file->progname = NULL;                  /* No #line seen yet    */
539*b1cdbd2cSJim Jagielski         file->unrecur = 0;                      /* No macro fixup       */
540*b1cdbd2cSJim Jagielski         file->bptr = file->buffer;              /* Initialize line ptr  */
541*b1cdbd2cSJim Jagielski         file->buffer[0] = EOS;                  /* Force first read     */
542*b1cdbd2cSJim Jagielski         file->line = 0;                         /* (Not used just yet)  */
543*b1cdbd2cSJim Jagielski         if (infile != NULL)                     /* If #include file     */
544*b1cdbd2cSJim Jagielski             infile->line = line;                /* Save current line    */
545*b1cdbd2cSJim Jagielski         infile = file;                          /* New current file     */
546*b1cdbd2cSJim Jagielski         line = 1;                               /* Note first line      */
547*b1cdbd2cSJim Jagielski         return (file);                          /* All done.            */
548*b1cdbd2cSJim Jagielski }
549*b1cdbd2cSJim Jagielski 
550*b1cdbd2cSJim Jagielski char *
getmem(int size)551*b1cdbd2cSJim Jagielski getmem(int size)
552*b1cdbd2cSJim Jagielski /*
553*b1cdbd2cSJim Jagielski  * Get a block of free memory.
554*b1cdbd2cSJim Jagielski  */
555*b1cdbd2cSJim Jagielski {
556*b1cdbd2cSJim Jagielski         register char   *result;
557*b1cdbd2cSJim Jagielski 
558*b1cdbd2cSJim Jagielski         if ((result = malloc((unsigned) size)) == NULL)
559*b1cdbd2cSJim Jagielski             cfatal("Out of memory", NULLST);
560*b1cdbd2cSJim Jagielski         return (result);
561*b1cdbd2cSJim Jagielski }
562*b1cdbd2cSJim Jagielski 
563*b1cdbd2cSJim Jagielski 
564*b1cdbd2cSJim Jagielski DEFBUF *
lookid(int c)565*b1cdbd2cSJim Jagielski lookid(int c)
566*b1cdbd2cSJim Jagielski /*
567*b1cdbd2cSJim Jagielski  * Look for the next token in the symbol table.  Returns token in "token".
568*b1cdbd2cSJim Jagielski  * If found, returns the table pointer;  Else returns NULL.
569*b1cdbd2cSJim Jagielski  */
570*b1cdbd2cSJim Jagielski {
571*b1cdbd2cSJim Jagielski         register int            nhash;
572*b1cdbd2cSJim Jagielski         register DEFBUF         *dp;
573*b1cdbd2cSJim Jagielski         register char           *np;
574*b1cdbd2cSJim Jagielski         int                     temp = 0;
575*b1cdbd2cSJim Jagielski         int                     isrecurse;      /* For #define foo foo  */
576*b1cdbd2cSJim Jagielski 
577*b1cdbd2cSJim Jagielski         np = token;
578*b1cdbd2cSJim Jagielski         nhash = 0;
579*b1cdbd2cSJim Jagielski         if (0 != (isrecurse = (c == DEF_MAGIC)))     /* If recursive macro   */
580*b1cdbd2cSJim Jagielski             c = get();                          /* hack, skip DEF_MAGIC */
581*b1cdbd2cSJim Jagielski         do {
582*b1cdbd2cSJim Jagielski             if (np < &token[IDMAX]) {           /* token dim is IDMAX+1 */
583*b1cdbd2cSJim Jagielski                 *np++ = (char)c;                /* Store token byte     */
584*b1cdbd2cSJim Jagielski                 nhash += c;                     /* Update hash value    */
585*b1cdbd2cSJim Jagielski             }
586*b1cdbd2cSJim Jagielski             c = get();                          /* And get another byte */
587*b1cdbd2cSJim Jagielski         } while (type[c] == LET || type[c] == DIG);
588*b1cdbd2cSJim Jagielski         unget();                                /* Rescan terminator    */
589*b1cdbd2cSJim Jagielski         *np = EOS;                              /* Terminate token      */
590*b1cdbd2cSJim Jagielski         if (isrecurse)                          /* Recursive definition */
591*b1cdbd2cSJim Jagielski             return (NULL);                      /* undefined just now   */
592*b1cdbd2cSJim Jagielski         nhash += (np - token);                  /* Fix hash value       */
593*b1cdbd2cSJim Jagielski         dp = symtab[nhash & SBMASK];            /* Starting bucket      */
594*b1cdbd2cSJim Jagielski         while (dp != (DEFBUF *) NULL) {         /* Search symbol table  */
595*b1cdbd2cSJim Jagielski             if (dp->hash == nhash               /* Fast precheck        */
596*b1cdbd2cSJim Jagielski              && (temp = strcmp(dp->name, token)) >= 0)
597*b1cdbd2cSJim Jagielski                 break;
598*b1cdbd2cSJim Jagielski             dp = dp->link;                      /* Nope, try next one   */
599*b1cdbd2cSJim Jagielski         }
600*b1cdbd2cSJim Jagielski         return ((temp == 0) ? dp : NULL);
601*b1cdbd2cSJim Jagielski }
602*b1cdbd2cSJim Jagielski 
603*b1cdbd2cSJim Jagielski DEFBUF *
defendel(char * name,int delete)604*b1cdbd2cSJim Jagielski defendel(char* name, int delete)
605*b1cdbd2cSJim Jagielski /*
606*b1cdbd2cSJim Jagielski  * Enter this name in the lookup table (delete = FALSE)
607*b1cdbd2cSJim Jagielski  * or delete this name (delete = TRUE).
608*b1cdbd2cSJim Jagielski  * Returns a pointer to the define block (delete = FALSE)
609*b1cdbd2cSJim Jagielski  * Returns NULL if the symbol wasn't defined (delete = TRUE).
610*b1cdbd2cSJim Jagielski  */
611*b1cdbd2cSJim Jagielski {
612*b1cdbd2cSJim Jagielski         register DEFBUF         *dp;
613*b1cdbd2cSJim Jagielski         register DEFBUF         **prevp;
614*b1cdbd2cSJim Jagielski         register char           *np;
615*b1cdbd2cSJim Jagielski         int                     nhash;
616*b1cdbd2cSJim Jagielski         int                     temp;
617*b1cdbd2cSJim Jagielski         int                     size;
618*b1cdbd2cSJim Jagielski 
619*b1cdbd2cSJim Jagielski         for (nhash = 0, np = name; *np != EOS;)
620*b1cdbd2cSJim Jagielski             nhash += *np++;
621*b1cdbd2cSJim Jagielski         size = (np - name);
622*b1cdbd2cSJim Jagielski         nhash += size;
623*b1cdbd2cSJim Jagielski         prevp = &symtab[nhash & SBMASK];
624*b1cdbd2cSJim Jagielski         while ((dp = *prevp) != (DEFBUF *) NULL) {
625*b1cdbd2cSJim Jagielski             if (dp->hash == nhash
626*b1cdbd2cSJim Jagielski              && (temp = strcmp(dp->name, name)) >= 0) {
627*b1cdbd2cSJim Jagielski                 if (temp > 0)
628*b1cdbd2cSJim Jagielski                     dp = NULL;                  /* Not found            */
629*b1cdbd2cSJim Jagielski                 else {
630*b1cdbd2cSJim Jagielski                     *prevp = dp->link;          /* Found, unlink and    */
631*b1cdbd2cSJim Jagielski                     if (dp->repl != NULL)       /* Free the replacement */
632*b1cdbd2cSJim Jagielski                         free(dp->repl);         /* if any, and then     */
633*b1cdbd2cSJim Jagielski                     free((char *) dp);          /* Free the symbol      */
634*b1cdbd2cSJim Jagielski                 }
635*b1cdbd2cSJim Jagielski                 break;
636*b1cdbd2cSJim Jagielski             }
637*b1cdbd2cSJim Jagielski             prevp = &dp->link;
638*b1cdbd2cSJim Jagielski         }
639*b1cdbd2cSJim Jagielski         if (!delete) {
640*b1cdbd2cSJim Jagielski             dp = (DEFBUF *) getmem(sizeof (DEFBUF) + size);
641*b1cdbd2cSJim Jagielski             dp->link = *prevp;
642*b1cdbd2cSJim Jagielski             *prevp = dp;
643*b1cdbd2cSJim Jagielski             dp->hash = nhash;
644*b1cdbd2cSJim Jagielski             dp->repl = NULL;
645*b1cdbd2cSJim Jagielski             dp->nargs = 0;
646*b1cdbd2cSJim Jagielski             strcpy(dp->name, name);
647*b1cdbd2cSJim Jagielski         }
648*b1cdbd2cSJim Jagielski         return (dp);
649*b1cdbd2cSJim Jagielski }
650*b1cdbd2cSJim Jagielski 
651*b1cdbd2cSJim Jagielski #if OSL_DEBUG_LEVEL > 1
652*b1cdbd2cSJim Jagielski 
dumpdef(char * why)653*b1cdbd2cSJim Jagielski void dumpdef(char *why)
654*b1cdbd2cSJim Jagielski {
655*b1cdbd2cSJim Jagielski         register DEFBUF         *dp;
656*b1cdbd2cSJim Jagielski         register DEFBUF         **syp;
657*b1cdbd2cSJim Jagielski 		FILE *pRememberOut = NULL;
658*b1cdbd2cSJim Jagielski 
659*b1cdbd2cSJim Jagielski 		if ( bDumpDefs )	/*ER */
660*b1cdbd2cSJim Jagielski 		{
661*b1cdbd2cSJim Jagielski 			pRememberOut = pCppOut;
662*b1cdbd2cSJim Jagielski 			pCppOut = pDefOut;
663*b1cdbd2cSJim Jagielski 		}
664*b1cdbd2cSJim Jagielski         fprintf( pCppOut, "CPP symbol table dump %s\n", why);
665*b1cdbd2cSJim Jagielski         for (syp = symtab; syp < &symtab[SBSIZE]; syp++) {
666*b1cdbd2cSJim Jagielski             if ((dp = *syp) != (DEFBUF *) NULL) {
667*b1cdbd2cSJim Jagielski                 fprintf( pCppOut, "symtab[%d]\n", (syp - symtab));
668*b1cdbd2cSJim Jagielski                 do {
669*b1cdbd2cSJim Jagielski                     dumpadef((char *) NULL, dp);
670*b1cdbd2cSJim Jagielski                 } while ((dp = dp->link) != (DEFBUF *) NULL);
671*b1cdbd2cSJim Jagielski             }
672*b1cdbd2cSJim Jagielski         }
673*b1cdbd2cSJim Jagielski 		if ( bDumpDefs )
674*b1cdbd2cSJim Jagielski 		{
675*b1cdbd2cSJim Jagielski             fprintf( pCppOut, "\n");
676*b1cdbd2cSJim Jagielski 			pCppOut = pRememberOut;
677*b1cdbd2cSJim Jagielski 		}
678*b1cdbd2cSJim Jagielski }
679*b1cdbd2cSJim Jagielski 
dumpadef(char * why,register DEFBUF * dp)680*b1cdbd2cSJim Jagielski void dumpadef(char *why, register DEFBUF *dp)
681*b1cdbd2cSJim Jagielski {
682*b1cdbd2cSJim Jagielski         register char           *cp;
683*b1cdbd2cSJim Jagielski         register int            c;
684*b1cdbd2cSJim Jagielski 		FILE *pRememberOut = NULL;
685*b1cdbd2cSJim Jagielski 
686*b1cdbd2cSJim Jagielski /*ER dump #define's to pDefOut */
687*b1cdbd2cSJim Jagielski 		if ( bDumpDefs )
688*b1cdbd2cSJim Jagielski 		{
689*b1cdbd2cSJim Jagielski 			pRememberOut = pCppOut;
690*b1cdbd2cSJim Jagielski 			pCppOut = pDefOut;
691*b1cdbd2cSJim Jagielski 		}
692*b1cdbd2cSJim Jagielski         fprintf( pCppOut, " \"%s\" [%d]", dp->name, dp->nargs);
693*b1cdbd2cSJim Jagielski         if (why != NULL)
694*b1cdbd2cSJim Jagielski             fprintf( pCppOut, " (%s)", why);
695*b1cdbd2cSJim Jagielski         if (dp->repl != NULL) {
696*b1cdbd2cSJim Jagielski             fprintf( pCppOut, " => ");
697*b1cdbd2cSJim Jagielski             for (cp = dp->repl; (c = *cp++ & 0xFF) != EOS;) {
698*b1cdbd2cSJim Jagielski #ifdef SOLAR
699*b1cdbd2cSJim Jagielski                 if (c == DEL) {
700*b1cdbd2cSJim Jagielski                     c = *cp++ & 0xFF;
701*b1cdbd2cSJim Jagielski                     if( c == EOS ) break;
702*b1cdbd2cSJim Jagielski                     fprintf( pCppOut, "<%%%d>", c - MAC_PARM);
703*b1cdbd2cSJim Jagielski                 }
704*b1cdbd2cSJim Jagielski #else
705*b1cdbd2cSJim Jagielski                 if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC))
706*b1cdbd2cSJim Jagielski                     fprintf( pCppOut, "<%%%d>", c - MAC_PARM);
707*b1cdbd2cSJim Jagielski #endif
708*b1cdbd2cSJim Jagielski                 else if (isprint(c) || c == '\n' || c == '\t')
709*b1cdbd2cSJim Jagielski                     PUTCHAR(c);
710*b1cdbd2cSJim Jagielski                 else if (c < ' ')
711*b1cdbd2cSJim Jagielski                     fprintf( pCppOut, "<^%c>", c + '@');
712*b1cdbd2cSJim Jagielski                 else
713*b1cdbd2cSJim Jagielski                     fprintf( pCppOut, "<\\0%o>", c);
714*b1cdbd2cSJim Jagielski             }
715*b1cdbd2cSJim Jagielski /*ER evaluate macros to pDefOut */
716*b1cdbd2cSJim Jagielski #ifdef EVALDEFS
717*b1cdbd2cSJim Jagielski 			if ( bDumpDefs && !bIsInEval && dp->nargs <= 0 )
718*b1cdbd2cSJim Jagielski 			{
719*b1cdbd2cSJim Jagielski 				FILEINFO *infileSave = infile;
720*b1cdbd2cSJim Jagielski 				char *tokenSave = savestring( token );
721*b1cdbd2cSJim Jagielski 				char *workSave = savestring( work );
722*b1cdbd2cSJim Jagielski 				int lineSave = line;
723*b1cdbd2cSJim Jagielski 				int wronglineSave = wrongline;
724*b1cdbd2cSJim Jagielski 				int recursionSave = recursion;
725*b1cdbd2cSJim Jagielski 				FILEINFO *file;
726*b1cdbd2cSJim Jagielski 				EVALTYPE valEval;
727*b1cdbd2cSJim Jagielski 
728*b1cdbd2cSJim Jagielski 				bIsInEval = 1;
729*b1cdbd2cSJim Jagielski 				infile = NULL;			/* start from scrap */
730*b1cdbd2cSJim Jagielski 				line = 0;
731*b1cdbd2cSJim Jagielski 				wrongline = 0;
732*b1cdbd2cSJim Jagielski 				*token = EOS;
733*b1cdbd2cSJim Jagielski 				*work = EOS;
734*b1cdbd2cSJim Jagielski 				recursion = 0;
735*b1cdbd2cSJim Jagielski 				file = getfile( strlen( dp->repl ), dp->name );
736*b1cdbd2cSJim Jagielski 				strcpy( file->buffer, dp->repl );
737*b1cdbd2cSJim Jagielski 	            fprintf( pCppOut, " ===> ");
738*b1cdbd2cSJim Jagielski 				nEvalOff = 0;
739*b1cdbd2cSJim Jagielski 				cppmain();				/* get() frees also *file */
740*b1cdbd2cSJim Jagielski 				valEval = 0;
741*b1cdbd2cSJim Jagielski 				if ( 0 == evaluate( EvalBuf, &valEval ) )
742*b1cdbd2cSJim Jagielski 				{
743*b1cdbd2cSJim Jagielski #ifdef EVALFLOATS
744*b1cdbd2cSJim Jagielski 					if ( valEval != (EVALTYPE)((long)valEval ) )
745*b1cdbd2cSJim Jagielski 		            	fprintf( pCppOut, " ==eval=> %f", valEval );
746*b1cdbd2cSJim Jagielski 					else
747*b1cdbd2cSJim Jagielski #endif
748*b1cdbd2cSJim Jagielski 		            	fprintf( pCppOut, " ==eval=> %ld", (long)valEval );
749*b1cdbd2cSJim Jagielski 				}
750*b1cdbd2cSJim Jagielski 				recursion = recursionSave;
751*b1cdbd2cSJim Jagielski 				wrongline = wronglineSave;
752*b1cdbd2cSJim Jagielski 				line = lineSave;
753*b1cdbd2cSJim Jagielski 				strcpy( work, workSave );
754*b1cdbd2cSJim Jagielski 				free( workSave );
755*b1cdbd2cSJim Jagielski 				strcpy( token, tokenSave );
756*b1cdbd2cSJim Jagielski 				free( tokenSave );
757*b1cdbd2cSJim Jagielski 				infile = infileSave;
758*b1cdbd2cSJim Jagielski 				bIsInEval = 0;
759*b1cdbd2cSJim Jagielski 			}
760*b1cdbd2cSJim Jagielski #endif
761*b1cdbd2cSJim Jagielski         }
762*b1cdbd2cSJim Jagielski         else {
763*b1cdbd2cSJim Jagielski             fprintf( pCppOut, ", no replacement.");
764*b1cdbd2cSJim Jagielski         }
765*b1cdbd2cSJim Jagielski         PUTCHAR('\n');
766*b1cdbd2cSJim Jagielski 		if ( bDumpDefs )
767*b1cdbd2cSJim Jagielski 			pCppOut = pRememberOut;
768*b1cdbd2cSJim Jagielski }
769*b1cdbd2cSJim Jagielski #endif
770*b1cdbd2cSJim Jagielski 
771*b1cdbd2cSJim Jagielski /*
772*b1cdbd2cSJim Jagielski  *                      G E T
773*b1cdbd2cSJim Jagielski  */
774*b1cdbd2cSJim Jagielski 
775*b1cdbd2cSJim Jagielski int
get()776*b1cdbd2cSJim Jagielski get()
777*b1cdbd2cSJim Jagielski /*
778*b1cdbd2cSJim Jagielski  * Return the next character from a macro or the current file.
779*b1cdbd2cSJim Jagielski  * Handle end of file from #include files.
780*b1cdbd2cSJim Jagielski  */
781*b1cdbd2cSJim Jagielski {
782*b1cdbd2cSJim Jagielski         register int            c;
783*b1cdbd2cSJim Jagielski         register FILEINFO       *file;
784*b1cdbd2cSJim Jagielski         register int            popped;         /* Recursion fixup      */
785*b1cdbd2cSJim Jagielski 
786*b1cdbd2cSJim Jagielski         popped = 0;
787*b1cdbd2cSJim Jagielski get_from_file:
788*b1cdbd2cSJim Jagielski         if ((file = infile) == NULL)
789*b1cdbd2cSJim Jagielski             return (EOF_CHAR);
790*b1cdbd2cSJim Jagielski newline:
791*b1cdbd2cSJim Jagielski #if 0
792*b1cdbd2cSJim Jagielski         fprintf( pCppOut, "get(%s), recursion %d, line %d, bptr = %d, buffer \"%s\"\n",
793*b1cdbd2cSJim Jagielski             file->filename, recursion, line,
794*b1cdbd2cSJim Jagielski             file->bptr - file->buffer, file->buffer);
795*b1cdbd2cSJim Jagielski #endif
796*b1cdbd2cSJim Jagielski         /*
797*b1cdbd2cSJim Jagielski          * Read a character from the current input line or macro.
798*b1cdbd2cSJim Jagielski          * At EOS, either finish the current macro (freeing temp.
799*b1cdbd2cSJim Jagielski          * storage) or read another line from the current input file.
800*b1cdbd2cSJim Jagielski          * At EOF, exit the current file (#include) or, at EOF from
801*b1cdbd2cSJim Jagielski          * the cpp input file, return EOF_CHAR to finish processing.
802*b1cdbd2cSJim Jagielski          */
803*b1cdbd2cSJim Jagielski         if ((c = *file->bptr++ & 0xFF) == EOS) {
804*b1cdbd2cSJim Jagielski             /*
805*b1cdbd2cSJim Jagielski              * Nothing in current line or macro.  Get next line (if
806*b1cdbd2cSJim Jagielski              * input from a file), or do end of file/macro processing.
807*b1cdbd2cSJim Jagielski              * In the latter case, jump back to restart from the top.
808*b1cdbd2cSJim Jagielski              */
809*b1cdbd2cSJim Jagielski             if (file->fp == NULL) {             /* NULL if macro        */
810*b1cdbd2cSJim Jagielski                 popped++;
811*b1cdbd2cSJim Jagielski                 recursion -= file->unrecur;
812*b1cdbd2cSJim Jagielski                 if (recursion < 0)
813*b1cdbd2cSJim Jagielski                     recursion = 0;
814*b1cdbd2cSJim Jagielski                 infile = file->parent;          /* Unwind file chain    */
815*b1cdbd2cSJim Jagielski             }
816*b1cdbd2cSJim Jagielski             else {                              /* Else get from a file */
817*b1cdbd2cSJim Jagielski                 if ((file->bptr = fgets(file->buffer, NBUFF, file->fp))
818*b1cdbd2cSJim Jagielski                         != NULL) {
819*b1cdbd2cSJim Jagielski #if OSL_DEBUG_LEVEL > 1
820*b1cdbd2cSJim Jagielski                     if (debug > 1) {            /* Dump it to stdout    */
821*b1cdbd2cSJim Jagielski                         fprintf( pCppOut, "\n#line %d (%s), %s",
822*b1cdbd2cSJim Jagielski                             line, file->filename, file->buffer);
823*b1cdbd2cSJim Jagielski                     }
824*b1cdbd2cSJim Jagielski #endif
825*b1cdbd2cSJim Jagielski                     goto newline;               /* process the line     */
826*b1cdbd2cSJim Jagielski                 }
827*b1cdbd2cSJim Jagielski                 else {
828*b1cdbd2cSJim Jagielski 		    if( file->fp != stdin )
829*b1cdbd2cSJim Jagielski                         fclose(file->fp);           /* Close finished file  */
830*b1cdbd2cSJim Jagielski                     if ((infile = file->parent) != NULL) {
831*b1cdbd2cSJim Jagielski                         /*
832*b1cdbd2cSJim Jagielski                          * There is an "ungotten" newline in the current
833*b1cdbd2cSJim Jagielski                          * infile buffer (set there by doinclude() in
834*b1cdbd2cSJim Jagielski                          * cpp1.c).  Thus, we know that the mainline code
835*b1cdbd2cSJim Jagielski                          * is skipping over blank lines and will do a
836*b1cdbd2cSJim Jagielski                          * #line at its convenience.
837*b1cdbd2cSJim Jagielski                          */
838*b1cdbd2cSJim Jagielski                         wrongline = TRUE;       /* Need a #line now     */
839*b1cdbd2cSJim Jagielski                     }
840*b1cdbd2cSJim Jagielski                 }
841*b1cdbd2cSJim Jagielski             }
842*b1cdbd2cSJim Jagielski             /*
843*b1cdbd2cSJim Jagielski              * Free up space used by the (finished) file or macro and
844*b1cdbd2cSJim Jagielski              * restart input from the parent file/macro, if any.
845*b1cdbd2cSJim Jagielski              */
846*b1cdbd2cSJim Jagielski             free(file->filename);               /* Free name and        */
847*b1cdbd2cSJim Jagielski             if (file->progname != NULL)         /* if a #line was seen, */
848*b1cdbd2cSJim Jagielski                 free(file->progname);           /* free it, too.        */
849*b1cdbd2cSJim Jagielski             free((char *) file);                /* Free file space      */
850*b1cdbd2cSJim Jagielski             if (infile == NULL)                 /* If at end of file    */
851*b1cdbd2cSJim Jagielski                 return (EOF_CHAR);              /* Return end of file   */
852*b1cdbd2cSJim Jagielski             line = infile->line;                /* Reset line number    */
853*b1cdbd2cSJim Jagielski             goto get_from_file;                 /* Get from the top.    */
854*b1cdbd2cSJim Jagielski         }
855*b1cdbd2cSJim Jagielski         /*
856*b1cdbd2cSJim Jagielski          * Common processing for the new character.
857*b1cdbd2cSJim Jagielski          */
858*b1cdbd2cSJim Jagielski         if (c == DEF_MAGIC && file->fp != NULL) /* Don't allow delete   */
859*b1cdbd2cSJim Jagielski             goto newline;                       /* from a file          */
860*b1cdbd2cSJim Jagielski         if (file->parent != NULL) {             /* Macro or #include    */
861*b1cdbd2cSJim Jagielski             if (popped != 0)
862*b1cdbd2cSJim Jagielski                 file->parent->unrecur += popped;
863*b1cdbd2cSJim Jagielski             else {
864*b1cdbd2cSJim Jagielski                 recursion -= file->parent->unrecur;
865*b1cdbd2cSJim Jagielski                 if (recursion < 0)
866*b1cdbd2cSJim Jagielski                     recursion = 0;
867*b1cdbd2cSJim Jagielski                 file->parent->unrecur = 0;
868*b1cdbd2cSJim Jagielski             }
869*b1cdbd2cSJim Jagielski         }
870*b1cdbd2cSJim Jagielski #if (HOST == SYS_UNIX)
871*b1cdbd2cSJim Jagielski /*ER*/	if (c == '\r')
872*b1cdbd2cSJim Jagielski /*ER*/		return get();						/* DOS fuck				*/
873*b1cdbd2cSJim Jagielski #endif
874*b1cdbd2cSJim Jagielski         if (c == '\n')                          /* Maintain current     */
875*b1cdbd2cSJim Jagielski             ++line;                             /* line counter         */
876*b1cdbd2cSJim Jagielski         if (instring)                           /* Strings just return  */
877*b1cdbd2cSJim Jagielski             return (c);                         /* the character.       */
878*b1cdbd2cSJim Jagielski         else if (c == '/') {                    /* Comment?             */
879*b1cdbd2cSJim Jagielski             instring = TRUE;                    /* So get() won't loop  */
880*b1cdbd2cSJim Jagielski /*MM c++ comments  */
881*b1cdbd2cSJim Jagielski /*MM*/      c = get();
882*b1cdbd2cSJim Jagielski /*MM*/      if ((c != '*') && (c != '/')) {     /* Next byte '*'?       */
883*b1cdbd2cSJim Jagielski                 instring = FALSE;               /* Nope, no comment     */
884*b1cdbd2cSJim Jagielski                 unget();                        /* Push the char. back  */
885*b1cdbd2cSJim Jagielski                 return ('/');                   /* Return the slash     */
886*b1cdbd2cSJim Jagielski             }
887*b1cdbd2cSJim Jagielski             if (keepcomments) {                 /* If writing comments  */
888*b1cdbd2cSJim Jagielski                 PUTCHAR('/');                   /* Write out the        */
889*b1cdbd2cSJim Jagielski                                                 /*   initializer        */
890*b1cdbd2cSJim Jagielski /*MM*/          if( '*' == c )
891*b1cdbd2cSJim Jagielski                     PUTCHAR('*');
892*b1cdbd2cSJim Jagielski /*MM*/          else
893*b1cdbd2cSJim Jagielski /*MM*/              PUTCHAR('/');
894*b1cdbd2cSJim Jagielski 
895*b1cdbd2cSJim Jagielski             }
896*b1cdbd2cSJim Jagielski /*MM*/      if( '*' == c ){
897*b1cdbd2cSJim Jagielski                 for (;;) {                          /* Eat a comment        */
898*b1cdbd2cSJim Jagielski                     c = get();
899*b1cdbd2cSJim Jagielski     test:           if (keepcomments && c != EOF_CHAR)
900*b1cdbd2cSJim Jagielski                         cput(c);
901*b1cdbd2cSJim Jagielski                     switch (c) {
902*b1cdbd2cSJim Jagielski                     case EOF_CHAR:
903*b1cdbd2cSJim Jagielski                         cerror("EOF in comment", NULLST);
904*b1cdbd2cSJim Jagielski                         return (EOF_CHAR);
905*b1cdbd2cSJim Jagielski 
906*b1cdbd2cSJim Jagielski                     case '/':
907*b1cdbd2cSJim Jagielski                         if ((c = get()) != '*')     /* Don't let comments   */
908*b1cdbd2cSJim Jagielski                             goto test;              /* Nest.                */
909*b1cdbd2cSJim Jagielski #ifdef STRICT_COMMENTS
910*b1cdbd2cSJim Jagielski                         cwarn("Nested comments", NULLST);
911*b1cdbd2cSJim Jagielski #endif
912*b1cdbd2cSJim Jagielski                                                     /* Fall into * stuff    */
913*b1cdbd2cSJim Jagielski                     case '*':
914*b1cdbd2cSJim Jagielski                         if ((c = get()) != '/')     /* If comment doesn't   */
915*b1cdbd2cSJim Jagielski                             goto test;              /* end, look at next    */
916*b1cdbd2cSJim Jagielski                         instring = FALSE;           /* End of comment,      */
917*b1cdbd2cSJim Jagielski                         if (keepcomments) {         /* Put out the comment  */
918*b1cdbd2cSJim Jagielski                             cput(c);                /* terminator, too      */
919*b1cdbd2cSJim Jagielski                         }
920*b1cdbd2cSJim Jagielski                         /*
921*b1cdbd2cSJim Jagielski                          * A comment is syntactically "whitespace" --
922*b1cdbd2cSJim Jagielski                          * however, there are certain strange sequences
923*b1cdbd2cSJim Jagielski                          * such as
924*b1cdbd2cSJim Jagielski                          *          #define foo(x)  (something)
925*b1cdbd2cSJim Jagielski                          *                  foo|* comment *|(123)
926*b1cdbd2cSJim Jagielski                          *       these are '/' ^           ^
927*b1cdbd2cSJim Jagielski                          * where just returning space (or COM_SEP) will cause
928*b1cdbd2cSJim Jagielski                          * problems.  This can be "fixed" by overwriting the
929*b1cdbd2cSJim Jagielski                          * '/' in the input line buffer with ' ' (or COM_SEP)
930*b1cdbd2cSJim Jagielski                          * but that may mess up an error message.
931*b1cdbd2cSJim Jagielski                          * So, we peek ahead -- if the next character is
932*b1cdbd2cSJim Jagielski                          * "whitespace" we just get another character, if not,
933*b1cdbd2cSJim Jagielski                          * we modify the buffer.  All in the name of purity.
934*b1cdbd2cSJim Jagielski                          */
935*b1cdbd2cSJim Jagielski                         if (*file->bptr == '\n'
936*b1cdbd2cSJim Jagielski                          || type[*file->bptr & 0xFF] == SPA)
937*b1cdbd2cSJim Jagielski                             goto newline;
938*b1cdbd2cSJim Jagielski #if COMMENT_INVISIBLE
939*b1cdbd2cSJim Jagielski                         /*
940*b1cdbd2cSJim Jagielski                          * Return magic (old-fashioned) syntactic space.
941*b1cdbd2cSJim Jagielski                          */
942*b1cdbd2cSJim Jagielski                         return ((file->bptr[-1] = COM_SEP));
943*b1cdbd2cSJim Jagielski #else
944*b1cdbd2cSJim Jagielski                         return ((file->bptr[-1] = ' '));
945*b1cdbd2cSJim Jagielski #endif
946*b1cdbd2cSJim Jagielski 
947*b1cdbd2cSJim Jagielski                     case '\n':                      /* we'll need a #line   */
948*b1cdbd2cSJim Jagielski                         if (!keepcomments)
949*b1cdbd2cSJim Jagielski                             wrongline = TRUE;       /* later...             */
950*b1cdbd2cSJim Jagielski                     default:                        /* Anything else is     */
951*b1cdbd2cSJim Jagielski                         break;                      /* Just a character     */
952*b1cdbd2cSJim Jagielski                     }                               /* End switch           */
953*b1cdbd2cSJim Jagielski                 }                                   /* End comment loop     */
954*b1cdbd2cSJim Jagielski             }
955*b1cdbd2cSJim Jagielski             else{                                   /* c++ comment          */
956*b1cdbd2cSJim Jagielski /*MM c++ comment*/
957*b1cdbd2cSJim Jagielski                 for (;;) {                          /* Eat a comment        */
958*b1cdbd2cSJim Jagielski                     c = get();
959*b1cdbd2cSJim Jagielski                     if (keepcomments && c != EOF_CHAR)
960*b1cdbd2cSJim Jagielski                         cput(c);
961*b1cdbd2cSJim Jagielski                     if( EOF_CHAR == c )
962*b1cdbd2cSJim Jagielski                         return (EOF_CHAR);
963*b1cdbd2cSJim Jagielski                     else if( '\n' == c ){
964*b1cdbd2cSJim Jagielski                         instring = FALSE;           /* End of comment,      */
965*b1cdbd2cSJim Jagielski                         return( c );
966*b1cdbd2cSJim Jagielski                     }
967*b1cdbd2cSJim Jagielski                 }
968*b1cdbd2cSJim Jagielski             }
969*b1cdbd2cSJim Jagielski         }                                       /* End if in comment    */
970*b1cdbd2cSJim Jagielski         else if (!inmacro && c == '\\') {       /* If backslash, peek   */
971*b1cdbd2cSJim Jagielski             if ((c = get()) == '\n') {          /* for a <nl>.  If so,  */
972*b1cdbd2cSJim Jagielski                 wrongline = TRUE;
973*b1cdbd2cSJim Jagielski                 goto newline;
974*b1cdbd2cSJim Jagielski             }
975*b1cdbd2cSJim Jagielski             else {                              /* Backslash anything   */
976*b1cdbd2cSJim Jagielski                 unget();                        /* Get it later         */
977*b1cdbd2cSJim Jagielski                 return ('\\');                  /* Return the backslash */
978*b1cdbd2cSJim Jagielski             }
979*b1cdbd2cSJim Jagielski         }
980*b1cdbd2cSJim Jagielski         else if (c == '\f' || c == VT)          /* Form Feed, Vertical  */
981*b1cdbd2cSJim Jagielski             c = ' ';                            /* Tab are whitespace   */
982*b1cdbd2cSJim Jagielski         else if (c == 0xef)						/* eat up UTF-8 BOM */
983*b1cdbd2cSJim Jagielski         {
984*b1cdbd2cSJim Jagielski             if((c = get()) == 0xbb)
985*b1cdbd2cSJim Jagielski             {
986*b1cdbd2cSJim Jagielski                 if((c = get()) == 0xbf)
987*b1cdbd2cSJim Jagielski                 {
988*b1cdbd2cSJim Jagielski                     c = get();
989*b1cdbd2cSJim Jagielski                     return c;
990*b1cdbd2cSJim Jagielski                 }
991*b1cdbd2cSJim Jagielski                 else
992*b1cdbd2cSJim Jagielski                 {
993*b1cdbd2cSJim Jagielski                     unget();
994*b1cdbd2cSJim Jagielski                     unget();
995*b1cdbd2cSJim Jagielski                     return 0xef;
996*b1cdbd2cSJim Jagielski                 }
997*b1cdbd2cSJim Jagielski             }
998*b1cdbd2cSJim Jagielski             else
999*b1cdbd2cSJim Jagielski             {
1000*b1cdbd2cSJim Jagielski                 unget();
1001*b1cdbd2cSJim Jagielski                 return 0xef;
1002*b1cdbd2cSJim Jagielski             }
1003*b1cdbd2cSJim Jagielski         }
1004*b1cdbd2cSJim Jagielski         return (c);                             /* Just return the char */
1005*b1cdbd2cSJim Jagielski }
1006*b1cdbd2cSJim Jagielski 
unget()1007*b1cdbd2cSJim Jagielski void unget()
1008*b1cdbd2cSJim Jagielski /*
1009*b1cdbd2cSJim Jagielski  * Backup the pointer to reread the last character.  Fatal error
1010*b1cdbd2cSJim Jagielski  * (code bug) if we backup too far.  unget() may be called,
1011*b1cdbd2cSJim Jagielski  * without problems, at end of file.  Only one character may
1012*b1cdbd2cSJim Jagielski  * be ungotten.  If you need to unget more, call ungetstring().
1013*b1cdbd2cSJim Jagielski  */
1014*b1cdbd2cSJim Jagielski {
1015*b1cdbd2cSJim Jagielski         register FILEINFO       *file;
1016*b1cdbd2cSJim Jagielski 
1017*b1cdbd2cSJim Jagielski         if ((file = infile) == NULL)
1018*b1cdbd2cSJim Jagielski             return;                     /* Unget after EOF              */
1019*b1cdbd2cSJim Jagielski         if (--file->bptr < file->buffer)
1020*b1cdbd2cSJim Jagielski             cfatal("Too much pushback", NULLST);
1021*b1cdbd2cSJim Jagielski         if (*file->bptr == '\n')        /* Ungetting a newline?         */
1022*b1cdbd2cSJim Jagielski             --line;                     /* Unget the line number, too   */
1023*b1cdbd2cSJim Jagielski }
1024*b1cdbd2cSJim Jagielski 
ungetstring(char * text)1025*b1cdbd2cSJim Jagielski void ungetstring(char* text)
1026*b1cdbd2cSJim Jagielski /*
1027*b1cdbd2cSJim Jagielski  * Push a string back on the input stream.  This is done by treating
1028*b1cdbd2cSJim Jagielski  * the text as if it were a macro.
1029*b1cdbd2cSJim Jagielski  */
1030*b1cdbd2cSJim Jagielski {
1031*b1cdbd2cSJim Jagielski         register FILEINFO       *file;
1032*b1cdbd2cSJim Jagielski #ifndef ZTC /* BP */
1033*b1cdbd2cSJim Jagielski         extern FILEINFO         *getfile();
1034*b1cdbd2cSJim Jagielski #endif
1035*b1cdbd2cSJim Jagielski         file = getfile(strlen(text) + 1, "");
1036*b1cdbd2cSJim Jagielski         strcpy(file->buffer, text);
1037*b1cdbd2cSJim Jagielski }
1038*b1cdbd2cSJim Jagielski 
1039*b1cdbd2cSJim Jagielski int
cget()1040*b1cdbd2cSJim Jagielski cget()
1041*b1cdbd2cSJim Jagielski /*
1042*b1cdbd2cSJim Jagielski  * Get one character, absorb "funny space" after comments or
1043*b1cdbd2cSJim Jagielski  * token concatenation
1044*b1cdbd2cSJim Jagielski  */
1045*b1cdbd2cSJim Jagielski {
1046*b1cdbd2cSJim Jagielski         register int    c;
1047*b1cdbd2cSJim Jagielski 
1048*b1cdbd2cSJim Jagielski         do {
1049*b1cdbd2cSJim Jagielski             c = get();
1050*b1cdbd2cSJim Jagielski #if COMMENT_INVISIBLE
1051*b1cdbd2cSJim Jagielski         } while (c == TOK_SEP || c == COM_SEP);
1052*b1cdbd2cSJim Jagielski #else
1053*b1cdbd2cSJim Jagielski         } while (c == TOK_SEP);
1054*b1cdbd2cSJim Jagielski #endif
1055*b1cdbd2cSJim Jagielski         return (c);
1056*b1cdbd2cSJim Jagielski }
1057*b1cdbd2cSJim Jagielski 
1058*b1cdbd2cSJim Jagielski /*
1059*b1cdbd2cSJim Jagielski  * Error messages and other hacks.  The first byte of severity
1060*b1cdbd2cSJim Jagielski  * is 'S' for string arguments and 'I' for int arguments.  This
1061*b1cdbd2cSJim Jagielski  * is needed for portability with machines that have int's that
1062*b1cdbd2cSJim Jagielski  * are shorter than  char *'s.
1063*b1cdbd2cSJim Jagielski  */
1064*b1cdbd2cSJim Jagielski 
domsg(char * severity,char * format,void * arg)1065*b1cdbd2cSJim Jagielski static void domsg(char* severity, char* format, void* arg)
1066*b1cdbd2cSJim Jagielski /*
1067*b1cdbd2cSJim Jagielski  * Print filenames, macro names, and line numbers for error messages.
1068*b1cdbd2cSJim Jagielski  */
1069*b1cdbd2cSJim Jagielski {
1070*b1cdbd2cSJim Jagielski         register char           *tp;
1071*b1cdbd2cSJim Jagielski         register FILEINFO       *file;
1072*b1cdbd2cSJim Jagielski 
1073*b1cdbd2cSJim Jagielski         fprintf(stderr, "%sline %d, %s: ", MSG_PREFIX, line, &severity[1]);
1074*b1cdbd2cSJim Jagielski         if (*severity == 'S')
1075*b1cdbd2cSJim Jagielski             fprintf(stderr, format, (char *)arg);
1076*b1cdbd2cSJim Jagielski         else
1077*b1cdbd2cSJim Jagielski             fprintf(stderr, format, *((int *)arg) );
1078*b1cdbd2cSJim Jagielski         putc('\n', stderr);
1079*b1cdbd2cSJim Jagielski         if ((file = infile) == NULL)
1080*b1cdbd2cSJim Jagielski             return;                             /* At end of file       */
1081*b1cdbd2cSJim Jagielski         if (file->fp != NULL) {
1082*b1cdbd2cSJim Jagielski             tp = file->buffer;                  /* Print current file   */
1083*b1cdbd2cSJim Jagielski             fprintf(stderr, "%s", tp);          /* name, making sure    */
1084*b1cdbd2cSJim Jagielski             if (tp[strlen(tp) - 1] != '\n')     /* there's a newline    */
1085*b1cdbd2cSJim Jagielski                 putc('\n', stderr);
1086*b1cdbd2cSJim Jagielski         }
1087*b1cdbd2cSJim Jagielski         while ((file = file->parent) != NULL) { /* Print #includes, too */
1088*b1cdbd2cSJim Jagielski             if (file->fp == NULL)
1089*b1cdbd2cSJim Jagielski                 fprintf(stderr, "from macro %s\n", file->filename);
1090*b1cdbd2cSJim Jagielski             else {
1091*b1cdbd2cSJim Jagielski                 tp = file->buffer;
1092*b1cdbd2cSJim Jagielski                 fprintf(stderr, "from file %s, line %d:\n%s",
1093*b1cdbd2cSJim Jagielski                     (file->progname != NULL)
1094*b1cdbd2cSJim Jagielski                         ? file->progname : file->filename,
1095*b1cdbd2cSJim Jagielski                     file->line, tp);
1096*b1cdbd2cSJim Jagielski                 if (tp[strlen(tp) - 1] != '\n')
1097*b1cdbd2cSJim Jagielski                     putc('\n', stderr);
1098*b1cdbd2cSJim Jagielski             }
1099*b1cdbd2cSJim Jagielski         }
1100*b1cdbd2cSJim Jagielski }
1101*b1cdbd2cSJim Jagielski 
cerror(char * format,char * sarg)1102*b1cdbd2cSJim Jagielski void cerror(char* format, char* sarg)
1103*b1cdbd2cSJim Jagielski /*
1104*b1cdbd2cSJim Jagielski  * Print a normal error message, string argument.
1105*b1cdbd2cSJim Jagielski  */
1106*b1cdbd2cSJim Jagielski {
1107*b1cdbd2cSJim Jagielski         domsg("SError", format, sarg);
1108*b1cdbd2cSJim Jagielski         errors++;
1109*b1cdbd2cSJim Jagielski }
1110*b1cdbd2cSJim Jagielski 
cierror(char * format,int narg)1111*b1cdbd2cSJim Jagielski void cierror(char* format, int narg)
1112*b1cdbd2cSJim Jagielski /*
1113*b1cdbd2cSJim Jagielski  * Print a normal error message, numeric argument.
1114*b1cdbd2cSJim Jagielski  */
1115*b1cdbd2cSJim Jagielski {
1116*b1cdbd2cSJim Jagielski         domsg("IError", format, &narg);
1117*b1cdbd2cSJim Jagielski         errors++;
1118*b1cdbd2cSJim Jagielski }
1119*b1cdbd2cSJim Jagielski 
cfatal(char * format,char * sarg)1120*b1cdbd2cSJim Jagielski void cfatal(char* format, char* sarg)
1121*b1cdbd2cSJim Jagielski /*
1122*b1cdbd2cSJim Jagielski  * A real disaster
1123*b1cdbd2cSJim Jagielski  */
1124*b1cdbd2cSJim Jagielski {
1125*b1cdbd2cSJim Jagielski         domsg("SFatal error", format, sarg);
1126*b1cdbd2cSJim Jagielski         exit(IO_ERROR);
1127*b1cdbd2cSJim Jagielski }
1128*b1cdbd2cSJim Jagielski 
cwarn(char * format,char * sarg)1129*b1cdbd2cSJim Jagielski void cwarn(char* format, char* sarg)
1130*b1cdbd2cSJim Jagielski /*
1131*b1cdbd2cSJim Jagielski  * A non-fatal error, string argument.
1132*b1cdbd2cSJim Jagielski  */
1133*b1cdbd2cSJim Jagielski {
1134*b1cdbd2cSJim Jagielski         domsg("SWarning", format, sarg);
1135*b1cdbd2cSJim Jagielski }
1136*b1cdbd2cSJim Jagielski 
ciwarn(char * format,int narg)1137*b1cdbd2cSJim Jagielski void ciwarn(char* format, int narg)
1138*b1cdbd2cSJim Jagielski /*
1139*b1cdbd2cSJim Jagielski  * A non-fatal error, numeric argument.
1140*b1cdbd2cSJim Jagielski  */
1141*b1cdbd2cSJim Jagielski {
1142*b1cdbd2cSJim Jagielski         domsg("IWarning", format, &narg);
1143*b1cdbd2cSJim Jagielski }
1144*b1cdbd2cSJim Jagielski 
1145