Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/usr.bin/make make(1): split Parse_File into smaller functions
details: https://anonhg.NetBSD.org/src/rev/fef20f3f1a9a
branches: trunk
changeset: 944964:fef20f3f1a9a
user: rillig <rillig%NetBSD.org@localhost>
date: Sat Oct 17 20:37:38 2020 +0000
description:
make(1): split Parse_File into smaller functions
diffstat:
usr.bin/make/parse.c | 307 +++++++++++++++++++++++++++-----------------------
1 files changed, 166 insertions(+), 141 deletions(-)
diffs (truncated from 354 to 300 lines):
diff -r fbb2210682db -r fef20f3f1a9a usr.bin/make/parse.c
--- a/usr.bin/make/parse.c Sat Oct 17 20:32:20 2020 +0000
+++ b/usr.bin/make/parse.c Sat Oct 17 20:37:38 2020 +0000
@@ -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 @@
}
}
+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 @@
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 @@
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 @@
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
Home |
Main Index |
Thread Index |
Old Index