koreth@panarthea.ebay.sun.com (Steven Grimm) (10/25/89)
Submitted-by: ncar.ucar.edu!dunike!onecom!wldrdg!hans (Johann Ruegg) Posting-number: Volume 2, Issue 96 Archive-name: sozobon1.2/part05 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 5 (of 9)." # Contents: hcc/FUN.C hcc/G2.C hcc/GEN.C # Wrapped by koreth@panarthea on Tue Oct 24 18:40:46 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'hcc/FUN.C' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'hcc/FUN.C'\" else echo shar: Extracting \"'hcc/FUN.C'\" \(11588 characters\) sed "s/^X//" >'hcc/FUN.C' <<'END_OF_FILE' X/* Copyright (c) 1988 by Sozobon, Limited. Author: Johann Ruegg X * X * Permission is granted to anyone to use this software for any purpose X * on any computer system, and to redistribute it freely, with the X * following restrictions: X * 1) No charge may be made other than reasonable charges for reproduction. X * 2) Modified versions must be clearly marked as such. X * 3) The authors are not responsible for any harmful consequences X * of using this software, even if they result from defects in it. X * X * fun.c X * X * Handle function entry, exit, etc. X * Parse statements. X * Also, general syntax error recovery strategy. X */ X X#include <stdio.h> X#include "param.h" X#include "tok.h" X#include "nodes.h" X#include "cookie.h" X X#if MMCC Xoverlay "pass2" X#endif X Xextern NODE *cur; X Xint level; XNODE *blktab; XNODE *labels; X Xstruct swittbl { X NODEP caselist; X int deflbl; X} *curswit; X Xint curbrk, curcont; Xint funtopl, funbotl, funretl, funstrl; XNODEP funtyp; Xint maxregs; Xlong maxlocs; X Xint skipon; X XNODEP glb_decls(); X Xextern int oflags[]; X#define debugl oflags['l'-'a'] X#define debugs oflags['s'-'a'] X#define debugv oflags['v'-'a'] X Xfindtok(x) X{ X while (cur->e_token != EOFTOK && cur->e_token != x) X fadvnode(); X if (cur->e_token == EOFTOK) X exit(1); X} X Xprogram() X{ X extern NODEP symtab[]; X NODEP last; X X skipon = 0; Xmore: X last = glb_decls(); X if (cur->e_token == EOFTOK) X return; X if (last) skipon = 0; /* saw something valid */ X if (last && last->n_tptr && last->n_tptr->t_token == '(') { X /* possible function definition */ X if (debugs) { X printf("FUN "); X put_nnm(last); X } X out_fstart(last); X#ifdef OUT_AZ X last->e_sc = HERE_SC; X#else X last->e_sc = K_EXTERN; X#endif X fun_start(last->n_tptr); X args_blk(last->n_tptr->n_right); X sub_block(); X fun_end(); X clr_lvl(); /* for args block */ X goto more; X } X /* error if get to here */ X if (last) { X error("missing ;"); X goto more; X } else { X skip(); X goto more; X } X} X Xfun_start(np) XNODEP np; X{ X NODEP functy(); X X funtyp = functy(np); X curbrk = curcont = -1; X funtopl = new_lbl(); X funbotl = new_lbl(); X funretl = new_lbl(); X switch (funtyp->t_token) { X case K_STRUCT: X case K_UNION: X funstrl = new_lbl(); X break; X default: X funstrl = 0; X } X maxregs = 0; X maxlocs = 0; X out_br(funbotl); X def_lbl(funtopl); X} X Xfun_end() X{ X NODEP np; X X if (labels) { X for (np = labels; np; np = np->n_next) X if (np->c_defined == 0) X errorn("undefined label", np); X freenode(labels); X labels = NULL; X } X def_lbl(funretl); X out_fret(maxregs, funstrl); X def_lbl(funbotl); X out_fend(maxregs, maxlocs); X out_br(funtopl); X if (funstrl) X out_fs(funstrl, funtyp->t_size); X} X Xskip() X{ X if (skipon == 0) { X error("syntax (try skipping...)"); X skipon = 1; X } X fadvnode(); X} X Xblock() X{ X int some; X int sawsome; X X some = loc_decls(); X if (cur->e_token == EOFTOK) X return; X if (some) skipon = 0; Xmore: X sawsome = stmts(); X if (sawsome) skipon = 0; X if (cur->e_token == '}') { X if (blktab->b_regs > maxregs) X maxregs = blktab->b_regs; X if (blktab->b_size + blktab->b_tsize > maxlocs) X maxlocs = blktab->b_size + blktab->b_tsize; X return; X } X X /* error if get to here */ X if (cur->e_token == EOFTOK || is_tykw(cur->e_token)) X /* get out of block */ X return; X else { X skip(); X goto more; X } X} X Xclr_lvl() X{ X NODE *bp; X X level--; X bp = blktab; X blktab = bp->n_next; X bp->n_next = NULL; X if (debugl && bp->b_syms) { X printf("local syms %d", level); X printlist(bp->b_syms); X } X#ifdef OUT_AZ X xrefl(bp->b_syms); X#endif X freenode(bp->b_syms); X if (debugl && bp->b_tags) { X printf("local tags %d", level); X printlist(bp->b_tags); X } X freenode(bp->b_tags); X freenode(bp); X} X Xeat(c) X{ X char *p = "assume X"; X X if (cur->e_token == c) X fadvnode(); X else { X p[strlen(p) - 1] = c; X error(p); X } X} X Xsub_block() X{ X register NODE *new; X X if (debugs) X printf("{ "); X eat('{'); X level++; X new = allocnode(); X new->n_next = blktab; X sprintf(new->n_name, "sub{"); X blktab = new; X block(); X clr_lvl(); X eat('}'); X if (debugs) X printf("}\n"); X} X Xargs_blk(np) XNODEP np; X{ X register NODE *p; X register NODE *new; X NODE *tp; X NODEP llook(); X long size; X int rmask; X X size = 0; X rmask = 0; X new = allocnode(); X new->n_next = blktab; X sprintf(new->n_name, "arg{"); X blktab = new; X level++; X loc_decls(); X /* make sure all decls were in arg list */ X for (p=new->b_syms; p != NULL; p = p->n_next) X if (llook(np, p) == NULL) X errorn("ID not param", p); X /* now make any names not mentioned INT */ X /* and generate offsets and alloc regs */ X for (p=np; p != NULL; p = p->n_next) { X if ((tp=llook(new->b_syms, p)) == NULL) { X def_arg(&new->b_syms, p); X tp = new->b_syms; X } X lc_size(&size, &rmask, tp); X if (tp->e_sc == K_REGISTER) X reg_arg(&rmask, tp); X if (debugv) { X printf("final o%ld r%d ", tp->e_offs, tp->e_rno); X put_nnm(tp); X putchar('\n'); X } X out_advice(tp); X } X new->b_regs = rmask; X} X Xreg_arg(rp, xp) Xint *rp; XNODEP xp; X{ X if (lc_reg(rp, xp) == 0) { /* out of regs? */ X xp->e_sc = K_AUTO; X return; X } X out_argreg(xp); X} X X Xstmts() X{ X int didsome; X X didsome = 0; X while (stmt()) X didsome++; X return didsome; X} X Xstmt_bc(brk,cont) X{ X int svb, svc; X X svb = curbrk; X svc = curcont; X curbrk = brk; X curcont = cont; X X stmt(); X X curbrk = svb; X curcont = svc; X} X Xstmt_b(brk) X{ X int svb; X X svb = curbrk; X curbrk = brk; X X stmt(); X X curbrk = svb; X} X X/* do a single statement */ Xstmt() X{ X register tok; X NODEP np; X NODEP getexpr(); X int i; X Xmore: X tok = cur->e_token; X if (is_stkw(tok)) { X if (is_blkst(tok)) { X i = blk_stmt(); X } else if (is_brast(tok)) { X i = bra_stmt(); X } else if (is_lblst(tok)) { X i = lbl_stmt(); X } else { X asm_stmt(); X return 1; X } X if (i == 0) X goto more; X return 1; X } X else if (tok == '{') { X sub_block(); X return 1; X } else if (tok == ';') { X fadvnode(); X return 1; X } X np = getexpr(); X if (np) { X if (cur->e_token == ':') { X fadvnode(); X label(np); X goto more; X } X expr_stmt(np); X if (cur->e_token != ';') X error("missing ;"); X else X fadvnode(); X return 1; X } X return 0; X} X Xexpr_stmt(np) XNODEP np; X{ X if (debugs) { X printf("E_STMT "); X if (debugs > 1) X printnode(np); X } X do_expr(np, FORSIDE); X} X Xlabel(np) XNODEP np; X{ X register NODEP tp; X NODEP llook(); X X if (debugs) { X printf("LABEL "); X if (debugs > 1) X printnode(np); X } X if (np->e_token != ID) { X error("weird label"); X return; X } X tp = llook(labels, np); X if (tp) { X freenode(np); X if (tp->c_defined) { X error("duplicate label"); X return; X } X } else { X putlist(&labels, np); X tp = np; X tp->c_casel = new_lbl(); X } X tp->c_defined = 1; X def_lbl(tp->c_casel); X} X Xblk_stmt() X{ X register tok; X int l1, l2, l3; X NODEP e1, e2, e3; X NODEP opt_expr(), paren_expr(), def_type(); X struct swittbl locswit, *oldp; X extern int lineno; X int svline, svline2; X X tok = cur->e_token; X fadvnode(); X switch (tok) { X case K_IF: X if (debugs) X printf("IF "); X l1 = new_lbl(); X e1 = paren_expr(); X gen_brf(e1, l1); X eat(')'); X stmt(); X opt_else(l1); X return 1; X case K_WHILE: X if (debugs) X printf("WHILE "); X e1 = paren_expr(); X l1 = new_lbl(); X l2 = new_lbl(); X X def_lbl(l1); X gen_brf(e1,l2); X eat(')'); X X stmt_bc(l2,l1); X X out_br(l1); X def_lbl(l2); X return 1; X case K_DO: X if (debugs) X printf("DO "); X l1 = new_lbl(); X l2 = new_lbl(); X l3 = new_lbl(); X def_lbl(l1); X X stmt_bc(l3,l2); X X def_lbl(l2); X eat(K_WHILE); X e1 = paren_expr(); X gen_brt(e1, l1); X eat(')'); X eat(';'); X def_lbl(l3); X return 1; X case K_FOR: X if (debugs) X printf("FOR "); X l1 = new_lbl(); X l2 = new_lbl(); X l3 = new_lbl(); X eat('('); X e1 = opt_expr(); X expr_stmt(e1); X eat(';'); X def_lbl(l1); X e2 = opt_expr(); X if (e2) X gen_brf(e2,l3); X eat(';'); X e3 = opt_expr(); /* save for later */ X svline = lineno; X eat(')'); X X stmt_bc(l3,l2); X X def_lbl(l2); X X svline2 = lineno; X lineno = svline; X expr_stmt(e3); X lineno = svline2; X X out_br(l1); X def_lbl(l3); X return 1; X case K_SWITCH: X if (debugs) X printf("SWITCH "); X e1 = paren_expr(); X l1 = new_lbl(); X l2 = new_lbl(); X to_d0(e1, def_type()); X eat(')'); X X out_br(l2); X oldp = curswit; X curswit = &locswit; X locswit.caselist = NULL; X locswit.deflbl = -1; X X stmt_b(l1); X X out_br(l1); X def_lbl(l2); X gen_switch(locswit.caselist, locswit.deflbl); X curswit = oldp; X def_lbl(l1); X return 1; X case K_ELSE: X error("unexpected 'else'"); X fadvnode(); X return 0; X } X} X XNODEP Xparen_expr() X{ X NODEP np; X NODEP need_expr(); X X eat('('); X np = need_expr(); X return np; X} X Xbra_stmt() X{ X register tok; X NODEP np, tp; X NODEP opt_expr(), llook(); X X tok = cur->e_token; X fadvnode(); X switch (tok) { X case K_BREAK: X if (debugs) X printf("BRK"); X eat(';'); X out_br(curbrk); X return 1; X case K_CONTINUE: X if (debugs) X printf("CONT "); X eat(';'); X out_br(curcont); X return 1; X case K_RETURN: X if (debugs) X printf("RETURN "); X np = opt_expr(); X if (np) { X if (funstrl) X ret_stru(np); X else X to_d0(np, funtyp); X } X out_br(funretl); X eat(';'); X return 1; X case K_GOTO: X if (debugs) X printf("GOTO "); X np = cur; advnode(); X if (np->e_token != ID) X error("bad goto"); X else { X tp = llook(labels, np); X if (tp) { X freenode(np); X } else { X tp = np; X putlist(&labels, tp); X tp->c_casel = new_lbl(); X } X out_br(tp->c_casel); X } X eat(';'); X return 1; X } X} X Xlbl_stmt() X{ X register tok; X NODEP need_expr(), np; X int l1, i; X X l1 = new_lbl(); X tok = cur->e_token; Xagain: X fadvnode(); X switch (tok) { X case K_CASE: X if (debugs) X printf("CASE "); X np = need_expr(); X i = conxval(np); X if (curswit) X add_case(i,l1); X else X error("'case' outside switch"); X eat(':'); X break; X case K_DEFAULT: X if (debugs) X printf("DEFAULT "); X if (curswit) { X if (curswit->deflbl >= 0) X error("multiple 'default'"); X curswit->deflbl = l1; X } else X error("'default' outside switch"); X eat(':'); X } X tok = cur->e_token; /* lookahead for more cases */ X if (tok == K_CASE || tok == K_DEFAULT) X goto again; X def_lbl(l1); X return 0; X} X Xasm_stmt() X{ X NODEP np, getexpr(); X X fadvnode(); X np = getexpr(); X if (np == NULL || np->e_token != SCON) { X error("bad asm() func"); X } else { X out_asm(np); X freenode(np); X } X eat(';'); X} X XNODEP Xopt_expr() X{ X NODE *np, *getexpr(); X X np = getexpr(); X if (np) { X if (debugs) { X printf("OXPR "); X if (debugs > 1) X printnode(np); X } X } X return np; X} X XNODEP Xneed_expr() X{ X NODE *np, *getexpr(); X X np = getexpr(); X if (np) { X if (debugs) { X printf("NXPR "); X if (debugs > 1) X printnode(np); X } X } else X error("need expr"); X return np; X} X Xopt_else(l1) X{ X int l2; X X if (cur->e_token == K_ELSE) { X if (debugs) X printf("ELSE "); X fadvnode(); X l2 = new_lbl(); X out_br(l2); X def_lbl(l1); X stmt(); X def_lbl(l2); X } else X def_lbl(l1); X} X Xadd_case(val, lbl) X{ X NODEP np, last, p; X X np = allocnode(); X np->c_casev = val; X np->c_casel = lbl; X sprintf(np->n_name, "%d:%d", val, lbl); X X last = NULL; X for (p = curswit->caselist; p; last=p, p=p->n_next) X if (p->c_casev == val) { X error("duplicate case"); X return; X } else if (p->c_casev > val) X break; X if (last) { X last->n_next = np; X np->n_next = p; X } else { X curswit->caselist = np; X np->n_next = p; X } X if (debugs) { X printf("CASELIST\n"); X printnode(curswit->caselist); X } X} X Xto_d0(np, typ) XNODEP np, typ; X{ X NODEP tp; X X tp = allocnode(); X tp->e_token = TCONV; X tp->n_tptr = typ; X tp->n_flags |= N_COPYT; X tp->n_left = np; X tp->e_type = E_UNARY; X strcpy(tp->n_name, "r cast"); X X do_expr(tp, IND0); X} X Xret_stru(np) XNODEP np; X{ X p2_expr(&np); X if (same_type(np->n_tptr, funtyp) == 0) { X error("bad struct return type"); X return; X } X genx(np, RETSTRU); X} END_OF_FILE if test 11588 -ne `wc -c <'hcc/FUN.C'`; then echo shar: \"'hcc/FUN.C'\" unpacked with wrong size! fi # end of 'hcc/FUN.C' fi if test -f 'hcc/G2.C' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'hcc/G2.C'\" else echo shar: Extracting \"'hcc/G2.C'\" \(11766 characters\) sed "s/^X//" >'hcc/G2.C' <<'END_OF_FILE' X/* Copyright (c) 1988 by Sozobon, Limited. Author: Johann Ruegg X * X * Permission is granted to anyone to use this software for any purpose X * on any computer system, and to redistribute it freely, with the X * following restrictions: X * 1) No charge may be made other than reasonable charges for reproduction. X * 2) Modified versions must be clearly marked as such. X * 3) The authors are not responsible for any harmful consequences X * of using this software, even if they result from defects in it. X * X * g2.c X * X * Generate code for binary nodes. X */ X X#include <stdio.h> X#include "param.h" X#include "nodes.h" X#include "flags.h" X#include "bstok.h" X#include "gen.h" X#include "ops.h" X X#define FAIL 0 X#define OKAY 1 X Xextern int cookflags[]; X X#define isimmed(np) ((np)->g_flags & IMMEDID) X#define isareg(np) ((np)->g_token == REGVAR && (np)->g_rno >= AREG) X Xstruct bop { X char *s_op, *u_op; X int opflags; X} bops[] = { X {"muls", "mulu", EOPD |ASSOC}, X {"divs", "divu", EOPD}, X {"divs", "divu", EOPD}, X {"and", "and", EOPD|DOPE|IOPE |ASSOC}, X {"or", "or", EOPD|DOPE|IOPE |ASSOC}, X {"eor", "eor", DOPE|IOPE |ASSOC}, X {"add", "add", EOPD|DOPE|EOPA|IOPE|AOPA|AOPD |ASSOC}, X {"sub", "sub", EOPD|DOPE|EOPA|IOPE|AOPA|AOPD}, X {"asl", "lsl", DOPD|QOPD|ONEOPM}, X {"asr", "lsr", DOPD|QOPD|ONEOPM}, X}; X Xchar *tstnm[] = { X "lt", /* < */ X "gt", /* > */ X "le", /* <= */ X "ge", /* >= */ X "eq", /* == */ X "ne", /* != */ X}; X Xint tstx[] = { X B_LT, B_GT, B_LE, B_GE, B_EQ, B_NE X}; X Xchar *utstnm[] = { X "cs", /* < */ X "hi", /* > */ X "ls", /* <= */ X "cc", /* >= */ X "eq", /* == */ X "ne", /* != */ X}; X Xint utstx[] = { X B_ULT, B_UGT, B_ULE, B_UGE, B_EQ, B_NE X}; X Xb_eval(np, cookie) Xregister NODEP np; X{ X NODEP lp = np->n_left, rp = np->n_right; X NODEP tp; X int lcook = FORADR, rcook = FORADR; X X switch (np->g_token) { /* special cookies */ X case DOUBLE '&': X case DOUBLE '|': X lcook = rcook = FORCC; X break; X case '?': X lcook = FORCC; X break; X case '(': X rcook = FORPUSH; X break; X case ',': X if (np->g_offs) /* function args */ X lcook = rcook = FORPUSH; X else { X lcook = FORSIDE; X rcook = cookie; X } X break; X case '=': X rcook = FORIMA; X break; X case '+': X case '-': X tp = rp; X while (tp->g_token == TCONV && tp->g_ty != ET_F) X tp = tp->n_left; X if (tp->g_token == ICON) X lcook = FORIMA; X break; X } X X if (np->g_type == EV_LR) { X if (eval(lp,lcook) == FAIL) X return FAIL; X freetmps(lp); X if (eval(rp,rcook) == FAIL) X return FAIL; X freetmps(rp); X } else if (np->g_type == EV_RL) { X if (eval(rp,rcook) == FAIL) X return FAIL; X freetmps(rp); X if (eval(lp,lcook) == FAIL) X return FAIL; X freetmps(lp); X } else { /* EV_LRSEP */ X if (eval(lp,lcook) == FAIL) X return FAIL; X freetmps(lp); X free1(NULL, lp); X if (eval(rp,rcook) == FAIL) X return FAIL; X freetmps(rp); X } X return b_sube(np, cookflags[cookie]); X} X Xb_sube(np, flags) Xregister NODEP np; X{ X NODEP lp = np->n_left, rp = np->n_right; X register int i, r; X int argsize; X char buf[40]; X X if (isassign(np->g_token)) X return as_eval(np); X X switch (np->g_token) { X case '=': X if (specasn(np, flags) || strasn(np)) X return OKAY; X inherit(np); X addcode(np, "\tmove.S\t>A,<A\n"); X return OKAY; X X case '(': X argsize = argmod(rp); X free1(NULL,rp); X if (np->g_ty == ET_A) { /* struct returned */ X frc_ral(AREG); X indir(np, AREG); X } else { X frc_ral(0); X retreg(np, 0); X } X sprintf(buf, "\tjsr\t<A\n\tadd.w\t#%d,sp\n", argsize); X addcode(np, buf); X return OKAY; X X case ',': X if (np->g_offs == 0) /* normal ',' */ X rinherit(np); X return OKAY; X X case DOUBLE '&': X free1(NULL, rp); X r = ralloc(0); X retreg(np, r); X holdlbls(np); X np->g_betw = iscc(lp) ? "<FL1\n" : X "<Q\tbeq\tL1\n"; X addcode(np, iscc(rp) ? ">FL1\n" : X ">Q\tbeq\tL1\n"); X addcode(np, "\tmoveq\t#1,A\n"); X addcode(np, "\tbra\tL2\nL1:\tclr\tA\nL2:\n"); X return OKAY; X X case DOUBLE '|': X free1(NULL, rp); X r = ralloc(0); X retreg(np, r); X holdlbls(np); X np->g_betw = iscc(lp) ? "<TL1\n" : X "<Q\tbne\tL1\n"; X addcode(np, iscc(rp) ? ">TL1\n" : X ">Q\tbne\tL1\n"); X addcode(np, "\tclr\tA\n"); X addcode(np, "\tbra\tL2\nL1:\tmoveq\t#1,A\nL2:\n"); X return OKAY; X X case '?': X rinherit(np); X rinhlbls(np); X np->g_betw = iscc(lp) ? "<FL1\n" : "<Q\tbeq\tL1\n"; X return OKAY; X X case ':': X free1(NULL, rp); X r = ralloc(0); X retreg(np, r); X holdlbls(np); X np->g_betw = same_a(np, lp) ? X "\tbra\tL2\nL1:\n" : X "\tmove.S\t<A,A\n\tbra\tL2\nL1:\n"; X if (!same_a(np, rp)) X addcode(np, "\tmove.S\t>A,A\n"); X addcode(np, "L2:\n"); X return OKAY; X X case '<': X i = 0; goto dotst; X case '>': X i = 1; goto dotst; X case LTEQ: X i = 2; goto dotst; X case GTEQ: X i = 3; goto dotst; X case DOUBLE '=': X i = 4; goto dotst; X case NOTEQ: X i = 5; Xdotst: X fix_cmp(np, EOPD|EOPA|IOPE|AOPA|AOPD); X if (flags & CC_OK) { X np->g_token = (lp->g_ty == ET_U ? X utstx[i] : tstx[i]) + BR_TOK; X } else { X strcpy(np->n_name, lp->g_ty == ET_U ? X utstnm[i] : tstnm[i]); X r = ralloc(0); X retreg(np, r); X addcode(np, "\tsN\tA\n\tand.w\t#1,A\n"); X } X return OKAY; X X case '*': X return fixmul(np, bops[0].opflags); X case '/': X return fixdiv(np, bops[1].opflags); X case '%': X return fixmod(np, bops[2].opflags); X case '&': i = 3; goto doop; X case '|': i = 4; goto doop; X case '^': i = 5; goto doop; X case '+': X if (optadd(np, flags, 1)) X return OKAY; X i = 6; goto doop; X case '-': X if (optadd(np, flags, -1)) X return OKAY; X i = 7; goto doop; X case DOUBLE '<':i = 8; goto doop; X case DOUBLE '>':i = 9; Xdoop: X strcpy(np->n_name, np->g_ty == ET_U ? X bops[i].u_op : bops[i].s_op); X r = fix2ops(np, bops[i].opflags); X cc_hack(np); X return r; X case FIELDAS: X return fldasn(np, flags); X default: X printf("Weird b_eval %s ", np->n_name); X return FAIL; X } X} X Xas_eval(np) Xregister NODEP np; X{ X NODEP rp = np->n_right; X register int op, i, r; X X rp = np->n_right; X X op = np->g_token; X op -= ASSIGN 0; X switch (op) { X X /* these get unfolded now */ X case '*': X return fixamul(np, bops[0].opflags); X case '/': X return fixadiv(np, bops[1].opflags); X case '%': X return fixamod(np, bops[2].opflags); X case '&': i = 3; goto doop; X case '|': i = 4; goto doop; X case '^': i = 5; goto doop; X case '+': i = 6; goto doop; X case '-': i = 7; goto doop; X case DOUBLE '<':i = 8; goto doop; X case DOUBLE '>':i = 9; Xdoop: X strcpy(np->n_name, np->g_ty == ET_U ? X bops[i].u_op : bops[i].s_op); X r = fix_asn(np, bops[i].opflags); X cc_hack(np); X return r; X X default: X printf("Weird as_eval %s ", np->n_name); X return FAIL; X } X} X Xrinherit(np) Xregister NODEP np; X{ X register NODEP rp = np->n_right; X X np->g_token = rp->g_token; X np->g_offs = rp->g_offs; X np->g_rno = rp->g_rno; X np->g_flags |= RCHILDNM | (rp->g_flags & IMMEDID); X} X Xargmod(np) Xregister NODEP np; X{ X int size = 0; X X if (np->g_token == ',') { X np->g_type = EV_RL; X size += argmod(np->n_right); X size += argmod(np->n_left); X return size; X } X size += onearg(np); X return size; X} X Xonearg(np) Xregister NODEP np; X{ X int rv; X X /* hack small ICON */ X if (np->g_sz == 1 && np->g_token == ICON) X np->g_sz = 2; X /* hack push of 0 */ X if (np->g_token == ICON && np->g_offs == 0 && isimmed(np)) { X addcode(np, "\tclr.S\t-(sp)\n"); X return (int)np->g_sz; X } X /* hack push of #OREG */ X if (np->g_token == OREG && isimmed(np)) { X np->g_flags &= ~IMMEDID; X addcode(np, "\tpea\tA\n"); X return 4; X } X X if (np->g_ty == ET_A) { X rv = strpush(np); X freetmps(np); X free1(NULL,np); X return rv; X } X X switch (np->g_sz) { X case 1: X addcode(np, (np->g_ty == ET_U) ? X "\tclr.w\td0\n\tmove.b\tA,d0\n\tmove.w\td0,-(sp)\n" : X "\tmove.b\tA,d0\n\text.w\td0\n\tmove.w\td0,-(sp)\n" ); X return 2; X case 2: X addcode(np, X "\tmove.w\tA,-(sp)\n"); X return 2; X default: X addcode(np, X "\tmove.l\tA,-(sp)\n"); X return 4; X } X} X X#define MAXD DRV_START X#define MAXA (ARV_START-AREG) X#define NEEDALL (MAXA*AREG + MAXD) X Xorder(np) Xregister NODEP np; X{ X int l, r; X X switch (np->g_type) { X case E_BIN: X order(np->n_right); X r = np->n_right->g_needs; X case E_UNARY: X order(np->n_left); X l = np->n_left->g_needs; X break; X default: /* leaf */ X np->g_type = EV_NONE; X np->g_needs = 0; X return; X } X X if (np->g_type == E_UNARY) { X switch (np->g_token) { X case STAR: X case UNARY '&': X np->g_needs = merge(l,AREG); X break; X case '(': X np->g_needs = NEEDALL; X break; X case POSTINC: X case POSTDEC: X case '!': X case TCONV: X np->g_needs = merge(l,1); X break; X case '.': X if (np->g_fldw) { X np->g_needs = merge(l,1); X break; X } X /* else fall through */ X default: X np->g_needs = l; X } X np->g_type = EV_LEFT; X return; X } X X/* at this point, have binary node */ X X switch (np->g_token) { X case DOUBLE '&': X case DOUBLE '|': X case '?': X case ':': X /* always left-right, no extra regs */ X np->g_type = EV_LRSEP; X np->g_needs = merge(1, merge(l,r)); X return; X case ',': X np->g_needs = merge(l, r); X np->g_type = EV_LRSEP; X return; X case '(': X np->g_needs = NEEDALL; X break; X case '^': X case DOUBLE '<': X case DOUBLE '>': X case ASSIGN '/': X case ASSIGN DOUBLE '<': X case ASSIGN DOUBLE '>': X np->g_needs = merge(bin(l,r), 2); X break; X default: X if (isassign(np->g_token) || np->g_token == '=') X np->g_needs = merge(rbin(l,r), 1); X else X np->g_needs = merge(bin(l,r), 1); X } X X if (isassign(np->g_token) || np->g_token == '=') X np->g_type = EV_RL; /* NO PUSHER's on L */ X else X np->g_type = worst_1st(l, r); X flag_saves(np, l, r); X} X Xflag_saves(np, l, r) XNODEP np; X{ X NODEP *cpp; X register int other; X X if (np->g_type == EV_LR) { X cpp = &np->n_left; X other = r; X } else { X cpp = &np->n_right; X other = l; X } X if ((other & 7) >= MAXD || (other/AREG) >= MAXA) X addtmp(np, cpp); X} X Xaddtmp(np, cpp) XNODEP np, *cpp; X{ X NODEP cp, tp; X NODEP copyone(); X X cp = *cpp; X tp = copyone(cp); X tp->n_left = cp; X *cpp = tp; X tp->g_token = PUSHER; X strcpy(tp->n_name, "pusher"); X tp->g_type = EV_LEFT; X} X Xworst_1st(l,r) X{ X int ld, rd; X X ld = l & 7; X rd = r & 7; X if (rd > ld) X return EV_RL; X if (r > l) X return EV_RL; X return EV_LR; X} X Xbin(l,r) X{ X int la, ra, na; X int ld, rd, nd; X int rfirst; X X la = l/AREG; X ra = r/AREG; X ld = l & 7; X rd = r & 7; X rfirst = (ra > la) || (rd > ld); X return rfirst ? rbin(l,r) : rbin(r,l); X} X Xrbin(last,first) X{ X int la, fa, na; X int ld, fd, nd; X X la = last/AREG; X fa = first/AREG; X ld = last & 7; X fd = first & 7; X na = fa > la ? fa : la + (fa ? 1 : 0); X if (na > MAXA) X na = MAXA; X nd = fd > ld ? fd : ld + (fd ? 1 : 0); X if (nd > MAXD) X nd = MAXD; X return na*AREG + nd; X} X Xmerge(need, have) X{ X int na, nd, ha, hd, xa, xd; X X na = need/AREG; X ha = have/AREG; X nd = need & 7; X hd = have & 7; X xa = na > ha ? na : ha; X xd = nd > hd ? nd : hd; X return xa*AREG + xd; X} X Xholdlbls(np) XNODEP np; X{ X np->g_bsize = new_lbl(); X new_lbl(); X} X Xrinhlbls(np) XNODEP np; X{ X np->g_bsize = np->n_right->g_bsize; X} X X/* limited version of same address check X assume one of these is a temp register */ Xsame_a(p1, p2) XNODEP p1, p2; X{ X if (p1->g_token != p2->g_token) X return 0; X if (p1->g_rno != p2->g_rno) X return 0; X return 1; X} X Xoptadd(np, flags, sign) Xregister NODEP np; X{ X NODEP lp = np->n_left, rp = np->n_right; X X if (rp->g_token != ICON) X return 0; X if (isimmed(lp) && isimmed(rp)) { X switch (lp->g_token) { X case OREG: X case ONAME: X inherit(np); X if (sign == -1) X rp->g_offs = -rp->g_offs; X np->g_offs += rp->g_offs; X X if ((flags & IMMA_OK) == 0) X imm_oreg(np); X return 1; X default: X return 0; X } X } X return 0; X} X Xiscc(np) XNODEP np; X{ X return (np->g_token >= BR_TOK) || (np->g_flags & SIDE_CC); X} X Xcc_hack(np) XNODEP np; X{ X if (isareg(np)) X return; X np->g_flags |= SIDE_CC; X} X Xcctok(np) XNODEP np; X{ X if (np->g_token >= BR_TOK) X return np->g_token - BR_TOK; X if (np->g_flags & SIDE_CC) X return B_NE; X printf("cctok error "); X return 0; X} END_OF_FILE if test 11766 -ne `wc -c <'hcc/G2.C'`; then echo shar: \"'hcc/G2.C'\" unpacked with wrong size! fi # end of 'hcc/G2.C' fi if test -f 'hcc/GEN.C' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'hcc/GEN.C'\" else echo shar: Extracting \"'hcc/GEN.C'\" \(11959 characters\) sed "s/^X//" >'hcc/GEN.C' <<'END_OF_FILE' X/* Copyright (c) 1988 by Sozobon, Limited. Author: Johann Ruegg X * X * Permission is granted to anyone to use this software for any purpose X * on any computer system, and to redistribute it freely, with the X * following restrictions: X * 1) No charge may be made other than reasonable charges for reproduction. X * 2) Modified versions must be clearly marked as such. X * 3) The authors are not responsible for any harmful consequences X * of using this software, even if they result from defects in it. X * X * gen.c X * X * Generate code. X * Includes main routine and code generation for unary nodes X * and leafs. X */ X X#include <stdio.h> X#include "param.h" X#include "bstok.h" X#include "tytok.h" X#include "flags.h" X#include "nodes.h" X#include "gen.h" X XNODEP strsave; Xint cctest; Xstatic int reserve; Xstatic int tmpused; X Xextern xflags[]; X#define debug xflags['g'-'a'] X X#define FAIL 0 X#define OKAY 1 X X#define isimmed(np) ((np)->g_flags & IMMEDID) X#define isareg(np) ((np)->g_token == REGVAR && (np)->g_rno >= AREG) X#define isdreg(np) ((np)->g_token == REGVAR && (np)->g_rno < AREG) X#define istdreg(np) ((np)->g_token == REGVAR && (np)->g_rno < DRV_START) X Xint cookflags[] = { X 0, X NOVAL_OK|CC_OK|IMMA_OK, /* FORSIDE */ X IMMA_OK, /* FORPUSH */ X CC_OK, /* FORCC */ X IMMA_OK, /* FORIMA */ X 0, /* FORADR */ X IMMA_OK, /* FORINIT */ X 0, /* IND0 */ X 0, /* RETSTRU */ X}; X Xgenx(np, cookie) Xregister NODEP np; X{ X extern nmerrors; X int rv; X extern NODE *blktab; X X if (np == NULL) return; X if (nmerrors) X goto bad; X if (debug) { X printf("GEN enter"); X printnode(np); X } X X untype(np); X if (debug>1) { X printf("after UNTYPE"); X printnode(np); X } X X tmpused = 0; X gunk(np); X if (tmpused && tmpused > blktab->b_tsize) X blktab->b_tsize = tmpused; X if (debug > 1) { X printf("after gunk"); X printnode(np); X } X order(np); X X reserve = 0; X rv = eval(np, cookie); X if (rv == OKAY && debug) { X printf("GEN exit"); X codeprint(np); X } X if (rv == OKAY) X rv = cookmon(np, cookie); X else X error("couldnt eval node"); X freenode(np); X return rv; Xbad: X freenode(np); X return FAIL; X} X Xeval(np, cookie) Xregister NODEP np; X{ X int rv; X X np->g_r1 = np->g_r2 = -1; X X if (np == NULL) return FAIL; X X switch (np->g_type) { X X default: X rv = b_eval(np, cookie); X /* already did freetmps */ X free1(np, np->n_left); X free1(np, np->n_right); X break; X X case EV_LEFT: X rv = u_eval(np, cookie); X freetmps(np); X free1(np, np->n_left); X break; X X case EV_NONE: X rv = l_eval(np); X break; X } X return rv; X} X Xu_eval(np, cookie) Xregister NODEP np; X{ X int subcook = FORADR; X X switch (np->g_token) { X case STAR: X subcook = FORIMA; X break; X case '!': X subcook = FORCC; X break; X } X X if (eval(np->n_left, subcook) == FAIL) X return FAIL; X return u_sube(np, cookflags[cookie]); X} X Xu_sube(np, flags) Xregister NODEP np; X{ X register NODEP lp = np->n_left; X long offs; X int i; X X switch (np->g_token) { X case '.': X if (np->g_fldw) X return fldget(np, flags); X offs = np->g_offs; X inherit(np); X np->g_offs += offs; X return OKAY; X case STAR: X if (isimmed(lp)) { X inherit(np); X np->g_flags &= ~IMMEDID; X } else if (isareg(lp)) { X indir(np, lp->g_rno); X } else { /* NEED A temp */ X if (lp->g_token == OREG && istemp(lp->g_rno)) X i = lp->g_rno; X else X i = ralloc(AREG); X addcode(np, "\tmove.l\t<A,R0\n"); X indir(np, i); X } X return OKAY; X case UNARY '&': X if (isimmed(lp)) X warn("& ignored"); X else if (lp->g_token == REGVAR) X return FAIL; X inherit(np); X np->g_flags |= IMMEDID; X if ((flags & IMMA_OK) == 0) X imm_oreg(np); X return OKAY; X case '~': X utemp(np); X addcode(np, "\tnot.S\tA\n"); X cc_hack(np); X return OKAY; X case UNARY '-': X utemp(np); X addcode(np, "\tneg.S\tA\n"); X cc_hack(np); X return OKAY; X case TCONV: X castgen(np); X return OKAY; X case PUSHER: /* must not be on left of assign or asn-op */ X if ((lp->g_token != OREG && lp->g_token != REGVAR) || X istemp(lp->g_rno) == 0) { X inherit(np); X return OKAY; X } X if (lp->g_ty == ET_A) X strxpush(np); X else X addcode(np, "\tmove.S\t<A,-(sp)\n"); X return OKAY; X case '(': X if (np->g_ty == ET_A) { /* struct returned */ X frc_ral(AREG); X indir(np, AREG); X } else { X frc_ral(0); X retreg(np, 0); X } X addcode(np, "\tjsr\t<A\n"); X return OKAY; X case DOUBLE '+': X holdcon(np); X inherit(np); X addcode(np, "\tadd.S\t#K,A\n"); X cc_hack(np); X return OKAY; X case DOUBLE '-': X holdcon(np); X inherit(np); X addcode(np, "\tsub.S\t#K,A\n"); X cc_hack(np); X return OKAY; X case POSTINC: X if ((flags & NOVAL_OK) == 0) { X i = ralloc(0); X retreg(np, i); X addcode(np, "\tmove.S\t<A,A\n"); X } X addcode(np, "\tadd.S\t#O,<A\n"); X return OKAY; X case POSTDEC: X if ((flags & NOVAL_OK) == 0) { X i = ralloc(0); X retreg(np, i); X addcode(np, "\tmove.S\t<A,A\n"); X } X addcode(np, "\tsub.S\t#O,<A\n"); X return OKAY; X case CMPBR: X i = ralloc(0); X retreg(np, i); X addcode(np, "\tsN\tA\n\tand.w\t#1,A\n"); X cc_hack(np); X return OKAY; X case '!': X if (flags & CC_OK) { X if (iscc(lp)) { X i = cctok(lp); X i = (i&1) ? i+1 : i-1; /* reverse truth */ X } else { X i = B_EQ; X addcode(np, "<Q"); X } X np->g_token = i + BR_TOK; X } else { X if (istdreg(lp)) X i = lp->g_rno; X else X i = ralloc(0); X retreg(np, i); X if (iscc(lp)) { X addcode(np, "<EA\n\tand.w\t#1,A\n"); X } else { X addcode(np, "<Q"); X addcode(np, "\tseq\tA\n\tand.w\t#1,A\n"); X } X } X return OKAY; X default: X printf("Weird u_eval %s ", np->n_name); X return FAIL; X } X} X Xholdcon(np) XNODEP np; X{ X np->g_bsize = np->g_offs; X} X Xretreg(np, rno) XNODEP np; X{ X np->g_token = REGVAR; X np->g_rno = rno; X} X Xindir(np, rno) Xregister NODEP np; X{ X np->g_token = OREG; X np->g_offs = 0; X np->g_rno = rno; X} X Xinherit(np) Xregister NODEP np; X{ X NODEP lp = np->n_left; X X np->g_token = lp->g_token; X np->g_offs = lp->g_offs; X np->g_rno = lp->g_rno; X np->g_flags |= CHILDNM | (lp->g_flags & IMMEDID); X} X Xcookmon(np, cookie) Xregister NODEP np; X{ X extern FILE *output; X X if (np == NULL) return FAIL; X X switch (cookie) { X case FORCC: X if (iscc(np)) { X outcode(np); X cctest = cctok(np); X } else { X if (np->g_token == ICON && isimmed(np)) { X cctest = np->g_offs ? B_YES : B_NO; X return OKAY; X } X outcode(np); X outsub("Q", np); X cctest = B_NE; X } X return OKAY; X case FORINIT: X if (anycode(np) == 0 && (np->g_flags & IMMEDID)) { X out_a(np, output); X return OKAY; X } X error("bad INIT expr"); X return FAIL; X case IND0: X outcode(np); X if (np->g_token != REGVAR || X np->g_rno != 0) X if (np->g_token == ICON && np->g_offs == 0 && X isimmed(np)) X outsub("\tclr.S\td0\n", np); X else X outsub("\tmove.S\tA,d0\n", np); X return OKAY; X case RETSTRU: X freetmps(np); X strret(np); X outcode(np); X return OKAY; X } X outcode(np); X return OKAY; X} X Xanycode(np) Xregister NODEP np; X{ X if (np->g_code) X return 1; X switch (np->g_type) { X case EV_NONE: X return 0; X case EV_LEFT: X return anycode(np->n_left); X case EV_RIGHT: X return anycode(np->n_right); X case EV_LR: X case EV_RL: X return anycode(np->n_left) || anycode(np->n_right); X } X} X Xl_eval(np) Xregister NODEP np; X{ X int l1; X X switch (np->g_token) { X case ID: X switch (np->g_sc) { X default: /* EXTERN or HERE */ X np->g_token = ONAME; X np->g_offs = 0; X if (np->n_name[0] != '%') X nnmins(np, "_"); X else /* hack for inline name */ X strcpy(np->n_name, &np->n_name[1]); X return OKAY; /* dont free n_nmx */ X case K_STATIC: X sprintf(np->n_name, "L%d", (int)np->g_offs); X np->g_offs = 0; X np->g_token = ONAME; X break; X case K_AUTO: X np->g_rno = FRAMEP; X np->g_token = OREG; X break; X case K_REGISTER: X np->g_token = REGVAR; X break; X } X if (np->n_nmx) { X freenode(np->n_nmx); X np->n_nmx = NULL; X } X return OKAY; X case ICON: X np->g_flags |= IMMEDID; X return OKAY; X case FCON: X np->g_flags |= IMMEDID; X return OKAY; X case SCON: X np->g_flags |= IMMEDID; X np->g_token = ONAME; X l1 = new_lbl(); X save_scon(np, l1); X sprintf(np->n_name, "L%d", l1); X return OKAY; X case OREG: X return OKAY; X } X return FAIL; X} X Xsave_scon(np, lbl) XNODEP np; X{ X NODEP tp, copyone(); X X tp = copyone(np); X tp->g_offs = lbl; X if (np->n_nmx) { X freenode(np->n_nmx); X np->n_nmx = NULL; X } X putlist(&strsave, tp); X} X Xutemp(np) XNODEP np; X{ X NODEP lp = np->n_left; X int i; X X if (lp->g_token == REGVAR && X istemp(lp->g_rno)) { X inherit(np); X return; X } X i = ralloc(0); X retreg(np, i); X addcode(np, "\tmove.S\t<A,A\n"); X} X Xfreetmps(np) Xregister NODEP np; X{ X if (np->g_r1 != -1) X rfree(np->g_r1); X if (np->g_r2 != -1) X rfree(np->g_r2); X} X Xfree1(np, cp) XNODEP np, cp; X{ X int cr; X X if (cp->g_token != OREG && cp->g_token != REGVAR) X return; X cr = cp->g_rno; X if (np && cr == np->g_rno && X (np->g_token == OREG || np->g_token == REGVAR)) X return; X if (istemp(cr)) X rfree(cr); X} X Xistemp(rno) X{ X return (rno < DRV_START || X (rno >= AREG && rno < ARV_START)); X} X Xrfree(rno) X{ X reserve &= ~(1<<rno); X} X Xfrc_ral(rno) X{ X int i; X X i = (1<<rno); X if (reserve & i) X error("rno reserved! "); X reserve |= i; X} X Xtempr(np, type) XNODEP np; X{ X int i; X X i = ralloc(type); X if (np->g_r1 == -1) X np->g_r1 = i; X else X np->g_r2 = i; X return i; X} X Xralloc(type) X{ X int starti, endi; X register int i; X X if (type == AREG) { X starti = AREG; X endi = ARV_START; X } else { X starti = 0; X endi = DRV_START; X } X for (i=starti; i<endi; i++) X if ((reserve & (1<<i)) == 0) { X reserve |= (1<<i); X return i; X } X error("Compiler failure - rallo"); X return -1; X} X Xtmp_alloc(sz) X{ X extern NODE *blktab; X X tmpused += sz; X return blktab->b_size + tmpused; X} X X/* fixes nodes with no code or aX is temp that are #d(aX) */ Ximm_oreg(np) XNODEP np; X{ X char *regnm(), buf[30]; X int i; X X if (np->g_token != OREG) X return; X if ((np->g_flags & IMMEDID) == 0) X return; X np->g_flags &= ~IMMEDID; X if (np->g_offs == 0) { /* #(a0) -> a0 */ X np->g_token = REGVAR; X return; X } X if (istemp(np->g_rno)) { X holdcon(np); X addcode(np, "\tadd\t#K,A\n"); X np->g_token = REGVAR; X return; X } X sprintf(buf, "\tlea\t%d(%s),A\n", (int)np->g_offs, regnm(np->g_rno)); X addcode(np, buf); X i = ralloc(AREG); X retreg(np, i); X} X Xcastgen(tp) Xregister NODEP tp; X{ X register NODEP np = tp->n_left; X int sz = tp->g_sz; X int i; X X if (np->g_token == ICON && isimmed(np)) { X if (tp->g_ty == ET_F) { X tp->g_token = FCON; X *(float *)&tp->g_offs = (float)np->g_offs; X tp->g_flags |= IMMEDID; X } else { X inherit(tp); X i_exp(tp, np->g_sz, np->g_ty); X squish(tp); X } X } else if (np->g_token == FCON && isimmed(np)) { X if (tp->g_ty != ET_F) { X tp->g_token = ICON; X tp->g_offs = (long)*(float *)&np->g_offs; X tp->g_flags |= IMMEDID; X squish(tp); X } else { X inherit(tp); X } X } else if (sz > np->g_sz) { X if (np->g_ty == ET_U) { X i = ralloc(0); X retreg(tp, i); X addcode(tp, "\tclr.S\tA\n\tmove.<S\t<A,A\n"); X } else { X if (isdreg(np)) { X inherit(tp); X } else { X i = ralloc(0); X retreg(tp, i); X addcode(tp, "\tmove.<S\t<A,A\n"); X } X if (sz == 4 && np->g_sz == 1) X addcode(tp, "\text.w\tA\n\text.l\tA\n"); X else X addcode(tp, "\text.S\tA\n"); X } X return; X } X else if (sz < np->g_sz) { X switch (np->g_token) { X case ONAME: X case OREG: X if (isimmed(np)) { Xsmfudge: X i = ralloc(0); X retreg(tp, i); X addcode(tp, "\tmove.<S\t<A,A\n"); X return; X } X inherit(tp); X tp->g_offs = np->g_offs + (np->g_sz - sz); X break; X case REGVAR: X if (sz == 1 && np->g_rno >= AREG) X goto smfudge; X /* fall through */ X default: X inherit(tp); X } X } else X inherit(tp); X} X Xsquish(np) XNODEP np; X{ X int neg; X X neg = (np->g_ty == ET_S && np->g_offs < 0); X X switch (np->g_sz) { X case 1: X if (neg) X np->g_offs |= 0xffffff00L; X else X np->g_offs &= 0xff; X break; X case 2: X if (neg) X np->g_offs |= 0xffff0000L; X else X np->g_offs &= 0xffffL; X break; X } X} X Xi_exp(np, osz, oty) XNODEP np; X{ X long l; X X if (oty == ET_S && osz < np->g_sz) { X l = np->g_offs; X switch (osz) { X case 1: X l = (char) l; X break; X case 2: X l = (short) l; X break; X } X np->g_offs = l; X } X} END_OF_FILE if test 11959 -ne `wc -c <'hcc/GEN.C'`; then echo shar: \"'hcc/GEN.C'\" unpacked with wrong size! fi # end of 'hcc/GEN.C' fi echo shar: End of archive 5 \(of 9\). cp /dev/null ark5isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 9 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0