📄 c-aux-info.c
字号:
This routine will also return with the global variable "data_type" set to some string value which is the "basic" data-type of the given complete type. This "data_type" string can be concatenated onto the front of the returned string after this routine returns to its caller. In complicated cases involving pointer types, array types, or function types, the C declaration syntax requires an "inside out" approach, i.e. if you have a type which is a "pointer-to-function" type, you need to handle the "pointer" part first, but it also has to be "innermost" (relative to the declaration stuff for the "function" type). Thus, is this case, you must prepend a "(*" and append a ")" to the name of the item (i.e. formal variable). Then you must append and prepend the other info for the "function type" part of the overall type. To handle the "innermost precedence" rules of complicated C declarators, we do the following (in this routine). The input parameter called "ret_val" is treated as a "seed". Each time gen_type is called (perhaps recursively) some additional strings may be appended or prepended (or both) to the "seed" string. If yet another (lower) level of the GCC tree exists for the given type (as in the case of a pointer type, an array type, or a function type) then the (wrapped) seed is passed to a (recursive) invocation of gen_type() this recursive invocation may again "wrap" the (new) seed with yet more declarator stuff, by appending, prepending (or both). By the time the recursion bottoms out, the "seed value" at that point will have a value which is (almost) the complete source version of the declarator (except for the data_type info). Thus, this deepest "seed" value is simply passed back up through all of the recursive calls until it is given (as the return value) to the initial caller of the gen_type() routine. All that remains to do at this point is for the initial caller to prepend the "data_type" string onto the returned "seed". */static char *gen_type (ret_val, t, style) char *ret_val; tree t; formals_style style;{ tree chain_p; if (TYPE_NAME (t) && DECL_NAME (TYPE_NAME (t))) data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t))); else { switch (TREE_CODE (t)) { case POINTER_TYPE: if (TYPE_READONLY (t)) ret_val = concat ("const ", ret_val); if (TYPE_VOLATILE (t)) ret_val = concat ("volatile ", ret_val); ret_val = concat ("*", ret_val); if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE || TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE) ret_val = concat3 ("(", ret_val, ")"); ret_val = gen_type (ret_val, TREE_TYPE (t), style); return ret_val; case ARRAY_TYPE: if (TYPE_SIZE (t) == 0 || TREE_CODE (TYPE_SIZE (t)) != INTEGER_CST) ret_val = gen_type (concat (ret_val, "[]"), TREE_TYPE (t), style); else if (int_size_in_bytes (t) == 0) ret_val = gen_type (concat (ret_val, "[0]"), TREE_TYPE (t), style); else { int size = (int_size_in_bytes (t) / int_size_in_bytes (TREE_TYPE (t))); char buff[10]; sprintf (buff, "[%d]", size); ret_val = gen_type (concat (ret_val, buff), TREE_TYPE (t), style); } break; case FUNCTION_TYPE: ret_val = gen_type (concat (ret_val, gen_formal_list_for_type (t, style)), TREE_TYPE (t), style); break; case IDENTIFIER_NODE: data_type = IDENTIFIER_POINTER (t); break; /* The following three cases are complicated by the fact that a user may do something really stupid, like creating a brand new "anonymous" type specification in a formal argument list (or as part of a function return type specification). For example: int f (enum { red, green, blue } color); In such cases, we have no name that we can put into the prototype to represent the (anonymous) type. Thus, we have to generate the whole darn type specification. Yuck! */ case RECORD_TYPE: if (TYPE_NAME (t)) data_type = IDENTIFIER_POINTER (TYPE_NAME (t)); else { data_type = ""; chain_p = TYPE_FIELDS (t); while (chain_p) { data_type = concat (data_type, gen_decl (chain_p, 0, ansi)); chain_p = TREE_CHAIN (chain_p); data_type = concat (data_type, "; "); } data_type = concat3 ("{ ", data_type, "}"); } data_type = concat ("struct ", data_type); break; case UNION_TYPE: if (TYPE_NAME (t)) data_type = IDENTIFIER_POINTER (TYPE_NAME (t)); else { data_type = ""; chain_p = TYPE_FIELDS (t); while (chain_p) { data_type = concat (data_type, gen_decl (chain_p, 0, ansi)); chain_p = TREE_CHAIN (chain_p); data_type = concat (data_type, "; "); } data_type = concat3 ("{ ", data_type, "}"); } data_type = concat ("union ", data_type); break; case ENUMERAL_TYPE: if (TYPE_NAME (t)) data_type = IDENTIFIER_POINTER (TYPE_NAME (t)); else { data_type = ""; chain_p = TYPE_VALUES (t); while (chain_p) { data_type = concat (data_type, IDENTIFIER_POINTER (TREE_PURPOSE (chain_p))); chain_p = TREE_CHAIN (chain_p); if (chain_p) data_type = concat (data_type, ", "); } data_type = concat3 ("{ ", data_type, " }"); } data_type = concat ("enum ", data_type); break; case TYPE_DECL: data_type = IDENTIFIER_POINTER (DECL_NAME (t)); break; case INTEGER_TYPE: data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t))); /* Normally, `unsigned' is part of the deal. Not so if it comes with `const' or `volatile'. */ if (TREE_UNSIGNED (t) && (TYPE_READONLY (t) || TYPE_VOLATILE (t))) data_type = concat ("unsigned ", data_type); break; case REAL_TYPE: data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t))); break; case VOID_TYPE: data_type = "void"; break; case ERROR_MARK: data_type = "[ERROR]"; break; default: abort (); } } if (TYPE_READONLY (t)) ret_val = concat ("const ", ret_val); if (TYPE_VOLATILE (t)) ret_val = concat ("volatile ", ret_val); return ret_val;}/* Generate a string (source) representation of an entire entity declaration (using some particular style for function types). The given entity may be either a variable or a function. If the "is_func_definition" parameter is non-zero, assume that the thing we are generating a declaration for is a FUNCTION_DECL node which is associated with a function definition. In this case, we can assume that an attached list of DECL nodes for function formal arguments is present. */static char *gen_decl (decl, is_func_definition, style) tree decl; int is_func_definition; formals_style style;{ char *ret_val; if (DECL_NAME (decl)) ret_val = IDENTIFIER_POINTER (DECL_NAME (decl)); else ret_val = ""; /* If we are just generating a list of names of formal parameters, we can simply return the formal parameter name (with no typing information attached to it) now. */ if (style == k_and_r_names) return ret_val; /* Note that for the declaration of some entity (either a function or a data object, like for instance a parameter) if the entity itself was declared as either const or volatile, then const and volatile properties are associated with just the declaration of the entity, and *not* with the `type' of the entity. Thus, for such declared entities, we have to generate the qualifiers here. */ if (TREE_THIS_VOLATILE (decl)) ret_val = concat ("volatile ", ret_val); if (TREE_READONLY (decl)) ret_val = concat ("const ", ret_val); data_type = ""; /* For FUNCTION_DECL nodes, there are two possible cases here. First, if this FUNCTION_DECL node was generated from a function "definition", then we will have a list of DECL_NODE's, one for each of the function's formal parameters. In this case, we can print out not only the types of each formal, but also each formal's name. In the second case, this FUNCTION_DECL node came from an actual function declaration (and *not* a definition). In this case, we do nothing here because the formal argument type-list will be output later, when the "type" of the function is added to the string we are building. Note that the ANSI-style formal parameter list is considered to be a (suffix) part of the "type" of the function. */ if (TREE_CODE (decl) == FUNCTION_DECL && is_func_definition) { ret_val = concat (ret_val, gen_formal_list_for_func_def (decl, ansi)); /* Since we have already added in the formals list stuff, here we don't add the whole "type" of the function we are considering (which would include its parameter-list info), rather, we only add in the "type" of the "type" of the function, which is really just the return-type of the function (and does not include the parameter list info). */ ret_val = gen_type (ret_val, TREE_TYPE (TREE_TYPE (decl)), style); } else ret_val = gen_type (ret_val, TREE_TYPE (decl), style); ret_val = affix_data_type (ret_val); if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl)) ret_val = concat ("register ", ret_val); if (TREE_PUBLIC (decl)) ret_val = concat ("extern ", ret_val); if (TREE_CODE (decl) == FUNCTION_DECL && !TREE_PUBLIC (decl)) ret_val = concat ("static ", ret_val); return ret_val;}extern FILE *aux_info_file;/* Generate and write a new line of info to the aux-info (.X) file. This routine is called once for each function declaration, and once for each function definition (even the implicit ones). */voidgen_aux_info_record (fndecl, is_definition, is_implicit, is_prototyped) tree fndecl; int is_definition; int is_implicit; int is_prototyped;{ if (flag_gen_aux_info) { static int compiled_from_record = 0; /* Each output .X file must have a header line. Write one now if we have not yet done so. */ if (! compiled_from_record++) { /* The first line tells which directory file names are relative to. Currently, -aux-info works only for files in the working directory, so just use a `.' as a placeholder for now. */ fprintf (aux_info_file, "/* compiled from: . */\n"); } /* Write the actual line of auxiliary info. */ fprintf (aux_info_file, "/* %s:%d:%c%c */ %s;", DECL_SOURCE_FILE (fndecl), DECL_SOURCE_LINE (fndecl), (is_implicit) ? 'I' : (is_prototyped) ? 'N' : 'O', (is_definition) ? 'F' : 'C', gen_decl (fndecl, is_definition, ansi)); /* If this is an explicit function declaration, we need to also write out an old-style (i.e. K&R) function header, just in case the user wants to run unprotoize. */ if (is_definition) { fprintf (aux_info_file, " /*%s %s*/", gen_formal_list_for_func_def (fndecl, k_and_r_names), gen_formal_list_for_func_def (fndecl, k_and_r_decls)); } fprintf (aux_info_file, "\n"); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -