📄 dt_parser.c
字号:
ctf_array_info(lfp, lbase, &r) == 0) { lref = ctf_type_resolve(lfp, r.ctr_contents); } } if (!rp_is_int) { rbase = ctf_type_resolve(rfp, rp->dn_type); rkind = ctf_type_kind(rfp, rbase); if (rkind == CTF_K_POINTER) { rref = ctf_type_resolve(rfp, ctf_type_reference(rfp, rbase)); } else if (rkind == CTF_K_ARRAY && ctf_array_info(rfp, rbase, &r) == 0) { rref = ctf_type_resolve(rfp, r.ctr_contents); } } /* * We know that one or the other type may still be a zero-valued * integer constant. To simplify the code below, set the integer * type variables equal to the non-integer types and proceed. */ if (lp_is_int) { lbase = rbase; lkind = rkind; lref = rref; lfp = rfp; } else if (rp_is_int) { rbase = lbase; rkind = lkind; rref = lref; rfp = lfp; } lp_is_void = ctf_type_encoding(lfp, lref, &e) == 0 && IS_VOID(e); rp_is_void = ctf_type_encoding(rfp, rref, &e) == 0 && IS_VOID(e); /* * The types are compatible if both are pointers to the same type, or * if either pointer is a void pointer. If they are compatible, set * tp to point to the more specific pointer type and return it. */ compat = (lkind == CTF_K_POINTER || lkind == CTF_K_ARRAY) && (rkind == CTF_K_POINTER || rkind == CTF_K_ARRAY) && (lp_is_void || rp_is_void || ctf_type_compat(lfp, lref, rfp, rref)); if (compat) { if (fpp != NULL) *fpp = rp_is_void ? lfp : rfp; if (tp != NULL) *tp = rp_is_void ? lbase : rbase; } return (compat);}/* * The rules for checking argument types against parameter types are described * in the ANSI-C spec (see K&R[A7.3.2] and K&R[A7.17]). We use the same rule * set to determine whether associative array arguments match the prototype. */intdt_node_is_argcompat(const dt_node_t *lp, const dt_node_t *rp){ ctf_file_t *lfp = lp->dn_ctfp; ctf_file_t *rfp = rp->dn_ctfp; assert(lp->dn_flags & DT_NF_COOKED); assert(rp->dn_flags & DT_NF_COOKED); if (dt_node_is_integer(lp) && dt_node_is_integer(rp)) return (1); /* integer types are compatible */ if (dt_node_is_strcompat(lp) && dt_node_is_strcompat(rp)) return (1); /* string types are compatible */ if (dt_node_is_stack(lp) && dt_node_is_stack(rp)) return (1); /* stack types are compatible */ switch (ctf_type_kind(lfp, ctf_type_resolve(lfp, lp->dn_type))) { case CTF_K_FUNCTION: case CTF_K_STRUCT: case CTF_K_UNION: return (ctf_type_compat(lfp, lp->dn_type, rfp, rp->dn_type)); default: return (dt_node_is_ptrcompat(lp, rp, NULL, NULL)); }}/* * We provide dt_node_is_posconst() as a convenience routine for callers who * wish to verify that an argument is a positive non-zero integer constant. */intdt_node_is_posconst(const dt_node_t *dnp){ return (dnp->dn_kind == DT_NODE_INT && dnp->dn_value != 0 && ( (dnp->dn_flags & DT_NF_SIGNED) == 0 || (int64_t)dnp->dn_value > 0));}intdt_node_is_actfunc(const dt_node_t *dnp){ return (dnp->dn_kind == DT_NODE_FUNC && dnp->dn_ident->di_kind == DT_IDENT_ACTFUNC);}/* * The original rules for integer constant typing are described in K&R[A2.5.1]. * However, since we support long long, we instead use the rules from ISO C99 * clause 6.4.4.1 since that is where long longs are formally described. The * rules require us to know whether the constant was specified in decimal or * in octal or hex, which we do by looking at our lexer's 'yyintdecimal' flag. * The type of an integer constant is the first of the corresponding list in * which its value can be represented: * * unsuffixed decimal: int, long, long long * unsuffixed oct/hex: int, unsigned int, long, unsigned long, * long long, unsigned long long * suffix [uU]: unsigned int, unsigned long, unsigned long long * suffix [lL] decimal: long, long long * suffix [lL] oct/hex: long, unsigned long, long long, unsigned long long * suffix [uU][Ll]: unsigned long, unsigned long long * suffix ll/LL decimal: long long * suffix ll/LL oct/hex: long long, unsigned long long * suffix [uU][ll/LL]: unsigned long long * * Given that our lexer has already validated the suffixes by regexp matching, * there is an obvious way to concisely encode these rules: construct an array * of the types in the order int, unsigned int, long, unsigned long, long long, * unsigned long long. Compute an integer array starting index based on the * suffix (e.g. none = 0, u = 1, ull = 5), and compute an increment based on * the specifier (dec/oct/hex) and suffix (u). Then iterate from the starting * index to the end, advancing using the increment, and searching until we * find a limit that matches or we run out of choices (overflow). To make it * even faster, we precompute the table of type information in dtrace_open(). */dt_node_t *dt_node_int(uintmax_t value){ dt_node_t *dnp = dt_node_alloc(DT_NODE_INT); dtrace_hdl_t *dtp = yypcb->pcb_hdl; int n = (yyintdecimal | (yyintsuffix[0] == 'u')) + 1; int i = 0; const char *p; char c; dnp->dn_op = DT_TOK_INT; dnp->dn_value = value; for (p = yyintsuffix; (c = *p) != '\0'; p++) { if (c == 'U' || c == 'u') i += 1; else if (c == 'L' || c == 'l') i += 2; } for (; i < sizeof (dtp->dt_ints) / sizeof (dtp->dt_ints[0]); i += n) { if (value <= dtp->dt_ints[i].did_limit) { dt_node_type_assign(dnp, dtp->dt_ints[i].did_ctfp, dtp->dt_ints[i].did_type); /* * If a prefix character is present in macro text, add * in the corresponding operator node (see dt_lex.l). */ switch (yyintprefix) { case '+': return (dt_node_op1(DT_TOK_IPOS, dnp)); case '-': return (dt_node_op1(DT_TOK_INEG, dnp)); default: return (dnp); } } } xyerror(D_INT_OFLOW, "integer constant 0x%llx cannot be represented " "in any built-in integral type\n", (u_longlong_t)value); /*NOTREACHED*/ return (NULL); /* keep gcc happy */}dt_node_t *dt_node_string(char *string){ dtrace_hdl_t *dtp = yypcb->pcb_hdl; dt_node_t *dnp; if (string == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); dnp = dt_node_alloc(DT_NODE_STRING); dnp->dn_op = DT_TOK_STRING; dnp->dn_string = string; dt_node_type_assign(dnp, DT_STR_CTFP(dtp), DT_STR_TYPE(dtp)); return (dnp);}dt_node_t *dt_node_ident(char *name){ dtrace_hdl_t *dtp = yypcb->pcb_hdl; dt_ident_t *idp; dt_node_t *dnp; if (name == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); /* * If the identifier is an inlined integer constant, then create an INT * node that is a clone of the inline parse tree node and return that * immediately, allowing this inline to be used in parsing contexts * that require constant expressions (e.g. scalar array sizes). */ if ((idp = dt_idhash_lookup(dtp->dt_globals, name)) != NULL && (idp->di_flags & DT_IDFLG_INLINE)) { dt_idnode_t *inp = idp->di_data; if (inp->din_root->dn_kind == DT_NODE_INT) { free(name); dnp = dt_node_alloc(DT_NODE_INT); dnp->dn_op = DT_TOK_INT; dnp->dn_value = inp->din_root->dn_value; dt_node_type_propagate(inp->din_root, dnp); return (dnp); } } dnp = dt_node_alloc(DT_NODE_IDENT); dnp->dn_op = name[0] == '@' ? DT_TOK_AGG : DT_TOK_IDENT; dnp->dn_string = name; return (dnp);}/* * Create an empty node of type corresponding to the given declaration. * Explicit references to user types (C or D) are assigned the default * stability; references to other types are _dtrace_typattr (Private). */dt_node_t *dt_node_type(dt_decl_t *ddp){ dtrace_hdl_t *dtp = yypcb->pcb_hdl; dtrace_typeinfo_t dtt; dt_node_t *dnp; char *name = NULL; int err; /* * If 'ddp' is NULL, we get a decl by popping the decl stack. This * form of dt_node_type() is used by parameter rules in dt_grammar.y. */ if (ddp == NULL) ddp = dt_decl_pop_param(&name); err = dt_decl_type(ddp, &dtt); dt_decl_free(ddp); if (err != 0) { free(name); longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER); } dnp = dt_node_alloc(DT_NODE_TYPE); dnp->dn_op = DT_TOK_IDENT; dnp->dn_string = name; dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type); if (dtt.dtt_ctfp == dtp->dt_cdefs->dm_ctfp || dtt.dtt_ctfp == dtp->dt_ddefs->dm_ctfp) dt_node_attr_assign(dnp, _dtrace_defattr); else dt_node_attr_assign(dnp, _dtrace_typattr); return (dnp);}/* * Create a type node corresponding to a varargs (...) parameter by just * assigning it type CTF_ERR. The decl processing code will handle this. */dt_node_t *dt_node_vatype(void){ dt_node_t *dnp = dt_node_alloc(DT_NODE_TYPE); dnp->dn_op = DT_TOK_IDENT; dnp->dn_ctfp = NULL; dnp->dn_type = CTF_ERR; dnp->dn_attr = _dtrace_defattr; return (dnp);}/* * Instantiate a decl using the contents of the current declaration stack. As * we do not currently permit decls to be initialized, this function currently * returns NULL and no parse node is created. When this function is called, * the topmost scope's ds_ident pointer will be set to NULL (indicating no * init_declarator rule was matched) or will point to the identifier to use. */dt_node_t *dt_node_decl(void){ dtrace_hdl_t *dtp = yypcb->pcb_hdl; dt_scope_t *dsp = &yypcb->pcb_dstack; dt_dclass_t class = dsp->ds_class; dt_decl_t *ddp = dt_decl_top(); dt_module_t *dmp; dtrace_typeinfo_t dtt; ctf_id_t type; char n1[DT_TYPE_NAMELEN]; char n2[DT_TYPE_NAMELEN]; if (dt_decl_type(ddp, &dtt) != 0) longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER); /* * If we have no declaration identifier, then this is either a spurious * declaration of an intrinsic type (e.g. "extern int;") or declaration * or redeclaration of a struct, union, or enum type or tag. */ if (dsp->ds_ident == NULL) { if (ddp->dd_kind != CTF_K_STRUCT && ddp->dd_kind != CTF_K_UNION && ddp->dd_kind != CTF_K_ENUM) xyerror(D_DECL_USELESS, "useless declaration\n"); dt_dprintf("type %s added as id %ld\n", dt_type_name( ddp->dd_ctfp, ddp->dd_type, n1, sizeof (n1)), ddp->dd_type); return (NULL); } if (strchr(dsp->ds_ident, '`') != NULL) { xyerror(D_DECL_SCOPE, "D scoping operator may not be used in " "a declaration name (%s)\n", dsp->ds_ident); } /* * If we are nested inside of a C include file, add the declaration to * the C definition module; otherwise use the D definition module. */ if (yypcb->pcb_idepth != 0) dmp = dtp->dt_cdefs; else dmp = dtp->dt_ddefs; /* * If we see a global or static declaration of a function prototype, * treat this as equivalent to a D extern declaration. */ if (ctf_type_kind(dtt.dtt_ctfp, dtt.dtt_type) == CTF_K_FUNCTION && (class == DT_DC_DEFAULT || class == DT_DC_STATIC)) class = DT_DC_EXTERN; switch (class) { case DT_DC_AUTO: case DT_DC_REGISTER: case DT_DC_STATIC: xyerror(D_DECL_BADCLASS, "specified storage class not " "appropriate in D\n"); /*NOTREACHED*/ case DT_DC_EXTERN: { dtrace_typeinfo_t ott; dtrace_syminfo_t dts; GElf_Sym sym; int exists = dtrace_lookup_by_name(dtp, dmp->dm_name, dsp->ds_ident, &sym, &dts) == 0; if (exists && (dtrace_symbol_type(dtp, &sym, &dts, &ott) != 0 || ctf_type_cmp(dtt.dtt_ctfp, dtt.dtt_type, ott.dtt_ctfp, ott.dtt_type) != 0)) { xyerror(D_DECL_IDRED, "identifier redeclared: %s`%s\n" "\t current: %s\n\tprevious: %s\n", dmp->dm_name, dsp->ds_ident, dt_type_name(dtt.dtt_ctfp, dtt.dtt_type, n1, sizeof (n1)), dt_type_name(ott.dtt_ctfp, ott.dtt_type, n2, sizeof (n2))); } else if (!exists && dt_module_extern(dtp, dmp, dsp->ds_ident, &dtt) == NULL) { xyerror(D_UNKNOWN, "failed to extern %s: %s\n", dsp->ds_ident, dtrace_errmsg(dtp, dtrace_errno(dtp))); } else { dt_dprintf("extern %s`%s type=<%s>\n", dmp->dm_name, dsp->ds_ident, dt_type_name(dtt.dtt_ctfp, dtt.dtt_type, n1, sizeof (n1))); } break; } case DT_DC_TYPEDEF: /* * If the source type for the typedef is not defined in the * target container or its parent, copy the type to the target * container and reset dtt_ctfp and dtt_type to the copy. */ if (dtt.dtt_ctfp != dmp->dm_ctfp && dtt.dtt_ctfp != ctf_parent_file(dmp->dm_ctfp)) { dtt.dtt_type = ctf_add_type(dmp->dm_ctfp, dtt.dtt_ctfp, dtt.dtt_type); dtt.dtt_ctfp = dmp->dm_ctfp; if (dtt.dtt_type == CTF_ERR || ctf_update(dtt.dtt_ctfp) == CTF_ERR) { xyerror(D_UNKNOWN, "failed to copy typedef %s " "source type: %s\n", dsp->ds_ident, ctf_errmsg(ctf_errno(dtt.dtt_ctfp))); } } type = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT, dsp->ds_ident, dtt.dtt_type); if (type == CTF_ERR || ctf_update(dmp->dm_ctfp) == CTF_ERR) { xyerror(D_UNKNOWN, "failed to typedef %s: %s\n", dsp->ds_ident, ctf_errmsg(ctf_errno(dmp->dm_ctfp))); } dt_dprintf("typedef %s added as id %ld\n", dsp->ds_ident, type); break; default: { ctf_encoding_t cte; dt_idhash_t *dhp; dt_ident_t *idp; dt_node_t idn; int assc, idkind; uint_t id, kind; ushort_t idflags; switch (class) { case DT_DC_THIS: dhp = yypcb->pcb_locals; idflags = DT_IDFLG_LOCAL; break; case DT_DC_SELF: dhp = dtp->dt_tls; idflags = DT_IDFLG_TLS; break; default: dhp = dtp->dt_globals; idflags = 0; break; } if (ddp->dd_kind == CTF_K_ARRAY && ddp->dd_node == NULL) { xyerror(D_DECL_ARRNULL, "array declaration requires array dimension or " "tuple signature: %s\n", dsp->ds_ident); } /* * Create a fake dt_node_t on the stack so we can determine the * type of the ident if it's defined. We look it up in the * appropriate hash table (dhp) and cook it into the node (idn). */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -