home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Dream 48
/
Amiga_Dream_48.iso
/
Atari
/
c
/
cpp.zoo
/
src
/
define.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-03
|
4KB
|
206 lines
#include <string.h>
#include "global.h"
/*
get_parms() -- return a list of the formal parameters in a macro
definition. Return the number of parameters in |*n|.
*/
static TokenP get_parms(n)
int *n;
{
TokenP T, parms = NULL;
for (*n = 0;;) {
T = token();
if (T->type == EOL)
goto oops;
if (T->type == RPAREN) {
if (*n == 0)
return NULL;
goto oops;
}
if (T->type != ID)
goto oops;
if (!parms)
parms = T;
else
parms->next = T;
(*n)++;
T = token();
switch (T->type) {
case COMMA:
free_token(T);
continue;
case RPAREN:
free_token(T);
return parms;
default:
free_token(T);
goto oops;
}
}
oops:
error("syntax error in macro definition");
if (parms)
free_tlist(parms);
*n = -1;
return NULL;
}
/*
macro_eq() -- determine if macro bodies |M1| and |M2| are equal, modulo
whitespace. Currently unfinished.
*/
int macro_eq(M1, M2)
Macro *M1, *M2;
{
if (M1->flags != M2->flags || M1->nargs != M2->nargs)
return 0;
return 1;
}
/*
is_parm() -- determine if Token |T| is one of the formal parameters of the
macro. Return the "index" into the list of parameters, or -1 if there is
no match
*/
static int is_parm(T, parms)
TokenP T, parms;
{
int i;
register TokenP t;
if (parms == NULL)
return -1;
for (i = 0, t = parms; t; i++, t = t->next) {
if (streq(T->txt, t->txt))
return i;
}
return -1;
}
/* do_define() -- handle a #define directive */
void do_define()
{
TokenP K, L;
register TokenP T, pT;
Macro *M, *M1;
int i;
static Token head;
_tokenize_line();
K = token();
if (K->type != ID) {
error("argument \"%s\" to #define is not an identifier", K->txt);
return;
}
M = (Macro *)mallok(sizeof (Macro));
M->flags = 0;
T = token();
if (strlen(T->pre_ws) == 0 && T->type == LPAREN) {
/* a macro with arguments -- get the formal parameters */
free_token(T);
T = NULL;
M->flags |= HASARGS;
M->argnames = get_parms(&M->nargs);
if (M->nargs < 0) {
free_tlist(M->argnames);
free(M);
return;
}
} else {
M->nargs = 0;
M->argnames = NULL;
push_tlist(T);
}
L = &head;
head.next = NULL;
for (;;) {
T = token();
if (T->type == EOL)
break;
switch (T->type) {
case POUND:
free_token(T);
T = token();
if ((i = is_parm(T, M->argnames)) < 0) {
error("# not followed by macro parameter");
push_tlist(T);
break;
}
T->type = MACRO_ARG;
T->flags |= STRINGIZE_ME;
T->val = i;
L = L->next = T;
break;
case TOK_CAT:
free_token(T);
T = token();
if (L == &head || T->type == EOL) {
if (L == &head)
error("## at beginning of macro body");
if (T->type == EOL)
error("## at end of macro body");
push_tlist(T);
break;
}
L->flags |= CONCAT_NEXT;
L = L->next = T;
break;
case ID:
if ((i = is_parm(T, M->argnames)) >= 0) {
T->type = MACRO_ARG;
T->val = i;
}
L = L->next = T;
break;
default:
L = L->next = T;
break;
}
}
/* remove leading space from the resulting sequence */
T = head.next;
if (T)
*T->pre_ws = '\0';
M->m_text = head.next;
/*
As per the Standard, a macro can only be re-#define'd with an identical
body, modulo whitespace.
*/
if ((M1 = lookup(K->txt, K->hashval)) && !macro_eq(M, M1)) {
warning("non-identical redefine of \"%s\"", K->txt);
free_tlist(M->m_text);
free_tlist(M->argnames);
free(M);
} else {
hash_add(K->txt, K->hashval, M);
}
free_token(K);
}
/* do_undefine() -- handle an #undef directive */
void do_undefine()
{
Macro *M;
TokenP T;
T = token();
if (T->type != ID) {
error("argument \"%s\" to #undef is not an identifier", T->txt);
free_token(T);
return;
}
M = lookup(T->txt, T->hashval);
if (M && !(M->flags & MAGIC))
hash_remove(T->txt, T->hashval);
free_token(T);
T = token();
if (T->type != EOL)
warning("garbage after #undef");
free_token(T);
}