cond.c 14 KB

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