📄 dt_parser.c
字号:
/* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only. * See the file usr/src/LICENSING.NOTICE in this distribution or * http://www.opensolaris.org/license/ for details. */#pragma ident "@(#)dt_parser.c 1.11 04/12/17 SMI"/* * DTrace D Language Parser * * The D Parser is a lex/yacc parser consisting of the lexer dt_lex.l, the * parsing grammar dt_grammar.y, and this file, dt_parser.c, which handles * the construction of the parse tree nodes and their syntactic validation. * The parse tree is constructed of dt_node_t structures (see <dt_parser.h>) * that are built in two passes: (1) the "create" pass, where the parse tree * nodes are allocated by calls from the grammar to dt_node_*() subroutines, * and (2) the "cook" pass, where nodes are coalesced, assigned D types, and * validated according to the syntactic rules of the language. * * All node allocations are performed using dt_node_alloc(). All node frees * during the parsing phase are performed by dt_node_free(), which frees node- * internal state but does not actually free the nodes. All final node frees * are done as part of the end of dt_compile() or as part of destroying * persistent identifiers or translators which have embedded nodes. * * The dt_node_* routines that implement pass (1) may allocate new nodes. The * dt_cook_* routines that implement pass (2) may *not* allocate new nodes. * They may free existing nodes using dt_node_free(), but they may not actually * deallocate any dt_node_t's. Currently dt_cook_op2() is an exception to this * rule: see the comments therein for how this issue is resolved. * * The dt_cook_* routines are responsible for (at minimum) setting the final * node type (dn_ctfp/dn_type) and attributes (dn_attr). If dn_ctfp/dn_type * are set manually (i.e. not by one of the type assignment functions), then * the DT_NF_COOKED flag must be set manually on the node. * * The cooking pass can be applied to the same parse tree more than once (used * in the case of a comma-separated list of probe descriptions). As such, the * cook routines must not perform any parse tree transformations which would * be invalid if the tree were subsequently cooked using a different context. * * The dn_ctfp and dn_type fields form the type of the node. This tuple can * take on the following set of values, which form our type invariants: * * 1. dn_ctfp = NULL, dn_type = CTF_ERR * * In this state, the node has unknown type and is not yet cooked. The * DT_NF_COOKED flag is not yet set on the node. * * 2. dn_ctfp = DT_DYN_CTFP(dtp), dn_type = DT_DYN_TYPE(dtp) * * In this state, the node is a dynamic D type. This means that general * operations are not valid on this node and only code that knows how to * examine the inner details of the value can operate on it. When a node is * of type <DYN>, dn_ident *must* be valid on the node and it points to an * identifier describing the object and its type. The DT_NF_REF flag is * set for all dt_node_t objects of type <DYN>. * * 3. dn_ctfp = DT_STR_CTFP(dtp), dn_type = DT_STR_TYPE(dtp) * * In this state, the node is of type D string. The string type is really * a char[0] typedef, but requires special handling throughout the compiler. * * 4. dn_ctfp != NULL, dn_type = any other type ID * * In this state, the node is of some known D/CTF type. The normal libctf * APIs can be used to learn more about the type name or structure. When * the type is assigned, the DT_NF_SIGNED, DT_NF_REF, and DT_NF_BITFIELD * flags cache the corresponding attributes of the underlying CTF type. */#include <sys/param.h>#include <limits.h>#include <setjmp.h>#include <strings.h>#include <assert.h>#include <alloca.h>#include <stdlib.h>#include <stdarg.h>#include <stdio.h>#include <errno.h>#include <ctype.h>#include <dt_impl.h>#include <dt_grammar.h>#include <dt_module.h>#include <dt_provider.h>#include <dt_string.h>#include <dt_as.h>dt_pcb_t *yypcb; /* current control block for parser */dt_node_t *yypragma; /* lex token list for control lines */char yyintprefix; /* int token macro prefix (+/-) */char yyintsuffix[4]; /* int token suffix string [uU][lL] */int yyintdecimal; /* int token format flag (1=decimal, 0=octal/hex) */static const char *opstr(int op){ switch (op) { case DT_TOK_COMMA: return (","); case DT_TOK_ELLIPSIS: return ("..."); case DT_TOK_ASGN: return ("="); case DT_TOK_ADD_EQ: return ("+="); case DT_TOK_SUB_EQ: return ("-="); case DT_TOK_MUL_EQ: return ("*="); case DT_TOK_DIV_EQ: return ("/="); case DT_TOK_MOD_EQ: return ("%="); case DT_TOK_AND_EQ: return ("&="); case DT_TOK_XOR_EQ: return ("^="); case DT_TOK_OR_EQ: return ("|="); case DT_TOK_LSH_EQ: return ("<<="); case DT_TOK_RSH_EQ: return (">>="); case DT_TOK_QUESTION: return ("?"); case DT_TOK_COLON: return (":"); case DT_TOK_LOR: return ("||"); case DT_TOK_LXOR: return ("^^"); case DT_TOK_LAND: return ("&&"); case DT_TOK_BOR: return ("|"); case DT_TOK_XOR: return ("^"); case DT_TOK_BAND: return ("&"); case DT_TOK_EQU: return ("=="); case DT_TOK_NEQ: return ("!="); case DT_TOK_LT: return ("<"); case DT_TOK_LE: return ("<="); case DT_TOK_GT: return (">"); case DT_TOK_GE: return (">="); case DT_TOK_LSH: return ("<<"); case DT_TOK_RSH: return (">>"); case DT_TOK_ADD: return ("+"); case DT_TOK_SUB: return ("-"); case DT_TOK_MUL: return ("*"); case DT_TOK_DIV: return ("/"); case DT_TOK_MOD: return ("%"); case DT_TOK_LNEG: return ("!"); case DT_TOK_BNEG: return ("~"); case DT_TOK_ADDADD: return ("++"); case DT_TOK_PREINC: return ("++"); case DT_TOK_POSTINC: return ("++"); case DT_TOK_SUBSUB: return ("--"); case DT_TOK_PREDEC: return ("--"); case DT_TOK_POSTDEC: return ("--"); case DT_TOK_IPOS: return ("+"); case DT_TOK_INEG: return ("-"); case DT_TOK_DEREF: return ("*"); case DT_TOK_ADDROF: return ("&"); case DT_TOK_OFFSETOF: return ("offsetof"); case DT_TOK_SIZEOF: return ("sizeof"); case DT_TOK_STRINGOF: return ("stringof"); case DT_TOK_XLATE: return ("xlate"); case DT_TOK_LPAR: return ("("); case DT_TOK_RPAR: return (")"); case DT_TOK_LBRAC: return ("["); case DT_TOK_RBRAC: return ("]"); case DT_TOK_PTR: return ("->"); case DT_TOK_DOT: return ("."); case DT_TOK_STRING: return ("<string>"); case DT_TOK_IDENT: return ("<ident>"); case DT_TOK_TNAME: return ("<type>"); case DT_TOK_INT: return ("<int>"); default: return ("<?>"); }}intdt_type_lookup(const char *s, dtrace_typeinfo_t *tip){ static const char delimiters[] = " \t\n\r\v\f*`"; dtrace_hdl_t *dtp = yypcb->pcb_hdl; const char *p, *q, *end, *obj; for (p = s, end = s + strlen(s); *p != '\0'; p = q) { while (isspace(*p)) p++; /* skip leading whitespace prior to token */ if (p == end || (q = strpbrk(p + 1, delimiters)) == NULL) break; /* empty string or single token remaining */ if (*q == '`') { char *object = alloca((size_t)(q - p) + 1); char *type = alloca((size_t)(end - s) + 1); /* * Copy from the start of the token (p) to the location * backquote (q) to extract the nul-terminated object. */ bcopy(p, object, (size_t)(q - p)); object[(size_t)(q - p)] = '\0'; /* * Copy the original string up to the start of this * token (p) into type, and then concatenate everything * after q. This is the type name without the object. */ bcopy(s, type, (size_t)(p - s)); bcopy(q + 1, type + (size_t)(p - s), strlen(q + 1) + 1); if (strchr(q + 1, '`') != NULL) return (dt_set_errno(dtp, EDT_BADSCOPE)); return (dtrace_lookup_by_type(dtp, object, type, tip)); } } if (yypcb->pcb_idepth != 0) obj = DTRACE_OBJ_CDEFS; else obj = DTRACE_OBJ_EVERY; return (dtrace_lookup_by_type(dtp, obj, s, tip));}/* * When we parse type expressions or parse an expression with unary "&", we * need to find a type that is a pointer to a previously known type. * Unfortunately CTF is limited to a per-container view, so ctf_type_pointer() * alone does not suffice for our needs. We provide a more intelligent wrapper * for the compiler that attempts to compute a pointer to either the given type * or its base (that is, we try both "foo_t *" and "struct foo *"), and also * to potentially construct the required type on-the-fly. */intdt_type_pointer(dtrace_typeinfo_t *tip){ dtrace_hdl_t *dtp = yypcb->pcb_hdl; ctf_file_t *ctfp = tip->dtt_ctfp; ctf_id_t type = tip->dtt_type; ctf_id_t base = ctf_type_resolve(ctfp, type); dt_module_t *dmp; ctf_id_t ptr; if ((ptr = ctf_type_pointer(ctfp, type)) != CTF_ERR || (ptr = ctf_type_pointer(ctfp, base)) != CTF_ERR) { tip->dtt_type = ptr; return (0); } if (yypcb->pcb_idepth != 0) dmp = dtp->dt_cdefs; else dmp = dtp->dt_ddefs; if (ctfp != dmp->dm_ctfp && ctfp != ctf_parent_file(dmp->dm_ctfp) && (type = ctf_add_type(dmp->dm_ctfp, ctfp, type)) == CTF_ERR) return (-1); /* errno is set for us */ ptr = ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT, type); if (ptr == CTF_ERR || ctf_update(dmp->dm_ctfp) == CTF_ERR) return (-1); /* errno is set for us */ tip->dtt_object = dmp->dm_name; tip->dtt_ctfp = dmp->dm_ctfp; tip->dtt_type = ptr; return (0);}const char *dt_type_name(ctf_file_t *ctfp, ctf_id_t type, char *buf, size_t len){ dtrace_hdl_t *dtp = yypcb->pcb_hdl; if (ctfp == DT_FPTR_CTFP(dtp) && type == DT_FPTR_TYPE(dtp)) (void) snprintf(buf, len, "function pointer"); else if (ctfp == DT_FUNC_CTFP(dtp) && type == DT_FUNC_TYPE(dtp)) (void) snprintf(buf, len, "function"); else if (ctfp == DT_DYN_CTFP(dtp) && type == DT_DYN_TYPE(dtp)) (void) snprintf(buf, len, "dynamic variable"); else if (ctfp == NULL) (void) snprintf(buf, len, "<none>"); else if (ctf_type_name(ctfp, type, buf, len) == NULL) (void) snprintf(buf, len, "unknown"); return (buf);}/* * Perform the "usual arithmetic conversions" to determine which of the two * input operand types should be promoted and used as a result type. The * rules for this are described in ISOC[6.3.1.8] and K&R[A6.5]. */static voiddt_type_promote(dt_node_t *lp, dt_node_t *rp, ctf_file_t **ofp, ctf_id_t *otype){ ctf_file_t *lfp = lp->dn_ctfp; ctf_id_t ltype = lp->dn_type; ctf_file_t *rfp = rp->dn_ctfp; ctf_id_t rtype = rp->dn_type; ctf_id_t lbase = ctf_type_resolve(lfp, ltype); uint_t lkind = ctf_type_kind(lfp, lbase); ctf_id_t rbase = ctf_type_resolve(rfp, rtype); uint_t rkind = ctf_type_kind(rfp, rbase); dtrace_hdl_t *dtp = yypcb->pcb_hdl; ctf_encoding_t le, re; uint_t lrank, rrank; assert(lkind == CTF_K_INTEGER || lkind == CTF_K_ENUM); assert(rkind == CTF_K_INTEGER || rkind == CTF_K_ENUM); if (lkind == CTF_K_ENUM) { lfp = DT_INT_CTFP(dtp); ltype = lbase = DT_INT_TYPE(dtp); } if (rkind == CTF_K_ENUM) { rfp = DT_INT_CTFP(dtp); rtype = rbase = DT_INT_TYPE(dtp); } if (ctf_type_encoding(lfp, lbase, &le) == CTF_ERR) { yypcb->pcb_hdl->dt_ctferr = ctf_errno(lfp); longjmp(yypcb->pcb_jmpbuf, EDT_CTF); } if (ctf_type_encoding(rfp, rbase, &re) == CTF_ERR) { yypcb->pcb_hdl->dt_ctferr = ctf_errno(rfp); longjmp(yypcb->pcb_jmpbuf, EDT_CTF); } /* * Compute an integer rank based on the size and unsigned status. * If rank is identical, pick the "larger" of the equivalent types * which we define as having a larger base ctf_id_t. If rank is * different, pick the type with the greater rank. */ lrank = le.cte_bits + ((le.cte_format & CTF_INT_SIGNED) == 0); rrank = re.cte_bits + ((re.cte_format & CTF_INT_SIGNED) == 0); if (lrank == rrank) { if (lbase - rbase < 0) goto return_rtype; else goto return_ltype; } else if (lrank > rrank) { goto return_ltype; } else goto return_rtype;return_ltype: *ofp = lfp; *otype = ltype; return;return_rtype: *ofp = rfp; *otype = rtype;}voiddt_node_promote(dt_node_t *lp, dt_node_t *rp, dt_node_t *dnp){ dt_type_promote(lp, rp, &dnp->dn_ctfp, &dnp->dn_type); dt_node_type_assign(dnp, dnp->dn_ctfp, dnp->dn_type); dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));}const char *dt_node_name(const dt_node_t *dnp, char *buf, size_t len){ char n1[DT_TYPE_NAMELEN]; char n2[DT_TYPE_NAMELEN]; const char *prefix = "", *suffix = ""; const dtrace_syminfo_t *dts; char *s; switch (dnp->dn_kind) { case DT_NODE_INT: (void) snprintf(buf, len, "integer constant 0x%llx", (u_longlong_t)dnp->dn_value); break; case DT_NODE_STRING: s = strchr2esc(dnp->dn_string, strlen(dnp->dn_string)); (void) snprintf(buf, len, "string constant \"%s\"", s != NULL ? s : dnp->dn_string); free(s); break; case DT_NODE_IDENT: (void) snprintf(buf, len, "identifier %s", dnp->dn_string); break; case DT_NODE_VAR: case DT_NODE_FUNC: case DT_NODE_AGG: case DT_NODE_INLINE: switch (dnp->dn_ident->di_kind) { case DT_IDENT_FUNC: case DT_IDENT_AGGFUNC: case DT_IDENT_ACTFUNC: suffix = "( )"; break; case DT_IDENT_AGG: prefix = "@"; break; } (void) snprintf(buf, len, "%s %s%s%s", dt_idkind_name(dnp->dn_ident->di_kind), prefix, dnp->dn_ident->di_name, suffix); break; case DT_NODE_SYM: dts = dnp->dn_ident->di_data; (void) snprintf(buf, len, "symbol %s`%s", dts->dts_object, dts->dts_name); break; case DT_NODE_TYPE: (void) snprintf(buf, len, "type %s", dt_node_type_name(dnp, n1, sizeof (n1))); break; case DT_NODE_OP1: case DT_NODE_OP2: case DT_NODE_OP3: (void) snprintf(buf, len, "operator %s", opstr(dnp->dn_op)); break; case DT_NODE_DEXPR: case DT_NODE_DFUNC: if (dnp->dn_expr) return (dt_node_name(dnp->dn_expr, buf, len)); (void) snprintf(buf, len, "%s", "statement"); break; case DT_NODE_PDESC: if (dnp->dn_desc->dtpd_id == 0) { (void) snprintf(buf, len, "probe description %s:%s:%s:%s", dnp->dn_desc->dtpd_provider, dnp->dn_desc->dtpd_mod, dnp->dn_desc->dtpd_func, dnp->dn_desc->dtpd_name); } else { (void) snprintf(buf, len, "probe description %u", dnp->dn_desc->dtpd_id); } break; case DT_NODE_CLAUSE: (void) snprintf(buf, len, "%s", "clause"); break; case DT_NODE_MEMBER: (void) snprintf(buf, len, "member %s", dnp->dn_membname); break; case DT_NODE_XLATOR: (void) snprintf(buf, len, "translator <%s> (%s)", dt_type_name(dnp->dn_xlator->dx_dst_ctfp, dnp->dn_xlator->dx_dst_type, n1, sizeof (n1)), dt_type_name(dnp->dn_xlator->dx_src_ctfp, dnp->dn_xlator->dx_src_type, n2, sizeof (n2))); break; case DT_NODE_PROG: (void) snprintf(buf, len, "%s", "program"); break; default: (void) snprintf(buf, len, "node <%u>", dnp->dn_kind); break; } return (buf);}static dt_node_t *dt_node_alloc(int kind){ dt_node_t *dnp = malloc(sizeof (dt_node_t)); if (dnp == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); dnp->dn_ctfp = NULL; dnp->dn_type = CTF_ERR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -