📄 unproto.c
字号:
/* Find the last interesting item. */
for (p = s->head; p; p = p->next) {
if (p->tokno == TOK_WORD) {
t = p; /* remember last word */
} else if (p->tokno == '{') {
p = skip_enclosed(p, '}'); /* skip structured stuff */
} else if (p->tokno == '[') {
break; /* dimension may be a macro */
} else if (IS_FUNC_PTR_TYPE(p)) {
t = p; /* or function pointer */
p = p->next;
}
}
/* Extract argument name from last interesting item. */
if (t) {
if (t->tokno == TOK_LIST)
show_arg_name(t->head); /* function pointer, recurse */
else
tok_show(t); /* print last word */
}
}
}
/* show_type - rewrite type to old-style syntax */
static void show_type(s)
register struct token *s;
{
register struct token *p;
/*
* Rewrite (*stuff)(args) to (*stuff)(). Rewrite word(args) to word(),
* but only if the word was preceded by a word, '*' or '}'. Leave
* anything else alone.
*/
for (p = s->head; p; p = p->next) {
if (IS_FUNC_PTR_TYPE(p)) {
p = show_func_ptr_type(p, p->next); /* function pointer type */
} else {
register struct token *q;
register struct token *r;
tok_show(p); /* other */
if ((p->tokno == TOK_WORD || p->tokno == '*' || p->tokno == '}')
&& (q = p->next) && q->tokno == TOK_WORD
&& (r = q->next) && r->tokno == TOK_LIST) {
tok_show(q); /* show name */
show_empty_list(p = r); /* strip args */
}
}
}
}
/* show_func_ptr_type - display function_pointer type using old-style syntax */
static struct token *show_func_ptr_type(t1, t2)
struct token *t1;
struct token *t2;
{
register struct token *s;
/*
* Rewrite (list1) (list2) to (list1) (). Account for the rare case that
* (list1) is a comma-separated list. That should be an error, but we do
* not want to waste any information.
*/
for (s = t1->head; s; s = s->next) {
tok_show_ch(s); /* '(' or ',' or ')' */
show_type(s); /* recurse */
}
show_empty_list(t2);
return (t2);
}
/* show_empty_list - display opening and closing parentheses (if available) */
static void show_empty_list(t)
register struct token *t;
{
tok_show_ch(t->head); /* opening paren */
if (t->tail->tokno == ')')
tok_show_ch(t->tail); /* closing paren */
}
/* show_struct_type - display structured type, rewrite function-pointer types */
static struct token *show_struct_type(p)
register struct token *p;
{
tok_show(p); /* opening brace */
while (p->next) { /* XXX cannot return 0 */
p = p->next;
if (IS_FUNC_PTR_TYPE(p)) {
p = show_func_ptr_type(p, p->next); /* function-pointer member */
} else if (p->tokno == '{') {
p = show_struct_type(p); /* recurse */
} else {
tok_show(p); /* other */
if (p->tokno == '}') {
return (p); /* done */
}
}
}
DPRINTF("/* missing '}' */");
return (p);
}
/* is_func_ptr_cast - recognize function-pointer type cast */
static int is_func_ptr_cast(t)
register struct token *t;
{
register struct token *p;
/*
* Examine superficial structure. Require (list1) (list2). Require that
* list1 begins with a star.
*/
if (!IS_FUNC_PTR_TYPE(t))
return (0);
/*
* Make sure that there is no name in (list1). Do not worry about
* unexpected tokens, because the compiler will complain anyway.
*/
for (p = t->head->head; p; p = p->next) {
switch (p->tokno) {
case TOK_LIST: /* recurse */
return (is_func_ptr_cast(p));
case TOK_WORD: /* name in list */
return (0);
case '[':
return (1); /* dimension may be a macro */
}
}
return (1); /* no name found */
}
/* check_cast - display ()-delimited, comma-separated list */
static void check_cast(t)
struct token *t;
{
register struct token *s;
register struct token *p;
/*
* Rewrite function-pointer types and function-pointer casts. Do not
* blindly rewrite (*list1)(list2) to (*list1)(). Function argument lists
* are about the only thing we can discard without provoking diagnostics
* from the compiler.
*/
for (s = t->head; s; s = s->next) {
tok_show_ch(s); /* '(' or ',' or ')' */
for (p = s->head; p; p = p->next) {
switch (p->tokno) {
case TOK_LIST:
if (is_func_ptr_cast(p)) { /* not: IS_FUNC_PTR_TYPE(p) */
p = show_func_ptr_type(p, p->next);
} else {
check_cast(p); /* recurse */
}
break;
case '{':
p = show_struct_type(p); /* rewrite func. ptr. types */
break;
default:
tok_show(p);
break;
}
}
}
}
/* block_dcls - on the fly rewrite decls/initializers at start of block */
static void block_dcls()
{
register struct token *t;
/*
* Away from the top level, a declaration should be preceded by type or
* storage-class information. That is why inside blocks, structs and
* unions we insist on reading one word before passing the _next_ token
* to the dcl_flush() function.
*
* Struct and union declarations look the same everywhere: we make an
* exception for these more regular constructs and pass the "struct" and
* "union" tokens to the type_dcl() function.
*/
while (t = tok_class()) {
switch (t->tokno) {
case TOK_WSPACE: /* preserve white space */
case '\n': /* preserve line count */
tok_flush(t);
break;
case TOK_WORD: /* type declarations? */
tok_flush(t); /* advance to next token */
t = tok_class(); /* null return is ok */
/* FALLTRHOUGH */
case TOK_COMPOSITE: /* struct or union */
if ((t = dcl_flush(t)) == 0)
break;
/* FALLTRHOUGH */
default: /* end of declarations */
DPRINTF("/* end dcls */");
/* FALLTRHOUGH */
case '}': /* end of block */
tok_unget(t);
return;
}
}
}
/* block_flush - rewrite struct, union or statement block on the fly */
static void block_flush(t)
register struct token *t;
{
static int count = 0;
tok_flush(t);
DPRINTF("/*%d*/", ++count);
/*
* Rewrite function pointer types in declarations and function pointer
* casts in initializers at start of block.
*/
block_dcls();
/* Remainder of block: only rewrite function pointer casts. */
while (t = tok_class()) {
if (t->tokno == TOK_LIST) {
check_cast_flush(t);
} else if (t->tokno == '{') {
block_flush(t);
} else {
tok_flush(t);
if (t->tokno == '}') {
DPRINTF("/*%d*/", count--);
return;
}
}
}
DPRINTF("/* missing '}' */");
}
/* pair_flush - on the fly rewrite casts in grouped stuff */
static void pair_flush(t, start, stop)
register struct token *t;
register int start;
register int stop;
{
tok_flush(t);
while (t = tok_class()) {
if (t->tokno == start) { /* recurse */
pair_flush(t, start, stop);
} else if (t->tokno == TOK_LIST) { /* expression or cast */
check_cast_flush(t);
} else { /* other, copy */
tok_flush(t);
if (t->tokno == stop) { /* done */
return;
}
}
}
DPRINTF("/* missing '%c' */", stop);
}
/* initializer - on the fly rewrite casts in initializer */
static void initializer()
{
register struct token *t;
while (t = tok_class()) {
switch (t->tokno) {
case ',': /* list separator */
case ';': /* list terminator */
tok_unget(t);
return;
case TOK_LIST: /* expression or cast */
check_cast_flush(t);
break;
case '[': /* array subscript, may nest */
pair_flush(t, '[', ']');
break;
case '{': /* structured data, may nest */
pair_flush(t, '{', '}');
break;
default: /* other, just copy */
tok_flush(t);
break;
}
}
}
/* func_ptr_dcl_flush - rewrite function pointer stuff */
static struct token *func_ptr_dcl_flush(list)
register struct token *list;
{
register struct token *t;
register struct token *t2;
/*
* Ignore blanks and newlines because we are too lazy to maintain more
* than one token worth of lookahead. The output routines will regenerate
* discarded newline tokens.
*/
while (t = tok_class()) {
switch (t->tokno) {
case TOK_WSPACE:
case '\n':
tok_free(t);
break;
case TOK_LIST:
/* Function pointer or function returning pointer to function. */
while ((t2 = tok_class()) /* skip blanks etc. */
&&(t2->tokno == TOK_WSPACE || t2->tokno == '\n'))
tok_free(t2);
switch (t2 ? t2->tokno : 0) {
case '{': /* function heading (new) */
fpf_header(list, t);
break;
case TOK_WORD: /* function heading (old) */
tok_show(list);
tok_show(t);
break;
default: /* func pointer type */
(void) show_func_ptr_type(list, t);
break;
}
tok_free(list);
tok_free(t);
if (t2)
tok_unget(t2);
return (0);
default: /* not a declaration */
tok_unget(t);
return (list);
}
}
/* Hit EOF; must be mistake, but do not waste any information. */
return (list);
}
/* function_dcl_flush - rewrite function { heading, type declaration } */
static struct token *function_dcl_flush(list)
register struct token *list;
{
register struct token *t;
/*
* Ignore blanks and newlines because we are too lazy to maintain more
* than one token worth of lookahead. The output routines will regenerate
* ignored newline tokens.
*/
while (t = tok_class()) {
switch (t->tokno) {
case TOK_WSPACE:
case '\n':
tok_free(t);
break;
case '{':
/* Function heading: word (list) { -> old style heading */
header_flush(list);
tok_unget(t);
return (0);
case TOK_WORD:
/* Old-style function heading: word (list) word... */
tok_flush(list);
tok_unget(t);
return (0);
case TOK_LIST:
/* Function pointer: word (list1) (list2) -> word (list1) () */
tok_flush(list);
show_empty_list(t);
tok_free(t);
return (0);
case ',':
case ';':
/* Function type declaration: word (list) -> word () */
show_empty_list(list);
tok_free(list);
tok_unget(t);
return (0);
default:
/* Something else, reject the list. */
tok_unget(t);
return (list);
}
}
/* Hit EOF; must be mistake, but do not waste any information. */
return (list);
}
/* dcl_flush - parse declaration on the fly, return rejected token */
static struct token *dcl_flush(t)
register struct token *t;
{
register int got_word;
/*
* Away from the top level, type or storage-class information is required
* for an (extern or forward) function type declaration or a variable
* declaration.
*
* With our naive word-counting approach, this means that the caller should
* read one word before passing the next token to us. This is how we
* distinguish, for example, function declarations from function calls.
*
* An exception are structs and unions, because they look the same at any
* level. The caller should give is the "struct" or "union" token.
*/
for (got_word = 0; t; t = tok_class()) {
switch (t->tokno) {
case TOK_WSPACE: /* advance past blanks */
case '\n': /* advance past newline */
case '*': /* indirection: keep trying */
tok_flush(t);
break;
case TOK_WORD: /* word: keep trying */
case TOK_COMPOSITE: /* struct or union */
got_word = 1;
tok_flush(t);
break;
default:
/*
* Function pointer types can be preceded by zero or more words
* (at least one when not at the top level). Other stuff can be
* accepted only after we have seen at least one word (two words
* when not at the top level). See also the above comment on
* structs and unions.
*/
if (t->tokno == TOK_LIST && LIST_BEGINS_WITH_STAR(t)) {
if (t = func_ptr_dcl_flush(t)) {
return (t); /* reject token */
} else {
got_word = 1; /* for = and [ and , and ; */
}
} else if (got_word == 0) {
return (t); /* reject token */
} else {
switch (t->tokno) {
case TOK_LIST: /* function type */
if (t = function_dcl_flush(t))
return (t); /* reject token */
break;
case '[': /* dimension, does not nest */
pair_flush(t, '[', ']');
break;
case '=': /* initializer follows */
tok_flush(t);
initializer(); /* rewrite casts */
break;
case '{': /* struct, union, may nest */
block_flush(t); /* use code for stmt blocks */
break;
case ',': /* separator: keep trying */
got_word = 0;
tok_flush(t);
break;
case ';': /* terminator: succeed */
tok_flush(t);
return (0);
default: /* reject token */
return (t);
}
}
}
}
return (0); /* hit EOF */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -