📄 tree.c
字号:
/* Language-indepednent node constructors for parse phase of GNU compiler. Copyright (C) 1987, 1988 Free Software Foundation, Inc.This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 1, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. *//* This file contains the low level primitives for operating on tree nodes, including allocation, list operations, interning of identifiers, construction of data type nodes and statement nodes, and construction of type conversion nodes. It also contains tables index by tree code that describe how to take apart nodes of that code. It is intended to be language-independent, but occasionally calls language-dependent routines defined (for C) in typecheck.c. The low-level allocation routines oballoc and permalloc are used also for allocating many other kinds of objects by all passes of the compiler. */#include "config.h"#include <stdio.h>#include "tree.h"#include "obstack.h"#include "gvarargs.h"#include "flags.h"#define obstack_chunk_alloc xmalloc#define obstack_chunk_free freeextern int xmalloc ();extern void free ();/* Tree nodes of permanent duration are allocated in this obstack. They are the identifier nodes, and everything outside of the bodies and parameters of function definitions. */struct obstack permanent_obstack;/* The initial RTL, and all ..._TYPE nodes, in a function are allocated in this obstack. Usually they are freed at the end of the function, but if the function is inline they are saved. */struct obstack maybepermanent_obstack;/* The contents of the current function definition are allocated in this obstack, and all are freed at the end of the function. */struct obstack temporary_obstack;/* The tree nodes of an expression are allocated in this obstack, and all are freed at the end of the expression. */struct obstack momentary_obstack;/* This points at either permanent_obstack or maybepermanent_obstack. */struct obstack *saveable_obstack;/* This is same as saveable_obstack during parse and expansion phase; it points to temporary_obstack during optimization. This is the obstack to be used for creating rtl objects. */struct obstack *rtl_obstack;/* This points at either permanent_obstack or temporary_obstack. */struct obstack *current_obstack;/* This points at either permanent_obstack or temporary_obstack or momentary_obstack. */struct obstack *expression_obstack;/* Addresses of first objects in some obstacks. This is for freeing their entire contents. */char *maybepermanent_firstobj;char *temporary_firstobj;char *momentary_firstobj;/* Nonzero means all ..._TYPE nodes should be allocated permanently. */int all_types_permanent;/* Stack of places to restore the momentary obstack back to. */ struct momentary_level{ /* Pointer back to previous such level. */ struct momentary_level *prev; /* First object allocated within this level. */ char *base; /* Value of expression_obstack saved at entry to this level. */ struct obstack *obstack;};struct momentary_level *momentary_stack;/* Table indexed by tree code giving a string containing a character classifying the tree code. Possibilities are t, d, s, c, r and e. See tree.def for details. */#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,char *tree_code_type[] = {#include "tree.def"};#undef DEFTREECODE/* Table indexed by tree code giving number of expression operands beyond the fixed part of the node structure. Not used for types or decls. */#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,int tree_code_length[] = {#include "tree.def"};#undef DEFTREECODE/* Counter for assigning unique ids to all tree nodes. */int tree_node_counter = 0;/* Hash table for uniquizing IDENTIFIER_NODEs by name. */#define MAX_HASH_TABLE 1009static tree hash_table[MAX_HASH_TABLE]; /* id hash buckets *//* 0 while creating built-in identifiers. */static int do_identifier_warnings;/* Init data for node creation, at the beginning of compilation. */voidinit_tree (){ obstack_init (&permanent_obstack); obstack_init (&temporary_obstack); temporary_firstobj = (char *) obstack_alloc (&temporary_obstack, 0); obstack_init (&momentary_obstack); momentary_firstobj = (char *) obstack_alloc (&momentary_obstack, 0); obstack_init (&maybepermanent_obstack); maybepermanent_firstobj = (char *) obstack_alloc (&maybepermanent_obstack, 0); current_obstack = &permanent_obstack; expression_obstack = &permanent_obstack; rtl_obstack = saveable_obstack = &permanent_obstack; tree_node_counter = 1; bzero (hash_table, sizeof hash_table);}/* Start allocating on the temporary (per function) obstack. This is done in start_function before parsing the function body, and before each initialization at top level, and to go back to temporary allocation after doing end_temporary_allocation. */voidtemporary_allocation (){ current_obstack = &temporary_obstack; expression_obstack = &temporary_obstack; rtl_obstack = saveable_obstack = &maybepermanent_obstack; momentary_stack = 0;}/* Start allocating on the permanent obstack but don't free the temporary data. After calling this, call `permanent_allocation' to fully resume permanent allocation status. */voidend_temporary_allocation (){ current_obstack = &permanent_obstack; expression_obstack = &permanent_obstack; rtl_obstack = saveable_obstack = &permanent_obstack;}/* Resume allocating on the temporary obstack, undoing effects of `end_temporary_allocation'. */voidresume_temporary_allocation (){ current_obstack = &temporary_obstack; expression_obstack = &temporary_obstack; rtl_obstack = saveable_obstack = &maybepermanent_obstack;}/* Nonzero if temporary allocation is currently in effect. Zero if currently doing permanent allocation. */intallocation_temporary_p (){ return current_obstack == &temporary_obstack;}/* Go back to allocating on the permanent obstack and free everything in the temporary obstack. This is done in finish_function after fully compiling a function. */voidpermanent_allocation (){ /* Free up previous temporary obstack data */ obstack_free (&temporary_obstack, temporary_firstobj); obstack_free (&momentary_obstack, momentary_firstobj); obstack_free (&maybepermanent_obstack, maybepermanent_firstobj); current_obstack = &permanent_obstack; expression_obstack = &permanent_obstack; rtl_obstack = saveable_obstack = &permanent_obstack;}/* Save permanently everything on the maybepermanent_obstack. */voidpreserve_data (){ maybepermanent_firstobj = (char *) obstack_alloc (&maybepermanent_obstack, 0);}/* Allocate SIZE bytes in the current obstack and return a pointer to them. In practice the current obstack is always the temporary one. */char *oballoc (size) int size;{ return (char *) obstack_alloc (current_obstack, size);}/* Free the object PTR in the current obstack as well as everything allocated since PTR. In practice the current obstack is always the temporary one. */voidobfree (ptr) char *ptr;{ obstack_free (current_obstack, ptr);}/* Allocate SIZE bytes in the permanent obstack and return a pointer to them. */char *permalloc (size) long size;{ return (char *) obstack_alloc (&permanent_obstack, size);}/* Allocate SIZE bytes in the saveable obstack and return a pointer to them. */char *savealloc (size) int size;{ return (char *) obstack_alloc (saveable_obstack, size);}/* Start a level of momentary allocation. In C, each compound statement has its own level and that level is freed at the end of each statement. All expression nodes are allocated in the momentary allocation level. */voidpush_momentary (){ struct momentary_level *tem = (struct momentary_level *) obstack_alloc (&momentary_obstack, sizeof (struct momentary_level)); tem->prev = momentary_stack; tem->base = (char *) obstack_base (&momentary_obstack); tem->obstack = expression_obstack; momentary_stack = tem; expression_obstack = &momentary_obstack;}/* Free all the storage in the current momentary-allocation level. In C, this happens at the end of each statement. */voidclear_momentary (){ obstack_free (&momentary_obstack, momentary_stack->base);}/* Discard a level of momentary allocation. In C, this happens at the end of each compound statement. Restore the status of expression node allocation that was in effect before this level was created. */voidpop_momentary (){ struct momentary_level *tem = momentary_stack; momentary_stack = tem->prev; obstack_free (&momentary_obstack, tem); expression_obstack = tem->obstack;}/* Call when starting to parse a declaration: make expressions in the declaration last the length of the function. Returns an argument that should be passed to resume_momentary later. */intsuspend_momentary (){ register int tem = expression_obstack == &momentary_obstack; expression_obstack = saveable_obstack; return tem;}/* Call when finished parsing a declaration: restore the treatment of node-allocation that was in effect before the suspension. YES should be the value previously returned by suspend_momentary. */voidresume_momentary (yes) int yes;{ if (yes) expression_obstack = &momentary_obstack;}/* Return a newly allocated node of code CODE. Initialize the node's unique id and its TREE_PERMANENT flag. For decl and type nodes, some other fields are initialized. The rest of the node is initialized to zero. Achoo! I got a code in the node. */treemake_node (code) enum tree_code code;{ register tree t; register int type = *tree_code_type[(int) code]; register int length; register struct obstack *obstack = current_obstack; register int i; switch (type) { case 'd': /* A decl node */ length = sizeof (struct tree_decl); /* All decls in an inline function need to be saved. */ if (obstack != &permanent_obstack) obstack = saveable_obstack; /* PARM_DECLs always go on saveable_obstack, not permanent, even though we may make them before the function turns on temporary allocation. */ else if (code == PARM_DECL) obstack = &maybepermanent_obstack; break; case 't': /* a type node */ length = sizeof (struct tree_type); /* All data types are put where we can preserve them if nec. */ if (obstack != &permanent_obstack) obstack = all_types_permanent ? &permanent_obstack : saveable_obstack; break; case 's': /* a stmt node */ length = sizeof (struct tree_common) + 2 * sizeof (int) + tree_code_length[(int) code] * sizeof (char *); /* All stmts are put where we can preserve them if nec. */ if (obstack != &permanent_obstack) obstack = saveable_obstack; break; case 'r': /* a reference */ case 'e': /* an expression */ obstack = expression_obstack; length = sizeof (struct tree_exp) + (tree_code_length[(int) code] - 1) * sizeof (char *); break; case 'c': /* a constant */ obstack = expression_obstack; /* We can't use tree_code_length for this, since the number of words is machine-dependent due to varying alignment of `double'. */ if (code == REAL_CST) { length = sizeof (struct tree_real_cst); break; } case 'x': /* something random, like an identifier. */ length = sizeof (struct tree_common) + tree_code_length[(int) code] * sizeof (char *); /* Identifier nodes are always permanent since they are unique in a compiler run. */ if (code == IDENTIFIER_NODE) obstack = &permanent_obstack; } t = (tree) obstack_alloc (obstack, length); TREE_UID (t) = tree_node_counter++; TREE_TYPE (t) = 0; TREE_CHAIN (t) = 0; for (i = (length / sizeof (int)) - 1; i >= sizeof (struct tree_common) / sizeof (int) - 1; i--) ((int *) t)[i] = 0; TREE_SET_CODE (t, code); if (obstack == &permanent_obstack) TREE_PERMANENT (t) = 1; if (type == 'd') { extern int lineno; DECL_ALIGN (t) = 1; DECL_SIZE_UNIT (t) = 1; DECL_VOFFSET_UNIT (t) = 1; DECL_SOURCE_LINE (t) = lineno; DECL_SOURCE_FILE (t) = input_filename; } if (type == 't') { TYPE_ALIGN (t) = 1; TYPE_SIZE_UNIT (t) = 1; TYPE_MAIN_VARIANT (t) = t; } if (type == 'c') { TREE_LITERAL (t) = 1; } return t;}/* Return a new node with the same contents as NODE except that its TREE_CHAIN is zero and it has a fresh uid. */treecopy_node (node) tree node;{ register tree t; register enum tree_code code = TREE_CODE (node); register int length; register int i; switch (*tree_code_type[(int) code]) { case 'd': /* A decl node */ length = sizeof (struct tree_decl); break; case 't': /* a type node */ length = sizeof (struct tree_type); break; case 's': length = sizeof (struct tree_common) + 2 * sizeof (int) + tree_code_length[(int) code] * sizeof (char *); break; case 'r': /* a reference */ case 'e': /* a expression */ length = sizeof (struct tree_exp) + (tree_code_length[(int) code] - 1) * sizeof (char *); break; case 'c': /* a constant */ /* We can't use tree_code_length for this, since the number of words is machine-dependent due to varying alignment of `double'. */ if (code == REAL_CST) { length = sizeof (struct tree_real_cst); break; } case 'x': /* something random, like an identifier. */ length = sizeof (struct tree_common) + tree_code_length[(int) code] * sizeof (char *); } t = (tree) obstack_alloc (current_obstack, length); for (i = ((length + sizeof (int) - 1) / sizeof (int)) - 1; i >= 0; i--) ((int *) t)[i] = ((int *) node)[i]; TREE_UID (t) = tree_node_counter++; TREE_CHAIN (t) = 0; TREE_PERMANENT (t) = (current_obstack == &permanent_obstack); return t;}/* Return a copy of a chain of nodes, chained through the TREE_CHAIN field. For example, this can copy a list made of TREE_LIST nodes. */treecopy_list (list) tree list;{ tree head; register tree prev, next; if (list == 0) return 0; head = prev = copy_node (list); next = TREE_CHAIN (list); while (next) { TREE_CHAIN (prev) = copy_node (next); prev = TREE_CHAIN (prev); next = TREE_CHAIN (next); } return head;}#define HASHBITS 30/* Return an IDENTIFIER_NODE whose name is TEXT (a null-terminated string). If an identifier with that name has previously been referred to, the same node is returned this time. */treeget_identifier (text) register char *text;{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -