version 1.20, 2007/09/17 09:28:36 |
version 1.21, 2007/09/22 10:23:02 |
|
|
|
|
/* Input stream structure, file or string. */ |
/* Input stream structure, file or string. */ |
typedef struct { |
typedef struct { |
const char *fname; /* Name of file */ |
const char *fname; /* Name of file */ |
unsigned long lineno; /* Line number */ |
unsigned long lineno; /* Line number */ |
FILE *F; /* Open stream, or NULL if pure string. */ |
FILE *F; /* Open stream, or NULL if pure string. */ |
char *str; /* Input string, if F == NULL. */ |
char *str; /* Input string, if F == NULL. */ |
|
|
/* Line buffer. */ |
/* Line buffer. */ |
char *ptr; /* Where we are. */ |
char *ptr; /* Where we are. */ |
char *end; /* Don't overdo it. */ |
char *end; /* Don't overdo it. */ |
} IFile; |
} IFile; |
|
|
static IFile *current; /* IFile being parsed. */ |
static IFile *current; /* IFile being parsed. */ |
|
|
static LIST input_stack; /* Stack of IFiles waiting to be parsed |
static LIST input_stack; /* Stack of IFiles waiting to be parsed |
* (includes and loop reparses) */ |
* (includes and loop reparses) */ |
|
|
/* IFile ctors. |
/* IFile ctors. |
|
|
/* Handling basic character reading. |
/* Handling basic character reading. |
* c = ParseReadc(); |
* c = ParseReadc(); |
* New character c from current input stream, or EOF at end of stream. */ |
* New character c from current input stream, or EOF at end of stream. */ |
#define ParseReadc() current->ptr < current->end ? *current->ptr++ : newline() |
#define ParseReadc() \ |
|
current->ptr < current->end ? *current->ptr++ : newline() |
/* len = newline(); |
/* len = newline(); |
* Guts for ParseReadc. Grabs a new line off fgetln when we have |
* Guts for ParseReadc. Grabs a new line off fgetln when we have |
* consumed the current line and returns its length. Or EOF at end of |
* consumed the current line and returns its length. Or EOF at end of |
|
|
static IFile * |
static IFile * |
new_ifile(const char *name, FILE *stream) |
new_ifile(const char *name, FILE *stream) |
{ |
{ |
IFile *ifile; |
IFile *ifile; |
#if 0 |
#if 0 |
Lst_AtEnd(&fileNames, name); |
Lst_AtEnd(&fileNames, name); |
#endif |
#endif |
|
|
ifile = emalloc(sizeof(*ifile)); |
ifile = emalloc(sizeof(*ifile)); |
ifile->fname = name; |
ifile->fname = name; |
ifile->str = NULL; |
ifile->str = NULL; |
/* Naturally enough, we start reading at line 0. */ |
/* Naturally enough, we start reading at line 0. */ |
ifile->lineno = 0; |
ifile->lineno = 0; |
ifile->F = stream; |
ifile->F = stream; |
ifile->ptr = ifile->end = NULL; |
ifile->ptr = ifile->end = NULL; |
return ifile; |
return ifile; |
} |
} |
|
|
static void |
static void |
free_ifile(IFile *ifile) |
free_ifile(IFile *ifile) |
{ |
{ |
if (ifile->F && fileno(ifile->F) != STDIN_FILENO) |
if (ifile->F && fileno(ifile->F) != STDIN_FILENO) |
(void)fclose(ifile->F); |
(void)fclose(ifile->F); |
free(ifile->str); |
free(ifile->str); |
/* Note we can't free the file names yet, as they are embedded in GN for |
/* Note we can't free the file names yet, as they are embedded in GN |
* error reports. */ |
* for error reports. */ |
free(ifile); |
free(ifile); |
} |
} |
|
|
static IFile * |
static IFile * |
new_istring(char *str, const char *name, unsigned long lineno) |
new_istring(char *str, const char *name, unsigned long lineno) |
{ |
{ |
IFile *ifile; |
IFile *ifile; |
|
|
ifile = emalloc(sizeof(*ifile)); |
ifile = emalloc(sizeof(*ifile)); |
/* No malloc, name is always taken from an already existing ifile */ |
/* No malloc, name is always taken from an already existing ifile */ |
ifile->fname = name; |
ifile->fname = name; |
ifile->F = NULL; |
ifile->F = NULL; |
/* Strings are used in for loops, so we need to reset the line counter |
/* Strings are used in for loops, so we need to reset the line counter |
* to an appropriate value. */ |
* to an appropriate value. */ |
ifile->lineno = lineno; |
ifile->lineno = lineno; |
ifile->ptr = ifile->str = str; |
ifile->ptr = ifile->str = str; |
ifile->end = str + strlen(str); |
ifile->end = str + strlen(str); |
return ifile; |
return ifile; |
} |
} |
|
|
|
|
void |
void |
Parse_FromString(char *str, unsigned long lineno) |
Parse_FromString(char *str, unsigned long lineno) |
{ |
{ |
if (DEBUG(FOR)) |
if (DEBUG(FOR)) |
(void)fprintf(stderr, "%s\n----\n", str); |
(void)fprintf(stderr, "%s\n----\n", str); |
|
|
if (current != NULL) |
if (current != NULL) |
Lst_Push(&input_stack, current); |
Lst_Push(&input_stack, current); |
current = new_istring(str, current->fname, lineno); |
current = new_istring(str, current->fname, lineno); |
} |
} |
|
|
|
|
void |
void |
Parse_FromFile(const char *name, FILE *stream) |
Parse_FromFile(const char *name, FILE *stream) |
{ |
{ |
if (current != NULL) |
if (current != NULL) |
Lst_Push(&input_stack, current); |
Lst_Push(&input_stack, current); |
current = new_ifile(name, stream); |
current = new_ifile(name, stream); |
} |
} |
|
|
bool |
bool |
Parse_NextFile(void) |
Parse_NextFile(void) |
{ |
{ |
if (current != NULL) |
if (current != NULL) |
free_ifile(current); |
free_ifile(current); |
current = (IFile *)Lst_Pop(&input_stack); |
current = (IFile *)Lst_Pop(&input_stack); |
return current != NULL; |
return current != NULL; |
} |
} |
|
|
static int |
static int |
newline(void) |
newline(void) |
{ |
{ |
size_t len; |
size_t len; |
|
|
if (current->F) { |
if (current->F) { |
current->ptr = fgetln(current->F, &len); |
current->ptr = fgetln(current->F, &len); |
if (current->ptr) { |
if (current->ptr) { |
current->end = current->ptr + len; |
current->end = current->ptr + len; |
return *current->ptr++; |
return *current->ptr++; |
} else { |
} else { |
current->end = NULL; |
current->end = NULL; |
|
} |
} |
} |
} |
return EOF; |
return EOF; |
|
} |
} |
|
|
static int |
static int |
skiptoendofline(void) |
skiptoendofline(void) |
{ |
{ |
if (current->F) { |
if (current->F) { |
if (current->end - current->ptr > 1) |
if (current->end - current->ptr > 1) |
current->ptr = current->end - 1; |
current->ptr = current->end - 1; |
if (*current->ptr == '\n') |
if (*current->ptr == '\n') |
return *current->ptr++; |
return *current->ptr++; |
return EOF; |
return EOF; |
} else { |
} else { |
int c; |
int c; |
|
|
do { |
do { |
c = ParseReadc(); |
c = ParseReadc(); |
} while (c != '\n' && c != EOF); |
} while (c != '\n' && c != EOF); |
return c; |
return c; |
} |
} |
} |
} |
|
|
|
|
char * |
char * |
Parse_ReadNextConditionalLine(Buffer linebuf) |
Parse_ReadNextConditionalLine(Buffer linebuf) |
{ |
{ |
int c; |
int c; |
|
|
/* If first char isn't dot, skip to end of line, handling \ */ |
/* If first char isn't dot, skip to end of line, handling \ */ |
while ((c = ParseReadc()) != '.') { |
while ((c = ParseReadc()) != '.') { |
for (;c != '\n'; c = ParseReadc()) { |
for (;c != '\n'; c = ParseReadc()) { |
if (c == '\\') { |
if (c == '\\') { |
c = ParseReadc(); |
c = ParseReadc(); |
if (c == '\n') |
if (c == '\n') |
current->lineno++; |
current->lineno++; |
} |
} |
if (c == EOF) { |
if (c == EOF) { |
Parse_Error(PARSE_FATAL, "Unclosed conditional"); |
Parse_Error(PARSE_FATAL, |
return NULL; |
"Unclosed conditional"); |
} |
return NULL; |
|
} |
|
} |
|
current->lineno++; |
} |
} |
current->lineno++; |
|
} |
|
|
|
/* This is the line we need to copy */ |
/* This is the line we need to copy */ |
return Parse_ReadUnparsedLine(linebuf, "conditional"); |
return Parse_ReadUnparsedLine(linebuf, "conditional"); |
} |
} |
|
|
static void |
static void |
ParseFoldLF(Buffer linebuf, int c) |
ParseFoldLF(Buffer linebuf, int c) |
{ |
{ |
for (;;) { |
for (;;) { |
if (c == '\n') { |
if (c == '\n') { |
current->lineno++; |
current->lineno++; |
break; |
break; |
} |
|
if (c == EOF) |
|
break; |
|
Buf_AddChar(linebuf, c); |
|
c = ParseReadc(); |
|
while (c == '\\') { |
|
c = ParseReadc(); |
|
if (c == '\n') { |
|
Buf_AddSpace(linebuf); |
|
current->lineno++; |
|
do { |
|
c = ParseReadc(); |
|
} while (c == ' ' || c == '\t'); |
|
} else { |
|
Buf_AddChar(linebuf, '\\'); |
|
if (c == '\\') { |
|
Buf_AddChar(linebuf, '\\'); |
|
c = ParseReadc(); |
|
} |
} |
break; |
if (c == EOF) |
} |
break; |
|
Buf_AddChar(linebuf, c); |
|
c = ParseReadc(); |
|
while (c == '\\') { |
|
c = ParseReadc(); |
|
if (c == '\n') { |
|
Buf_AddSpace(linebuf); |
|
current->lineno++; |
|
do { |
|
c = ParseReadc(); |
|
} while (c == ' ' || c == '\t'); |
|
} else { |
|
Buf_AddChar(linebuf, '\\'); |
|
if (c == '\\') { |
|
Buf_AddChar(linebuf, '\\'); |
|
c = ParseReadc(); |
|
} |
|
break; |
|
} |
|
} |
} |
} |
} |
|
} |
} |
|
|
char * |
char * |
Parse_ReadUnparsedLine(Buffer linebuf, const char *type) |
Parse_ReadUnparsedLine(Buffer linebuf, const char *type) |
{ |
{ |
int c; |
int c; |
|
|
Buf_Reset(linebuf); |
Buf_Reset(linebuf); |
c = ParseReadc(); |
|
if (c == EOF) { |
|
Parse_Error(PARSE_FATAL, "Unclosed %s", type); |
|
return NULL; |
|
} |
|
|
|
/* Handle '\' at beginning of line, since \\n needs special treatment */ |
|
while (c == '\\') { |
|
c = ParseReadc(); |
c = ParseReadc(); |
if (c == '\n') { |
if (c == EOF) { |
current->lineno++; |
Parse_Error(PARSE_FATAL, "Unclosed %s", type); |
do { |
return NULL; |
|
} |
|
|
|
/* Handle '\' at beginning of line, since \\n needs special treatment */ |
|
while (c == '\\') { |
c = ParseReadc(); |
c = ParseReadc(); |
} while (c == ' ' || c == '\t'); |
if (c == '\n') { |
} else { |
current->lineno++; |
Buf_AddChar(linebuf, '\\'); |
do { |
if (c == '\\') { |
c = ParseReadc(); |
Buf_AddChar(linebuf, '\\'); |
} while (c == ' ' || c == '\t'); |
c = ParseReadc(); |
} else { |
} |
Buf_AddChar(linebuf, '\\'); |
break; |
if (c == '\\') { |
|
Buf_AddChar(linebuf, '\\'); |
|
c = ParseReadc(); |
|
} |
|
break; |
|
} |
} |
} |
} |
ParseFoldLF(linebuf, c); |
ParseFoldLF(linebuf, c); |
|
|
|
return Buf_Retrieve(linebuf); |
return Buf_Retrieve(linebuf); |
} |
} |
|
|
/* This is a fairly complex function, but without it, we could not skip |
/* This is a fairly complex function, but without it, we could not skip |
|
|
static int |
static int |
ParseSkipEmptyLines(Buffer linebuf) |
ParseSkipEmptyLines(Buffer linebuf) |
{ |
{ |
int c; /* the current character */ |
int c; /* the current character */ |
|
|
for (;;) { |
for (;;) { |
Buf_Reset(linebuf); |
Buf_Reset(linebuf); |
c = ParseReadc(); |
|
/* Strip leading spaces, fold on '\n' */ |
|
if (c == ' ') { |
|
do { |
|
c = ParseReadc(); |
c = ParseReadc(); |
} while (c == ' ' || c == '\t'); |
/* Strip leading spaces, fold on '\n' */ |
while (c == '\\') { |
if (c == ' ') { |
c = ParseReadc(); |
do { |
if (c == '\n') { |
c = ParseReadc(); |
current->lineno++; |
} while (c == ' ' || c == '\t'); |
do { |
while (c == '\\') { |
c = ParseReadc(); |
c = ParseReadc(); |
} while (c == ' ' || c == '\t'); |
if (c == '\n') { |
} else { |
current->lineno++; |
Buf_AddChar(linebuf, '\\'); |
do { |
if (c == '\\') { |
c = ParseReadc(); |
Buf_AddChar(linebuf, '\\'); |
} while (c == ' ' || c == '\t'); |
c = ParseReadc(); |
} else { |
} |
Buf_AddChar(linebuf, '\\'); |
if (c == EOF) |
if (c == '\\') { |
return '\n'; |
Buf_AddChar(linebuf, '\\'); |
else |
c = ParseReadc(); |
return c; |
} |
|
if (c == EOF) |
|
return '\n'; |
|
else |
|
return c; |
|
} |
|
} |
|
assert(c != '\t'); |
} |
} |
} |
if (c == '#') |
assert(c != '\t'); |
c = skiptoendofline(); |
} |
/* Almost identical to spaces, except this occurs after |
if (c == '#') |
* comments have been taken care of, and we keep the tab |
c = skiptoendofline(); |
* itself. */ |
/* Almost identical to spaces, except this occurs after comments |
if (c == '\t') { |
* have been taken care of, and we keep the tab itself. */ |
Buf_AddChar(linebuf, '\t'); |
if (c == '\t') { |
do { |
Buf_AddChar(linebuf, '\t'); |
c = ParseReadc(); |
do { |
} while (c == ' ' || c == '\t'); |
c = ParseReadc(); |
while (c == '\\') { |
} while (c == ' ' || c == '\t'); |
c = ParseReadc(); |
while (c == '\\') { |
if (c == '\n') { |
c = ParseReadc(); |
current->lineno++; |
if (c == '\n') { |
do { |
current->lineno++; |
c = ParseReadc(); |
do { |
} while (c == ' ' || c == '\t'); |
c = ParseReadc(); |
} else { |
} while (c == ' ' || c == '\t'); |
Buf_AddChar(linebuf, '\\'); |
} else { |
if (c == '\\') { |
Buf_AddChar(linebuf, '\\'); |
Buf_AddChar(linebuf, '\\'); |
if (c == '\\') { |
c = ParseReadc(); |
Buf_AddChar(linebuf, '\\'); |
} |
c = ParseReadc(); |
if (c == EOF) |
} |
return '\n'; |
if (c == EOF) |
else |
return '\n'; |
return c; |
else |
} |
return c; |
} |
} |
} |
} |
if (c == '\n') |
|
current->lineno++; |
|
else |
|
return c; |
} |
} |
if (c == '\n') |
|
current->lineno++; |
|
else |
|
return c; |
|
} |
|
} |
} |
|
|
/* Parse_ReadNormalLine removes beginning and trailing blanks (but keeps |
/* Parse_ReadNormalLine removes beginning and trailing blanks (but keeps |
|
|
char * |
char * |
Parse_ReadNormalLine(Buffer linebuf) |
Parse_ReadNormalLine(Buffer linebuf) |
{ |
{ |
int c; /* the current character */ |
int c; /* the current character */ |
|
|
c = ParseSkipEmptyLines(linebuf); |
c = ParseSkipEmptyLines(linebuf); |
|
|
if (c == EOF) |
if (c == EOF) |
return NULL; |
return NULL; |
else { |
else { |
ParseFoldLF(linebuf, c); |
ParseFoldLF(linebuf, c); |
Buf_KillTrailingSpaces(linebuf); |
Buf_KillTrailingSpaces(linebuf); |
return Buf_Retrieve(linebuf); |
return Buf_Retrieve(linebuf); |
} |
} |
} |
} |
|
|
unsigned long |
unsigned long |
Parse_Getlineno(void) |
Parse_Getlineno(void) |
{ |
{ |
return current ? current->lineno : 0; |
return current ? current->lineno : 0; |
} |
} |
|
|
const char * |
const char * |
Parse_Getfilename(void) |
Parse_Getfilename(void) |
{ |
{ |
return current ? current->fname : NULL; |
return current ? current->fname : NULL; |
} |
} |
|
|
#ifdef CLEANUP |
#ifdef CLEANUP |
void |
void |
LowParse_Init(void) |
LowParse_Init(void) |
{ |
{ |
Static_Lst_Init(&input_stack); |
Static_Lst_Init(&input_stack); |
current = NULL; |
current = NULL; |
} |
} |
|
|
void |
void |
LowParse_End(void) |
LowParse_End(void) |
{ |
{ |
Lst_Destroy(&input_stack, NOFREE); /* Should be empty now */ |
Lst_Destroy(&input_stack, NOFREE); /* Should be empty now */ |
#if 0 |
#if 0 |
Lst_Destroy(&fileNames, (SimpleProc)free); |
Lst_Destroy(&fileNames, (SimpleProc)free); |
#endif |
#endif |
} |
} |
#endif |
#endif |
|
|
void |
void |
Parse_ReportErrors(void) |
Parse_ReportErrors(void) |
{ |
{ |
if (fatal_errors) { |
if (fatal_errors) { |
#ifdef CLEANUP |
#ifdef CLEANUP |
while (Parse_NextFile()) |
while (Parse_NextFile()) |
; |
; |
#endif |
#endif |
fprintf(stderr, "Fatal errors encountered -- cannot continue\n"); |
fprintf(stderr, |
exit(1); |
"Fatal errors encountered -- cannot continue\n"); |
} else |
exit(1); |
assert(current == NULL); |
} else |
|
assert(current == NULL); |
} |
} |