PageRenderTime 40ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/contrib/binutils-2.25/gas/cond.c

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