pax_global_header00006660000000000000000000000064145617731300014521gustar00rootroot0000000000000052 comment=e528e4802e3fdc2364a9a92aa127e7a5091a8d4e DavidKinder-Inform6-e528e48/000077500000000000000000000000001456177313000155715ustar00rootroot00000000000000DavidKinder-Inform6-e528e48/README.md000066400000000000000000000047301456177313000170540ustar00rootroot00000000000000# Inform 6 This is Inform 6.42, copyright (c) Graham Nelson 1993 - 2024, a compiler for interactive fiction (text adventure games). Release notes, manuals, executables and more are available from https://ifarchive.org/indexes/if-archive/infocom/compilers/inform6/. ## Introduction Back in the late 1980s, people began investigating the format of Infocom's text adventures. Infocom used a standard format that defined a virtual machine, which has come to be known as the Z-Machine, to allow them to be able to port their games to many different computers. This investigation lead to the creation of open source implementations of the Z-Machine, such as the InfoTaskForce interpreter, Zip, Frotz, and many others. In 1993, Graham Nelson released the first version of Inform, which compiled a somewhat C-like language ("Inform") to the Z-Machine. In the years that followed this led to the creation of hundreds of free games by a community that had sprung up based around the Usenet group rec.arts.int-fiction. The latest version of Inform is [Inform 7](http://inform7.com/), but Inform 6 still lives on, both as the code generator used by Inform 7, and as a language and compiler in its own right. Inform 6 is now considered stable and only has bugs fixed and minor, non-breaking features added, but development continues. ## Using Inform 6 To use the compiler, you will need an executable. There are [pre-built executables](https://ifarchive.org/indexes/if-archive/infocom/compilers/inform6/executables/) available, or you can compile the source yourself. There is no makefile as compilation does not really need one: all that is required is a C compiler and for it to be invoked with something like cc -O2 -o inform *.c Suitable defaults for various operating systems can be selected by defining the appropriate symbol, a list of which are near the top of the "header.h" file (under "Our host machine or OS for today is..."). For example, to compile for Windows, use cc -DPC_WIN32 -O2 -o inform *.c To write a work of interactive fiction with Inform 6, you will also need a version of the Inform 6 library. [Stable versions](https://ifarchive.org/indexes/if-archive/infocom/compilers/inform6/library/) of the library are available, and development of the library continues in a [separate project](https://gitlab.com/DavidGriffith/inform6lib). More resources and documentation, including the Inform Designer's Manual, are available from the [Inform 6 web site](https://www.inform-fiction.org/). DavidKinder-Inform6-e528e48/ReleaseNotes.html000066400000000000000000000462621456177313000210620ustar00rootroot00000000000000 Inform Release Notes

Inform 6.4 Release Notes

Introduction

This is a maintenance release of the Inform 6 compiler for creating interactive fiction. Although just about all known bugs are fixed, the approach to enhancing Inform is more conservative. The selection of suggestions to implement has been governed by two factors: Older release notes (Inform 6.30 through 6.36) are archived here.

Since the first release of the Inform 6.3 compiler, the Inform 6 library has been split into a separate project, maintained at https://gitlab.com/DavidGriffith/inform6lib.

Acknowledgements

Far too many people contributed towards this release — reporting and resolving bugs, making helpful suggestions, providing support and facilities, testing, and so on — for their names to be individually listed. So instead, this is a general thank-you to everybody who has made this release happen, and specific ones to Graham Nelson for permitting it in the first place, and to Andrew Plotkin, who is responsible for most of the actual changes to the compiler code.

Inform 6.42

These are the changes delivered in version 6.42 of the Inform compiler.

Features added

Bugs fixed

Inform 6.41

These are the changes delivered in version 6.41 of the Inform compiler.

Features added

Inform 6.40

These are the changes delivered in version 6.40 of the Inform compiler.

Features added

Bugs fixed

DavidKinder-Inform6-e528e48/arrays.c000066400000000000000000000775451456177313000172600ustar00rootroot00000000000000/* ------------------------------------------------------------------------- */ /* "arrays" : Parses array declarations and constructs arrays from them; */ /* likewise global variables, which are in some ways a */ /* simpler form of the same thing. */ /* */ /* Part of Inform 6.42 */ /* copyright (c) Graham Nelson 1993 - 2024 */ /* */ /* ------------------------------------------------------------------------- */ #include "header.h" /* ------------------------------------------------------------------------- */ /* Arrays defined below: */ /* */ /* uchar dynamic_array_area[] Initial values for the bytes of */ /* the dynamic array area */ /* uchar static_array_area[] Initial values for the bytes of */ /* the static array area */ /* int32 global_initial_value[n] The initialised value of the nth */ /* global variable (counting 0 - 239, */ /* or higher for Glulx) */ /* */ /* The "dynamic array area" is the Z-machine area holding the current */ /* values of the global variables (in 240x2 = 480 bytes) followed by any */ /* (dynamic) arrays which may be defined. */ /* */ /* In Glulx, we don't keep the global variables in dynamic_array_area. */ /* Array data starts at the start. */ /* */ /* We can also store arrays (but not globals) into static memory (ROM). */ /* The storage for these goes, unsurprisingly, into static_array_area. */ /* ------------------------------------------------------------------------- */ uchar *dynamic_array_area; /* See above */ memory_list dynamic_array_area_memlist; int dynamic_array_area_size; /* Size in bytes */ int32 *global_initial_value; /* Allocated to no_globals */ static memory_list global_initial_value_memlist; int no_globals; /* Number of global variables used by the programmer (Inform itself uses the top seven -- but these do not count) */ /* In Glulx, Inform uses the bottom ten. */ uchar *static_array_area; memory_list static_array_area_memlist; int static_array_area_size; int no_arrays; arrayinfo *arrays; static memory_list arrays_memlist; static int array_entry_size, /* 1 for byte array, 2 for word array */ array_base; /* Offset in dynamic array area of the array being constructed. During the same time, dynamic_array_area_size is the offset of the initial entry in the array: so for "table" and "string" arrays, these numbers are different (by 2 and 1 bytes resp) */ /* In Glulx, of course, that will be 4 instead of 2. */ static memory_list current_array_name; /* The name of the global or array currently being compiled. */ /* Complete the array. Fill in the size field (if it has one) and advance foo_array_area_size. */ extern void finish_array(int32 i, int is_static) { uchar *area; int area_size; if (!is_static) { ensure_memory_list_available(&dynamic_array_area_memlist, dynamic_array_area_size+array_base+1*array_entry_size); area = dynamic_array_area; area_size = dynamic_array_area_size; } else { ensure_memory_list_available(&static_array_area_memlist, static_array_area_size+array_base+1*array_entry_size); area = static_array_area; area_size = static_array_area_size; } if (i == 0) { error("An array must have at least one entry"); } /* Write the array size into the 0th byte/word of the array, if it's a "table" or "string" array */ if (!glulx_mode) { if (array_base != area_size) { if (area_size-array_base==2) { area[array_base] = i/256; area[array_base+1] = i%256; } else { if (i>=256) error("A 'string' array can have at most 256 entries"); area[array_base] = i; } } } else { if (array_base != area_size) { if (area_size-array_base==4) { area[array_base] = (i >> 24) & 0xFF; area[array_base+1] = (i >> 16) & 0xFF; area[array_base+2] = (i >> 8) & 0xFF; area[array_base+3] = (i) & 0xFF; } else { if (i>=256) error("A 'string' array can have at most 256 entries"); area[array_base] = i; } } } /* Move on the static/dynamic array size so that it now points to the next available free space */ if (!is_static) { dynamic_array_area_size += i*array_entry_size; } else { static_array_area_size += i*array_entry_size; } } /* Fill in array entry i (in either the static or dynamic area). When this is called, foo_array_area_size is the end of the previous array; we're writing after that. */ extern void array_entry(int32 i, int is_static, assembly_operand VAL) { uchar *area; int area_size; if (!is_static) { ensure_memory_list_available(&dynamic_array_area_memlist, dynamic_array_area_size+(i+1)*array_entry_size); area = dynamic_array_area; area_size = dynamic_array_area_size; } else { ensure_memory_list_available(&static_array_area_memlist, static_array_area_size+(i+1)*array_entry_size); area = static_array_area; area_size = static_array_area_size; } if (!glulx_mode) { /* Array entry i (initial entry has i=0) is set to Z-machine value j */ if (array_entry_size==1) { area[area_size+i] = (VAL.value)%256; if (VAL.marker != 0) error("Entries in byte arrays and strings must be known constants"); /* If the entry is too large for a byte array, issue a warning and truncate the value */ else if (VAL.value >= 256) warning("Entry in '->', 'string' or 'buffer' array not in range 0 to 255"); } else { int32 addr = area_size + 2*i; area[addr] = (VAL.value)/256; area[addr+1] = (VAL.value)%256; if (VAL.marker != 0) { if (!is_static) { backpatch_zmachine(VAL.marker, DYNAMIC_ARRAY_ZA, addr); } else { backpatch_zmachine(VAL.marker, STATIC_ARRAY_ZA, addr); } } } } else { /* Array entry i (initial entry has i=0) is set to value j */ if (array_entry_size==1) { area[area_size+i] = (VAL.value) & 0xFF; if (VAL.marker != 0) error("Entries in byte arrays and strings must be known constants"); /* If the entry is too large for a byte array, issue a warning and truncate the value */ else if (VAL.value >= 256) warning("Entry in '->', 'string' or 'buffer' array not in range 0 to 255"); } else if (array_entry_size==4) { int32 addr = area_size + 4*i; area[addr] = (VAL.value >> 24) & 0xFF; area[addr+1] = (VAL.value >> 16) & 0xFF; area[addr+2] = (VAL.value >> 8) & 0xFF; area[addr+3] = (VAL.value) & 0xFF; if (VAL.marker != 0) { if (!is_static) { backpatch_zmachine(VAL.marker, DYNAMIC_ARRAY_ZA, addr); } else { /* We can't use backpatch_zmachine() because that only applies to RAM. Instead we add an entry to staticarray_backpatch_table. A backpatch entry is five bytes: *_MV followed by the array offset (in static array area). */ if (bpatch_trace_setting >= 2) printf("BP added: MV %d staticarray %04x\n", VAL.marker, addr); ensure_memory_list_available(&staticarray_backpatch_table_memlist, staticarray_backpatch_size+5); staticarray_backpatch_table[staticarray_backpatch_size++] = VAL.marker; staticarray_backpatch_table[staticarray_backpatch_size++] = ((addr >> 24) & 0xFF); staticarray_backpatch_table[staticarray_backpatch_size++] = ((addr >> 16) & 0xFF); staticarray_backpatch_table[staticarray_backpatch_size++] = ((addr >> 8) & 0xFF); staticarray_backpatch_table[staticarray_backpatch_size++] = (addr & 0xFF); } } } else { error("Somehow created an array of shorts"); } } } /* ------------------------------------------------------------------------- */ /* Global and Array directives. */ /* */ /* Global [ [=] ] */ /* */ /* Array [static] */ /* */ /* where an array specification is: */ /* */ /* | -> | */ /* | --> | ... */ /* | string | [ [;] ... ]; */ /* | table */ /* | buffer */ /* */ /* The "static" keyword (arrays only) places the array in static memory. */ /* */ /* ------------------------------------------------------------------------- */ extern void set_variable_value(int i, int32 v) { /* This isn't currently called to create a new global, but it has been used that way within living memory. So we call ensure. */ ensure_memory_list_available(&global_initial_value_memlist, i+1); global_initial_value[i]=v; } /* There are four ways to initialise arrays: */ #define UNSPECIFIED_AI -1 #define NULLS_AI 0 #define DATA_AI 1 #define ASCII_AI 2 #define BRACKET_AI 3 extern void make_global() { int32 i; int name_length; assembly_operand AO; uint32 globalnum; int32 global_symbol; debug_location_beginning beginning_debug_location = get_token_location_beginning(); directive_keywords.enabled = FALSE; get_next_token(); i = token_value; global_symbol = i; name_length = strlen(token_text) + 1; ensure_memory_list_available(¤t_array_name, name_length); strncpy(current_array_name.data, token_text, name_length); if (!glulx_mode) { if ((token_type==SYMBOL_TT) && (symbols[i].type==GLOBAL_VARIABLE_T) && (symbols[i].value >= LOWEST_SYSTEM_VAR_NUMBER)) { globalnum = symbols[i].value - MAX_LOCAL_VARIABLES; goto RedefinitionOfSystemVar; } } else { if ((token_type==SYMBOL_TT) && (symbols[i].type==GLOBAL_VARIABLE_T)) { globalnum = symbols[i].value - MAX_LOCAL_VARIABLES; goto RedefinitionOfSystemVar; } } if (token_type != SYMBOL_TT) { discard_token_location(beginning_debug_location); ebf_curtoken_error("new global variable name"); panic_mode_error_recovery(); return; } if (!(symbols[i].flags & UNKNOWN_SFLAG)) { discard_token_location(beginning_debug_location); ebf_symbol_error("new global variable name", token_text, typename(symbols[i].type), symbols[i].line); panic_mode_error_recovery(); return; } if (symbols[i].flags & USED_SFLAG) error_named("Variable must be defined before use:", token_text); directive_keywords.enabled = TRUE; get_next_token(); directive_keywords.enabled = FALSE; if ((token_type==DIR_KEYWORD_TT)&&(token_value==STATIC_DK)) { error("Global variables cannot be static"); } else { put_token_back(); } if (!glulx_mode && no_globals==233) { discard_token_location(beginning_debug_location); error("All 233 global variables already declared"); panic_mode_error_recovery(); return; } globalnum = no_globals; ensure_memory_list_available(&variables_memlist, MAX_LOCAL_VARIABLES+no_globals+1); variables[MAX_LOCAL_VARIABLES+no_globals].token = i; variables[MAX_LOCAL_VARIABLES+no_globals].usage = FALSE; assign_symbol(i, MAX_LOCAL_VARIABLES+no_globals, GLOBAL_VARIABLE_T); ensure_memory_list_available(&global_initial_value_memlist, no_globals+1); global_initial_value[no_globals++]=0; directive_keywords.enabled = TRUE; RedefinitionOfSystemVar: get_next_token(); if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) { /* No initial value. */ put_token_back(); if (debugfile_switch) { char *global_name = current_array_name.data; debug_file_printf(""); debug_file_printf("%s", global_name); debug_file_printf("
"); write_debug_global_backpatch(symbols[global_symbol].value); debug_file_printf("
"); write_debug_locations (get_token_location_end(beginning_debug_location)); debug_file_printf("
"); } return; } if (((token_type==SEP_TT)&&(token_value==ARROW_SEP)) || ((token_type==SEP_TT)&&(token_value==DARROW_SEP)) || ((token_type==DIR_KEYWORD_TT)&&(token_value==STRING_DK)) || ((token_type==DIR_KEYWORD_TT)&&(token_value==TABLE_DK)) || ((token_type==DIR_KEYWORD_TT)&&(token_value==BUFFER_DK))) { error("use 'Array' to define arrays, not 'Global'"); return; } /* Skip "=" if present. */ if (!((token_type == SEP_TT) && (token_value == SETEQUALS_SEP))) put_token_back(); AO = parse_expression(CONSTANT_CONTEXT); if (!glulx_mode) { if (AO.marker != 0) backpatch_zmachine(AO.marker, DYNAMIC_ARRAY_ZA, 2*globalnum); } else { if (AO.marker != 0) backpatch_zmachine(AO.marker, GLOBALVAR_ZA, 4*globalnum); } if (globalnum >= global_initial_value_memlist.count) compiler_error("Globalnum out of range"); global_initial_value[globalnum] = AO.value; if (debugfile_switch) { char *global_name = current_array_name.data; debug_file_printf(""); debug_file_printf("%s", global_name); debug_file_printf("
"); write_debug_global_backpatch(symbols[global_symbol].value); debug_file_printf("
"); write_debug_locations (get_token_location_end(beginning_debug_location)); debug_file_printf("
"); } } extern void make_array() { int32 i; int name_length; int array_type, data_type; int is_static = FALSE; assembly_operand AO; int extraspace; int32 global_symbol; debug_location_beginning beginning_debug_location = get_token_location_beginning(); directive_keywords.enabled = FALSE; get_next_token(); i = token_value; global_symbol = i; name_length = strlen(token_text) + 1; ensure_memory_list_available(¤t_array_name, name_length); strncpy(current_array_name.data, token_text, name_length); if (token_type != SYMBOL_TT) { discard_token_location(beginning_debug_location); ebf_curtoken_error("new array name"); panic_mode_error_recovery(); return; } if (!(symbols[i].flags & UNKNOWN_SFLAG)) { discard_token_location(beginning_debug_location); ebf_symbol_error("new array name", token_text, typename(symbols[i].type), symbols[i].line); panic_mode_error_recovery(); return; } directive_keywords.enabled = TRUE; get_next_token(); directive_keywords.enabled = FALSE; if ((token_type==DIR_KEYWORD_TT)&&(token_value==STATIC_DK)) { is_static = TRUE; } else { put_token_back(); } if (!is_static) { assign_symbol(i, dynamic_array_area_size, ARRAY_T); } else { assign_symbol(i, static_array_area_size, STATIC_ARRAY_T); } ensure_memory_list_available(&arrays_memlist, no_arrays+1); arrays[no_arrays].symbol = i; directive_keywords.enabled = TRUE; get_next_token(); if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) { discard_token_location(beginning_debug_location); ebf_curtoken_error("array definition"); put_token_back(); return; } array_type = BYTE_ARRAY; data_type = UNSPECIFIED_AI; /* The keywords "data", "initial", and "initstr" used to be accepted here -- but only in a Global directive, not Array. The Global directive no longer calls here, so those keywords are now (more) obsolete. */ if ((token_type==SEP_TT)&&(token_value==ARROW_SEP)) array_type = BYTE_ARRAY; else if ((token_type==SEP_TT)&&(token_value==DARROW_SEP)) array_type = WORD_ARRAY; else if ((token_type==DIR_KEYWORD_TT)&&(token_value==STRING_DK)) array_type = STRING_ARRAY; else if ((token_type==DIR_KEYWORD_TT)&&(token_value==TABLE_DK)) array_type = TABLE_ARRAY; else if ((token_type==DIR_KEYWORD_TT)&&(token_value==BUFFER_DK)) array_type = BUFFER_ARRAY; else { discard_token_location(beginning_debug_location); ebf_curtoken_error("'->', '-->', 'string', 'table' or 'buffer'"); panic_mode_error_recovery(); return; } array_entry_size=1; if ((array_type==WORD_ARRAY) || (array_type==TABLE_ARRAY)) array_entry_size=WORDSIZE; get_next_token(); if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) { discard_token_location(beginning_debug_location); error("No array size or initial values given"); put_token_back(); return; } switch(data_type) { case UNSPECIFIED_AI: if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP)) data_type = BRACKET_AI; else { data_type = NULLS_AI; if (token_type == DQ_TT) data_type = ASCII_AI; get_next_token(); if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) data_type = DATA_AI; put_token_back(); put_token_back(); } break; case NULLS_AI: obsolete_warning("use '->' instead of 'data'"); break; case DATA_AI: obsolete_warning("use '->' instead of 'initial'"); break; case ASCII_AI: obsolete_warning("use '->' instead of 'initstr'"); break; } /* Leave room to write the array size in later, if string/table array */ extraspace = 0; if ((array_type==STRING_ARRAY) || (array_type==TABLE_ARRAY)) extraspace += array_entry_size; if (array_type==BUFFER_ARRAY) extraspace += WORDSIZE; if (!is_static) { array_base = dynamic_array_area_size; dynamic_array_area_size += extraspace; } else { array_base = static_array_area_size; static_array_area_size += extraspace; } arrays[no_arrays].type = array_type; arrays[no_arrays].loc = is_static; /* Note that, from this point, we must continue through finish_array(). Exiting this routine on error causes problems. */ switch(data_type) { case NULLS_AI: AO = parse_expression(CONSTANT_CONTEXT); CalculatedArraySize: if (AO.marker != 0) { error("Array sizes must be known now, not defined later"); break; } if (!glulx_mode) { if ((AO.value <= 0) || (AO.value >= 32768)) { error("An array must have between 1 and 32767 entries"); AO.value = 1; } } else { if (AO.value <= 0 || (AO.value & 0x80000000)) { error("An array may not have 0 or fewer entries"); AO.value = 1; } } { for (i=0; i= 256)) { error("Unicode characters beyond Latin-1 cannot be used in a byte array"); } else { chars.value = unicode; } } else /* Z-code */ { zscii = unicode_to_zscii(unicode); if ((zscii != 5) && (zscii < 0x100)) chars.value = zscii; else { unicode_char_error("Character can only be used if declared in \ advance as part of 'Zcharacter table':", unicode); chars.value = '?'; } } chars.marker = 0; set_constant_ot(&chars); array_entry(i, is_static, chars); } } break; case BRACKET_AI: /* In this case the array is initialised to the sequence of constant values given over a whole range of compiler-lines, between square brackets [ and ] */ i = 0; while (TRUE) { assembly_operand AO; /* This isn't the start of a statement, but it's safe to release token texts anyway. Expressions in an array list are independent of each other. */ release_token_texts(); get_next_token(); if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) continue; if ((token_type == SEP_TT) && (token_value == CLOSE_SQUARE_SEP)) break; if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP)) { /* Minimal error recovery: we assume that a ] has been missed, and the programmer is now starting a new routine */ ebf_curtoken_error("']'"); put_token_back(); break; } put_token_back(); AO = parse_expression(ARRAY_CONTEXT); if (AO.marker == ERROR_MV) break; array_entry(i, is_static, AO); i++; } } finish_array(i, is_static); if (debugfile_switch) { int32 new_area_size; char *global_name = current_array_name.data; debug_file_printf(""); debug_file_printf("%s", global_name); debug_file_printf(""); write_debug_array_backpatch(symbols[global_symbol].value); debug_file_printf(""); new_area_size = (!is_static ? dynamic_array_area_size : static_array_area_size); debug_file_printf ("%d", new_area_size - array_base); debug_file_printf ("%d", array_entry_size); debug_file_printf ("%s", (array_type == STRING_ARRAY || array_type == TABLE_ARRAY) ? "true" : "false"); get_next_token(); write_debug_locations(get_token_location_end(beginning_debug_location)); put_token_back(); debug_file_printf(""); } if ((array_type==BYTE_ARRAY) || (array_type==WORD_ARRAY)) i--; if (array_type==BUFFER_ARRAY) i+=WORDSIZE-1; arrays[no_arrays++].size = i; } extern int32 begin_table_array(void) { /* The "box" statement needs to be able to construct table arrays of strings like this. (Static data, but we create a dynamic array for maximum backwards compatibility.) */ array_base = dynamic_array_area_size; array_entry_size = WORDSIZE; /* Leave room to write the array size in later */ dynamic_array_area_size += array_entry_size; return array_base; } extern int32 begin_word_array(void) { /* The "random(a, b, ...)" function needs to be able to construct word arrays like this. (Static data, but we create a dynamic array for maximum backwards compatibility.) */ array_base = dynamic_array_area_size; array_entry_size = WORDSIZE; return array_base; } /* ========================================================================= */ /* Data structure management routines */ /* ------------------------------------------------------------------------- */ extern void init_arrays_vars(void) { dynamic_array_area = NULL; static_array_area = NULL; arrays = NULL; global_initial_value = NULL; variables = NULL; } extern void arrays_begin_pass(void) { int ix, totalvar; no_arrays = 0; if (!glulx_mode) { no_globals = 0; /* The compiler-defined globals start at 239 and go down, so we need to initialize the entire list from the start. */ totalvar = MAX_ZCODE_GLOBAL_VARS; } else { /* The compiler-defined globals run from 0 to 10. */ no_globals = 11; totalvar = no_globals; } ensure_memory_list_available(&global_initial_value_memlist, totalvar); for (ix=0; ixvalue >= 0 && AO->value <= 255) AO->type = SHORT_CONSTANT_OT; else AO->type = LONG_CONSTANT_OT; } else { if (AO->value == 0) AO->type = ZEROCONSTANT_OT; else if (AO->value >= -0x80 && AO->value < 0x80) AO->type = BYTECONSTANT_OT; else if (AO->value >= -0x8000 && AO->value < 0x8000) AO->type = HALFCONSTANT_OT; else AO->type = CONSTANT_OT; } } extern int is_constant_ot(int otval) { if (!glulx_mode) { return ((otval == LONG_CONSTANT_OT) || (otval == SHORT_CONSTANT_OT)); } else { return ((otval == CONSTANT_OT) || (otval == HALFCONSTANT_OT) || (otval == BYTECONSTANT_OT) || (otval == ZEROCONSTANT_OT)); } } extern int is_variable_ot(int otval) { if (!glulx_mode) { return (otval == VARIABLE_OT); } else { return ((otval == LOCALVAR_OT) || (otval == GLOBALVAR_OT)); } } /* ------------------------------------------------------------------------- */ /* Used in printing assembly traces */ /* ------------------------------------------------------------------------- */ extern char *variable_name(int32 i) { if (i==0) return("sp"); if (i= 256 && i < 286) { if (i - 256 < NUMBER_SYSTEM_FUNCTIONS) return system_functions.keywords[i - 256]; return ""; } } else { switch (i - MAX_LOCAL_VARIABLES) { case 0: return "temp_global"; case 1: return "temp__global2"; case 2: return "temp__global3"; case 3: return "temp__global4"; case 4: return "self"; case 5: return "sender"; case 6: return "sw__var"; case 7: return "sys__glob0"; case 8: return "sys__glob1"; case 9: return "sys__glob2"; case 10: return "sys_statusline_flag"; } } return (symbols[variables[i].token].name); } /* Print symbolic information about the AO, if there is any. */ static void print_operand_annotation(const assembly_operand *o) { int any = FALSE; if (o->marker) { printf((!any) ? " (" : ": "); any = TRUE; printf("%s", describe_mv(o->marker)); switch (o->marker) { case VROUTINE_MV: printf(": %s", veneer_routine_name(o->value)); break; case INCON_MV: printf(": %s", name_of_system_constant(o->value)); break; case DWORD_MV: printf(": '"); print_dict_word(o->value); printf("'"); break; } } if (o->symindex >= 0 && o->symindex < no_symbols) { printf((!any) ? " (" : ": "); any = TRUE; printf("%s", symbols[o->symindex].name); } if (any) printf(")"); } static void print_operand_z(const assembly_operand *o, int annotate) { switch(o->type) { case EXPRESSION_OT: printf("expr_"); break; case LONG_CONSTANT_OT: printf("long_"); break; case SHORT_CONSTANT_OT: printf("short_"); break; case VARIABLE_OT: if (o->value==0) { printf("sp"); return; } printf("%s", variable_name(o->value)); return; case OMITTED_OT: printf(""); return; } printf("%d", o->value); if (annotate) print_operand_annotation(o); } static void print_operand_g(const assembly_operand *o, int annotate) { switch (o->type) { case EXPRESSION_OT: printf("expr_"); break; case CONSTANT_OT: printf("long_"); break; case HALFCONSTANT_OT: printf("short_"); break; case BYTECONSTANT_OT: printf("byte_"); break; case ZEROCONSTANT_OT: printf("zero_"); return; case DEREFERENCE_OT: printf("*"); break; case GLOBALVAR_OT: printf("global_%d (%s)", o->value, variable_name(o->value)); return; case LOCALVAR_OT: if (o->value == 0) printf("stackptr"); else printf("local_%d (%s)", o->value-1, variable_name(o->value)); return; case SYSFUN_OT: if (o->value >= 0 && o->value < NUMBER_SYSTEM_FUNCTIONS) printf("%s", system_functions.keywords[o->value]); else printf(""); return; case OMITTED_OT: printf(""); return; default: printf("???_"); break; } printf("%d", o->value); if (annotate) print_operand_annotation(o); } extern void print_operand(const assembly_operand *o, int annotate) { if (!glulx_mode) print_operand_z(o, annotate); else print_operand_g(o, annotate); } /* ------------------------------------------------------------------------- */ /* Writing bytes to the code area */ /* ------------------------------------------------------------------------- */ static void byteout(int32 i, int mv) { ensure_memory_list_available(&zcode_markers_memlist, zcode_ha_size+1); ensure_memory_list_available(&zcode_holding_area_memlist, zcode_ha_size+1); zcode_markers[zcode_ha_size] = (uchar) mv; zcode_holding_area[zcode_ha_size++] = (uchar) i; zmachine_pc++; } /* ------------------------------------------------------------------------- */ /* A database of the 115 canonical Infocom opcodes in Versions 3 to 6 */ /* And of the however-many-there-are Glulx opcodes */ /* ------------------------------------------------------------------------- */ typedef struct opcodez { uchar *name; /* Lower case standard name */ int version1; /* Valid from this version number... */ int version2; /* ...until this one (or forever if this is 0) */ int extension; /* In later versions, see this line in extension table: if -1, the opcode is illegal in later versions */ int code; /* Opcode number within its operand-number block */ int flags; /* Flags (see below) */ int op_rules; /* Any unusual operand rule applying (see below) */ int flags2_set; /* If not zero, set this bit in Flags 2 in the header of any game using the opcode */ int no; /* Number of operands (see below) */ } opcodez; typedef struct opcodeg { uchar *name; /* Lower case standard name */ int32 code; /* Opcode number */ int flags; /* Flags (see below) */ int op_rules; /* Any unusual operand rule applying (see below) */ int no; /* Number of operands */ } opcodeg; /* Flags which can be set */ #define St 1 /* Store */ #define Br 2 /* Branch */ #define Rf 4 /* "Return flag": execution never continues after this opcode (e.g., is a return or unconditional jump) */ #define St2 8 /* Store2 (second-to-last operand is store (Glulx)) */ /* Codes for any unusual operand assembly rules */ /* Z-code: */ #define VARIAB 1 /* First operand expected to be a variable name and assembled to a short constant: the variable number */ #define TEXT 2 /* One text operand, to be Z-encoded into the program */ #define LABEL 3 /* One operand, a label, given as long constant offset */ #define CALL 4 /* First operand is name of a routine, to be assembled as long constant (the routine's packed address): as if the name were prefixed by #r$ */ /* Glulx: (bit flags for Glulx VM features) */ #define GOP_Unicode 1 /* uses_unicode_features */ #define GOP_MemHeap 2 /* uses_memheap_features */ #define GOP_Acceleration 4 /* uses_acceleration_features */ #define GOP_Float 8 /* uses_float_features */ #define GOP_ExtUndo 16 /* uses_extundo_features */ #define GOP_Double 32 /* uses_double_features */ /* Codes for the number of operands */ #define TWO 1 /* 2 (with certain types of operand, compiled as VAR) */ #define VAR 2 /* 0 to 4 */ #define VAR_LONG 3 /* 0 to 8 */ #define ONE 4 /* 1 */ #define ZERO 5 /* 0 */ #define EXT 6 /* Extended opcode set VAR: 0 to 4 */ #define EXT_LONG 7 /* Extended: 0 to 8 (not used by the canonical opcodes) */ static opcodez opcodes_table_z[] = { /* Opcodes introduced in Version 3 */ /* 0 */ { (uchar *) "je", 3, 0, -1, 0x01, Br, 0, 0, TWO }, /* 1 */ { (uchar *) "jl", 3, 0, -1, 0x02, Br, 0, 0, TWO }, /* 2 */ { (uchar *) "jg", 3, 0, -1, 0x03, Br, 0, 0, TWO }, /* 3 */ { (uchar *) "dec_chk", 3, 0, -1, 0x04, Br, VARIAB, 0, TWO }, /* 4 */ { (uchar *) "inc_chk", 3, 0, -1, 0x05, Br, VARIAB, 0, TWO }, /* 5 */ { (uchar *) "jin", 3, 0, -1, 0x06, Br, 0, 0, TWO }, /* 6 */ { (uchar *) "test", 3, 0, -1, 0x07, Br, 0, 0, TWO }, /* 7 */ { (uchar *) "or", 3, 0, -1, 0x08, St, 0, 0, TWO }, /* 8 */ { (uchar *) "and", 3, 0, -1, 0x09, St, 0, 0, TWO }, /* 9 */ { (uchar *) "test_attr", 3, 0, -1, 0x0A, Br, 0, 0, TWO }, /* 10 */ {(uchar *) "set_attr", 3, 0, -1, 0x0B, 0, 0, 0, TWO }, /* 11 */ {(uchar *) "clear_attr", 3, 0, -1, 0x0C, 0, 0, 0, TWO }, /* 12 */ {(uchar *) "store", 3, 0, -1, 0x0D, 0, VARIAB, 0, TWO }, /* 13 */ {(uchar *) "insert_obj", 3, 0, -1, 0x0E, 0, 0, 0, TWO }, /* 14 */ {(uchar *) "loadw", 3, 0, -1, 0x0F, St, 0, 0, TWO }, /* 15 */ {(uchar *) "loadb", 3, 0, -1, 0x10, St, 0, 0, TWO }, /* 16 */ {(uchar *) "get_prop", 3, 0, -1, 0x11, St, 0, 0, TWO }, /* 17 */ {(uchar *) "get_prop_addr", 3, 0, -1, 0x12, St, 0, 0, TWO }, /* 18 */ {(uchar *) "get_next_prop", 3, 0, -1, 0x13, St, 0, 0, TWO }, /* 19 */ {(uchar *) "add", 3, 0, -1, 0x14, St, 0, 0, TWO }, /* 20 */ {(uchar *) "sub", 3, 0, -1, 0x15, St, 0, 0, TWO }, /* 21 */ {(uchar *) "mul", 3, 0, -1, 0x16, St, 0, 0, TWO }, /* 22 */ {(uchar *) "div", 3, 0, -1, 0x17, St, 0, 0, TWO }, /* 23 */ {(uchar *) "mod", 3, 0, -1, 0x18, St, 0, 0, TWO }, /* 24 */ {(uchar *) "call", 3, 0, -1, 0x20, St, CALL, 0, VAR }, /* 25 */ {(uchar *) "storew", 3, 0, -1, 0x21, 0, 0, 0, VAR }, /* 26 */ {(uchar *) "storeb", 3, 0, -1, 0x22, 0, 0, 0, VAR }, /* 27 */ {(uchar *) "put_prop", 3, 0, -1, 0x23, 0, 0, 0, VAR }, /* This is the version of "read" called "sread" internally: */ /* 28 */ {(uchar *) "read", 3, 0, -1, 0x24, 0, 0, 0, VAR }, /* 29 */ {(uchar *) "print_char", 3, 0, -1, 0x25, 0, 0, 0, VAR }, /* 30 */ {(uchar *) "print_num", 3, 0, -1, 0x26, 0, 0, 0, VAR }, /* 31 */ {(uchar *) "random", 3, 0, -1, 0x27, St, 0, 0, VAR }, /* 32 */ {(uchar *) "push", 3, 0, -1, 0x28, 0, 0, 0, VAR }, /* 33 */ {(uchar *) "pull", 3, 5, 6, 0x29, 0, VARIAB, 0, VAR }, /* 34 */ {(uchar *) "split_window", 3, 0, -1, 0x2A, 0, 0, 0, VAR }, /* 35 */ {(uchar *) "set_window", 3, 0, -1, 0x2B, 0, 0, 0, VAR }, /* 36 */ {(uchar *) "output_stream", 3, 0, -1, 0x33, 0, 0, 0, VAR }, /* 37 */ {(uchar *) "input_stream", 3, 0, -1, 0x34, 0, 0, 0, VAR }, /* 38 */ {(uchar *) "sound_effect", 3, 0, -1, 0x35, 0, 0, 7, VAR }, /* 39 */ {(uchar *) "jz", 3, 0, -1, 0x00, Br, 0, 0, ONE }, /* 40 */ {(uchar *) "get_sibling", 3, 0, -1, 0x01, St+Br, 0, 0, ONE }, /* 41 */ {(uchar *) "get_child", 3, 0, -1, 0x02, St+Br, 0, 0, ONE }, /* 42 */ {(uchar *) "get_parent", 3, 0, -1, 0x03, St, 0, 0, ONE }, /* 43 */ {(uchar *) "get_prop_len", 3, 0, -1, 0x04, St, 0, 0, ONE }, /* 44 */ {(uchar *) "inc", 3, 0, -1, 0x05, 0, VARIAB, 0, ONE }, /* 45 */ {(uchar *) "dec", 3, 0, -1, 0x06, 0, VARIAB, 0, ONE }, /* 46 */ {(uchar *) "print_addr", 3, 0, -1, 0x07, 0, 0, 0, ONE }, /* 47 */ {(uchar *) "remove_obj", 3, 0, -1, 0x09, 0, 0, 0, ONE }, /* 48 */ {(uchar *) "print_obj", 3, 0, -1, 0x0A, 0, 0, 0, ONE }, /* 49 */ {(uchar *) "ret", 3, 0, -1, 0x0B, Rf, 0, 0, ONE }, /* 50 */ {(uchar *) "jump", 3, 0, -1, 0x0C, Rf, LABEL, 0, ONE }, /* 51 */ {(uchar *) "print_paddr", 3, 0, -1, 0x0D, 0, 0, 0, ONE }, /* 52 */ {(uchar *) "load", 3, 0, -1, 0x0E, St, VARIAB, 0, ONE }, /* 53 */ {(uchar *) "not", 3, 3, 0, 0x0F, St, 0, 0, ONE }, /* 54 */ {(uchar *) "rtrue", 3, 0, -1, 0x00, Rf, 0, 0,ZERO }, /* 55 */ {(uchar *) "rfalse", 3, 0, -1, 0x01, Rf, 0, 0,ZERO }, /* 56 */ {(uchar *) "print", 3, 0, -1, 0x02, 0, TEXT, 0,ZERO }, /* 57 */ {(uchar *) "print_ret", 3, 0, -1, 0x03, Rf, TEXT, 0,ZERO }, /* 58 */ {(uchar *) "nop", 3, 0, -1, 0x04, 0, 0, 0,ZERO }, /* 59 */ {(uchar *) "save", 3, 3, 1, 0x05, Br, 0, 0,ZERO }, /* 60 */ {(uchar *) "restore", 3, 3, 2, 0x06, Br, 0, 0,ZERO }, /* 61 */ {(uchar *) "restart", 3, 0, -1, 0x07, 0, 0, 0,ZERO }, /* 62 */ {(uchar *) "ret_popped", 3, 0, -1, 0x08, Rf, 0, 0,ZERO }, /* 63 */ {(uchar *) "pop", 3, 4, -1, 0x09, 0, 0, 0,ZERO }, /* 64 */ {(uchar *) "quit", 3, 0, -1, 0x0A, Rf, 0, 0,ZERO }, /* 65 */ {(uchar *) "new_line", 3, 0, -1, 0x0B, 0, 0, 0,ZERO }, /* 66 */ {(uchar *) "show_status", 3, 3, -1, 0x0C, 0, 0, 0,ZERO }, /* 67 */ {(uchar *) "verify", 3, 0, -1, 0x0D, Br, 0, 0,ZERO }, /* Opcodes introduced in Version 4 */ /* 68 */ {(uchar *) "call_2s", 4, 0, -1, 0x19, St, CALL, 0, TWO }, /* 69 */ {(uchar *) "call_vs", 4, 0, -1, 0x20, St, CALL, 0, VAR }, /* This is the version of "read" called "aread" internally: */ /* 70 */ {(uchar *) "read", 4, 0, -1, 0x24, St, 0, 0, VAR }, /* 71 */ {(uchar *) "call_vs2", 4, 0, -1, 0x2C, St, CALL, 0, VAR_LONG }, /* 72 */ {(uchar *) "erase_window", 4, 0, -1, 0x2D, 0, 0, 0, VAR }, /* 73 */ {(uchar *) "erase_line", 4, 0, -1, 0x2E, 0, 0, 0, VAR }, /* 74 */ {(uchar *) "set_cursor", 4, 0, -1, 0x2F, 0, 0, 0, VAR }, /* 75 */ {(uchar *) "get_cursor", 4, 0, -1, 0x30, 0, 0, 0, VAR }, /* 76 */ {(uchar *) "set_text_style", 4, 0, -1, 0x31, 0, 0, 0, VAR }, /* 77 */ {(uchar *) "buffer_mode", 4, 0, -1, 0x32, 0, 0, 0, VAR }, /* 78 */ {(uchar *) "read_char", 4, 0, -1, 0x36, St, 0, 0, VAR }, /* 79 */ {(uchar *) "scan_table", 4, 0, -1, 0x37, St+Br, 0, 0, VAR }, /* 80 */ {(uchar *) "call_1s", 4, 0, -1, 0x08, St, CALL, 0, ONE }, /* Opcodes introduced in Version 5 */ /* 81 */ {(uchar *) "call_2n", 5, 0, -1, 0x1a, 0, CALL, 0, TWO }, /* 82 */ {(uchar *) "set_colour", 5, 0, -1, 0x1b, 0, 0, 6, TWO }, /* 83 */ {(uchar *) "throw", 5, 0, -1, 0x1c, 0, 0, 0, TWO }, /* 84 */ {(uchar *) "call_vn", 5, 0, -1, 0x39, 0, CALL, 0, VAR }, /* 85 */ {(uchar *) "call_vn2", 5, 0, -1, 0x3a, 0, CALL, 0, VAR_LONG }, /* 86 */ {(uchar *) "tokenise", 5, 0, -1, 0x3b, 0, 0, 0, VAR }, /* 87 */ {(uchar *) "encode_text", 5, 0, -1, 0x3c, 0, 0, 0, VAR }, /* 88 */ {(uchar *) "copy_table", 5, 0, -1, 0x3d, 0, 0, 0, VAR }, /* 89 */ {(uchar *) "print_table", 5, 0, -1, 0x3e, 0, 0, 0, VAR }, /* 90 */ {(uchar *) "check_arg_count", 5, 0, -1, 0x3f, Br, 0, 0, VAR }, /* 91 */ {(uchar *) "call_1n", 5, 0, -1, 0x0F, 0, CALL, 0, ONE }, /* 92 */ {(uchar *) "catch", 5, 0, -1, 0x09, St, 0, 0, ZERO }, /* 93 */ {(uchar *) "piracy", 5, 0, -1, 0x0F, Br, 0, 0, ZERO }, /* 94 */ {(uchar *) "log_shift", 5, 0, -1, 0x02, St, 0, 0, EXT }, /* 95 */ {(uchar *) "art_shift", 5, 0, -1, 0x03, St, 0, 0, EXT }, /* 96 */ {(uchar *) "set_font", 5, 0, -1, 0x04, St, 0, 0, EXT }, /* 97 */ {(uchar *) "save_undo", 5, 0, -1, 0x09, St, 0, 4, EXT }, /* 98 */ {(uchar *) "restore_undo", 5, 0, -1, 0x0A, St, 0, 4, EXT }, /* Opcodes introduced in Version 6 */ /* 99 */ { (uchar *) "draw_picture", 6, 6, -1, 0x05, 0, 0, 3, EXT }, /* 100 */ { (uchar *) "picture_data", 6, 6, -1, 0x06, Br, 0, 3, EXT }, /* 101 */ { (uchar *) "erase_picture", 6, 6, -1, 0x07, 0, 0, 3, EXT }, /* 102 */ { (uchar *) "set_margins", 6, 6, -1, 0x08, 0, 0, 0, EXT }, /* 103 */ { (uchar *) "move_window", 6, 6, -1, 0x10, 0, 0, 0, EXT }, /* 104 */ { (uchar *) "window_size", 6, 6, -1, 0x11, 0, 0, 0, EXT }, /* 105 */ { (uchar *) "window_style", 6, 6, -1, 0x12, 0, 0, 0, EXT }, /* 106 */ { (uchar *) "get_wind_prop", 6, 6, -1, 0x13, St, 0, 0, EXT }, /* 107 */ { (uchar *) "scroll_window", 6, 6, -1, 0x14, 0, 0, 0, EXT }, /* 108 */ { (uchar *) "pop_stack", 6, 6, -1, 0x15, 0, 0, 0, EXT }, /* 109 */ { (uchar *) "read_mouse", 6, 6, -1, 0x16, 0, 0, 5, EXT }, /* 110 */ { (uchar *) "mouse_window", 6, 6, -1, 0x17, 0, 0, 5, EXT }, /* 111 */ { (uchar *) "push_stack", 6, 6, -1, 0x18, Br, 0, 0, EXT }, /* 112 */ { (uchar *) "put_wind_prop", 6, 6, -1, 0x19, 0, 0, 0, EXT }, /* 113 */ { (uchar *) "print_form", 6, 6, -1, 0x1a, 0, 0, 0, EXT }, /* 114 */ { (uchar *) "make_menu", 6, 6, -1, 0x1b, Br, 0, 8, EXT }, /* 115 */ { (uchar *) "picture_table", 6, 6, -1, 0x1c, 0, 0, 3, EXT }, /* Opcodes introduced in Z-Machine Specification Standard 1.0 */ /* 116 */ { (uchar *) "print_unicode", 5, 0, -1, 0x0b, 0, 0, 0, EXT }, /* 117 */ { (uchar *) "check_unicode", 5, 0, -1, 0x0c, St, 0, 0, EXT }, /* Opcodes introduced in Z-Machine Specification Standard 1.1 */ /* 118 */ { (uchar *) "set_true_colour", 5, 0, -1, 0x0d, 0, 0, 0, EXT }, /* 119 */ { (uchar *) "buffer_screen", 6, 6, -1, 0x1d, St, 0, 0, EXT } }; /* Subsequent forms for opcodes whose meaning changes with version */ static opcodez extension_table_z[] = { /* 0 */ { (uchar *) "not", 4, 4, 3, 0x0F, St, 0, 0, ONE }, /* 1 */ { (uchar *) "save", 4, 4, 4, 0x05, St, 0, 0,ZERO }, /* 2 */ { (uchar *) "restore", 4, 4, 5, 0x06, St, 0, 0,ZERO }, /* 3 */ { (uchar *) "not", 5, 0, -1, 0x38, St, 0, 0, VAR }, /* 4 */ { (uchar *) "save", 5, 0, -1, 0x00, St, 0, 0, EXT }, /* 5 */ { (uchar *) "restore", 5, 0, -1, 0x01, St, 0, 0, EXT }, /* 6 */ { (uchar *) "pull", 6, 6, -1, 0x29, St, 0, 0, VAR } }; static opcodez invalid_opcode_z = { (uchar *) "invalid", 0, 0, -1, 0xff, 0, 0, 0, ZERO}; static opcodez custom_opcode_z; /* Note that this table assumes that all opcodes have at most two branch-label or store operands, and that if they exist, they are the last operands. Glulx does not actually guarantee this. But it is true for all opcodes in the current Glulx spec, so we will assume it for now. Also note that Inform can only compile branches to constant offsets, even though the Glulx machine can handle stack or memory-loaded operands in a branch instruction. */ static opcodeg opcodes_table_g[] = { { (uchar *) "nop", 0x00, 0, 0, 0 }, { (uchar *) "add", 0x10, St, 0, 3 }, { (uchar *) "sub", 0x11, St, 0, 3 }, { (uchar *) "mul", 0x12, St, 0, 3 }, { (uchar *) "div", 0x13, St, 0, 3 }, { (uchar *) "mod", 0x14, St, 0, 3 }, { (uchar *) "neg", 0x15, St, 0, 2 }, { (uchar *) "bitand", 0x18, St, 0, 3 }, { (uchar *) "bitor", 0x19, St, 0, 3 }, { (uchar *) "bitxor", 0x1A, St, 0, 3 }, { (uchar *) "bitnot", 0x1B, St, 0, 2 }, { (uchar *) "shiftl", 0x1C, St, 0, 3 }, { (uchar *) "sshiftr", 0x1D, St, 0, 3 }, { (uchar *) "ushiftr", 0x1E, St, 0, 3 }, { (uchar *) "jump", 0x20, Br|Rf, 0, 1 }, { (uchar *) "jz", 0x22, Br, 0, 2 }, { (uchar *) "jnz", 0x23, Br, 0, 2 }, { (uchar *) "jeq", 0x24, Br, 0, 3 }, { (uchar *) "jne", 0x25, Br, 0, 3 }, { (uchar *) "jlt", 0x26, Br, 0, 3 }, { (uchar *) "jge", 0x27, Br, 0, 3 }, { (uchar *) "jgt", 0x28, Br, 0, 3 }, { (uchar *) "jle", 0x29, Br, 0, 3 }, { (uchar *) "jltu", 0x2A, Br, 0, 3 }, { (uchar *) "jgeu", 0x2B, Br, 0, 3 }, { (uchar *) "jgtu", 0x2C, Br, 0, 3 }, { (uchar *) "jleu", 0x2D, Br, 0, 3 }, { (uchar *) "call", 0x30, St, 0, 3 }, { (uchar *) "return", 0x31, Rf, 0, 1 }, { (uchar *) "catch", 0x32, Br|St, 0, 2 }, { (uchar *) "throw", 0x33, Rf, 0, 2 }, { (uchar *) "tailcall", 0x34, Rf, 0, 2 }, { (uchar *) "copy", 0x40, St, 0, 2 }, { (uchar *) "copys", 0x41, St, 0, 2 }, { (uchar *) "copyb", 0x42, St, 0, 2 }, { (uchar *) "sexs", 0x44, St, 0, 2 }, { (uchar *) "sexb", 0x45, St, 0, 2 }, { (uchar *) "aload", 0x48, St, 0, 3 }, { (uchar *) "aloads", 0x49, St, 0, 3 }, { (uchar *) "aloadb", 0x4A, St, 0, 3 }, { (uchar *) "aloadbit", 0x4B, St, 0, 3 }, { (uchar *) "astore", 0x4C, 0, 0, 3 }, { (uchar *) "astores", 0x4D, 0, 0, 3 }, { (uchar *) "astoreb", 0x4E, 0, 0, 3 }, { (uchar *) "astorebit", 0x4F, 0, 0, 3 }, { (uchar *) "stkcount", 0x50, St, 0, 1 }, { (uchar *) "stkpeek", 0x51, St, 0, 2 }, { (uchar *) "stkswap", 0x52, 0, 0, 0 }, { (uchar *) "stkroll", 0x53, 0, 0, 2 }, { (uchar *) "stkcopy", 0x54, 0, 0, 1 }, { (uchar *) "streamchar", 0x70, 0, 0, 1 }, { (uchar *) "streamnum", 0x71, 0, 0, 1 }, { (uchar *) "streamstr", 0x72, 0, 0, 1 }, { (uchar *) "gestalt", 0x0100, St, 0, 3 }, { (uchar *) "debugtrap", 0x0101, 0, 0, 1 }, { (uchar *) "getmemsize", 0x0102, St, 0, 1 }, { (uchar *) "setmemsize", 0x0103, St, 0, 2 }, { (uchar *) "jumpabs", 0x0104, Rf, 0, 1 }, { (uchar *) "random", 0x0110, St, 0, 2 }, { (uchar *) "setrandom", 0x0111, 0, 0, 1 }, { (uchar *) "quit", 0x0120, Rf, 0, 0 }, { (uchar *) "verify", 0x0121, St, 0, 1 }, { (uchar *) "restart", 0x0122, 0, 0, 0 }, { (uchar *) "save", 0x0123, St, 0, 2 }, { (uchar *) "restore", 0x0124, St, 0, 2 }, { (uchar *) "saveundo", 0x0125, St, 0, 1 }, { (uchar *) "restoreundo", 0x0126, St, 0, 1 }, { (uchar *) "protect", 0x0127, 0, 0, 2 }, { (uchar *) "glk", 0x0130, St, 0, 3 }, { (uchar *) "getstringtbl", 0x0140, St, 0, 1 }, { (uchar *) "setstringtbl", 0x0141, 0, 0, 1 }, { (uchar *) "getiosys", 0x0148, St|St2, 0, 2 }, { (uchar *) "setiosys", 0x0149, 0, 0, 2 }, { (uchar *) "linearsearch", 0x0150, St, 0, 8 }, { (uchar *) "binarysearch", 0x0151, St, 0, 8 }, { (uchar *) "linkedsearch", 0x0152, St, 0, 7 }, { (uchar *) "callf", 0x0160, St, 0, 2 }, { (uchar *) "callfi", 0x0161, St, 0, 3 }, { (uchar *) "callfii", 0x0162, St, 0, 4 }, { (uchar *) "callfiii", 0x0163, St, 0, 5 }, { (uchar *) "streamunichar", 0x73, 0, GOP_Unicode, 1 }, { (uchar *) "mzero", 0x170, 0, GOP_MemHeap, 2 }, { (uchar *) "mcopy", 0x171, 0, GOP_MemHeap, 3 }, { (uchar *) "malloc", 0x178, St, GOP_MemHeap, 2 }, { (uchar *) "mfree", 0x179, 0, GOP_MemHeap, 1 }, { (uchar *) "accelfunc", 0x180, 0, GOP_Acceleration, 2 }, { (uchar *) "accelparam", 0x181, 0, GOP_Acceleration, 2 }, { (uchar *) "hasundo", 0x128, St, GOP_ExtUndo, 1 }, { (uchar *) "discardundo",0x129, 0, GOP_ExtUndo, 0 }, { (uchar *) "numtof", 0x190, St, GOP_Float, 2 }, { (uchar *) "ftonumz", 0x191, St, GOP_Float, 2 }, { (uchar *) "ftonumn", 0x192, St, GOP_Float, 2 }, { (uchar *) "ceil", 0x198, St, GOP_Float, 2 }, { (uchar *) "floor", 0x199, St, GOP_Float, 2 }, { (uchar *) "fadd", 0x1A0, St, GOP_Float, 3 }, { (uchar *) "fsub", 0x1A1, St, GOP_Float, 3 }, { (uchar *) "fmul", 0x1A2, St, GOP_Float, 3 }, { (uchar *) "fdiv", 0x1A3, St, GOP_Float, 3 }, { (uchar *) "fmod", 0x1A4, St|St2, GOP_Float, 4 }, { (uchar *) "sqrt", 0x1A8, St, GOP_Float, 2 }, { (uchar *) "exp", 0x1A9, St, GOP_Float, 2 }, { (uchar *) "log", 0x1AA, St, GOP_Float, 2 }, { (uchar *) "pow", 0x1AB, St, GOP_Float, 3 }, { (uchar *) "sin", 0x1B0, St, GOP_Float, 2 }, { (uchar *) "cos", 0x1B1, St, GOP_Float, 2 }, { (uchar *) "tan", 0x1B2, St, GOP_Float, 2 }, { (uchar *) "asin", 0x1B3, St, GOP_Float, 2 }, { (uchar *) "acos", 0x1B4, St, GOP_Float, 2 }, { (uchar *) "atan", 0x1B5, St, GOP_Float, 2 }, { (uchar *) "atan2", 0x1B6, St, GOP_Float, 3 }, { (uchar *) "jfeq", 0x1C0, Br, GOP_Float, 4 }, { (uchar *) "jfne", 0x1C1, Br, GOP_Float, 4 }, { (uchar *) "jflt", 0x1C2, Br, GOP_Float, 3 }, { (uchar *) "jfle", 0x1C3, Br, GOP_Float, 3 }, { (uchar *) "jfgt", 0x1C4, Br, GOP_Float, 3 }, { (uchar *) "jfge", 0x1C5, Br, GOP_Float, 3 }, { (uchar *) "jisnan", 0x1C8, Br, GOP_Float, 2 }, { (uchar *) "jisinf", 0x1C9, Br, GOP_Float, 2 }, { (uchar *) "numtod", 0x200, St|St2, GOP_Double, 3 }, { (uchar *) "dtonumz", 0x201, St, GOP_Double, 3 }, { (uchar *) "dtonumn", 0x202, St, GOP_Double, 3 }, { (uchar *) "ftod", 0x203, St|St2, GOP_Double, 3 }, { (uchar *) "dtof", 0x204, St, GOP_Double, 3 }, { (uchar *) "dceil", 0x208, St|St2, GOP_Double, 4 }, { (uchar *) "dfloor", 0x209, St|St2, GOP_Double, 4 }, { (uchar *) "dadd", 0x210, St|St2, GOP_Double, 6 }, { (uchar *) "dsub", 0x211, St|St2, GOP_Double, 6 }, { (uchar *) "dmul", 0x212, St|St2, GOP_Double, 6 }, { (uchar *) "ddiv", 0x213, St|St2, GOP_Double, 6 }, { (uchar *) "dmodr", 0x214, St|St2, GOP_Double, 6 }, { (uchar *) "dmodq", 0x215, St|St2, GOP_Double, 6 }, { (uchar *) "dsqrt", 0x218, St|St2, GOP_Double, 4 }, { (uchar *) "dexp", 0x219, St|St2, GOP_Double, 4 }, { (uchar *) "dlog", 0x21A, St|St2, GOP_Double, 4 }, { (uchar *) "dpow", 0x21B, St|St2, GOP_Double, 6 }, { (uchar *) "dsin", 0x220, St|St2, GOP_Double, 4 }, { (uchar *) "dcos", 0x221, St|St2, GOP_Double, 4 }, { (uchar *) "dtan", 0x222, St|St2, GOP_Double, 4 }, { (uchar *) "dasin", 0x223, St|St2, GOP_Double, 4 }, { (uchar *) "dacos", 0x224, St|St2, GOP_Double, 4 }, { (uchar *) "datan", 0x225, St|St2, GOP_Double, 4 }, { (uchar *) "datan2", 0x226, St|St2, GOP_Double, 6 }, { (uchar *) "jdeq", 0x230, Br, GOP_Double, 7 }, { (uchar *) "jdne", 0x231, Br, GOP_Double, 7 }, { (uchar *) "jdlt", 0x232, Br, GOP_Double, 5 }, { (uchar *) "jdle", 0x233, Br, GOP_Double, 5 }, { (uchar *) "jdgt", 0x234, Br, GOP_Double, 5 }, { (uchar *) "jdge", 0x235, Br, GOP_Double, 5 }, { (uchar *) "jdisnan", 0x238, Br, GOP_Double, 3 }, { (uchar *) "jdisinf", 0x239, Br, GOP_Double, 3 }, }; /* The opmacros table is used for fake opcodes. The opcode numbers are ignored; this table is only used for argument parsing. */ static opcodeg opmacros_table_g[] = { { (uchar *) "pull", pull_gm, St, 0, 1 }, { (uchar *) "push", push_gm, 0, 0, 1 }, { (uchar *) "dload", dload_gm, St|St2, 0, 3 }, { (uchar *) "dstore", dstore_gm, 0, 0, 3 }, }; static opcodeg custom_opcode_g; static opcodez internal_number_to_opcode_z(int32 i) { opcodez x; ASSERT_ZCODE(); if (i == -1) return custom_opcode_z; x = opcodes_table_z[i]; if (instruction_set_number < x.version1) return invalid_opcode_z; if (x.version2 == 0) return x; if (instruction_set_number <= x.version2) return x; i = x.extension; if (i < 0) return invalid_opcode_z; x = extension_table_z[i]; if (instruction_set_number < x.version1) return invalid_opcode_z; if (x.version2 == 0) return x; if (instruction_set_number <= x.version2) return x; return extension_table_z[x.extension]; } static void make_opcode_syntax_z(opcodez opco) { char *p = "", *q = opcode_syntax_string; /* TODO: opcode_syntax_string[128] is unsafe */ sprintf(q, "%s", opco.name); switch(opco.no) { case ONE: p=" "; break; case TWO: p=" "; break; case EXT: case VAR: p=" <0 to 4 operands>"; break; case VAR_LONG: p=" <0 to 8 operands>"; break; } switch(opco.op_rules) { case TEXT: sprintf(q+strlen(q), " "); return; case LABEL: sprintf(q+strlen(q), "