📄 macro.c
字号:
/*****************************************************************************The function 'macro()' is repeatedly called by the parser to obtainits next input token. The default behaviour is just grabbing such a tokenfrom the lexical analyser.However if the fetched token is an aliased keyword, unaliasing is done.if the fetched token leads a macro call: - it will read the entire macro call in a local parse tree. - it will perform a macro expansion - subsequently deliver tokens from this expansion, until it is exhausted. Thus the parser can perform real grammar checking on the expanded result.Note that macro calls can nest!*****************************************************************************/#include <stdio.h>#include "defines.h"#include "types.h"#include "keywords.h"/** IMPORTED ***/extern int yy_create_edf_lex();extern int yy_create_edf_lineno;extern int err_count;extern int debug;extern char yy_create_edf_text[];extern char *str_hash(), *treetxt();extern PARSETREE *get_parsetree(), *put_parsetree();extern PARSETREE *locate();extern char *keywords[];/*** EXPORTED ***/PARSETREE *token;int keywordlevelused;/*** LOCAL ***/static PARSETREE *newkeydef[MAXKEYWORDS];/* defined keywords*/static int newkeyalias[MAXKEYWORDS]; /* keyword aliases */static int curr_macro; /* type number of macro now expanded*/static char *formal_asgn; /* formal argument being assigned*/static int mlines[2]; /* begin-end line numbers of call*//*** FORWARD ***/extern char *lineno(), *tokentxt();extern PARSETREE *readmacrocall(), *expandmacro(), *assignformal();extern PARSETREE *buildmacro(), *cpy_parsetree(), *find_actual();int macro(){ static PARSETREE *mstack[MAXDEPTH]; /* pointers in macro storage */ static int stackp; /* for sequential output */ static int lastline; int type; PARSETREE **p, *exp;again: /* Nothing on stack from last macro expansion? */ /* then read new input from file */ if (stackp==0 && !mstack[0]) { if (!token) token = get_parsetree(); else token->next = NULL; /* thus actually always NULL */ token->type = type = yy_create_edf_lex(); token->line = yy_create_edf_lineno; DEBUG(9) "macro: reading token '%s' from yy_create_edf_lex (line %d)\n", yy_create_edf_text, yy_create_edf_lineno); switch( type) { case NUMBER: token->data.ival = atoi( yy_create_edf_text); Case STRING: case IDENT: token->data.token = str_hash( yy_create_edf_text); Case KEYWORD: token->data.tree = NULL; token->type = type = key_hash( yy_create_edf_text, 0); } /* Have I got a newly-introduced keyword name? */ /* If it was a simple keyword alias, then replace */ if (type>NKEYWORDS && newkeyalias[ type]) { type = newkeyalias[type]; DEBUG(3) "macro: keyword alias '%s' to '%s'\n", yy_create_edf_text, keywords[type]); } if (type <= NKEYWORDS) return( type); /* Return standard EDIF item */ /* type is macro call requiring expansion.... */ /* save line numbers, read full macro call */ mlines[0] = yy_create_edf_lineno; mstack[ stackp=0 ] = readmacrocall( type); mlines[1] = lastline = yy_create_edf_lineno; } /****** read next token from stored macro expansion ***/ /****** if keyword alias, then unalias ****************/ /****** if macro call, then replace by its expansion **/ /** remove token from storage just before it is returned */ /** only (keyword is removed after ) ******************/ if (token) put_parsetree(token); token = mstack[ stackp]; DEBUG(8) "macro: reading token '%s' from macro expansion stack, level %d\n", treetxt(token), stackp); if (!token) /* end of list reached */ { DEBUG(5) "macro expansion returns ')'\n"); if (stackp<=0) { fprintf( stderr, "Program error: end of macro stack!\n"); terminate(3); } stackp--; /* all done? then clear inputline info */ if (stackp==0 && !mstack[ 0]) mlines[0] = mlines[1] = 0; if (!token) token = get_parsetree(); else token->next = NULL; token->line = lastline; return( token->type = ENDLIST); } /* else .... */ type = token->type; if (ISKEYWORD(type) || type==KEYWORD) { if (type>NKEYWORDS && newkeyalias[type]) { DEBUG(3) "macro: keyword alias '%s' to '%s'\n", keywords[type], keywords[newkeyalias[type]]); token->type = type = newkeyalias[type]; } if (type>NKEYWORDS && newkeydef[type]) { /* macro call: replace by its expansion */ /* preform macro expansion, result in exp */ exp = expandmacro( token); /* remove macro call from stack */ mstack[ stackp] = put_parsetree(token); token = NULL; if (exp) { /* insert nonemtpy (list?) result in stack */ DEBUG(5) "macro: insert macro-expansion in stack[%d]\n", stackp); for (p= &(exp->next); *p; p= &((*p)->next)); *p = mstack[ stackp]; mstack[ stackp] = exp; } else DEBUG(5) "macro: expansion had empty result\n"); if (stackp==0 && !mstack[0]) mlines[0] = mlines[1] = 0; DEBUG(6) "macro: go back, try to return token to parser\n"); goto again; } /* reference to standard EDIF keyword */ /* remove keyword token from stack, add 'next' and 'data.tree'*/ mstack[ stackp] = token->next; /* == mstack[stackp]->next */ mstack[ ++stackp] = token->data.tree; } else mstack[ stackp] = token->next; token->next = NULL; DEBUG(5) "macro expansion returns '%s'\n", tokentxt()); lastline = token->line; return( type);}void keywordalias( p)PARSETREE *p;{ int type, newtype; if (keywordlevelused < 1) keywordlevelused = 1; newtype = key_hash( p->data.tree->data.token, 1); if (!newtype) { fprintf( stderr, "%s keywordAlias redefines existing keyword '%s'!\n", lineno(), p->data.tree->data.token); err_count++; return; } type = key_hash( p->data.tree->next->data.token, 0); if (!ISKEYWORD(type)) { fprintf( stderr, "%s keywordAlias references unknown keyword '%s'!\n", lineno(), p->data.tree->next->data.token); err_count++; return; } if (newkeyalias[type]) /* resolve multilevel alias */ type = newkeyalias[type]; newkeyalias[ newtype] = type;}void keyworddefine( p)PARSETREE *p;{ int newtype; if (keywordlevelused < 2) keywordlevelused = 2; newtype = key_hash( p->data.tree->data.token, 1); if (!newtype) { fprintf( stderr, "%s keywordDefine redefines existing keyword '%s'!\n", lineno(), p->data.tree->data.token); err_count++; return; } newkeydef[ newtype] = p;}static PARSETREE *readmacrocall( type)int type;{ PARSETREE *call, **p; call = get_parsetree(); call->type = (newkeyalias[type])? newkeyalias[type] : type; call->line = yy_create_edf_lineno; DEBUG(3) "macro: storing call '(%s'\n", keywords[call->type]); p = &(call->data.tree); while ((type=yy_create_edf_lex()) != ENDLIST && type != ENDFILE) { if (type == KEYWORD) *p = readmacrocall( key_hash( yy_create_edf_text, 0)); else { *p = get_parsetree(); (*p)->type = type; (*p)->line = yy_create_edf_lineno; if (type == IDENT || type == STRING) (*p)->data.token = str_hash( yy_create_edf_text); else if (type == NUMBER) (*p)->data.ival = atoi( yy_create_edf_text); } p = &((*p)->next); } return( call);}/**** generate new parsetree with the expansion of the macro call ***/static PARSETREE *expandmacro( call)PARSETREE *call;{ PARSETREE *formal, *mdef, *result, *args; DEBUG(3) "macro: perform macro expansion of '%s' call (line %d)\n", keywords[call->type], call->line); curr_macro = call->type; /*** get formal par decl ***/ formal = locate( newkeydef[curr_macro], KkeywordParameters, Kformal, 0); /*** assign formal arguments ***/ args = assignformal( formal, call->data.tree); /*** get body of macro definition ***/ mdef = locate( newkeydef[curr_macro], Kgenerate, 0)->data.tree; /*** building expanded result **/ result = buildmacro( args, mdef); /*** free argument values, and return result ***/ while (args) args=put_parsetree(args); return( result);}static PARSETREE *assignformal( formal, call)PARSETREE *formal, *call;{ PARSETREE *f, *result, **rp, *coll, *opt, **vp; int ncolls, nopts, cnt, formal_type;; cnt=ncolls=nopts=formal_type=0; /* scan once for the characteristics of the declared formal args */ for (f=formal; f; f=f->next) { cnt++; /* count the number of declared arguments */ if (coll=locate( f, Kcollector, 0)) { ncolls++; /* collector found */ if (!formal_type) formal_type = coll->type; } if (opt=locate( f, Koptional, 0)) { nopts++; /* optional arg found */ if (!formal_type) formal_type = opt->type; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -