/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 | 47 | { |
71 | | /* Points to name of symbol. */ |
72 | 47 | char *name; |
73 | | /* Points to symbol. */ |
74 | 47 | symbolS *symbolP; |
75 | 47 | struct conditional_frame cframe; |
76 | 47 | char c; |
77 | | |
78 | | /* Leading whitespace is part of operand. */ |
79 | 47 | SKIP_WHITESPACE (); |
80 | 47 | name = input_line_pointer; |
81 | | |
82 | 47 | 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 | 45 | c = get_symbol_name (& name); |
91 | 45 | symbolP = symbol_find (name); |
92 | 45 | (void) restore_line_pointer (c); |
93 | | |
94 | 45 | initialize_cframe (&cframe); |
95 | | |
96 | 45 | if (cframe.dead_tree) |
97 | 0 | cframe.ignoring = 1; |
98 | 45 | else |
99 | 45 | { |
100 | 45 | 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 | 45 | is_defined = |
106 | 45 | symbolP != NULL |
107 | 16 | && (S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP)) |
108 | 16 | && S_GET_SEGMENT (symbolP) != reg_section; |
109 | | |
110 | 45 | cframe.ignoring = ! (test_defined ^ is_defined); |
111 | 45 | } |
112 | | |
113 | 45 | current_cframe = obstack_alloc (&cond_obstack, sizeof cframe); |
114 | 45 | memcpy (current_cframe, &cframe, sizeof cframe); |
115 | | |
116 | 45 | 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 | 45 | demand_empty_rest_of_line (); |
123 | 45 | } |
124 | | |
125 | | void |
126 | | s_if (int arg) |
127 | 2.82k | { |
128 | 2.82k | expressionS operand; |
129 | 2.82k | struct conditional_frame cframe; |
130 | 2.82k | int t; |
131 | 2.82k | char *stop = NULL; |
132 | 2.82k | char stopc = 0; |
133 | | |
134 | 2.82k | if (flag_mri) |
135 | 2.74k | stop = mri_comment_field (&stopc); |
136 | | |
137 | | /* Leading whitespace is part of operand. */ |
138 | 2.82k | SKIP_WHITESPACE (); |
139 | | |
140 | 2.82k | if (current_cframe != NULL && current_cframe->ignoring) |
141 | 2.79k | { |
142 | 2.79k | operand.X_add_number = 0; |
143 | 38.0k | while (! is_end_of_stmt (*input_line_pointer)) |
144 | 35.2k | ++input_line_pointer; |
145 | 2.79k | } |
146 | 29 | else |
147 | 29 | { |
148 | 29 | expression_and_evaluate (&operand); |
149 | 29 | if (operand.X_op != O_constant) |
150 | 26 | as_bad (_("non-constant expression in \".if\" statement")); |
151 | 29 | } |
152 | | |
153 | 2.82k | switch ((operatorT) arg) |
154 | 2.82k | { |
155 | 6 | case O_eq: t = operand.X_add_number == 0; break; |
156 | 2.80k | case O_ne: t = operand.X_add_number != 0; break; |
157 | 0 | case O_lt: t = operand.X_add_number < 0; break; |
158 | 12 | 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 | 2.82k | } |
165 | | |
166 | | /* If the above error is signaled, this will dispatch |
167 | | using an undefined result. No big deal. */ |
168 | 2.82k | initialize_cframe (&cframe); |
169 | 2.82k | cframe.ignoring = cframe.dead_tree || ! t; |
170 | 2.82k | current_cframe = obstack_alloc (&cond_obstack, sizeof cframe); |
171 | 2.82k | memcpy (current_cframe, & cframe, sizeof cframe); |
172 | | |
173 | 2.82k | 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 | 2.82k | if (flag_mri) |
180 | 2.74k | mri_comment_end (stop, stopc); |
181 | | |
182 | 2.82k | demand_empty_rest_of_line (); |
183 | 2.82k | } |
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 | 2.34k | { |
191 | 2.34k | struct conditional_frame cframe; |
192 | | |
193 | 2.34k | initialize_cframe (&cframe); |
194 | | |
195 | 2.34k | if (cframe.dead_tree) |
196 | 0 | cframe.ignoring = 1; |
197 | 2.34k | else |
198 | 2.34k | { |
199 | 2.34k | int is_eol; |
200 | | |
201 | 2.34k | SKIP_WHITESPACE (); |
202 | 2.34k | is_eol = is_end_of_stmt (*input_line_pointer); |
203 | 2.34k | cframe.ignoring = (test_blank == !is_eol); |
204 | 2.34k | } |
205 | | |
206 | 2.34k | current_cframe = obstack_alloc (&cond_obstack, sizeof cframe); |
207 | 2.34k | memcpy (current_cframe, &cframe, sizeof cframe); |
208 | | |
209 | 2.34k | 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 | 2.34k | ignore_rest_of_line (); |
216 | 2.34k | } |
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 | 896 | { |
223 | 896 | char *ret; |
224 | 896 | char *s; |
225 | | |
226 | 896 | SKIP_WHITESPACE (); |
227 | 896 | s = ret = input_line_pointer; |
228 | 896 | if (*input_line_pointer == '\'') |
229 | 0 | { |
230 | 0 | ++s; |
231 | 0 | ++input_line_pointer; |
232 | 0 | while (! is_end_of_stmt (*input_line_pointer)) |
233 | 0 | { |
234 | 0 | *s++ = *input_line_pointer++; |
235 | 0 | if (s[-1] == '\'') |
236 | 0 | { |
237 | 0 | if (*input_line_pointer != '\'') |
238 | 0 | break; |
239 | 0 | ++input_line_pointer; |
240 | 0 | } |
241 | 0 | } |
242 | 0 | SKIP_WHITESPACE (); |
243 | 0 | } |
244 | 896 | else |
245 | 896 | { |
246 | 6.60k | while (*input_line_pointer != terminator |
247 | 6.16k | && ! is_end_of_stmt (*input_line_pointer)) |
248 | 5.71k | ++input_line_pointer; |
249 | 896 | s = input_line_pointer; |
250 | 952 | while (s > ret && is_whitespace (s[-1])) |
251 | 56 | --s; |
252 | 896 | } |
253 | | |
254 | 896 | *len = s - ret; |
255 | 896 | return ret; |
256 | 896 | } |
257 | | |
258 | | /* The MRI IFC and IFNC pseudo-ops. */ |
259 | | |
260 | | void |
261 | | s_ifc (int arg) |
262 | 448 | { |
263 | 448 | char *stop = NULL; |
264 | 448 | char stopc = 0; |
265 | 448 | char *s1, *s2; |
266 | 448 | int len1, len2; |
267 | 448 | int res; |
268 | 448 | struct conditional_frame cframe; |
269 | | |
270 | 448 | if (flag_mri) |
271 | 448 | stop = mri_comment_field (&stopc); |
272 | | |
273 | 448 | s1 = get_mri_string (',', &len1); |
274 | | |
275 | 448 | if (*input_line_pointer != ',') |
276 | 0 | as_bad (_("bad format for ifc or ifnc")); |
277 | 448 | else |
278 | 448 | ++input_line_pointer; |
279 | | |
280 | 448 | s2 = get_mri_string (';', &len2); |
281 | | |
282 | 448 | res = len1 == len2 && strncmp (s1, s2, len1) == 0; |
283 | | |
284 | 448 | initialize_cframe (&cframe); |
285 | 448 | cframe.ignoring = cframe.dead_tree || ! (res ^ arg); |
286 | 448 | current_cframe = obstack_alloc (&cond_obstack, sizeof cframe); |
287 | 448 | memcpy (current_cframe, &cframe, sizeof cframe); |
288 | | |
289 | 448 | 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 | 448 | if (flag_mri) |
296 | 448 | mri_comment_end (stop, stopc); |
297 | | |
298 | 448 | demand_empty_rest_of_line (); |
299 | 448 | } |
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 | 2.23k | { |
379 | 2.23k | struct conditional_frame *hold; |
380 | | |
381 | 2.23k | if (current_cframe == NULL) |
382 | 53 | { |
383 | 53 | as_bad (_("\".endif\" without \".if\"")); |
384 | 53 | } |
385 | 2.18k | else |
386 | 2.18k | { |
387 | 2.18k | 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 | 2.18k | hold = current_cframe; |
394 | 2.18k | current_cframe = current_cframe->previous_cframe; |
395 | 2.18k | obstack_free (&cond_obstack, hold); |
396 | 2.18k | } /* if one pop too many */ |
397 | | |
398 | 2.23k | if (flag_mri) |
399 | 2.23k | { |
400 | 2.50k | while (! is_end_of_stmt (*input_line_pointer)) |
401 | 267 | ++input_line_pointer; |
402 | 2.23k | } |
403 | | |
404 | 2.23k | demand_empty_rest_of_line (); |
405 | 2.23k | } |
406 | | |
407 | | void |
408 | | s_else (int arg ATTRIBUTE_UNUSED) |
409 | 3.96k | { |
410 | 3.96k | if (current_cframe == NULL) |
411 | 26 | { |
412 | 26 | as_bad (_("\".else\" without matching \".if\"")); |
413 | 26 | } |
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 | 3.96k | if (flag_mri) |
446 | 23 | { |
447 | 71 | while (! is_end_of_stmt (*input_line_pointer)) |
448 | 48 | ++input_line_pointer; |
449 | 23 | } |
450 | | |
451 | 3.96k | demand_empty_rest_of_line (); |
452 | 3.96k | } |
453 | | |
454 | | void |
455 | | s_ifeqs (int arg) |
456 | 114 | { |
457 | 114 | char *s1, *s2; |
458 | 114 | int len1, len2; |
459 | 114 | int res; |
460 | 114 | struct conditional_frame cframe; |
461 | | |
462 | 114 | s1 = demand_copy_C_string (&len1); |
463 | 114 | if (s1 == NULL) |
464 | 28 | { |
465 | 28 | ignore_rest_of_line (); |
466 | 28 | return; |
467 | 28 | } |
468 | | |
469 | 86 | SKIP_WHITESPACE (); |
470 | 86 | if (*input_line_pointer != ',') |
471 | 10 | { |
472 | 10 | as_bad (_(".ifeqs syntax error")); |
473 | 10 | ignore_rest_of_line (); |
474 | 10 | return; |
475 | 10 | } |
476 | | |
477 | 76 | ++input_line_pointer; |
478 | | |
479 | 76 | s2 = demand_copy_C_string (&len2); |
480 | 76 | if (s2 == NULL) |
481 | 10 | { |
482 | 10 | ignore_rest_of_line (); |
483 | 10 | return; |
484 | 10 | } |
485 | | |
486 | 66 | res = len1 == len2 && strncmp (s1, s2, len1) == 0; |
487 | | |
488 | 66 | initialize_cframe (&cframe); |
489 | 66 | cframe.ignoring = cframe.dead_tree || ! (res ^ arg); |
490 | 66 | current_cframe = obstack_alloc (&cond_obstack, sizeof cframe); |
491 | 66 | memcpy (current_cframe, &cframe, sizeof cframe); |
492 | | |
493 | 66 | 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 | 66 | demand_empty_rest_of_line (); |
500 | 66 | } |
501 | | |
502 | | int |
503 | | ignore_input (void) |
504 | 681k | { |
505 | 681k | char *s; |
506 | | |
507 | 681k | s = input_line_pointer; |
508 | | |
509 | 681k | if (NO_PSEUDO_DOT || flag_m68k_mri) |
510 | 0 | { |
511 | 0 | if (s[-1] != '.') |
512 | 0 | --s; |
513 | 0 | } |
514 | 681k | else |
515 | 681k | { |
516 | 681k | if (s[-1] != '.') |
517 | 281k | return current_cframe != NULL && current_cframe->ignoring; |
518 | 681k | } |
519 | | |
520 | | /* We cannot ignore certain pseudo ops. */ |
521 | 399k | switch (s[0]) |
522 | 399k | { |
523 | 26.1k | case 'i': case 'I': |
524 | 26.1k | if (s[1] == 'f' || s[1] == 'F') |
525 | 5.84k | return 0; |
526 | 20.2k | break; |
527 | 93.6k | case 'e': case 'E': |
528 | 93.6k | if (!strncasecmp (s, "else", 4) |
529 | 81.7k | || !strncasecmp (s, "endif", 5) |
530 | 79.0k | || !strncasecmp (s, "endc", 4)) |
531 | 14.6k | return 0; |
532 | 78.9k | break; |
533 | 91.7k | case 'l': case 'L': |
534 | 91.7k | if (!strncasecmp (s, "linefile", 8)) |
535 | 81.8k | return 0; |
536 | 9.84k | break; |
537 | 399k | } |
538 | | |
539 | 297k | return current_cframe != NULL && current_cframe->ignoring; |
540 | 399k | } |
541 | | |
542 | | static void |
543 | | initialize_cframe (struct conditional_frame *cframe) |
544 | 5.73k | { |
545 | 5.73k | memset (cframe, 0, sizeof (*cframe)); |
546 | 5.73k | cframe->if_file_line.file = as_where (&cframe->if_file_line.line); |
547 | 5.73k | cframe->previous_cframe = current_cframe; |
548 | 5.73k | cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring; |
549 | 5.73k | cframe->macro_nest = macro_nest; |
550 | 5.73k | } |
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 | 656 | { |
560 | 656 | if (current_cframe != NULL && current_cframe->macro_nest >= nest) |
561 | 38 | { |
562 | 38 | if (nest >= 0) |
563 | 4 | as_bad (_("end of macro inside conditional")); |
564 | 34 | else |
565 | 34 | as_bad (_("end of file inside conditional")); |
566 | | |
567 | 38 | as_bad_where (current_cframe->if_file_line.file, |
568 | 38 | current_cframe->if_file_line.line, |
569 | 38 | _("here is the start of the unterminated conditional")); |
570 | 38 | 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 | 38 | cond_exit_macro (nest); |
575 | 38 | } |
576 | 656 | } |
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 | 51 | { |
585 | 3.59k | while (current_cframe != NULL && current_cframe->macro_nest >= nest) |
586 | 3.54k | { |
587 | 3.54k | struct conditional_frame *hold; |
588 | | |
589 | 3.54k | hold = current_cframe; |
590 | 3.54k | current_cframe = current_cframe->previous_cframe; |
591 | 3.54k | obstack_free (&cond_obstack, hold); |
592 | 3.54k | } |
593 | 51 | } |