/src/binutils-gdb/gas/cond.c
Line | Count | Source |
1 | | /* cond.c - conditional assembly pseudo-ops, and .include |
2 | | Copyright (C) 1990-2026 Free Software Foundation, Inc. |
3 | | |
4 | | This file is part of GAS, the GNU Assembler. |
5 | | |
6 | | GAS is free software; you can redistribute it and/or modify |
7 | | it under the terms of the GNU General Public License as published by |
8 | | the Free Software Foundation; either version 3, or (at your option) |
9 | | any later version. |
10 | | |
11 | | GAS is distributed in the hope that it will be useful, |
12 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | GNU General Public License for more details. |
15 | | |
16 | | You should have received a copy of the GNU General Public License |
17 | | along with GAS; see the file COPYING. If not, write to the Free |
18 | | Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA |
19 | | 02110-1301, USA. */ |
20 | | |
21 | | #include "as.h" |
22 | | #include "sb.h" |
23 | | #include "macro.h" |
24 | | |
25 | | #include "obstack.h" |
26 | | |
27 | | /* This is allocated to grow and shrink as .ifdef/.endif pairs are |
28 | | scanned. */ |
29 | | struct obstack cond_obstack; |
30 | | |
31 | | struct file_line |
32 | | { |
33 | | const char *file; |
34 | | unsigned int line; |
35 | | }; |
36 | | |
37 | | /* We push one of these structures for each .if, and pop it at the |
38 | | .endif. */ |
39 | | |
40 | | struct conditional_frame |
41 | | { |
42 | | /* The source file & line number of the "if". */ |
43 | | struct file_line if_file_line; |
44 | | /* The source file & line of the "else". */ |
45 | | struct file_line else_file_line; |
46 | | /* The previous conditional. */ |
47 | | struct conditional_frame *previous_cframe; |
48 | | /* Have we seen an else yet? */ |
49 | | int else_seen; |
50 | | /* Whether we are currently ignoring input. */ |
51 | | int ignoring; |
52 | | /* Whether a conditional at a higher level is ignoring input. |
53 | | Set also when a branch of an "if .. elseif .." tree has matched |
54 | | to prevent further matches. */ |
55 | | int dead_tree; |
56 | | /* Macro nesting level at which this conditional was created. */ |
57 | | int macro_nest; |
58 | | }; |
59 | | |
60 | | static void initialize_cframe (struct conditional_frame *cframe); |
61 | | static char *get_mri_string (int, int *); |
62 | | |
63 | | static struct conditional_frame *current_cframe = NULL; |
64 | | |
65 | | /* Performs the .ifdef (test_defined == 1) and |
66 | | the .ifndef (test_defined == 0) pseudo op. */ |
67 | | |
68 | | void |
69 | | s_ifdef (int test_defined) |
70 | 46 | { |
71 | | /* Points to name of symbol. */ |
72 | 46 | char *name; |
73 | | /* Points to symbol. */ |
74 | 46 | symbolS *symbolP; |
75 | 46 | struct conditional_frame cframe; |
76 | 46 | char c; |
77 | | |
78 | | /* Leading whitespace is part of operand. */ |
79 | 46 | SKIP_WHITESPACE (); |
80 | 46 | name = input_line_pointer; |
81 | | |
82 | 46 | if (!is_name_beginner (*name) && *name != '"') |
83 | 2 | { |
84 | 2 | as_bad (_("invalid identifier for \".ifdef\"")); |
85 | 2 | obstack_1grow (&cond_obstack, 0); |
86 | 2 | ignore_rest_of_line (); |
87 | 2 | return; |
88 | 2 | } |
89 | | |
90 | 44 | c = get_symbol_name (& name); |
91 | 44 | symbolP = symbol_find (name); |
92 | 44 | (void) restore_line_pointer (c); |
93 | | |
94 | 44 | initialize_cframe (&cframe); |
95 | | |
96 | 44 | if (cframe.dead_tree) |
97 | 0 | cframe.ignoring = 1; |
98 | 44 | else |
99 | 44 | { |
100 | 44 | int is_defined; |
101 | | |
102 | | /* Use the same definition of 'defined' as .equiv so that a symbol |
103 | | which has been referenced but not yet given a value/address is |
104 | | considered to be undefined. */ |
105 | 44 | is_defined = |
106 | 44 | symbolP != NULL |
107 | 16 | && (S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP)) |
108 | 16 | && S_GET_SEGMENT (symbolP) != reg_section; |
109 | | |
110 | 44 | cframe.ignoring = ! (test_defined ^ is_defined); |
111 | 44 | } |
112 | | |
113 | 44 | current_cframe = obstack_alloc (&cond_obstack, sizeof cframe); |
114 | 44 | memcpy (current_cframe, &cframe, sizeof cframe); |
115 | | |
116 | 44 | if (LISTING_SKIP_COND () |
117 | 0 | && cframe.ignoring |
118 | 0 | && (cframe.previous_cframe == NULL |
119 | 0 | || ! cframe.previous_cframe->ignoring)) |
120 | 0 | listing_list (2); |
121 | | |
122 | 44 | demand_empty_rest_of_line (); |
123 | 44 | } |
124 | | |
125 | | void |
126 | | s_if (int arg) |
127 | 5.70k | { |
128 | 5.70k | expressionS operand; |
129 | 5.70k | struct conditional_frame cframe; |
130 | 5.70k | int t; |
131 | 5.70k | char *stop = NULL; |
132 | 5.70k | char stopc = 0; |
133 | | |
134 | 5.70k | if (flag_mri) |
135 | 2.75k | stop = mri_comment_field (&stopc); |
136 | | |
137 | | /* Leading whitespace is part of operand. */ |
138 | 5.70k | SKIP_WHITESPACE (); |
139 | | |
140 | 5.70k | if (current_cframe != NULL && current_cframe->ignoring) |
141 | 5.46k | { |
142 | 5.46k | operand.X_add_number = 0; |
143 | 76.4k | while (! is_end_of_stmt (*input_line_pointer)) |
144 | 71.0k | ++input_line_pointer; |
145 | 5.46k | } |
146 | 239 | else |
147 | 239 | { |
148 | 239 | expression_and_evaluate (&operand); |
149 | 239 | if (operand.X_op != O_constant) |
150 | 236 | as_bad (_("non-constant expression in \".if\" statement")); |
151 | 239 | } |
152 | | |
153 | 5.70k | switch ((operatorT) arg) |
154 | 5.70k | { |
155 | 214 | case O_eq: t = operand.X_add_number == 0; break; |
156 | 5.47k | case O_ne: t = operand.X_add_number != 0; break; |
157 | 8 | case O_lt: t = operand.X_add_number < 0; break; |
158 | 11 | case O_le: t = operand.X_add_number <= 0; break; |
159 | 0 | case O_ge: t = operand.X_add_number >= 0; break; |
160 | 0 | case O_gt: t = operand.X_add_number > 0; break; |
161 | 0 | default: |
162 | 0 | abort (); |
163 | 0 | return; |
164 | 5.70k | } |
165 | | |
166 | | /* If the above error is signaled, this will dispatch |
167 | | using an undefined result. No big deal. */ |
168 | 5.70k | initialize_cframe (&cframe); |
169 | 5.70k | cframe.ignoring = cframe.dead_tree || ! t; |
170 | 5.70k | current_cframe = obstack_alloc (&cond_obstack, sizeof cframe); |
171 | 5.70k | memcpy (current_cframe, & cframe, sizeof cframe); |
172 | | |
173 | 5.70k | if (LISTING_SKIP_COND () |
174 | 0 | && cframe.ignoring |
175 | 0 | && (cframe.previous_cframe == NULL |
176 | 0 | || ! cframe.previous_cframe->ignoring)) |
177 | 0 | listing_list (2); |
178 | | |
179 | 5.70k | if (flag_mri) |
180 | 2.75k | mri_comment_end (stop, stopc); |
181 | | |
182 | 5.70k | demand_empty_rest_of_line (); |
183 | 5.70k | } |
184 | | |
185 | | /* Performs the .ifb (test_blank == 1) and |
186 | | the .ifnb (test_blank == 0) pseudo op. */ |
187 | | |
188 | | void |
189 | | s_ifb (int test_blank) |
190 | 1.97k | { |
191 | 1.97k | struct conditional_frame cframe; |
192 | | |
193 | 1.97k | initialize_cframe (&cframe); |
194 | | |
195 | 1.97k | if (cframe.dead_tree) |
196 | 0 | cframe.ignoring = 1; |
197 | 1.97k | else |
198 | 1.97k | { |
199 | 1.97k | int is_eol; |
200 | | |
201 | 1.97k | SKIP_WHITESPACE (); |
202 | 1.97k | is_eol = is_end_of_stmt (*input_line_pointer); |
203 | 1.97k | cframe.ignoring = (test_blank == !is_eol); |
204 | 1.97k | } |
205 | | |
206 | 1.97k | current_cframe = obstack_alloc (&cond_obstack, sizeof cframe); |
207 | 1.97k | memcpy (current_cframe, &cframe, sizeof cframe); |
208 | | |
209 | 1.97k | if (LISTING_SKIP_COND () |
210 | 0 | && cframe.ignoring |
211 | 0 | && (cframe.previous_cframe == NULL |
212 | 0 | || ! cframe.previous_cframe->ignoring)) |
213 | 0 | listing_list (2); |
214 | | |
215 | 1.97k | ignore_rest_of_line (); |
216 | 1.97k | } |
217 | | |
218 | | /* Get a string for the MRI IFC or IFNC pseudo-ops. */ |
219 | | |
220 | | static char * |
221 | | get_mri_string (int terminator, int *len) |
222 | 48 | { |
223 | 48 | char *ret; |
224 | 48 | char *s; |
225 | | |
226 | 48 | SKIP_WHITESPACE (); |
227 | 48 | s = ret = input_line_pointer; |
228 | 48 | if (*input_line_pointer == '\'') |
229 | 23 | { |
230 | 23 | ++s; |
231 | 23 | ++input_line_pointer; |
232 | 76 | while (! is_end_of_stmt (*input_line_pointer)) |
233 | 74 | { |
234 | 74 | *s++ = *input_line_pointer++; |
235 | 74 | if (s[-1] == '\'') |
236 | 21 | { |
237 | 21 | if (*input_line_pointer != '\'') |
238 | 21 | break; |
239 | 0 | ++input_line_pointer; |
240 | 0 | } |
241 | 74 | } |
242 | 23 | SKIP_WHITESPACE (); |
243 | 23 | } |
244 | 25 | else |
245 | 25 | { |
246 | 63 | while (*input_line_pointer != terminator |
247 | 63 | && ! is_end_of_stmt (*input_line_pointer)) |
248 | 38 | ++input_line_pointer; |
249 | 25 | s = input_line_pointer; |
250 | 25 | while (s > ret && is_whitespace (s[-1])) |
251 | 0 | --s; |
252 | 25 | } |
253 | | |
254 | 48 | *len = s - ret; |
255 | 48 | return ret; |
256 | 48 | } |
257 | | |
258 | | /* The MRI IFC and IFNC pseudo-ops. */ |
259 | | |
260 | | void |
261 | | s_ifc (int arg) |
262 | 24 | { |
263 | 24 | char *stop = NULL; |
264 | 24 | char stopc = 0; |
265 | 24 | char *s1, *s2; |
266 | 24 | int len1, len2; |
267 | 24 | int res; |
268 | 24 | struct conditional_frame cframe; |
269 | | |
270 | 24 | if (flag_mri) |
271 | 24 | stop = mri_comment_field (&stopc); |
272 | | |
273 | 24 | s1 = get_mri_string (',', &len1); |
274 | | |
275 | 24 | if (*input_line_pointer != ',') |
276 | 24 | as_bad (_("bad format for ifc or ifnc")); |
277 | 0 | else |
278 | 0 | ++input_line_pointer; |
279 | | |
280 | 24 | s2 = get_mri_string (';', &len2); |
281 | | |
282 | 24 | res = len1 == len2 && strncmp (s1, s2, len1) == 0; |
283 | | |
284 | 24 | initialize_cframe (&cframe); |
285 | 24 | cframe.ignoring = cframe.dead_tree || ! (res ^ arg); |
286 | 24 | current_cframe = obstack_alloc (&cond_obstack, sizeof cframe); |
287 | 24 | memcpy (current_cframe, &cframe, sizeof cframe); |
288 | | |
289 | 24 | if (LISTING_SKIP_COND () |
290 | 0 | && cframe.ignoring |
291 | 0 | && (cframe.previous_cframe == NULL |
292 | 0 | || ! cframe.previous_cframe->ignoring)) |
293 | 0 | listing_list (2); |
294 | | |
295 | 24 | if (flag_mri) |
296 | 24 | mri_comment_end (stop, stopc); |
297 | | |
298 | 24 | demand_empty_rest_of_line (); |
299 | 24 | } |
300 | | |
301 | | void |
302 | | s_elseif (int arg) |
303 | 5.91k | { |
304 | 5.91k | if (current_cframe == NULL) |
305 | 3 | { |
306 | 3 | as_bad (_("\".elseif\" without matching \".if\"")); |
307 | 3 | } |
308 | 5.90k | else if (current_cframe->else_seen) |
309 | 0 | { |
310 | 0 | as_bad (_("\".elseif\" after \".else\"")); |
311 | 0 | as_bad_where (current_cframe->else_file_line.file, |
312 | 0 | current_cframe->else_file_line.line, |
313 | 0 | _("here is the previous \".else\"")); |
314 | 0 | as_bad_where (current_cframe->if_file_line.file, |
315 | 0 | current_cframe->if_file_line.line, |
316 | 0 | _("here is the previous \".if\"")); |
317 | 0 | } |
318 | 5.90k | else |
319 | 5.90k | { |
320 | 5.90k | current_cframe->else_file_line.file |
321 | 5.90k | = as_where (¤t_cframe->else_file_line.line); |
322 | | |
323 | 5.90k | current_cframe->dead_tree |= !current_cframe->ignoring; |
324 | 5.90k | current_cframe->ignoring = current_cframe->dead_tree; |
325 | 5.90k | } |
326 | | |
327 | 5.91k | if (current_cframe == NULL || current_cframe->ignoring) |
328 | 3 | { |
329 | 6 | while (! is_end_of_stmt (*input_line_pointer)) |
330 | 3 | ++input_line_pointer; |
331 | | |
332 | 3 | if (current_cframe == NULL) |
333 | 3 | return; |
334 | 3 | } |
335 | 5.90k | else |
336 | 5.90k | { |
337 | 5.90k | expressionS operand; |
338 | 5.90k | int t; |
339 | | |
340 | | /* Leading whitespace is part of operand. */ |
341 | 5.90k | SKIP_WHITESPACE (); |
342 | | |
343 | 5.90k | expression_and_evaluate (&operand); |
344 | 5.90k | if (operand.X_op != O_constant) |
345 | 5.90k | as_bad (_("non-constant expression in \".elseif\" statement")); |
346 | | |
347 | 5.90k | switch (arg) |
348 | 5.90k | { |
349 | 0 | case O_eq: t = operand.X_add_number == 0; break; |
350 | 5.90k | case O_ne: t = operand.X_add_number != 0; break; |
351 | 0 | case O_lt: t = operand.X_add_number < 0; break; |
352 | 0 | case O_le: t = operand.X_add_number <= 0; break; |
353 | 0 | case O_ge: t = operand.X_add_number >= 0; break; |
354 | 0 | case O_gt: t = operand.X_add_number > 0; break; |
355 | 0 | default: |
356 | 0 | abort (); |
357 | 0 | return; |
358 | 5.90k | } |
359 | | |
360 | 5.90k | current_cframe->ignoring = current_cframe->dead_tree || ! t; |
361 | 5.90k | } |
362 | | |
363 | 5.90k | if (LISTING_SKIP_COND () |
364 | 0 | && (current_cframe->previous_cframe == NULL |
365 | 0 | || ! current_cframe->previous_cframe->ignoring)) |
366 | 0 | { |
367 | 0 | if (! current_cframe->ignoring) |
368 | 0 | listing_list (1); |
369 | 0 | else |
370 | 0 | listing_list (2); |
371 | 0 | } |
372 | | |
373 | 5.90k | demand_empty_rest_of_line (); |
374 | 5.90k | } |
375 | | |
376 | | void |
377 | | s_endif (int arg ATTRIBUTE_UNUSED) |
378 | 4.12k | { |
379 | 4.12k | struct conditional_frame *hold; |
380 | | |
381 | 4.12k | if (current_cframe == NULL) |
382 | 29 | { |
383 | 29 | as_bad (_("\".endif\" without \".if\"")); |
384 | 29 | } |
385 | 4.09k | else |
386 | 4.09k | { |
387 | 4.09k | if (LISTING_SKIP_COND () |
388 | 0 | && current_cframe->ignoring |
389 | 0 | && (current_cframe->previous_cframe == NULL |
390 | 0 | || ! current_cframe->previous_cframe->ignoring)) |
391 | 0 | listing_list (1); |
392 | | |
393 | 4.09k | hold = current_cframe; |
394 | 4.09k | current_cframe = current_cframe->previous_cframe; |
395 | 4.09k | obstack_free (&cond_obstack, hold); |
396 | 4.09k | } /* if one pop too many */ |
397 | | |
398 | 4.12k | if (flag_mri) |
399 | 2.19k | { |
400 | 2.23k | while (! is_end_of_stmt (*input_line_pointer)) |
401 | 39 | ++input_line_pointer; |
402 | 2.19k | } |
403 | | |
404 | 4.12k | demand_empty_rest_of_line (); |
405 | 4.12k | } |
406 | | |
407 | | void |
408 | | s_else (int arg ATTRIBUTE_UNUSED) |
409 | 4.09k | { |
410 | 4.09k | if (current_cframe == NULL) |
411 | 152 | { |
412 | 152 | as_bad (_("\".else\" without matching \".if\"")); |
413 | 152 | } |
414 | 3.94k | else if (current_cframe->else_seen) |
415 | 1.96k | { |
416 | 1.96k | as_bad (_("duplicate \".else\"")); |
417 | 1.96k | as_bad_where (current_cframe->else_file_line.file, |
418 | 1.96k | current_cframe->else_file_line.line, |
419 | 1.96k | _("here is the previous \".else\"")); |
420 | 1.96k | as_bad_where (current_cframe->if_file_line.file, |
421 | 1.96k | current_cframe->if_file_line.line, |
422 | 1.96k | _("here is the previous \".if\"")); |
423 | 1.96k | } |
424 | 1.97k | else |
425 | 1.97k | { |
426 | 1.97k | current_cframe->else_file_line.file |
427 | 1.97k | = as_where (¤t_cframe->else_file_line.line); |
428 | | |
429 | 1.97k | current_cframe->ignoring = |
430 | 1.97k | current_cframe->dead_tree | !current_cframe->ignoring; |
431 | | |
432 | 1.97k | if (LISTING_SKIP_COND () |
433 | 0 | && (current_cframe->previous_cframe == NULL |
434 | 0 | || ! current_cframe->previous_cframe->ignoring)) |
435 | 0 | { |
436 | 0 | if (! current_cframe->ignoring) |
437 | 0 | listing_list (1); |
438 | 0 | else |
439 | 0 | listing_list (2); |
440 | 0 | } |
441 | | |
442 | 1.97k | current_cframe->else_seen = 1; |
443 | 1.97k | } |
444 | | |
445 | 4.09k | if (flag_mri) |
446 | 4.08k | { |
447 | 4.13k | while (! is_end_of_stmt (*input_line_pointer)) |
448 | 48 | ++input_line_pointer; |
449 | 4.08k | } |
450 | | |
451 | 4.09k | demand_empty_rest_of_line (); |
452 | 4.09k | } |
453 | | |
454 | | void |
455 | | s_ifeqs (int arg) |
456 | 37 | { |
457 | 37 | char *s1, *s2; |
458 | 37 | int len1, len2; |
459 | 37 | int res; |
460 | 37 | struct conditional_frame cframe; |
461 | | |
462 | 37 | s1 = demand_copy_C_string (&len1); |
463 | 37 | if (s1 == NULL) |
464 | 19 | { |
465 | 19 | ignore_rest_of_line (); |
466 | 19 | return; |
467 | 19 | } |
468 | | |
469 | 18 | SKIP_WHITESPACE (); |
470 | 18 | if (*input_line_pointer != ',') |
471 | 2 | { |
472 | 2 | as_bad (_(".ifeqs syntax error")); |
473 | 2 | ignore_rest_of_line (); |
474 | 2 | return; |
475 | 2 | } |
476 | | |
477 | 16 | ++input_line_pointer; |
478 | | |
479 | 16 | s2 = demand_copy_C_string (&len2); |
480 | 16 | if (s2 == NULL) |
481 | 15 | { |
482 | 15 | ignore_rest_of_line (); |
483 | 15 | return; |
484 | 15 | } |
485 | | |
486 | 1 | res = len1 == len2 && strncmp (s1, s2, len1) == 0; |
487 | | |
488 | 1 | initialize_cframe (&cframe); |
489 | 1 | cframe.ignoring = cframe.dead_tree || ! (res ^ arg); |
490 | 1 | current_cframe = obstack_alloc (&cond_obstack, sizeof cframe); |
491 | 1 | memcpy (current_cframe, &cframe, sizeof cframe); |
492 | | |
493 | 1 | if (LISTING_SKIP_COND () |
494 | 0 | && cframe.ignoring |
495 | 0 | && (cframe.previous_cframe == NULL |
496 | 0 | || ! cframe.previous_cframe->ignoring)) |
497 | 0 | listing_list (2); |
498 | | |
499 | 1 | demand_empty_rest_of_line (); |
500 | 1 | } |
501 | | |
502 | | int |
503 | | ignore_input (void) |
504 | 811k | { |
505 | 811k | char *s; |
506 | | |
507 | 811k | s = input_line_pointer; |
508 | | |
509 | 811k | if (NO_PSEUDO_DOT || flag_m68k_mri) |
510 | 0 | { |
511 | 0 | if (s[-1] != '.') |
512 | 0 | --s; |
513 | 0 | } |
514 | 811k | else |
515 | 811k | { |
516 | 811k | if (s[-1] != '.') |
517 | 363k | return current_cframe != NULL && current_cframe->ignoring; |
518 | 811k | } |
519 | | |
520 | | /* We cannot ignore certain pseudo ops. */ |
521 | 448k | switch (s[0]) |
522 | 448k | { |
523 | 29.3k | case 'i': case 'I': |
524 | 29.3k | if (s[1] == 'f' || s[1] == 'F') |
525 | 7.83k | return 0; |
526 | 21.5k | break; |
527 | 95.4k | case 'e': case 'E': |
528 | 95.4k | if (!strncasecmp (s, "else", 4) |
529 | 83.5k | || !strncasecmp (s, "endif", 5) |
530 | 78.2k | || !strncasecmp (s, "endc", 4)) |
531 | 17.2k | return 0; |
532 | 78.2k | break; |
533 | 99.2k | case 'l': case 'L': |
534 | 99.2k | if (!strncasecmp (s, "linefile", 8)) |
535 | 88.9k | return 0; |
536 | 10.2k | break; |
537 | 448k | } |
538 | | |
539 | 334k | return current_cframe != NULL && current_cframe->ignoring; |
540 | 448k | } |
541 | | |
542 | | static void |
543 | | initialize_cframe (struct conditional_frame *cframe) |
544 | 7.74k | { |
545 | 7.74k | memset (cframe, 0, sizeof (*cframe)); |
546 | 7.74k | cframe->if_file_line.file = as_where (&cframe->if_file_line.line); |
547 | 7.74k | cframe->previous_cframe = current_cframe; |
548 | 7.74k | cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring; |
549 | 7.74k | cframe->macro_nest = macro_nest; |
550 | 7.74k | } |
551 | | |
552 | | /* Give an error if a conditional is unterminated inside a macro or |
553 | | the assembly as a whole. If NEST is non negative, we are being |
554 | | called because of the end of a macro expansion. If NEST is |
555 | | negative, we are being called at the of the input files. */ |
556 | | |
557 | | void |
558 | | cond_finish_check (int nest) |
559 | 619 | { |
560 | 619 | if (current_cframe != NULL && current_cframe->macro_nest >= nest) |
561 | 40 | { |
562 | 40 | if (nest >= 0) |
563 | 4 | as_bad (_("end of macro inside conditional")); |
564 | 36 | else |
565 | 36 | as_bad (_("end of file inside conditional")); |
566 | | |
567 | 40 | as_bad_where (current_cframe->if_file_line.file, |
568 | 40 | current_cframe->if_file_line.line, |
569 | 40 | _("here is the start of the unterminated conditional")); |
570 | 40 | if (current_cframe->else_seen) |
571 | 0 | as_bad_where (current_cframe->else_file_line.file, |
572 | 0 | current_cframe->else_file_line.line, |
573 | 0 | _("here is the \"else\" of the unterminated conditional")); |
574 | 40 | cond_exit_macro (nest); |
575 | 40 | } |
576 | 619 | } |
577 | | |
578 | | /* This function is called when we exit out of a macro. We assume |
579 | | that any conditionals which began within the macro are correctly |
580 | | nested, and just pop them off the stack. */ |
581 | | |
582 | | void |
583 | | cond_exit_macro (int nest) |
584 | 53 | { |
585 | 3.70k | while (current_cframe != NULL && current_cframe->macro_nest >= nest) |
586 | 3.65k | { |
587 | 3.65k | struct conditional_frame *hold; |
588 | | |
589 | 3.65k | hold = current_cframe; |
590 | 3.65k | current_cframe = current_cframe->previous_cframe; |
591 | 3.65k | obstack_free (&cond_obstack, hold); |
592 | 3.65k | } |
593 | 53 | } |