⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dt_parser.c

📁 Sun Solaris 10 中的 DTrace 组件的源代码。请参看: http://www.sun.com/software/solaris/observability.jsp
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * 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 + -