📄 tok_io.c
字号:
t->tokno = TOK_OTHER;
break;
} else if (ISSPACE(c)) {
COLLECT(t->vstr, c, ISSPACE(c));
t->tokno = TOK_WSPACE;
break;
} else if (ISALPHA(c)) {
COLLECT(t->vstr, c, ISALNUM(c));
t->tokno = TOK_WORD;
break;
} else if (isdigit(c)) {
COLLECT(t->vstr, c, isdigit(c));
t->tokno = TOK_NUMBER;
break;
} else if (c == '"' || c == '\'') {
t->tokno = read_quoted(t->vstr, c); /* detect missing end quote */
break;
} else if (ISDOT(c)) {
COLLECT(t->vstr, c, ISDOT(c));
t->tokno = TOK_OTHER;
break;
} else if (c == '#' && last_tokno == '\n') {
do_control();
continue;
} else {
t->vstr->str[0] = c;
if (c == '\n') {
in_line++;
if (nl_compensate > 0) { /* compensation for bs-nl */
UNPUT('\n');
nl_compensate--;
}
} else if (c == '/') {
if ((INPUT(d)) == '*') {
t->vstr->str[1] = d; /* comment */
read_comment(t->vstr);
t->tokno = TOK_WSPACE;
break;
} else {
if (d != EOF)
UNPUT(d);
}
} else if (c == '\\') {
t->vstr->str[1] = (INPUT(c) == EOF ? 0 : c);
t->vstr->str[2] = 0;
t->tokno = TOK_OTHER;
break;
}
t->vstr->str[1] = 0;
t->tokno = c;
break;
}
}
last_tokno = t->tokno;
t->end_line = in_line;
return (t);
}
/* read_quoted - read string or character literal, canonicalize escapes */
static int read_quoted(vs, ch)
register struct vstring *vs;
int ch;
{
register char *cp = vs->str;
register int c;
int ret = TOK_OTHER;
*cp++ = ch;
/*
* Clobber the token type in case of a premature newline or EOF. This
* prevents us from attempting to concatenate string constants with
* broken ones that have no closing quote.
*/
while (INPUT(c) != EOF) {
if (c == '\n') { /* newline in string */
UNPUT(c);
break;
}
if (VS_ADDCH(vs, cp, c) == 0) /* store character */
fatal("out of memory");
if (c == ch) { /* closing quote */
ret = c;
break;
}
if (c == '\\') { /* parse escape sequence */
if ((INPUT(c)) == EOF) { /* EOF, punt */
break;
} else if (c == 'a') { /* \a -> audible bell */
if ((cp = vs_strcpy(vs, cp, BELL)) == 0)
fatal("out of memory");
} else if (c == 'x') { /* \xhh -> \nnn */
cp = read_hex(vs, cp);
} else if (ISOCTAL(c) && ch != '\'') {
cp = read_octal(vs, cp, c); /* canonicalize \octal */
} else {
if (VS_ADDCH(vs, cp, c) == 0) /* \other: leave alone */
fatal("out of memory");
}
}
}
*cp = 0;
return (ret);
}
/* read_comment - stuff a whole comment into one huge token */
static void read_comment(vs)
register struct vstring *vs;
{
register char *cp = vs->str + 2; /* skip slash star */
register int c;
register int d;
while (INPUT(c) != EOF) {
if (VS_ADDCH(vs, cp, c) == 0)
fatal("out of memory");
if (c == '*') {
if ((INPUT(d)) == '/') {
if (VS_ADDCH(vs, cp, d) == 0)
fatal("out of memory");
break;
} else {
if (d != EOF)
UNPUT(d);
}
} else if (c == '\n') {
in_line++;
} else if (c == '\\') {
if ((INPUT(d)) != EOF && VS_ADDCH(vs, cp, d) == 0)
fatal("out of memory");
}
}
*cp = 0;
}
/* read_hex - rewrite hex escape to three-digit octal escape */
static char *read_hex(vs, cp)
struct vstring *vs;
register char *cp;
{
register int c;
register int i;
char buf[BUFSIZ];
int len;
unsigned val;
/*
* Eat up all subsequent hex digits. Complain later when there are too
* many.
*/
for (i = 0; i < sizeof(buf) && (INPUT(c) != EOF) && ISHEX(c); i++)
buf[i] = c;
buf[i] = 0;
if (i < sizeof(buf) && c)
UNPUT(c);
/*
* Convert hex form to three-digit octal form. The three-digit form is
* used so that strings can be concatenated without problems. Complain
* about malformed input; truncate the result to at most three octal
* digits.
*/
if (i == 0) {
error("\\x escape sequence without hexadecimal digits");
if (VS_ADDCH(vs, cp, 'x') == 0)
fatal("out of memory");
} else {
(void) sscanf(buf, "%x", &val);
sprintf(buf, "%03o", val);
if ((len = strlen(buf)) > 3)
error("\\x escape sequence yields non-character value");
if ((cp = vs_strcpy(vs, cp, buf + len - 3)) == 0)
fatal("out of memory");
}
return (cp);
}
/* read_octal - convert octal escape to three-digit format */
static char obuf[] = "00123";
static char *read_octal(vs, cp, c)
register struct vstring *vs;
register char *cp;
register int c;
{
register int i;
#define buf_input (obuf + 2)
/* Eat up at most three octal digits. */
buf_input[0] = c;
for (i = 1; i < 3 && (INPUT(c) != EOF) && ISOCTAL(c); i++)
buf_input[i] = c;
buf_input[i] = 0;
if (i < 3 && c)
UNPUT(c);
/*
* Leave three-digit octal escapes alone. Convert one-digit and two-digit
* octal escapes to three-digit form by prefixing them with a suitable
* number of '0' characters. This is done so that strings can be
* concatenated without problems.
*/
if ((cp = vs_strcpy(vs, cp, buf_input + i - 3)) == 0)
fatal("out of memory");
return (cp);
}
/* put_nl - emit newline and adjust output line count */
void put_nl()
{
put_ch('\n');
out_line++;
}
/* fix_line_control - to adjust path and/or line count info in output */
static void fix_line_control(path, line)
register char *path;
register int line;
{
/*
* This function is called sporadically, so it should not be a problem
* that we repeat some of the tests that preceded this function call.
*
* Emit a newline if we are not at the start of a line.
*
* If we switch files, or if we jump backwards, emit line control. If we
* jump forward, emit the proper number of newlines to compensate.
*/
if (last_ch != '\n') /* terminate open line */
put_nl();
if (path != out_path || line < out_line) { /* file switch or back jump */
printf("# %d %s\n", out_line = line, out_path = path);
last_ch = '\n';
} else { /* forward jump */
while (line > out_line)
put_nl();
}
}
/* tok_show_ch - output single-character token (not newline) */
void tok_show_ch(t)
register struct token *t;
{
CHECK_LINE_CONTROL(t->path, t->line);
put_ch(t->tokno); /* show token contents */
}
/* tok_show - output (possibly composite) token */
void tok_show(t)
register struct token *t;
{
register struct token *p;
if (t->tokno == TOK_LIST) {
register struct token *s;
/*
* This branch is completely in terms of tok_xxx() primitives, so
* there is no need to check the line control information.
*/
for (s = t->head; s; s = s->next) {
tok_show_ch(s); /* '(' or ',' or ')' */
for (p = s->head; p; p = p->next)
tok_show(p); /* show list element */
}
} else {
register char *cp = t->vstr->str;
/*
* Measurements show that it pays off to give special treatment to
* single-character tokens. Note that both types of token may cause a
* change of output line number.
*/
CHECK_LINE_CONTROL(t->path, t->line);
if (cp[1] == 0) {
put_ch(*cp); /* single-character token */
} else {
put_str(cp); /* multi_character token */
}
out_line = t->end_line; /* may span multiple lines */
for (p = t->head; p; p = p->next)
tok_show(p); /* trailing blanks */
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -