home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / Epoc / Palmtime / files / FrotzCE2_src.ZIP / FrotzCE / Frotz / PROCESS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-14  |  13.0 KB  |  767 lines

  1. /*
  2.  * process.c
  3.  *
  4.  * Interpreter loop and program control
  5.  *
  6.  */
  7.  
  8. #include "frotz.h"
  9.  
  10. #define MAX_CALL_LEVEL 3
  11.  
  12. zword zargs[8];
  13. int zargc;
  14.  
  15. static zword saved_zargs[MAX_CALL_LEVEL][8];
  16. static int saved_zargc[MAX_CALL_LEVEL];
  17.  
  18. static call_level = 0;
  19. static finished = 0;
  20.  
  21. void __extended__ (void);
  22. void __illegal__ (void);
  23.  
  24. void (*op0_opcodes[0x10]) (void) = {
  25.     z_rtrue,
  26.     z_rfalse,
  27.     z_print,
  28.     z_print_ret,
  29.     z_nop,
  30.     z_save,
  31.     z_restore,
  32.     z_restart,
  33.     z_ret_popped,
  34.     z_catch,
  35.     z_quit,
  36.     z_new_line,
  37.     z_show_status,
  38.     z_verify,
  39.     __extended__,
  40.     z_piracy
  41. };
  42.  
  43. void (*op1_opcodes[0x10]) (void) = {
  44.     z_jz,
  45.     z_get_sibling,
  46.     z_get_child,
  47.     z_get_parent,
  48.     z_get_prop_len,
  49.     z_inc,
  50.     z_dec,
  51.     z_print_addr,
  52.     z_call_s,
  53.     z_remove_obj,
  54.     z_print_obj,
  55.     z_ret,
  56.     z_jump,
  57.     z_print_paddr,
  58.     z_load,
  59.     z_call_n
  60. };
  61.  
  62. void (*var_opcodes[0x40]) (void) = {
  63.     __illegal__,
  64.     z_je,
  65.     z_jl,
  66.     z_jg,
  67.     z_dec_chk,
  68.     z_inc_chk,
  69.     z_jin,
  70.     z_test,
  71.     z_or,
  72.     z_and,
  73.     z_test_attr,
  74.     z_set_attr,
  75.     z_clear_attr,
  76.     z_store,
  77.     z_insert_obj,
  78.     z_loadw,
  79.     z_loadb,
  80.     z_get_prop,
  81.     z_get_prop_addr,
  82.     z_get_next_prop,
  83.     z_add,
  84.     z_sub,
  85.     z_mul,
  86.     z_div,
  87.     z_mod,
  88.     z_call_s,
  89.     z_call_n,
  90.     z_set_colour,
  91.     z_throw,
  92.     __illegal__,
  93.     __illegal__,
  94.     __illegal__,
  95.     z_call_s,
  96.     z_storew,
  97.     z_storeb,
  98.     z_put_prop,
  99.     z_read,
  100.     z_print_char,
  101.     z_print_num,
  102.     z_random,
  103.     z_push,
  104.     z_pull,
  105.     z_split_window,
  106.     z_set_window,
  107.     z_call_s,
  108.     z_erase_window,
  109.     z_erase_line,
  110.     z_set_cursor,
  111.     z_get_cursor,
  112.     z_set_text_style,
  113.     z_buffer_mode,
  114.     z_output_stream,
  115.     z_input_stream,
  116.     z_sound_effect,
  117.     z_read_char,
  118.     z_scan_table,
  119.     z_not,
  120.     z_call_n,
  121.     z_call_n,
  122.     z_tokenise,
  123.     z_encode_text,
  124.     z_copy_table,
  125.     z_print_table,
  126.     z_check_arg_count
  127. };
  128.  
  129. void (*ext_opcodes[0x1d]) (void) = {
  130.     z_save,
  131.     z_restore,
  132.     z_log_shift,
  133.     z_art_shift,
  134.     z_set_font,
  135.     z_draw_picture,
  136.     z_picture_data,
  137.     z_erase_picture,
  138.     z_set_margins,
  139.     z_save_undo,
  140.     z_restore_undo,
  141.     __illegal__,
  142.     __illegal__,
  143.     __illegal__,
  144.     __illegal__,
  145.     __illegal__,
  146.     z_move_window,
  147.     z_window_size,
  148.     z_window_style,
  149.     z_get_wind_prop,
  150.     z_scroll_window,
  151.     z_pop_stack,
  152.     z_read_mouse,
  153.     z_mouse_window,
  154.     z_push_stack,
  155.     z_put_wind_prop,
  156.     z_print_form,
  157.     z_make_menu,
  158.     z_picture_table
  159. };
  160.  
  161. /*
  162.  * save_operands
  163.  *
  164.  * Save the values of the operands and the operand count.
  165.  *
  166.  */
  167.  
  168. static void save_operands (void)
  169. {
  170.     int i;
  171.  
  172.     if (++call_level >= MAX_CALL_LEVEL)
  173.     call_level -= MAX_CALL_LEVEL;
  174.  
  175.     for (i = 0; i < 8; i++)
  176.     saved_zargs[call_level][i] = zargs[i];
  177.  
  178.     saved_zargc[call_level] = zargc;
  179.  
  180. }/* save_operands */
  181.  
  182. /*
  183.  * restore_operands
  184.  *
  185.  * Restore the values of the operands and the operand count.
  186.  *
  187.  */
  188.  
  189. static void restore_operands (void)
  190. {
  191.     int i;
  192.  
  193.     for (i = 0; i < 8; i++)
  194.     zargs[i] = saved_zargs[call_level][i];
  195.  
  196.     zargc = saved_zargc[call_level];
  197.  
  198.     if (--call_level < 0)
  199.     call_level += MAX_CALL_LEVEL;
  200.  
  201. }/* restore_operands */
  202.  
  203. /*
  204.  * call
  205.  *
  206.  * Call a subroutine. Save PC and FP then load new PC and initialise
  207.  * new stack frame. Note that the caller may legally provide less or
  208.  * more arguments than the function actually has. The call type "ct"
  209.  * can be 0 (z_call_s), 1 (z_call_n) or 2 (direct call).
  210.  *
  211.  */
  212.  
  213. void call (zword routine, int argc, zword *args, int ct)
  214. {
  215.     long pc;
  216.     zword value;
  217.     zbyte count;
  218.     int i;
  219.  
  220.     if (sp - stack < 4 + argc)
  221.     runtime_error ("Stack overflow");
  222.  
  223.     GET_PC (pc)
  224.  
  225.     *--sp = ZWORD (pc >> 9);        /* for historical reasons */
  226.     *--sp = ZWORD (pc & 0x1ff);        /* Frotz keeps its stack  */
  227.     *--sp = ZWORD (fp - stack - 1);    /* format compatible with */
  228.     *--sp = ZWORD (argc | (ct << 8));    /* Mark Howell's Zip      */
  229.  
  230.     fp = sp;
  231.  
  232.     /* Calculate byte address of routine */
  233.  
  234.     if (h_version <= V3)
  235.     pc = (long) routine << 1;
  236.     else if (h_version <= V5)
  237.     pc = (long) routine << 2;
  238.     else if (h_version <= V7)
  239.     pc = ((long) routine << 2) + ((long) h_functions_offset << 3);
  240.     else /* h_version == V8 */
  241.     pc = (long) routine << 3;
  242.  
  243.     if (pc >= story_size)
  244.     runtime_error ("Call to illegal address");
  245.  
  246.     SET_PC (pc)
  247.  
  248.     /* Initialise local variables */
  249.  
  250.     CODE_BYTE (count)
  251.  
  252.     if (count > 15)
  253.     runtime_error ("Call to non-routine");
  254.  
  255.     value = 0;
  256.  
  257.     for (i = 0; i < count; i++) {
  258.  
  259.     if (h_version <= V4)        /* V1 to V4 games provide default */
  260.         CODE_WORD (value)        /* values for all local variables */
  261.  
  262.     *--sp = ZWORD ((argc-- > 0) ? args[i] : value);
  263.  
  264.     }
  265.  
  266. }/* call */
  267.  
  268. /*
  269.  * ret
  270.  *
  271.  * Return from the current subroutine and restore the previous stack
  272.  * frame. The result may be stored (0), thrown away (1) or pushed on
  273.  * the stack (2). In the latter case a direct call has been finished
  274.  * and we must restore the operands and exit the interpreter loop.
  275.  *
  276.  */
  277.  
  278. void ret (zword value)
  279. {
  280.     long pc;
  281.     int ct;
  282.  
  283.     sp = fp;
  284.  
  285.     ct = *sp++ >> 8;
  286.     fp = stack + 1 + *sp++;
  287.     pc = *sp++;
  288.     pc = ((long) *sp++ << 9) | pc;
  289.  
  290.     SET_PC (pc)
  291.  
  292.     if (ct == 0)
  293.     store (value);
  294.  
  295.     if (ct != 2)
  296.     return;
  297.  
  298.     restore_operands ();
  299.  
  300.     finished++;
  301.  
  302.     *--sp = value;
  303.  
  304. }/* ret */
  305.  
  306. /*
  307.  * branch
  308.  *
  309.  * Take a jump after an instruction based on the flag, either true or
  310.  * false. The branch can be short or long; it is encoded in one or two
  311.  * bytes respectively. When bit 7 of the first byte is set, the jump
  312.  * takes place if the flag is true; otherwise it is taken if the flag
  313.  * is false. When bit 6 of the first byte is set, the branch is short;
  314.  * otherwise it is long. The offset occupies the bottom 6 bits of the
  315.  * first byte plus all the bits in the second byte for long branches.
  316.  * Uniquely, an offset of 0 means return false, and an offset of 1 is
  317.  * return true.
  318.  *
  319.  */
  320.  
  321. void branch (int flag)
  322. {
  323.     long pc;
  324.     zword offset;
  325.     zbyte specifier;
  326.     zbyte off1;
  327.     zbyte off2;
  328.  
  329.     CODE_BYTE (specifier)
  330.  
  331.     off1 = ZBYTE (specifier & 0x3f);
  332.  
  333.     if (!flag)
  334.     specifier ^= 0x80;
  335.  
  336.     if (!(specifier & 0x40)) {        /* it's a long branch */
  337.  
  338.     if (off1 & 0x20)        /* propagate sign bit */
  339.         off1 |= 0xc0;
  340.  
  341.     CODE_BYTE (off2)
  342.  
  343.     offset = (off1 << 8) | off2;
  344.  
  345.     } else offset = off1;        /* it's a short branch */
  346.  
  347.     if (specifier & 0x80)
  348.  
  349.     if (offset > 1) {        /* normal branch */
  350.  
  351.         GET_PC (pc)
  352.         pc += (short) offset - 2;
  353.         SET_PC (pc)
  354.  
  355.     } else ret (offset);        /* special case, return 0 or 1 */
  356.  
  357. }/* branch */
  358.  
  359. /*
  360.  * store
  361.  *
  362.  * Store an operand, either as a variable or pushed on the stack.
  363.  *
  364.  */
  365.  
  366. void store (zword value)
  367. {
  368.     zbyte variable;
  369.  
  370.     CODE_BYTE (variable)
  371.  
  372.     if (variable == 0)
  373.     *--sp = value;
  374.     else if (variable < 16)
  375.     *(fp - variable) = value;
  376.     else {
  377.     zword addr = h_globals + 2 * (variable - 16);
  378.     SET_WORD (addr, value)
  379.     }
  380.  
  381. }/* store */
  382.  
  383. /*
  384.  * load_operand
  385.  *
  386.  * Load an operand, either a variable or a constant.
  387.  *
  388.  */
  389.  
  390. static void load_operand (zbyte type)
  391. {
  392.     zword value;
  393.  
  394.     if (type & 2) {             /* variable */
  395.  
  396.     zbyte variable;
  397.  
  398.     CODE_BYTE (variable)
  399.  
  400.     if (variable == 0)
  401.         value = *sp++;
  402.     else if (variable < 16)
  403.         value = *(fp - variable);
  404.     else {
  405.         zword addr = h_globals + 2 * (variable - 16);
  406.         LOW_WORD (addr, value)
  407.     }
  408.  
  409.     } else if (type & 1) {         /* small constant */
  410.  
  411.     zbyte bvalue;
  412.  
  413.     CODE_BYTE (bvalue)
  414.     value = ZWORD (bvalue);
  415.  
  416.     } else CODE_WORD (value)         /* large constant */
  417.  
  418.     zargs[zargc++] = value;
  419.  
  420. }/* load_operand */
  421.  
  422. /*
  423.  * load_all_operands
  424.  *
  425.  * Given the operand specifier byte, load all (up to four) operands
  426.  * for a VAR or EXT opcode.
  427.  *
  428.  */
  429.  
  430. static void load_all_operands (zbyte specifier)
  431. {
  432.     int i;
  433.  
  434.     for (i = 6; i >= 0; i -= 2) {
  435.  
  436.     zbyte type = ZBYTE ((specifier >> i) & 0x03);
  437.  
  438.     if (type == 3)
  439.         break;
  440.  
  441.     load_operand (type);
  442.  
  443.     }
  444.  
  445. }/* load_all_operands */
  446.  
  447. /*
  448.  * interpret
  449.  *
  450.  * Z-code interpreter main loop
  451.  *
  452.  */
  453.  
  454. void interpret (void)
  455. {
  456.  
  457.     do {
  458.  
  459.     zbyte opcode;
  460.  
  461.     CODE_BYTE (opcode)
  462.  
  463.     zargc = 0;
  464.  
  465.     if (opcode < 0x80) {            /* 2OP opcodes */
  466.  
  467.         load_operand (ZBYTE ((opcode & 0x40) ? 2 : 1));
  468.         load_operand (ZBYTE ((opcode & 0x20) ? 2 : 1));
  469.  
  470.         var_opcodes[opcode & 0x1f] ();
  471.  
  472.     } else if (opcode < 0xb0) {        /* 1OP opcodes */
  473.  
  474.         load_operand (ZBYTE (opcode >> 4));
  475.  
  476.         op1_opcodes[opcode & 0x0f] ();
  477.  
  478.     } else if (opcode < 0xc0) {        /* 0OP opcodes */
  479.  
  480.         op0_opcodes[opcode - 0xb0] ();
  481.  
  482.     } else {                /* VAR opcodes */
  483.  
  484.         zbyte specifier1;
  485.         zbyte specifier2;
  486.  
  487.         if (opcode == 0xec || opcode == 0xfa) {    /* opcodes 0xec */
  488.         CODE_BYTE (specifier1)                  /* and 0xfa are */
  489.         CODE_BYTE (specifier2)                  /* call opcodes */
  490.         load_all_operands (specifier1);        /* with up to 8 */
  491.         load_all_operands (specifier2);         /* arguments    */
  492.         } else {
  493.         CODE_BYTE (specifier1)
  494.         load_all_operands (specifier1);
  495.         }
  496.  
  497.         var_opcodes[opcode - 0xc0] ();
  498.  
  499.     }
  500.  
  501.     } while (!finished);
  502.  
  503. }/* interpret */
  504.  
  505. /*
  506.  * direct_call
  507.  *
  508.  * Call the interpreter loop directly. This is necessary when
  509.  *
  510.  * - a sound effect has been finished
  511.  * - a read instruction has timed out
  512.  * - a newline countdown has hit zero
  513.  *
  514.  * The interpreter returns the result value on the stack.
  515.  *
  516.  */
  517.  
  518. int direct_call (zword addr)
  519. {
  520.  
  521.     if (addr) {
  522.  
  523.     save_operands ();
  524.  
  525.     call (addr, 0, 0, 2);
  526.  
  527.     interpret ();
  528.  
  529.     finished--;
  530.  
  531.     return (short) *sp++;
  532.  
  533.     } else return 0;
  534.  
  535. }/* direct_call */
  536.  
  537. /*
  538.  * __extended__
  539.  *
  540.  * Load and execute an extended opcode.
  541.  *
  542.  */
  543.  
  544. static void __extended__ (void)
  545. {
  546.     zbyte opcode;
  547.     zbyte specifier;
  548.  
  549.     CODE_BYTE (opcode)
  550.     CODE_BYTE (specifier)
  551.  
  552.     load_all_operands (specifier);
  553.  
  554.     if (opcode < 0x1d)            /* extended opcodes from 0x1d on */
  555.     ext_opcodes[opcode] ();        /* are reserved for future spec' */
  556.  
  557. }/* __extended__ */
  558.  
  559. /*
  560.  * __illegal__
  561.  *
  562.  * Exit game because an unknown opcode has been used.
  563.  *
  564.  */
  565.  
  566. static void __illegal__ (void)
  567. {
  568.  
  569.     runtime_error ("Illegal opcode");
  570.  
  571. }/* __illegal__ */
  572.  
  573. /*
  574.  * z_catch, store the current stack frame for later use with z_throw.
  575.  *
  576.  *    no zargs used
  577.  *
  578.  */
  579.  
  580. void z_catch (void)
  581. {
  582.  
  583.     store (ZWORD (fp - stack));
  584.  
  585. }/* z_catch */
  586.  
  587. /*
  588.  * z_throw, go back to the given stack frame and return the given value.
  589.  *
  590.  *    zargs[0] = value to return
  591.  *    zargs[1] = stack frame
  592.  *
  593.  */
  594.  
  595. void z_throw (void)
  596. {
  597.  
  598.     if (zargs[1] >= STACK_SIZE)
  599.     runtime_error ("Bad stack frame");
  600.  
  601.     fp = stack + zargs[1];
  602.  
  603.     ret (zargs[0]);
  604.  
  605. }/* z_throw */
  606.  
  607. /*
  608.  * z_call_n, call a subroutine and discard its result.
  609.  *
  610.  *     zargs[0] = packed address of subroutine
  611.  *    zargs[1] = first argument (optional)
  612.  *    ...
  613.  *    zargs[7] = seventh argument (optional)
  614.  *
  615.  */
  616.  
  617. void z_call_n (void)
  618. {
  619.  
  620.     if (zargs[0])
  621.     call (zargs[0], zargc - 1, zargs + 1, 1);
  622.  
  623. }/* z_call_n */
  624.  
  625. /*
  626.  * z_call_s, call a subroutine and store its result.
  627.  *
  628.  *     zargs[0] = packed address of subroutine
  629.  *    zargs[1] = first argument (optional)
  630.  *    ...
  631.  *    zargs[7] = seventh argument (optional)
  632.  *
  633.  */
  634.  
  635. void z_call_s (void)
  636. {
  637.  
  638.     if (zargs[0])
  639.     call (zargs[0], zargc - 1, zargs + 1, 0);
  640.     else
  641.     store (0);
  642.  
  643. }/* z_call_s */
  644.  
  645. /*
  646.  * z_check_arg_count, branch if subroutine was called with >= n arg's.
  647.  *
  648.  *     zargs[0] = number of arguments
  649.  *
  650.  */
  651.  
  652. void z_check_arg_count (void)
  653. {
  654.  
  655.     if (fp == stack + STACK_SIZE)
  656.     branch (zargs[0] == 0);
  657.     else
  658.     branch (zargs[0] <= (*fp & 0xff));
  659.  
  660. }/* z_check_arg_count */
  661.  
  662. /*
  663.  * z_jump, jump unconditionally to the given address.
  664.  *
  665.  *    zargs[0] = PC relative address
  666.  *
  667.  */
  668.  
  669. void z_jump (void)
  670. {
  671.     long pc;
  672.  
  673.     GET_PC (pc)
  674.  
  675.     pc += (short) zargs[0] - 2;
  676.  
  677.     if (pc >= story_size)
  678.     runtime_error ("Jump to illegal address");
  679.  
  680.     SET_PC (pc)
  681.  
  682. }/* z_jump */
  683.  
  684. /*
  685.  * z_nop, no operation.
  686.  *
  687.  *    no zargs used
  688.  *
  689.  */
  690.  
  691. void z_nop (void)
  692. {
  693.  
  694.     /* Do nothing */
  695.  
  696. }/* z_nop */
  697.  
  698. /*
  699.  * z_quit, stop game and exit interpreter.
  700.  *
  701.  *    no zargs used
  702.  *
  703.  */
  704.  
  705. void z_quit (void)
  706. {
  707.  
  708.     finished = MAX_CALL_LEVEL + 1;
  709.  
  710. }/* z_quit */
  711.  
  712. /*
  713.  * z_ret, return from a subroutine with the given value.
  714.  *
  715.  *    zargs[0] = value to return
  716.  *
  717.  */
  718.  
  719. void z_ret (void)
  720. {
  721.  
  722.     ret (zargs[0]);
  723.  
  724. }/* z_ret */
  725.  
  726. /*
  727.  * z_ret_popped, return from a subroutine with a value popped off the stack.
  728.  *
  729.  *    no zargs used
  730.  *
  731.  */
  732.  
  733. void z_ret_popped (void)
  734. {
  735.  
  736.     ret (*sp++);
  737.  
  738. }/* z_ret_popped */
  739.  
  740. /*
  741.  * z_rfalse, return from a subroutine with false (0).
  742.  *
  743.  *     no zargs used
  744.  *
  745.  */
  746.  
  747. void z_rfalse (void)
  748. {
  749.  
  750.     ret (0);
  751.  
  752. }/* z_rfalse */
  753.  
  754. /*
  755.  * z_rtrue, return from a subroutine with true (1).
  756.  *
  757.  *     no zargs used
  758.  *
  759.  */
  760.  
  761. void z_rtrue (void)
  762. {
  763.  
  764.     ret (1);
  765.  
  766. }/* z_rtrue */
  767.