/*
* Copyright (c) 2004 - 2007, Nils R. Weller
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Parsing of ``advanced declarations''.
* This module exports parse_func/struct/enum() used by the parse_decl()
* subsystem
*/
#include "decl_adv.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "type.h"
#include "backend.h"
#include "token.h"
#include "misc.h"
#include "decl.h"
#include "symlist.h"
#include "error.h"
#include "scope.h"
#include "reg.h"
#include "typemap.h"
#include "expr.h"
#include "attribute.h"
#include "inlineasm.h"
#include "debug.h"
#include "n_libc.h"
/* Parsing framework for structure and function definitions/declarations */
#define STORE_FUNC (1)
#define STORE_STRUCT (2)
/*
* Stores src argument as structure member(s) of deststr argument
* The integer pointed to by the ``alloc'' argument must be set to
* zero every time a new structure is parsed, but not be touched after-
* wards
*/
static void
store_member_struct(struct ty_struct *deststr,
struct decl **src) {
int nsrc;
/* Determine number of declarations */
for (nsrc = 0; src[nsrc] != NULL; ++nsrc)
;
deststr->nmemb += nsrc;
store_decl_scope(deststr->scope, src);
}
/* Same as store_member_struct(), but for function arguments */
static void
store_member_func(struct ty_func *destfun,
struct decl **src) {
int nsrc;
/* Determine number of declarations */
for (nsrc = 0; src[nsrc] != NULL; ++nsrc)
;
destfun->lastarg = src[nsrc - 1];
destfun->nargs += nsrc;
store_decl_scope(curscope, src);
}
static int
store_member_enum(struct ty_enum *dest,
char *name,
struct token *value,
struct type *type,
int *alloc) {
int i;
struct scope *scope;
struct vreg *vr;
struct decl *dec[2];
/* Resize space if necessary */
if (dest->nmemb >= *alloc) {
*alloc += 8;
dest->members =
n_xrealloc(dest->members,
*alloc * sizeof *dest->members);
}
vr = vreg_alloc(NULL, value, NULL, NULL);
if (type == NULL) {
vr->type =
n_xmemdup(make_basic_type(TY_INT), sizeof *vr->type);
} else {
vr->type = type;
}
vr->size = backend->get_sizeof_type(vr->type, NULL);
dec[0] = alloc_decl();
dec[0]->dtype = vr->type;
dec[0]->dtype->name = name;
dec[0]->dtype->tenum = dest;
dec[0]->vreg = vr;
dec[1] = NULL;
/* Store */
dest->members[ dest->nmemb ].name = name;
dest->members[ dest->nmemb ].dec = dec[0];
for (i = 0; i < dest->nmemb; ++i) {
if (strcmp(dest->members[i].name, name) == 0) {
return -1;
}
}
++dest->nmemb;
/*
* An enumeration constant need only appear in the symbol list,
* as it doesn't have to be allocated anywhere
*/
for (scope = curscope;
scope->type == SCOPE_STRUCT;
scope = scope->parent)
;
append_symlist(scope, &scope->slist,
&scope->slist_tail, dec[0]);
return 0;
}
/*
* Function for glueing the member declarations of structures and unions
* together. This must be called by the declaration parsing code as soon
* as a structure *definition* (struct foo { ... }) is encountered, where
* the curtok argument must point to the node after {
* Returns a pointer to the newly allocated definition on success, else
* a null pointer
*/
#define PS_RET_ERR(ret) do { \
if (ret && ret->scope) { \
/*free(ret->scope);*/ \
} \
free(ret); \
close_scope(); \
return NULL; \
} while (0)
/*
* XXX struct alignment is done in x86_emit_nasm.c, print_init_list() and
* x86_emit_nasm.c, do_print_struct() ... there is some duplication of
* efforts, should probably all be done here
*/
struct ty_struct *
parse_struct(struct token **curtok, char *tag, int type) {
struct token *t;
struct token *prevtok = NULL;
struct decl **dec = NULL;
struct ty_struct *ret;
struct sym_entry *se;
unsigned long offset = 0;
size_t maxalign = 0;
size_t align;
ret = alloc_ty_struct();
ret->tag = tag;
#ifdef DEBUG2
printf("Parsing structure definition...\n");
#endif
ret->scope = new_scope(SCOPE_STRUCT);
for (t = *curtok; t != NULL; t = t->next) {
prevtok = t;
if (t->type == TOK_COMP_CLOSE) {
/* } reached - definition complete */
break;
} else if (!IS_KEYWORD(t->type) && t->type != TOK_IDENTIFIER) {
errorfl(t, "Syntax error at ``%s'' - "
"Expected start of structure member definition",
t->ascii);
PS_RET_ERR(ret);
}
if ((dec = parse_decl(&t, DECL_STRUCT)) == NULL) {
PS_RET_ERR(ret);
}
store_member_struct(ret, dec);
/*
* If any of the structure members is incomplete, the entire
* structure is incomplete
* XXX implement incomplete check in decl.c!
*/
#if 0 /* dtype is not yet filled! */
if (dec->dtype->incomplete) {
ret->incomplete = 1;
}
#endif
}
if (ret->scope->slist == NULL) {
errorfl(t, "Empty structure declaration");
PS_RET_ERR(ret);
}
ret->size = 0;
for (se = ret->scope->slist; se != NULL; se = se->next) {
size_t size;
struct type *ty = se->dec->dtype;
if (ty->tlist != NULL) {
if (ty->tlist->type == TN_ARRAY_OF
&& ty->tlist->arrarg->const_value == NULL) {
/* C99 flexible array member */
/*
* 09/15/07: Wow this was missing alignment
* and member offset assignment... because
* we used to ``break'' here
*/
if (se->next != NULL) {
errorfl(NULL /* XXX */,
"Flexible array not "
"last member of "
"structure");
continue;
} else {
ret->flexible = se->dec;
/* break;*/
}
/* continue;*/
}
}
if (ret->flexible != se->dec) {
size = backend->get_sizeof_decl(se->dec, NULL);
if (size == 0) {
errorfl(NULL, "Incomplete type `%s'", ty->name);
continue;
}
}
if (type == TY_STRUCT) {
/* struct */
align = backend->get_align_type(ty);
if (/*align*/1) {
/* Align all types > char */
while (offset % align/*size*/) ++offset;
}
se->dec->offset = offset;
offset += size;
} else {
/* union */
size_t align;
align = backend->get_align_type(ty);
if (align > maxalign) {
maxalign = align;
}
if (size > ret->size) {
ret->size = size;
}
}
}
if (type == TY_UNION) {
/* XXX this seems completely bogus ... */
if (/*align*/1) {
while (ret->size % maxalign) ++ret->size;
}
} else {
/* XXX ?!? */
ret->size = offset;
se = ret->scope->slist;
#if 0
align = backend->get_align_type(se->dec->dtype);
#endif
{
static struct type ty;
ty.code = TY_STRUCT;
ty.tstruc = ret;
align = backend->get_align_type(&ty);
}
while (ret->size % align) {
++ret->size;
}
}
if (t == NULL) {
errorfl(prevtok, "Unexpected end of file");
PS_RET_ERR(ret);
}
#ifdef DEBUG2
printf("Structure def with %d members parsed successfully!\n",
ret->nmemb);
#endif
if (ret->nmemb == 0) {
if (ret->tag != NULL) {
errorfl(*curtok,
"Empty structure declaration `%s'", ret->tag);
} else {
errorfl(*curtok, "Empty structure declaration");
}
}
/* XXX ? */ *curtok = t;
close_scope();
return ret;
}
struct ty_enum *
parse_enum(struct token **curtok) {
struct ty_enum *ret;
struct token *t;
struct token *prevtok = NULL;
struct token *valtok;
struct expr *ex;
char *name;
int op;
int val = 0;
int alloc;
int curval = 0;
ret = alloc_ty_enum();
alloc = 0;
#ifdef DEBUG2
puts("------------------------------------");
#endif
for (t = *curtok; t != NULL; t = t->next) {
prevtok = t;
if (t->type == TOK_COMP_CLOSE) {
/* End of definition reached */
break;
} else if (t->type != TOK_IDENTIFIER) {
errorfl(t, "Syntax error at `%s' - Expected enum "
"member name", t->ascii);
free(ret);
return NULL;
}
/*
* Ok, is identifier. Either read constant expression, if
* specified, or add one to previous member value
*/
name = t->data;
if (next_token(&t) != 0) {
free(ret);
return NULL;
}
if (t->type == TOK_COMP_CLOSE) {
/* } - Definition ends here */
val = curval;
valtok = const_from_value(&val, NULL);
if (store_member_enum(ret, name, valtok,
NULL, &alloc) != 0) {
errorfl(t, "Multiple definitions of `%s'",
name);
}
break;
} else if (t->type == TOK_OPERATOR) {
/* Must be ``,'' or ``='' */
op = *(int *)t->data;
if (op == TOK_OP_ASSIGN) {
if (next_token(&t) != 0) {
return NULL;
}
ex = parse_expr(&t, TOK_OP_COMMA,
TOK_COMP_CLOSE, EXPR_CONST, 1);
if (ex == NULL) {
#ifndef NO_EXPR
return NULL;
#endif
}
if (t->type == TOK_COMP_CLOSE) {
t = t->prev;
}
/* XXX evaluate ex ... */
valtok = const_from_value(
ex->const_value->value,
ex->const_value->type);
if (store_member_enum(ret, name, valtok,
NULL, &alloc) != 0) {
errorfl(t, "Multiple definitions of "
"`%s'", name);
}
/* Now update current value counter */
curval = (int)cross_to_host_size_t(
ex->const_value);
++curval;
} else if (op == TOK_OP_COMMA) {
/*
* No initializer given, so this gets the value
* of the previous member + 1. Note that C99
* permits a ``dangling'' comma at the end of
* an enum def., as in ``enum foo { FOO, BAR,
* };'', so we must also check whether the
* definition ends here
*/
val = curval++;
valtok = const_from_value(&val, NULL);
if (store_member_enum(ret, name, valtok,
NULL, &alloc) != 0) {
errorfl(t, "Multiple definitions of "
"`%s'", name);
}
if (t->next
&& t->next->type == TOK_COMP_CLOSE) {
/* Definition ends */
t = t->next;
break;
}
}
} else {
errorfl(t,
"Syntax error at `%s' - "
"Expected enum initializer, comma or }",
t->ascii);
free(ret);
return NULL;
}
}
#ifdef DEBUG2
puts("------------------------------------");
#endif
if (t == NULL) {
errorfl(prevtok, "Unexpected end of file");
free(ret);
return NULL;
}
*curtok = t;
return ret;
}
struct ntab {
struct nentry {
char *name;
int refcount;
int line;
struct decl *dec;
} *nametab;
int alloc;
int index;
};
/*
* Delete structure members or function arguments of dest, if existent, then
* delete dest. Intended to use for early escape from syntax errors in struct
* and func parsing
*/
static void
drop_stuff(struct ty_func *dest, struct ntab *n) {
#if 0
if (dest->args != NULL) {
/* Is function */
free(dest->args);
dest->args = NULL;
}
#endif
if (dest->scope != NULL) {
/* free(dest->scope); */
}
free(dest);
if (n != NULL && n->nametab != NULL) {
free(n->nametab);
n->nametab = NULL;
}
}
/*
* Stores pointer ``p'' in the name entry table pointed to by ``dest''.
* The table must be created with all members set to zero, e.g. by
* writing: struct ntab n = { 0, 0, 0 };
* Returns 1 if a string equivalent to the one to by ``p'' already
* resides in the table (p is not stored if this happens), else 0
* n.nametab[n.index].name will always be a null pointer
*/
static int
store_ident(struct ntab *dest, char *name, int line) {
int i;
if (dest->index >= (dest->alloc - 1)) {
dest->alloc += 8;
dest->nametab =
n_xrealloc(dest->nametab,
dest->alloc * sizeof *dest->nametab);
}
/* Make sure we have no multiple definitions */
for (i = 0; i < dest->index; ++i) {
if (strcmp(dest->nametab[i].name, name) == 0) {
/* Already exists - no need to save */
return 1;
}
}
dest->nametab[ dest->index ].name = name;
dest->nametab[ dest->index ].line = line;
dest->nametab[ dest->index ].refcount = 0;
dest->nametab[ ++dest->index ].name = NULL;
return 0;
}
/*
* Looks up string pointed to by ``name'' in name table pointed to by
* ``n''. Returns a pointer to that on success, else NULL.
*/
static struct nentry *
lookup_ident(struct ntab *n, char *name) {
int i;
for (i = 0; n->nametab[i].name != NULL; ++i) {
if (strcmp(n->nametab[i].name, name) == 0) {
++n->nametab[i].refcount;
return &n->nametab[i];
}
}
return NULL;
}
/*
* Helper macro for parse_func() - Close scope only if it is a function
* prototype scope, i.e. not a definition. If we are dealing with a
* definition (prototype followed by a ``{''), this is block scope and
* should not be closed
*/
#if 0
#define CLOSE_SCOPE(tok) do { \
if (tok) { \
struct token *_t2; \
if ((_t2 = ignore_attr(tok)) != NULL) { \
if (_t2->type != TOK_COMP_OPEN) { \
/* Is declaration */ \
close_scope(); \
} \
} \
} \
} while (0)
#endif
void CLOSE_SCOPE(struct token *tok) { do { \
if (tok) { \
struct token *_t2; \
if ((_t2 = ignore_attr(tok)) != NULL) { \
if (_t2->type != TOK_COMP_OPEN) { \
/* Is declaration */ \
close_scope(); \
} \
} \
} \
} while (0)
; }
static void
check_matches(struct token *t, struct ntab *n, struct decl **dec) {
int i;
struct nentry *np;
for (i = 0; dec[i] != NULL; ++i) {
if ((np = lookup_ident(n, dec[i]->dtype->name)) == NULL) {
errorfl(t,
"Declaration for non-existent parameter `%s'",
dec[i]->dtype->name);
} else if (np->refcount > 1) {
errorfl(t,
"Multiple declarations for parameter `%s'",
dec[i]->dtype->name);
} else {
np->dec = dec[i];
}
}
}
static int
do_parse_kr_func(struct token **tok, struct ty_func *ret) {
struct token *t;
struct decl **dec;
int errors = 0;
int i;
char **names = NULL;
struct nentry *np;
struct ntab n = { 0, 0, 0 };
ret->type = FDTYPE_KR;
(void) names;
for (t = *tok; t != NULL; t = t->next) {
if (t->type == TOK_PAREN_CLOSE) {
/*
* End of parenthesized part of declaration reached -
* read parameter declarations now!
*/
if (next_token(&t) != 0) {
return -1;
}
for (; t != NULL; t = t->next) {
if (t->type == TOK_COMP_OPEN) {
/*
* Opening compound statement -
* end reached
*/
t = t->prev;
break;
} else if (IS_TYPE(t)) {
dec = parse_decl(&t, DECL_FUNCARG_KR);
if (dec == NULL) {
return -1;
}
if (t && t->type != TOK_SEMICOLON) {
errorfl(t,
"Syntax error at `%s' - "
"Expected semicolon", t->ascii);
return -1;
} else if (t == NULL) {
break;
}
check_matches(t, &n, dec);
#if 0
store_member_func(ret, dec);
#endif
} else {
if (t->type == TOK_OPERATOR) {
int i;
for (i = 0; i < 3; ++i) {
if (*(int *)t->data
!= TOK_OP_STRUMEMB) {
break;
}
if (t->next == NULL) {
break;
}
t = t->next;
}
if (i == 3) continue;
}
/* Garbage */
errorfl(t, "Syntax error at `%s' - "
"Expected parameter "
"declaration", t->ascii);
return -1;
}
}
/*
* If this point is reached, either the declaration
* list was valid, or the end-of-file has been
* encountered prematurely. Both cases are handled by
* the code below...
* We must check whether all parameters enclosed by
* parentheses have been resolved by declarations!
*/
if ((np = n.nametab) != NULL) {
for (i = 0; n.nametab[i].name != NULL; ++i) {
struct decl *dummy[2];
if (n.nametab[i].refcount < 1) {
/* Undeclared - assume int */
n.nametab[i].dec = alloc_decl();
n.nametab[i].dec->dtype =
n_xmemdup(
make_basic_type(TY_INT),
sizeof(struct type));
n.nametab[i].dec->dtype->name =
n.nametab[i].name;
}
dummy[0] = n.nametab[i].dec;
dummy[1] = NULL;
store_member_func(ret, dummy);
}
}
break;
} else {
/*
* This must be an identifier. Everything else is
* illegal!
*/
if (t->type != TOK_IDENTIFIER) {
errorfl(t, "Syntax error at `%s' - "
"Expected identifier", t->ascii);
break;
}
if (store_ident(&n, t->data, t->line) == 1) {
errorfl(t,
"Multiple definitions of `%s'",
t->ascii);
++errors;
}
if (next_token(&t) != 0) {
return -1;
}
if (t->type == TOK_OPERATOR) {
if (*(int *)t->data != TOK_OP_COMMA) {
errorfl(t, "Syntax error at `%s' - "
"expected comma or closing "
"parentheses", t->ascii);
} else {
continue;
}
} else if (t->type != TOK_PAREN_CLOSE) {
errorfl(t, "Syntax error at `%s' - "
"expected comma or closing parentheses",
t->ascii);
} else {
t = t->prev;
continue;
}
return -1;
}
}
if (errors) {
return -1;
}
*tok = t;
return 0;
}
static int
do_parse_iso_func(struct token **tok, struct ty_func *ret) {
struct token *t;
struct token *prevtok;
struct decl **dec;
ret->type = FDTYPE_ISO;
t = *tok;
for (t = *tok; t != NULL; t = t->next) {
prevtok = t;
if (t->type == TOK_PAREN_CLOSE) {
if (t->next == NULL) {
break;
}
if (t->next->type != TOK_COMP_OPEN) {
if (ret->nargs == 0) {
/*
* This is a declaration and no
* arguments are given; -1 indicates
* an unknown amount of arguments
*/
ret->nargs = -1;
}
if (t->next->type == TOK_KEY_ASM) {
t = t->next;
ret->asmname
= parse_asm_varname(&t);
if (ret->asmname == NULL) {
return -1;
}
t = t->prev;
}
}
#if 0
/* End of declaration reached */
if (ret->nargs == 0) {
/*
* This might either be a declaration like
* void f();
* or a definition like
* void f() {
* In case of a declaration, -1 indicates
* unknown number of arguments.
*/
if (t->next != NULL
&& t->next->type != TOK_COMP_OPEN) {
ret->nargs = -1;
}
}
#endif
break;
} else if (IS_TYPE(t)) {
struct token *tmp;
/* int, unsigned, static, etc or typedef */
if (ret->variadic) {
errorfl(t, "`...' must be last argument");
}
tmp = t;
if ((dec = parse_decl(&t, DECL_FUNCARG)) == NULL) {
return -1;
}
#ifdef DEBUG2
printf("parsed declaration:\n");
puts("--------------");
while (tmp != t) {
printf("%s\n", tmp->ascii);
tmp = tmp->next;
}
puts("--------------");
#endif
if (t &&
(t->type != TOK_OPERATOR ||
*(int *)t->data != TOK_OP_COMMA)) {
if (t->type != TOK_PAREN_CLOSE) {
errorfl(t,
"Syntax error at `%s' - "
"expected comma", t->ascii);
return -1;
} else {
t = t->prev;
}
}
store_member_func(ret, dec);
} else {
/* Garbage or variadic function */
if (t->type == TOK_OPERATOR) {
int i = 0;
do {
if (*(int *)t->data
!= TOK_OP_STRUMEMB) {
break;
}
} while (++i < 3
&& (t = t->next)
&& t->type == TOK_OPERATOR);
if (i == 3) {
if (ret->variadic) {
errorfl(t, "Duplicate use of "
"`...'");
}
ret->variadic = 1;
if (ret->nargs == 0) {
errorfl(t, "At least one "
"argument before `...'"
"required");
}
t = t->next;
if (t &&
(t->type != TOK_OPERATOR ||
*(int *)t->data
!= TOK_OP_COMMA)) {
if (t->type
!= TOK_PAREN_CLOSE) {
errorfl(t, "Syntax "
"error at `%s'"
"- expected "
"comma",
t->ascii);
return -1;
} else {
t = t->prev;
}
}
continue;
}
}
errorfl(t,
"Syntax error at `%s' - Expected closing "
"parentheses or start of parameter declaration",
t->ascii);
return -1;
}
}
*tok = t;
return 0;
}
static void
put_func_name(const char *name) {
size_t size = strlen(name) + 1;
struct decl *d = alloc_decl();
struct initializer *init = alloc_initializer();
struct ty_string *ts;
struct expr *ex = alloc_expr();
struct decl *decls[4];
ts = make_ty_string(name, size);
ts->ty->tlist->arrarg = ex;
ex->const_value = n_xmalloc(sizeof *ex->const_value);
memset(ex->const_value, 0, sizeof *ex->const_value);
ex->const_value->str = ts;
ex->const_value->type = ts->ty;
init->type = INIT_EXPR;
init->data = ex;
ts->ty->storage = TOK_KEY_STATIC;
d->dtype = ts->ty;
ts->ty->name = "__func__";
d->init = init;
decls[0] = d;
decls[1] = n_xmemdup(d, sizeof *d);
decls[1]->dtype = n_xmemdup(decls[1]->dtype, sizeof *decls[1]->dtype);
decls[1]->dtype->name = "__PRETTY_FUNCTION__";
/* 09/30/07: BitchX uses __FUNCTION__ */
decls[2] = n_xmemdup(d, sizeof *d);
decls[2]->dtype = n_xmemdup(decls[1]->dtype, sizeof *decls[1]->dtype);
decls[2]->dtype->name = "__FUNCTION__";
decls[3] = NULL;
store_decl_scope(curscope, decls);
decls[1]->dtype->name = decls[0]->dtype->name;
decls[2]->dtype->name = decls[0]->dtype->name;
#if 0
decls[1]->is_alias = 1;
#endif
/*
* 070501: Setting a boolean alias flag is not correct. Instead we
* must have a pointer to the base declaration, so that access_
* symbol() can reference it. And then only define that declaration
* in the backend (currently only PowerPC seems to make use of
* is_alias at all
*/
decls[1]->is_alias = decls[0];
decls[2]->is_alias = decls[0];
}
/*
* Must be called with a curtok pointing to the beginning of the function
* argument list
* void f(foo)
* ^
* 09/30/07: Now we pass the declaration type to avoid breakage when a
* cast is read;
*
* (void(*)())expr;
*
* ... here the (kludged) search for the identifier breaks. Maybe we
* should pass the name instead of searching it here
*/
struct ty_func *
parse_func(struct token **curtok, const char *name) {
struct token *t = NULL;
struct token *prevtok = NULL;
struct type *td = NULL;
struct ty_func *ret;
struct ntab n = { 0, 0, 0 };
/* char *name;*/
ret = alloc_ty_func();
#if 0
/* XXX kludge */
for (t = (*curtok)->prev; t->type != TOK_IDENTIFIER; t = t->prev) {
;
}
name = t->ascii;
#endif
if (next_token(curtok) != 0) {
free(ret);
return NULL;
}
t = *curtok;
ret->scope = new_scope(SCOPE_CODE);
if (t->type == TOK_KEY_VOID) {
if (t->next != NULL) {
if (t->next->type == TOK_PAREN_CLOSE) {
#ifdef DEBUG2
printf("Function takes no arguments\n");
#endif
*curtok = t->next;
if (t->next->next
&& t->next->next->type
== TOK_COMP_OPEN) {
put_func_name(name);
CLOSE_SCOPE(t->next->next);
return ret;
}
t = t->next;
#if 0
CLOSE_SCOPE(t->next->next);
return ret;
#endif
}
} else {
errorfl(t, "Premature end of file");
free(ret);
return NULL;
}
}
/*
* There are two possible definition types:
* ISO style or K&R style, i.e.
* void f(char *foo, char bar, int x) {
* or
* void f(foo, bar, x)
* char *foo, bar;
* int x; {
* K&R C has no prototypes, so every paramter declaration
* indicates a function definition. Thus, it can be assumed
* that the parameter declarations end when the ``{'' token
* is encountered.
*
* If the first node of the token list at this point is an
* identifier, we simply assume a K&R declaration, else ISO
*/
if (t->type == TOK_IDENTIFIER
&& (td = lookup_typedef(curscope, t->data)) == NULL) {
/* Is K&R declaration */
if (do_parse_kr_func(&t, ret) != 0) {
drop_stuff(ret, &n);
recover(curtok, TOK_PAREN_CLOSE, 0);
ret = NULL;
}
} else {
/* Is ISO declaration */
if (do_parse_iso_func(&t, ret) != 0) {
drop_stuff(ret, &n);
recover(curtok, TOK_PAREN_CLOSE, 0);
ret = NULL;
}
}
if (t == NULL) {
errorfl(prevtok, "Unexpected end of file");
drop_stuff(ret, ret->type == FDTYPE_KR?
(void *)&n : (void *)NULL);
return NULL;
}
if (t->next && t->next->type == TOK_COMP_OPEN) {
put_func_name(name);
}
*curtok = t;
CLOSE_SCOPE(t->next);
return ret;
}
syntax highlighted by Code2HTML, v. 0.9.1