Mercurial > hg > CbC > CbC_gcc
annotate gcc/tree-browser.c @ 63:b7f97abdc517 gcc-4.6-20100522
update gcc from gcc-4.5.0 to gcc-4.6
author | ryoma <e075725@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 24 May 2010 12:47:05 +0900 |
parents | a06113de4d67 |
children | f6334be47118 |
rev | line source |
---|---|
0 | 1 /* Tree browser. |
63
b7f97abdc517
update gcc from gcc-4.5.0 to gcc-4.6
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2 Copyright (C) 2002, 2003, 2004, 2007, 2008, 2010 |
b7f97abdc517
update gcc from gcc-4.5.0 to gcc-4.6
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
3 Free Software Foundation, Inc. |
0 | 4 Contributed by Sebastian Pop <s.pop@laposte.net> |
5 | |
6 This file is part of GCC. | |
7 | |
8 GCC is free software; you can redistribute it and/or modify it under | |
9 the terms of the GNU General Public License as published by the Free | |
10 Software Foundation; either version 3, or (at your option) any later | |
11 version. | |
12 | |
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 for more details. | |
17 | |
18 You should have received a copy of the GNU General Public License | |
19 along with GCC; see the file COPYING3. If not see | |
20 <http://www.gnu.org/licenses/>. */ | |
21 | |
22 #include "config.h" | |
23 #include "system.h" | |
24 #include "coretypes.h" | |
25 #include "tm.h" | |
26 #include "tree.h" | |
27 #include "tree-inline.h" | |
28 #include "diagnostic.h" | |
63
b7f97abdc517
update gcc from gcc-4.5.0 to gcc-4.6
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
29 #include "tree-pretty-print.h" |
0 | 30 #include "hashtab.h" |
31 | |
32 | |
33 #define TB_OUT_FILE stdout | |
34 #define TB_IN_FILE stdin | |
35 #define TB_NIY fprintf (TB_OUT_FILE, "Sorry this command is not yet implemented.\n") | |
36 #define TB_WF fprintf (TB_OUT_FILE, "Warning, this command failed.\n") | |
37 | |
38 | |
39 /* Structures for handling Tree Browser's commands. */ | |
40 #define DEFTBCODE(COMMAND, STRING, HELP) COMMAND, | |
41 enum TB_Comm_code { | |
42 #include "tree-browser.def" | |
43 TB_UNUSED_COMMAND | |
44 }; | |
45 #undef DEFTBCODE | |
46 typedef enum TB_Comm_code TB_CODE; | |
47 | |
48 struct tb_command { | |
49 const char *help_msg; | |
50 const char *comm_text; | |
51 size_t comm_len; | |
52 TB_CODE comm_code; | |
53 }; | |
54 | |
55 #define DEFTBCODE(code, str, help) { help, str, sizeof(str) - 1, code }, | |
56 static const struct tb_command tb_commands[] = | |
57 { | |
58 #include "tree-browser.def" | |
59 }; | |
60 #undef DEFTBCODE | |
61 | |
62 #define TB_COMMAND_LEN(N) (tb_commands[N].comm_len) | |
63 #define TB_COMMAND_TEXT(N) (tb_commands[N].comm_text) | |
64 #define TB_COMMAND_CODE(N) (tb_commands[N].comm_code) | |
65 #define TB_COMMAND_HELP(N) (tb_commands[N].help_msg) | |
66 | |
67 | |
68 /* Next structure is for parsing TREE_CODEs. */ | |
69 struct tb_tree_code { | |
70 enum tree_code code; | |
71 const char *code_string; | |
72 size_t code_string_len; | |
73 }; | |
74 | |
75 #define DEFTREECODE(SYM, STRING, TYPE, NARGS) { SYM, STRING, sizeof (STRING) - 1 }, | |
76 #define END_OF_BASE_TREE_CODES \ | |
77 { LAST_AND_UNUSED_TREE_CODE, "@dummy", sizeof ("@dummy") - 1 }, | |
78 static const struct tb_tree_code tb_tree_codes[] = | |
79 { | |
80 #include "all-tree.def" | |
81 }; | |
82 #undef DEFTREECODE | |
83 #undef END_OF_BASE_TREE_CODES | |
84 | |
85 #define TB_TREE_CODE(N) (tb_tree_codes[N].code) | |
86 #define TB_TREE_CODE_TEXT(N) (tb_tree_codes[N].code_string) | |
87 #define TB_TREE_CODE_LEN(N) (tb_tree_codes[N].code_string_len) | |
88 | |
89 | |
90 /* Function declarations. */ | |
91 | |
92 static long TB_getline (char **, long *, FILE *); | |
93 static TB_CODE TB_get_command (char *); | |
94 static enum tree_code TB_get_tree_code (char *); | |
95 static tree find_node_with_code (tree *, int *, void *); | |
96 static tree store_child_info (tree *, int *, void *); | |
97 static void TB_update_up (tree); | |
98 static tree TB_current_chain_node (tree); | |
99 static tree TB_prev_expr (tree); | |
100 static tree TB_next_expr (tree); | |
101 static tree TB_up_expr (tree); | |
102 static tree TB_first_in_bind (tree); | |
103 static tree TB_last_in_bind (tree); | |
104 static int TB_parent_eq (const void *, const void *); | |
105 static tree TB_history_prev (void); | |
106 | |
107 /* FIXME: To be declared in a .h file. */ | |
108 void browse_tree (tree); | |
109 | |
110 /* Static variables. */ | |
111 static htab_t TB_up_ht; | |
112 static tree TB_history_stack = NULL_TREE; | |
113 static int TB_verbose = 1; | |
114 | |
115 | |
116 /* Entry point in the Tree Browser. */ | |
117 | |
118 void | |
119 browse_tree (tree begin) | |
120 { | |
121 tree head; | |
122 TB_CODE tbc = TB_UNUSED_COMMAND; | |
123 ssize_t rd; | |
124 char *input = NULL; | |
125 long input_size = 0; | |
126 | |
127 fprintf (TB_OUT_FILE, "\nTree Browser\n"); | |
128 | |
129 #define TB_SET_HEAD(N) do { \ | |
130 TB_history_stack = tree_cons (NULL_TREE, (N), TB_history_stack); \ | |
131 head = N; \ | |
132 if (TB_verbose) \ | |
133 if (head) \ | |
134 { \ | |
135 print_generic_expr (TB_OUT_FILE, head, 0); \ | |
136 fprintf (TB_OUT_FILE, "\n"); \ | |
137 } \ | |
138 } while (0) | |
139 | |
140 TB_SET_HEAD (begin); | |
141 | |
142 /* Store in a hashtable information about previous and upper statements. */ | |
143 { | |
144 TB_up_ht = htab_create (1023, htab_hash_pointer, &TB_parent_eq, NULL); | |
145 TB_update_up (head); | |
146 } | |
147 | |
148 while (24) | |
149 { | |
150 fprintf (TB_OUT_FILE, "TB> "); | |
151 rd = TB_getline (&input, &input_size, TB_IN_FILE); | |
152 | |
153 if (rd == -1) | |
154 /* EOF. */ | |
155 goto ret; | |
156 | |
157 if (rd != 1) | |
158 /* Get a new command. Otherwise the user just pressed enter, and thus | |
159 she expects the last command to be reexecuted. */ | |
160 tbc = TB_get_command (input); | |
161 | |
162 switch (tbc) | |
163 { | |
164 case TB_UPDATE_UP: | |
165 TB_update_up (head); | |
166 break; | |
167 | |
168 case TB_MAX: | |
169 if (head && (INTEGRAL_TYPE_P (head) | |
170 || TREE_CODE (head) == REAL_TYPE | |
171 || TREE_CODE (head) == FIXED_POINT_TYPE)) | |
172 TB_SET_HEAD (TYPE_MAX_VALUE (head)); | |
173 else | |
174 TB_WF; | |
175 break; | |
176 | |
177 case TB_MIN: | |
178 if (head && (INTEGRAL_TYPE_P (head) | |
179 || TREE_CODE (head) == REAL_TYPE | |
180 || TREE_CODE (head) == FIXED_POINT_TYPE)) | |
181 TB_SET_HEAD (TYPE_MIN_VALUE (head)); | |
182 else | |
183 TB_WF; | |
184 break; | |
185 | |
186 case TB_ELT: | |
187 if (head && TREE_CODE (head) == TREE_VEC) | |
188 { | |
189 /* This command takes another argument: the element number: | |
190 for example "elt 1". */ | |
191 TB_NIY; | |
192 } | |
193 else if (head && TREE_CODE (head) == VECTOR_CST) | |
194 { | |
195 /* This command takes another argument: the element number: | |
196 for example "elt 1". */ | |
197 TB_NIY; | |
198 } | |
199 else | |
200 TB_WF; | |
201 break; | |
202 | |
203 case TB_VALUE: | |
204 if (head && TREE_CODE (head) == TREE_LIST) | |
205 TB_SET_HEAD (TREE_VALUE (head)); | |
206 else | |
207 TB_WF; | |
208 break; | |
209 | |
210 case TB_PURPOSE: | |
211 if (head && TREE_CODE (head) == TREE_LIST) | |
212 TB_SET_HEAD (TREE_PURPOSE (head)); | |
213 else | |
214 TB_WF; | |
215 break; | |
216 | |
217 case TB_IMAG: | |
218 if (head && TREE_CODE (head) == COMPLEX_CST) | |
219 TB_SET_HEAD (TREE_IMAGPART (head)); | |
220 else | |
221 TB_WF; | |
222 break; | |
223 | |
224 case TB_REAL: | |
225 if (head && TREE_CODE (head) == COMPLEX_CST) | |
226 TB_SET_HEAD (TREE_REALPART (head)); | |
227 else | |
228 TB_WF; | |
229 break; | |
230 | |
231 case TB_BLOCK: | |
232 if (head && TREE_CODE (head) == BIND_EXPR) | |
233 TB_SET_HEAD (TREE_OPERAND (head, 2)); | |
234 else | |
235 TB_WF; | |
236 break; | |
237 | |
238 case TB_SUBBLOCKS: | |
239 if (head && TREE_CODE (head) == BLOCK) | |
240 TB_SET_HEAD (BLOCK_SUBBLOCKS (head)); | |
241 else | |
242 TB_WF; | |
243 break; | |
244 | |
245 case TB_SUPERCONTEXT: | |
246 if (head && TREE_CODE (head) == BLOCK) | |
247 TB_SET_HEAD (BLOCK_SUPERCONTEXT (head)); | |
248 else | |
249 TB_WF; | |
250 break; | |
251 | |
252 case TB_VARS: | |
253 if (head && TREE_CODE (head) == BLOCK) | |
254 TB_SET_HEAD (BLOCK_VARS (head)); | |
255 else if (head && TREE_CODE (head) == BIND_EXPR) | |
256 TB_SET_HEAD (TREE_OPERAND (head, 0)); | |
257 else | |
258 TB_WF; | |
259 break; | |
260 | |
261 case TB_REFERENCE_TO_THIS: | |
262 if (head && TYPE_P (head)) | |
263 TB_SET_HEAD (TYPE_REFERENCE_TO (head)); | |
264 else | |
265 TB_WF; | |
266 break; | |
267 | |
268 case TB_POINTER_TO_THIS: | |
269 if (head && TYPE_P (head)) | |
270 TB_SET_HEAD (TYPE_POINTER_TO (head)); | |
271 else | |
272 TB_WF; | |
273 break; | |
274 | |
275 case TB_BASETYPE: | |
276 if (head && TREE_CODE (head) == OFFSET_TYPE) | |
277 TB_SET_HEAD (TYPE_OFFSET_BASETYPE (head)); | |
278 else | |
279 TB_WF; | |
280 break; | |
281 | |
282 case TB_ARG_TYPES: | |
283 if (head && (TREE_CODE (head) == FUNCTION_TYPE | |
284 || TREE_CODE (head) == METHOD_TYPE)) | |
285 TB_SET_HEAD (TYPE_ARG_TYPES (head)); | |
286 else | |
287 TB_WF; | |
288 break; | |
289 | |
290 case TB_METHOD_BASE_TYPE: | |
291 if (head && (TREE_CODE (head) == FUNCTION_TYPE | |
292 || TREE_CODE (head) == METHOD_TYPE) | |
293 && TYPE_METHOD_BASETYPE (head)) | |
294 TB_SET_HEAD (TYPE_METHOD_BASETYPE (head)); | |
295 else | |
296 TB_WF; | |
297 break; | |
298 | |
299 case TB_FIELDS: | |
300 if (head && (TREE_CODE (head) == RECORD_TYPE | |
301 || TREE_CODE (head) == UNION_TYPE | |
302 || TREE_CODE (head) == QUAL_UNION_TYPE)) | |
303 TB_SET_HEAD (TYPE_FIELDS (head)); | |
304 else | |
305 TB_WF; | |
306 break; | |
307 | |
308 case TB_DOMAIN: | |
309 if (head && TREE_CODE (head) == ARRAY_TYPE) | |
310 TB_SET_HEAD (TYPE_DOMAIN (head)); | |
311 else | |
312 TB_WF; | |
313 break; | |
314 | |
315 case TB_VALUES: | |
316 if (head && TREE_CODE (head) == ENUMERAL_TYPE) | |
317 TB_SET_HEAD (TYPE_VALUES (head)); | |
318 else | |
319 TB_WF; | |
320 break; | |
321 | |
322 case TB_ARG_TYPE: | |
323 if (head && TREE_CODE (head) == PARM_DECL) | |
324 TB_SET_HEAD (DECL_ARG_TYPE (head)); | |
325 else | |
326 TB_WF; | |
327 break; | |
328 | |
329 case TB_INITIAL: | |
330 if (head && DECL_P (head)) | |
331 TB_SET_HEAD (DECL_INITIAL (head)); | |
332 else | |
333 TB_WF; | |
334 break; | |
335 | |
336 case TB_RESULT: | |
337 if (head && DECL_P (head)) | |
338 TB_SET_HEAD (DECL_RESULT_FLD (head)); | |
339 else | |
340 TB_WF; | |
341 break; | |
342 | |
343 case TB_ARGUMENTS: | |
344 if (head && DECL_P (head)) | |
345 TB_SET_HEAD (DECL_ARGUMENTS (head)); | |
346 else | |
347 TB_WF; | |
348 break; | |
349 | |
350 case TB_ABSTRACT_ORIGIN: | |
351 if (head && DECL_P (head)) | |
352 TB_SET_HEAD (DECL_ABSTRACT_ORIGIN (head)); | |
353 else if (head && TREE_CODE (head) == BLOCK) | |
354 TB_SET_HEAD (BLOCK_ABSTRACT_ORIGIN (head)); | |
355 else | |
356 TB_WF; | |
357 break; | |
358 | |
359 case TB_ATTRIBUTES: | |
360 if (head && DECL_P (head)) | |
361 TB_SET_HEAD (DECL_ATTRIBUTES (head)); | |
362 else if (head && TYPE_P (head)) | |
363 TB_SET_HEAD (TYPE_ATTRIBUTES (head)); | |
364 else | |
365 TB_WF; | |
366 break; | |
367 | |
368 case TB_CONTEXT: | |
369 if (head && DECL_P (head)) | |
370 TB_SET_HEAD (DECL_CONTEXT (head)); | |
371 else if (head && TYPE_P (head) | |
372 && TYPE_CONTEXT (head)) | |
373 TB_SET_HEAD (TYPE_CONTEXT (head)); | |
374 else | |
375 TB_WF; | |
376 break; | |
377 | |
378 case TB_OFFSET: | |
379 if (head && TREE_CODE (head) == FIELD_DECL) | |
380 TB_SET_HEAD (DECL_FIELD_OFFSET (head)); | |
381 else | |
382 TB_WF; | |
383 break; | |
384 | |
385 case TB_BIT_OFFSET: | |
386 if (head && TREE_CODE (head) == FIELD_DECL) | |
387 TB_SET_HEAD (DECL_FIELD_BIT_OFFSET (head)); | |
388 else | |
389 TB_WF; | |
390 break; | |
391 | |
392 case TB_UNIT_SIZE: | |
393 if (head && DECL_P (head)) | |
394 TB_SET_HEAD (DECL_SIZE_UNIT (head)); | |
395 else if (head && TYPE_P (head)) | |
396 TB_SET_HEAD (TYPE_SIZE_UNIT (head)); | |
397 else | |
398 TB_WF; | |
399 break; | |
400 | |
401 case TB_SIZE: | |
402 if (head && DECL_P (head)) | |
403 TB_SET_HEAD (DECL_SIZE (head)); | |
404 else if (head && TYPE_P (head)) | |
405 TB_SET_HEAD (TYPE_SIZE (head)); | |
406 else | |
407 TB_WF; | |
408 break; | |
409 | |
410 case TB_TYPE: | |
411 if (head && TREE_TYPE (head)) | |
412 TB_SET_HEAD (TREE_TYPE (head)); | |
413 else | |
414 TB_WF; | |
415 break; | |
416 | |
417 case TB_DECL_SAVED_TREE: | |
418 if (head && TREE_CODE (head) == FUNCTION_DECL | |
419 && DECL_SAVED_TREE (head)) | |
420 TB_SET_HEAD (DECL_SAVED_TREE (head)); | |
421 else | |
422 TB_WF; | |
423 break; | |
424 | |
425 case TB_BODY: | |
426 if (head && TREE_CODE (head) == BIND_EXPR) | |
427 TB_SET_HEAD (TREE_OPERAND (head, 1)); | |
428 else | |
429 TB_WF; | |
430 break; | |
431 | |
432 case TB_CHILD_0: | |
433 if (head && EXPR_P (head) && TREE_OPERAND (head, 0)) | |
434 TB_SET_HEAD (TREE_OPERAND (head, 0)); | |
435 else | |
436 TB_WF; | |
437 break; | |
438 | |
439 case TB_CHILD_1: | |
440 if (head && EXPR_P (head) && TREE_OPERAND (head, 1)) | |
441 TB_SET_HEAD (TREE_OPERAND (head, 1)); | |
442 else | |
443 TB_WF; | |
444 break; | |
445 | |
446 case TB_CHILD_2: | |
447 if (head && EXPR_P (head) && TREE_OPERAND (head, 2)) | |
448 TB_SET_HEAD (TREE_OPERAND (head, 2)); | |
449 else | |
450 TB_WF; | |
451 break; | |
452 | |
453 case TB_CHILD_3: | |
454 if (head && EXPR_P (head) && TREE_OPERAND (head, 3)) | |
455 TB_SET_HEAD (TREE_OPERAND (head, 3)); | |
456 else | |
457 TB_WF; | |
458 break; | |
459 | |
460 case TB_PRINT: | |
461 if (head) | |
462 debug_tree (head); | |
463 else | |
464 TB_WF; | |
465 break; | |
466 | |
467 case TB_PRETTY_PRINT: | |
468 if (head) | |
469 { | |
470 print_generic_stmt (TB_OUT_FILE, head, 0); | |
471 fprintf (TB_OUT_FILE, "\n"); | |
472 } | |
473 else | |
474 TB_WF; | |
475 break; | |
476 | |
477 case TB_SEARCH_NAME: | |
478 | |
479 break; | |
480 | |
481 case TB_SEARCH_CODE: | |
482 { | |
483 enum tree_code code; | |
484 char *arg_text; | |
485 | |
486 arg_text = strchr (input, ' '); | |
487 if (arg_text == NULL) | |
488 { | |
489 fprintf (TB_OUT_FILE, "First argument is missing. This isn't a valid search command. \n"); | |
490 break; | |
491 } | |
492 code = TB_get_tree_code (arg_text + 1); | |
493 | |
494 /* Search in the subtree a node with the given code. */ | |
495 { | |
496 tree res; | |
497 | |
498 res = walk_tree (&head, find_node_with_code, &code, NULL); | |
499 if (res == NULL_TREE) | |
500 { | |
501 fprintf (TB_OUT_FILE, "There's no node with this code (reachable via the walk_tree function from this node).\n"); | |
502 } | |
503 else | |
504 { | |
505 fprintf (TB_OUT_FILE, "Achoo! I got this node in the tree.\n"); | |
506 TB_SET_HEAD (res); | |
507 } | |
508 } | |
509 break; | |
510 } | |
511 | |
512 #define TB_MOVE_HEAD(FCT) do { \ | |
513 if (head) \ | |
514 { \ | |
515 tree t; \ | |
516 t = FCT (head); \ | |
517 if (t) \ | |
518 TB_SET_HEAD (t); \ | |
519 else \ | |
520 TB_WF; \ | |
521 } \ | |
522 else \ | |
523 TB_WF; \ | |
524 } while (0) | |
525 | |
526 case TB_FIRST: | |
527 TB_MOVE_HEAD (TB_first_in_bind); | |
528 break; | |
529 | |
530 case TB_LAST: | |
531 TB_MOVE_HEAD (TB_last_in_bind); | |
532 break; | |
533 | |
534 case TB_UP: | |
535 TB_MOVE_HEAD (TB_up_expr); | |
536 break; | |
537 | |
538 case TB_PREV: | |
539 TB_MOVE_HEAD (TB_prev_expr); | |
540 break; | |
541 | |
542 case TB_NEXT: | |
543 TB_MOVE_HEAD (TB_next_expr); | |
544 break; | |
545 | |
546 case TB_HPREV: | |
547 /* This command is a little bit special, since it deals with history | |
548 stack. For this reason it should keep the "head = ..." statement | |
549 and not use TB_MOVE_HEAD. */ | |
550 if (head) | |
551 { | |
552 tree t; | |
553 t = TB_history_prev (); | |
554 if (t) | |
555 { | |
556 head = t; | |
557 if (TB_verbose) | |
558 { | |
559 print_generic_expr (TB_OUT_FILE, head, 0); | |
560 fprintf (TB_OUT_FILE, "\n"); | |
561 } | |
562 } | |
563 else | |
564 TB_WF; | |
565 } | |
566 else | |
567 TB_WF; | |
568 break; | |
569 | |
570 case TB_CHAIN: | |
571 /* Don't go further if it's the last node in this chain. */ | |
572 if (head && TREE_CODE (head) == BLOCK) | |
573 TB_SET_HEAD (BLOCK_CHAIN (head)); | |
574 else if (head && TREE_CHAIN (head)) | |
575 TB_SET_HEAD (TREE_CHAIN (head)); | |
576 else | |
577 TB_WF; | |
578 break; | |
579 | |
580 case TB_FUN: | |
581 /* Go up to the current function declaration. */ | |
582 TB_SET_HEAD (current_function_decl); | |
583 fprintf (TB_OUT_FILE, "Current function declaration.\n"); | |
584 break; | |
585 | |
586 case TB_HELP: | |
587 /* Display a help message. */ | |
588 { | |
589 int i; | |
590 fprintf (TB_OUT_FILE, "Possible commands are:\n\n"); | |
591 for (i = 0; i < TB_UNUSED_COMMAND; i++) | |
592 { | |
593 fprintf (TB_OUT_FILE, "%20s - %s\n", TB_COMMAND_TEXT (i), TB_COMMAND_HELP (i)); | |
594 } | |
595 } | |
596 break; | |
597 | |
598 case TB_VERBOSE: | |
599 if (TB_verbose == 0) | |
600 { | |
601 TB_verbose = 1; | |
602 fprintf (TB_OUT_FILE, "Verbose on.\n"); | |
603 } | |
604 else | |
605 { | |
606 TB_verbose = 0; | |
607 fprintf (TB_OUT_FILE, "Verbose off.\n"); | |
608 } | |
609 break; | |
610 | |
611 case TB_EXIT: | |
612 case TB_QUIT: | |
613 /* Just exit from this function. */ | |
614 goto ret; | |
615 | |
616 default: | |
617 TB_NIY; | |
618 } | |
619 } | |
620 | |
621 ret:; | |
622 htab_delete (TB_up_ht); | |
623 return; | |
624 } | |
625 | |
626 | |
627 /* Search the first node in this BIND_EXPR. */ | |
628 | |
629 static tree | |
630 TB_first_in_bind (tree node) | |
631 { | |
632 tree t; | |
633 | |
634 if (node == NULL_TREE) | |
635 return NULL_TREE; | |
636 | |
637 while ((t = TB_prev_expr (node))) | |
638 node = t; | |
639 | |
640 return node; | |
641 } | |
642 | |
643 /* Search the last node in this BIND_EXPR. */ | |
644 | |
645 static tree | |
646 TB_last_in_bind (tree node) | |
647 { | |
648 tree t; | |
649 | |
650 if (node == NULL_TREE) | |
651 return NULL_TREE; | |
652 | |
653 while ((t = TB_next_expr (node))) | |
654 node = t; | |
655 | |
656 return node; | |
657 } | |
658 | |
659 /* Search the parent expression for this node. */ | |
660 | |
661 static tree | |
662 TB_up_expr (tree node) | |
663 { | |
664 tree res; | |
665 if (node == NULL_TREE) | |
666 return NULL_TREE; | |
667 | |
668 res = (tree) htab_find (TB_up_ht, node); | |
669 return res; | |
670 } | |
671 | |
672 /* Search the previous expression in this BIND_EXPR. */ | |
673 | |
674 static tree | |
675 TB_prev_expr (tree node) | |
676 { | |
677 node = TB_current_chain_node (node); | |
678 | |
679 if (node == NULL_TREE) | |
680 return NULL_TREE; | |
681 | |
682 node = TB_up_expr (node); | |
683 if (node && TREE_CODE (node) == COMPOUND_EXPR) | |
684 return node; | |
685 else | |
686 return NULL_TREE; | |
687 } | |
688 | |
689 /* Search the next expression in this BIND_EXPR. */ | |
690 | |
691 static tree | |
692 TB_next_expr (tree node) | |
693 { | |
694 node = TB_current_chain_node (node); | |
695 | |
696 if (node == NULL_TREE) | |
697 return NULL_TREE; | |
698 | |
699 node = TREE_OPERAND (node, 1); | |
700 return node; | |
701 } | |
702 | |
703 static tree | |
704 TB_current_chain_node (tree node) | |
705 { | |
706 if (node == NULL_TREE) | |
707 return NULL_TREE; | |
708 | |
709 if (TREE_CODE (node) == COMPOUND_EXPR) | |
710 return node; | |
711 | |
712 node = TB_up_expr (node); | |
713 if (node) | |
714 { | |
715 if (TREE_CODE (node) == COMPOUND_EXPR) | |
716 return node; | |
717 | |
718 node = TB_up_expr (node); | |
719 if (TREE_CODE (node) == COMPOUND_EXPR) | |
720 return node; | |
721 } | |
722 | |
723 return NULL_TREE; | |
724 } | |
725 | |
726 /* For each node store in its children nodes that the current node is their | |
727 parent. This function is used by walk_tree. */ | |
728 | |
729 static tree | |
730 store_child_info (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, | |
731 void *data ATTRIBUTE_UNUSED) | |
732 { | |
733 tree node; | |
734 void **slot; | |
735 | |
736 node = *tp; | |
737 | |
738 /* 'node' is the parent of 'TREE_OPERAND (node, *)'. */ | |
739 if (EXPR_P (node)) | |
740 { | |
741 int n = TREE_OPERAND_LENGTH (node); | |
742 int i; | |
743 for (i = 0; i < n; i++) | |
744 { | |
745 tree op = TREE_OPERAND (node, i); | |
746 slot = htab_find_slot (TB_up_ht, op, INSERT); | |
747 *slot = (void *) node; | |
748 } | |
749 } | |
750 | |
751 /* Never stop walk_tree. */ | |
752 return NULL_TREE; | |
753 } | |
754 | |
755 /* Function used in TB_up_ht. */ | |
756 | |
757 static int | |
758 TB_parent_eq (const void *p1, const void *p2) | |
759 { | |
760 const_tree const node = (const_tree)p2; | |
761 const_tree const parent = (const_tree) p1; | |
762 | |
763 if (p1 == NULL || p2 == NULL) | |
764 return 0; | |
765 | |
766 if (EXPR_P (parent)) | |
767 { | |
768 int n = TREE_OPERAND_LENGTH (parent); | |
769 int i; | |
770 for (i = 0; i < n; i++) | |
771 if (node == TREE_OPERAND (parent, i)) | |
772 return 1; | |
773 } | |
774 return 0; | |
775 } | |
776 | |
777 /* Update information about upper expressions in the hash table. */ | |
778 | |
779 static void | |
780 TB_update_up (tree node) | |
781 { | |
782 while (node) | |
783 { | |
784 walk_tree (&node, store_child_info, NULL, NULL); | |
785 | |
786 /* Walk function's body. */ | |
787 if (TREE_CODE (node) == FUNCTION_DECL) | |
788 if (DECL_SAVED_TREE (node)) | |
789 walk_tree (&DECL_SAVED_TREE (node), store_child_info, NULL, NULL); | |
790 | |
791 /* Walk rest of the chain. */ | |
792 node = TREE_CHAIN (node); | |
793 } | |
794 fprintf (TB_OUT_FILE, "Up/prev expressions updated.\n"); | |
795 } | |
796 | |
797 /* Parse the input string for determining the command the user asked for. */ | |
798 | |
799 static TB_CODE | |
800 TB_get_command (char *input) | |
801 { | |
802 unsigned int mn, size_tok; | |
803 int comp; | |
804 char *space; | |
805 | |
806 space = strchr (input, ' '); | |
807 if (space != NULL) | |
808 size_tok = strlen (input) - strlen (space); | |
809 else | |
810 size_tok = strlen (input) - 1; | |
811 | |
812 for (mn = 0; mn < TB_UNUSED_COMMAND; mn++) | |
813 { | |
814 if (size_tok != TB_COMMAND_LEN (mn)) | |
815 continue; | |
816 | |
817 comp = memcmp (input, TB_COMMAND_TEXT (mn), TB_COMMAND_LEN (mn)); | |
818 if (comp == 0) | |
819 /* Here we just determined the command. If this command takes | |
820 an argument, then the argument is determined later. */ | |
821 return TB_COMMAND_CODE (mn); | |
822 } | |
823 | |
824 /* Not a valid command. */ | |
825 return TB_UNUSED_COMMAND; | |
826 } | |
827 | |
828 /* Parse the input string for determining the tree code. */ | |
829 | |
830 static enum tree_code | |
831 TB_get_tree_code (char *input) | |
832 { | |
833 unsigned int mn, size_tok; | |
834 int comp; | |
835 char *space; | |
836 | |
837 space = strchr (input, ' '); | |
838 if (space != NULL) | |
839 size_tok = strlen (input) - strlen (space); | |
840 else | |
841 size_tok = strlen (input) - 1; | |
842 | |
843 for (mn = 0; mn < LAST_AND_UNUSED_TREE_CODE; mn++) | |
844 { | |
845 if (size_tok != TB_TREE_CODE_LEN (mn)) | |
846 continue; | |
847 | |
848 comp = memcmp (input, TB_TREE_CODE_TEXT (mn), TB_TREE_CODE_LEN (mn)); | |
849 if (comp == 0) | |
850 { | |
851 fprintf (TB_OUT_FILE, "%s\n", TB_TREE_CODE_TEXT (mn)); | |
852 return TB_TREE_CODE (mn); | |
853 } | |
854 } | |
855 | |
856 /* This isn't a valid code. */ | |
857 return LAST_AND_UNUSED_TREE_CODE; | |
858 } | |
859 | |
860 /* Find a node with a given code. This function is used as an argument to | |
861 walk_tree. */ | |
862 | |
863 static tree | |
864 find_node_with_code (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, | |
865 void *data) | |
866 { | |
867 enum tree_code *code; | |
868 code = (enum tree_code *) data; | |
869 if (*code == TREE_CODE (*tp)) | |
870 return *tp; | |
871 | |
872 return NULL_TREE; | |
873 } | |
874 | |
875 /* Returns a pointer to the last visited node. */ | |
876 | |
877 static tree | |
878 TB_history_prev (void) | |
879 { | |
880 if (TB_history_stack) | |
881 { | |
882 TB_history_stack = TREE_CHAIN (TB_history_stack); | |
883 if (TB_history_stack) | |
884 return TREE_VALUE (TB_history_stack); | |
885 } | |
886 return NULL_TREE; | |
887 } | |
888 | |
889 /* Read up to (and including) a '\n' from STREAM into *LINEPTR | |
890 (and null-terminate it). *LINEPTR is a pointer returned from malloc | |
891 (or NULL), pointing to *N characters of space. It is realloc'd as | |
892 necessary. Returns the number of characters read (not including the | |
893 null terminator), or -1 on error or EOF. | |
894 This function comes from sed (and is supposed to be a portable version | |
895 of getline). */ | |
896 | |
897 static long | |
898 TB_getline (char **lineptr, long *n, FILE *stream) | |
899 { | |
900 char *line, *p; | |
901 long size, copy; | |
902 | |
903 if (lineptr == NULL || n == NULL) | |
904 { | |
905 errno = EINVAL; | |
906 return -1; | |
907 } | |
908 | |
909 if (ferror (stream)) | |
910 return -1; | |
911 | |
912 /* Make sure we have a line buffer to start with. */ | |
913 if (*lineptr == NULL || *n < 2) /* !seen and no buf yet need 2 chars. */ | |
914 { | |
915 #ifndef MAX_CANON | |
916 #define MAX_CANON 256 | |
917 #endif | |
918 line = (char *) xrealloc (*lineptr, MAX_CANON); | |
919 if (line == NULL) | |
920 return -1; | |
921 *lineptr = line; | |
922 *n = MAX_CANON; | |
923 } | |
924 | |
925 line = *lineptr; | |
926 size = *n; | |
927 | |
928 copy = size; | |
929 p = line; | |
930 | |
931 while (1) | |
932 { | |
933 long len; | |
934 | |
935 while (--copy > 0) | |
936 { | |
937 register int c = getc (stream); | |
938 if (c == EOF) | |
939 goto lose; | |
940 else if ((*p++ = c) == '\n') | |
941 goto win; | |
942 } | |
943 | |
944 /* Need to enlarge the line buffer. */ | |
945 len = p - line; | |
946 size *= 2; | |
947 line = (char *) xrealloc (line, size); | |
948 if (line == NULL) | |
949 goto lose; | |
950 *lineptr = line; | |
951 *n = size; | |
952 p = line + len; | |
953 copy = size - len; | |
954 } | |
955 | |
956 lose: | |
957 if (p == *lineptr) | |
958 return -1; | |
959 | |
960 /* Return a partial line since we got an error in the middle. */ | |
961 win: | |
962 #if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(MSDOS) | |
963 if (p - 2 >= *lineptr && p[-2] == '\r') | |
964 p[-2] = p[-1], --p; | |
965 #endif | |
966 *p = '\0'; | |
967 return p - *lineptr; | |
968 } |