home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 1 / crawlyvol1.bin / program / compiler / bob13st / bobcom.c < prev    next >
C/C++ Source or Header  |  1991-12-24  |  33KB  |  1,516 lines

  1. /* bobcom.c - the bytecode compiler */
  2. /*
  3.     Copyright (c) 1991, by David Michael Betz
  4.     All rights reserved
  5. */
  6.  
  7. /*
  8.     1.3ST    12/25/91    Ported to Atari ST and Mark Williams C
  9.                         Ansi void * declarations removed
  10. */
  11.  
  12. #include <setjmp.h>
  13. #include "bob.h"
  14.  
  15. /* partial value structure */
  16. typedef struct 
  17. {
  18.     int (*fcn)();
  19.     int val;
  20. } PVAL;
  21.  
  22. /* variable access function codes */
  23. #define LOAD    1
  24. #define STORE    2
  25. #define PUSH    3
  26. #define DUP        4
  27.  
  28. /* global variables */
  29. int decode = 0;         /* flag for decoding functions */
  30.  
  31. /* local variables */
  32. static ARGUMENT *arguments;        /* argument list */
  33. static ARGUMENT *temporaries;    /* temporary variable list */
  34. static LITERAL  *literals;        /* literal list */
  35. static VALUE     methodclass;    /* class of the current method */
  36. static unsigned  char *cbuff;    /* code buffer */
  37. static int cptr;                /* code pointer */
  38.  
  39. /* break/continue stacks */
  40. #define SSIZE    10
  41. static int bstack[SSIZE],*bsp;
  42. static int cstack[SSIZE],*csp;
  43.  
  44. /* external variables */
  45. extern jmp_buf error_trap;    /* trap for compile errors */
  46. extern VALUE  symbols;        /* symbol table */
  47. extern VALUE  classes;        /* class table */
  48. extern VALUE *sp;            /* stack pointer */
  49. extern int       t_value;        /* token value */
  50. extern char   t_token[];    /* token string */
  51.  
  52. /* forward declarations */
  53. CLASS *get_class();
  54. VECTOR *do_code();
  55. char *copystring();
  56. char *getmemory();
  57.  
  58. /* init_compiler - initialize the compiler */
  59. int init_compiler(cmax)
  60. int cmax;
  61. {
  62.     char *calloc();
  63.     
  64.     literals = NULL;
  65.     set_nil(&methodclass);
  66.     return ((cbuff = (unsigned char *)calloc(1,cmax)) != NULL);
  67. }
  68.  
  69. /* mark_compiler - mark compiler variables */
  70. mark_compiler()
  71. {
  72.     LITERAL *lit;
  73.     
  74.     for (lit = literals; lit != NULL; lit = lit->lit_next)
  75.         mark(&lit->lit_value);
  76.     mark(&methodclass);
  77. }
  78.  
  79. /* compile_definitions - compile class or function definitions */
  80. int compile_definitions(getcf,getcd)
  81. int (*getcf)(); 
  82. char *getcd;
  83. {
  84.     char name[TKNSIZE+1];
  85.     int tkn,i;
  86.  
  87.     if (setjmp(error_trap))             /* trap errors */
  88.         return (FALSE);
  89.  
  90.     init_scanner(getcf,getcd);         /* initialize */
  91.     bsp = &bstack[-1];
  92.     csp = &cstack[-1];
  93.  
  94.     while ((tkn = token()) != T_EOF) /* process statements until end of file */
  95.     {
  96.         switch (tkn) 
  97.         {
  98.         case T_IDENTIFIER:
  99.             strcpy(name,t_token);
  100.             do_function(name);
  101.             break;
  102.         case T_CLASS:
  103.             do_class();
  104.             break;
  105.         default:
  106.             parse_error("Expecting a declaration");
  107.             break;
  108.         }
  109.     }
  110.     return (TRUE);
  111. }
  112.  
  113. /* do_class - handle class declarations */
  114. static int do_class()
  115. {
  116.     ARGUMENT *mvars,*smvars,*fargs,**table,*p;
  117.     char cname[TKNSIZE+1],id[TKNSIZE+1];
  118.     DICT_ENTRY *entry;
  119.     int type,tkn,i;
  120.  
  121.     mvars = smvars = fargs = NULL;             /* initialize */
  122.     check(1);
  123.     
  124.     /* get the class name */
  125.     frequire(T_IDENTIFIER);
  126.     strcpy(cname,t_token);
  127.     
  128.     if ((tkn = token()) == ':')              /* get the optional base class */
  129.     {
  130.         frequire(T_IDENTIFIER);
  131.         push_class(get_class(t_token));
  132.         info("Class '%s', Base class '%s'", 
  133.                 cname, getcstring(id, sizeof(id), clgetname(sp)));
  134.     }
  135.     else 
  136.     {
  137.         push_nil();
  138.         stoken(tkn);
  139.         info("Class '%s'",cname);
  140.     }
  141.     frequire('{');
  142.  
  143.     set_class(sp,newclass(cname,sp));         /* create the new class object */
  144.     addentry(&classes,cname,ST_CLASS)->de_value = *sp;
  145.  
  146.     while ((tkn = token()) != '}')              /* handle each variable declaration */
  147.     {
  148.         if ((type = tkn) == T_STATIC)             /* check for static members */
  149.             tkn = token();
  150.  
  151.         if (tkn != T_IDENTIFIER)                 /* get the first identifier */
  152.             parse_error("Expecting a member declaration");
  153.         strcpy(id,t_token);
  154.  
  155.         if ((tkn = token()) == '(')              /* check for a member function declaration */
  156.         {
  157.             get_id_list(&fargs,")");
  158.             frequire(')');
  159.             addentry(clgetfunctions(sp),id,
  160.                  type == T_STATIC ? ST_SFUNCTION : ST_FUNCTION);
  161.             freelist(&fargs);
  162.         }
  163.         else                                      /* handle data members */
  164.         {
  165.             table = (type == T_STATIC ? &smvars : &mvars);
  166.             addargument(table,id);
  167.             if (tkn == ',')
  168.                 get_id_list(table,";");
  169.             else
  170.                 stoken(tkn);
  171.         }        
  172.         frequire(';');
  173.     }
  174.  
  175.     i = (isnil(clgetbase(sp)) ? 0 : clgetsize(clgetbase(sp))); /* store the member variable names */
  176.     for (p = mvars; p != NULL; p = p->arg_next) 
  177.     {
  178.         entry = addentry(clgetmembers(sp),p->arg_name,ST_DATA);
  179.         set_integer(&entry->de_value,i++);
  180.     }
  181.     sp->v.v_class->cl_size = i;
  182.     freelist(&mvars);
  183.  
  184.     for (p = smvars; p != NULL; p = p->arg_next)         /* store the static member variable names */
  185.         addentry(clgetmembers(sp),p->arg_name,ST_SDATA);
  186.     freelist(&smvars);
  187.     ++sp;
  188. }
  189.  
  190. /* findmember - find a class member */
  191. static DICT_ENTRY *findmember(class,name)
  192. CLASS *class; char *name;
  193. {
  194.     DICT_ENTRY *entry;
  195.     
  196.     if ((entry = findentry(&class->cl_members,name)) != NULL)
  197.         return (entry);
  198.     return (findentry(&class->cl_functions,name));
  199. }
  200.  
  201. /* rfindmember - recursive findmember */
  202. static DICT_ENTRY *rfindmember(class,name)
  203. CLASS *class; char *name;
  204. {
  205.     DICT_ENTRY *entry;
  206.     
  207.     if ((entry = findmember(class,name)) != NULL)
  208.         return (entry);
  209.     else
  210.         if (!isnil(&class->cl_base))
  211.             return (rfindmember(claddr(&class->cl_base),name));
  212.     return (NULL);
  213. }
  214.  
  215. /* do_function - handle function declarations */
  216. static do_function(name)
  217. char *name;
  218. {
  219.     switch (token()) 
  220.     {
  221.     case '(':
  222.         do_regular_function(name);
  223.         break;
  224.     case T_CC:
  225.         check(1);
  226.         push_class(get_class(name));
  227.         do_member_function(sp);
  228.         ++sp;
  229.         break;
  230.     default:
  231.         parse_error("Expecting a function declaration");
  232.         break;
  233.     }
  234. }
  235.  
  236. /* do_regular_function - parse a regular function definition */
  237. static do_regular_function(name)
  238. char *name;
  239. {
  240.     info("Function '%s'",name);             /* enter the function name */
  241.     check(1);
  242.     push_var(addentry(&symbols,name,ST_SFUNCTION));
  243.  
  244.     set_bytecode(&sp->v.v_var->de_value,do_code(name,&nil)); /* compile the body of the function */
  245.     ++sp;
  246.  
  247.     freelist(&arguments); freelist(&temporaries);     /* free the argument and temporary symbol lists */
  248. }
  249.  
  250. /* do_member_function - parse a member function definition */
  251. static do_member_function(class)
  252. VALUE *class;
  253. {
  254.     char name[TKNSIZE+1],selector[TKNSIZE+1];
  255.     DICT_ENTRY *entry;
  256.     int tkn;
  257.     
  258.     frequire(T_IDENTIFIER);                     /* get the selector */
  259.     strcpy(selector,t_token);
  260.     frequire('(');
  261.     getcstring(name,sizeof(name),clgetname(class));
  262.     info("Member function '%s::%s'",name,selector);
  263.  
  264.     if ((entry = findmember(claddr(class),selector)) != NULL /* make sure the type matches the declaration */
  265.         &&  entry->de_type != ST_FUNCTION
  266.         &&  entry->de_type != ST_SFUNCTION)
  267.             parse_error("Illegal redefinition");
  268.  
  269.     check(1);                                 /* compile the code */
  270.     push_var(addentry(clgetfunctions(class),selector,ST_FUNCTION));
  271.     set_bytecode(&sp->v.v_var->de_value,do_code(selector,class));
  272.     ++sp;
  273.  
  274.     freelist(&arguments); freelist(&temporaries);     /* free the argument and temporary symbol lists */
  275. }
  276.  
  277. /* do_code - compile the code part of a function or method */
  278. static VECTOR *do_code(name,class)
  279. char *name; VALUE *class;
  280. {
  281.     unsigned char *src,*dst;
  282.     int tcnt=0,nlits,tkn,i;
  283.     LITERAL *lit;
  284.  
  285.     arguments = temporaries = NULL;         /* initialize */
  286.     cptr = 0;
  287.  
  288.     if (!isnil(class))                     /* add the implicit 'this' argument for member functions */
  289.         addargument(&arguments,"this");
  290.     methodclass = *class;
  291.     
  292.     get_id_list(&arguments,";)");         /* get the argument list */
  293.  
  294.     if ((tkn = token()) == ';')           /* get temporary variables */
  295.     {
  296.         tcnt = get_id_list(&temporaries,")");
  297.         tkn = token();
  298.     }
  299.     require(tkn,')');
  300.     
  301.     if (tcnt > 0)                         /* reserve space for the temporaries */
  302.     {
  303.         putcbyte(OP_TSPACE);
  304.         putcbyte(tcnt);
  305.     }
  306.  
  307.     /* store the bytecodes, class and function name as the first literals */
  308.     
  309.     addliteral(&literals,&lit);            /* will become the bytecode string */
  310.     addliteral(&literals,&lit);            /* class */
  311.     lit->lit_value = *class;
  312.     make_lit_string(name);                /* function name */
  313.  
  314.     putcbyte(OP_PUSH);                    /* compile the code */
  315.     frequire('{');
  316.     do_block();
  317.     putcbyte(OP_RETURN);
  318.  
  319.     /* count the number of literals */
  320.     
  321.     for (nlits = 0, lit = literals; lit != NULL; lit = lit->lit_next)
  322.         ++nlits;
  323.  
  324.     check(1);                             /* build the function */
  325.     push_bytecode(newvector(nlits));
  326.     
  327.     /* create the code string */
  328.     
  329.     set_string(&literals->lit_value,newstring(cptr));
  330.     src = cbuff;
  331.     dst = strgetdata(&literals->lit_value);
  332.     while (--cptr >= 0)
  333.         *dst++ = *src++;
  334.     
  335.     /* copy the literals */
  336.     
  337.     for (i = 0, lit = literals; i < nlits; ++i, lit = lit->lit_next)
  338.         vecsetelement(sp,i,lit->lit_value);
  339.     freeliterals(&literals);
  340.  
  341.     if (decode)                 /* show the generated code */
  342.         decode_procedure(sp);
  343.  
  344.     return (vecaddr(sp++));     /* return the code object */
  345. }
  346.  
  347. /* get_class - get the class associated with a symbol */
  348. static CLASS *get_class(name)
  349. char *name;
  350. {
  351.     DICT_ENTRY *sym;
  352.     
  353.     sym = findentry(&classes,name);
  354.     if (sym == NULL || sym->de_value.v_type != DT_CLASS)
  355.         parse_error("Expecting a class name");
  356.     return (claddr(&sym->de_value));
  357. }
  358.  
  359. /* do_statement - compile a single statement */
  360. static do_statement()
  361. {
  362.     int tkn;
  363.     switch (tkn = token()) 
  364.     {
  365.     case T_IF:            do_if();        break;
  366.     case T_WHILE:        do_while();        break;
  367.     case T_DO:            do_dowhile();    break;
  368.     case T_FOR:            do_for();        break;
  369.     case T_BREAK:        do_break();        break;
  370.     case T_CONTINUE:    do_continue();    break;
  371.     case T_RETURN:        do_return();    break;
  372.     case '{':            do_block();        break;
  373.     case ';':            ;                break;
  374.     default:            stoken(tkn);
  375.                         do_expr();
  376.                         frequire(';');  break;
  377.     }
  378. }
  379.  
  380. /* do_if - compile the IF/ELSE expression */
  381. static do_if()
  382. {
  383.     int tkn,nxt,end;
  384.  
  385.     do_test();                         /* compile the test expression */
  386.  
  387.     putcbyte(OP_BRF);                 /* skip around the 'then' clause if the expression is false */
  388.     nxt = putcword(0);
  389.  
  390.     do_statement();                    /* compile the 'then' clause */
  391.     
  392.     if ((tkn = token()) == T_ELSE)  /* compile the 'else' clause */
  393.     {
  394.         putcbyte(OP_BR);
  395.         end = putcword(0);
  396.         fixup(nxt,cptr);
  397.         do_statement();
  398.         nxt = end;
  399.     }
  400.     else
  401.         stoken(tkn);
  402.  
  403.     fixup(nxt,cptr);                 /* handle the end of the statement */
  404. }
  405.  
  406. /* addbreak - add a break level to the stack */
  407. static int *addbreak(lbl)
  408. int lbl;
  409. {
  410.     int *old=bsp;
  411.     
  412.     if (++bsp < &bstack[SSIZE])
  413.         *bsp = lbl;
  414.     else
  415.         parse_error("Too many nested loops");
  416.     return (old);
  417. }
  418.  
  419. /* rembreak - remove a break level from the stack */
  420. static int rembreak(old,lbl)
  421. int *old,lbl;
  422. {
  423.    return (bsp > old ? *bsp-- : lbl);
  424. }
  425.  
  426. /* addcontinue - add a continue level to the stack */
  427. static int *addcontinue(lbl)
  428. int lbl;
  429. {
  430.     int *old=csp;
  431.     
  432.     if (++csp < &cstack[SSIZE])
  433.         *csp = lbl;
  434.     else
  435.         parse_error("Too many nested loops");
  436.     return (old);
  437. }
  438.  
  439. /* remcontinue - remove a continue level from the stack */
  440. static remcontinue(old)
  441. int *old;
  442. {
  443.     csp = old;
  444. }
  445.  
  446. /* do_while - compile the WHILE expression */
  447. static do_while()
  448. {
  449.     int nxt,end,*ob,*oc;
  450.  
  451.     nxt = cptr;                 /* compile the test expression */
  452.     do_test();
  453.  
  454.     putcbyte(OP_BRF);         /* skip around the loop body if the expression is false */
  455.     end = putcword(0);
  456.  
  457.     ob = addbreak(end);         /* compile the loop body */
  458.     oc = addcontinue(nxt);
  459.     do_statement();
  460.     end = rembreak(ob,end);
  461.     remcontinue(oc);
  462.  
  463.     putcbyte(OP_BR);         /* branch back to the start of the loop */
  464.     putcword(nxt);
  465.  
  466.     fixup(end,cptr);         /* handle the end of the statement */
  467. }
  468.  
  469. /* do_dowhile - compile the DO/WHILE expression */
  470. static do_dowhile()
  471. {
  472.     int nxt,end=0,*ob,*oc;
  473.  
  474.     nxt = cptr;             /* remember the start of the loop */
  475.  
  476.     ob = addbreak(0);         /* compile the loop body */
  477.     oc = addcontinue(nxt);
  478.     do_statement();
  479.     end = rembreak(ob,end);
  480.     remcontinue(oc);
  481.  
  482.     frequire(T_WHILE);         /* compile the test expression */
  483.     do_test();
  484.     frequire(';');
  485.  
  486.     putcbyte(OP_BRT);         /* branch to the top if the expression is true */
  487.     putcword(nxt);
  488.  
  489.     fixup(end,cptr);         /* handle the end of the statement */
  490. }
  491.  
  492. /* do_for - compile the FOR statement */
  493. static do_for()
  494. {
  495.     int tkn,nxt,end,body,update,*ob,*oc;
  496.  
  497.     frequire('(');             /* compile the initialization expression */
  498.     if ((tkn = token()) != ';') 
  499.     {
  500.         stoken(tkn);
  501.         do_expr();
  502.         frequire(';');
  503.     }
  504.  
  505.     nxt = cptr;             /* compile the test expression */
  506.     if ((tkn = token()) != ';') 
  507.     {
  508.         stoken(tkn);
  509.         do_expr();
  510.         frequire(';');
  511.     }
  512.  
  513.     putcbyte(OP_BRT);         /* branch to the loop body if the expression is true */
  514.     body = putcword(0);
  515.  
  516.     putcbyte(OP_BR);         /* branch to the end if the expression is false */
  517.     end = putcword(0);
  518.  
  519.     update = cptr;             /* compile the update expression */
  520.     if ((tkn = token()) != ')') 
  521.     {
  522.         stoken(tkn);
  523.         do_expr();
  524.         frequire(')');
  525.     }
  526.  
  527.     putcbyte(OP_BR);         /* branch back to the test code */
  528.     putcword(nxt);
  529.  
  530.     fixup(body,cptr);         /* compile the loop body */
  531.     ob = addbreak(end);
  532.     oc = addcontinue(update);
  533.     do_statement();
  534.     end = rembreak(ob,end);
  535.     remcontinue(oc);
  536.  
  537.     putcbyte(OP_BR);         /* branch back to the update code */
  538.     putcword(update);
  539.  
  540.     fixup(end,cptr);         /* handle the end of the statement */
  541. }
  542.  
  543. /* do_break - compile the BREAK statement */
  544. static do_break()
  545. {
  546.     if (bsp >= bstack) 
  547.     {
  548.         putcbyte(OP_BR);
  549.         *bsp = putcword(*bsp);
  550.     }
  551.     else
  552.         parse_error("Break outside of loop");
  553. }
  554.  
  555. /* do_continue - compile the CONTINUE statement */
  556. static do_continue()
  557. {
  558.     if (csp >= cstack) 
  559.     {
  560.         putcbyte(OP_BR);
  561.         putcword(*csp);
  562.     }
  563.     else
  564.         parse_error("Continue outside of loop");
  565. }
  566.  
  567. /* do_block - compile the {} expression */
  568. static do_block()
  569. {
  570.     int tkn;
  571.     
  572.     if ((tkn = token()) != '}') 
  573.     {
  574.         do 
  575.         {
  576.             stoken(tkn);
  577.             do_statement();
  578.         } while ((tkn = token()) != '}');
  579.     }
  580.     else
  581.         putcbyte(OP_NIL);
  582. }
  583.  
  584. /* do_return - handle the RETURN expression */
  585. static do_return()
  586. {
  587.     do_expr();
  588.     frequire(';');
  589.     putcbyte(OP_RETURN);
  590. }
  591.  
  592. /* do_test - compile a test expression */
  593. static do_test()
  594. {
  595.     frequire('(');
  596.     do_expr();
  597.     frequire(')');
  598. }
  599.  
  600. /* do_expr - parse an expression */
  601. static do_expr()
  602. {
  603.     PVAL pv;
  604.     
  605.     do_expr1(&pv);
  606.     rvalue(&pv);
  607. }
  608.  
  609. /* rvalue - get the rvalue of a partial expression */
  610. static rvalue(pv)
  611. PVAL *pv;
  612. {
  613.     if (pv->fcn) 
  614.     {
  615.         (*pv->fcn)(LOAD,pv->val);
  616.         pv->fcn = NULL;
  617.     }
  618. }
  619.  
  620. /* chklvalue - make sure we've got an lvalue */
  621. static chklvalue(pv)
  622. PVAL *pv;
  623. {
  624.     if (pv->fcn == NULL)
  625.         parse_error("Expecting an lvalue");
  626. }
  627.  
  628. /* do_expr1 - handle the ',' operator */
  629. static do_expr1(pv)
  630. PVAL *pv;
  631. {
  632.     int tkn;
  633.     
  634.     do_expr2(pv);
  635.     while ((tkn = token()) == ',') 
  636.     {
  637.         rvalue(pv);
  638.         do_expr1(pv); rvalue(pv);
  639.     }
  640.     stoken(tkn);
  641. }
  642.  
  643. /* do_expr2 - handle the assignment operators */
  644. static do_expr2(pv)
  645. PVAL *pv;
  646. {
  647.     int tkn,nxt,end;
  648.     PVAL rhs;
  649.     
  650.     do_expr3(pv);
  651.     while ((tkn = token()) == '='
  652.                 ||     tkn == T_ADDEQ || tkn == T_SUBEQ
  653.                 ||     tkn == T_MULEQ || tkn == T_DIVEQ || tkn == T_REMEQ
  654.                 ||     tkn == T_ANDEQ || tkn == T_OREQ  || tkn == T_XOREQ
  655.                 ||     tkn == T_SHLEQ || tkn == T_SHLEQ) 
  656.     {
  657.         chklvalue(pv);
  658.         switch (tkn) 
  659.         {
  660.         case '=':
  661.                             (*pv->fcn)(PUSH);
  662.                             do_expr1(&rhs); rvalue(&rhs);
  663.                             (*pv->fcn)(STORE,pv->val);
  664.                             break;
  665.         case T_ADDEQ:        do_assignment(pv,OP_ADD);        break;
  666.         case T_SUBEQ:        do_assignment(pv,OP_SUB);        break;
  667.         case T_MULEQ:        do_assignment(pv,OP_MUL);        break;
  668.         case T_DIVEQ:        do_assignment(pv,OP_DIV);        break;
  669.         case T_REMEQ:        do_assignment(pv,OP_REM);        break;
  670.         case T_ANDEQ:        do_assignment(pv,OP_BAND);        break;
  671.         case T_OREQ:        do_assignment(pv,OP_BOR);        break;
  672.         case T_XOREQ:        do_assignment(pv,OP_XOR);        break;
  673.         case T_SHLEQ:        do_assignment(pv,OP_SHL);        break;
  674.         case T_SHREQ:        do_assignment(pv,OP_SHR);        break;
  675.         }
  676.         pv->fcn = NULL;
  677.     }
  678.     stoken(tkn);
  679. }
  680.  
  681. /* do_assignment - handle assignment operations */
  682. static do_assignment(pv,op)
  683. PVAL *pv; int op;
  684. {
  685.     PVAL rhs;
  686.     
  687.     (*pv->fcn)(DUP);
  688.     (*pv->fcn)(LOAD,pv->val);
  689.     putcbyte(OP_PUSH);
  690.     do_expr1(&rhs); rvalue(&rhs);
  691.     putcbyte(op);
  692.     (*pv->fcn)(STORE,pv->val);
  693. }
  694.  
  695. /* do_expr3 - handle the '?:' operator */
  696. static do_expr3(pv)
  697. PVAL *pv;
  698. {
  699.     int tkn,nxt,end;
  700.     
  701.     do_expr4(pv);
  702.     while ((tkn = token()) == '?') 
  703.     {
  704.         rvalue(pv);
  705.         putcbyte(OP_BRF);
  706.         nxt = putcword(0);
  707.         do_expr1(pv); rvalue(pv);
  708.         frequire(':');
  709.         putcbyte(OP_BR);
  710.         end = putcword(0);
  711.         fixup(nxt,cptr);
  712.         do_expr1(pv); rvalue(pv);
  713.         fixup(end,cptr);
  714.     }
  715.     stoken(tkn);
  716. }
  717.  
  718. /* do_expr4 - handle the '||' operator */
  719. static do_expr4(pv)
  720. PVAL *pv;
  721. {
  722.     int tkn,end=0;
  723.     
  724.     do_expr5(pv);
  725.     while ((tkn = token()) == T_OR) 
  726.     {
  727.         rvalue(pv);
  728.         putcbyte(OP_BRT);
  729.         end = putcword(end);
  730.         do_expr5(pv); rvalue(pv);
  731.     }
  732.     fixup(end,cptr);
  733.     stoken(tkn);
  734. }
  735.  
  736. /* do_expr5 - handle the '&&' operator */
  737. static do_expr5(pv)
  738. PVAL *pv;
  739. {
  740.     int tkn,end=0;
  741.     
  742.     do_expr6(pv);
  743.     while ((tkn = token()) == T_AND) 
  744.     {
  745.         rvalue(pv);
  746.         putcbyte(OP_BRF);
  747.         end = putcword(end);
  748.         do_expr6(pv); rvalue(pv);
  749.     }
  750.     fixup(end,cptr);
  751.     stoken(tkn);
  752. }
  753.  
  754. /* do_expr6 - handle the '|' operator */
  755. static do_expr6(pv)
  756. PVAL *pv;
  757. {
  758.     int tkn;
  759.     
  760.     do_expr7(pv);
  761.     while ((tkn = token()) == '|') 
  762.     {
  763.         rvalue(pv);
  764.         putcbyte(OP_PUSH);
  765.         do_expr7(pv); rvalue(pv);
  766.         putcbyte(OP_BOR);
  767.     }
  768.     stoken(tkn);
  769. }
  770.  
  771. /* do_expr7 - handle the '^' operator */
  772. static do_expr7(pv)
  773. PVAL *pv;
  774. {
  775.     int tkn;
  776.     
  777.     do_expr8(pv);
  778.     while ((tkn = token()) == '^') 
  779.     {
  780.         rvalue(pv);
  781.         putcbyte(OP_PUSH);
  782.         do_expr8(pv); rvalue(pv);
  783.         putcbyte(OP_XOR);
  784.     }
  785.     stoken(tkn);
  786. }
  787.  
  788. /* do_expr8 - handle the '&' operator */
  789. static do_expr8(pv)
  790. PVAL *pv;
  791. {
  792.     int tkn;
  793.     
  794.     do_expr9(pv);
  795.     while ((tkn = token()) == '&') 
  796.     {
  797.         rvalue(pv);
  798.         putcbyte(OP_PUSH);
  799.         do_expr9(pv); rvalue(pv);
  800.         putcbyte(OP_BAND);
  801.     }
  802.     stoken(tkn);
  803. }
  804.  
  805. /* do_expr9 - handle the '==' and '!=' operators */
  806. static do_expr9(pv)
  807. PVAL *pv;
  808. {
  809.     int tkn,op;
  810.     
  811.     do_expr10(pv);
  812.     while ((tkn = token()) == T_EQ || tkn == T_NE) 
  813.     {
  814.         switch (tkn) 
  815.         {
  816.         case T_EQ: op = OP_EQ; break;
  817.         case T_NE: op = OP_NE; break;
  818.         }
  819.         rvalue(pv);
  820.         putcbyte(OP_PUSH);
  821.         do_expr10(pv); rvalue(pv);
  822.         putcbyte(op);
  823.     }
  824.     stoken(tkn);
  825. }
  826.  
  827. /* do_expr10 - handle the '<', '<=', '>=' and '>' operators */
  828. static do_expr10(pv)
  829. PVAL *pv;
  830. {
  831.     int tkn,op;
  832.     
  833.     do_expr11(pv);
  834.     while ((tkn = token()) == '<' || tkn == T_LE || tkn == T_GE || tkn == '>') 
  835.     {
  836.         switch (tkn) 
  837.         {
  838.         case '<':  op = OP_LT; break;
  839.         case T_LE: op = OP_LE; break;
  840.         case T_GE: op = OP_GE; break;
  841.         case '>':  op = OP_GT; break;
  842.         }
  843.         rvalue(pv);
  844.         putcbyte(OP_PUSH);
  845.         do_expr11(pv); rvalue(pv);
  846.         putcbyte(op);
  847.     }
  848.     stoken(tkn);
  849. }
  850.  
  851. /* do_expr11 - handle the '<<' and '>>' operators */
  852. static do_expr11(pv)
  853. PVAL *pv;
  854. {
  855.     int tkn,op;
  856.     
  857.     do_expr12(pv);
  858.     while ((tkn = token()) == T_SHL || tkn == T_SHR) 
  859.     {
  860.         switch (tkn) 
  861.         {
  862.         case T_SHL: op = OP_SHL; break;
  863.         case T_SHR: op = OP_SHR; break;
  864.         }
  865.         rvalue(pv);
  866.         putcbyte(OP_PUSH);
  867.         do_expr12(pv); rvalue(pv);
  868.         putcbyte(op);
  869.     }
  870.     stoken(tkn);
  871. }
  872.  
  873. /* do_expr12 - handle the '+' and '-' operators */
  874. static do_expr12(pv)
  875. PVAL *pv;
  876. {
  877.     int tkn,op;
  878.     
  879.     do_expr13(pv);
  880.     while ((tkn = token()) == '+' || tkn == '-') 
  881.     {
  882.         switch (tkn) 
  883.         {
  884.         case '+': op = OP_ADD; break;
  885.         case '-': op = OP_SUB; break;
  886.         }
  887.         rvalue(pv);
  888.         putcbyte(OP_PUSH);
  889.         do_expr13(pv); rvalue(pv);
  890.         putcbyte(op);
  891.     }
  892.     stoken(tkn);
  893. }
  894.  
  895. /* do_expr13 - handle the '*' and '/' operators */
  896. static do_expr13(pv)
  897. PVAL *pv;
  898. {
  899.     int tkn,op;
  900.     
  901.     do_expr14(pv);
  902.     while ((tkn = token()) == '*' || tkn == '/' || tkn == '%') 
  903.     {
  904.         switch (tkn) 
  905.         {
  906.         case '*': op = OP_MUL; break;
  907.         case '/': op = OP_DIV; break;
  908.         case '%': op = OP_REM; break;
  909.         }
  910.         rvalue(pv);
  911.         putcbyte(OP_PUSH);
  912.         do_expr14(pv); rvalue(pv);
  913.         putcbyte(op);
  914.     }
  915.     stoken(tkn);
  916. }
  917.  
  918. /* do_expr14 - handle unary operators */
  919. static do_expr14(pv)
  920. PVAL *pv;
  921. {
  922.     int tkn;
  923.     
  924.     switch (tkn = token()) 
  925.     {
  926.     case '-':
  927.         do_expr15(pv); rvalue(pv);
  928.         putcbyte(OP_NEG);
  929.         break;
  930.     case '!':
  931.         do_expr15(pv); rvalue(pv);
  932.         putcbyte(OP_NOT);
  933.         break;
  934.     case '~':
  935.         do_expr15(pv); rvalue(pv);
  936.         putcbyte(OP_BNOT);
  937.         break;
  938.     case T_INC:
  939.         do_preincrement(pv,OP_INC);
  940.         break;
  941.     case T_DEC:
  942.         do_preincrement(pv,OP_DEC);
  943.         break;
  944.     case T_NEW:
  945.         do_new(pv);
  946.         break;
  947.     default:
  948.         stoken(tkn);
  949.         do_expr15(pv);
  950.         return;
  951.     }
  952. }
  953.  
  954. /* do_preincrement - handle prefix '++' and '--' */
  955. static do_preincrement(pv,op)
  956. PVAL *pv;
  957. {
  958.     do_expr15(pv);
  959.     chklvalue(pv);
  960.     (*pv->fcn)(DUP);
  961.     (*pv->fcn)(LOAD,pv->val);
  962.     putcbyte(op);
  963.     (*pv->fcn)(STORE,pv->val);
  964.     pv->fcn = NULL;
  965. }
  966.  
  967. /* do_postincrement - handle postfix '++' and '--' */
  968. static do_postincrement(pv,op)
  969. PVAL *pv;
  970. {
  971.     chklvalue(pv);
  972.     (*pv->fcn)(DUP);
  973.     (*pv->fcn)(LOAD,pv->val);
  974.     putcbyte(op);
  975.     (*pv->fcn)(STORE,pv->val);
  976.     putcbyte(op == OP_INC ? OP_DEC : OP_INC);
  977.     pv->fcn = NULL;
  978. }
  979.  
  980. /* do_new - handle the 'new' operator */
  981. static do_new(pv)
  982. PVAL *pv;
  983. {
  984.     char selector[TKNSIZE+1];
  985.     LITERAL *lit;
  986.     CLASS *class;
  987.  
  988.     frequire(T_IDENTIFIER);
  989.     strcpy(selector,t_token);
  990.  
  991.     class = get_class(selector);
  992.  
  993.     code_literal(addliteral(&literals,&lit));
  994.     set_class(&lit->lit_value,class);
  995.  
  996.     putcbyte(OP_NEW);
  997.     pv->fcn = NULL;
  998.     
  999.     do_send(selector,pv);
  1000. }
  1001.  
  1002. /* do_expr15 - handle function calls */
  1003. static do_expr15(pv)
  1004. PVAL *pv;
  1005. {
  1006.     char selector[TKNSIZE+1];
  1007.     int tkn;
  1008.     do_primary(pv);
  1009.     
  1010.     while ((tkn = token()) == '(' || tkn == '[' || tkn == T_MEMREF
  1011.                         || tkn == T_INC || tkn == T_DEC)
  1012.     {                    
  1013.         switch (tkn) 
  1014.         {
  1015.         case '(':
  1016.             do_call(pv);
  1017.             break;
  1018.         case '[':
  1019.             do_index(pv);
  1020.             break;
  1021.         case T_MEMREF:
  1022.             frequire(T_IDENTIFIER);
  1023.             strcpy(selector,t_token);
  1024.             do_send(selector,pv);
  1025.             break;
  1026.         case T_INC:
  1027.             do_postincrement(pv,OP_INC);
  1028.             break;
  1029.         case T_DEC:
  1030.             do_postincrement(pv,OP_DEC);
  1031.             break;
  1032.         }
  1033.     }    
  1034.     stoken(tkn);
  1035. }
  1036.  
  1037. /* do_primary - parse a primary expression and unary operators */
  1038. static do_primary(pv)
  1039. PVAL *pv;
  1040. {
  1041.     char id[TKNSIZE+1];
  1042.     DICT_ENTRY *entry;
  1043.     CLASS *class;
  1044.     int tkn;
  1045.     
  1046.     switch (token()) 
  1047.     {
  1048.     case '(':
  1049.         do_expr1(pv);
  1050.         frequire(')');
  1051.         break;
  1052.     case T_NUMBER:
  1053.         do_lit_integer((long)t_value);
  1054.         pv->fcn = NULL;
  1055.         break;
  1056.     case T_STRING:
  1057.         do_lit_string(t_token);
  1058.         pv->fcn = NULL;
  1059.         break;
  1060.     case T_NIL:
  1061.         putcbyte(OP_NIL);
  1062.         break;
  1063.     case T_IDENTIFIER:
  1064.         strcpy(id,t_token);
  1065.         if ((tkn = token()) == T_CC) 
  1066.         {
  1067.             class = get_class(id);
  1068.             frequire(T_IDENTIFIER);
  1069.             if (!findclassvariable(class,t_token,pv))
  1070.             parse_error("Not a class member");
  1071.         }
  1072.         else 
  1073.         {
  1074.             stoken(tkn);
  1075.             findvariable(id,pv);
  1076.         }
  1077.         break;
  1078.     default:
  1079.         parse_error("Expecting a primary expression");
  1080.         break;
  1081.     }
  1082. }
  1083.  
  1084. /* do_call - compile a function call */
  1085. static do_call(pv)
  1086. PVAL *pv;
  1087. {
  1088.     int tkn,n=0;
  1089.     
  1090.     rvalue(pv);                                /* get the value of the function */
  1091.  
  1092.     if ((tkn = token()) != ')')              /* compile each argument expression */
  1093.     {
  1094.         stoken(tkn);
  1095.         do 
  1096.         {
  1097.             putcbyte(OP_PUSH);
  1098.             do_expr2(pv); rvalue(pv);
  1099.             ++n;
  1100.         } while ((tkn = token()) == ',');
  1101.     }
  1102.     require(tkn,')');
  1103.     putcbyte(OP_CALL);
  1104.     putcbyte(n);
  1105.  
  1106.     pv->fcn = NULL;                         /* we've got an rvalue now */
  1107. }
  1108.  
  1109. /* do_send - compile a message sending expression */
  1110. static do_send(selector,pv)
  1111. char *selector; PVAL *pv;
  1112. {
  1113.     LITERAL *lit;
  1114.     int tkn,n=1;
  1115.     
  1116.     rvalue(pv);                         /* get the receiver value */
  1117.  
  1118.     putcbyte(OP_PUSH);                     /* generate code to push the selector */
  1119.     code_literal(addliteral(&literals,&lit));
  1120.     set_string(&lit->lit_value,makestring(selector));
  1121.  
  1122.     frequire('(');                         /* compile the argument list */
  1123.     if ((tkn = token()) != ')') 
  1124.     {
  1125.         stoken(tkn);
  1126.         do 
  1127.         {
  1128.             putcbyte(OP_PUSH);
  1129.             do_expr2(pv); rvalue(pv);
  1130.             ++n;
  1131.         } while ((tkn = token()) == ',');
  1132.     }
  1133.     require(tkn,')');
  1134.  
  1135.     putcbyte(OP_SEND);                     /* send the message */
  1136.     putcbyte(n);
  1137.  
  1138.     pv->fcn = NULL;                     /* we've got an rvalue now */
  1139. }
  1140.  
  1141. /* do_index - compile an indexing operation */
  1142. static do_index(pv)
  1143. PVAL *pv;
  1144. {
  1145.     int code_index();
  1146.     
  1147.     rvalue(pv);
  1148.     putcbyte(OP_PUSH);
  1149.     do_expr(pv);
  1150.     frequire(']');
  1151.     pv->fcn = code_index;
  1152. }
  1153.  
  1154. /* get_id_list - get a comma separated list of identifiers */
  1155. static int get_id_list(list,term)
  1156. ARGUMENT **list; char *term;
  1157. {
  1158.     char *strchr();
  1159.     int tkn,cnt=0;
  1160.     
  1161.     tkn = token();
  1162.     if (!strchr(term,tkn)) 
  1163.     {
  1164.         stoken(tkn);
  1165.         do 
  1166.         {
  1167.             frequire(T_IDENTIFIER);
  1168.             addargument(list,t_token);
  1169.             ++cnt;
  1170.         } while ((tkn = token()) == ',');
  1171.     }
  1172.     stoken(tkn);
  1173.     return (cnt);
  1174. }
  1175.  
  1176. /* addargument - add a formal argument */
  1177. static addargument(list,name)
  1178. ARGUMENT **list; char *name;
  1179. {
  1180.     ARGUMENT *arg;
  1181.     
  1182.     arg = (ARGUMENT *)getmemory(sizeof(ARGUMENT));
  1183.     arg->arg_name = copystring(name);
  1184.     arg->arg_next = *list;
  1185.     *list = arg;
  1186. }
  1187.  
  1188. /* freelist - free a list of arguments or temporaries */
  1189. static freelist(plist)
  1190. ARGUMENT **plist;
  1191. {
  1192.     ARGUMENT *this,*next;
  1193.     
  1194.     for (this = *plist, *plist = NULL; this != NULL; this = next) 
  1195.     {
  1196.         next = this->arg_next;
  1197.         free(this->arg_name);
  1198.         free(this);
  1199.     }
  1200. }
  1201.  
  1202. /* findarg - find an argument offset */
  1203. static int findarg(name)
  1204. char *name;
  1205. {
  1206.     ARGUMENT *arg;
  1207.     int n;
  1208.     
  1209.     for (n = 0, arg = arguments; arg; n++, arg = arg->arg_next)
  1210.         if (strcmp(name,arg->arg_name) == 0)
  1211.             return (n);
  1212.     return (-1);
  1213. }
  1214.  
  1215. /* findtmp - find a temporary variable offset */
  1216. static int findtmp(name)
  1217. char *name;
  1218. {
  1219.     ARGUMENT *tmp;
  1220.     int n;
  1221.     
  1222.     for (n = 0, tmp = temporaries; tmp; n++, tmp = tmp->arg_next)
  1223.         if (strcmp(name,tmp->arg_name) == 0)
  1224.             return (n);
  1225.     return (-1);
  1226. }
  1227.  
  1228. /* finddatamember - find a class data member */
  1229. static DICT_ENTRY *finddatamember(name)
  1230. char *name;
  1231. {
  1232.     DICT_ENTRY *entry;
  1233.     VALUE *class;
  1234.     
  1235.     if (!isnil(class)) 
  1236.     {
  1237.         class = &methodclass;
  1238.         do 
  1239.         {
  1240.             if ((entry = findentry(clgetmembers(class),name)) != NULL)
  1241.             return (entry);
  1242.             class = clgetbase(class);
  1243.         } while (!isnil(class));
  1244.     }
  1245.     return (NULL);
  1246. }
  1247.  
  1248. /* addliteral - add a literal */
  1249. static int addliteral(list,pval)
  1250. LITERAL **list,**pval;
  1251. {
  1252.     LITERAL **plit,*lit;
  1253.     int n=0;
  1254.     
  1255.     for (plit = list; (lit = *plit) != NULL; plit = &lit->lit_next)
  1256.         ++n;
  1257.     lit = (LITERAL *)getmemory(sizeof(LITERAL));
  1258.     set_nil(&lit->lit_value);
  1259.     lit->lit_next = NULL;
  1260.     *pval = *plit = lit;
  1261.     return (n);
  1262. }
  1263.  
  1264. /* freeliterals - free a list of literals */
  1265. static freeliterals(plist)
  1266. LITERAL **plist;
  1267. {
  1268.     LITERAL *this,*next;
  1269.     for (this = *plist, *plist = NULL; this != NULL; this = next) 
  1270.     {
  1271.         next = this->lit_next;
  1272.         free(this);
  1273.     }
  1274. }
  1275.  
  1276. /* frequire - fetch a token and check it */
  1277. static frequire(rtkn)
  1278. int rtkn;
  1279. {
  1280.     require(token(),rtkn);
  1281. }
  1282.  
  1283. /* require - check for a required token */
  1284. static require(tkn,rtkn)
  1285. int tkn,rtkn;
  1286. {
  1287.     char msg[100],tknbuf[100],*tkn_name();
  1288.     
  1289.     if (tkn != rtkn) 
  1290.     {
  1291.         strcpy(tknbuf,tkn_name(rtkn));
  1292.         sprintf(msg,"Expecting '%s', found '%s'",tknbuf,tkn_name(tkn));
  1293.         parse_error(msg);
  1294.     }
  1295. }
  1296.  
  1297. /* do_lit_integer - compile a literal integer */
  1298. static do_lit_integer(n)
  1299. long n;
  1300. {
  1301.     LITERAL *lit;
  1302.     
  1303.     code_literal(addliteral(&literals,&lit));
  1304.     set_integer(&lit->lit_value,n);
  1305. }
  1306.  
  1307. /* do_lit_string - compile a literal string */
  1308. static do_lit_string(str)
  1309. char *str;
  1310. {
  1311.     code_literal(make_lit_string(str));
  1312. }
  1313.  
  1314. /* make_lit_string - make a literal string */
  1315. static int make_lit_string(str)
  1316. char *str;
  1317. {
  1318.     LITERAL *lit;
  1319.     int n;
  1320.     
  1321.     n = addliteral(&literals,&lit);
  1322.     set_string(&lit->lit_value,makestring(str));
  1323.     return (n);
  1324. }
  1325.  
  1326. /* make_lit_variable - make a literal reference to a variable */
  1327. static int make_lit_variable(sym)
  1328. DICT_ENTRY *sym;
  1329. {
  1330.     LITERAL *lit;
  1331.     int n;
  1332.     
  1333.     n = addliteral(&literals,&lit);
  1334.     set_var(&lit->lit_value,sym);
  1335.     return (n);
  1336. }
  1337.  
  1338. /* findvariable - find a variable */
  1339. static findvariable(id,pv)
  1340. char *id; PVAL *pv;
  1341. {    
  1342.     int code_argument(),code_temporary(),code_variable();
  1343.     DICT_ENTRY *entry;
  1344.     int n;
  1345.     
  1346.     if ((n = findarg(id)) >= 0) 
  1347.     {
  1348.         pv->fcn = code_argument;
  1349.         pv->val = n;
  1350.     }
  1351.     else 
  1352.         if ((n = findtmp(id)) >= 0) 
  1353.         {
  1354.         pv->fcn = code_temporary;
  1355.         pv->val = n;
  1356.         }
  1357.         else 
  1358.             if (isnil(&methodclass) || !findclassvariable(claddr(&methodclass),
  1359.                     id,pv)) 
  1360.             {
  1361.                 pv->fcn = code_variable;
  1362.                 pv->val = make_lit_variable(addentry(&symbols,id,ST_SDATA));
  1363.             }
  1364. }
  1365.  
  1366. /* findclassvariable - find a class member variable */
  1367. static int findclassvariable(class,name,pv)
  1368. CLASS *class; char *name; PVAL *pv;
  1369. {
  1370.     int code_member(),code_variable();
  1371.     DICT_ENTRY *entry;
  1372.     
  1373.     if ((entry = rfindmember(class,name)) == NULL)
  1374.         return (FALSE);
  1375.     switch (entry->de_type) 
  1376.     {
  1377.     case ST_DATA:
  1378.         pv->fcn = code_member;
  1379.         pv->val = entry->de_value.v.v_integer;
  1380.         break;
  1381.     case ST_SDATA:
  1382.         pv->fcn = code_variable;
  1383.            pv->val = make_lit_variable(entry);
  1384.         break;
  1385.     case ST_FUNCTION:
  1386.         findvariable("this",pv);
  1387.         do_send(name,pv);
  1388.         break;
  1389.     case ST_SFUNCTION:
  1390.         code_variable(LOAD,make_lit_variable(entry));
  1391.         pv->fcn = NULL;
  1392.         break;
  1393.     }
  1394.     return (TRUE);
  1395. }
  1396.  
  1397. /* code_argument - compile an argument reference */
  1398. static code_argument(fcn,n)
  1399. int fcn,n;
  1400. {
  1401.     switch (fcn) 
  1402.     {
  1403.     case LOAD:    putcbyte(OP_AREF); putcbyte(n); break;
  1404.     case STORE:    putcbyte(OP_ASET); putcbyte(n); break;
  1405.     }
  1406. }
  1407.  
  1408. /* code_temporary - compile a temporary variable reference */
  1409. static code_temporary(fcn,n)
  1410. int fcn,n;
  1411. {
  1412.     switch (fcn) 
  1413.     {
  1414.     case LOAD:    putcbyte(OP_TREF); putcbyte(n); break;
  1415.     case STORE:    putcbyte(OP_TSET); putcbyte(n); break;
  1416.     }
  1417. }
  1418.  
  1419. /* code_member - compile a data member reference */
  1420. static code_member(fcn,n)
  1421. int fcn,n;
  1422. {
  1423.     switch (fcn) 
  1424.     {
  1425.     case LOAD:    putcbyte(OP_MREF); putcbyte(n); break;
  1426.     case STORE:    putcbyte(OP_MSET); putcbyte(n); break;
  1427.     }
  1428. }
  1429.  
  1430. /* code_variable - compile a variable reference */
  1431. static code_variable(fcn,n)
  1432. int fcn,n;
  1433. {
  1434.     switch (fcn) 
  1435.     {
  1436.     case LOAD:    putcbyte(OP_REF); putcbyte(n); break;
  1437.     case STORE:    putcbyte(OP_SET); putcbyte(n); break;
  1438.     }
  1439. }
  1440.  
  1441. /* code_index - compile an indexed reference */
  1442. static code_index(fcn)
  1443. int fcn;
  1444. {
  1445.     switch (fcn) 
  1446.     {
  1447.     case LOAD:    putcbyte(OP_VREF); break;
  1448.     case STORE:    putcbyte(OP_VSET); break;
  1449.     case PUSH:  putcbyte(OP_PUSH); break;
  1450.     case DUP:    putcbyte(OP_DUP2); break;
  1451.     }
  1452. }
  1453.  
  1454. /* code_literal - compile a literal reference */
  1455. static code_literal(n)
  1456. int n;
  1457. {
  1458.     putcbyte(OP_LIT);
  1459.     putcbyte(n);
  1460. }
  1461.  
  1462. /* putcbyte - put a code byte into data space */
  1463. static int putcbyte(b)
  1464. int b;
  1465. {
  1466.     if (cptr >= CMAX)
  1467.         parse_error("Insufficient code space");
  1468.     cbuff[cptr] = b;
  1469.     return (cptr++);
  1470. }
  1471.  
  1472. /* putcword - put a code word into data space */
  1473. static int putcword(w)
  1474. int w;
  1475. {
  1476.     putcbyte(w);
  1477.     putcbyte(w >> 8);
  1478.     return (cptr-2);
  1479. }
  1480.  
  1481. /* fixup - fixup a reference chain */
  1482. static fixup(chn,val)
  1483. int chn,val;
  1484. {
  1485.     int hval,nxt;
  1486.     
  1487.     for (hval = val >> 8; chn != 0; chn = nxt) 
  1488.     {
  1489.         nxt = (cbuff[chn] & 0xFF) | (cbuff[chn+1] << 8);
  1490.         cbuff[chn] = val;
  1491.         cbuff[chn+1] = hval;
  1492.     }
  1493. }
  1494.  
  1495. /* copystring - make a copy of a string */
  1496. static char *copystring(str)
  1497. char *str;
  1498. {
  1499.     char *val;
  1500.     
  1501.     val = getmemory(strlen(str)+1);
  1502.     strcpy(val,str);
  1503.     return (val);
  1504. }
  1505.  
  1506. /* getmemory - allocate memory and complain if there isn't enough */
  1507. static char *getmemory(size)
  1508. int size;
  1509. {
  1510.     char *calloc(),*val;
  1511.     
  1512.     if ((val = calloc(1,size)) == NULL)
  1513.         error("Insufficient memory");
  1514.     return (val);
  1515. }
  1516.