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

📄 parse.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
 * Side Effects: *--------------------------------------------------------------------- */static intParseReadc(){    if (curFILE)	return fgetc(curFILE);	      if (curPTR && *curPTR->ptr)	return *curPTR->ptr++;    return EOF;}/*- *--------------------------------------------------------------------- * ParseUnreadc  -- *	Put back a character to the current file  * * Results: *	None. * * Side Effects: *--------------------------------------------------------------------- */static voidParseUnreadc(c)    int c;{    if (curFILE) {	ungetc(c, curFILE);	return;    }    if (curPTR) {	*--(curPTR->ptr) = c;	return;    }}/* ParseSkipLine(): *	Grab the next line */static char *ParseSkipLine(skip)    int skip; 		/* Skip lines that don't start with . */{    char *line;    int c, lastc = '\0', lineLength;    Buffer buf;    c = ParseReadc();    if (skip) {	/*	 * Skip lines until get to one that begins with a	 * special char.	 */	while ((c != '.') && (c != EOF)) {	    while (((c != '\n') || (lastc == '\\')) && (c != EOF))	    {		/*		 * Advance to next unescaped newline		 */		if ((lastc = c) == '\n') {		    lineno++;		}		c = ParseReadc();	    }	    lineno++;	    	    lastc = c;	    c = ParseReadc ();	}    }        if (c == EOF) {	Parse_Error (PARSE_FATAL, "Unclosed conditional/for loop");	return ((char *)NULL);    }        /*     * Read the entire line into buf     */    buf = Buf_Init (MAKE_BSIZE);    if (c != '\n') {	do {	    Buf_AddByte (buf, (Byte)c);	    c = ParseReadc();	} while ((c != '\n') && (c != EOF));    }    lineno++;        Buf_AddByte (buf, (Byte)'\0');    line = (char *)Buf_GetAll (buf, &lineLength);    Buf_Destroy (buf, FALSE);    return line;}/*- *--------------------------------------------------------------------- * ParseReadLine -- *	Read an entire line from the input file. Called only by Parse_File. *	To facilitate escaped newlines and what have you, a character is *	buffered in 'lastc', which is '\0' when no characters have been *	read. When we break out of the loop, c holds the terminating *	character and lastc holds a character that should be added to *	the line (unless we don't read anything but a terminator). * * Results: *	A line w/o its newline * * Side Effects: *	Only those associated with reading a character *--------------------------------------------------------------------- */static char *ParseReadLine (){    Buffer  	  buf;	    	/* Buffer for current line */    register int  c;	      	/* the current character */    register int  lastc;    	/* The most-recent character */    Boolean	  semiNL;     	/* treat semi-colons as newlines */    Boolean	  ignDepOp;   	/* TRUE if should ignore dependency operators				 * for the purposes of setting semiNL */    Boolean 	  ignComment;	/* TRUE if should ignore comments (in a				 * shell command */    char    	  *line;    	/* Result */    int	    	  lineLength;	/* Length of result */    semiNL = FALSE;    ignDepOp = FALSE;    ignComment = FALSE;    /*     * Handle special-characters at the beginning of the line. Either a     * leading tab (shell command) or pound-sign (possible conditional)     * forces us to ignore comments and dependency operators and treat     * semi-colons as semi-colons (by leaving semiNL FALSE). This also     * discards completely blank lines.     */    for (;;) {	c = ParseReadc();	if (c == '\t') {	    ignComment = ignDepOp = TRUE;	    break;	} else if (c == '\n') {	    lineno++;	} else if (c == '#') {	    ParseUnreadc(c);	    break;	} else {	    /*	     * Anything else breaks out without doing anything	     */	    break;	}    }	    if (c != EOF) {	lastc = c;	buf = Buf_Init(MAKE_BSIZE);		while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) &&	       (c != EOF))	{test_char:	    switch(c) {	    case '\n':		/*		 * Escaped newline: read characters until a non-space or an		 * unescaped newline and replace them all by a single space.		 * This is done by storing the space over the backslash and		 * dropping through with the next nonspace. If it is a		 * semi-colon and semiNL is TRUE, it will be recognized as a		 * newline in the code below this...		 */		lineno++;		lastc = ' ';		while ((c = ParseReadc ()) == ' ' || c == '\t') {		    continue;		}		if (c == EOF || c == '\n') {		    goto line_read;		} else {		    /*		     * Check for comments, semiNL's, etc. -- easier than		     * ParseUnreadc(c); continue;		     */		    goto test_char;		}		/*NOTREACHED*/		break;	    case ';':		/*		 * Semi-colon: Need to see if it should be interpreted as a		 * newline		 */		if (semiNL) {		    /*		     * To make sure the command that may be following this		     * semi-colon begins with a tab, we push one back into the		     * input stream. This will overwrite the semi-colon in the		     * buffer. If there is no command following, this does no		     * harm, since the newline remains in the buffer and the		     * whole line is ignored.		     */		    ParseUnreadc('\t');		    goto line_read;		} 		break;	    case '=':		if (!semiNL) {		    /*		     * Haven't seen a dependency operator before this, so this		     * must be a variable assignment -- don't pay attention to		     * dependency operators after this.		     */		    ignDepOp = TRUE;		} else if (lastc == ':' || lastc == '!') {		    /*		     * Well, we've seen a dependency operator already, but it		     * was the previous character, so this is really just an		     * expanded variable assignment. Revert semi-colons to		     * being just semi-colons again and ignore any more		     * dependency operators.		     *		     * XXX: Note that a line like "foo : a:=b" will blow up,		     * but who'd write a line like that anyway?		     */		    ignDepOp = TRUE; semiNL = FALSE;		}		break;	    case '#':		if (!ignComment) {		    if (compatMake || (lastc != '\\')) {			/*			 * If the character is a hash mark and it isn't escaped			 * (or we're being compatible), the thing is a comment.			 * Skip to the end of the line.			 */			do {			    c = ParseReadc();			} while ((c != '\n') && (c != EOF));			goto line_read;		    } else {			/*			 * Don't add the backslash. Just let the # get copied			 * over.			 */			lastc = c;			continue;		    }		}		break;	    case ':':	    case '!':		if (!ignDepOp && (c == ':' || c == '!')) {		    /*		     * A semi-colon is recognized as a newline only on		     * dependency lines. Dependency lines are lines with a		     * colon or an exclamation point. Ergo...		     */		    semiNL = TRUE;		}		break;	    }	    /*	     * Copy in the previous character and save this one in lastc.	     */	    Buf_AddByte (buf, (Byte)lastc);	    lastc = c;	    	}    line_read:	lineno++;		if (lastc != '\0') {	    Buf_AddByte (buf, (Byte)lastc);	}	Buf_AddByte (buf, (Byte)'\0');	line = (char *)Buf_GetAll (buf, &lineLength);	Buf_Destroy (buf, FALSE);		if (line[0] == '.') {	    /*	     * The line might be a conditional. Ask the conditional module	     * about it and act accordingly	     */	    switch (Cond_Eval (line)) {	    case COND_SKIP:		/*		 * Skip to next conditional that evaluates to COND_PARSE.		 */		do {		    free (line);		    line = ParseSkipLine(1);		} while (line && Cond_Eval(line) != COND_PARSE);		if (line == NULL)		    break;		/*FALLTHRU*/	    case COND_PARSE:		free ((Address) line);		line = ParseReadLine();		break;	    case COND_INVALID:		if (For_Eval(line)) {		    int ok;		    free(line);		    do {			/*			 * Skip after the matching end			 */			line = ParseSkipLine(0);			if (line == NULL) {			    Parse_Error (PARSE_FATAL, 				     "Unexpected end of file in for loop.\n");			    break;			}			ok = For_Eval(line);			free(line);		    }		    while (ok);		    if (line != NULL)			For_Run();		    line = ParseReadLine();		}		break;	    }	}	return (line);    } else {	/*	 * Hit end-of-file, so return a NULL line to indicate this.	 */	return((char *)NULL);    }}/*- *----------------------------------------------------------------------- * ParseFinishLine -- *	Handle the end of a dependency group. * * Results: *	Nothing. * * Side Effects: *	inLine set FALSE. 'targets' list destroyed. * *----------------------------------------------------------------------- */static voidParseFinishLine(){    extern int Suff_EndTransform();    if (inLine) {	Lst_ForEach(targets, Suff_EndTransform, (ClientData)NULL);	Lst_Destroy (targets, ParseHasCommands);	inLine = FALSE;    }}		    /*- *--------------------------------------------------------------------- * Parse_File -- *	Parse a file into its component parts, incorporating it into the *	current dependency graph. This is the main function and controls *	almost every other function in this module * * Results: *	None * * Side Effects: *	Loads. Nodes are added to the list of all targets, nodes and links *	are added to the dependency graph. etc. etc. etc. *--------------------------------------------------------------------- */voidParse_File(name, stream)    char          *name;	/* the name of the file being read */    FILE *	  stream;   	/* Stream open to makefile to parse */{    register char *cp,		/* pointer into the line */                  *line;	/* the line we're working on */    inLine = FALSE;    fname = name;    curFILE = stream;    lineno = 0;    fatals = 0;    do {	while ((line = ParseReadLine ()) != NULL) {	    if (*line == '.') {		/*		 * Lines that begin with the special character are either		 * include or undef directives.		 */		for (cp = line + 1; isspace (*cp); cp++) {		    continue;		}		if (strncmp (cp, "include", 7) == 0) {		    ParseDoInclude (cp + 7);		    goto nextLine;		} else if (strncmp(cp, "undef", 5) == 0) {		    char *cp2;		    for (cp += 5; isspace(*cp); cp++) {			continue;		    }		    for (cp2 = cp; !isspace(*cp2) && (*cp2 != '\0'); cp2++) {			continue;		    }		    *cp2 = '\0';		    Var_Delete(cp, VAR_GLOBAL);		    goto nextLine;		}	    }	    if (*line == '#') {		/* If we're this far, the line must be a comment. */		goto nextLine;	    }	    	    if (*line == '\t'#ifdef POSIX		       || *line == ' '#endif		       )	    {		/*		 * If a line starts with a tab (or space in POSIX-land), it		 * can only hope to be a creation command.		 */	    shellCommand:		for (cp = line + 1; isspace (*cp); cp++) {		    continue;		}		if (*cp) {		    if (inLine) {			/*			 * So long as it's not a blank line and we're actually			 * in a dependency spec, add the command to the list of			 * commands of all targets in the dependency spec 			 */			Lst_ForEach (targets, ParseAddCmd, (ClientData)cp);			continue;		    } else {			Parse_Error (PARSE_FATAL,				     "Unassociated shell command \"%.20s\"",				     cp);		    }		}#ifdef SYSVINCLUDE	    } else if (strncmp (line, "include", 7) == 0 && 		       strchr(line, ':') == NULL) {		/*		 * It's an S3/S5-style "include".		 */		ParseTraditionalInclude (line + 7);		goto nextLine;#endif	    } else if (Parse_IsVar (line)) {		ParseFinishLine();		Parse_DoVar (line, VAR_GLOBAL);	    } else {		/*		 * We now know it's a dependency line so it needs to have all		 * variables expanded before being parsed. Tell the variable		 * module to complain if some variable is undefined...		 * To make life easier on novices, if the line is indented we		 * first make sure the line has a dependency operator in it.		 * If it doesn't have an operator and we're in a dependency		 * line's script, we assume it's actually a shell command	

⌨️ 快捷键说明

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