Subject: v11i041: Inline code expander for C, Part03/04 Newsgroups: comp.sources.unix Sender: sources Approved: rs@uunet.UU.NET Submitted-by: omepd!mcg Posting-number: Volume 11, Issue 41 Archive-name: inline/Part03 # This is a shell archive. Remove anything before this line # then unpack it by saving it in a file and typing "sh file" # (Files unpacked will be owned by you and have original permissions). # This archive contains the following files: # ./expand.c # ./rewrite.c # ./yylex.c # ./tokens.c # ./utils.c # ./mem.c # if `test ! -s ./expand.c` then echo "writing ./expand.c" sed 's/^X//' > ./expand.c << '\Rogue\Monster\' X/* X * inline code expander X * X * (c) 1986 - copyright 1986, s. mcgeady, all rights reserved X */ X X/* $Header: expand.c,v 1.13 87/06/24 13:11:24 mcg Rel $ */ X X/* X * find an expansion opportunity, get its parameters, and expand the node X */ X X#include "inline.h" X#include "tokens.h" X Xextern struct expand_node *mkenode(); /* forward declaration */ Xextern struct expand_node *doactuals(); Xextern struct token *dostmt(); Xextern struct token *doexpr(); X Xdoinline(mem,prog) Xregister int mem; Xregister struct toklist *prog; X{ X register struct token *tt, *tl, *tx; X register struct token *begin = NILTOK; X register struct token *end; X register struct expand_node *e; X register struct inline_node *node; X register int i; X register int emem; X int expanded = 0; X X /* X * look through list to find first expansion possibility, X * keeping track of statement breaks. a statement break occurs X * at the last semicolon, closing brace, or opening brace. expansions X * inside control statements complicate matters X */ X X emem = openpool(); X tt = NILTOK; X for (tl = prog->tl_head; tl != NILTOK; tt = tl, tl = tl->t_next) { X switch(tl->t_tok) { X case T_IDENT: X if (iscall(tl) && (node = isinline(tl->t_id))) { X node->i_nseen++; X X /* don't expand if this expression has ||, && */ X /* or ?: --- should not expand if there's a */ X /* comma operator, but can't identify those */ X /* easily */ X X for (tx = begin; tx && tx != tl; tx = tx->t_next) { X if (tx->t_tok == T_CAND || X tx->t_tok == T_COR || X tx->t_tok == T_QUEST) { X if (node->i_flags&I_EXPR) { X tl->t_flags |= TNEEDEXPR; X } else { X tl->t_flags |= TNOEXPAND; X warn(tl->t_line,"inline %s is not expandable in this context", tl->t_id); X } X } X } X if (tl->t_flags&TNOEXPAND) { X break; X } X X if ((e = doactuals(emem,tt,node)) == NILP(struct expand_node *)) { X /* don't expand again */ X tl->t_flags |= TNOEXPAND; X warn(tl->t_line,"inline %s is not expandable in this context", tl->t_id); X } else { X X end = dostmt(begin->t_next,0); X if (doexpand(mem,begin,end,tt->t_next,tl->t_flags&TNEEDEXPR,e)) { X node->i_nexpand++; X tl = begin; X expanded++; X } X } X } X break; X X case T_IF: X case T_SWITCH: X begin = tt; /* point to node before */ X break; X X case T_WHILE: X case T_FOR: X /* skip over control part */ X end = dostmt(tl,1); X i = 0; X for (tx = tl->t_next; tx != end; tx = tx->t_next) { X if (iscall(tx) && (node = isinline(tx->t_id))) { X node->i_nseen++; X if (node->i_flags&I_EXPR) { X tx->t_flags |= TNEEDEXPR; X i = 1; X } else { X warn(tx->t_line,"inline %s is not expandable in this context", tx->t_id); X tx->t_flags |= TNOEXPAND; X } X } X } X /* no expansion possibility inside for, while */ X if (i) { X begin = tt; X } else { X begin = tl = end; X } X break; X X case T_COLON: X /* distinguish between label and ? : op */ X for (tx = begin; tx != tl; tx = tx->t_next) { X if (tx->t_tok == T_QUEST) { X break; X } X } X if (tx->t_tok == T_QUEST) { X break; X } X /*FALLTHROUGH*/ X X case T_SEMIC: X case T_LBRACE: X case T_RBRACE: X begin = tl; X break; X X default: X if (istype(tl) || isstoreclass(tl)) { X end = dostmt(tl->t_next,0); X for (tx = tl->t_next; tx != end; tx = tx->t_next) { X if (iscall(tx) && (node = isinline(tx->t_id))) { X node->i_nseen++; X tx->t_flags |= TNOEXPAND; X warn(tx->t_line,"inline %s is not expandable in this context", tx->t_id); X } X } X /* no expansion in initializations */ X begin = tl = end; X } X break; X } X } X (void) closepool(emem); X return(expanded); X} X Xstruct token * Xdostmt(begin,ctrl) Xregister struct token *begin; Xregister int ctrl; X{ X register struct token *tx; X register int seenquest = 0; X X begin = skipws(begin); X while (begin) { X switch(begin->t_tok) { X case T_SWITCH: X case T_WHILE: X case T_FOR: X case T_IF: X /* find end of control part */ X tx = doexpr(begin->t_next,1); X if (ctrl) { X return(tx); X } X /* find end of body */ X tx = dostmt(tx->t_next,0); X X if (begin->t_tok == T_IF) { X /* look for 'else' */ X begin = skipws(tx->t_next); X if (begin->t_tok == T_ELSE) { X return(dostmt(begin,0)); X } X } X return(tx); X X case T_ELSE: X return(dostmt(begin->t_next,0)); X X case T_LBRACE: X for (tx = begin; tx != NILTOK; tx = tx->t_next) { X if ((tx->t_tok == T_RBRACE) && X (tx->t_level == begin->t_level)) { X return(tx); X } X } X error(begin->t_line,"unmatched {"); X break; X X case T_SEMIC: X return(begin); X X case T_COLON: X if (seenquest--) { X begin = begin->t_next; X continue; X } X return(begin); X X case T_QUEST: X seenquest++; X default: X begin = begin->t_next; X continue; X } X /* if we get here, it's an error */ X break; X } X error(begin->t_line, "statement termination error"); X return(NILTOK); X} X Xstruct token * Xdoexpr(begin,ctrl) Xregister struct token *begin; Xregister int ctrl; X{ X register int seenquest = 0; X register struct token *tx; X X begin = skipws(begin); X while (begin) { X switch(begin->t_tok) { X case T_LPAREN: X for(tx = begin; tx != NILTOK; tx = tx->t_next) { X if ((tx->t_tok == T_RPAREN) && X (tx->t_paren == begin->t_paren)) { X if (ctrl) { X return(tx); X } else { X begin = begin->t_next; X continue; X } X } X } X error(begin->t_line, "unmatched parenthesis"); X break; X X case T_WHILE: X case T_FOR: X case T_SWITCH: X case T_IF: X break; X X X case T_RBRACE: X case T_LBRACE: X case T_SEMIC: X return(begin); X X case T_QUEST: X seenquest++; X begin = begin->t_next; X continue; X X case T_COLON: X if (seenquest--) { X return(begin); X } X default: X begin = begin->t_next; X continue; X } X /* if we get here, it's an error */ X break; X } X error(begin->t_line, "expression error"); X return(NILTOK); X} X Xdoexpand(mem,begin,end,here,expr,enode) Xregister int mem; Xregister int expr; Xregister struct token *begin, *end, *here; Xregister struct expand_node *enode; X{ X struct toklist insert; X register struct token *tl, *tx, *th, *tp; X register struct inline_node *node; X register int formal; X register int i; X static int ident = 0; X X if ((here->t_tok != T_ARGLIST) || !(node = isinline(here->t_id))) { X error(here->t_line, "bad call to doexpand '%s' not inline", X here->t_id); X return(0); X } X if (expr && !node->i_flags&I_EXPR) { X error(here->t_line, "bad call to doexpand '%s' not inline", X here->t_id); X return(0); X } X X insert.tl_head = insert.tl_tail = NILTOK; X X addtok(&insert, newtok(mem,T_WS, "\n")); X addtok(&insert, newtok(mem,T_LBRACE, NIL)); X addtok(&insert, newtok(mem,T_WS, "\n")); X X /* output declaration sections for each inline */ X /* declare formal parameters */ X X cpytoklist(mem,&insert,&node->i_tl[SDECLBODY]); X if (expr) { X cpytoklist(mem,&insert,&node->i_tl[SEXPRDECL]); X } X X for(tx = insert.tl_head; tx != NILTOK; tx = tx->t_next) { X if (tx->t_tok == T_FORMAL) { X tx->t_flags |= TNOEXPAND; X } X } X X /* declare return value holders */ X X if (node->i_flags&NEEDRETVAL) { X addtok(&insert, newtok(mem,T_AUTO,NIL)); X addtok(&insert, newtok(mem,T_WS, " ")); X X /* cpytoklist(mem, &insert, &node->i_tl[SDECL]); */ X X /* X * this is a hack to rewrite function pointers found in X * declaration form, e.g: X * int (*(*fp())())() {} [1] X * int (*fp())() {} [2] X * into pointer declaration form: X * int (*(*fp)())(); [1] X * int (*fp)(); [2] X * X * we do this by putting an RPAREN immediately after the X * identifier, and then deleting the next RPAREN of the X * appropriate nesting level. X * X * thanks to the bizarre syntax of C for this one X */ X X { X int plev = -1; X for(tp = node->i_tl[SDECL].tl_head;tp != NILTOK; tp = tp->t_next) { X if (tp->t_tok == T_RPAREN && tp->t_paren == plev) { X plev = -1; X continue; X } X if ((tp->t_tok == T_LPAREN) && (tp->t_paren > 0) && X (tp->t_next->t_tok == T_RPAREN)) { X addtok(&insert,newtok(mem,T_RPAREN,NIL)); X plev = tp->t_paren - 1; X } X addtok(&insert,duptok(mem,tp)); X } X } X X /* end of hack */ X X addtok(&insert, newtok(mem,T_SEMIC,NIL)); X addtok(&insert, newtok(mem,T_WS, "\n")); X } X X /* determine which actuals can be substituted directly, and */ X /* which need to be copied in -- if the formal is never used */ X /* as an lvalue in the expanded routine, and if the actual */ X /* doesn't have any side-effects of referencing it, then it is */ X /* ok to replace instances of the formal with the actual string */ X X /* output initialization */ X /* ... but only for those not sub'd directly */ X X /* cpytoklist(mem,&insert,&node->i_tl[SINITBODY]); */ X X for (i = 0; i < node->i_nformals; i++) { X node->i_formalinfo[i] &= ~I_SUB_OK; X if ((node->i_formalinfo[i]&I_LVALUE) || X (sideeffect(&enode->e_actuals[i]))) { X addtok(&insert,newtok(mem,T_FORMAL,node->i_formals[i])); X /* addtok(&insert,newtok(mem,T_EQ,NIL)); */ X addtok(&insert,newtok(mem,T_ACTUAL,node->i_formals[i])); X addtok(&insert,newtok(mem,T_SEMIC,NIL)); X addtok(&insert,newtok(mem,T_WS," ")); X } else { X /* this actual can be sub'd directly */ X node->i_formalinfo[i] |= I_SUB_OK; X } X } X X /* output body */ X X X here->t_tok = T_WS; X here->t_id = ""; X X if (expr) { X (void) instok(begin, insert.tl_head); X insert.tl_head = insert.tl_tail = NILTOK; X cpytoklist(mem,&insert,&node->i_tl[SEXPRBODY]); X (void) instok(here, insert.tl_head); X } else { X cpytoklist(mem,&insert,&node->i_tl[SBODY]); X if (node->i_flags&NEEDRETVAL) { X here->t_tok = T_IDENT; X here->t_id = mkstr(mem,"_",node->i_id,"_ret_",itoa(ident),"_",0); X } X (void) instok(begin, insert.tl_head); X } X X tl = instok(end, newtok(mem,T_RBRACE, NIL)); X end = instok(tl, newtok(mem,T_WS, "\n")); X X /* go back and fix up all the special stuff */ X X for(tp = NILTOK,tx = begin; tx && tx != end; tp = tx,tx = tx->t_next) { X switch(tx->t_tok) { X case T_RETLAB: X tx->t_tok = T_IDENT; X tx->t_id = mkstr(mem,"_",node->i_id,"_end_",itoa(ident),"_",0); X break; X X case T_RETVAL: X tx->t_tok = T_IDENT; X tx->t_id = mkstr(mem,"_",node->i_id,"_ret_",itoa(ident),"_",0); X break; X X case T_FORMAL: X if ((formal = isformal(node,tx)) < 0) { X error(tx->t_line,"bogus formal"); X break; X } X if ((node->i_formalinfo[formal]&I_SUB_OK) && !(tx->t_flags&TNOEXPAND)) { X insert.tl_head = insert.tl_tail = NILTOK; X addtok(&insert,newtok(mem,T_LPAREN,NIL)); X cpytoklist(mem,&insert,&enode->e_actuals[formal]); X addtok(&insert,newtok(mem,T_RPAREN,NIL)); X tp->t_next = tx->t_next; /* drop formal node */ X (void) instok(tp, insert.tl_head); X X } else { X tx->t_tok = T_IDENT; X tx->t_id = mkstr(mem,"_",node->i_id,"_",tx->t_id,"_",itoa(ident),0); X tx->t_flags &= ~TNOEXPAND; X } X break; X X case T_ACTUAL: X if ((formal = isformal(node,tx)) < 0) { X error(tx->t_line,"actual-formal mismatch"); X break; X } X insert.tl_head = insert.tl_tail = NILTOK; X addtok(&insert, newtok(mem,T_WS, " ")); X addtok(&insert, newtok(mem,T_EQ, NIL)); X addtok(&insert, newtok(mem,T_WS, " ")); X cpytoklist(mem,&insert,&enode->e_actuals[formal]); X tp->t_next = tx->t_next; /* drop formal node */ X (void) instok(tp, insert.tl_head); X X break; X X case T_LABEL: X tx->t_id = mkstr(mem,"_",node->i_id,"_",tx->t_id,"_",itoa(ident),0); X break; X } X } X X /* update expansion identifier digit */ X ident++; X X return(1); X} X X/* X * begin an inline expansion by gathering actual arguments X */ X Xstruct expand_node * Xdoactuals(mem,prog,node) Xregister int mem; Xstruct token *prog; Xstruct inline_node *node; X{ X register struct token *tl; X int paramnest = 0; X register struct toklist *subparam; X struct expand_node *e; X int sawtok = 0; X X for (tl = prog->t_next; tl != NILTOK; tl = tl->t_next) { X if (tl->t_tok == T_LPAREN) X break; X } X X if (!tl) { /* error */ X error(prog->t_line, "gack!! lost '(' in doactuals()"); X return(NILP(struct expand_node *)); X } X X /* setup an expansion node for this expansion */ X X e = mkenode(mem); X e->e_node = node; X subparam = e->e_actuals; X X /* store the actuals away in the expansion node */ X X for ( ; tl != NILTOK; tl = tl->t_next) { X /* gather the actual parameter list */ X switch(tl->t_tok) { X case T_LPAREN: X if (paramnest++ == 0) { X /* don't add the paren */ X continue; X } X break; X X case T_RPAREN: X if (paramnest == 0) { X error(tl->t_line, "bad parameter list - too many ')'s"); X return(NILP(struct expand_node *)); X } X if (--paramnest == 0) { /* end of parameter list */ X if (sawtok) { X e->e_nactuals++; X } X if (e->e_nactuals != node->i_nformals) { X error(tl->t_line, "wrong number of actuals to inline func %s", node->i_id); X return(NILP(struct expand_node *)); X } X /* replace to argument list with the ARGLIST token */ X prog->t_next = newtok(mem,T_ARGLIST,e->e_node->i_id); X prog->t_next->t_next = tl->t_next; X X return(e); X } X break; X X case T_COMMA: X if (paramnest == 1) { X subparam++; X e->e_nactuals++; X sawtok = 0; X /* don't include the comma */ X continue; X } X break; X } X if (paramnest) { X sawtok = 1; X addtok(subparam,duptok(mem,tl)); X } X } X /* hmm, got an EOF */ X error(prog->t_line, "improper call - EOF during arg gathering"); X return(NILP(struct expand_node *)); X} X Xstruct expand_node * Xmkenode(mem) { X register struct expand_node *e; X register int i; X X e = (struct expand_node *) getmem(mem,1,sizeof(struct expand_node)); X X e->e_node = NILP(struct inline_node *); X e->e_multiple = 0; /* more than one call to this inline */ X for (i = 0; i < NFORMALS; i++) { X e->e_actuals[i].tl_head = NILTOK; X e->e_actuals[i].tl_tail = NILTOK; X } X e->e_nactuals = 0; X return(e); X} X Xsideeffect(tl) Xregister struct toklist *tl; X{ X register struct token *t,*tp; X X tp = NILTOK; X for (t = tl->tl_head; t != NILTOK; t = t->t_next) { X switch(t->t_tok) { X case T_EQ: case T_RS_EQ: case T_LS_EQ: X case T_ADD_EQ: case T_SUB_EQ: case T_MUL_EQ: X case T_DIV_EQ: case T_MOD_EQ: case T_AND_EQ: X case T_XOR_EQ: case T_OR_EQ: X case T_INC: case T_DEC: X return(1); X X case T_LPAREN: X /* function call */ X /* catches "fp(x)", "(*fp)(x)", "fp[foo](x)" */ X if (tp && ( X (tp->t_tok == T_IDENT) || X (tp->t_tok == T_RPAREN) || X (tp->t_tok == T_RSQ) X )) { X return(1); X } X break; X X case T_LBRACE: case T_RBRACE: X error(tp->t_line, "brace in actual argument", 0); X return(1); X X case T_WS: case T_COMMENT: X break; X X default: X if (istype(t)) { /* must be a cast */ X return(1); /* ???? */ X } X tp = t; /* save previous non-ws token */ X break; X } X if (t == tl->tl_tail) { X break; X } X } X return(0); X} X \Rogue\Monster\ else echo "will not over write ./expand.c" fi chmod 444 ./expand.c if [ `wc -c ./expand.c | awk '{printf $1}'` -ne 14621 ] then echo `wc -c ./expand.c | awk '{print "Got " $1 ", Expected " 14621}'` fi if `test ! -s ./rewrite.c` then echo "writing ./rewrite.c" sed 's/^X//' > ./rewrite.c << '\Rogue\Monster\' X/* X * inline code expander - rewrite a procedure into an expression if possible X * X * (c) 1986 - copyright 1986, s. mcgeady, all rights reserved X */ X X/* $Header: rewrite.c,v 1.3 87/05/12 10:53:05 mcg Rel $ */ X X#include "inline.h" X#include "tokens.h" X Xextern struct token *dostmt(); /* see expand.c */ Xextern struct token *doexpr(); /* see expand.c */ X X X/* X * This module takes arbitrary sequences of C statements (assumed to be X * the output of the inline declaration process), and rewrites them, if X * possible, in an expression form, depositing the result in the X * appropriate place (i_tl[SEXPRBODY]) in the inline node structure. X * X * This is done, fundamentally, by replacing semicolons with commas, X * and deleting if's, following if conditional expressions with '?', and X * replacing else's with ':'. Clearly, it is somewhat more complex than X * that, but most of the difficulty merely comes in keeping one's X * parentheses matched. X * X * One subtlety is that local declarations need to be factored out, X * except that if they contain initializations, the initializations need X * to be separated from the declarations and prepended to the expression X * list. This is handled by the routine coalesce(). Coalesce() also X * needs to handle name conflicts caused by local variables declared in X * inner scopes when it is moving these to outer scopes. X * X * If rewrite() finds a statement that it can't rewrite into an expression X * (this class consists entirely of loops (while(), for()), goto's, and X * switch statements, and the break's and continue's that go along with X * these), then it returns -1, and the calling routine (declare.c:dodecl()) X * frees the memory pool associated with it. X */ X X Xstatic int saw_innerret = 0; X X X/* turn a basic block into an expression */ X Xrewrite(node,tl,toplevel) Xregister struct inline_node *node; Xregister struct toklist *tl; Xregister int toplevel; X{ X register struct token *tx, *tt; X register struct token *estart; /* start of current expression */ X register struct token *bstart; /* start of this block */ X register struct token *last = NILTOK; X struct toklist *expr = &node->i_tl[SEXPRBODY]; X register int mem = node->i_exprmem; X struct toklist block; X register int inblock = 0; X register int ntok = 0; X int saw_topret = 0; X int nonempty = 0; X X X /* skip over leading whitespace */ X X tx = skipws(tl->tl_head); X if (tx->t_tok == T_LBRACE) { X inblock++; X } X if (toplevel) { X addtok(expr,last = bstart = estart = newtok(mem,T_WS,"")); X saw_innerret = 0; X } else { X bstart = estart = expr->tl_tail; X } X X for( ; tx && tx != tl->tl_tail; last = tx, tx = tx->t_next) { X if (istype(tx) || isstoreclass(tx)) { X /* local definition block */ X block.tl_head = tx; X tx = block.tl_tail = dostmt(tx,0); X X if (tx->t_tok != T_SEMIC) { X /* weird */ X return(-1); X } X X if (ntok = coalesce(node,&block)) { X nonempty++; X } X } X X X switch(tx->t_tok) { X case T_CONTINUE: X case T_BREAK: X /*FALLTHROUGH*/ X case T_WHILE: X case T_FOR: X case T_SWITCH: X return(-1); X X case T_RBRACE: X if (inblock && tx->t_level == tl->tl_head->t_level) { X goto end; X } X /*FALLTHROUGH*/ X X case T_LBRACE: X break; X X case T_GOTO: X /* if it's not a rewritten return(), it's an error */ X if (tx->t_next->t_next->t_tok == T_RETLAB) { X tx = dostmt(tx,0); X break; X } X return(-1); X X case T_IF: X block.tl_head = skipws(tx->t_next); X block.tl_tail = doexpr(block.tl_head,1); X X /* copy control part */ X cpytoklist(mem,expr,&block); X X addtok(expr,newtok(mem,T_QUEST,NIL)); X addtok(expr,newtok(mem,T_WS," ")); X X block.tl_head = skipws(block.tl_tail->t_next); X block.tl_tail = dostmt(block.tl_head,0); X X if ((ntok = rewrite(node,&block,0)) < 0) { X return(-1); X } X /* if no tokens added - i.e. empty block */ X if (ntok == 0) { X addtok(expr,newtok(mem,T_NUM,"0")); X } X X addtok(expr,newtok(mem,T_COLON,NIL)); X addtok(expr,newtok(mem,T_WS," ")); X X tx = skipws(block.tl_tail->t_next); X if (tx && tx != tl->tl_tail) { X if (tx->t_tok != T_ELSE) { X /* no else - treat rest of block like else */ X block.tl_head = tx; X tx = block.tl_tail = tl->tl_tail; X if ((ntok = rewrite(node,&block,0)) < 0) { X return(-1); X } X } else { X block.tl_head = skipws(tx->t_next); X tx = block.tl_tail = dostmt(block.tl_head,0); X if ((ntok = rewrite(node,&block,0)) < 0) { X return(-1); X } X } X } else { X ntok = 0; X } X /* if no tokens added - i.e. empty block */ X if (ntok == 0) { X addtok(expr,newtok(mem,T_NUM,"0")); X } X ntok = 1; X nonempty++; X /*FALLTHROUGH*/ X X case T_SEMIC: X if (ntok == 0) { X break; X } X /* if there was a preceding expression, insert a comma */ X if (estart && estart->t_tok == T_RPAREN) { X instok(estart,tt = newtok(mem,T_COMMA,NIL)); X estart = tt; X } X X /* wrap some parens around the expression itself */ X instok(estart,newtok(mem,T_LPAREN,NIL)); X addtok(expr,newtok(mem,T_RPAREN,NIL)); X X /* ... and around the whole expression so far */ X if (bstart && bstart != expr->tl_head) { X instok(bstart,newtok(mem,T_LPAREN,NIL)); X addtok(expr,newtok(mem,T_RPAREN,NIL)); X } X estart = expr->tl_tail; X bstart = bstart->t_next; X ntok = 0; X nonempty++; X if (debug >= 9) { X fprintf(stderr,"> "); X prtoklist(expr,0,stderr); X fprintf(stderr,"\n"); X } X break; X X case T_WS: X if (last && last->t_tok != T_WS && X last->t_tok != T_RPAREN && X last->t_tok != T_LPAREN) { X addtok(expr,newtok(mem,T_WS," ")); X } X break; X X case T_RETVAL: X if (toplevel) { X saw_topret++; X for ( ; tx && tx != tl->tl_tail; tx = tx->t_next) { X if (tx->t_tok == T_EQ) { X break; X } X } X break; X } else { X saw_innerret++; X } X /*FALLTHROUGH*/ X default: X addtok(expr,duptok(mem,tx)); X ntok++; X nonempty++; X break; X } X } X end: X if (toplevel) { X if (saw_innerret == 0 && saw_topret == 0) { X /* no returns, must be void */ X return(-1); X } X if (saw_innerret) { X if (expr->tl_head != expr->tl_tail) { X addtok(expr,newtok(mem,T_COMMA,NIL)); X } X addtok(expr,newtok(mem,T_RETVAL,NIL)); X } X instok(expr->tl_head,newtok(mem,T_LPAREN,NIL)); X addtok(expr,newtok(mem,T_RPAREN,NIL)); X fixparens(expr,0,0); X } X if (debug >= 9) { X fprintf(stderr,"% "); X prtoklist(expr,0,stderr); X fprintf(stderr,"\n"); X } X return(nonempty); X} X X Xcoalesce(node,tl) Xregister struct inline_node *node; Xregister struct toklist *tl; X{ X register struct token *tx, *ts, *estart, *bstart; X struct toklist *expr = &node->i_tl[SEXPRBODY]; X struct toklist *exprdecl = &node->i_tl[SEXPRDECL]; X register int mem = node->i_exprmem; X int initializer = 0; X int ntok = 0; X X bstart = expr->tl_tail; X X /* copy up to an '=' or ';' */ X for(tx = tl->tl_head; tx && tx != tl->tl_tail->t_next; tx = tx->t_next) { X if (!initializer) { X if (tx->t_tok == T_IDENT) { X ts = tx; /* save for future reference */ X } X if (tx->t_tok != T_EQ) { X addtok(exprdecl,duptok(mem,tx)); X if (tx->t_tok == T_SEMIC) { X return(ntok); X } X continue; X } X estart = expr->tl_tail; X /* an '=' */ X addtok(expr,duptok(mem,ts)); X addtok(expr,newtok(mem,T_WS," ")); X ntok++; X initializer = 1; X } X /* in initializer */ X X /* look for ',' or ';' terminating initialization */ X if ((tx->t_tok == T_COMMA && tx->t_paren <= ts->t_paren) X || tx->t_tok == T_SEMIC) { X X addtok(exprdecl,duptok(mem,tx)); X X /* if there was a preceeding expr, prepend a comma */ X if (estart && estart->t_tok == T_RPAREN) { X instok(estart,ts = newtok(mem,T_COMMA,NIL)); X estart = ts; X } X X /* wrap some parens around this expr */ X instok(estart,newtok(mem,T_LPAREN,NIL)); X addtok(expr,newtok(mem,T_RPAREN,NIL)); X X /* ... and around the whole expression so far */ X if (bstart && bstart != estart) { X instok(bstart,newtok(mem,T_LPAREN,NIL)); X addtok(expr,newtok(mem,T_RPAREN,NIL)); X } X estart = expr->tl_tail; X bstart = bstart->t_next; X initializer = 0; X if (debug >= 9) { X fprintf(stderr,">> "); X prtoklist(expr,0,stderr); X fprintf(stderr,"\n"); X } X } else { X addtok(expr,duptok(mem,tx)); X } X } X if (debug >= 9) { X fprintf(stderr,">> "); X prtoklist(expr,0,stderr); X fprintf(stderr,"\n"); X } X return(ntok); X} \Rogue\Monster\ else echo "will not over write ./rewrite.c" fi chmod 444 ./rewrite.c if [ `wc -c ./rewrite.c | awk '{printf $1}'` -ne 8260 ] then echo `wc -c ./rewrite.c | awk '{print "Got " $1 ", Expected " 8260}'` fi if `test ! -s ./yylex.c` then echo "writing ./yylex.c" sed 's/^X//' > ./yylex.c << '\Rogue\Monster\' X/* X * inline code expander X * X * (c) 1986,1987 - copyright 1986,1987, s. mcgeady, all rights reserved X */ X X/* X * fast lexer for C X */ X X/* $Header: yylex.c,v 1.9 87/06/24 13:05:47 mcg Rel $ */ X X#include "inline.h" X#include X#include "tokens.h" X X#define MAXLEXBUF 1024 X X/* you can use these macros on any machine with stdio guts like a VAX */ X#if defined(vax) || defined(sun) || defined(gould) || defined(pyr) X X#ifndef lint X#define peekc(p) ((p)->_cnt > 0 ? (int)(*(unsigned char *)(p)->_ptr) \ X :((_filbuf(p) == EOF) ? EOF : \ X ((p)->_cnt++),(int)(*(unsigned char *)(--(p)->_ptr)))) X X X#define ungetc(c, p) ((c) == EOF) ? EOF : ((p)->_cnt++ == 0 ? \ X (((p)->_ptr == (p)->_base) ? \ X *(p)->_ptr = (c) : (*--((p)->_ptr) = (c))) \ X : (((p)->_ptr == (p)->_base) ? (p)->_cnt--,EOF : \ X (*--((p)->_ptr) = (c)))) X X#endif X#else Xstatic int _pc; /* 'peek'ed character holder */ X X#define peekc(p) ((_pc = getc(p),ungetc(_pc,p)),_pc) X#endif X Xextern char *gather(); X X#ifndef NIL X#define NIL (char *) 0 X#endif X X/* 33 keywords */ Xstruct keys { X char *k_str; X int k_val; X} kw[8][10] = { X{ X { NIL, 0, /* */ }, X}, X{ X { "do", T_DO, /* do */ }, X { "if", T_IF, /* if */ }, X { NIL, 0, /* */ }, X}, X{ X { "for", T_FOR, /* for */ }, X { "int", T_INT, /* int */ }, X { NIL, 0, /* */ }, X}, X{ X { "auto", T_AUTO, /* auto */ }, X { "case", T_CASE, /* case */ }, X { "char", T_CHAR, /* char */ }, X { "else", T_ELSE, /* else */ }, X { "enum", T_ENUM, /* enum */ }, X { "goto", T_GOTO, /* goto */ }, X { "long", T_LONG, /* long */ }, X { "void", T_VOID, /* void */ }, X { NIL, 0, /* */ }, X}, X{ X { "break", T_BREAK, /* break */ }, X { "const", T_CONST, /* const */ }, X { "float", T_FLOAT, /* float */ }, X { "short", T_SHORT, /* short */ }, X { "union", T_UNION, /* union */ }, X { "while", T_WHILE, /* while */ }, X { NIL, 0, /* */ }, X}, X{ X { "double", T_DOUBLE, /* double */ }, X { "extern", T_EXTERN, /* extern */ }, X { "inline", T_INLINE, /* inline */ }, X { "return", T_RETURN, /* return */ }, X { "signed", T_SIGNED, /* signed */ }, X { "sizeof", T_SIZEOF, /* sizeof */ }, X { "static", T_STATIC, /* static */ }, X { "struct", T_STRUCT, /* struct */ }, X { "switch", T_SWITCH, /* switch */ }, X { NIL, 0, /* */ }, X}, X{ X { "default", T_DEFAULT, /* default */ }, X { "typedef", T_TYPEDEF, /* typedef */ }, X { NIL, 0, /* */ }, X}, X{ X { "continue", T_CONTINUE, /* continue */ }, X { "register", T_REGISTER, /* register */ }, X { "unsigned", T_UNSIGNED, /* unsigned */ }, X { "volatile", T_VOLATILE, /* volatile */ }, X { NIL, 0, /* */ }, X} X}; X Xiskeyword(s,n) Xregister char *s; Xregister int n; X{ X register struct keys *kwp; X X kwp = &kw[n-1][0]; X X if (n < 2 || n > 8) return(0); X do { X if (s[0] != kwp->k_str[0] || s[1] != kwp->k_str[1]) X continue; X if (strncmp(s,kwp->k_str,n) == 0) X return(kwp->k_val); X } while ((++kwp)->k_str); /* fix thanks to ucbcad!thomas */ X return(0); X} X Xstatic char yytext[MAXLEXBUF]; Xstatic char *yylval; Xint line = 1; X Xyylex(mem) Xregister int mem; X{ X register int c, cc, pc; X register int len; X register char *p; X int base, i; X X base = 10; X yylval = NIL; X X if ((c = getc(stdin)) == EOF) { X return(0); X } X pc = peekc(stdin); X if (pc == '=') { X cc = getc(stdin); X switch(c) { X case '+': { return(T_ADD_EQ); } X case '-': { return(T_SUB_EQ); } X case '*': { return(T_MUL_EQ); } X case '/': { return(T_DIV_EQ); } X case '%': { return(T_MOD_EQ); } X case '&': { return(T_AND_EQ); } X case '^': { return(T_XOR_EQ); } X case '|': { return(T_OR_EQ); } X case '=': { return(T_CEQ); } X case '!': { return(T_NE); } X default: X ungetc(cc,stdin); X /* pc is correct */ X break; X } X } else if (pc == c) { X cc = getc(stdin); X pc = peekc(stdin); X switch(c) { X case '+': { return(T_INC); } X case '-': { return(T_DEC); } X case '&': { return(T_CAND); } X case '|': { return(T_COR); } X case '>': /* also >>, >>= */ X if (pc == '=') { X getc(stdin); X return(T_RS_EQ); X } X return(T_RS); X X case '<': /* also <<, <<= */ X if (pc == '=') { X getc(stdin); X return(T_LS_EQ); X } X return(T_LS); X X default: X ungetc(cc,stdin); X pc = cc; X break; X } X } X switch(c) { X case '#': /* CPP line */ X yylval = gather(mem,T_CPP,"#"); X return(T_CPP); X X X case '-': /* also --, -=, -> */ X if (pc == '>') { getc(stdin); return(T_PTR); } X return(T_MINUS); X X X case '/': /* also /=, comment */ X if (pc == '*') { /* comment */ X getc(stdin); X yylval = gather(mem,T_COMMENT,"/*"); X return(T_COMMENT); X } X return(T_DIV); X X case '<': return(T_LT); /* also <<, <<= */ X case '>': return(T_GT); /* also >>, >>= */ X case '+': return(T_PLUS); /* also ++, += */ X case '*': return(T_STAR); /* also *= */ X case '%': return(T_MOD); /* also %= */ X case '&': return(T_AMPER); /* also &&, &= */ X case '^': return(T_XOR); /* also ^= */ X case '|': return(T_OR); /* also ||, |= */ X case '=': return(T_EQ); /* also == */ X case '!': return(T_NOT); /* also != */ X case '.': /* also ... */ X if (pc == '.') { X cc = getc(stdin); X if (peekc(stdin) == '.') { X getc(stdin); X return(T_ELLIPSES); X } X ungetc(cc,stdin); X } X return(T_DOT); X X case ';': return(T_SEMIC); X case '{': return(T_LBRACE); X case '}': return(T_RBRACE); X case ',': return(T_COMMA); X case ':': return(T_COLON); X case '(': return(T_LPAREN); X case ')': return(T_RPAREN); X case '[': return(T_LSQ); X case ']': return(T_RSQ); X case '~': return(T_TILDE); X case '?': return(T_QUEST); X X case '\'': X yylval = gather(mem,T_CHARCONST,"'"); X return(T_CHARCONST); X X case '"': X yylval = gather(mem,T_STR,"\""); X return(T_STR); X X case ' ': case '\t': case '\v': case '\n': case '\f': X p = yytext; X do { X *p++ = c; X if (c == '\n') line++; X c = peekc(stdin); X } while ((c == ' ' || c == '\t' || c == '\v' || c == '\n' || X c == '\f') && (p < &yytext[MAXLEXBUF]) && X ((c = getc(stdin)) != EOF)); X *p = '\0'; X yylval = yytext; X return(T_WS); X X case '0': X p = yytext; X *p++ = c; X if (tolower(pc) == 'x') { X base = 16; X *p++ = getc(stdin); X c = getc(stdin); X } else if (tolower(pc) == 'f') { X#ifdef notdef X /* 0finf or 0fnan(xxx) */ X *p++ = getc(stdin); X base = -1; /* FLOAT */ X c = getc(stdin); X#endif X } else if (isdigit(pc)) { X base = 8; X c = getc(stdin); X } else { X p = yytext; X } X /*FALLTHROUGH*/ X X case '1': case '2': case '3': case '4': case '5': X case '6': case '7': case '8': case '9': X X if (base == 10) { X p = yytext; X } X do { X if (!isdigit(c) && X !((c == '.') || (tolower(c) == 'e') || X (c == '+') || (c == '-'))) { X ungetc(c,stdin); X break; X } X *p++ = c; X } while((c = getc(stdin)) != EOF); X *p = '\0'; X yylval = yytext; X return(T_NUM); X X case EOF: X return(0); X X default: /* an identifier or keyword */ X if ((c < ' ') || (c > '~') || !isalpha(c)) { X error(line,"illegal character"); X yytext[0] = c; yytext[1] = '\0'; X yylval = yytext; X return(T_WS); X } X /*FALLTHROUGH*/ X case '_': X yytext[0] = c; X p = &yytext[1]; X len = 1; X while((c = getc(stdin)) != EOF) { X if (!isalpha(c) && !isdigit(c) && c != '$' && c != '_') { X ungetc(c,stdin); X break; X } X *p++ = c; X len++; X } X *p = '\0'; X if (i = iskeyword(yytext,len)) { X return(i); X } else { X yylval = yytext; X return(T_IDENT); X } X } X /*NOTREACHED*/ X} X X/* X */ X Xchar * Xgather(mem,type,init) Xregister int mem; Xint type; Xchar *init; X{ X char buf[MAXLEXBUF]; X register int c; X register char *tbuf; X register int tbufsize = 0; X register char *bb = buf; X register char *p = bb; X register char *ebuf = &buf[MAXLEXBUF-1]; X X X strcpy(buf,init); X p = buf + strlen(init); X while ((c = getc(stdin)) != EOF) { X *p = c; X if (*p == 0) X break; X X if (*p == '\n') line++; X X switch (type) { X case T_COMMENT: X if (*p == '*' && peekc(stdin) == '/') { X *++p = getc(stdin); X goto end; X } X break; X case T_CPP: X if (*p == '\\') { X *++p = getc(stdin); X } else if (*p == '\n') { X /* ungetc(*p,stdin); */ X goto end; X } X break; X case T_STR: X if (*p == '\\') { X *++p = getc(stdin); X } else if (*p == '\n') { X /* error */ X } else if (*p == '"') { X goto end; X } X break; X X case T_CHARCONST: X if (*p == '\\') { X *++p = getc(stdin); X } else if (*p == '\n') { X /* error */ X } else if (*p == '\'') { X goto end; X } X break; X } X /* leave two slots open at end */ X if (++p >= ebuf-1) { X *p = '\0'; X if (tbufsize == 0) { X tbufsize = 1024; X } X if (mem < 0) { X tbuf = (char *) malloc((unsigned) (tbufsize *= 2)); X } else { X tbuf = getmem(mem, 0, (unsigned) (tbufsize *= 2)); X } X strcpy(tbuf, bb); X p = tbuf + (p - bb); X if (bb != buf) { X free(bb); X } X bb = tbuf; X ebuf = bb + tbufsize; X } X } X end: X *++p = '\0'; X p++; X if (tbufsize == 0) { X if (mem < 0) { X tbuf = (char *) malloc((unsigned) (p-bb)); X } else { X tbuf = getmem(mem, 0, (unsigned) (p-bb)); X } X strcpy(tbuf, bb); X bb = tbuf; X } X return(bb); X} X X X#ifndef TEST X Xcheck_type(tok) Xregister struct token *tok; X{ X register int i; X register char **p; X X for (i = 0; (i < NSCOPE) && (typeid[i] != NILP(struct typelist *));i++) { X for (p = typeid[i]->type_id; *p != NIL; p++) { X if (strcmp(tok->t_id,*p) == 0) { X tok->t_tok = T_TYPE_ID; X return; X } X } X } X} X Xstruct token * Xgettok(mem) Xregister int mem; X{ X register int t; X struct token *tok; X static int bracelev = 0; X static int parenlev = 0; X X if ((t = yylex(mem)) == 0) X return((struct token *) 0); X tok = newtok(mem, t, yylval); X tok->t_line = line; X switch(t) { X case T_COMMENT: X case T_CPP: X tok->t_tok = T_WS; X /*FALLTHROUGH*/ X case T_STR: X /* free(yylval); */ X break; X X case T_LBRACE: X tok->t_level = bracelev++; X tok->t_paren = parenlev; X pushscope(bracelev); X break; X case T_LPAREN: X tok->t_paren = parenlev++; X tok->t_level = bracelev; X break; X case T_RPAREN: X tok->t_level = bracelev; X tok->t_paren = --parenlev; X break; X case T_RBRACE: X popscope(bracelev); X tok->t_level = --bracelev; X tok->t_paren = parenlev; X break; X X default: X tok->t_level = bracelev; X tok->t_paren = parenlev; X break; X } X if (t == T_IDENT) { X check_type(tok); X } X return(tok); X} X#endif X X#ifdef TEST Xmain() { X int tok; X extern char *tokens[]; X X while(tok = yylex(-1)) { X switch (tok) { X case T_COMMENT: X case T_STR: X case T_CPP: X free(yylval); X X case T_IDENT: X case T_WS: X case T_NUM: X case T_CHARCONST: X case T_TYPE_ID: X fputs(yylval,stdout); X break; X case T_ACTUAL: X fputs("",stdout); X break; X case T_RETVAL: X fputs("",stdout); X break; X case T_ARGLIST: X fprintf(stdout,"%s(ARGLIST)", yylval); X break; X case T_RETLAB: X fputs("",stdout); X break; X case T_FORMAL: X fprintf(stdout,"",yylval); X break; X default: X if (tok <= T_INLINE) X fputs(tokens[tok],stdout); X else X fputs("???",stdout); X X break; X } X } X} X#endif \Rogue\Monster\ else echo "will not over write ./yylex.c" fi chmod 444 ./yylex.c if [ `wc -c ./yylex.c | awk '{printf $1}'` -ne 10795 ] then echo `wc -c ./yylex.c | awk '{print "Got " $1 ", Expected " 10795}'` fi if `test ! -s ./tokens.c` then echo "writing ./tokens.c" sed 's/^X//' > ./tokens.c << '\Rogue\Monster\' X/* X * inline code expander X * X * (c) 1986 - copyright 1986, s. mcgeady, all rights reserved X */ X X/* $Header: tokens.c,v 1.3 87/04/27 18:16:52 mcg Rel $ */ X X Xchar *tokens[] = { X "", X "auto", X "break", X "case", X "char", X "const", X "continue", X "default", X "do", X "double", X "else", X "enum", X "extern", X "float", X "for", X "goto", X "if", X "int", X "long", X "register", X "return", X "short", X "signed", X "sizeof", X "static", X "struct", X "switch", X "typedef", X "union", X "unsigned", X "void", X "volatile", X "while", X "...", X "=", X ",", X "{", X "}", X ";", X ">>=", X "<<=", X "+=", X "-=", X "*=", X "/=", X "%=", X "&=", X "^=", X "|=", X ">>", X "<<", X "++", X "--", X "->", X "&&", X "||", X "<=", X ">=", X "==", X "!=", X ":", X "", X "(", X ")", X "[", X "]", X ".", X "&", X "!", X "~", X "-", X "+", X "*", X "/", X "%", X "<", X ">", X "^", X "|", X "?", X "inline", X}; \Rogue\Monster\ else echo "will not over write ./tokens.c" fi chmod 444 ./tokens.c if [ `wc -c ./tokens.c | awk '{printf $1}'` -ne 828 ] then echo `wc -c ./tokens.c | awk '{print "Got " $1 ", Expected " 828}'` fi if `test ! -s ./utils.c` then echo "writing ./utils.c" sed 's/^X//' > ./utils.c << '\Rogue\Monster\' X/* X * C inline code substituter - 11/24/86 - mcg X * X * utility routines X * X * (c) 1986 - copyright 1986, s. mcgeady, all rights reserved X */ X X/* $Header: utils.c,v 1.13 87/06/24 13:11:40 mcg Rel $ */ X X X#include X#include "tokens.h" X#include "inline.h" X Xstruct token * Xskipws(t) Xregister struct token *t; X{ X while (t && t->t_next && (t->t_tok == T_WS)) { X t = t->t_next; X } X return(t); X} X X/* X * add a token to a list X */ X Xaddtok(list, tok) Xregister struct toklist *list; Xregister struct token *tok; X{ X if (list->tl_head == NILTOK) { X list->tl_head = tok; X } X if (list->tl_tail != NILTOK) { X list->tl_tail->t_next = tok; X } X list->tl_tail = tok; X} X Xstruct token * Xinstok(tok,ntok) Xregister struct token *tok; Xregister struct token *ntok; X{ X register struct token *tl; X X if (ntok == NILTOK) { X return(tok); X } X /* find end of new token list */ X for(tl = ntok; tl->t_next != NILTOK; tl = tl->t_next) X ; X X if (tok->t_next == NILTOK) { X tok->t_next = ntok; X } else { X tl->t_next = tok->t_next; X tok->t_next = ntok; X } X return(tl); /* return end of new list */ X} X X/* X * get a new token X */ X Xstruct token * Xnewtok(mem,val, id) Xint val; Xchar *id; X{ X register struct token *t; X register unsigned int len,l; X X len = sizeof(struct token); X if (id) { X len += (l = strlen(id) + 1); X } X X t = (struct token *) getmem(mem,1,len); X X if (id) { X t->t_id = ((char *) t) + sizeof(struct token); X (void) strncpy(t->t_id,id,l); X } else { X t->t_id = NIL; X } X X t->t_tok = val; X t->t_flags = 0; X t->t_num = 0; X t->t_level = 0; X t->t_paren = 0; X t->t_line = 0; X t->t_next = NILTOK; X return(t); X} X Xstruct token * Xduptok(mem,tok) Xregister struct token *tok; X{ X register struct token *t; X X t = newtok(mem,tok->t_tok, tok->t_id); X t->t_flags = tok->t_flags; X t->t_num = tok->t_num; X t->t_level = tok->t_level; X t->t_paren = tok->t_paren; X t->t_line = 0; X t->t_next = NILTOK; /* next token in this list */ X return(t); X} X Xcpytoklist(mem, olist, ilist) Xint mem; Xregister struct toklist *olist; Xregister struct toklist *ilist; X{ X register struct token *tl; X X for(tl = ilist->tl_head; tl != NILTOK; tl = tl->t_next) { X addtok(olist,duptok(mem,tl)); X if (tl == ilist->tl_tail) X break; X } X} X Xfixparens(tl,plev,blev) Xregister struct toklist *tl; Xregister int plev, blev; X{ X register struct token *tp; X register int paren = plev; X register int brace = blev; X X for (tp = tl->tl_head; tp && tp != tl->tl_tail->t_next; tp = tp->t_next) { X tp->t_paren = paren; X tp->t_level = brace; X switch(tp->t_tok) { X case T_LPAREN: X paren++; X break; X case T_LBRACE: X brace++; X break; X case T_RBRACE: X tp->t_level = --brace; X break; X case T_RPAREN: X tp->t_paren = --paren; X break; X default: X break; X } X } X} X X#include "varargs.h" X X/*VARARGS1*/ Xchar * Xmkstr(mem,va_alist) Xint mem; Xva_dcl X{ X va_list s; X register int i; X register char *rs,*ts; X X va_start(s); X i = 0; X while(1) { X rs = va_arg(s, char *); X if (rs == NIL) { X break; X } X i += strlen(rs); X } X va_end(s); X rs = (char *) getmem(mem,0,(unsigned) i+1); X *rs = '\0'; X va_start(s); X while(1) { X ts = va_arg(s, char *); X if (ts == NIL) { X break; X } X (void) strcat(rs,ts); X } X va_end(s); X return(rs); X} X X X#ifdef vax X/*VARARGS*/ Xerror(lin,fmt,args) Xint lin; Xchar *fmt; Xchar *args; X{ X if (infile) { X fprintf(stderr,"\"%s\", line %d: ",infile,lin); X } else { X fprintf(stderr,"%s: line %d: ",myname,lin); X } X _doprnt(fmt,&args,stderr); X fputs("\n",stderr); X errs++; X} X X X/*VARARGS*/ Xwarn(lin,fmt,args) Xint lin; Xchar *fmt; Xchar *args; X{ X if (nowarn) return; X X if (infile) { X fprintf(stderr,"\"%s\", line %d: warning: ",infile,lin); X } else { X fprintf(stderr,"%s: line %d: warning: ",myname,lin); X } X _doprnt(fmt,&args,stderr); X fputs("\n",stderr); X} X#else X/*VARARGS*/ Xerror(line,fmt,va_alist) Xint line; Xchar *fmt; Xva_dcl X{ X va_list s; X va_list *p; X register int i; X register char *rs,*ts; X X va_start(s); X p = &s; X if (infile) { X fprintf(stderr,"\"%s\", line %d: ",infile,line); X } else { X fprintf(stderr,"%s: line %d: ",myname,line); X } X _doprnt(fmt,p,stderr); X fputs("\n",stderr); X va_end(s); X errs++; X} X X/*VARARGS*/ Xwarn(line,fmt,va_alist) Xint line; Xchar *fmt; Xva_dcl X{ X va_list s; X va_list *p; X register int i; X register char *rs,*ts; X X if (nowarn) return; X X va_start(s); X p = &s; X if (infile) { X fprintf(stderr,"%s: \"%s\", line %d: ",infile,line); X } else { X fprintf(stderr,"%s: line %d: ",myname,line); X } X _doprnt(fmt,p,stderr); X fputs("\n",stderr); X} X X#endif X X X/* extremely limited - positive numbers only */ X/* useful only for appending positive digits to strings */ X Xchar * Xitoa(n) X{ X static char buf[20]; X register char *p = &buf[18]; X X buf[19] = '\0'; X do { X *p-- = '0' + (n%10); X n /= 10; X } while(n && (p >= buf)); X return(++p); X} X X/* X * create a (non-filled-in) inline expansion node X */ X Xstruct inline_node * Xmknode(mem) Xint mem; X{ X register struct inline_node *node; X register int i; X X node = (struct inline_node *) getmem(mem,1,sizeof (struct inline_node)); X node->i_id = NIL; X for (i=0; i < NSTATES; i++) { X node->i_tl[i].tl_head = NILTOK; X node->i_tl[i].tl_tail = NILTOK; X } X X node->i_text.tl_head = NILTOK; X node->i_text.tl_tail = NILTOK; X X for(i=0; i < NFORMALS; i++) { X node->i_formals[i] = NIL; X node->i_formalinfo[i] = 0; X } X node->i_nformals = 0; X X node->i_mem = mem; X node->i_line = 0; X node->i_flags = 0; X node->i_storclass = 0; X node->i_nseen = 0; X node->i_nexpand = 0; X X node->i_exprmem = -1; X X return(node); X} X Xprtoklist(tl,doauto,s) Xregister struct toklist *tl; Xint doauto; XFILE *s; X{ X register struct token *th = tl->tl_head; X X while (th != NILTOK) { X prtok(th,doauto,s); X th = th->t_next; X } X} X Xprtok(tok,doauto,s) Xstruct token *tok; Xint doauto; XFILE *s; X{ X extern char *tokens[]; X X switch (tok->t_tok) { X case T_IDENT: X if (doauto && tok->t_flags&TAUTO) { X if (tok->t_flags&TINLINE) { X if (tok->t_num > 1) { X fprintf(s,"_loc_%s_%d",tok->t_id,tok->t_num); X break; X } X } else { X fprintf(s,"_auto_%s",tok->t_id); X break; X } X } X /*FALLTHROUGH*/ X case T_LABEL: X case T_WS: X case T_NUM: X case T_CHARCONST: X case T_CPP: X case T_STR: X case T_TYPE_ID: X case T_STRTAG: X fputs(tok->t_id,s); X break; X case T_ACTUAL: X fputs("",s); X break; X case T_RETVAL: X fputs("",s); X break; X case T_ARGLIST: X fprintf(s,"%s(ARGLIST)", tok->t_id); X break; X case T_RETLAB: X fputs("",s); X break; X case T_FORMAL: X fprintf(s,"",tok->t_id); X break; X default: X if (tok->t_tok <= T_INLINE) X fputs(tokens[tok->t_tok],s); X else X fputs("???",s); X X break; X } X} X X Xdebugnode(node) Xregister struct inline_node *node; X{ X register int i; X X fprintf(stderr,"> inline '%s' @ line %d\n",node->i_id,node->i_line); X fprintf(stderr,"> formals (%d):\n", node->i_nformals); X for (i = 0; i < node->i_nformals; i++) { X fprintf(stderr,"> '%s'\n", node->i_formals[i]); X } X fprintf(stderr,"> function type:\n"); X prtoklist(&node->i_tl[SDECL],0,stderr); X fprintf(stderr,"\n"); X fprintf(stderr,"> declarations:\n"); X prtoklist(&node->i_tl[SDECLBODY],0,stderr); X fprintf(stderr,"> body:\n"); X prtoklist(&node->i_tl[SBODY],1,stderr); X fprintf(stderr,"\n"); X if (node->i_flags&I_EXPR) { X fprintf(stderr,"> as expression:\n"); X fprintf(stderr,"> declarations:\n"); X prtoklist(&node->i_tl[SEXPRDECL],1,stderr); X fprintf(stderr,"\n> body:\n"); X prtoklist(&node->i_tl[SEXPRBODY],1,stderr); X fprintf(stderr,"\n"); X } else { X fprintf(stderr, "(not an expression)\n"); X } X} X X X Xistype(tok) Xstruct token *tok; X{ X switch(tok->t_tok) { X case T_CHAR: X case T_INT: X case T_SHORT: X case T_LONG: X case T_FLOAT: X case T_DOUBLE: X case T_UNSIGNED: X case T_SIGNED: X case T_VOID: X case T_ENUM: X case T_STRUCT: X case T_UNION: X case T_TYPE_ID: X return(1); X X default: X return(0); X } X} X Xisstoreclass(tok) Xstruct token *tok; X{ X switch(tok->t_tok) { X case T_REGISTER: X case T_EXTERN: X case T_STATIC: X case T_AUTO: X case T_CONST: X case T_VOLATILE: X return(1); X default: X return(0); X } X} X Xiscontrol(tok) Xstruct token *tok; X{ X switch(tok->t_tok) { X case T_IF: X case T_WHILE: X case T_FOR: X case T_SWITCH: X return(1); X default: X return(0); X } X} X X/* X * returns true if the tokens following the argument conform to X * the pattern of a simple call: X * identifier, optional whitespace, leftparen X * e.g.: X * foo /* comment (); X * X * thus X * (foo)(); (*foo)(); etc X * are not calls X */ X Xiscall(tok) Xregister struct token *tok; X{ X if (tok == NILTOK) { X return(0); X } X if ((tok->t_tok != T_IDENT) || (tok->t_flags&TNOEXPAND)) { X return(0); X } X /* skip over any leading whitespace */ X for(tok = tok->t_next; tok != NILTOK; tok = tok->t_next) { X if (tok->t_tok != T_WS) { X break; X } X } X if (tok && (tok->t_tok == T_LPAREN)) { X return(1); X } X return(0); X} X \Rogue\Monster\ else echo "will not over write ./utils.c" fi chmod 444 ./utils.c if [ `wc -c ./utils.c | awk '{printf $1}'` -ne 8665 ] then echo `wc -c ./utils.c | awk '{print "Got " $1 ", Expected " 8665}'` fi if `test ! -s ./mem.c` then echo "writing ./mem.c" sed 's/^X//' > ./mem.c << '\Rogue\Monster\' X/* X * pool-based memory allocation scheme X * X * (c) 1986 - copyright 1986, s. mcgeady, all rights reserved X * X * this is good for low-overhead memory allocation of many small units, X * where all the memory is freed at once at the end X */ X X/* $Header: mem.c,v 1.6 87/04/27 18:16:43 mcg Rel $ */ X X X#define STATS 1 X#define FREELIST 1 /* maintain freelist of hunks and bufs, cutting down */ X /* on calls to malloc() and free() */ X#define NFREEBUFS 10 /* number of free buffers to maintain */ X X/* #define TEST 1 */ X/* #define ZEROMEM(p,n,a) bzero(p,n) /* define to zero memory on allocation */ X#define ZEROMEM(p,n,a) X Xextern char *malloc(); Xextern char *sbrk(); Xextern char *getmem(); X X#define NIL 0 X#define POOLSIZE 4096 X Xstruct memhunk { X char *m_base; /* pointer to memory buffer */ X char *m_free; /* pointer to free mem */ X unsigned m_size; /* size of this buffer */ X unsigned m_nleft; /* number of bytes left */ X struct memhunk *m_next; /* next pool in this cache */ X}; X X/* X * each pool consists of a series of 'hunks' of memory, organized X * as a linked list. the pool 'handle' is really a pointer to the X * poolhead for the list X */ X Xstruct poolhead { X struct memhunk *pl_pool; X struct poolhead *pl_next; X}; X Xstatic struct poolhead head = {0}; X X#ifdef STATS Xstatic int nrequest = 0; Xstatic int nloops = 0; Xstatic int maxloops = 0; Xstatic int minloops = 0; Xstatic int nfree = 0; Xstatic int nmalloc = 0; Xstatic int maxsize = 0; Xstatic int npools = 0; Xstatic int maxpools = 0; Xstatic int nhunks = 0; Xstatic int maxhunks = 0; Xstatic int firsttime = 0; Xstatic unsigned totsize = 0; Xstatic char *lowwater = 0; Xstatic char *hiwater = 0; Xstatic int nphdr = 0; X Xstatic Xchar * XMALLOC(n) Xunsigned int n; X{ X register char *p; X X nmalloc++; X p = malloc(n); X if (p > hiwater) { X hiwater = p; X } X return(p); X} X X#define FREE(x) (nfree++,free((unsigned)x)) X X#else X X#define MALLOC malloc X#define FREE free X X#endif X X#ifndef FREELIST X X#define getpool() ((struct poolhead *) MALLOC(sizeof(struct poolhead))) X#define gethunk() ((struct memhunk *) MALLOC(sizeof(struct memhunk))) X#define getbuf(s) ((char *) MALLOC(*(s))) X#define freebuf(p,s) (FREE(p)) X#define freehunk(p) (FREE(p)) X X#else X#define getpool() ((struct poolhead *) MALLOC(sizeof(struct poolhead))) X Xstruct freebufs { X int fb_size; X char *fb_buf; X}; X Xstatic struct memhunk *hunks = {0}; Xstatic struct freebufs bufs[NFREEBUFS] = {0}; X X Xstruct memhunk * Xgethunk() { X register struct memhunk *p = hunks; X X if (p != NIL) { X hunks = p->m_next; X return(p); X } X return((struct memhunk *) MALLOC(sizeof(struct memhunk))); X} X X#define freehunk(p) ((p)->m_next = hunks, hunks = (p)) X Xchar * Xgetbuf(size) Xunsigned int *size; X{ X register int i; X register struct freebufs *p; X X if (*size == 0) return(NIL); X X for (i = 0, p = bufs; i < NFREEBUFS; i++, p++) { X if (p->fb_size >= *size) { X *size = p->fb_size; X p->fb_size = 0; X return(p->fb_buf); X } X } X return((char *) MALLOC(*size)); X} X Xvoid Xfreebuf(p,size) Xchar *p; Xunsigned size; X{ X register int i; X register struct freebufs *q; X X for (i = 0, q = bufs; i < NFREEBUFS; i++, q++) { X if (q->fb_size == 0) { X q->fb_size = size; X q->fb_buf = p; X return; X } X } X FREE(p); X} X X#endif X X X/* X * open a new memory pool, returning a handle to it X */ X Xopenpool() { X register struct poolhead *pl, *lastpl; X register int pool = 0; X X#ifdef STATS X if (firsttime == 0) { X firsttime++; X lowwater = sbrk(0); X } X npools++; X if (npools > maxpools) { X maxpools = npools; X } X#endif X /* this finds the last pool header */ X for (pl = &head; X ((pl != NIL) && (pl->pl_pool != NIL)); X lastpl = pl, pl = pl->pl_next) X { X pool++; X } X if (pl == NIL) { X /* add a new pool header on the end */ X pl = lastpl->pl_next = getpool(); X pl->pl_pool = gethunk(); X pl->pl_next = NIL; X pl->pl_pool->m_base = NIL; X pl->pl_pool->m_free = NIL; X pl->pl_pool->m_size = 0; X pl->pl_pool->m_nleft = 0; X pl->pl_pool->m_next = NIL; X#ifdef STATS X nhunks++; X nphdr++; X#endif X } X return(pool); X} X X X X/* X * close a memory pool, freeing all memory associated with it X */ X Xclosepool(pool) Xregister int pool; X{ X register struct poolhead *pl; X register struct memhunk *p, *q; X X if (pool < 0) { X return(NIL); X } X for(pl = &head; pl != NIL; pl = pl->pl_next) { X if (pool == 0) { X break; X } X pool--; X } X if (pool != 0) { /* invalid pool */ X return(0); X } X X for(p = pl->pl_pool; p != NIL; p = q) { X q = p->m_next; X if (p->m_base) { X freebuf(p->m_base,p->m_size); X } X freehunk(p); X#ifdef STATS X nhunks--; X#endif X } X pl->pl_pool = NIL; X#ifdef STATS X npools--; X#endif X return(1); X} X X X/* X * get 'size' bytes, from 'pool' X * if 'align' is 1, align the result on a (sizeof long) boundary X */ X Xchar * Xgetmem(pool,align,size) Xint pool; Xunsigned align; Xunsigned size; X{ X register struct poolhead *pl; X register struct memhunk *p,*lastp; X register char *r; X register int psize; X register int lnloops; X X#ifdef STATS X nrequest++; X totsize += size; X if (size > maxsize) { X maxsize = size; X } X lnloops = 0; X#endif X X if (pool < 0) { X return(NIL); X } X for(pl = &head; pl != NIL; pl = pl->pl_next) { X if (pool == 0) { X break; X } X pool--; X } X if (pool != 0) { /* invalid pool */ X return(NIL); X } X X for(p = pl->pl_pool,lastp = NIL; p != NIL; lastp = p, p = p->m_next) { X#ifdef STATS X nloops++; X lnloops++; X#endif X if (!p->m_nleft) X continue; X if (align && (psize = (((int) p->m_free) % sizeof(long)))) { X psize = sizeof(long) - psize; X if (p->m_nleft >= size+psize) { X p->m_nleft -= psize; X p->m_free += psize; X } else { X continue; X } X } X if (p->m_nleft && (p->m_nleft >= size)) { X r = p->m_free; X p->m_nleft -= size; X p->m_free += size; X ZEROMEM(r,size,align); X return(r); X } X } X if (size < POOLSIZE) { X psize = POOLSIZE; X } else { X psize = size; X } X X#ifdef STATS X nhunks++; X if (nhunks > maxhunks) { X maxhunks = nhunks; X } X if (lnloops > maxloops) { X maxloops = lnloops; X } X if ((minloops == 0) || (lnloops < minloops)) { X minloops = lnloops; X } X#endif X X /* don't need to worry about alignment here, malloc always aligned */ X p = gethunk(); X X /* if lastp == NIL, then this is first allocation for this pool */ X if (lastp != NIL) { X lastp->m_next = p; X } else { X pl->pl_pool = p; X } X p->m_nleft = p->m_size = psize; X p->m_free = p->m_base = getbuf(&p->m_nleft); X p->m_next = NIL; X X r = p->m_free; X p->m_nleft -= size; X p->m_free += size; X ZEROMEM(r,size,align); X return(r); X} X X#ifdef notdef X/* should improve this */ X Xbzero(p,s,a) Xregister char *p; Xregister int s; Xregister int a; X{ X while(s--) { X *p++ = 0; X } X} X#endif X X#ifdef STATS X#include X Xmemstats() { X fprintf(stderr,"%d hunks (max %d) in %d pools (max %d), (%d hdrs), largest is %d\n", X nhunks,maxhunks,npools,maxpools,nphdr,maxsize); X fprintf(stderr,"%d loops in getmem (avg), %d min, %d max\n", X nloops/nrequest, minloops, maxloops); X fprintf(stderr, "pools between 0x%x and 0x%x, heap max %d.%d Kb\n", X lowwater, hiwater, (hiwater-lowwater)/1024, (hiwater-lowwater)%1024); X fprintf(stderr, "%d requests, %d mallocs, %d frees\n", nrequest,nmalloc,nfree); X fprintf(stderr, "%d total bytes, average request %d.%d\n", totsize, X totsize/nrequest, totsize%nrequest); X} X#endif X X#ifdef TEST X/* X * testing code X */ X X#include X X#define skipws(p) while((*p == ' ') || (*p == '\t')) p++ X#define skiptows(p) while((*p != ' ') && (*p != '\t') && (*p != '\0')) p++ X Xmain() { X register int i,n,x; X char buf[20]; X char c; X register char *p,*q; X X printf("memory allocator test routine\n"); X while(printf("> "),gets(buf) != NIL) { X p = buf; X skipws(p); X c = *p++; X skipws(p); X switch(c) { X case 'd': X dump(); X break; X case 's': X#ifdef STATS X memstats(); X#else X printf("no statistics available\n"); X#endif X break; X case 'g': /* get mem (nbytes) (align) (poolnum) */ X n = atoi(p); X skiptows(p); skipws(p); X i = atoi(p); X skiptows(p); skipws(p); X x = atoi(p); X q = getmem(x, i, n); X printf("got %d bytes @ 0x%x %sfrom pool %d\n", n, q, X i ? "(aligned) ": "", x); X break; X case 'o': /* open a new pool */ X n = openpool(); X printf("pool %d opened\n", n); X break; X case 'c': /* close pool */ X printf("closing pool %d\n", n = atoi(p)); X x = closepool(n); X if (!x) { X printf("error closing pool %d\n", x); X } X break; X case 'q': X printf("exiting ...\n"); X return; X default: X printf("unrecognized command '%c'\n", c); X break; X X } X } X} X Xdump() { X register struct poolhead *pl; X register struct memhunk *p; X register int i,j; X X for (i=0, pl = &head; pl != NIL; i++,pl = pl->pl_next) { X printf("\tpool %d (@ 0x%x):\n", i, pl); X for(j=0, p = pl->pl_pool; p != NIL; j++,p = p->m_next) { X printf("\t\tmemhunk %d (@ 0x%x)", j, p); X printf("buf %d bytes @ 0x%x (%d left @ 0x%x)\n", X p->m_size, p->m_base, p->m_nleft, p->m_free); X } X } X} X Xstatic Xatoi(p) Xregister char *p; X{ X register int n = 0; X X while ((*p >= '0') && (*p <= '9')) { X n = (n*10) + (*p - '0'); X p++; X } X return(n); X} X X#endif /* TEST */ \Rogue\Monster\ else echo "will not over write ./mem.c" fi chmod 444 ./mem.c if [ `wc -c ./mem.c | awk '{printf $1}'` -ne 8948 ] then echo `wc -c ./mem.c | awk '{print "Got " $1 ", Expected " 8948}'` fi echo "Finished archive 2 of 3" # if you want to concatenate archives, remove anything after this line exit