version 1.10, 1999/12/16 17:02:45 |
version 1.11, 1999/12/16 17:07:20 |
|
|
* ... |
* ... |
* .endfor |
* .endfor |
* |
* |
* The trick is to look for the matching end inside for for loop |
* The trick is to look for the matching .end inside .for loops. |
* To do that, we count the current nesting level of the for loops. |
* To do that, we keep track of the nesting level of .for loops |
* and the .endfor statements, accumulating all the statements between |
* and matching .endfor statements, accumulating all statements between |
* the initial .for loop and the matching .endfor; |
* the initial .for loop and the matching .endfor, |
* then we evaluate the for loop for each variable in the varlist. |
* then we evaluate the .for loop for each variable in the varlist. |
*/ |
*/ |
|
|
static int forLevel = 0; /* Nesting level */ |
/* State of a for loop. */ |
static char *forVar; /* Iteration variable */ |
struct For_ { |
static BUFFER forBuf; /* Commands in loop */ |
char *text; /* unexpanded text */ |
static Lst forLst; /* List of items */ |
char *var; /* Index name */ |
static unsigned long forLineno; /* Line at beginning of loop */ |
Lst lst; /* List of items */ |
|
BUFFER buf; /* Accumulating text */ |
|
unsigned long lineno; /* Line number at start of loop */ |
|
unsigned long level; /* Nesting level */ |
|
}; |
|
|
/* |
static int ForExec __P((ClientData, ClientData)); |
* State of a for loop. |
|
*/ |
|
typedef struct _For { |
|
Buffer buf; /* Unexpanded buffer */ |
|
char* var; /* Index name */ |
|
Lst lst; /* List of variables */ |
|
unsigned long lineno; |
|
} For; |
|
|
|
static int ForExec __P((ClientData, ClientData)); |
|
static void build_words_list __P((Lst, const char *)); |
static void build_words_list __P((Lst, const char *)); |
|
|
/* Cut a string into words, stuff that into list. */ |
/* Cut a string into words, stuff that into list. */ |
|
|
break; |
break; |
for (wrd = s; *s != '\0' && !isspace(*s); s++) |
for (wrd = s; *s != '\0' && !isspace(*s); s++) |
continue; |
continue; |
/* note that we fill the list backward, since |
/* note that we fill the list backward, since |
* Parse_FromString stacks strings. */ |
* Parse_FromString stacks strings. */ |
Lst_AtFront(lst, (ClientData)interval_dup(wrd, s)); |
Lst_AtFront(lst, (ClientData)interval_dup(wrd, s)); |
} |
} |
} |
} |
|
|
|
/* |
/*- |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* For_Eval -- |
* For_Eval -- |
* Evaluate the for loop in the passed line. The line |
* Evaluate the for loop in the passed line. The line |
|
|
* .for <variable> in <varlist> |
* .for <variable> in <varlist> |
* |
* |
* Results: |
* Results: |
* TRUE: We found a for loop, or we are inside a for loop |
* Loop structure, to accumulate further lines. |
* FALSE: We did not find a for loop, or we found the end of the for |
* NULL if this was not a for loop after all. |
* for loop. |
|
* |
|
* Side Effects: |
|
* None. |
|
* |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
int |
|
For_Eval (line) |
For * |
|
For_Eval(line) |
char *line; /* Line to parse */ |
char *line; /* Line to parse */ |
{ |
{ |
char *ptr = line; |
char *ptr = line; |
int level; /* Level at which to report errors. */ |
char *wrd; |
|
char *sub; |
|
char *endVar; |
|
For *arg; |
|
|
level = PARSE_FATAL; |
for (ptr++; *ptr && isspace(*ptr); ptr++) |
|
continue; |
|
/* If we are not in a for loop quickly determine if the statement is |
|
* a for. */ |
|
if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' || |
|
!isspace(ptr[3])) |
|
return NULL; |
|
ptr += 4; |
|
|
|
while (*ptr && isspace(*ptr)) |
|
ptr++; |
|
|
if (forLevel == 0) { |
/* We found a for loop, and now we are going to parse it. */ |
char *endVar; |
|
char *sub; |
|
char *wrd; |
|
|
|
for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++) |
/* Grab the variable. */ |
continue; |
for (wrd = ptr; *ptr && !isspace(*ptr); ptr++) |
/* If we are not in a for loop quickly determine if the statement is |
continue; |
* a for. */ |
if (ptr - wrd == 0) { |
if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' || |
Parse_Error(PARSE_FATAL, "missing variable in for"); |
!isspace((unsigned char) ptr[3])) |
return 0; |
return FALSE; |
} |
ptr += 3; |
endVar = ptr++; |
|
|
/* We found a for loop, and now we are going to parse it. */ |
while (*ptr && isspace(*ptr)) |
while (*ptr && isspace((unsigned char) *ptr)) |
ptr++; |
ptr++; |
|
|
|
/* Grab the variable. */ |
/* Grab the `in'. */ |
for (wrd = ptr; *ptr && !isspace((unsigned char) *ptr); ptr++) |
if (ptr[0] != 'i' || ptr[1] != 'n' || |
continue; |
!isspace(ptr[2])) { |
|
Parse_Error(PARSE_FATAL, "missing `in' in for"); |
|
printf("%s\n", ptr); |
|
return NULL; |
|
} |
|
ptr += 3; |
|
|
if (ptr - wrd == 0) { |
/* .for loop is go, collate what we need. */ |
Parse_Error(level, "missing variable in for"); |
arg = emalloc(sizeof(*arg)); |
return 0; |
arg->var = interval_dup(wrd, endVar); |
} |
|
endVar = ptr++; |
|
|
|
while (*ptr && isspace((unsigned char) *ptr)) |
/* Make a list with the remaining words. */ |
ptr++; |
sub = Var_Subst(NULL, ptr, VAR_GLOBAL, FALSE); |
|
if (DEBUG(FOR)) |
|
(void)fprintf(stderr, "For: Iterator %s List %s\n", arg->var, sub); |
|
|
/* Grab the `in'. */ |
arg->lst = Lst_Init(FALSE); |
if (ptr[0] != 'i' || ptr[1] != 'n' || |
build_words_list(arg->lst, sub); |
!isspace((unsigned char) ptr[2])) { |
free(sub); |
Parse_Error(level, "missing `in' in for"); |
arg->lineno = Parse_Getlineno(); |
printf("%s\n", ptr); |
arg->level = 1; |
return 0; |
Buf_Init(&arg->buf, 0); |
} |
|
ptr += 3; |
|
|
|
/* .for loop is go, collate what we need. */ |
return arg; |
forVar = interval_dup(wrd, endVar); |
} |
|
|
/* Make a list with the remaining words. */ |
|
sub = Var_Subst(NULL, ptr, VAR_GLOBAL, FALSE); |
/*- |
if (DEBUG(FOR)) |
*----------------------------------------------------------------------- |
(void)fprintf(stderr, "For: Iterator %s List %s\n", forVar, sub); |
* For_Accumulate -- |
|
* Accumulate lines in a for loop, until we find the matching endfor. |
|
* |
|
* Results: |
|
* TRUE: keep accumulating lines. |
|
* FALSE: We found the matching .endfor |
|
* |
|
* Side Effects: |
|
* Accumulate lines in arg. |
|
*----------------------------------------------------------------------- |
|
*/ |
|
Boolean |
|
For_Accumulate(arg, line) |
|
For *arg; |
|
const char *line; /* Line to parse */ |
|
{ |
|
const char *ptr = line; |
|
|
forLst = Lst_Init(FALSE); |
assert(arg->level > 0); |
build_words_list(forLst, sub); |
|
free(sub); |
|
forLineno = Parse_Getlineno(); |
|
Buf_Init(&forBuf, 0); |
|
forLevel++; |
|
return 1; |
|
} |
|
else if (*ptr == '.') { |
|
|
|
for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++) |
if (*ptr == '.') { |
|
|
|
for (ptr++; *ptr && isspace(*ptr); ptr++) |
continue; |
continue; |
|
|
if (strncmp(ptr, "endfor", 6) == 0 && |
if (strncmp(ptr, "endfor", 6) == 0 && |
(isspace((unsigned char) ptr[6]) || !ptr[6])) { |
(isspace(ptr[6]) || !ptr[6])) { |
if (DEBUG(FOR)) |
if (DEBUG(FOR)) |
(void) fprintf(stderr, "For: end for %d\n", forLevel); |
(void)fprintf(stderr, "For: end for %lu\n", arg->level); |
if (--forLevel < 0) { |
/* If matching endfor, don't add line to buffer. */ |
Parse_Error(level, "for-less endfor"); |
if (--arg->level == 0) |
return 0; |
return FALSE; |
} |
|
} |
} |
else if (strncmp(ptr, "for", 3) == 0 && |
else if (strncmp(ptr, "for", 3) == 0 && |
isspace((unsigned char) ptr[3])) { |
isspace(ptr[3])) { |
forLevel++; |
arg->level++; |
if (DEBUG(FOR)) |
if (DEBUG(FOR)) |
(void) fprintf(stderr, "For: new loop %d\n", forLevel); |
(void)fprintf(stderr, "For: new loop %lu\n", arg->level); |
} |
} |
} |
} |
|
Buf_AddString(&arg->buf, line); |
if (forLevel != 0) { |
Buf_AddChar(&arg->buf, '\n'); |
Buf_AddString(&forBuf, line); |
return TRUE; |
Buf_AddChar(&forBuf, '\n'); |
|
return 1; |
|
} |
|
else { |
|
return 0; |
|
} |
|
} |
} |
|
|
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* ForExec -- |
* ForExec -- |
* Expand the for loop for this index and push it in the Makefile |
* Expand the for loop for this index and push it in the Makefile |
* |
|
* Results: |
|
* None. |
|
* |
|
* Side Effects: |
|
* None. |
|
* |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static int |
static int |
|
|
ClientData namep; |
ClientData namep; |
ClientData argp; |
ClientData argp; |
{ |
{ |
char *name = (char *) namep; |
char *name = (char *)namep; |
For *arg = (For *) argp; |
For *arg = (For *)argp; |
|
|
Var_Set(arg->var, name, VAR_GLOBAL); |
Var_Set(arg->var, name, VAR_GLOBAL); |
if (DEBUG(FOR)) |
if (DEBUG(FOR)) |
(void) fprintf(stderr, "--- %s = %s\n", arg->var, name); |
(void)fprintf(stderr, "--- %s = %s\n", arg->var, name); |
Parse_FromString(Var_Subst(arg->var, Buf_Retrieve(arg->buf), |
Parse_FromString(Var_Subst(arg->var, arg->text, VAR_GLOBAL, FALSE), |
VAR_GLOBAL, FALSE), arg->lineno); |
arg->lineno); |
Var_Delete(arg->var, VAR_GLOBAL); |
Var_Delete(arg->var, VAR_GLOBAL); |
|
|
return 0; |
return 0; |
} |
} |
|
|
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* For_Run -- |
* For_Run -- |
* Run the for loop, immitating the actions of an include file |
* Run the for loop, pushing expanded lines for reparse |
* |
|
* Results: |
|
* None. |
|
* |
|
* Side Effects: |
|
* None. |
|
* |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
|
|
void |
void |
For_Run() |
For_Run(arg) |
|
For *arg; |
{ |
{ |
For arg; |
arg->text = Buf_Retrieve(&arg->buf); |
|
|
if (forVar == NULL || forLst == NULL) |
Lst_ForEach(arg->lst, ForExec, (ClientData)arg); |
return; |
free(arg->var); |
arg.var = forVar; |
free(arg->text); |
arg.buf = &forBuf; |
Lst_Destroy(arg->lst, (void (*) __P((ClientData)))free); |
arg.lst = forLst; |
free(arg); |
arg.lineno = forLineno; |
|
forVar = NULL; |
|
forLst = NULL; |
|
|
|
Lst_ForEach(arg.lst, ForExec, (ClientData) &arg); |
|
|
|
free((Address)arg.var); |
|
Lst_Destroy(arg.lst, (void (*) __P((ClientData))) free); |
|
Buf_Destroy(arg.buf); |
|
} |
} |