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

📄 parse.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Copyright (c) 1988, 1989, 1990, 1993 *	The Regents of the University of California.  All rights reserved. * Copyright (c) 1989 by Berkeley Softworks * All rights reserved. * * This code is derived from software contributed to Berkeley by * Adam de Boor. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)parse.c	8.3 (Berkeley) 3/19/94";#endif /* not lint *//*- * parse.c -- *	Functions to parse a makefile. * *	One function, Parse_Init, must be called before any functions *	in this module are used. After that, the function Parse_File is the *	main entry point and controls most of the other functions in this *	module. * *	Most important structures are kept in Lsts. Directories for *	the #include "..." function are kept in the 'parseIncPath' Lst, while *	those for the #include <...> are kept in the 'sysIncPath' Lst. The *	targets currently being defined are kept in the 'targets' Lst. * *	The variables 'fname' and 'lineno' are used to track the name *	of the current file and the line number in that file so that error *	messages can be more meaningful. * * Interface: *	Parse_Init	    	    Initialization function which must be *	    	  	    	    called before anything else in this module *	    	  	    	    is used. * *	Parse_File	    	    Function used to parse a makefile. It must *	    	  	    	    be given the name of the file, which should *	    	  	    	    already have been opened, and a function *	    	  	    	    to call to read a character from the file. * *	Parse_IsVar	    	    Returns TRUE if the given line is a *	    	  	    	    variable assignment. Used by MainParseArgs *	    	  	    	    to determine if an argument is a target *	    	  	    	    or a variable assignment. Used internally *	    	  	    	    for pretty much the same thing... * *	Parse_Error	    	    Function called when an error occurs in *	    	  	    	    parsing. Used by the variable and *	    	  	    	    conditional modules. *	Parse_MainName	    	    Returns a Lst of the main target to create. */#if __STDC__#include <stdarg.h>#else#include <varargs.h>#endif#include <stdio.h>#include <ctype.h>#include <errno.h>#include <sys/wait.h>#include "make.h"#include "hash.h"#include "dir.h"#include "job.h"#include "buf.h"#include "pathnames.h"/* * These values are returned by ParseEOF to tell Parse_File whether to * CONTINUE parsing, i.e. it had only reached the end of an include file, * or if it's DONE. */#define	CONTINUE	1#define	DONE		0static Lst     	    targets;	/* targets we're working on */static Boolean	    inLine;	/* true if currently in a dependency				 * line or its commands */typedef struct {    char *str;    char *ptr;} PTR;static char    	    *fname;	/* name of current file (for errors) */static int          lineno;	/* line number in current file */static FILE   	    *curFILE = NULL; 	/* current makefile */static PTR 	    *curPTR = NULL; 	/* current makefile */static int	    fatals = 0;static GNode	    *mainNode;	/* The main target to create. This is the				 * first target on the first dependency				 * line in the first makefile *//* * Definitions for handling #include specifications */typedef struct IFile {    char           *fname;	    /* name of previous file */    int             lineno;	    /* saved line number */    FILE *          F;		    /* the open stream */    PTR *	    p;	    	    /* the char pointer */} IFile;static Lst      includes;  	/* stack of IFiles generated by				 * #includes */Lst         	parseIncPath;	/* list of directories for "..." includes */Lst         	sysIncPath;	/* list of directories for <...> includes *//*- * specType contains the SPECial TYPE of the current target. It is * Not if the target is unspecial. If it *is* special, however, the children * are linked as children of the parent but not vice versa. This variable is * set in ParseDoDependency */typedef enum {    Begin,  	    /* .BEGIN */    Default,	    /* .DEFAULT */    End,    	    /* .END */    Ignore,	    /* .IGNORE */    Includes,	    /* .INCLUDES */    Interrupt,	    /* .INTERRUPT */    Libs,	    /* .LIBS */    MFlags,	    /* .MFLAGS or .MAKEFLAGS */    Main,	    /* .MAIN and we don't have anything user-specified to		     * make */    NoExport,	    /* .NOEXPORT */    Not,	    /* Not special */    NotParallel,    /* .NOTPARALELL */    Null,   	    /* .NULL */    Order,  	    /* .ORDER */    ExPath,	    /* .PATH */    Precious,	    /* .PRECIOUS */    ExShell,	    /* .SHELL */    Silent,	    /* .SILENT */    SingleShell,    /* .SINGLESHELL */    Suffixes,	    /* .SUFFIXES */    Attribute	    /* Generic attribute */} ParseSpecial;static ParseSpecial specType;/* * Predecessor node for handling .ORDER. Initialized to NILGNODE when .ORDER * seen, then set to each successive source on the line. */static GNode	*predecessor;/* * The parseKeywords table is searched using binary search when deciding * if a target or source is special. The 'spec' field is the ParseSpecial * type of the keyword ("Not" if the keyword isn't special as a target) while * the 'op' field is the operator to apply to the list of targets if the * keyword is used as a source ("0" if the keyword isn't special as a source) */static struct {    char    	  *name;    	/* Name of keyword */    ParseSpecial  spec;	    	/* Type when used as a target */    int	    	  op;	    	/* Operator when used as a source */} parseKeywords[] = {{ ".BEGIN", 	  Begin,    	0 },{ ".DEFAULT",	  Default,  	0 },{ ".OPTIONAL",	  Attribute,   	OP_OPTIONAL },{ ".END",   	  End,	    	0 },{ ".EXEC",	  Attribute,   	OP_EXEC },{ ".IGNORE",	  Ignore,   	OP_IGNORE },{ ".INCLUDES",	  Includes, 	0 },{ ".INTERRUPT",	  Interrupt,	0 },{ ".INVISIBLE",	  Attribute,   	OP_INVISIBLE },{ ".JOIN",  	  Attribute,   	OP_JOIN },{ ".LIBS",  	  Libs,	    	0 },{ ".MAIN",	  Main,		0 },{ ".MAKE",  	  Attribute,   	OP_MAKE },{ ".MAKEFLAGS",	  MFlags,   	0 },{ ".MFLAGS",	  MFlags,   	0 },{ ".NOTMAIN",	  Attribute,   	OP_NOTMAIN },{ ".NOTPARALLEL", NotParallel,	0 },{ ".NULL",  	  Null,	    	0 },{ ".ORDER", 	  Order,    	0 },{ ".PATH",	  ExPath,	0 },{ ".PRECIOUS",	  Precious, 	OP_PRECIOUS },{ ".RECURSIVE",	  Attribute,	OP_MAKE },{ ".SHELL", 	  ExShell,    	0 },{ ".SILENT",	  Silent,   	OP_SILENT },{ ".SINGLESHELL", SingleShell,	0 },{ ".SUFFIXES",	  Suffixes, 	0 },{ ".USE",   	  Attribute,   	OP_USE },};static int ParseFindKeyword __P((char *));static int ParseLinkSrc __P((GNode *, GNode *));static int ParseDoOp __P((GNode *, int));static void ParseDoSrc __P((int, char *));static int ParseFindMain __P((GNode *));static int ParseAddDir __P((Lst, char *));static int ParseClearPath __P((Lst));static void ParseDoDependency __P((char *));static int ParseAddCmd __P((GNode *, char *));static int ParseReadc __P((void));static void ParseUnreadc __P((int));static int ParseHasCommands __P((GNode *));static void ParseDoInclude __P((char *));#ifdef SYSVINCLUDEstatic void ParseTraditionalInclude __P((char *));#endifstatic int ParseEOF __P((int));static char *ParseReadLine __P((void));static char *ParseSkipLine __P((int));static void ParseFinishLine __P((void));/*- *---------------------------------------------------------------------- * ParseFindKeyword -- *	Look in the table of keywords for one matching the given string. * * Results: *	The index of the keyword, or -1 if it isn't there. * * Side Effects: *	None *---------------------------------------------------------------------- */static intParseFindKeyword (str)    char	    *str;		/* String to find */{    register int    start,		    end,		    cur;    register int    diff;        start = 0;    end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1;    do {	cur = start + ((end - start) / 2);	diff = strcmp (str, parseKeywords[cur].name);	if (diff == 0) {	    return (cur);	} else if (diff < 0) {	    end = cur - 1;	} else {	    start = cur + 1;	}    } while (start <= end);    return (-1);}/*- * Parse_Error  -- *	Error message abort function for parsing. Prints out the context *	of the error (line number and file) as well as the message with *	two optional arguments. * * Results: *	None * * Side Effects: *	"fatals" is incremented if the level is PARSE_FATAL. *//* VARARGS */void#if __STDC__Parse_Error(int type, const char *fmt, ...)#elseParse_Error(va_alist)	va_dcl#endif{	va_list ap;#if __STDC__	va_start(ap, fmt);#else	int type;		/* Error type (PARSE_WARNING, PARSE_FATAL) */	char *fmt;	va_start(ap);	type = va_arg(ap, int);	fmt = va_arg(ap, char *);#endif	(void)fprintf(stderr, "\"%s\", line %d: ", fname, lineno);	if (type == PARSE_WARNING)		(void)fprintf(stderr, "warning: ");	(void)vfprintf(stderr, fmt, ap);	va_end(ap);	(void)fprintf(stderr, "\n");	(void)fflush(stderr);	if (type == PARSE_FATAL)		fatals += 1;}/*- *--------------------------------------------------------------------- * ParseLinkSrc  -- *	Link the parent node to its new child. Used in a Lst_ForEach by *	ParseDoDependency. If the specType isn't 'Not', the parent *	isn't linked as a parent of the child. * * Results: *	Always = 0 * * Side Effects: *	New elements are added to the parents list of cgn and the *	children list of cgn. the unmade field of pgn is updated *	to reflect the additional child. *--------------------------------------------------------------------- */static intParseLinkSrc (pgn, cgn)    GNode          *pgn;	/* The parent node */    GNode          *cgn;	/* The child node */{    if (Lst_Member (pgn->children, (ClientData)cgn) == NILLNODE) {	(void)Lst_AtEnd (pgn->children, (ClientData)cgn);	if (specType == Not) {	    (void)Lst_AtEnd (cgn->parents, (ClientData)pgn);	}	pgn->unmade += 1;    }    return (0);}/*- *--------------------------------------------------------------------- * ParseDoOp  -- *	Apply the parsed operator to the given target node. Used in a *	Lst_ForEach call by ParseDoDependency once all targets have *	been found and their operator parsed. If the previous and new *	operators are incompatible, a major error is taken. * * Results: *	Always 0 * * Side Effects: *	The type field of the node is altered to reflect any new bits in *	the op. *--------------------------------------------------------------------- */static intParseDoOp (gn, op)    GNode          *gn;		/* The node to which the operator is to be				 * applied */    int             op;		/* The operator to apply */{    /*     * If the dependency mask of the operator and the node don't match and     * the node has actually had an operator applied to it before, and     * the operator actually has some dependency information in it, complain.      */    if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) &&	!OP_NOP(gn->type) && !OP_NOP(op))    {	Parse_Error (PARSE_FATAL, "Inconsistent operator for %s", gn->name);	return (1);    }    if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) {	/*	 * If the node was the object of a :: operator, we need to create a	 * new instance of it for the children and commands on this dependency	 * line. The new instance is placed on the 'cohorts' list of the	 * initial one (note the initial one is not on its own cohorts list)	 * and the new instance is linked to all parents of the initial	 * instance.	 */	register GNode	*cohort;	LstNode	    	ln;				cohort = Targ_NewGN(gn->name);	/*	 * Duplicate links to parents so graph traversal is simple. Perhaps	 * some type bits should be duplicated?	 *	 * Make the cohort invisible as well to avoid duplicating it into	 * other variables. True, parents of this target won't tend to do	 * anything with their local variables, but better safe than	 * sorry.	 */	Lst_ForEach(gn->parents, ParseLinkSrc, (ClientData)cohort);	cohort->type = OP_DOUBLEDEP|OP_INVISIBLE;	(void)Lst_AtEnd(gn->cohorts, (ClientData)cohort);	/*	 * Replace the node in the targets list with the new copy	 */	ln = Lst_Member(targets, (ClientData)gn);	Lst_Replace(ln, (ClientData)cohort);	gn = cohort;    }    /*     * We don't want to nuke any previous flags (whatever they were) so we     * just OR the new operator into the old      */    gn->type |= op;    return (0);}/*- *--------------------------------------------------------------------- * ParseDoSrc  -- *	Given the name of a source, figure out if it is an attribute *	and apply it to the targets if it is. Else decide if there is *	some attribute which should be applied *to* the source because *	of some special target and apply it if so. Otherwise, make the *	source be a child of the targets in the list 'targets' * * Results: *	None * * Side Effects: *	Operator bits may be added to the list of targets or to the source. *	The targets may have a new source added to their lists of children. *--------------------------------------------------------------------- */static voidParseDoSrc (tOp, src)    int		tOp;	/* operator (if any) from special targets */    char	*src;	/* name of the source to handle */{    int		op;	/* operator (if any) from special source */    GNode	*gn;    op = 0;    if (*src == '.' && isupper (src[1])) {	int keywd = ParseFindKeyword(src);	if (keywd != -1) {	    op = parseKeywords[keywd].op;	}    }    if (op != 0) {	Lst_ForEach (targets, ParseDoOp, (ClientData)op);    } else if (specType == Main) {	/*	 * If we have noted the existence of a .MAIN, it means we need	 * to add the sources of said target to the list of things	 * to create. The string 'src' is likely to be free, so we	 * must make a new copy of it. Note that this will only be	 * invoked if the user didn't specify a target on the command	 * line. This is to allow #ifmake's to succeed, or something...	 */	(void) Lst_AtEnd (create, (ClientData)strdup(src));	/*	 * Add the name to the .TARGETS variable as well, so the user cna	 * employ that, if desired.	 */	Var_Append(".TARGETS", src, VAR_GLOBAL);    } else if (specType == Order) {	/*	 * Create proper predecessor/successor links between the previous	 * source and the current one.	 */	gn = Targ_FindNode(src, TARG_CREATE);	if (predecessor != NILGNODE) {

⌨️ 快捷键说明

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