Module Name:    src
Committed By:   rillig
Date:           Sat Oct 17 20:37:38 UTC 2020

Modified Files:
        src/usr.bin/make: parse.c

Log Message:
make(1): split Parse_File into smaller functions


To generate a diff of this commit:
cvs rdiff -u -r1.378 -r1.379 src/usr.bin/make/parse.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/make/parse.c
diff -u src/usr.bin/make/parse.c:1.378 src/usr.bin/make/parse.c:1.379
--- src/usr.bin/make/parse.c:1.378	Sat Oct 17 20:32:20 2020
+++ src/usr.bin/make/parse.c	Sat Oct 17 20:37:38 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: parse.c,v 1.378 2020/10/17 20:32:20 rillig Exp $	*/
+/*	$NetBSD: parse.c,v 1.379 2020/10/17 20:37:38 rillig Exp $	*/
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
@@ -131,7 +131,7 @@
 #include "pathnames.h"
 
 /*	"@(#)parse.c	8.3 (Berkeley) 3/19/94"	*/
-MAKE_RCSID("$NetBSD: parse.c,v 1.378 2020/10/17 20:32:20 rillig Exp $");
+MAKE_RCSID("$NetBSD: parse.c,v 1.379 2020/10/17 20:37:38 rillig Exp $");
 
 /* types and constants */
 
@@ -2883,6 +2883,155 @@ ParseLine_ShellCommand(const char *p)
     }
 }
 
+static Boolean
+ParseDirective(char *line)
+{
+    char *cp;
+
+    if (*line == '.') {
+	/*
+	 * Lines that begin with the special character may be
+	 * include or undef directives.
+	 * On the other hand they can be suffix rules (.c.o: ...)
+	 * or just dependencies for filenames that start '.'.
+	 */
+	cp = line + 1;
+	pp_skip_whitespace(&cp);
+	if (IsInclude(cp, FALSE)) {
+	    ParseDoInclude(cp);
+	    return TRUE;
+	}
+	if (strncmp(cp, "undef", 5) == 0) {
+	    const char *varname;
+	    cp += 5;
+	    pp_skip_whitespace(&cp);
+	    varname = cp;
+	    for (; !ch_isspace(*cp) && *cp != '\0'; cp++)
+		continue;
+	    *cp = '\0';
+	    Var_Delete(varname, VAR_GLOBAL);
+	    /* TODO: undefine all variables, not only the first */
+	    /* TODO: use Str_Words, like everywhere else */
+	    return TRUE;
+	} else if (strncmp(cp, "export", 6) == 0) {
+	    cp += 6;
+	    pp_skip_whitespace(&cp);
+	    Var_Export(cp, TRUE);
+	    return TRUE;
+	} else if (strncmp(cp, "unexport", 8) == 0) {
+	    Var_UnExport(cp);
+	    return TRUE;
+	} else if (strncmp(cp, "info", 4) == 0 ||
+		   strncmp(cp, "error", 5) == 0 ||
+		   strncmp(cp, "warning", 7) == 0) {
+	    if (ParseMessage(cp))
+		return TRUE;
+	}
+    }
+    return FALSE;
+}
+
+static Boolean
+ParseVarassign(const char *line)
+{
+    VarAssign var;
+    if (Parse_IsVar(line, &var)) {
+	FinishDependencyGroup();
+	Parse_DoVar(&var, VAR_GLOBAL);
+	return TRUE;
+    }
+    return FALSE;
+}
+
+/* dependency	-> target... op [source...]
+ * op		-> ':' | '::' | '!' */
+static void
+ParseDependency(char *line, const char **out_shellcmd)
+{
+    VarEvalFlags eflags;
+    char *expanded_line;
+
+    /*
+     * For some reason - probably to make the parser impossible -
+     * a ';' can be used to separate commands from dependencies.
+     * Attempt to avoid ';' inside substitution patterns.
+     */
+    {
+	int level = 0;
+	char *cp;
+
+	for (cp = line; *cp != 0; cp++) {
+	    if (*cp == '\\' && cp[1] != 0) {
+		cp++;
+		continue;
+	    }
+	    if (*cp == '$' &&
+		(cp[1] == '(' || cp[1] == '{')) {
+		level++;
+		continue;
+	    }
+	    if (level > 0) {
+		if (*cp == ')' || *cp == '}') {
+		    level--;
+		    continue;
+		}
+	    } else if (*cp == ';') {
+		break;
+	    }
+	}
+
+	if (*cp != 0) {
+	    /* Terminate the dependency list at the ';' */
+	    *cp++ = 0;
+	    *out_shellcmd = cp;
+	} else
+	    *out_shellcmd = NULL;
+    }
+
+    /*
+     * We now know it's a dependency line so it needs to have all
+     * variables expanded before being parsed.
+     *
+     * XXX: Ideally the dependency line would first be split into
+     * its left-hand side, dependency operator and right-hand side,
+     * and then each side would be expanded on its own.  This would
+     * allow for the left-hand side to allow only defined variables
+     * and to allow variables on the right-hand side to be undefined
+     * as well.
+     *
+     * Parsing the line first would also prevent that targets
+     * generated from variable expressions are interpreted as the
+     * dependency operator, such as in "target${:U:} middle: source",
+     * in which the middle is interpreted as a source, not a target.
+     */
+
+    /* In lint mode, allow undefined variables to appear in
+     * dependency lines.
+     *
+     * Ideally, only the right-hand side would allow undefined
+     * variables since it is common to have no dependencies.
+     * Having undefined variables on the left-hand side is more
+     * unusual though.  Since both sides are expanded in a single
+     * pass, there is not much choice what to do here.
+     *
+     * In normal mode, it does not matter whether undefined
+     * variables are allowed or not since as of 2020-09-14,
+     * Var_Parse does not print any parse errors in such a case.
+     * It simply returns the special empty string var_Error,
+     * which cannot be detected in the result of Var_Subst. */
+    eflags = DEBUG(LINT) ? VARE_WANTRES : VARE_UNDEFERR | VARE_WANTRES;
+    (void)Var_Subst(line, VAR_CMD, eflags, &expanded_line);
+    /* TODO: handle errors */
+
+    /* Need a fresh list for the target nodes */
+    if (targets != NULL)
+	Lst_Free(targets);
+    targets = Lst_Init();
+
+    ParseDoDependency(expanded_line);
+    free(expanded_line);
+}
+
 /* Parse a top-level makefile into its component parts, incorporating them
  * into the global dependency graph.
  *
@@ -2893,7 +3042,6 @@ ParseLine_ShellCommand(const char *p)
 void
 Parse_File(const char *name, int fd)
 {
-    char *cp;			/* pointer into the line */
     char *line;			/* the line we're working on */
     struct loadedfile *lf;
 
@@ -2911,55 +3059,12 @@ Parse_File(const char *name, int fd)
     do {
 	for (; (line = ParseReadLine()) != NULL; ) {
 	    DEBUG2(PARSE, "ParseReadLine (%d): '%s'\n", curFile->lineno, line);
-	    if (*line == '.') {
-		/*
-		 * Lines that begin with the special character may be
-		 * include or undef directives.
-		 * On the other hand they can be suffix rules (.c.o: ...)
-		 * or just dependencies for filenames that start '.'.
-		 */
-		cp = line + 1;
-		pp_skip_whitespace(&cp);
-		if (IsInclude(cp, FALSE)) {
-		    ParseDoInclude(cp);
-		    continue;
-		}
-		if (strncmp(cp, "undef", 5) == 0) {
-		    const char *varname;
-		    cp += 5;
-		    pp_skip_whitespace(&cp);
-		    varname = cp;
-		    for (; !ch_isspace(*cp) && *cp != '\0'; cp++)
-			continue;
-		    *cp = '\0';
-		    Var_Delete(varname, VAR_GLOBAL);
-		    /* TODO: undefine all variables, not only the first */
-		    /* TODO: use Str_Words, like everywhere else */
-		    continue;
-		} else if (strncmp(cp, "export", 6) == 0) {
-		    cp += 6;
-		    pp_skip_whitespace(&cp);
-		    Var_Export(cp, TRUE);
-		    continue;
-		} else if (strncmp(cp, "unexport", 8) == 0) {
-		    Var_UnExport(cp);
-		    continue;
-		} else if (strncmp(cp, "info", 4) == 0 ||
-			   strncmp(cp, "error", 5) == 0 ||
-			   strncmp(cp, "warning", 7) == 0) {
-		    if (ParseMessage(cp))
-			continue;
-		}
-	    }
+
+	    if (ParseDirective(line))
+		continue;
 
 	    if (*line == '\t') {
-		/*
-		 * If a line starts with a tab, it can only hope to be
-		 * a creation command.
-		 */
-		cp = line + 1;
-	    shellCommand:
-		ParseLine_ShellCommand(cp);
+		ParseLine_ShellCommand(line + 1);
 		continue;
 	    }
 
@@ -2982,100 +3087,20 @@ Parse_File(const char *name, int fd)
 		continue;
 	    }
 #endif
-	    {
-		VarAssign var;
-		if (Parse_IsVar(line, &var)) {
-		    FinishDependencyGroup();
-		    Parse_DoVar(&var, VAR_GLOBAL);
-		    continue;
-		}
-	    }
+	    if (ParseVarassign(line))
+		continue;
 
+#ifndef POSIX
+	    if (ParseNoviceMistake())
+	        continue;
+#endif
 	    FinishDependencyGroup();
 
-	    /*
-	     * For some reason - probably to make the parser impossible -
-	     * a ';' can be used to separate commands from dependencies.
-	     * Attempt to avoid ';' inside substitution patterns.
-	     */
-	    {
-		int level = 0;
-
-		for (cp = line; *cp != 0; cp++) {
-		    if (*cp == '\\' && cp[1] != 0) {
-			cp++;
-			continue;
-		    }
-		    if (*cp == '$' &&
-			(cp[1] == '(' || cp[1] == '{')) {
-			level++;
-			continue;
-		    }
-		    if (level > 0) {
-			if (*cp == ')' || *cp == '}') {
-			    level--;
-			    continue;
-			}
-		    } else if (*cp == ';') {
-			break;
-		    }
-		}
-	    }
-	    if (*cp != 0)
-		/* Terminate the dependency list at the ';' */
-		*cp++ = 0;
-	    else
-		cp = NULL;
-
-	    /*
-	     * We now know it's a dependency line so it needs to have all
-	     * variables expanded before being parsed.
-	     *
-	     * XXX: Ideally the dependency line would first be split into
-	     * its left-hand side, dependency operator and right-hand side,
-	     * and then each side would be expanded on its own.  This would
-	     * allow for the left-hand side to allow only defined variables
-	     * and to allow variables on the right-hand side to be undefined
-	     * as well.
-	     *
-	     * Parsing the line first would also prevent that targets
-	     * generated from variable expressions are interpreted as the
-	     * dependency operator, such as in "target${:U:} middle: source",
-	     * in which the middle is interpreted as a source, not a target.
-	     */
 	    {
-		/* In lint mode, allow undefined variables to appear in
-		 * dependency lines.
-		 *
-		 * Ideally, only the right-hand side would allow undefined
-		 * variables since it is common to have no dependencies.
-		 * Having undefined variables on the left-hand side is more
-		 * unusual though.  Since both sides are expanded in a single
-		 * pass, there is not much choice what to do here.
-		 *
-		 * In normal mode, it does not matter whether undefined
-		 * variables are allowed or not since as of 2020-09-14,
-		 * Var_Parse does not print any parse errors in such a case.
-		 * It simply returns the special empty string var_Error,
-		 * which cannot be detected in the result of Var_Subst. */
-		VarEvalFlags eflags = DEBUG(LINT)
-				      ? VARE_WANTRES
-				      : VARE_UNDEFERR|VARE_WANTRES;
-		(void)Var_Subst(line, VAR_CMD, eflags, &line);
-		/* TODO: handle errors */
-	    }
-
-	    /* Need a fresh list for the target nodes */
-	    if (targets != NULL)
-		Lst_Free(targets);
-	    targets = Lst_Init();
-
-	    ParseDoDependency(line);
-	    free(line);
-
-	    /* If there were commands after a ';', add them now */
-	    if (cp != NULL) {
-		goto shellCommand;
+		const char *shellcmd;
+		ParseDependency(line, &shellcmd);
+		if (shellcmd != NULL)
+		    ParseLine_ShellCommand(shellcmd);
 	    }
 	}
 	/*

Reply via email to