home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.cs.arizona.edu
/
ftp.cs.arizona.edu.tar
/
ftp.cs.arizona.edu
/
icon
/
historic
/
v941.tgz
/
icon.v941src.tar
/
icon.v941src
/
src
/
preproc
/
gettok.c
< prev
next >
Wrap
C/C++ Source or Header
|
2001-12-12
|
7KB
|
253 lines
/*
* This files contains routines for getting the "next" token.
*/
#include "../preproc/preproc.h"
#include "../preproc/ptoken.h"
#include "../preproc/pproto.h"
/*
* next_tok - get the next raw token. No macros are expanded here (although
* the tokens themselves may be the result of a macro expansion initiated
* at a "higher" level). Only #line directives are processed here.
*/
struct token *next_tok()
{
struct token *t, *t1;
struct tok_lst *tlst;
struct char_src *cs;
struct str_buf *sbuf;
char *s;
char *fname;
int n;
if (src_stack->flag == DummySrc)
return NULL; /* source stack is empty - end of input */
/*
* See if a directive pushed back any tokens.
*/
if (src_stack->ntoks > 0)
return src_stack->toks[--src_stack->ntoks];
switch (src_stack->flag) {
case CharSrc:
/*
* Tokens from a raw character "stream".
*/
t = tokenize();
if (t != NULL && src_stack->u.cs->f != NULL)
t->flag |= LineChk;
if (t != NULL && t->tok_id == PpLine) {
/*
* #line directives must be processed here so they are not
* put in macros.
*/
cs = src_stack->u.cs;
t1 = NULL;
/*
* Get the line number from the directive.
*/
advance_tok(&t1);
if (t1->tok_id != PpNumber)
errt1(t1, "#line requires an integer argument");
n = 0;
for (s = t1->image; *s != '\0'; ++s) {
if (*s >= '0' && *s <= '9')
n = 10 * n + (*s - '0');
else
errt1(t1, "#line requires an integer argument");
}
/*
* Get the file name, if there is one, from the directive.
*/
advance_tok(&t1);
fname = NULL;
if (t1->tok_id == StrLit) {
sbuf = get_sbuf();
for (s = t1->image; *s != '\0'; ++s) {
if (s[0] == '\\' && (s[1] == '\\' || s[1] == '"'))
++s;
AppChar(*sbuf, *s);
}
fname = str_install(sbuf);
rel_sbuf(sbuf);
advance_tok(&t1);
}
if (t1->tok_id != PpDirEnd)
errt1(t1, "syntax error in #line");
/*
* Note the effect of the line directive in the character
* source. Line number changes are handled as a relative
* adjustments to the line numbers of following lines.
*/
if (fname != NULL)
cs->fname = fname;
cs->line_adj = n - cs->line_buf[next_char - first_char + 1];
if (*next_char == '\n')
++cs->line_adj; /* the next lines contains no characters */
t = next_tok(); /* the caller does not see #line directives */
}
break;
case MacExpand:
/*
* Tokens from macro expansion.
*/
t = mac_tok();
break;
case TokLst:
/*
* Tokens from a macro argument.
*/
tlst = src_stack->u.tlst;
if (tlst == NULL)
t = NULL;
else {
t = copy_t(tlst->t);
src_stack->u.tlst = tlst->next;
}
break;
case PasteLsts:
/*
* Tokens from token Pasting.
*/
return paste();
}
if (t == NULL) {
/*
* We have exhausted this entry on the source stack without finding
* a token to return.
*/
pop_src();
return next_tok();
}
else
return t;
}
/*
* Get the next raw non-white space token, freeing token that the argument
* used to point to.
*/
void nxt_non_wh(tp)
struct token **tp;
{
register struct token *t;
t = next_tok();
while (t != NULL && t->tok_id == WhiteSpace) {
free_t(t);
t = next_tok();
}
free_t(*tp);
*tp = t;
}
/*
* advance_tok - skip past white space after expanding macros and
* executing preprocessor directives. This routine may only be
* called from within a preprocessor directive because it assumes
* it will not see EOF (the input routines insure that a terminating
* new-line, and thus, for a directive, the PpDirEnd token, will be
* seen immediately before EOF).
*/
void advance_tok(tp)
struct token **tp;
{
struct token *t;
t = interp_dir();
while (t->tok_id == WhiteSpace) {
free_t(t);
t = interp_dir();
}
free_t(*tp);
*tp = t;
}
/*
* merge_whsp - merge a sequence of white space tokens into one token,
* returning it along with the next token. Whether these are raw or
* processed tokens depends on the token source function, t_src.
*/
void merge_whsp(whsp, next_t, t_src)
struct token **whsp;
struct token **next_t;
struct token *(*t_src)(void);
{
struct token *t1;
struct str_buf *sbuf;
int line = -1;
char *fname = "";
char *s;
free_t(*whsp);
t1 = (*t_src)();
if (t1 == NULL || t1->tok_id != WhiteSpace)
*whsp = NULL; /* no white space here */
else {
*whsp = t1;
t1 = (*t_src)();
if (t1 != NULL && t1->tok_id == WhiteSpace) {
if (whsp_image == NoSpelling) {
/*
* We don't care what the white space looks like, so
* discard the rest of it.
*/
while (t1 != NULL && t1->tok_id == WhiteSpace) {
free_t(t1);
t1 = (*t_src)();
}
}
else {
/*
* Must actually merge white space. Put it all white space
* in a string buffer and use that as the image of the merged
* token. The line number and file name of the new token
* is that of the last token whose line number and file
* name is important for generating #line directives in
* the output.
*/
sbuf = get_sbuf();
if ((*whsp)->flag & LineChk) {
line = (*whsp)->line;
fname = (*whsp)->fname;
}
for (s = (*whsp)->image; *s != '\0'; ++s) {
AppChar(*sbuf, *s);
if (*s == '\n' && line != -1)
++line;
}
while (t1 != NULL && t1->tok_id == WhiteSpace) {
if (t1->flag & LineChk) {
line = t1->line;
fname = t1->fname;
}
for (s = t1->image; *s != '\0'; ++s) {
AppChar(*sbuf, *s);
if (*s == '\n' && line != -1)
++line;
}
free_t(t1);
t1 = (*t_src)();
}
(*whsp)->image = str_install(sbuf);
rel_sbuf(sbuf);
if (t1 != NULL && !(t1->flag & LineChk) && line != -1) {
t1->flag |= LineChk;
t1->line = line;
t1->fname = fname;
}
}
}
}
*next_t = t1;
}