home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1991 / 09 / bob / bobcom.c < prev    next >
Text File  |  1991-07-10  |  31KB  |  1,427 lines

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