home *** CD-ROM | disk | FTP | other *** search
-
- #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);
- }
-