2 |
7u83 |
1 |
/*
|
|
|
2 |
Crown Copyright (c) 1997
|
|
|
3 |
|
|
|
4 |
This TenDRA(r) Computer Program is subject to Copyright
|
|
|
5 |
owned by the United Kingdom Secretary of State for Defence
|
|
|
6 |
acting through the Defence Evaluation and Research Agency
|
|
|
7 |
(DERA). It is made available to Recipients with a
|
|
|
8 |
royalty-free licence for its use, reproduction, transfer
|
|
|
9 |
to other parties and amendment for any purpose not excluding
|
|
|
10 |
product development provided that any such use et cetera
|
|
|
11 |
shall be deemed to be acceptance of the following conditions:-
|
|
|
12 |
|
|
|
13 |
(1) Its Recipients shall ensure that this Notice is
|
|
|
14 |
reproduced upon any copies or amended versions of it;
|
|
|
15 |
|
|
|
16 |
(2) Any amended version of it shall be clearly marked to
|
|
|
17 |
show both the nature of and the organisation responsible
|
|
|
18 |
for the relevant amendment or amendments;
|
|
|
19 |
|
|
|
20 |
(3) Its onward transfer from a recipient to another
|
|
|
21 |
party shall be deemed to be that party's acceptance of
|
|
|
22 |
these conditions;
|
|
|
23 |
|
|
|
24 |
(4) DERA gives no warranty or assurance as to its
|
|
|
25 |
quality or suitability for any purpose and DERA accepts
|
|
|
26 |
no liability whatsoever in relation to any use to which
|
|
|
27 |
it may be put.
|
|
|
28 |
*/
|
|
|
29 |
|
|
|
30 |
|
|
|
31 |
#include "config.h"
|
|
|
32 |
#include "system.h"
|
|
|
33 |
#include "c_types.h"
|
|
|
34 |
#include "exp_ops.h"
|
|
|
35 |
#include "hashid_ops.h"
|
|
|
36 |
#include "id_ops.h"
|
|
|
37 |
#include "loc_ext.h"
|
|
|
38 |
#include "member_ops.h"
|
|
|
39 |
#include "nat_ops.h"
|
|
|
40 |
#include "str_ops.h"
|
|
|
41 |
#include "tok_ops.h"
|
|
|
42 |
#include "type_ops.h"
|
|
|
43 |
#include "error.h"
|
|
|
44 |
#include "catalog.h"
|
|
|
45 |
#include "option.h"
|
|
|
46 |
#include "buffer.h"
|
|
|
47 |
#include "char.h"
|
|
|
48 |
#include "compile.h"
|
|
|
49 |
#include "constant.h"
|
|
|
50 |
#include "convert.h"
|
|
|
51 |
#include "dump.h"
|
|
|
52 |
#include "file.h"
|
|
|
53 |
#include "hash.h"
|
|
|
54 |
#include "identifier.h"
|
|
|
55 |
#include "lex.h"
|
|
|
56 |
#include "literal.h"
|
|
|
57 |
#include "macro.h"
|
|
|
58 |
#include "namespace.h"
|
|
|
59 |
#include "parse.h"
|
|
|
60 |
#include "pragma.h"
|
|
|
61 |
#include "predict.h"
|
|
|
62 |
#include "preproc.h"
|
|
|
63 |
#include "print.h"
|
|
|
64 |
#include "statement.h"
|
|
|
65 |
#include "symbols.h"
|
|
|
66 |
#include "syntax.h"
|
|
|
67 |
#include "tokdef.h"
|
|
|
68 |
#include "token.h"
|
|
|
69 |
#include "ustring.h"
|
|
|
70 |
#include "xalloc.h"
|
|
|
71 |
|
|
|
72 |
|
|
|
73 |
/*
|
|
|
74 |
FORWARD DECLARATIONS
|
|
|
75 |
|
|
|
76 |
The following functions, which are concerned with processing assertions,
|
|
|
77 |
are used in read_if_exp before they are defined.
|
|
|
78 |
*/
|
|
|
79 |
|
|
|
80 |
static int eq_pptok PROTO_S ( ( PPTOKEN *, PPTOKEN * ) ) ;
|
|
|
81 |
static PPTOKEN *skip_predicate PROTO_S ( ( PPTOKEN **, int ) ) ;
|
|
|
82 |
static int check_assert PROTO_S ( ( HASHID, PPTOKEN *, int ) ) ;
|
|
|
83 |
|
|
|
84 |
|
|
|
85 |
/*
|
|
|
86 |
PREPROCESSING FLAGS
|
|
|
87 |
|
|
|
88 |
The flag in_preproc_dir is set to true in a preprocessing directive.
|
|
|
89 |
The flag preproc_only causes only the preprocessor to be run. Finally
|
|
|
90 |
preproc_loc records the position of the start of each preprocessing
|
|
|
91 |
directive.
|
|
|
92 |
*/
|
|
|
93 |
|
|
|
94 |
int in_preproc_dir = 0 ;
|
|
|
95 |
int no_preproc_dir = 0 ;
|
|
|
96 |
int in_pragma_dir = 0 ;
|
|
|
97 |
int in_hash_if_exp = 0 ;
|
|
|
98 |
int pragma_number = 0 ;
|
|
|
99 |
int preproc_only = 0 ;
|
|
|
100 |
int preproc_space = 0 ;
|
|
|
101 |
LOCATION preproc_loc = NULL_loc ;
|
|
|
102 |
|
|
|
103 |
|
|
|
104 |
/*
|
|
|
105 |
NEGATE A CONDITIONAL
|
|
|
106 |
|
|
|
107 |
This routine negates the conditional cond. Note that skipped and
|
|
|
108 |
unresolved conditions negate to themselves.
|
|
|
109 |
*/
|
|
|
110 |
|
|
|
111 |
static unsigned negate_cond
|
|
|
112 |
PROTO_N ( ( cond ) )
|
|
|
113 |
PROTO_T ( unsigned cond )
|
|
|
114 |
{
|
|
|
115 |
if ( cond == PP_TRUE ) return ( PP_FALSE ) ;
|
|
|
116 |
if ( cond == PP_FALSE ) return ( PP_TRUE ) ;
|
|
|
117 |
if ( cond == PP_PAST ) return ( PP_FALSE ) ;
|
|
|
118 |
return ( cond ) ;
|
|
|
119 |
}
|
|
|
120 |
|
|
|
121 |
|
|
|
122 |
/*
|
|
|
123 |
CONDITIONAL COMPILATION STACK
|
|
|
124 |
|
|
|
125 |
The stack preproc_stack gives all the active conditional compilation
|
|
|
126 |
states. In addition loc_stack records the corresponding file locations.
|
|
|
127 |
preproc_depth gives the depth of conditional compilation within the
|
|
|
128 |
current file.
|
|
|
129 |
*/
|
|
|
130 |
|
|
|
131 |
static STACK ( unsigned ) preproc_stack = NULL_stack ( unsigned ) ;
|
|
|
132 |
static STACK ( LOCATION ) loc_stack = NULL_stack ( LOCATION ) ;
|
|
|
133 |
static unsigned preproc_depth = 0 ;
|
|
|
134 |
|
|
|
135 |
|
|
|
136 |
/*
|
|
|
137 |
SET UP CONDITIONAL COMPILATION STACK
|
|
|
138 |
|
|
|
139 |
This routine sets up the conditional compilation stack at the start
|
|
|
140 |
of a source file by pushing an end marker.
|
|
|
141 |
*/
|
|
|
142 |
|
|
|
143 |
void start_preproc_if
|
|
|
144 |
PROTO_Z ()
|
|
|
145 |
{
|
|
|
146 |
PUSH_unsigned ( preproc_depth, preproc_stack ) ;
|
|
|
147 |
PUSH_unsigned ( PP_END, preproc_stack ) ;
|
|
|
148 |
PUSH_loc ( crt_loc, loc_stack ) ;
|
|
|
149 |
preproc_depth = 0 ;
|
|
|
150 |
return ;
|
|
|
151 |
}
|
|
|
152 |
|
|
|
153 |
|
|
|
154 |
/*
|
|
|
155 |
CLEAR CONDITIONAL COMPILATION STACK
|
|
|
156 |
|
|
|
157 |
This routine is called at the end of each source file to check for
|
|
|
158 |
any unmatched '#if', '#elif' or '#else' directives. It clears the
|
|
|
159 |
conditional compilation stack down as far as the end marker set up
|
|
|
160 |
by the previous routine. It is possible for the routine to be
|
|
|
161 |
called more than once for the main source file, hence the necessity
|
|
|
162 |
to check that the stack is not empty. The routine returns true if
|
|
|
163 |
no unmatched directives are found.
|
|
|
164 |
*/
|
|
|
165 |
|
|
|
166 |
int clear_preproc_if
|
|
|
167 |
PROTO_Z ()
|
|
|
168 |
{
|
|
|
169 |
int ok = 1 ;
|
|
|
170 |
while ( !IS_NULL_stack ( preproc_stack ) ) {
|
|
|
171 |
int dir ;
|
|
|
172 |
LOCATION loc ;
|
|
|
173 |
unsigned cond ;
|
|
|
174 |
POP_unsigned ( cond, preproc_stack ) ;
|
|
|
175 |
POP_loc ( loc, loc_stack ) ;
|
|
|
176 |
if ( cond == PP_END ) {
|
|
|
177 |
/* Restore stored preprocessing depth */
|
|
|
178 |
POP_unsigned ( preproc_depth, preproc_stack ) ;
|
|
|
179 |
break ;
|
|
|
180 |
}
|
|
|
181 |
if ( cond & PP_HAVE_ELSE ) {
|
|
|
182 |
dir = lex_else ;
|
|
|
183 |
} else if ( cond & PP_HAVE_ELIF ) {
|
|
|
184 |
dir = lex_elif ;
|
|
|
185 |
} else {
|
|
|
186 |
dir = lex_if ;
|
|
|
187 |
}
|
|
|
188 |
report ( loc, ERR_cpp_cond_if_match ( dir, lex_endif ) ) ;
|
|
|
189 |
decr_value ( OPT_VAL_hash_if_depth ) ;
|
|
|
190 |
preproc_depth-- ;
|
|
|
191 |
ok = 0 ;
|
|
|
192 |
}
|
|
|
193 |
return ( ok ) ;
|
|
|
194 |
}
|
|
|
195 |
|
|
|
196 |
|
|
|
197 |
/*
|
|
|
198 |
MACRO-LIKE TOKEN IDENTIFIER
|
|
|
199 |
|
|
|
200 |
If check_macro finds a macro-like token then the corresponding identifier
|
|
|
201 |
is stored in this variable.
|
|
|
202 |
*/
|
|
|
203 |
|
|
|
204 |
IDENTIFIER token_macro = NULL_id ;
|
|
|
205 |
|
|
|
206 |
|
|
|
207 |
/*
|
|
|
208 |
CHECK WHETHER A MACRO IS DEFINED
|
|
|
209 |
|
|
|
210 |
This routine checks whether the hash table entry macro represents a
|
|
|
211 |
valid macro. It returns PP_TRUE if macro is already defined and
|
|
|
212 |
PP_FALSE otherwise. It also reports on ISO keywords and other invalid
|
|
|
213 |
macro identifiers. If used is true then the macro is marked as having
|
|
|
214 |
been used.
|
|
|
215 |
*/
|
|
|
216 |
|
|
|
217 |
unsigned check_macro
|
|
|
218 |
PROTO_N ( ( macro, used ) )
|
|
|
219 |
PROTO_T ( HASHID macro X int used )
|
|
|
220 |
{
|
|
|
221 |
/* Check for simple macros */
|
|
|
222 |
DECL_SPEC ds ;
|
|
|
223 |
IDENTIFIER id ;
|
|
|
224 |
if ( IS_NULL_hashid ( macro ) ) {
|
|
|
225 |
/* Special case for protection macros */
|
|
|
226 |
return ( PP_TRUE ) ;
|
|
|
227 |
}
|
|
|
228 |
id = DEREF_id ( hashid_id ( macro ) ) ;
|
|
|
229 |
switch ( TAG_id ( id ) ) {
|
|
|
230 |
case id_obj_macro_tag :
|
|
|
231 |
case id_func_macro_tag : {
|
|
|
232 |
if ( used ) {
|
|
|
233 |
ds = DEREF_dspec ( id_storage ( id ) ) ;
|
|
|
234 |
ds |= dspec_used ;
|
|
|
235 |
COPY_dspec ( id_storage ( id ), ds ) ;
|
|
|
236 |
if ( do_macro && do_usage ) dump_use ( id, &preproc_loc, 1 ) ;
|
|
|
237 |
}
|
|
|
238 |
return ( PP_TRUE ) ;
|
|
|
239 |
}
|
|
|
240 |
case id_iso_keyword_tag : {
|
|
|
241 |
if ( used ) report ( preproc_loc, ERR_lex_key_iso ( macro ) ) ;
|
|
|
242 |
break ;
|
|
|
243 |
}
|
|
|
244 |
}
|
|
|
245 |
|
|
|
246 |
/* Check for tokenised values */
|
|
|
247 |
if ( preproc_only ) {
|
|
|
248 |
id = underlying_id ( id ) ;
|
|
|
249 |
ds = DEREF_dspec ( id_storage ( id ) ) ;
|
|
|
250 |
if ( ds & dspec_token ) {
|
|
|
251 |
/* May be a token */
|
|
|
252 |
token_macro = id ;
|
|
|
253 |
return ( PP_TOKEN | PP_UNRESOLVED ) ;
|
|
|
254 |
}
|
|
|
255 |
|
|
|
256 |
} else {
|
|
|
257 |
id = find_id ( macro ) ;
|
|
|
258 |
while ( !IS_NULL_id ( id ) ) {
|
|
|
259 |
IDENTIFIER tid = find_token ( id ) ;
|
|
|
260 |
if ( IS_id_token ( tid ) ) {
|
|
|
261 |
IDENTIFIER sid = DEREF_id ( id_token_alt ( tid ) ) ;
|
|
|
262 |
ds = DEREF_dspec ( id_storage ( sid ) ) ;
|
|
|
263 |
if ( ( ds & dspec_token ) && !( ds & dspec_template ) ) {
|
|
|
264 |
TOKEN tok = DEREF_tok ( id_token_sort ( tid ) ) ;
|
|
|
265 |
switch ( TAG_tok ( tok ) ) {
|
|
|
266 |
case tok_exp_tag :
|
|
|
267 |
case tok_stmt_tag :
|
|
|
268 |
case tok_nat_tag :
|
|
|
269 |
case tok_snat_tag :
|
|
|
270 |
case tok_func_tag :
|
|
|
271 |
case tok_proc_tag : {
|
|
|
272 |
/* These are in the macro namespace */
|
|
|
273 |
if ( used ) use_id ( id, 0 ) ;
|
|
|
274 |
token_macro = id ;
|
|
|
275 |
ds = DEREF_dspec ( id_storage ( tid ) ) ;
|
|
|
276 |
if ( ds & ( dspec_pure | dspec_defn ) ) {
|
|
|
277 |
return ( PP_TOKEN | PP_TRUE ) ;
|
|
|
278 |
}
|
|
|
279 |
return ( PP_TOKEN | PP_FALSE ) ;
|
|
|
280 |
}
|
|
|
281 |
}
|
|
|
282 |
}
|
|
|
283 |
}
|
|
|
284 |
if ( !IS_id_function_etc ( id ) ) break ;
|
|
|
285 |
id = DEREF_id ( id_function_etc_over ( id ) ) ;
|
|
|
286 |
}
|
|
|
287 |
}
|
|
|
288 |
return ( PP_FALSE ) ;
|
|
|
289 |
}
|
|
|
290 |
|
|
|
291 |
|
|
|
292 |
/*
|
|
|
293 |
TARGET DEPENDENT CONDITION
|
|
|
294 |
|
|
|
295 |
Any target dependent conditional compilation expressions encountered
|
|
|
296 |
are stored in this variable.
|
|
|
297 |
*/
|
|
|
298 |
|
|
|
299 |
EXP crt_hash_if_exp = NULL_exp ;
|
|
|
300 |
|
|
|
301 |
|
|
|
302 |
/*
|
|
|
303 |
PATCH PREPROCESSING DIRECTIVE INTO PREPROCESSOR OUTPUT
|
|
|
304 |
|
|
|
305 |
This routine is used to patch the preprocessing directive given by
|
|
|
306 |
the preprocessing tokens p into the main preprocessor output. It is
|
|
|
307 |
used to preserve target dependent conditionals and other directives
|
|
|
308 |
which need to be passed through to the output.
|
|
|
309 |
*/
|
|
|
310 |
|
|
|
311 |
void patch_preproc_dir
|
|
|
312 |
PROTO_N ( ( p ) )
|
|
|
313 |
PROTO_T ( PPTOKEN *p )
|
|
|
314 |
{
|
|
|
315 |
if ( p ) {
|
|
|
316 |
PPTOKEN *q = p ;
|
|
|
317 |
while ( q->next && q->next->tok != lex_newline ) q = q->next ;
|
|
|
318 |
free_tok_list ( q->next ) ;
|
|
|
319 |
q->next = crt_token->next ;
|
|
|
320 |
crt_token->next = p ;
|
|
|
321 |
p->pp_space = WHITE_SPACE ;
|
|
|
322 |
}
|
|
|
323 |
return ;
|
|
|
324 |
}
|
|
|
325 |
|
|
|
326 |
|
|
|
327 |
/*
|
|
|
328 |
READ AN EXPRESSION COMPILATION CONDITION
|
|
|
329 |
|
|
|
330 |
This routine reads the constant expression following a '#if' or '#elif'
|
|
|
331 |
preprocessing directive. It returns a value indicating whether the
|
|
|
332 |
expression is zero or nonzero. The argument act is false to indicate
|
|
|
333 |
that the directive is being skipped. The expression consists of all
|
|
|
334 |
the preprocessing tokens in the rest of the directive with any
|
|
|
335 |
defined operations suitably expanded. This is then macro expanded
|
|
|
336 |
and finally has any remaining identifiers replaced by 0. All the
|
|
|
337 |
parsing is done using this list of tokens - no other tokens are read
|
|
|
338 |
from the input file (the newline appended by read_line ensures that
|
|
|
339 |
the parser doesn't spill off the end).
|
|
|
340 |
*/
|
|
|
341 |
|
|
|
342 |
static unsigned read_if_exp
|
|
|
343 |
PROTO_N ( ( act, dir ) )
|
|
|
344 |
PROTO_T ( int act X int dir )
|
|
|
345 |
{
|
|
|
346 |
EXP e = NULL_exp ;
|
|
|
347 |
unsigned cond = PP_SKIP ;
|
|
|
348 |
if ( act ) {
|
|
|
349 |
/* Read the rest of the line */
|
|
|
350 |
PARSE_STATE ps ;
|
|
|
351 |
HASHID def = KEYWORD ( lex_defined ) ;
|
|
|
352 |
PPTOKEN *p = read_line ( lex_ignore_token, lex_newline ) ;
|
|
|
353 |
PPTOKEN *q = p ;
|
|
|
354 |
|
|
|
355 |
/* Scan line for defined operations and assertions */
|
|
|
356 |
while ( q != NULL ) {
|
|
|
357 |
int t = q->tok ;
|
|
|
358 |
|
|
|
359 |
if ( t == lex_identifier &&
|
|
|
360 |
EQ_hashid ( q->pp_data.id.hash, def ) ) {
|
|
|
361 |
/* Deal with 'defined' */
|
|
|
362 |
PPTOKEN *r = q->next ;
|
|
|
363 |
/* Because of final newline don't need to check r != NULL */
|
|
|
364 |
t = r->tok ;
|
|
|
365 |
if ( t == lex_identifier ) {
|
|
|
366 |
/* Operation of the form 'defined id' */
|
|
|
367 |
HASHID macro = r->pp_data.id.hash ;
|
|
|
368 |
unsigned c = check_macro ( macro, 1 ) ;
|
|
|
369 |
c &= PP_COND_MASK ;
|
|
|
370 |
if ( c == PP_UNRESOLVED ) {
|
|
|
371 |
q->tok = lex_defined ;
|
|
|
372 |
cond = PP_UNRESOLVED ;
|
|
|
373 |
} else {
|
|
|
374 |
q->tok = lex_integer_Hlit ;
|
|
|
375 |
q->pp_data.text = ustrlit ( c ? "1" : "0" ) ;
|
|
|
376 |
q->next = r->next ;
|
|
|
377 |
r->next = NULL ;
|
|
|
378 |
free_tok_list ( r ) ;
|
|
|
379 |
}
|
|
|
380 |
|
|
|
381 |
} else if ( t == lex_open_Hround &&
|
|
|
382 |
r->next->tok == lex_identifier &&
|
|
|
383 |
r->next->next->tok == lex_close_Hround ) {
|
|
|
384 |
/* Operation of the form 'defined ( id )' */
|
|
|
385 |
HASHID macro = r->next->pp_data.id.hash ;
|
|
|
386 |
unsigned c = check_macro ( macro, 1 ) ;
|
|
|
387 |
c &= PP_COND_MASK ;
|
|
|
388 |
if ( c == PP_UNRESOLVED ) {
|
|
|
389 |
q->tok = lex_defined ;
|
|
|
390 |
cond = PP_UNRESOLVED ;
|
|
|
391 |
} else {
|
|
|
392 |
q->tok = lex_integer_Hlit ;
|
|
|
393 |
q->pp_data.text = ustrlit ( c ? "1" : "0" ) ;
|
|
|
394 |
q->next = r->next->next->next ;
|
|
|
395 |
r->next->next->next = NULL ;
|
|
|
396 |
free_tok_list ( r ) ;
|
|
|
397 |
}
|
|
|
398 |
|
|
|
399 |
} else {
|
|
|
400 |
/* Badly formed 'defined' operation */
|
|
|
401 |
report ( preproc_loc, ERR_cpp_cond_def_id () ) ;
|
|
|
402 |
}
|
|
|
403 |
|
|
|
404 |
} else if ( ( t == lex_hash_H1 || t == lex_hash_H2 ) &&
|
|
|
405 |
q->next->tok == lex_identifier ) {
|
|
|
406 |
/* Deal with '#predicate' */
|
|
|
407 |
CONST char *c = "0" ;
|
|
|
408 |
PPTOKEN *r = q->next ;
|
|
|
409 |
HASHID pred = r->pp_data.id.hash ;
|
|
|
410 |
if ( t == lex_hash_H2 ) IGNORE get_digraph ( t ) ;
|
|
|
411 |
if ( r->next->tok == lex_open_Hround ) {
|
|
|
412 |
/* Check for a particular predicate */
|
|
|
413 |
PPTOKEN *s = r->next->next ;
|
|
|
414 |
q->next = skip_predicate ( &s, dir ) ;
|
|
|
415 |
if ( check_assert ( pred, s, 0 ) ) c = "1" ;
|
|
|
416 |
} else {
|
|
|
417 |
/* Check for any predicate */
|
|
|
418 |
if ( check_assert ( pred, r, 1 ) ) c = "1" ;
|
|
|
419 |
q->next = r->next ;
|
|
|
420 |
r->next = NULL ;
|
|
|
421 |
}
|
|
|
422 |
free_tok_list ( r ) ;
|
|
|
423 |
q->tok = lex_integer_Hlit ;
|
|
|
424 |
q->pp_data.text = ustrlit ( c ) ;
|
|
|
425 |
}
|
|
|
426 |
q = q->next ;
|
|
|
427 |
}
|
|
|
428 |
|
|
|
429 |
/* Macro expand the line */
|
|
|
430 |
q = expand_tok_list ( p ) ;
|
|
|
431 |
free_tok_list ( p ) ;
|
|
|
432 |
p = q ;
|
|
|
433 |
|
|
|
434 |
/* Check for any remaining identifiers */
|
|
|
435 |
while ( q != NULL ) {
|
|
|
436 |
if ( q->tok == lex_identifier ) {
|
|
|
437 |
HASHID nm = q->pp_data.id.hash ;
|
|
|
438 |
IDENTIFIER id = DEREF_id ( hashid_id ( nm ) ) ;
|
|
|
439 |
unsigned tag = TAG_id ( id ) ;
|
|
|
440 |
if ( tag == id_obj_macro_tag || tag == id_func_macro_tag ) {
|
|
|
441 |
/* Allow for unexpanded macros */
|
|
|
442 |
id = DEREF_id ( id_alias ( id ) ) ;
|
|
|
443 |
tag = TAG_id ( id ) ;
|
|
|
444 |
}
|
|
|
445 |
if ( tag == id_keyword_tag ) {
|
|
|
446 |
int u = ( int ) DEREF_ulong ( id_no ( id ) ) ;
|
|
|
447 |
if ( u == lex_true || u == lex_false ) {
|
|
|
448 |
/* Preserve boolean literals */
|
|
|
449 |
tag = id_iso_keyword_tag ;
|
|
|
450 |
}
|
|
|
451 |
}
|
|
|
452 |
if ( tag == id_iso_keyword_tag ) {
|
|
|
453 |
/* Allow for ISO keywords */
|
|
|
454 |
int u = ( int ) DEREF_ulong ( id_no ( id ) ) ;
|
|
|
455 |
int v = primary_form ( u ) ;
|
|
|
456 |
if ( v != u ) {
|
|
|
457 |
ERROR err = ERR_lex_digraph_iso ( nm, v ) ;
|
|
|
458 |
report ( preproc_loc, err ) ;
|
|
|
459 |
}
|
|
|
460 |
q->tok = v ;
|
|
|
461 |
} else {
|
|
|
462 |
unsigned c = check_macro ( nm, 0 ) ;
|
|
|
463 |
if ( c & PP_TOKEN ) {
|
|
|
464 |
/* Preserve token identifiers */
|
|
|
465 |
c &= PP_COND_MASK ;
|
|
|
466 |
if ( c == PP_UNRESOLVED ) {
|
|
|
467 |
cond = PP_UNRESOLVED ;
|
|
|
468 |
}
|
|
|
469 |
} else {
|
|
|
470 |
/* Replace other identifiers by 0 */
|
|
|
471 |
ERROR err ;
|
|
|
472 |
if ( EQ_hashid ( nm, def ) ) {
|
|
|
473 |
/* Shouldn't have defined */
|
|
|
474 |
err = ERR_cpp_cond_def_replace () ;
|
|
|
475 |
if ( !IS_NULL_err ( err ) ) {
|
|
|
476 |
report ( preproc_loc, err ) ;
|
|
|
477 |
}
|
|
|
478 |
}
|
|
|
479 |
/* QUERY: what about true and false? */
|
|
|
480 |
err = ERR_cpp_cond_zero ( nm ) ;
|
|
|
481 |
if ( !IS_NULL_err ( err ) ) {
|
|
|
482 |
report ( preproc_loc, err ) ;
|
|
|
483 |
}
|
|
|
484 |
q->tok = lex_integer_Hlit ;
|
|
|
485 |
q->pp_data.text = ustrlit ( "0" ) ;
|
|
|
486 |
}
|
|
|
487 |
}
|
|
|
488 |
}
|
|
|
489 |
q = q->next ;
|
|
|
490 |
}
|
|
|
491 |
|
|
|
492 |
/* Parse the line for a constant expression */
|
|
|
493 |
save_state ( &ps, 0 ) ;
|
|
|
494 |
init_parser ( p ) ;
|
|
|
495 |
in_hash_if_exp++ ;
|
|
|
496 |
crt_loc = preproc_loc ;
|
|
|
497 |
crt_line_changed = 1 ;
|
|
|
498 |
ADVANCE_LEXER ;
|
|
|
499 |
if ( cond == PP_UNRESOLVED ) {
|
|
|
500 |
/* Unresolved tokens when preprocessing */
|
|
|
501 |
ASSERT ( preproc_only ) ;
|
|
|
502 |
/* EMPTY */
|
|
|
503 |
} else {
|
|
|
504 |
/* Parse condition */
|
|
|
505 |
cond = PP_FALSE ;
|
|
|
506 |
parse_nat ( &e ) ;
|
|
|
507 |
if ( crt_lex_token != lex_newline && !have_syntax_error ) {
|
|
|
508 |
/* Should have reached the end of the line */
|
|
|
509 |
ERROR err = ERR_lex_parse ( crt_token ) ;
|
|
|
510 |
err = concat_error ( err, ERR_cpp_end ( dir ) ) ;
|
|
|
511 |
report ( preproc_loc, err ) ;
|
|
|
512 |
}
|
|
|
513 |
}
|
|
|
514 |
restore_state ( &ps ) ;
|
|
|
515 |
|
|
|
516 |
/* Check the result expression */
|
|
|
517 |
if ( !IS_NULL_exp ( e ) ) {
|
|
|
518 |
/* Evaluate the expression */
|
|
|
519 |
ERROR err = NULL_err ;
|
|
|
520 |
IGNORE make_nat_exp ( e, &err ) ;
|
|
|
521 |
e = convert_boolean ( e, exp_paren_tag, &err ) ;
|
|
|
522 |
if ( !IS_NULL_err ( err ) ) {
|
|
|
523 |
err = concat_error ( err, ERR_cpp_cond_if_const ( dir ) ) ;
|
|
|
524 |
report ( preproc_loc, err ) ;
|
|
|
525 |
cond = PP_FALSE ;
|
|
|
526 |
} else {
|
|
|
527 |
unsigned b = eval_const_cond ( e ) ;
|
|
|
528 |
if ( b == BOOL_TRUE ) {
|
|
|
529 |
cond = PP_TRUE ;
|
|
|
530 |
} else if ( b == BOOL_FALSE ) {
|
|
|
531 |
cond = PP_FALSE ;
|
|
|
532 |
} else {
|
|
|
533 |
cond = PP_UNRESOLVED ;
|
|
|
534 |
}
|
|
|
535 |
}
|
|
|
536 |
}
|
|
|
537 |
|
|
|
538 |
/* Restore the parser */
|
|
|
539 |
p = restore_parser () ;
|
|
|
540 |
if ( cond == PP_UNRESOLVED ) {
|
|
|
541 |
/* Save target dependent conditions */
|
|
|
542 |
if ( preproc_only ) {
|
|
|
543 |
/* Patch crt_token with tokens comprising condition */
|
|
|
544 |
p = clean_tok_list ( p ) ;
|
|
|
545 |
patch_preproc_dir ( p ) ;
|
|
|
546 |
p = NULL ;
|
|
|
547 |
} else {
|
|
|
548 |
/* Store condition in crt_hash_if_exp */
|
|
|
549 |
report ( preproc_loc, ERR_cpp_cond_if_ti ( dir ) ) ;
|
|
|
550 |
crt_hash_if_exp = e ;
|
|
|
551 |
}
|
|
|
552 |
}
|
|
|
553 |
free_tok_list ( p ) ;
|
|
|
554 |
in_hash_if_exp-- ;
|
|
|
555 |
}
|
|
|
556 |
if ( in_preproc_dir ) IGNORE skip_to_end () ;
|
|
|
557 |
return ( cond ) ;
|
|
|
558 |
}
|
|
|
559 |
|
|
|
560 |
|
|
|
561 |
/*
|
|
|
562 |
READ A DEFINED COMPILATION CONDITION
|
|
|
563 |
|
|
|
564 |
This routine reads the macro identifier following a '#ifdef' or
|
|
|
565 |
'#ifndef' preprocessing directive. It returns a value indicating
|
|
|
566 |
whether the macro is defined or not. The argument act is false to
|
|
|
567 |
indicate that the directive is being skipped, prev is as in
|
|
|
568 |
read_preproc_dir.
|
|
|
569 |
*/
|
|
|
570 |
|
|
|
571 |
static unsigned read_if_def
|
|
|
572 |
PROTO_N ( ( act, dir, prev ) )
|
|
|
573 |
PROTO_T ( int act X int dir X int prev )
|
|
|
574 |
{
|
|
|
575 |
unsigned cond ;
|
|
|
576 |
if ( act ) {
|
|
|
577 |
int t = read_token () ;
|
|
|
578 |
update_column () ;
|
|
|
579 |
if ( in_preproc_dir ) preproc_loc = crt_loc ;
|
|
|
580 |
if ( t == lex_identifier ) {
|
|
|
581 |
HASHID macro = token_hashid ;
|
|
|
582 |
cond = check_macro ( macro, 1 ) ;
|
|
|
583 |
cond &= PP_COND_MASK ;
|
|
|
584 |
if ( prev == lex_included ) {
|
|
|
585 |
/* Protection macro begins '#ifndef macro' */
|
|
|
586 |
protection_macro ( macro, prev, dir ) ;
|
|
|
587 |
}
|
|
|
588 |
if ( in_preproc_dir && skip_to_end () ) {
|
|
|
589 |
report ( preproc_loc, ERR_cpp_end ( dir ) ) ;
|
|
|
590 |
}
|
|
|
591 |
} else {
|
|
|
592 |
report ( preproc_loc, ERR_cpp_cond_ifdef_id ( dir ) ) ;
|
|
|
593 |
cond = PP_FALSE ;
|
|
|
594 |
}
|
|
|
595 |
} else {
|
|
|
596 |
cond = PP_SKIP ;
|
|
|
597 |
}
|
|
|
598 |
if ( in_preproc_dir ) IGNORE skip_to_end () ;
|
|
|
599 |
return ( cond ) ;
|
|
|
600 |
}
|
|
|
601 |
|
|
|
602 |
|
|
|
603 |
/*
|
|
|
604 |
DEAL WITH CONDITIONAL COMPILATIONS
|
|
|
605 |
|
|
|
606 |
This routine deals with the various conditional compilation preprocessing
|
|
|
607 |
directives. dir gives the directive identifier and c indicates the
|
|
|
608 |
associated condition. The skipping of unused code is incorporated into
|
|
|
609 |
this routine. The routine returns lex_ignore_token for simple '#if' and
|
|
|
610 |
'#elif' directives, lex_end_condition for simple '#else' and '#endif'
|
|
|
611 |
directives, and one of the values lex_hash_Hif, lex_hash_Helif,
|
|
|
612 |
lex_hash_Helse and lex_hash_Hendif for target dependent conditions.
|
|
|
613 |
*/
|
|
|
614 |
|
|
|
615 |
static int read_if
|
|
|
616 |
PROTO_N ( ( dir, c, prev ) )
|
|
|
617 |
PROTO_T ( int dir X unsigned c X int prev )
|
|
|
618 |
{
|
|
|
619 |
unsigned cond = c ;
|
|
|
620 |
int ret = lex_ignore_token ;
|
|
|
621 |
|
|
|
622 |
if ( dir == lex_if || dir == lex_ifdef || dir == lex_ifndef ) {
|
|
|
623 |
/* Deal with '#if', '#ifdef' and '#ifndef' */
|
|
|
624 |
if ( cond == PP_UNRESOLVED ) ret = lex_hash_Hif ;
|
|
|
625 |
if ( prev != lex_included && preproc_depth == 0 ) {
|
|
|
626 |
/* Can't have second '#if' in protection macro */
|
|
|
627 |
protection_macro ( NULL_hashid, lex_ignore_token, dir ) ;
|
|
|
628 |
}
|
|
|
629 |
PUSH_unsigned ( cond, preproc_stack ) ;
|
|
|
630 |
PUSH_loc ( preproc_loc, loc_stack ) ;
|
|
|
631 |
IGNORE incr_value ( OPT_VAL_hash_if_depth ) ;
|
|
|
632 |
preproc_depth++ ;
|
|
|
633 |
|
|
|
634 |
} else {
|
|
|
635 |
/* Get current condition for other directives */
|
|
|
636 |
LOCATION loc ;
|
|
|
637 |
unsigned crt_cond ;
|
|
|
638 |
POP_unsigned ( cond, preproc_stack ) ;
|
|
|
639 |
decr_value ( OPT_VAL_hash_if_depth ) ;
|
|
|
640 |
preproc_depth-- ;
|
|
|
641 |
/* Don't pop location yet */
|
|
|
642 |
if ( cond == PP_END ) {
|
|
|
643 |
/* No matching '#if' */
|
|
|
644 |
ERROR err = ERR_cpp_cond_if_match ( dir, lex_if ) ;
|
|
|
645 |
report ( preproc_loc, err ) ;
|
|
|
646 |
PUSH_unsigned ( cond, preproc_stack ) ;
|
|
|
647 |
PUSH_loc ( preproc_loc, loc_stack ) ;
|
|
|
648 |
IGNORE incr_value ( OPT_VAL_hash_if_depth ) ;
|
|
|
649 |
preproc_depth++ ;
|
|
|
650 |
cond = c ;
|
|
|
651 |
}
|
|
|
652 |
crt_cond = ( cond & PP_COND_MASK ) ;
|
|
|
653 |
ret = lex_end_condition ;
|
|
|
654 |
|
|
|
655 |
if ( dir == lex_endif ) {
|
|
|
656 |
/* Deal with '#endif' */
|
|
|
657 |
if ( crt_cond == PP_UNRESOLVED ) {
|
|
|
658 |
ret = lex_hash_Hendif ;
|
|
|
659 |
cond = PP_TRUE ;
|
|
|
660 |
} else if ( crt_cond == PP_SKIP ) {
|
|
|
661 |
cond = PP_SKIP ;
|
|
|
662 |
} else {
|
|
|
663 |
cond = PP_TRUE ;
|
|
|
664 |
}
|
|
|
665 |
POP_loc ( loc, loc_stack ) ;
|
|
|
666 |
UNUSED ( loc ) ;
|
|
|
667 |
|
|
|
668 |
} else if ( dir == lex_else ) {
|
|
|
669 |
/* Deal with '#else' */
|
|
|
670 |
PTR ( LOCATION ) ploc ;
|
|
|
671 |
ploc = HEAD_list ( LIST_stack ( loc_stack ) ) ;
|
|
|
672 |
if ( cond & PP_HAVE_ELSE ) {
|
|
|
673 |
/* Duplicate '#else' directives */
|
|
|
674 |
ERROR err = ERR_cpp_cond_else_dup ( dir, dir, ploc ) ;
|
|
|
675 |
report ( preproc_loc, err ) ;
|
|
|
676 |
}
|
|
|
677 |
if ( crt_cond == PP_UNRESOLVED ) ret = lex_hash_Helse ;
|
|
|
678 |
cond = ( negate_cond ( crt_cond ) | PP_HAVE_ELSE ) ;
|
|
|
679 |
PUSH_unsigned ( cond, preproc_stack ) ;
|
|
|
680 |
COPY_loc ( ploc, preproc_loc ) ;
|
|
|
681 |
if ( preproc_depth == 0 ) {
|
|
|
682 |
/* Can't have '#else' in protection macro */
|
|
|
683 |
protection_macro ( NULL_hashid, lex_ignore_token, dir ) ;
|
|
|
684 |
}
|
|
|
685 |
IGNORE incr_value ( OPT_VAL_hash_if_depth ) ;
|
|
|
686 |
preproc_depth++ ;
|
|
|
687 |
|
|
|
688 |
} else {
|
|
|
689 |
/* Deal with '#elif' (fairly tricky) */
|
|
|
690 |
unsigned new_cond ;
|
|
|
691 |
PTR ( LOCATION ) ploc ;
|
|
|
692 |
ploc = HEAD_list ( LIST_stack ( loc_stack ) ) ;
|
|
|
693 |
if ( cond & PP_HAVE_ELSE ) {
|
|
|
694 |
/* '#elif' after '#else' */
|
|
|
695 |
ERROR err = ERR_cpp_cond_else_dup ( dir, lex_else, ploc ) ;
|
|
|
696 |
report ( preproc_loc, err ) ;
|
|
|
697 |
}
|
|
|
698 |
if ( crt_cond == PP_TRUE || crt_cond == PP_PAST ) {
|
|
|
699 |
/* A previous '#if' or '#elif' was true */
|
|
|
700 |
ret = lex_ignore_token ;
|
|
|
701 |
IGNORE read_if_exp ( 0, dir ) ;
|
|
|
702 |
c = PP_PAST ;
|
|
|
703 |
new_cond = ( c | PP_HAVE_ELIF ) ;
|
|
|
704 |
} else if ( crt_cond == PP_FALSE ) {
|
|
|
705 |
/* All previous '#if's and '#elif's were false */
|
|
|
706 |
c = read_if_exp ( 1, dir ) ;
|
|
|
707 |
if ( c == PP_UNRESOLVED ) ret = lex_hash_Hif ;
|
|
|
708 |
new_cond = ( c | PP_HAVE_ELIF ) ;
|
|
|
709 |
} else if ( crt_cond == PP_UNRESOLVED ) {
|
|
|
710 |
/* Unresolved existing condition */
|
|
|
711 |
c = read_if_exp ( 1, dir ) ;
|
|
|
712 |
if ( c == PP_FALSE ) {
|
|
|
713 |
/* Overall condition is still unresolved */
|
|
|
714 |
ret = lex_ignore_token ;
|
|
|
715 |
new_cond = ( crt_cond | PP_HAVE_ELIF ) ;
|
|
|
716 |
} else if ( c == PP_TRUE ) {
|
|
|
717 |
/* This terminates the conditional */
|
|
|
718 |
ret = lex_hash_Hendif ;
|
|
|
719 |
new_cond = ( c | PP_HAVE_ELIF ) ;
|
|
|
720 |
} else {
|
|
|
721 |
/* A second unresolved condition */
|
|
|
722 |
ret = lex_hash_Helif ;
|
|
|
723 |
new_cond = ( c | PP_HAVE_ELIF ) ;
|
|
|
724 |
}
|
|
|
725 |
} else {
|
|
|
726 |
/* Skip this directive */
|
|
|
727 |
ret = lex_ignore_token ;
|
|
|
728 |
c = read_if_exp ( 0, dir ) ;
|
|
|
729 |
new_cond = ( c | PP_HAVE_ELIF ) ;
|
|
|
730 |
}
|
|
|
731 |
PUSH_unsigned ( new_cond, preproc_stack ) ;
|
|
|
732 |
COPY_loc ( ploc, preproc_loc ) ;
|
|
|
733 |
if ( preproc_depth == 0 ) {
|
|
|
734 |
/* Can't have '#elif' in protection macro */
|
|
|
735 |
protection_macro ( NULL_hashid, lex_ignore_token, dir ) ;
|
|
|
736 |
}
|
|
|
737 |
IGNORE incr_value ( OPT_VAL_hash_if_depth ) ;
|
|
|
738 |
preproc_depth++ ;
|
|
|
739 |
cond = c ;
|
|
|
740 |
}
|
|
|
741 |
}
|
|
|
742 |
ASSERT ( !in_preproc_dir ) ;
|
|
|
743 |
|
|
|
744 |
/* Step over any unused code */
|
|
|
745 |
cond &= PP_COND_MASK ;
|
|
|
746 |
if ( cond == PP_FALSE || cond == PP_PAST || cond == PP_SKIP ) {
|
|
|
747 |
for ( ; ; ) {
|
|
|
748 |
int t ;
|
|
|
749 |
unsigned long sp = skip_white ( 1 ) ;
|
|
|
750 |
in_preproc_dir = 1 ;
|
|
|
751 |
t = read_token () ;
|
|
|
752 |
update_column () ;
|
|
|
753 |
if ( in_preproc_dir ) preproc_loc = crt_loc ;
|
|
|
754 |
if ( t == lex_hash_H2 ) t = get_digraph ( t ) ;
|
|
|
755 |
if ( t == lex_hash_H1 ) {
|
|
|
756 |
/* Scan any nested preprocessing directives */
|
|
|
757 |
int p ;
|
|
|
758 |
unsigned long sp2 = skip_white ( 0 ) ;
|
|
|
759 |
update_column () ;
|
|
|
760 |
p = read_preproc_dir ( 0, lex_ignore_token ) ;
|
|
|
761 |
switch ( p ) {
|
|
|
762 |
case lex_hash_Hif :
|
|
|
763 |
case lex_hash_Helif :
|
|
|
764 |
case lex_hash_Helse :
|
|
|
765 |
case lex_hash_Hendif :
|
|
|
766 |
case lex_end_condition : {
|
|
|
767 |
/* These terminate the current condition */
|
|
|
768 |
if ( sp & ( WHITE_SPACE | WHITE_ESC_NEWLINE ) ) {
|
|
|
769 |
report ( preproc_loc, ERR_cpp_indent () ) ;
|
|
|
770 |
}
|
|
|
771 |
if ( sp2 & ( WHITE_SPACE | WHITE_ESC_NEWLINE ) ) {
|
|
|
772 |
report ( preproc_loc, ERR_cpp_indent_dir () ) ;
|
|
|
773 |
}
|
|
|
774 |
in_preproc_dir = 0 ;
|
|
|
775 |
return ( p ) ;
|
|
|
776 |
}
|
|
|
777 |
}
|
|
|
778 |
} else if ( t == lex_eof ) {
|
|
|
779 |
if ( sp & ( WHITE_SPACE | WHITE_ESC_NEWLINE ) ) {
|
|
|
780 |
report ( crt_loc, ERR_lex_phases_eof () ) ;
|
|
|
781 |
}
|
|
|
782 |
break ;
|
|
|
783 |
} else {
|
|
|
784 |
if ( in_preproc_dir ) IGNORE skip_to_end () ;
|
|
|
785 |
}
|
|
|
786 |
}
|
|
|
787 |
}
|
|
|
788 |
in_preproc_dir = 0 ;
|
|
|
789 |
return ( ret ) ;
|
|
|
790 |
}
|
|
|
791 |
|
|
|
792 |
|
|
|
793 |
/*
|
|
|
794 |
PATCH TARGET DEPENDENT CONDITIONALS
|
|
|
795 |
|
|
|
796 |
Any list of statements in a target dependent conditional are treated
|
|
|
797 |
as if they comprised a compound statement. In particular any variables
|
|
|
798 |
declared within the conditional are only in scope inside that condition.
|
|
|
799 |
The neatest way to do this is for the preprocessor to patch the necessary
|
|
|
800 |
open and close braces into the parser input. This is the purpose of
|
|
|
801 |
this routine.
|
|
|
802 |
*/
|
|
|
803 |
|
|
|
804 |
int patch_cond
|
|
|
805 |
PROTO_N ( ( t, dir ) )
|
|
|
806 |
PROTO_T ( int t X int dir )
|
|
|
807 |
{
|
|
|
808 |
HASHID nm ;
|
|
|
809 |
PPTOKEN *p ;
|
|
|
810 |
IDENTIFIER id ;
|
|
|
811 |
|
|
|
812 |
/* Compilation action */
|
|
|
813 |
if ( !preproc_only ) {
|
|
|
814 |
switch ( t ) {
|
|
|
815 |
case lex_hash_Hif : {
|
|
|
816 |
/* Create '#if {' */
|
|
|
817 |
p = patch_tokens ( 1 ) ;
|
|
|
818 |
p->tok = lex_open_Hbrace_H1 ;
|
|
|
819 |
break ;
|
|
|
820 |
}
|
|
|
821 |
case lex_hash_Helif :
|
|
|
822 |
case lex_hash_Helse : {
|
|
|
823 |
/* Create '} #elif {' and '} #else {' */
|
|
|
824 |
p = patch_tokens ( 2 ) ;
|
|
|
825 |
p->tok = t ;
|
|
|
826 |
token_parts ( t, p ) ;
|
|
|
827 |
p->next->tok = lex_open_Hbrace_H1 ;
|
|
|
828 |
t = lex_close_Hbrace_H1 ;
|
|
|
829 |
break ;
|
|
|
830 |
}
|
|
|
831 |
case lex_hash_Hendif : {
|
|
|
832 |
/* Create '} #endif' */
|
|
|
833 |
p = patch_tokens ( 1 ) ;
|
|
|
834 |
p->tok = t ;
|
|
|
835 |
t = lex_close_Hbrace_H1 ;
|
|
|
836 |
break ;
|
|
|
837 |
}
|
|
|
838 |
}
|
|
|
839 |
return ( t ) ;
|
|
|
840 |
}
|
|
|
841 |
|
|
|
842 |
/* Preprocessing action */
|
|
|
843 |
id = token_macro ;
|
|
|
844 |
if ( IS_NULL_id ( id ) ) return ( t ) ;
|
|
|
845 |
nm = DEREF_hashid ( id_name ( id ) ) ;
|
|
|
846 |
switch ( t ) {
|
|
|
847 |
|
|
|
848 |
case lex_hash_Hif : {
|
|
|
849 |
if ( dir == lex_ifdef ) {
|
|
|
850 |
/* Create '#if defined x' */
|
|
|
851 |
p = patch_tokens ( 2 ) ;
|
|
|
852 |
p->tok = lex_identifier ,
|
|
|
853 |
p->pp_data.id.hash = KEYWORD ( lex_defined ) ;
|
|
|
854 |
p->next->tok = lex_identifier ,
|
|
|
855 |
p->next->pp_data.id.hash = nm ;
|
|
|
856 |
p->next->pp_data.id.use = id ;
|
|
|
857 |
} else if ( dir == lex_ifndef ) {
|
|
|
858 |
/* Create '#if !defined x' */
|
|
|
859 |
p = patch_tokens ( 3 ) ;
|
|
|
860 |
p->tok = lex_not_H1 ;
|
|
|
861 |
p->next->tok = lex_identifier ,
|
|
|
862 |
p->next->pp_data.id.hash = KEYWORD ( lex_defined ) ;
|
|
|
863 |
p->next->pp_space = 0 ;
|
|
|
864 |
p->next->next->tok = lex_identifier ,
|
|
|
865 |
p->next->next->pp_data.id.hash = nm ;
|
|
|
866 |
p->next->next->pp_data.id.use = id ;
|
|
|
867 |
}
|
|
|
868 |
break ;
|
|
|
869 |
}
|
|
|
870 |
|
|
|
871 |
case lex_hash_Hop : {
|
|
|
872 |
/* Create '#define x ...' or '#undef x' */
|
|
|
873 |
if ( dir == lex_define ) {
|
|
|
874 |
/* Patch in macro definition */
|
|
|
875 |
PPTOKEN *q = NULL ;
|
|
|
876 |
unsigned tag = TAG_id ( id ) ;
|
|
|
877 |
if ( tag == id_obj_macro_tag ) {
|
|
|
878 |
q = DEREF_pptok ( id_obj_macro_defn ( id ) ) ;
|
|
|
879 |
} else if ( tag == id_func_macro_tag ) {
|
|
|
880 |
q = DEREF_pptok ( id_func_macro_defn ( id ) ) ;
|
|
|
881 |
}
|
|
|
882 |
q = expand_tok_list ( q ) ;
|
|
|
883 |
q = clean_tok_list ( q ) ;
|
|
|
884 |
patch_preproc_dir ( q ) ;
|
|
|
885 |
if ( tag == id_func_macro_tag ) {
|
|
|
886 |
unsigned n ;
|
|
|
887 |
LIST ( HASHID ) pars ;
|
|
|
888 |
pars = DEREF_list ( id_func_macro_params ( id ) ) ;
|
|
|
889 |
n = DEREF_unsigned ( id_func_macro_no_params ( id ) ) ;
|
|
|
890 |
p = patch_tokens ( ( int ) ( 2 * n + 2 ) ) ;
|
|
|
891 |
p->tok = lex_open_Hround ;
|
|
|
892 |
p->pp_space = 0 ;
|
|
|
893 |
p->next->tok = lex_close_Hround ;
|
|
|
894 |
p->next->pp_space = 0 ;
|
|
|
895 |
while ( !IS_NULL_list ( pars ) ) {
|
|
|
896 |
HASHID par = DEREF_hashid ( HEAD_list ( pars ) ) ;
|
|
|
897 |
pars = TAIL_list ( pars ) ;
|
|
|
898 |
p = p->next ;
|
|
|
899 |
p->tok = lex_identifier ;
|
|
|
900 |
p->pp_data.id.hash = par ;
|
|
|
901 |
p->pp_space = WHITE_SPACE ;
|
|
|
902 |
p = p->next ;
|
|
|
903 |
if ( IS_NULL_list ( pars ) ) {
|
|
|
904 |
p->tok = lex_close_Hround ;
|
|
|
905 |
p->pp_space = WHITE_SPACE ;
|
|
|
906 |
} else {
|
|
|
907 |
p->tok = lex_comma ;
|
|
|
908 |
p->pp_space = 0 ;
|
|
|
909 |
}
|
|
|
910 |
}
|
|
|
911 |
}
|
|
|
912 |
}
|
|
|
913 |
p = patch_tokens ( 2 ) ;
|
|
|
914 |
p->tok = lex_identifier ;
|
|
|
915 |
p->pp_data.id.hash = KEYWORD ( dir ) ;
|
|
|
916 |
p->pp_space = 0 ;
|
|
|
917 |
p->next->tok = lex_identifier ,
|
|
|
918 |
p->next->pp_data.id.hash = nm ;
|
|
|
919 |
p->next->pp_data.id.use = id ;
|
|
|
920 |
break ;
|
|
|
921 |
}
|
|
|
922 |
}
|
|
|
923 |
return ( t ) ;
|
|
|
924 |
}
|
|
|
925 |
|
|
|
926 |
|
|
|
927 |
/*
|
|
|
928 |
READ AN INCLUDE DIRECTIVE
|
|
|
929 |
|
|
|
930 |
This routine processes a '#include' or similar directive. This consists
|
|
|
931 |
of just a header name or a sequence of tokens which expand to a header
|
|
|
932 |
name. If act is true then the actual inclusion is initialised.
|
|
|
933 |
The name of the preprocessing directive, dir, is passed in for the
|
|
|
934 |
purposes of error reporting. The routine returns lex_included to
|
|
|
935 |
indicate that control has passed to the new file.
|
|
|
936 |
*/
|
|
|
937 |
|
|
|
938 |
int read_include
|
|
|
939 |
PROTO_N ( ( act, dir ) )
|
|
|
940 |
PROTO_T ( int act X int dir )
|
|
|
941 |
{
|
|
|
942 |
int ret = lex_ignore_token ;
|
|
|
943 |
if ( act ) {
|
|
|
944 |
string s ;
|
|
|
945 |
character c ;
|
|
|
946 |
int end = 0 ;
|
|
|
947 |
int next = 0 ;
|
|
|
948 |
int legal = 1 ;
|
|
|
949 |
int import = 0 ;
|
|
|
950 |
character quote = 0 ;
|
|
|
951 |
|
|
|
952 |
/* Look ahead for start of header name */
|
|
|
953 |
if ( dir == lex_import ) import = 1 ;
|
|
|
954 |
if ( dir == lex_include_Hnext ) next = 1 ;
|
|
|
955 |
IGNORE skip_white ( 0 ) ;
|
|
|
956 |
if ( peek_char ( char_less, &legal ) ) {
|
|
|
957 |
quote = char_greater ;
|
|
|
958 |
} else if ( peek_char ( char_quote, &legal ) ) {
|
|
|
959 |
quote = char_quote ;
|
|
|
960 |
} else if ( dir == lex_pragma ) {
|
|
|
961 |
if ( peek_char ( char_open_square, &legal ) ) {
|
|
|
962 |
quote = char_close_square ;
|
|
|
963 |
next = 1 ;
|
|
|
964 |
}
|
|
|
965 |
}
|
|
|
966 |
update_column () ;
|
|
|
967 |
|
|
|
968 |
if ( quote ) {
|
|
|
969 |
/* Read simple header name */
|
|
|
970 |
int e = read_string ( ( int ) quote, 0 ) ;
|
|
|
971 |
if ( e != lex_eof ) {
|
|
|
972 |
if ( in_preproc_dir ) end = skip_to_end () ;
|
|
|
973 |
}
|
|
|
974 |
s = token_buff.start ;
|
|
|
975 |
} else {
|
|
|
976 |
/* Expand complex header name */
|
|
|
977 |
PPTOKEN *p = read_line ( lex_ignore_token, lex_ignore_token ) ;
|
|
|
978 |
PPTOKEN *q = expand_tok_list ( p ) ;
|
|
|
979 |
IGNORE quote_tok_list ( q, 0, char_quote ) ;
|
|
|
980 |
s = token_buff.start ;
|
|
|
981 |
|
|
|
982 |
/* Check first character */
|
|
|
983 |
c = s [0] ;
|
|
|
984 |
if ( c == char_less ) {
|
|
|
985 |
quote = char_greater ;
|
|
|
986 |
} else if ( c == char_quote ) {
|
|
|
987 |
quote = char_quote ;
|
|
|
988 |
} else if ( dir == lex_pragma && c == char_open_square ) {
|
|
|
989 |
quote = char_close_square ;
|
|
|
990 |
next = 1 ;
|
|
|
991 |
} else {
|
|
|
992 |
report ( preproc_loc, ERR_cpp_include_bad () ) ;
|
|
|
993 |
act = 0 ;
|
|
|
994 |
}
|
|
|
995 |
|
|
|
996 |
/* Scan header name */
|
|
|
997 |
if ( quote ) {
|
|
|
998 |
string t = ++s ;
|
|
|
999 |
for ( ; ; ) {
|
|
|
1000 |
if ( *t == quote ) {
|
|
|
1001 |
*t = 0 ;
|
|
|
1002 |
if ( t + 1 != token_buff.posn ) end = 1 ;
|
|
|
1003 |
break ;
|
|
|
1004 |
}
|
|
|
1005 |
if ( t == token_buff.posn ) {
|
|
|
1006 |
/* End of buffer reached */
|
|
|
1007 |
report ( preproc_loc, ERR_cpp_include_incompl () ) ;
|
|
|
1008 |
break ;
|
|
|
1009 |
}
|
|
|
1010 |
t++ ;
|
|
|
1011 |
}
|
|
|
1012 |
}
|
|
|
1013 |
free_tok_list ( p ) ;
|
|
|
1014 |
free_tok_list ( q ) ;
|
|
|
1015 |
}
|
|
|
1016 |
if ( end ) report ( preproc_loc, ERR_cpp_end ( dir ) ) ;
|
|
|
1017 |
in_preproc_dir = 0 ;
|
|
|
1018 |
if ( act ) {
|
|
|
1019 |
/* Check header name */
|
|
|
1020 |
string t = s ;
|
|
|
1021 |
while ( c = *( t++ ), c != 0 ) {
|
|
|
1022 |
if ( c == char_quote ||
|
|
|
1023 |
c == char_single_quote || c == char_backslash ||
|
|
|
1024 |
( c == char_slash && *t == char_asterix ) ||
|
|
|
1025 |
( c == char_slash && *t == char_slash ) ) {
|
|
|
1026 |
report ( preproc_loc, ERR_cpp_include_undef ( s ) ) ;
|
|
|
1027 |
break ;
|
|
|
1028 |
}
|
|
|
1029 |
}
|
|
|
1030 |
if ( start_include ( s, ( int ) quote, import, next ) ) {
|
|
|
1031 |
/* Control passed to new file */
|
|
|
1032 |
ret = lex_included ;
|
|
|
1033 |
}
|
|
|
1034 |
}
|
|
|
1035 |
} else {
|
|
|
1036 |
/* Ignore rest of line */
|
|
|
1037 |
if ( in_preproc_dir ) IGNORE skip_to_end () ;
|
|
|
1038 |
}
|
|
|
1039 |
return ( ret ) ;
|
|
|
1040 |
}
|
|
|
1041 |
|
|
|
1042 |
|
|
|
1043 |
/*
|
|
|
1044 |
CHECK THAT TWO PREPROCESSING TOKENS ARE EQUAL
|
|
|
1045 |
|
|
|
1046 |
This routine checks whether the lists of preprocessing tokens p and q
|
|
|
1047 |
are identical. It returns 2 if they are equal including preceeding
|
|
|
1048 |
white spaces, 1 if they are otherwise equal, and 0 otherwise.
|
|
|
1049 |
*/
|
|
|
1050 |
|
|
|
1051 |
static int eq_pptok
|
|
|
1052 |
PROTO_N ( ( p, q ) )
|
|
|
1053 |
PROTO_T ( PPTOKEN *p X PPTOKEN *q )
|
|
|
1054 |
{
|
|
|
1055 |
int eq = 2 ;
|
|
|
1056 |
while ( p && q ) {
|
|
|
1057 |
int t1 = p->tok ;
|
|
|
1058 |
int t2 = q->tok ;
|
|
|
1059 |
if ( t1 != t2 ) return ( 0 ) ;
|
|
|
1060 |
if ( p->pp_space != q->pp_space ) eq = 1 ;
|
|
|
1061 |
switch ( t1 ) {
|
|
|
1062 |
case lex_identifier : {
|
|
|
1063 |
/* Check identifiers */
|
|
|
1064 |
HASHID n1 = p->pp_data.id.hash ;
|
|
|
1065 |
HASHID n2 = q->pp_data.id.hash ;
|
|
|
1066 |
if ( !EQ_hashid ( n1, n2 ) ) return ( 0 ) ;
|
|
|
1067 |
break ;
|
|
|
1068 |
}
|
|
|
1069 |
case lex_integer_Hlit : {
|
|
|
1070 |
/* Check integer and floating-point literals */
|
|
|
1071 |
string s1 = p->pp_data.text ;
|
|
|
1072 |
string s2 = q->pp_data.text ;
|
|
|
1073 |
if ( !ustreq ( s1, s2 ) ) return ( 0 ) ;
|
|
|
1074 |
break ;
|
|
|
1075 |
}
|
|
|
1076 |
case lex_char_Hlit :
|
|
|
1077 |
case lex_string_Hlit :
|
|
|
1078 |
case lex_wchar_Hlit :
|
|
|
1079 |
case lex_wstring_Hlit : {
|
|
|
1080 |
/* Check string and characters literals */
|
|
|
1081 |
string s1 = p->pp_data.str.start ;
|
|
|
1082 |
string s2 = q->pp_data.str.start ;
|
|
|
1083 |
gen_size n1 = ( gen_size ) ( p->pp_data.str.end - s1 ) ;
|
|
|
1084 |
gen_size n2 = ( gen_size ) ( q->pp_data.str.end - s2 ) ;
|
|
|
1085 |
if ( n1 != n2 ) return ( 0 ) ;
|
|
|
1086 |
if ( xumemcmp ( s1, s2, n1 ) != 0 ) return ( 0 ) ;
|
|
|
1087 |
break ;
|
|
|
1088 |
}
|
|
|
1089 |
case lex_unknown : {
|
|
|
1090 |
/* Check unknown characters */
|
|
|
1091 |
string s1 = p->pp_data.buff ;
|
|
|
1092 |
string s2 = q->pp_data.buff ;
|
|
|
1093 |
gen_size n1 = MULTI_WIDTH ;
|
|
|
1094 |
if ( xumemcmp ( s1, s2, n1 ) != 0 ) return ( 0 ) ;
|
|
|
1095 |
break ;
|
|
|
1096 |
}
|
|
|
1097 |
case lex_macro_Harg : {
|
|
|
1098 |
/* Check macro parameter applications */
|
|
|
1099 |
unsigned long m1 = p->pp_data.par.no ;
|
|
|
1100 |
unsigned long m2 = q->pp_data.par.no ;
|
|
|
1101 |
if ( m1 != m2 ) return ( 0 ) ;
|
|
|
1102 |
break ;
|
|
|
1103 |
}
|
|
|
1104 |
}
|
|
|
1105 |
p = p->next ;
|
|
|
1106 |
q = q->next ;
|
|
|
1107 |
}
|
|
|
1108 |
if ( p || q ) return ( 0 ) ;
|
|
|
1109 |
return ( eq ) ;
|
|
|
1110 |
}
|
|
|
1111 |
|
|
|
1112 |
|
|
|
1113 |
/*
|
|
|
1114 |
CHECK CONSISTENCY OF TWO MACRO DEFINITIONS
|
|
|
1115 |
|
|
|
1116 |
This routine checks that a definition of the macro given by id_new is
|
|
|
1117 |
consistent with the previous definition, id_old. It returns an error
|
|
|
1118 |
message reporting on the level of consistency.
|
|
|
1119 |
*/
|
|
|
1120 |
|
|
|
1121 |
static ERROR check_macro_redef
|
|
|
1122 |
PROTO_N ( ( id_new, id_old ) )
|
|
|
1123 |
PROTO_T ( IDENTIFIER id_new X IDENTIFIER id_old )
|
|
|
1124 |
{
|
|
|
1125 |
int defn_ok ;
|
|
|
1126 |
int pars_ok = 1 ;
|
|
|
1127 |
ERROR err = NULL_err ;
|
|
|
1128 |
PTR ( LOCATION ) loc_old ;
|
|
|
1129 |
PPTOKEN *defn_new, *defn_old ;
|
|
|
1130 |
unsigned tag_new = TAG_id ( id_new ) ;
|
|
|
1131 |
unsigned tag_old = TAG_id ( id_old ) ;
|
|
|
1132 |
DECL_SPEC ds_old = DEREF_dspec ( id_storage ( id_old ) ) ;
|
|
|
1133 |
|
|
|
1134 |
/* Check on old macro definition */
|
|
|
1135 |
loc_old = id_loc ( id_old ) ;
|
|
|
1136 |
if ( ( ds_old & dspec_builtin ) && crt_file_type == 0 ) {
|
|
|
1137 |
/* Built-in macro redefined */
|
|
|
1138 |
err = ERR_cpp_predef_redef ( id_old ) ;
|
|
|
1139 |
}
|
|
|
1140 |
|
|
|
1141 |
/* Macro types must agree */
|
|
|
1142 |
if ( tag_new != tag_old ) {
|
|
|
1143 |
ERROR e = ERR_cpp_replace_redef_bad ( id_old, loc_old ) ;
|
|
|
1144 |
err = concat_error ( err, e ) ;
|
|
|
1145 |
return ( err ) ;
|
|
|
1146 |
}
|
|
|
1147 |
|
|
|
1148 |
if ( tag_new == id_obj_macro_tag ) {
|
|
|
1149 |
/* Find the definitions for object-like macros */
|
|
|
1150 |
defn_new = DEREF_pptok ( id_obj_macro_defn ( id_new ) ) ;
|
|
|
1151 |
defn_old = DEREF_pptok ( id_obj_macro_defn ( id_old ) ) ;
|
|
|
1152 |
|
|
|
1153 |
} else {
|
|
|
1154 |
/* Check parameter lists for function-like macros */
|
|
|
1155 |
unsigned no_pars_new, no_pars_old ;
|
|
|
1156 |
LIST ( HASHID ) pars_new, pars_old ;
|
|
|
1157 |
pars_new = DEREF_list ( id_func_macro_params ( id_new ) ) ;
|
|
|
1158 |
pars_old = DEREF_list ( id_func_macro_params ( id_old ) ) ;
|
|
|
1159 |
no_pars_new = DEREF_unsigned ( id_func_macro_no_params ( id_new ) ) ;
|
|
|
1160 |
no_pars_old = DEREF_unsigned ( id_func_macro_no_params ( id_old ) ) ;
|
|
|
1161 |
|
|
|
1162 |
if ( no_pars_new != no_pars_old ) {
|
|
|
1163 |
/* Number of parameters must match */
|
|
|
1164 |
ERROR e = ERR_cpp_replace_redef_bad ( id_old, loc_old ) ;
|
|
|
1165 |
err = concat_error ( err, e ) ;
|
|
|
1166 |
return ( err ) ;
|
|
|
1167 |
}
|
|
|
1168 |
|
|
|
1169 |
while ( !IS_NULL_list ( pars_new ) ) {
|
|
|
1170 |
/* Check that parameter names match */
|
|
|
1171 |
HASHID p_new = DEREF_hashid ( HEAD_list ( pars_new ) ) ;
|
|
|
1172 |
HASHID p_old = DEREF_hashid ( HEAD_list ( pars_old ) ) ;
|
|
|
1173 |
if ( !EQ_hashid ( p_new, p_old ) ) {
|
|
|
1174 |
/* Just clear pars_ok if they don't */
|
|
|
1175 |
pars_ok = 0 ;
|
|
|
1176 |
break ;
|
|
|
1177 |
}
|
|
|
1178 |
pars_new = TAIL_list ( pars_new ) ;
|
|
|
1179 |
pars_old = TAIL_list ( pars_old ) ;
|
|
|
1180 |
}
|
|
|
1181 |
|
|
|
1182 |
/* Find the definitions for function-like macros */
|
|
|
1183 |
defn_new = DEREF_pptok ( id_func_macro_defn ( id_new ) ) ;
|
|
|
1184 |
defn_old = DEREF_pptok ( id_func_macro_defn ( id_old ) ) ;
|
|
|
1185 |
}
|
|
|
1186 |
|
|
|
1187 |
/* Check that the definitions match */
|
|
|
1188 |
defn_ok = eq_pptok ( defn_new, defn_old ) ;
|
|
|
1189 |
if ( defn_ok == 0 ) {
|
|
|
1190 |
/* Inconsistent redefinition */
|
|
|
1191 |
ERROR e = ERR_cpp_replace_redef_bad ( id_old, loc_old ) ;
|
|
|
1192 |
err = concat_error ( err, e ) ;
|
|
|
1193 |
return ( err ) ;
|
|
|
1194 |
} else if ( defn_ok == 1 ) {
|
|
|
1195 |
/* Consistent redefinition up to white space */
|
|
|
1196 |
ERROR e = ERR_cpp_replace_redef_space ( id_old, loc_old ) ;
|
|
|
1197 |
e = set_severity ( e, OPT_macro_redef, -1 ) ;
|
|
|
1198 |
err = concat_error ( err, e ) ;
|
|
|
1199 |
}
|
|
|
1200 |
|
|
|
1201 |
/* Prepare final error */
|
|
|
1202 |
if ( pars_ok ) {
|
|
|
1203 |
/* Consistent macro redefinition */
|
|
|
1204 |
if ( IS_NULL_err ( err ) ) {
|
|
|
1205 |
err = ERR_cpp_replace_redef_ok ( id_old, loc_old ) ;
|
|
|
1206 |
}
|
|
|
1207 |
} else {
|
|
|
1208 |
/* Consistent redefinition up to parameter names */
|
|
|
1209 |
ERROR e = ERR_cpp_replace_redef_weak ( id_old, loc_old ) ;
|
|
|
1210 |
e = set_severity ( e, OPT_macro_redef, -1 ) ;
|
|
|
1211 |
err = concat_error ( err, e ) ;
|
|
|
1212 |
}
|
|
|
1213 |
return ( err ) ;
|
|
|
1214 |
}
|
|
|
1215 |
|
|
|
1216 |
|
|
|
1217 |
/*
|
|
|
1218 |
FREE A MACRO DEFINITION
|
|
|
1219 |
|
|
|
1220 |
This routine frees the macro definition given by the identifier id.
|
|
|
1221 |
It returns the previous definition of id.
|
|
|
1222 |
*/
|
|
|
1223 |
|
|
|
1224 |
static IDENTIFIER free_macro_defn
|
|
|
1225 |
PROTO_N ( ( id ) )
|
|
|
1226 |
PROTO_T ( IDENTIFIER id )
|
|
|
1227 |
{
|
|
|
1228 |
PPTOKEN *defn ;
|
|
|
1229 |
IDENTIFIER prev = DEREF_id ( id_alias ( id ) ) ;
|
|
|
1230 |
if ( IS_id_obj_macro ( id ) ) {
|
|
|
1231 |
defn = DEREF_pptok ( id_obj_macro_defn ( id ) ) ;
|
|
|
1232 |
COPY_pptok ( id_obj_macro_defn ( id ), NULL ) ;
|
|
|
1233 |
} else {
|
|
|
1234 |
defn = DEREF_pptok ( id_func_macro_defn ( id ) ) ;
|
|
|
1235 |
COPY_pptok ( id_func_macro_defn ( id ), NULL ) ;
|
|
|
1236 |
}
|
|
|
1237 |
free_tok_list ( defn ) ;
|
|
|
1238 |
return ( prev ) ;
|
|
|
1239 |
}
|
|
|
1240 |
|
|
|
1241 |
|
|
|
1242 |
/*
|
|
|
1243 |
READ A DEFINE DIRECTIVE
|
|
|
1244 |
|
|
|
1245 |
This routine processes a '#define' directive. This consists of a macro
|
|
|
1246 |
identifier, and optional list of macro parameters, and a list of token
|
|
|
1247 |
comprising the macro definition. Note that the list of parameters is
|
|
|
1248 |
built up in the reverse order to that in which they appear in the file
|
|
|
1249 |
(also see read_macro_args). The routine returns true if the directive
|
|
|
1250 |
is a macro definition.
|
|
|
1251 |
*/
|
|
|
1252 |
|
|
|
1253 |
static int read_define
|
|
|
1254 |
PROTO_Z ()
|
|
|
1255 |
{
|
|
|
1256 |
HASHID macro ;
|
|
|
1257 |
PPTOKEN *defn ;
|
|
|
1258 |
int legal = 1 ;
|
|
|
1259 |
IDENTIFIER id ;
|
|
|
1260 |
IDENTIFIER tok ;
|
|
|
1261 |
IDENTIFIER prev ;
|
|
|
1262 |
unsigned prev_def ;
|
|
|
1263 |
unsigned npars = 0 ;
|
|
|
1264 |
int object_like = 0 ;
|
|
|
1265 |
int ret = lex_ignore_token ;
|
|
|
1266 |
int first_tok = lex_ignore_token ;
|
|
|
1267 |
LIST ( HASHID ) pars = NULL_list ( HASHID ) ;
|
|
|
1268 |
OPTION preproc_strings = option ( OPT_preproc_old ) ;
|
|
|
1269 |
|
|
|
1270 |
/* Read the macro identifier */
|
|
|
1271 |
int t = read_token () ;
|
|
|
1272 |
update_column () ;
|
|
|
1273 |
if ( in_preproc_dir ) preproc_loc = crt_loc ;
|
|
|
1274 |
if ( t != lex_identifier ) {
|
|
|
1275 |
report ( preproc_loc, ERR_cpp_replace_id ( lex_define ) ) ;
|
|
|
1276 |
return ( ret ) ;
|
|
|
1277 |
}
|
|
|
1278 |
macro = token_hashid ;
|
|
|
1279 |
if ( EQ_KEYWORD ( macro, lex_defined ) ) {
|
|
|
1280 |
/* Cannot define defined as a macro */
|
|
|
1281 |
report ( preproc_loc, ERR_cpp_predef_bad ( macro, lex_define ) ) ;
|
|
|
1282 |
} else {
|
|
|
1283 |
id = DEREF_id ( hashid_id ( macro ) ) ;
|
|
|
1284 |
if ( IS_id_keyword ( id ) && !preproc_only ) {
|
|
|
1285 |
/* Warn about redefining keywords */
|
|
|
1286 |
report ( preproc_loc, ERR_cpp_predef_keyword ( macro ) ) ;
|
|
|
1287 |
}
|
|
|
1288 |
}
|
|
|
1289 |
prev_def = check_macro ( macro, 0 ) ;
|
|
|
1290 |
tok = token_macro ;
|
|
|
1291 |
|
|
|
1292 |
/* Check for macro parameters */
|
|
|
1293 |
if ( peek_char ( char_open_round, &legal ) ) {
|
|
|
1294 |
PPTOKEN *p ;
|
|
|
1295 |
int err = 0 ;
|
|
|
1296 |
int par_next = 2 ;
|
|
|
1297 |
LIST ( HASHID ) lp ;
|
|
|
1298 |
unsigned long par_no = 1 ;
|
|
|
1299 |
|
|
|
1300 |
/* Scan through definition looking for parameters */
|
|
|
1301 |
update_column () ;
|
|
|
1302 |
if ( in_preproc_dir ) preproc_loc = crt_loc ;
|
|
|
1303 |
while ( t = read_token (), t != lex_close_Hround ) {
|
|
|
1304 |
update_column () ;
|
|
|
1305 |
if ( in_preproc_dir ) preproc_loc = crt_loc ;
|
|
|
1306 |
if ( t == lex_identifier ) {
|
|
|
1307 |
/* Identifiers are parameter names */
|
|
|
1308 |
unsigned long mark ;
|
|
|
1309 |
HASHID par = token_hashid ;
|
|
|
1310 |
IGNORE check_macro ( par, 0 ) ;
|
|
|
1311 |
CONS_hashid ( par, pars, pars ) ;
|
|
|
1312 |
|
|
|
1313 |
/* Mark name with parameter number */
|
|
|
1314 |
mark = DEREF_ulong ( hashid_hash ( par ) ) ;
|
|
|
1315 |
if ( mark >= HASH_SIZE ) {
|
|
|
1316 |
/* Parameter already marked */
|
|
|
1317 |
ERROR e = ERR_cpp_replace_par_dup ( par, macro ) ;
|
|
|
1318 |
report ( preproc_loc, e ) ;
|
|
|
1319 |
mark %= HASH_SIZE ;
|
|
|
1320 |
}
|
|
|
1321 |
mark += HASH_SIZE * par_no ;
|
|
|
1322 |
COPY_ulong ( hashid_hash ( par ), mark ) ;
|
|
|
1323 |
if ( !par_next ) err = 1 ;
|
|
|
1324 |
par_next = 0 ;
|
|
|
1325 |
par_no++ ;
|
|
|
1326 |
} else if ( t == lex_comma ) {
|
|
|
1327 |
/* Commas separate parameters */
|
|
|
1328 |
if ( par_next ) err = 1 ;
|
|
|
1329 |
par_next = 1 ;
|
|
|
1330 |
} else {
|
|
|
1331 |
/* Anything else is an error */
|
|
|
1332 |
first_tok = t ;
|
|
|
1333 |
err = 1 ;
|
|
|
1334 |
break ;
|
|
|
1335 |
}
|
|
|
1336 |
}
|
|
|
1337 |
update_column () ;
|
|
|
1338 |
if ( in_preproc_dir ) preproc_loc = crt_loc ;
|
|
|
1339 |
if ( err || par_next == 1 ) {
|
|
|
1340 |
/* Report any errors */
|
|
|
1341 |
report ( preproc_loc, ERR_cpp_replace_par_bad ( macro ) ) ;
|
|
|
1342 |
}
|
|
|
1343 |
|
|
|
1344 |
/* Allow for parameter expansion in strings */
|
|
|
1345 |
if ( preproc_strings ) {
|
|
|
1346 |
/* This causes strings not to be recognised */
|
|
|
1347 |
set_char_lookup ( char_quote, char_illegal ) ;
|
|
|
1348 |
set_char_lookup ( char_single_quote, char_illegal ) ;
|
|
|
1349 |
}
|
|
|
1350 |
|
|
|
1351 |
/* Read the macro definition for function-like macros */
|
|
|
1352 |
defn = read_line ( first_tok, lex_ignore_token ) ;
|
|
|
1353 |
if ( defn ) defn->pp_space = WHITE_SPACE ;
|
|
|
1354 |
|
|
|
1355 |
/* Restore string terminators */
|
|
|
1356 |
if ( preproc_strings ) {
|
|
|
1357 |
set_char_lookup ( char_quote, char_quote ) ;
|
|
|
1358 |
set_char_lookup ( char_single_quote, char_single_quote ) ;
|
|
|
1359 |
}
|
|
|
1360 |
|
|
|
1361 |
/* Mark the macro parameters in the definition */
|
|
|
1362 |
for ( p = defn ; p != NULL ; p = p->next ) {
|
|
|
1363 |
int tk = p->tok ;
|
|
|
1364 |
if ( tk == lex_identifier ) {
|
|
|
1365 |
HASHID par = p->pp_data.id.hash ;
|
|
|
1366 |
unsigned long mark = DEREF_ulong ( hashid_hash ( par ) ) ;
|
|
|
1367 |
if ( mark >= HASH_SIZE ) {
|
|
|
1368 |
/* Parameters are identified by the parameter number */
|
|
|
1369 |
p->tok = lex_macro_Harg ;
|
|
|
1370 |
p->pp_data.par.hash = par ;
|
|
|
1371 |
p->pp_data.par.no = ( mark / HASH_SIZE ) ;
|
|
|
1372 |
}
|
|
|
1373 |
}
|
|
|
1374 |
}
|
|
|
1375 |
|
|
|
1376 |
/* Check for quoted parameters */
|
|
|
1377 |
if ( preproc_strings ) {
|
|
|
1378 |
defn = recognise_strings ( defn, macro, 0 ) ;
|
|
|
1379 |
}
|
|
|
1380 |
|
|
|
1381 |
/* Check for '#' operators */
|
|
|
1382 |
for ( p = defn ; p != NULL ; p = p->next ) {
|
|
|
1383 |
int tk = p->tok ;
|
|
|
1384 |
if ( tk == lex_hash_H2 ) tk = get_digraph ( tk ) ;
|
|
|
1385 |
if ( tk == lex_hash_H1 ) {
|
|
|
1386 |
/* '#' should be followed by a parameter */
|
|
|
1387 |
if ( p->next == NULL || p->next->tok != lex_macro_Harg ) {
|
|
|
1388 |
report ( preproc_loc, ERR_cpp_stringize_par ( macro ) ) ;
|
|
|
1389 |
} else {
|
|
|
1390 |
p->tok = lex_hash_Hop ;
|
|
|
1391 |
}
|
|
|
1392 |
}
|
|
|
1393 |
}
|
|
|
1394 |
|
|
|
1395 |
/* Clear the parameter marks */
|
|
|
1396 |
for ( lp = pars ; !IS_NULL_list ( lp ) ; lp = TAIL_list ( lp ) ) {
|
|
|
1397 |
HASHID par = DEREF_hashid ( HEAD_list ( lp ) ) ;
|
|
|
1398 |
unsigned long mark = DEREF_ulong ( hashid_hash ( par ) ) ;
|
|
|
1399 |
mark %= HASH_SIZE ;
|
|
|
1400 |
COPY_ulong ( hashid_hash ( par ), mark ) ;
|
|
|
1401 |
npars++ ;
|
|
|
1402 |
}
|
|
|
1403 |
pars = REVERSE_list ( pars ) ;
|
|
|
1404 |
|
|
|
1405 |
} else {
|
|
|
1406 |
/* Read the macro definition for object-like macros */
|
|
|
1407 |
if ( !legal ) report ( preproc_loc, ERR_cpp_space_replace () ) ;
|
|
|
1408 |
defn = read_line ( first_tok, lex_ignore_token ) ;
|
|
|
1409 |
object_like = 1 ;
|
|
|
1410 |
}
|
|
|
1411 |
|
|
|
1412 |
/* Check for '##' operators */
|
|
|
1413 |
if ( defn ) {
|
|
|
1414 |
PPTOKEN *p ;
|
|
|
1415 |
int tk = defn->tok ;
|
|
|
1416 |
if ( tk == lex_hash_Hhash_H2 ) tk = get_digraph ( tk ) ;
|
|
|
1417 |
if ( tk == lex_hash_Hhash_H1 ) {
|
|
|
1418 |
/* Definition can't start with '##' */
|
|
|
1419 |
report ( preproc_loc, ERR_cpp_concat_place ( macro ) ) ;
|
|
|
1420 |
}
|
|
|
1421 |
for ( p = defn->next ; p != NULL ; p = p->next ) {
|
|
|
1422 |
tk = p->tok ;
|
|
|
1423 |
if ( tk == lex_hash_Hhash_H2 ) tk = get_digraph ( tk ) ;
|
|
|
1424 |
if ( tk == lex_hash_Hhash_H1 ) {
|
|
|
1425 |
if ( p->next == NULL ) {
|
|
|
1426 |
/* Definition can't end with '##' */
|
|
|
1427 |
report ( preproc_loc, ERR_cpp_concat_place ( macro ) ) ;
|
|
|
1428 |
} else {
|
|
|
1429 |
p->tok = lex_hash_Hhash_Hop ;
|
|
|
1430 |
}
|
|
|
1431 |
}
|
|
|
1432 |
}
|
|
|
1433 |
}
|
|
|
1434 |
|
|
|
1435 |
/* Define the macro */
|
|
|
1436 |
if ( !IS_NULL_exp ( crt_hash_cond ) ) {
|
|
|
1437 |
report ( preproc_loc, ERR_cpp_cond_if_macro ( macro ) ) ;
|
|
|
1438 |
}
|
|
|
1439 |
prev = DEREF_id ( hashid_id ( macro ) ) ;
|
|
|
1440 |
if ( object_like ) {
|
|
|
1441 |
MAKE_id_obj_macro ( macro, dspec_defn, NULL_nspace, preproc_loc,
|
|
|
1442 |
defn, id ) ;
|
|
|
1443 |
} else {
|
|
|
1444 |
IGNORE check_value ( OPT_VAL_macro_pars, ( ulong ) npars ) ;
|
|
|
1445 |
MAKE_id_func_macro ( macro, dspec_defn, NULL_nspace, preproc_loc,
|
|
|
1446 |
defn, pars, npars, id ) ;
|
|
|
1447 |
}
|
|
|
1448 |
COPY_id ( id_alias ( id ), prev ) ;
|
|
|
1449 |
if ( prev_def & PP_TOKEN ) {
|
|
|
1450 |
/* Allow for token definitions */
|
|
|
1451 |
prev_def &= PP_COND_MASK ;
|
|
|
1452 |
if ( prev_def == PP_UNRESOLVED ) {
|
|
|
1453 |
/* Can only happen when preprocessing */
|
|
|
1454 |
token_macro = id ;
|
|
|
1455 |
ret = lex_hash_Hop ;
|
|
|
1456 |
} else {
|
|
|
1457 |
int tokdef ;
|
|
|
1458 |
DECL_SPEC ds = DEREF_dspec ( id_storage ( id ) ) ;
|
|
|
1459 |
COPY_dspec ( id_storage ( id ), ( ds | dspec_temp ) ) ;
|
|
|
1460 |
tokdef = define_token_macro ( tok, id ) ;
|
|
|
1461 |
COPY_dspec ( id_storage ( id ), ds ) ;
|
|
|
1462 |
if ( tokdef ) {
|
|
|
1463 |
IGNORE free_macro_defn ( id ) ;
|
|
|
1464 |
no_declarations++ ;
|
|
|
1465 |
return ( ret ) ;
|
|
|
1466 |
}
|
|
|
1467 |
prev_def = PP_FALSE ;
|
|
|
1468 |
}
|
|
|
1469 |
}
|
|
|
1470 |
COPY_id ( hashid_id ( macro ), id ) ;
|
|
|
1471 |
if ( do_macro ) {
|
|
|
1472 |
/* Dump macro definition using current namespace */
|
|
|
1473 |
COPY_nspace ( id_parent ( id ), crt_namespace ) ;
|
|
|
1474 |
dump_declare ( id, &preproc_loc, 1 ) ;
|
|
|
1475 |
COPY_nspace ( id_parent ( id ), NULL_nspace ) ;
|
|
|
1476 |
}
|
|
|
1477 |
|
|
|
1478 |
/* Check consistency of previous definition */
|
|
|
1479 |
if ( prev_def == PP_TRUE ) {
|
|
|
1480 |
ERROR err ;
|
|
|
1481 |
if ( option ( OPT_macro_nest ) == OPTION_DISALLOW ) {
|
|
|
1482 |
err = check_macro_redef ( id, prev ) ;
|
|
|
1483 |
prev = free_macro_defn ( prev ) ;
|
|
|
1484 |
} else {
|
|
|
1485 |
PTR ( LOCATION ) loc = id_loc ( prev ) ;
|
|
|
1486 |
err = ERR_cpp_replace_redef_nest ( prev, loc ) ;
|
|
|
1487 |
}
|
|
|
1488 |
if ( !IS_NULL_err ( err ) ) report ( preproc_loc, err ) ;
|
|
|
1489 |
COPY_id ( id_alias ( id ), prev ) ;
|
|
|
1490 |
} else {
|
|
|
1491 |
IGNORE incr_value ( OPT_VAL_macro_ids ) ;
|
|
|
1492 |
}
|
|
|
1493 |
return ( ret ) ;
|
|
|
1494 |
}
|
|
|
1495 |
|
|
|
1496 |
|
|
|
1497 |
/*
|
|
|
1498 |
READ AN UNDEFINE DIRECTIVE
|
|
|
1499 |
|
|
|
1500 |
This routine processes a '#undef' directive. This just consists of a
|
|
|
1501 |
macro identifier. The routine returns true if the macro represents
|
|
|
1502 |
a token.
|
|
|
1503 |
*/
|
|
|
1504 |
|
|
|
1505 |
static int read_undef
|
|
|
1506 |
PROTO_Z ()
|
|
|
1507 |
{
|
|
|
1508 |
/* Read the macro identifier */
|
|
|
1509 |
unsigned def ;
|
|
|
1510 |
HASHID macro ;
|
|
|
1511 |
int ret = lex_ignore_token ;
|
|
|
1512 |
int t = read_token () ;
|
|
|
1513 |
update_column () ;
|
|
|
1514 |
if ( in_preproc_dir ) preproc_loc = crt_loc ;
|
|
|
1515 |
if ( t != lex_identifier ) {
|
|
|
1516 |
report ( preproc_loc, ERR_cpp_scope_id ( lex_undef ) ) ;
|
|
|
1517 |
return ( ret ) ;
|
|
|
1518 |
}
|
|
|
1519 |
macro = token_hashid ;
|
|
|
1520 |
if ( EQ_KEYWORD ( macro, lex_defined ) ) {
|
|
|
1521 |
/* Cannot undefine defined */
|
|
|
1522 |
report ( preproc_loc, ERR_cpp_predef_bad ( macro, lex_undef ) ) ;
|
|
|
1523 |
}
|
|
|
1524 |
|
|
|
1525 |
/* Undefine the macro if necessary */
|
|
|
1526 |
def = check_macro ( macro, 0 ) ;
|
|
|
1527 |
if ( def == PP_TRUE ) {
|
|
|
1528 |
/* Previously defined as macro */
|
|
|
1529 |
IDENTIFIER prev = DEREF_id ( hashid_id ( macro ) ) ;
|
|
|
1530 |
DECL_SPEC ds = DEREF_dspec ( id_storage ( prev ) ) ;
|
|
|
1531 |
if ( ( ds & dspec_builtin ) && crt_file_type == 0 ) {
|
|
|
1532 |
report ( preproc_loc, ERR_cpp_predef_undef ( prev ) ) ;
|
|
|
1533 |
}
|
|
|
1534 |
if ( do_macro ) dump_undefine ( prev, &preproc_loc, 1 ) ;
|
|
|
1535 |
prev = free_macro_defn ( prev ) ;
|
|
|
1536 |
COPY_id ( hashid_id ( macro ), prev ) ;
|
|
|
1537 |
decr_value ( OPT_VAL_macro_ids ) ;
|
|
|
1538 |
|
|
|
1539 |
} else if ( def & PP_TOKEN ) {
|
|
|
1540 |
/* Previously defined as token */
|
|
|
1541 |
IDENTIFIER prev = token_macro ;
|
|
|
1542 |
def &= PP_COND_MASK ;
|
|
|
1543 |
if ( def == PP_UNRESOLVED ) {
|
|
|
1544 |
/* Can only happen when preprocessing */
|
|
|
1545 |
ret = lex_hash_Hop ;
|
|
|
1546 |
} else {
|
|
|
1547 |
if ( IS_id_function_etc ( prev ) ) {
|
|
|
1548 |
do {
|
|
|
1549 |
DECL_SPEC ds = DEREF_dspec ( id_storage ( prev ) ) ;
|
|
|
1550 |
TYPE f = DEREF_type ( id_function_etc_form ( prev ) ) ;
|
|
|
1551 |
if ( !IS_NULL_type ( f ) && IS_type_token ( f ) ) {
|
|
|
1552 |
IDENTIFIER ext = DEREF_id ( type_token_tok ( f ) ) ;
|
|
|
1553 |
if ( !IS_NULL_id ( ext ) && IS_id_token ( ext ) ) {
|
|
|
1554 |
if ( do_dump ) {
|
|
|
1555 |
dump_undefine ( prev, &preproc_loc, 1 ) ;
|
|
|
1556 |
}
|
|
|
1557 |
f = NULL_type ;
|
|
|
1558 |
COPY_type ( id_function_etc_form ( prev ), f ) ;
|
|
|
1559 |
}
|
|
|
1560 |
}
|
|
|
1561 |
ds &= ~dspec_token ;
|
|
|
1562 |
COPY_dspec ( id_storage ( prev ), ds ) ;
|
|
|
1563 |
prev = DEREF_id ( id_function_etc_over ( prev ) ) ;
|
|
|
1564 |
} while ( !IS_NULL_id ( prev ) ) ;
|
|
|
1565 |
} else {
|
|
|
1566 |
if ( do_dump ) dump_undefine ( prev, &preproc_loc, 1 ) ;
|
|
|
1567 |
remove_id ( prev ) ;
|
|
|
1568 |
}
|
|
|
1569 |
}
|
|
|
1570 |
|
|
|
1571 |
} else {
|
|
|
1572 |
/* Not previously declared */
|
|
|
1573 |
report ( preproc_loc, ERR_cpp_scope_undef ( macro ) ) ;
|
|
|
1574 |
}
|
|
|
1575 |
|
|
|
1576 |
/* Check the rest of the directive */
|
|
|
1577 |
if ( in_preproc_dir && skip_to_end () ) {
|
|
|
1578 |
report ( preproc_loc, ERR_cpp_end ( lex_undef ) ) ;
|
|
|
1579 |
}
|
|
|
1580 |
return ( ret ) ;
|
|
|
1581 |
}
|
|
|
1582 |
|
|
|
1583 |
|
|
|
1584 |
/*
|
|
|
1585 |
READ A LINE DIRECTIVE
|
|
|
1586 |
|
|
|
1587 |
This routine processes a '#line' or '#file' directive (as indicated
|
|
|
1588 |
by dir).
|
|
|
1589 |
*/
|
|
|
1590 |
|
|
|
1591 |
static void read_location
|
|
|
1592 |
PROTO_N ( ( dir ) )
|
|
|
1593 |
PROTO_T ( int dir )
|
|
|
1594 |
{
|
|
|
1595 |
/* Read the line */
|
|
|
1596 |
PPTOKEN *p = read_line ( lex_ignore_token, lex_ignore_token ) ;
|
|
|
1597 |
unsigned long ln = crt_loc.line ;
|
|
|
1598 |
string fn = DEREF_string ( posn_file ( crt_loc.posn ) ) ;
|
|
|
1599 |
unsigned long ln_old = ln ;
|
|
|
1600 |
string fn_old = fn ;
|
|
|
1601 |
|
|
|
1602 |
/* Macro expand the line */
|
|
|
1603 |
PPTOKEN *q = expand_tok_list ( p ) ;
|
|
|
1604 |
q = clean_tok_list ( q ) ;
|
|
|
1605 |
if ( q && q->tok == lex_integer_Hlit && dir == lex_line ) {
|
|
|
1606 |
/* Process '#line number string-opt' */
|
|
|
1607 |
unsigned err = 0 ;
|
|
|
1608 |
PPTOKEN *r = q->next ;
|
|
|
1609 |
ln = eval_line_digits ( q->pp_data.text, &err ) ;
|
|
|
1610 |
if ( ln != ln_old ) crt_line_changed = 1 ;
|
|
|
1611 |
if ( err & 2 ) {
|
|
|
1612 |
report ( preproc_loc, ERR_cpp_line_float ( dir ) ) ;
|
|
|
1613 |
}
|
|
|
1614 |
if ( ( err & 1 ) || ( ln == 0 ) ) {
|
|
|
1615 |
report ( preproc_loc, ERR_cpp_line_range ( dir ) ) ;
|
|
|
1616 |
}
|
|
|
1617 |
if ( r && r->tok == lex_string_Hlit ) {
|
|
|
1618 |
fn = r->pp_data.str.start ;
|
|
|
1619 |
if ( !ustreq ( fn, fn_old ) ) {
|
|
|
1620 |
crt_file_changed = 1 ;
|
|
|
1621 |
crt_line_changed = 1 ;
|
|
|
1622 |
}
|
|
|
1623 |
r = r->next ;
|
|
|
1624 |
}
|
|
|
1625 |
if ( r ) report ( preproc_loc, ERR_cpp_end ( dir ) ) ;
|
|
|
1626 |
} else if ( q && q->tok == lex_string_Hlit && dir == lex_file ) {
|
|
|
1627 |
/* Process '#file string' */
|
|
|
1628 |
PPTOKEN *r = q->next ;
|
|
|
1629 |
fn = q->pp_data.str.start ;
|
|
|
1630 |
if ( !ustreq ( fn, fn_old ) ) {
|
|
|
1631 |
crt_file_changed = 1 ;
|
|
|
1632 |
crt_line_changed = 1 ;
|
|
|
1633 |
}
|
|
|
1634 |
if ( r ) report ( preproc_loc, ERR_cpp_end ( dir ) ) ;
|
|
|
1635 |
} else {
|
|
|
1636 |
report ( preproc_loc, ERR_cpp_line_bad ( dir ) ) ;
|
|
|
1637 |
}
|
|
|
1638 |
free_tok_list ( p ) ;
|
|
|
1639 |
free_tok_list ( q ) ;
|
|
|
1640 |
if ( crt_line_changed ) {
|
|
|
1641 |
PTR ( POSITION ) posn = crt_loc.posn ;
|
|
|
1642 |
string d = DEREF_string ( posn_dir ( posn ) ) ;
|
|
|
1643 |
string input = DEREF_string ( posn_input ( posn ) ) ;
|
|
|
1644 |
unsigned long off = DEREF_ulong ( posn_offset ( posn ) ) ;
|
|
|
1645 |
unsigned long date = DEREF_ulong ( posn_datestamp ( posn ) ) ;
|
|
|
1646 |
PTR ( LOCATION ) from = DEREF_ptr ( posn_from ( posn ) ) ;
|
|
|
1647 |
off += ( ln - ln_old ) ;
|
|
|
1648 |
posn = MAKE_ptr ( SIZE_posn ) ;
|
|
|
1649 |
MAKE_posn ( fn, input, fn, d, off, from, date, posn ) ;
|
|
|
1650 |
crt_loc.posn = posn ;
|
|
|
1651 |
}
|
|
|
1652 |
crt_loc.line = ln ;
|
|
|
1653 |
crt_loc.column = 0 ;
|
|
|
1654 |
return ;
|
|
|
1655 |
}
|
|
|
1656 |
|
|
|
1657 |
|
|
|
1658 |
/*
|
|
|
1659 |
READ AN ERROR DIRECTIVE
|
|
|
1660 |
|
|
|
1661 |
This routine processes a '#error' or '#warning' directive (as indicated
|
|
|
1662 |
by the error severity level sev).
|
|
|
1663 |
*/
|
|
|
1664 |
|
|
|
1665 |
static void read_error
|
|
|
1666 |
PROTO_N ( ( opt ) )
|
|
|
1667 |
PROTO_T ( int opt )
|
|
|
1668 |
{
|
|
|
1669 |
ERROR err ;
|
|
|
1670 |
PPTOKEN *p = read_line ( lex_ignore_token, lex_ignore_token ) ;
|
|
|
1671 |
IGNORE quote_tok_list ( p, 0, char_quote ) ;
|
|
|
1672 |
err = ERR_cpp_error_msg ( token_buff.start ) ;
|
|
|
1673 |
if ( !IS_NULL_err ( err ) ) {
|
|
|
1674 |
err = set_severity ( err, opt, 0 ) ;
|
|
|
1675 |
report ( preproc_loc, err ) ;
|
|
|
1676 |
}
|
|
|
1677 |
free_tok_list ( p ) ;
|
|
|
1678 |
return ;
|
|
|
1679 |
}
|
|
|
1680 |
|
|
|
1681 |
|
|
|
1682 |
/*
|
|
|
1683 |
READ AN IDENT DIRECTIVE
|
|
|
1684 |
|
|
|
1685 |
This routine processes a '#ident' directive.
|
|
|
1686 |
*/
|
|
|
1687 |
|
|
|
1688 |
void read_ident
|
|
|
1689 |
PROTO_N ( ( dir ) )
|
|
|
1690 |
PROTO_T ( int dir )
|
|
|
1691 |
{
|
|
|
1692 |
int t = read_token () ;
|
|
|
1693 |
update_column () ;
|
|
|
1694 |
if ( in_preproc_dir ) preproc_loc = crt_loc ;
|
|
|
1695 |
if ( t == lex_string_Hlit ) {
|
|
|
1696 |
string s = token_buff.start ;
|
|
|
1697 |
unsigned long n = ( unsigned long ) ( token_buff.posn - s ) ;
|
|
|
1698 |
compile_comment ( s, n ) ;
|
|
|
1699 |
if ( in_preproc_dir && skip_to_end () ) {
|
|
|
1700 |
report ( preproc_loc, ERR_cpp_end ( dir ) ) ;
|
|
|
1701 |
}
|
|
|
1702 |
} else {
|
|
|
1703 |
report ( preproc_loc, ERR_pragma_cpp_ident ( dir ) ) ;
|
|
|
1704 |
}
|
|
|
1705 |
return ;
|
|
|
1706 |
}
|
|
|
1707 |
|
|
|
1708 |
|
|
|
1709 |
/*
|
|
|
1710 |
CREATE AN ASSERTION
|
|
|
1711 |
|
|
|
1712 |
This routine looks up the assertion named pred, creating it if it does
|
|
|
1713 |
not already exist.
|
|
|
1714 |
*/
|
|
|
1715 |
|
|
|
1716 |
IDENTIFIER make_assert
|
|
|
1717 |
PROTO_N ( ( pred, key ) )
|
|
|
1718 |
PROTO_T ( HASHID pred X int key )
|
|
|
1719 |
{
|
|
|
1720 |
NAMESPACE ns = assert_namespace ;
|
|
|
1721 |
MEMBER mem = search_member ( ns, pred, 1 ) ;
|
|
|
1722 |
IDENTIFIER id = DEREF_id ( member_id ( mem ) ) ;
|
|
|
1723 |
if ( IS_NULL_id ( id ) ) {
|
|
|
1724 |
/* Define assertion if not already defined */
|
|
|
1725 |
MAKE_id_predicate ( pred, dspec_none, ns, preproc_loc, id ) ;
|
|
|
1726 |
COPY_ulong ( id_no ( id ), ( unsigned long ) key ) ;
|
|
|
1727 |
COPY_id ( member_id ( mem ), id ) ;
|
|
|
1728 |
}
|
|
|
1729 |
return ( id ) ;
|
|
|
1730 |
}
|
|
|
1731 |
|
|
|
1732 |
|
|
|
1733 |
/*
|
|
|
1734 |
SKIP A PREDICATE
|
|
|
1735 |
|
|
|
1736 |
This routine skips a predicate given by the list of preprocessing
|
|
|
1737 |
tokens p. It is entered after the initial open bracket and returns
|
|
|
1738 |
the token after the matching close bracket.
|
|
|
1739 |
*/
|
|
|
1740 |
|
|
|
1741 |
static PPTOKEN *skip_predicate
|
|
|
1742 |
PROTO_N ( ( p, dir ) )
|
|
|
1743 |
PROTO_T ( PPTOKEN **p X int dir )
|
|
|
1744 |
{
|
|
|
1745 |
PPTOKEN *q = *p ;
|
|
|
1746 |
PPTOKEN *r = NULL ;
|
|
|
1747 |
int bracket = 1 ;
|
|
|
1748 |
if ( q ) q->pp_space = 0 ;
|
|
|
1749 |
while ( q ) {
|
|
|
1750 |
int t = q->tok ;
|
|
|
1751 |
if ( t == lex_open_Hround ) {
|
|
|
1752 |
/* Increase bracket count */
|
|
|
1753 |
bracket++ ;
|
|
|
1754 |
} else if ( t == lex_close_Hround ) {
|
|
|
1755 |
/* Decrease bracket count */
|
|
|
1756 |
if ( --bracket == 0 ) {
|
|
|
1757 |
if ( r ) {
|
|
|
1758 |
r->next = NULL ;
|
|
|
1759 |
} else if ( dir == lex_define || dir == lex_undef ) {
|
|
|
1760 |
*p = NULL ;
|
|
|
1761 |
} else {
|
|
|
1762 |
report ( preproc_loc, ERR_pragma_assert_empty ( dir ) ) ;
|
|
|
1763 |
*p = NULL ;
|
|
|
1764 |
}
|
|
|
1765 |
r = q->next ;
|
|
|
1766 |
q->next = free_tokens ;
|
|
|
1767 |
free_tokens = q ;
|
|
|
1768 |
return ( r ) ;
|
|
|
1769 |
}
|
|
|
1770 |
} else if ( t == lex_newline ) {
|
|
|
1771 |
/* Terminate if a newline is reached */
|
|
|
1772 |
report ( preproc_loc, ERR_pragma_assert_paren ( dir ) ) ;
|
|
|
1773 |
if ( r ) {
|
|
|
1774 |
r->next = NULL ;
|
|
|
1775 |
} else {
|
|
|
1776 |
report ( preproc_loc, ERR_pragma_assert_empty ( dir ) ) ;
|
|
|
1777 |
*p = NULL ;
|
|
|
1778 |
}
|
|
|
1779 |
return ( q ) ;
|
|
|
1780 |
}
|
|
|
1781 |
r = q ;
|
|
|
1782 |
q = q->next ;
|
|
|
1783 |
}
|
|
|
1784 |
report ( preproc_loc, ERR_pragma_assert_paren ( dir ) ) ;
|
|
|
1785 |
return ( NULL ) ;
|
|
|
1786 |
}
|
|
|
1787 |
|
|
|
1788 |
|
|
|
1789 |
/*
|
|
|
1790 |
CHECK A PREDICATE VALUE
|
|
|
1791 |
|
|
|
1792 |
This routine checks whether the value p, or any value if def is true,
|
|
|
1793 |
has been defined in the predicate pred.
|
|
|
1794 |
*/
|
|
|
1795 |
|
|
|
1796 |
static int check_assert
|
|
|
1797 |
PROTO_N ( ( pred, p, def ) )
|
|
|
1798 |
PROTO_T ( HASHID pred X PPTOKEN *p X int def )
|
|
|
1799 |
{
|
|
|
1800 |
IDENTIFIER id = make_assert ( pred, lex_unknown ) ;
|
|
|
1801 |
int key = ( int ) DEREF_ulong ( id_no ( id ) ) ;
|
|
|
1802 |
LIST ( PPTOKEN_P ) s = DEREF_list ( id_predicate_values ( id ) ) ;
|
|
|
1803 |
report ( preproc_loc, ERR_pragma_assert_pred ( pred ) ) ;
|
|
|
1804 |
if ( def ) {
|
|
|
1805 |
/* Check for any predicate */
|
|
|
1806 |
if ( !IS_NULL_list ( s ) ) return ( 1 ) ;
|
|
|
1807 |
} else {
|
|
|
1808 |
while ( !IS_NULL_list ( s ) ) {
|
|
|
1809 |
PPTOKEN *q = DEREF_pptok ( HEAD_list ( s ) ) ;
|
|
|
1810 |
if ( eq_pptok ( p, q ) == 2 ) return ( 1 ) ;
|
|
|
1811 |
s = TAIL_list ( s ) ;
|
|
|
1812 |
}
|
|
|
1813 |
}
|
|
|
1814 |
if ( key == lex_include ) {
|
|
|
1815 |
/* '#include' checks for included files */
|
|
|
1816 |
if ( def ) return ( 1 ) ;
|
|
|
1817 |
IGNORE quote_tok_list ( p, 0, char_quote ) ;
|
|
|
1818 |
return ( start_include ( token_buff.start, char_quote, 4, 0 ) ) ;
|
|
|
1819 |
}
|
|
|
1820 |
if ( key == lex_keyword ) {
|
|
|
1821 |
/* '#keyword' checks for keywords */
|
|
|
1822 |
if ( def ) return ( 1 ) ;
|
|
|
1823 |
if ( p && p->next == NULL ) {
|
|
|
1824 |
if ( p->tok == lex_identifier ) {
|
|
|
1825 |
IDENTIFIER pid = p->pp_data.id.use ;
|
|
|
1826 |
if ( IS_id_keyword ( pid ) ) return ( 1 ) ;
|
|
|
1827 |
if ( IS_id_iso_keyword ( pid ) ) return ( 1 ) ;
|
|
|
1828 |
}
|
|
|
1829 |
}
|
|
|
1830 |
}
|
|
|
1831 |
if ( key == lex_option ) {
|
|
|
1832 |
/* '#option' checks for options */
|
|
|
1833 |
int n ;
|
|
|
1834 |
ulong sn ;
|
|
|
1835 |
string sb ;
|
|
|
1836 |
static STRING str = NULL_str ;
|
|
|
1837 |
if ( def ) return ( 1 ) ;
|
|
|
1838 |
IGNORE quote_tok_list ( p, 0, char_quote ) ;
|
|
|
1839 |
sb = token_buff.start ;
|
|
|
1840 |
sn = ( ulong ) ( token_buff.posn - sb ) ;
|
|
|
1841 |
if ( IS_NULL_str ( str ) ) {
|
|
|
1842 |
MAKE_str_simple ( sn, sb, STRING_NONE, str ) ;
|
|
|
1843 |
} else {
|
|
|
1844 |
COPY_string ( str_simple_text ( str ), sb ) ;
|
|
|
1845 |
COPY_ulong ( str_simple_len ( str ), sn ) ;
|
|
|
1846 |
}
|
|
|
1847 |
n = find_option_no ( str, 0 ) ;
|
|
|
1848 |
if ( n != -1 && option ( n ) ) return ( 1 ) ;
|
|
|
1849 |
}
|
|
|
1850 |
return ( 0 ) ;
|
|
|
1851 |
}
|
|
|
1852 |
|
|
|
1853 |
|
|
|
1854 |
/*
|
|
|
1855 |
SET A PREDICATE VALUE
|
|
|
1856 |
|
|
|
1857 |
This routine sets the assertion value of the preprocessing tokens p
|
|
|
1858 |
in the predicate id to be def.
|
|
|
1859 |
*/
|
|
|
1860 |
|
|
|
1861 |
static void set_assert
|
|
|
1862 |
PROTO_N ( ( id, p, def ) )
|
|
|
1863 |
PROTO_T ( IDENTIFIER id X PPTOKEN *p X int def )
|
|
|
1864 |
{
|
|
|
1865 |
LIST ( PPTOKEN_P ) s ;
|
|
|
1866 |
PTR ( LIST ( PPTOKEN_P ) ) ps = id_predicate_values ( id ) ;
|
|
|
1867 |
LIST ( PPTOKEN_P ) r = DEREF_list ( ps ) ;
|
|
|
1868 |
while ( s = DEREF_list ( ps ), !IS_NULL_list ( s ) ) {
|
|
|
1869 |
PPTOKEN *q = DEREF_pptok ( HEAD_list ( s ) ) ;
|
|
|
1870 |
if ( eq_pptok ( p, q ) == 2 ) {
|
|
|
1871 |
/* Already asserted */
|
|
|
1872 |
if ( !def ) {
|
|
|
1873 |
DESTROY_CONS_pptok ( destroy, q, s, s ) ;
|
|
|
1874 |
COPY_list ( ps, s ) ;
|
|
|
1875 |
free_tok_list ( q ) ;
|
|
|
1876 |
}
|
|
|
1877 |
free_tok_list ( p ) ;
|
|
|
1878 |
return ;
|
|
|
1879 |
}
|
|
|
1880 |
ps = PTR_TAIL_list ( s ) ;
|
|
|
1881 |
}
|
|
|
1882 |
if ( def ) {
|
|
|
1883 |
/* Create assertion */
|
|
|
1884 |
CONS_pptok ( p, r, r ) ;
|
|
|
1885 |
COPY_list ( id_predicate_values ( id ), r ) ;
|
|
|
1886 |
} else {
|
|
|
1887 |
free_tok_list ( p ) ;
|
|
|
1888 |
}
|
|
|
1889 |
return ;
|
|
|
1890 |
}
|
|
|
1891 |
|
|
|
1892 |
|
|
|
1893 |
/*
|
|
|
1894 |
READ AN ASSERT DIRECTIVE
|
|
|
1895 |
|
|
|
1896 |
This routine processes a '#assert' directive.
|
|
|
1897 |
*/
|
|
|
1898 |
|
|
|
1899 |
static void read_assert
|
|
|
1900 |
PROTO_N ( ( dir ) )
|
|
|
1901 |
PROTO_T ( int dir )
|
|
|
1902 |
{
|
|
|
1903 |
/* Read the predicate name */
|
|
|
1904 |
int def = 1 ;
|
|
|
1905 |
IDENTIFIER id ;
|
|
|
1906 |
PPTOKEN *p, *q ;
|
|
|
1907 |
int t = read_token () ;
|
|
|
1908 |
update_column () ;
|
|
|
1909 |
if ( in_preproc_dir ) preproc_loc = crt_loc ;
|
|
|
1910 |
if ( t != lex_identifier ) {
|
|
|
1911 |
report ( preproc_loc, ERR_pragma_assert_id ( dir ) ) ;
|
|
|
1912 |
return ;
|
|
|
1913 |
}
|
|
|
1914 |
id = make_assert ( token_hashid, lex_unknown ) ;
|
|
|
1915 |
|
|
|
1916 |
/* Read the predicate token sequence */
|
|
|
1917 |
t = read_token () ;
|
|
|
1918 |
update_column () ;
|
|
|
1919 |
if ( in_preproc_dir ) preproc_loc = crt_loc ;
|
|
|
1920 |
if ( t != lex_open_Hround ) {
|
|
|
1921 |
report ( preproc_loc, ERR_pragma_assert_open ( dir ) ) ;
|
|
|
1922 |
return ;
|
|
|
1923 |
}
|
|
|
1924 |
p = read_line ( lex_ignore_token, lex_ignore_token ) ;
|
|
|
1925 |
q = skip_predicate ( &p, dir ) ;
|
|
|
1926 |
if ( q ) {
|
|
|
1927 |
report ( preproc_loc, ERR_cpp_end ( dir ) ) ;
|
|
|
1928 |
free_tok_list ( q ) ;
|
|
|
1929 |
}
|
|
|
1930 |
|
|
|
1931 |
/* Create the assertion */
|
|
|
1932 |
if ( p ) set_assert ( id, p, def ) ;
|
|
|
1933 |
return ;
|
|
|
1934 |
}
|
|
|
1935 |
|
|
|
1936 |
|
|
|
1937 |
/*
|
|
|
1938 |
READ AN UNASSERT DIRECTIVE
|
|
|
1939 |
|
|
|
1940 |
This routine processes a '#unassert' directive.
|
|
|
1941 |
*/
|
|
|
1942 |
|
|
|
1943 |
static void read_unassert
|
|
|
1944 |
PROTO_N ( ( dir ) )
|
|
|
1945 |
PROTO_T ( int dir )
|
|
|
1946 |
{
|
|
|
1947 |
/* Read the predicate name */
|
|
|
1948 |
IDENTIFIER id ;
|
|
|
1949 |
PPTOKEN *p, *q ;
|
|
|
1950 |
int t = read_token () ;
|
|
|
1951 |
update_column () ;
|
|
|
1952 |
if ( in_preproc_dir ) preproc_loc = crt_loc ;
|
|
|
1953 |
if ( t != lex_identifier ) {
|
|
|
1954 |
report ( preproc_loc, ERR_pragma_assert_id ( dir ) ) ;
|
|
|
1955 |
return ;
|
|
|
1956 |
}
|
|
|
1957 |
id = make_assert ( token_hashid, lex_unknown ) ;
|
|
|
1958 |
|
|
|
1959 |
/* Check for simple identifier */
|
|
|
1960 |
t = read_token () ;
|
|
|
1961 |
update_column () ;
|
|
|
1962 |
if ( in_preproc_dir ) preproc_loc = crt_loc ;
|
|
|
1963 |
if ( t == lex_newline ) {
|
|
|
1964 |
p = NULL ;
|
|
|
1965 |
} else {
|
|
|
1966 |
/* Read the predicate token sequence */
|
|
|
1967 |
if ( t != lex_open_Hround ) {
|
|
|
1968 |
report ( preproc_loc, ERR_pragma_assert_open ( dir ) ) ;
|
|
|
1969 |
return ;
|
|
|
1970 |
}
|
|
|
1971 |
p = read_line ( lex_ignore_token, lex_ignore_token ) ;
|
|
|
1972 |
q = skip_predicate ( &p, dir ) ;
|
|
|
1973 |
if ( q ) {
|
|
|
1974 |
report ( preproc_loc, ERR_cpp_end ( dir ) ) ;
|
|
|
1975 |
free_tok_list ( q ) ;
|
|
|
1976 |
}
|
|
|
1977 |
}
|
|
|
1978 |
|
|
|
1979 |
if ( p == NULL ) {
|
|
|
1980 |
/* Unassert all values */
|
|
|
1981 |
LIST ( PPTOKEN_P ) r ;
|
|
|
1982 |
r = DEREF_list ( id_predicate_values ( id ) ) ;
|
|
|
1983 |
while ( !IS_NULL_list ( r ) ) {
|
|
|
1984 |
DESTROY_CONS_pptok ( destroy, q, r, r ) ;
|
|
|
1985 |
free_tok_list ( q ) ;
|
|
|
1986 |
}
|
|
|
1987 |
COPY_list ( id_predicate_values ( id ), r ) ;
|
|
|
1988 |
COPY_ulong ( id_no ( id ), lex_unknown ) ;
|
|
|
1989 |
} else {
|
|
|
1990 |
/* Destroy the assertion */
|
|
|
1991 |
set_assert ( id, p, 0 ) ;
|
|
|
1992 |
}
|
|
|
1993 |
return ;
|
|
|
1994 |
}
|
|
|
1995 |
|
|
|
1996 |
|
|
|
1997 |
/*
|
|
|
1998 |
LOOK UP AN IDENTIFIER IN A PRAGMA WEAK DIRECTIVE
|
|
|
1999 |
|
|
|
2000 |
This routine looks up the identifier named nm used in a '#pragma
|
|
|
2001 |
weak' directive. The result should be an external variable or
|
|
|
2002 |
function. The null identifier is returned to indicate an error.
|
|
|
2003 |
*/
|
|
|
2004 |
|
|
|
2005 |
static IDENTIFIER find_weak_id
|
|
|
2006 |
PROTO_N ( ( nm ) )
|
|
|
2007 |
PROTO_T ( HASHID nm )
|
|
|
2008 |
{
|
|
|
2009 |
if ( !IS_NULL_hashid ( nm ) ) {
|
|
|
2010 |
ERROR err ;
|
|
|
2011 |
IDENTIFIER id = find_id ( nm ) ;
|
|
|
2012 |
switch ( TAG_id ( id ) ) {
|
|
|
2013 |
case id_variable_tag : {
|
|
|
2014 |
DECL_SPEC ds = DEREF_dspec ( id_storage ( id ) ) ;
|
|
|
2015 |
if ( !( ds & dspec_auto ) ) {
|
|
|
2016 |
ds |= dspec_used ;
|
|
|
2017 |
COPY_dspec ( id_storage ( id ), ds ) ;
|
|
|
2018 |
return ( id ) ;
|
|
|
2019 |
}
|
|
|
2020 |
break ;
|
|
|
2021 |
}
|
|
|
2022 |
case id_function_tag : {
|
|
|
2023 |
TYPE t = DEREF_type ( id_function_type ( id ) ) ;
|
|
|
2024 |
IDENTIFIER over = DEREF_id ( id_function_over ( id ) ) ;
|
|
|
2025 |
if ( IS_NULL_id ( over ) && IS_type_func ( t ) ) {
|
|
|
2026 |
DECL_SPEC ds = DEREF_dspec ( id_storage ( id ) ) ;
|
|
|
2027 |
ds |= dspec_used ;
|
|
|
2028 |
COPY_dspec ( id_storage ( id ), ds ) ;
|
|
|
2029 |
return ( id ) ;
|
|
|
2030 |
}
|
|
|
2031 |
break ;
|
|
|
2032 |
}
|
|
|
2033 |
}
|
|
|
2034 |
err = ERR_pragma_preserve_undecl ( lex_weak, id ) ;
|
|
|
2035 |
report ( preproc_loc, err ) ;
|
|
|
2036 |
}
|
|
|
2037 |
return ( NULL_id ) ;
|
|
|
2038 |
}
|
|
|
2039 |
|
|
|
2040 |
|
|
|
2041 |
/*
|
|
|
2042 |
READ A PRAGMA WEAK DIRECTIVE
|
|
|
2043 |
|
|
|
2044 |
This routine processes a '#pragma weak' directive.
|
|
|
2045 |
*/
|
|
|
2046 |
|
|
|
2047 |
void read_weak
|
|
|
2048 |
PROTO_N ( ( dir ) )
|
|
|
2049 |
PROTO_T ( int dir )
|
|
|
2050 |
{
|
|
|
2051 |
IDENTIFIER id = NULL_id ;
|
|
|
2052 |
IDENTIFIER aid = NULL_id ;
|
|
|
2053 |
int t = read_token () ;
|
|
|
2054 |
update_column () ;
|
|
|
2055 |
if ( in_preproc_dir ) preproc_loc = crt_loc ;
|
|
|
2056 |
if ( t == lex_identifier ) {
|
|
|
2057 |
id = find_weak_id ( token_hashid ) ;
|
|
|
2058 |
t = read_token () ;
|
|
|
2059 |
update_column () ;
|
|
|
2060 |
if ( in_preproc_dir ) preproc_loc = crt_loc ;
|
|
|
2061 |
if ( t == lex_assign ) {
|
|
|
2062 |
t = read_token () ;
|
|
|
2063 |
update_column () ;
|
|
|
2064 |
if ( in_preproc_dir ) preproc_loc = crt_loc ;
|
|
|
2065 |
if ( t == lex_identifier ) {
|
|
|
2066 |
aid = find_weak_id ( token_hashid ) ;
|
|
|
2067 |
t = read_token () ;
|
|
|
2068 |
update_column () ;
|
|
|
2069 |
if ( in_preproc_dir ) preproc_loc = crt_loc ;
|
|
|
2070 |
}
|
|
|
2071 |
}
|
|
|
2072 |
} else {
|
|
|
2073 |
t = lex_unknown ;
|
|
|
2074 |
}
|
|
|
2075 |
if ( !IS_NULL_id ( aid ) ) {
|
|
|
2076 |
static LIST ( IDENTIFIER ) weak_ids = NULL_list ( IDENTIFIER ) ;
|
|
|
2077 |
LIST ( IDENTIFIER ) p = weak_ids ;
|
|
|
2078 |
while ( !IS_NULL_list ( p ) ) {
|
|
|
2079 |
IDENTIFIER pid = DEREF_id ( HEAD_list ( p ) ) ;
|
|
|
2080 |
if ( EQ_id ( id, pid ) ) {
|
|
|
2081 |
report ( preproc_loc, ERR_pragma_weak_redef ( id ) ) ;
|
|
|
2082 |
id = NULL_id ;
|
|
|
2083 |
break ;
|
|
|
2084 |
}
|
|
|
2085 |
p = TAIL_list ( p ) ;
|
|
|
2086 |
}
|
|
|
2087 |
if ( !IS_NULL_id ( id ) ) {
|
|
|
2088 |
CONS_id ( id, weak_ids, weak_ids ) ;
|
|
|
2089 |
}
|
|
|
2090 |
}
|
|
|
2091 |
compile_weak ( id, aid ) ;
|
|
|
2092 |
if ( t != lex_newline ) {
|
|
|
2093 |
report ( preproc_loc, ERR_cpp_end ( dir ) ) ;
|
|
|
2094 |
}
|
|
|
2095 |
if ( in_preproc_dir ) IGNORE skip_to_end () ;
|
|
|
2096 |
return ;
|
|
|
2097 |
}
|
|
|
2098 |
|
|
|
2099 |
|
|
|
2100 |
/*
|
|
|
2101 |
READ A PREPROCESSING DIRECTIVE
|
|
|
2102 |
|
|
|
2103 |
This routine processes a preprocessing directive up to and including
|
|
|
2104 |
the terminating newline character. The act argument indicates
|
|
|
2105 |
whether the directive is active or is being skipped in a conditional
|
|
|
2106 |
compilation. prev gives the previous preprocessing directive value.
|
|
|
2107 |
The routine returns a lexical token value which is used to
|
|
|
2108 |
communicate the effect of the directive on the main processor. Most
|
|
|
2109 |
directives are only visible to the preprocessor, and return one of
|
|
|
2110 |
the values lex_ignore_token, lex_end_condition or lex_included (note
|
|
|
2111 |
that these are all less than zero). Other directives (for example,
|
|
|
2112 |
target dependent conditionals) do communicate with the main
|
|
|
2113 |
processor by returning a valid lexical token value.
|
|
|
2114 |
*/
|
|
|
2115 |
|
|
|
2116 |
int read_preproc_dir
|
|
|
2117 |
PROTO_N ( ( act, prev ) )
|
|
|
2118 |
PROTO_T ( int act X int prev )
|
|
|
2119 |
{
|
|
|
2120 |
int t ;
|
|
|
2121 |
ERROR err ;
|
|
|
2122 |
HASHID dir ;
|
|
|
2123 |
int pp = lex_ignore_token ;
|
|
|
2124 |
in_preproc_dir = 1 ;
|
|
|
2125 |
preproc_loc = crt_loc ;
|
|
|
2126 |
|
|
|
2127 |
/* Read the token following the '#' */
|
|
|
2128 |
t = read_token () ;
|
|
|
2129 |
update_column () ;
|
|
|
2130 |
if ( in_preproc_dir ) preproc_loc = crt_loc ;
|
|
|
2131 |
if ( t != lex_identifier ) {
|
|
|
2132 |
if ( t == lex_newline || t == lex_eof ) {
|
|
|
2133 |
/* Warn about empty directives */
|
|
|
2134 |
report ( preproc_loc, ERR_cpp_null () ) ;
|
|
|
2135 |
goto end_label ;
|
|
|
2136 |
}
|
|
|
2137 |
/* Give an error for other directives */
|
|
|
2138 |
report ( preproc_loc, ERR_cpp_bad () ) ;
|
|
|
2139 |
goto end_label ;
|
|
|
2140 |
}
|
|
|
2141 |
|
|
|
2142 |
/* Analyse the '#identifier' directive */
|
|
|
2143 |
dir = token_hashid ;
|
|
|
2144 |
t = find_hashid ( dir ) ;
|
|
|
2145 |
switch ( t ) {
|
|
|
2146 |
|
|
|
2147 |
case lex_define : {
|
|
|
2148 |
/* Deal with '#define' */
|
|
|
2149 |
if ( act ) {
|
|
|
2150 |
pp = read_define () ;
|
|
|
2151 |
if ( pp >= 0 ) pp = patch_cond ( pp, t ) ;
|
|
|
2152 |
}
|
|
|
2153 |
goto end_label ;
|
|
|
2154 |
}
|
|
|
2155 |
|
|
|
2156 |
case lex_else :
|
|
|
2157 |
case lex_endif : {
|
|
|
2158 |
/* Deal with '#else' and '#endif' */
|
|
|
2159 |
if ( in_preproc_dir && skip_to_end () ) {
|
|
|
2160 |
/* Check end of directive */
|
|
|
2161 |
report ( preproc_loc, ERR_cpp_cond_endif_end ( t ) ) ;
|
|
|
2162 |
}
|
|
|
2163 |
pp = read_if ( t, PP_FALSE, lex_ignore_token ) ;
|
|
|
2164 |
if ( act && pp >= 0 ) pp = patch_cond ( pp, t ) ;
|
|
|
2165 |
return ( pp ) ;
|
|
|
2166 |
}
|
|
|
2167 |
|
|
|
2168 |
case lex_elif : {
|
|
|
2169 |
/* Deal with '#elif' (expression is read in read_if) */
|
|
|
2170 |
report ( preproc_loc, ERR_cpp_old ( t ) ) ;
|
|
|
2171 |
pp = read_if ( t, PP_FALSE, lex_ignore_token ) ;
|
|
|
2172 |
if ( act && pp >= 0 ) pp = patch_cond ( pp, t ) ;
|
|
|
2173 |
return ( pp ) ;
|
|
|
2174 |
}
|
|
|
2175 |
|
|
|
2176 |
case lex_error : {
|
|
|
2177 |
/* Deal with '#error' */
|
|
|
2178 |
report ( preproc_loc, ERR_cpp_old ( t ) ) ;
|
|
|
2179 |
if ( act ) read_error ( OPT_error ) ;
|
|
|
2180 |
goto end_label ;
|
|
|
2181 |
}
|
|
|
2182 |
|
|
|
2183 |
case lex_include : {
|
|
|
2184 |
/* Deal with '#include' */
|
|
|
2185 |
pp = read_include ( act, t ) ;
|
|
|
2186 |
return ( pp ) ;
|
|
|
2187 |
}
|
|
|
2188 |
|
|
|
2189 |
case lex_if : {
|
|
|
2190 |
/* Deal with '#if' */
|
|
|
2191 |
unsigned cond = read_if_exp ( act, t ) ;
|
|
|
2192 |
pp = read_if ( t, cond, lex_ignore_token ) ;
|
|
|
2193 |
if ( act && pp >= 0 ) pp = patch_cond ( pp, t ) ;
|
|
|
2194 |
return ( pp ) ;
|
|
|
2195 |
}
|
|
|
2196 |
|
|
|
2197 |
case lex_ifdef : {
|
|
|
2198 |
/* Deal with '#ifdef' */
|
|
|
2199 |
unsigned cond = read_if_def ( act, t, prev ) ;
|
|
|
2200 |
pp = read_if ( t, cond, prev ) ;
|
|
|
2201 |
if ( act && pp >= 0 ) pp = patch_cond ( pp, t ) ;
|
|
|
2202 |
return ( pp ) ;
|
|
|
2203 |
}
|
|
|
2204 |
|
|
|
2205 |
case lex_ifndef : {
|
|
|
2206 |
/* Deal with '#ifndef' */
|
|
|
2207 |
unsigned cond = read_if_def ( act, t, prev ) ;
|
|
|
2208 |
pp = read_if ( t, negate_cond ( cond ), prev ) ;
|
|
|
2209 |
if ( act && pp >= 0 ) pp = patch_cond ( pp, t ) ;
|
|
|
2210 |
return ( pp ) ;
|
|
|
2211 |
}
|
|
|
2212 |
|
|
|
2213 |
case lex_line : {
|
|
|
2214 |
/* Deal with '#line' */
|
|
|
2215 |
if ( act ) read_location ( t ) ;
|
|
|
2216 |
goto end_label ;
|
|
|
2217 |
}
|
|
|
2218 |
|
|
|
2219 |
case lex_pragma : {
|
|
|
2220 |
/* Deal with '#pragma' */
|
|
|
2221 |
if ( act ) {
|
|
|
2222 |
int ts = have_type_specifier ;
|
|
|
2223 |
int td = have_type_declaration ;
|
|
|
2224 |
int fd = have_func_declarator ;
|
|
|
2225 |
QUALIFIER cq = crt_id_qualifier ;
|
|
|
2226 |
in_pragma_dir = 1 ;
|
|
|
2227 |
pp = read_pragma () ;
|
|
|
2228 |
in_pragma_dir = 0 ;
|
|
|
2229 |
pragma_number = 0 ;
|
|
|
2230 |
crt_id_qualifier = cq ;
|
|
|
2231 |
have_type_specifier = ts ;
|
|
|
2232 |
have_type_declaration = td ;
|
|
|
2233 |
have_func_declarator = fd ;
|
|
|
2234 |
}
|
|
|
2235 |
goto end_label ;
|
|
|
2236 |
}
|
|
|
2237 |
|
|
|
2238 |
case lex_undef : {
|
|
|
2239 |
/* Deal with '#undef' */
|
|
|
2240 |
if ( act ) {
|
|
|
2241 |
pp = read_undef () ;
|
|
|
2242 |
if ( pp >= 0 ) pp = patch_cond ( pp, t ) ;
|
|
|
2243 |
}
|
|
|
2244 |
goto end_label ;
|
|
|
2245 |
}
|
|
|
2246 |
|
|
|
2247 |
case lex_assert : {
|
|
|
2248 |
/* Deal with '#assert' (extension) */
|
|
|
2249 |
OPTION opt = option ( OPT_ppdir_assert ) ;
|
|
|
2250 |
if ( opt != OPTION_DISALLOW ) {
|
|
|
2251 |
if ( opt != OPTION_ALLOW ) {
|
|
|
2252 |
err = ERR_pragma_cpp_known ( t ) ;
|
|
|
2253 |
err = set_severity ( err, OPT_ppdir_assert, 0 ) ;
|
|
|
2254 |
report ( preproc_loc, err ) ;
|
|
|
2255 |
}
|
|
|
2256 |
if ( act && !option ( OPT_ppdir_assert_ignore ) ) {
|
|
|
2257 |
read_assert ( t ) ;
|
|
|
2258 |
}
|
|
|
2259 |
goto end_label ;
|
|
|
2260 |
}
|
|
|
2261 |
break ;
|
|
|
2262 |
}
|
|
|
2263 |
|
|
|
2264 |
case lex_file : {
|
|
|
2265 |
/* Deal with '#file' (extension) */
|
|
|
2266 |
OPTION opt = option ( OPT_ppdir_file ) ;
|
|
|
2267 |
if ( opt != OPTION_DISALLOW ) {
|
|
|
2268 |
if ( opt != OPTION_ALLOW ) {
|
|
|
2269 |
err = ERR_pragma_cpp_known ( t ) ;
|
|
|
2270 |
err = set_severity ( err, OPT_ppdir_file, 0 ) ;
|
|
|
2271 |
report ( preproc_loc, err ) ;
|
|
|
2272 |
}
|
|
|
2273 |
if ( act && !option ( OPT_ppdir_file_ignore ) ) {
|
|
|
2274 |
read_location ( t ) ;
|
|
|
2275 |
}
|
|
|
2276 |
goto end_label ;
|
|
|
2277 |
}
|
|
|
2278 |
break ;
|
|
|
2279 |
}
|
|
|
2280 |
|
|
|
2281 |
case lex_ident : {
|
|
|
2282 |
/* Deal with '#ident' (extension) */
|
|
|
2283 |
OPTION opt = option ( OPT_ppdir_ident ) ;
|
|
|
2284 |
if ( opt != OPTION_DISALLOW ) {
|
|
|
2285 |
if ( opt != OPTION_ALLOW ) {
|
|
|
2286 |
err = ERR_pragma_cpp_known ( t ) ;
|
|
|
2287 |
err = set_severity ( err, OPT_ppdir_ident, 0 ) ;
|
|
|
2288 |
report ( preproc_loc, err ) ;
|
|
|
2289 |
}
|
|
|
2290 |
if ( act && !option ( OPT_ppdir_ident_ignore ) ) {
|
|
|
2291 |
read_ident ( t ) ;
|
|
|
2292 |
}
|
|
|
2293 |
goto end_label ;
|
|
|
2294 |
}
|
|
|
2295 |
break ;
|
|
|
2296 |
}
|
|
|
2297 |
|
|
|
2298 |
case lex_import :
|
|
|
2299 |
case lex_include_Hnext : {
|
|
|
2300 |
/* Deal with '#import' and '#include_next' (extension) */
|
|
|
2301 |
OPTION opt = option ( OPT_ppdir_import ) ;
|
|
|
2302 |
if ( opt != OPTION_DISALLOW ) {
|
|
|
2303 |
if ( opt != OPTION_ALLOW ) {
|
|
|
2304 |
err = ERR_pragma_cpp_known ( t ) ;
|
|
|
2305 |
err = set_severity ( err, OPT_ppdir_import, 0 ) ;
|
|
|
2306 |
report ( preproc_loc, err ) ;
|
|
|
2307 |
}
|
|
|
2308 |
if ( !option ( OPT_ppdir_import_ignore ) ) {
|
|
|
2309 |
pp = read_include ( act, t ) ;
|
|
|
2310 |
return ( pp ) ;
|
|
|
2311 |
}
|
|
|
2312 |
goto end_label ;
|
|
|
2313 |
}
|
|
|
2314 |
break ;
|
|
|
2315 |
}
|
|
|
2316 |
|
|
|
2317 |
case lex_unassert : {
|
|
|
2318 |
/* Deal with '#unassert' (extension) */
|
|
|
2319 |
OPTION opt = option ( OPT_ppdir_unassert ) ;
|
|
|
2320 |
if ( opt != OPTION_DISALLOW ) {
|
|
|
2321 |
if ( opt != OPTION_ALLOW ) {
|
|
|
2322 |
err = ERR_pragma_cpp_known ( t ) ;
|
|
|
2323 |
err = set_severity ( err, OPT_ppdir_unassert, 0 ) ;
|
|
|
2324 |
report ( preproc_loc, err ) ;
|
|
|
2325 |
}
|
|
|
2326 |
if ( act && !option ( OPT_ppdir_unassert_ignore ) ) {
|
|
|
2327 |
read_unassert ( t ) ;
|
|
|
2328 |
}
|
|
|
2329 |
goto end_label ;
|
|
|
2330 |
}
|
|
|
2331 |
break ;
|
|
|
2332 |
}
|
|
|
2333 |
|
|
|
2334 |
case lex_warning : {
|
|
|
2335 |
/* Deal with '#warning' (extension) */
|
|
|
2336 |
OPTION opt = option ( OPT_ppdir_warning ) ;
|
|
|
2337 |
if ( opt != OPTION_DISALLOW ) {
|
|
|
2338 |
if ( opt != OPTION_ALLOW ) {
|
|
|
2339 |
err = ERR_pragma_cpp_known ( t ) ;
|
|
|
2340 |
err = set_severity ( err, OPT_ppdir_warning, 0 ) ;
|
|
|
2341 |
report ( preproc_loc, err ) ;
|
|
|
2342 |
}
|
|
|
2343 |
if ( act && !option ( OPT_ppdir_warning_ignore ) ) {
|
|
|
2344 |
read_error ( OPT_warning ) ;
|
|
|
2345 |
}
|
|
|
2346 |
goto end_label ;
|
|
|
2347 |
}
|
|
|
2348 |
break ;
|
|
|
2349 |
}
|
|
|
2350 |
|
|
|
2351 |
case lex_weak : {
|
|
|
2352 |
/* Deal with '#weak' (extension) */
|
|
|
2353 |
OPTION opt = option ( OPT_ppdir_weak ) ;
|
|
|
2354 |
if ( opt != OPTION_DISALLOW ) {
|
|
|
2355 |
if ( opt != OPTION_ALLOW ) {
|
|
|
2356 |
err = ERR_pragma_cpp_known ( t ) ;
|
|
|
2357 |
err = set_severity ( err, OPT_ppdir_weak, 0 ) ;
|
|
|
2358 |
report ( preproc_loc, err ) ;
|
|
|
2359 |
}
|
|
|
2360 |
if ( act && !option ( OPT_ppdir_weak_ignore ) ) {
|
|
|
2361 |
read_weak ( t ) ;
|
|
|
2362 |
}
|
|
|
2363 |
goto end_label ;
|
|
|
2364 |
}
|
|
|
2365 |
break ;
|
|
|
2366 |
}
|
|
|
2367 |
}
|
|
|
2368 |
|
|
|
2369 |
/* Unknown directives */
|
|
|
2370 |
report ( preproc_loc, ERR_cpp_unknown ( dir ) ) ;
|
|
|
2371 |
end_label : {
|
|
|
2372 |
if ( in_preproc_dir ) IGNORE skip_to_end () ;
|
|
|
2373 |
return ( pp ) ;
|
|
|
2374 |
}
|
|
|
2375 |
}
|
|
|
2376 |
|
|
|
2377 |
|
|
|
2378 |
/*
|
|
|
2379 |
PREPROCESS A FILE
|
|
|
2380 |
|
|
|
2381 |
This routine gives the preprocessor entry point for the compiler. Each
|
|
|
2382 |
token is read, preprocessed, and printed. The white space in the output
|
|
|
2383 |
does not necessarily bear any resemblance to that in the input.
|
|
|
2384 |
*/
|
|
|
2385 |
|
|
|
2386 |
void preprocess_file
|
|
|
2387 |
PROTO_Z ()
|
|
|
2388 |
{
|
|
|
2389 |
int t ;
|
|
|
2390 |
FILE *f ;
|
|
|
2391 |
string fn ;
|
|
|
2392 |
BUFFER *bf ;
|
|
|
2393 |
unsigned long ws = 0 ;
|
|
|
2394 |
unsigned long ln = 0 ;
|
|
|
2395 |
int force_space = preproc_space ;
|
|
|
2396 |
static BUFFER preproc_buff = { NULL, NULL, NULL, NULL } ;
|
|
|
2397 |
|
|
|
2398 |
/* Initialise input file */
|
|
|
2399 |
init_lex () ;
|
|
|
2400 |
fn = DEREF_string ( posn_file ( preproc_loc.posn ) ) ;
|
|
|
2401 |
|
|
|
2402 |
/* Open output file */
|
|
|
2403 |
if ( !open_output ( OUTPUT_PREPROC, text_mode ) ) {
|
|
|
2404 |
string nm = output_name [ OUTPUT_PREPROC ] ;
|
|
|
2405 |
fail ( ERR_fail_output ( nm ) ) ;
|
|
|
2406 |
term_error ( 0 ) ;
|
|
|
2407 |
return ;
|
|
|
2408 |
}
|
|
|
2409 |
f = output_file [ OUTPUT_PREPROC ] ;
|
|
|
2410 |
bf = clear_buffer ( &preproc_buff, f ) ;
|
|
|
2411 |
fprintf_v ( f, "#line 1 \"%s\"", strlit ( fn ) ) ;
|
|
|
2412 |
crt_file_changed = 1 ;
|
|
|
2413 |
|
|
|
2414 |
/* Scan through preprocessing tokens */
|
|
|
2415 |
while ( t = expand_preproc ( EXPAND_NORMAL ), t != lex_eof ) {
|
|
|
2416 |
/* Allow for skipped files */
|
|
|
2417 |
if ( crt_file_type ) continue ;
|
|
|
2418 |
|
|
|
2419 |
/* Replace keywords by underlying identifier */
|
|
|
2420 |
if ( t >= FIRST_KEYWORD && t <= LAST_KEYWORD ) {
|
|
|
2421 |
crt_token->tok = lex_identifier ;
|
|
|
2422 |
}
|
|
|
2423 |
if ( t == lex_builtin_Hfile ) {
|
|
|
2424 |
fputc_v ( '\n', f ) ;
|
|
|
2425 |
ln++ ;
|
|
|
2426 |
crt_line_changed = 1 ;
|
|
|
2427 |
crt_spaces = 0 ;
|
|
|
2428 |
continue ;
|
|
|
2429 |
}
|
|
|
2430 |
|
|
|
2431 |
/* Print any required '#line' directives */
|
|
|
2432 |
if ( crt_line_changed ) {
|
|
|
2433 |
int ch = crt_file_changed ;
|
|
|
2434 |
unsigned long n = crt_loc.line ;
|
|
|
2435 |
unsigned long sp = crt_spaces ;
|
|
|
2436 |
unsigned long tab = tab_width ;
|
|
|
2437 |
output_buffer ( bf, 0 ) ;
|
|
|
2438 |
if ( ch ) {
|
|
|
2439 |
string fm = DEREF_string ( posn_file ( crt_loc.posn ) ) ;
|
|
|
2440 |
if ( ch > 1 || !ustreq ( fn, fm ) ) {
|
|
|
2441 |
char *s = strlit ( fm ) ;
|
|
|
2442 |
fprintf_v ( f, "\n\n#line %lu \"%s\"\n", n, s ) ;
|
|
|
2443 |
fn = fm ;
|
|
|
2444 |
ln = n ;
|
|
|
2445 |
}
|
|
|
2446 |
crt_file_changed = 0 ;
|
|
|
2447 |
}
|
|
|
2448 |
if ( n != ln ) {
|
|
|
2449 |
if ( n > ln && n <= ln + 10 ) {
|
|
|
2450 |
for ( ; ln < n ; ln++ ) fputc_v ( '\n', f ) ;
|
|
|
2451 |
} else {
|
|
|
2452 |
/* Force '#line' for more than 10 blank lines */
|
|
|
2453 |
fprintf_v ( f, "\n\n#line %lu\n", n ) ;
|
|
|
2454 |
}
|
|
|
2455 |
ln = n ;
|
|
|
2456 |
}
|
|
|
2457 |
crt_line_changed = 0 ;
|
|
|
2458 |
|
|
|
2459 |
/* Print indentation */
|
|
|
2460 |
ws = sp ;
|
|
|
2461 |
for ( ; sp >= tab ; sp -= tab ) bfputc ( bf, '\t' ) ;
|
|
|
2462 |
for ( ; sp ; sp-- ) bfputc ( bf, ' ' ) ;
|
|
|
2463 |
|
|
|
2464 |
/* Allow for hash symbols */
|
|
|
2465 |
if ( t == lex_hash_H1 ) crt_token->tok = lex_hash_Hhash_H1 ;
|
|
|
2466 |
if ( t == lex_hash_H2 ) crt_token->tok = lex_hash_Hhash_H2 ;
|
|
|
2467 |
|
|
|
2468 |
} else {
|
|
|
2469 |
unsigned long sp = crt_spaces ;
|
|
|
2470 |
if ( sp != ws || force_space ) {
|
|
|
2471 |
/* Print space */
|
|
|
2472 |
ws = sp ;
|
|
|
2473 |
bfputc ( bf, ' ' ) ;
|
|
|
2474 |
}
|
|
|
2475 |
}
|
|
|
2476 |
|
|
|
2477 |
/* Print the token name */
|
|
|
2478 |
IGNORE print_pptok ( crt_token, bf, 0 ) ;
|
|
|
2479 |
}
|
|
|
2480 |
bfputc ( bf, '\n' ) ;
|
|
|
2481 |
output_buffer ( bf, 0 ) ;
|
|
|
2482 |
close_output ( OUTPUT_PREPROC ) ;
|
|
|
2483 |
return ;
|
|
|
2484 |
}
|