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

📄 parse.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
	    (void)Lst_AtEnd(predecessor->successors, (ClientData)gn);	    (void)Lst_AtEnd(gn->preds, (ClientData)predecessor);	}	/*	 * The current source now becomes the predecessor for the next one.	 */	predecessor = gn;    } else {	/*	 * If the source is not an attribute, we need to find/create	 * a node for it. After that we can apply any operator to it	 * from a special target or link it to its parents, as	 * appropriate.	 *	 * In the case of a source that was the object of a :: operator,	 * the attribute is applied to all of its instances (as kept in	 * the 'cohorts' list of the node) or all the cohorts are linked	 * to all the targets.	 */	gn = Targ_FindNode (src, TARG_CREATE);	if (tOp) {	    gn->type |= tOp;	} else {	    Lst_ForEach (targets, ParseLinkSrc, (ClientData)gn);	}	if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) {	    register GNode  	*cohort;	    register LstNode	ln;	    for (ln=Lst_First(gn->cohorts); ln != NILLNODE; ln = Lst_Succ(ln)){		cohort = (GNode *)Lst_Datum(ln);		if (tOp) {		    cohort->type |= tOp;		} else {		    Lst_ForEach(targets, ParseLinkSrc, (ClientData)cohort);		}	    }	}    }}/*- *----------------------------------------------------------------------- * ParseFindMain -- *	Find a real target in the list and set it to be the main one. *	Called by ParseDoDependency when a main target hasn't been found *	yet. * * Results: *	0 if main not found yet, 1 if it is. * * Side Effects: *	mainNode is changed and Targ_SetMain is called. * *----------------------------------------------------------------------- */static intParseFindMain(gn)    GNode   	  *gn;	    /* Node to examine */{    if ((gn->type & (OP_NOTMAIN|OP_USE|OP_EXEC|OP_TRANSFORM)) == 0) {	mainNode = gn;	Targ_SetMain(gn);	return (1);    } else {	return (0);    }}/*- *----------------------------------------------------------------------- * ParseAddDir -- *	Front-end for Dir_AddDir to make sure Lst_ForEach keeps going * * Results: *	=== 0 * * Side Effects: *	See Dir_AddDir. * *----------------------------------------------------------------------- */static intParseAddDir(path, name)    Lst	    path;    char    *name;{    Dir_AddDir(path, name);    return(0);}/*- *----------------------------------------------------------------------- * ParseClearPath -- *	Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going * * Results: *	=== 0 * * Side Effects: *	See Dir_ClearPath * *----------------------------------------------------------------------- */static intParseClearPath(path)    Lst	    path;{    Dir_ClearPath(path);    return(0);}/*- *--------------------------------------------------------------------- * ParseDoDependency  -- *	Parse the dependency line in line. * * Results: *	None * * Side Effects: *	The nodes of the sources are linked as children to the nodes of the *	targets. Some nodes may be created. * *	We parse a dependency line by first extracting words from the line and * finding nodes in the list of all targets with that name. This is done * until a character is encountered which is an operator character. Currently * these are only ! and :. At this point the operator is parsed and the * pointer into the line advanced until the first source is encountered. * 	The parsed operator is applied to each node in the 'targets' list, * which is where the nodes found for the targets are kept, by means of * the ParseDoOp function. *	The sources are read in much the same way as the targets were except * that now they are expanded using the wildcarding scheme of the C-Shell * and all instances of the resulting words in the list of all targets * are found. Each of the resulting nodes is then linked to each of the * targets as one of its children. *	Certain targets are handled specially. These are the ones detailed * by the specType variable. *	The storing of transformation rules is also taken care of here. * A target is recognized as a transformation rule by calling * Suff_IsTransform. If it is a transformation rule, its node is gotten * from the suffix module via Suff_AddTransform rather than the standard * Targ_FindNode in the target module. *--------------------------------------------------------------------- */static voidParseDoDependency (line)    char           *line;	/* the line to parse */{    register char  *cp;		/* our current position */    register GNode *gn;		/* a general purpose temporary node */    register int    op;		/* the operator on the line */    char            savec;	/* a place to save a character */    Lst    	    paths;   	/* List of search paths to alter when parsing				 * a list of .PATH targets */    int	    	    tOp;    	/* operator from special target */    Lst	    	    sources;	/* list of source names after expansion */    Lst 	    curTargs;	/* list of target names to be found and added				 * to the targets list */    tOp = 0;    specType = Not;    paths = (Lst)NULL;    curTargs = Lst_Init(FALSE);        do {	for (cp = line;	     *cp && !isspace (*cp) &&	     (*cp != '!') && (*cp != ':') && (*cp != '(');	     cp++)	{	    if (*cp == '$') {		/*		 * Must be a dynamic source (would have been expanded		 * otherwise), so call the Var module to parse the puppy		 * so we can safely advance beyond it...There should be		 * no errors in this, as they would have been discovered		 * in the initial Var_Subst and we wouldn't be here.		 */		int 	length;		Boolean	freeIt;		char	*result;		result=Var_Parse(cp, VAR_CMD, TRUE, &length, &freeIt);		if (freeIt) {		    free(result);		}		cp += length-1;	    }	    continue;	}	if (*cp == '(') {	    /*	     * Archives must be handled specially to make sure the OP_ARCHV	     * flag is set in their 'type' field, for one thing, and because	     * things like "archive(file1.o file2.o file3.o)" are permissible.	     * Arch_ParseArchive will set 'line' to be the first non-blank	     * after the archive-spec. It creates/finds nodes for the members	     * and places them on the given list, returning SUCCESS if all	     * went well and FAILURE if there was an error in the	     * specification. On error, line should remain untouched.	     */	    if (Arch_ParseArchive (&line, targets, VAR_CMD) != SUCCESS) {		Parse_Error (PARSE_FATAL,			     "Error in archive specification: \"%s\"", line);		return;	    } else {		continue;	    }	}	savec = *cp;		if (!*cp) {	    /*	     * Ending a dependency line without an operator is a Bozo	     * no-no 	     */	    Parse_Error (PARSE_FATAL, "Need an operator");	    return;	}	*cp = '\0';	/*	 * Have a word in line. See if it's a special target and set	 * specType to match it.	 */	if (*line == '.' && isupper (line[1])) {	    /*	     * See if the target is a special target that must have it	     * or its sources handled specially. 	     */	    int keywd = ParseFindKeyword(line);	    if (keywd != -1) {		if (specType == ExPath && parseKeywords[keywd].spec != ExPath) {		    Parse_Error(PARSE_FATAL, "Mismatched special targets");		    return;		}				specType = parseKeywords[keywd].spec;		tOp = parseKeywords[keywd].op;		/*		 * Certain special targets have special semantics:		 *	.PATH		Have to set the dirSearchPath		 *			variable too		 *	.MAIN		Its sources are only used if		 *			nothing has been specified to		 *			create.		 *	.DEFAULT    	Need to create a node to hang		 *			commands on, but we don't want		 *			it in the graph, nor do we want		 *			it to be the Main Target, so we		 *			create it, set OP_NOTMAIN and		 *			add it to the list, setting		 *			DEFAULT to the new node for		 *			later use. We claim the node is		 *	    	    	A transformation rule to make		 *	    	    	life easier later, when we'll		 *	    	    	use Make_HandleUse to actually		 *	    	    	apply the .DEFAULT commands.		 *	.BEGIN		 *	.END		 *	.INTERRUPT  	Are not to be considered the		 *			main target.		 *  	.NOTPARALLEL	Make only one target at a time.		 *  	.SINGLESHELL	Create a shell for each command.		 *  	.ORDER	    	Must set initial predecessor to NIL		 */		switch (specType) {		    case ExPath:			if (paths == NULL) {			    paths = Lst_Init(FALSE);			}			(void)Lst_AtEnd(paths, (ClientData)dirSearchPath);			break;		    case Main:			if (!Lst_IsEmpty(create)) {			    specType = Not;			}			break;		    case Begin:		    case End:		    case Interrupt:			gn = Targ_FindNode(line, TARG_CREATE);			gn->type |= OP_NOTMAIN;			(void)Lst_AtEnd(targets, (ClientData)gn);			break;		    case Default:			gn = Targ_NewGN(".DEFAULT");			gn->type |= (OP_NOTMAIN|OP_TRANSFORM);			(void)Lst_AtEnd(targets, (ClientData)gn);			DEFAULT = gn;			break;		    case NotParallel:		    {			extern int  maxJobs;						maxJobs = 1;			break;		    }		    case SingleShell:			compatMake = 1;			break;		    case Order:			predecessor = NILGNODE;			break;		    default:			break;		}	    } else if (strncmp (line, ".PATH", 5) == 0) {		/*		 * .PATH<suffix> has to be handled specially.		 * Call on the suffix module to give us a path to		 * modify.		 */		Lst 	path;				specType = ExPath;		path = Suff_GetPath (&line[5]);		if (path == NILLST) {		    Parse_Error (PARSE_FATAL,				 "Suffix '%s' not defined (yet)",				 &line[5]);		    return;		} else {		    if (paths == (Lst)NULL) {			paths = Lst_Init(FALSE);		    }		    (void)Lst_AtEnd(paths, (ClientData)path);		}	    }	}		/*	 * Have word in line. Get or create its node and stick it at	 * the end of the targets list 	 */	if ((specType == Not) && (*line != '\0')) {	    if (Dir_HasWildcards(line)) {		/*		 * Targets are to be sought only in the current directory,		 * so create an empty path for the thing. Note we need to		 * use Dir_Destroy in the destruction of the path as the		 * Dir module could have added a directory to the path...		 */		Lst	    emptyPath = Lst_Init(FALSE);				Dir_Expand(line, emptyPath, curTargs);				Lst_Destroy(emptyPath, Dir_Destroy);	    } else {		/*		 * No wildcards, but we want to avoid code duplication,		 * so create a list with the word on it.		 */		(void)Lst_AtEnd(curTargs, (ClientData)line);	    }	    	    while(!Lst_IsEmpty(curTargs)) {		char	*targName = (char *)Lst_DeQueue(curTargs);				if (!Suff_IsTransform (targName)) {		    gn = Targ_FindNode (targName, TARG_CREATE);		} else {		    gn = Suff_AddTransform (targName);		}				(void)Lst_AtEnd (targets, (ClientData)gn);	    }	} else if (specType == ExPath && *line != '.' && *line != '\0') {	    Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line);	}		*cp = savec;	/*	 * If it is a special type and not .PATH, it's the only target we	 * allow on this line...	 */	if (specType != Not && specType != ExPath) {	    Boolean warn = FALSE;	    	    while ((*cp != '!') && (*cp != ':') && *cp) {		if (*cp != ' ' && *cp != '\t') {		    warn = TRUE;		}		cp++;	    }	    if (warn) {		Parse_Error(PARSE_WARNING, "Extra target ignored");	    }	} else {	    while (*cp && isspace (*cp)) {		cp++;	    }	}	line = cp;    } while ((*line != '!') && (*line != ':') && *line);    /*     * Don't need the list of target names anymore...     */    Lst_Destroy(curTargs, NOFREE);    if (!Lst_IsEmpty(targets)) {	switch(specType) {	    default:		Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored");		break;	    case Default:	    case Begin:	    case End:	    case Interrupt:		/*		 * These four create nodes on which to hang commands, so		 * targets shouldn't be empty...		 */	    case Not:		/*		 * Nothing special here -- targets can be empty if it wants.		 */		break;	}    }    /*     * Have now parsed all the target names. Must parse the operator next. The     * result is left in  op .     */    if (*cp == '!') {	op = OP_FORCE;    } else if (*cp == ':') {	if (cp[1] == ':') {	    op = OP_DOUBLEDEP;	    cp++;	} else {	    op = OP_DEPENDS;	}    } else {	Parse_Error (PARSE_FATAL, "Missing dependency operator");	return;    }    cp++;			/* Advance beyond operator */    Lst_ForEach (targets, ParseDoOp, (ClientData)op);    /*     * Get to the first source      */    while (*cp && isspace (*cp)) {	cp++;    }    line = cp;    /*     * Several special targets take different actions if present with no     * sources:     *	a .SUFFIXES line with no sources clears out all old suffixes     *	a .PRECIOUS line makes all targets precious     *	a .IGNORE line ignores errors for all targets     *	a .SILENT line creates silence when making all targets     *	a .PATH removes all directories from the search path(s).     */    if (!*line) {	switch (specType) {	    case Suffixes:		Suff_ClearSuffixes ();		break;	    case Precious:		allPrecious = TRUE;		break;	    case Ignore:		ignoreErrors = TRUE;		break;	    case Silent:		beSilent = TRUE;		break;	    case ExPath:		Lst_ForEach(paths, ParseClearPath, (ClientData)NULL);		break;	    default:		break;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -