Update to commit e33eef4f8fab800eaf4a32b2d159cde6c4bbb38e
authorJason Self <j@jxself.org>
Tue, 18 May 2021 01:15:42 +0000 (18:15 -0700)
committerJason Self <j@jxself.org>
Tue, 18 May 2021 01:15:42 +0000 (18:15 -0700)
Dated May 15 2021. These changes are similiarly relicensed to GPL
per Section 4(c)(ii) of the Artistic License 2.0.

18 files changed:
src/arrays.c
src/asm.c
src/bpatch.c
src/directs.c
src/errors.c
src/expressc.c
src/expressp.c
src/files.c
src/header.h
src/inform.c
src/linker.c
src/memory.c
src/objects.c
src/states.c
src/symbols.c
src/tables.c
src/text.c
src/verbs.c

index 4c8f56feac5672331da185a4c0b9110eebd30991..9c001ccb0ed57ec678f1c6542910ac257c8be8c2 100644 (file)
@@ -294,7 +294,6 @@ extern void make_global(int array_flag, int name_only)
     assembly_operand AO;
     
     int extraspace;
-    int orig_area_size;
 
     int32 global_symbol;
     const char *global_name;
@@ -535,12 +534,10 @@ extern void make_global(int array_flag, int name_only)
         extraspace += WORDSIZE;
     
     if (!is_static) {
-        orig_area_size = dynamic_array_area_size;
         array_base = dynamic_array_area_size;
         dynamic_array_area_size += extraspace;
     }
     else {
-        orig_area_size = static_array_area_size;
         array_base = static_array_area_size;
         static_array_area_size += extraspace;
     }
index faace9c168ad549a8c3e6ebfcacb751bd18931b9..6a263a311b6196ec327fcbd6d2cbc72a5ff307e3 100644 (file)
--- a/src/asm.c
+++ b/src/asm.c
@@ -867,7 +867,7 @@ extern void assemblez_instruction(assembly_instruction *AI)
 
     if (operand_rules==TEXT)
     {   int32 i;
-        uchar *tmp = translate_text(zcode_holding_area + zcode_ha_size, zcode_holding_area+MAX_ZCODE_SIZE, AI->text);
+        uchar *tmp = translate_text(zcode_holding_area + zcode_ha_size, zcode_holding_area+MAX_ZCODE_SIZE, AI->text, STRCTX_GAMEOPC);
         if (!tmp)
             memoryerror("MAX_ZCODE_SIZE", MAX_ZCODE_SIZE);
         j = subtract_pointers(tmp, (zcode_holding_area + zcode_ha_size));
@@ -1575,7 +1575,7 @@ extern int32 assemble_routine_header(int no_locals,
         sprintf(fnt, "[ %s(", name);
         AO.marker = STRING_MV;
         AO.type   = CONSTANT_OT;
-        AO.value  = compile_string(fnt, FALSE, FALSE);
+        AO.value  = compile_string(fnt, STRCTX_INFIX);
         assembleg_1(streamstr_gc, AO);
 
         if (!stackargs) {
@@ -1583,7 +1583,7 @@ extern int32 assemble_routine_header(int no_locals,
             sprintf(fnt, "%s%s = ", (ix==1)?"":", ", variable_name(ix));
             AO.marker = STRING_MV;
             AO.type   = CONSTANT_OT;
-            AO.value  = compile_string(fnt, FALSE, FALSE);
+            AO.value  = compile_string(fnt, STRCTX_INFIX);
             assembleg_1(streamstr_gc, AO);
             AO.marker = 0;
             AO.type = LOCALVAR_OT;
@@ -1596,7 +1596,7 @@ extern int32 assemble_routine_header(int no_locals,
           sprintf(fnt, "%s = ", variable_name(1));
           AO.marker = STRING_MV;
           AO.type   = CONSTANT_OT;
-          AO.value  = compile_string(fnt, FALSE, FALSE);
+          AO.value  = compile_string(fnt, STRCTX_INFIX);
           assembleg_1(streamstr_gc, AO);
           AO.marker = 0;
           AO.type = LOCALVAR_OT;
@@ -1630,7 +1630,7 @@ extern int32 assemble_routine_header(int no_locals,
 
         AO.marker = STRING_MV;
         AO.type   = CONSTANT_OT;
-        AO.value  = compile_string(") ]^", FALSE, FALSE);
+        AO.value  = compile_string(") ]^", STRCTX_INFIX);
         assembleg_1(streamstr_gc, AO);
       }
     }
index b3a467e1c107065df97ab53ccb13c5609cfdabf0..daca6fbe4552f28b0786ca91b044369d47fbe85c 100644 (file)
@@ -320,6 +320,7 @@ static int32 backpatch_value_g(int32 value)
                       break;
                     case CONSTANT_T:
                     case INDIVIDUAL_PROPERTY_T:
+                    case PROPERTY_T:
                       /* value is unchanged */
                       break;
                     default:
index 5df6b0b666f6a4249a0a29966205ec4194f48523..15831728118b840102d401f7f67b7619c996a21e 100644 (file)
@@ -34,7 +34,8 @@ brief_location routine_starts_line; /* Source code location where the current
 
 static int constant_made_yet;      /* Have any constants been defined yet?   */
 
-static int ifdef_stack[32], ifdef_sp;
+#define MAX_IFDEF_STACK (32)
+static int ifdef_stack[MAX_IFDEF_STACK], ifdef_sp;
 
 /* ------------------------------------------------------------------------- */
 
@@ -315,7 +316,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
                 assembly_operand AO;
                 put_token_back();
                 AO = parse_expression(CONSTANT_CONTEXT);
-                if (module_switch && (AO.marker != 0))
+                if (AO.marker != 0)
                     error("A definite value must be given as a Dictionary flag");
                 else
                     val1 = AO.value;
@@ -328,7 +329,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
                     assembly_operand AO;
                     put_token_back();
                     AO = parse_expression(CONSTANT_CONTEXT);
-                    if (module_switch && (AO.marker != 0))
+                    if (AO.marker != 0)
                         error("A definite value must be given as a Dictionary flag");
                     else
                         val3 = AO.value;
@@ -472,7 +473,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
     case IFTRUE_CODE:
         {   assembly_operand AO;
             AO = parse_expression(CONSTANT_CONTEXT);
-            if (module_switch && (AO.marker != 0))
+            if (AO.marker != 0)
             {   error("This condition can't be determined");
                 flag = 0;
             }
@@ -483,7 +484,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
     case IFFALSE_CODE:
         {   assembly_operand AO;
             AO = parse_expression(CONSTANT_CONTEXT);
-            if (module_switch && (AO.marker != 0))
+            if (AO.marker != 0)
             {   error("This condition can't be determined");
                 flag = 1;
             }
@@ -496,6 +497,11 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
         if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
             return ebf_error_recover("semicolon after 'If...' condition", token_text);
 
+        if (ifdef_sp >= MAX_IFDEF_STACK) {
+            error("'If' directives nested too deeply");
+            panic_mode_error_recovery(); return FALSE;
+        }
+        
         if (flag)
         {   ifdef_stack[ifdef_sp++] = TRUE; return FALSE; }
         else
@@ -621,7 +627,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
         if (token_type != DQ_TT)
             return ebf_error_recover("literal string in double-quotes", token_text);
 
-        assign_symbol(i, compile_string(token_text, TRUE, TRUE), CONSTANT_T);
+        assign_symbol(i, compile_string(token_text, STRCTX_LOWSTRING), CONSTANT_T);
         break;
 
     /* --------------------------------------------------------------------- */
@@ -767,7 +773,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
     case RELEASE_CODE:
         {   assembly_operand AO;
             AO = parse_expression(CONSTANT_CONTEXT);
-            if (module_switch && (AO.marker != 0))
+            if (AO.marker != 0)
                 error("A definite value must be given as release number");
             else
                 release_number = AO.value;
@@ -1081,7 +1087,7 @@ the first constant definition");
               break;
             }
 
-            if (module_switch && (AO.marker != 0))
+            if (AO.marker != 0)
                 error("A definite value must be given as version number");
             else 
             if (glulx_mode) 
index 08dd87efa21a698074499f4fe492b907a668e59e..195bfe9f90948bee4ef85c2cec4df79979630d11 100644 (file)
@@ -56,6 +56,7 @@ static void print_preamble(void)
 
             if (!(ErrorReport.main_flag)) printf("\"%s\", ", p);
             printf("line %d: ", ErrorReport.line_number);
+            
             if (ErrorReport.orig_file) {
                 char *op;
                 if (ErrorReport.orig_file <= 0 || ErrorReport.orig_file > total_files)
@@ -81,12 +82,48 @@ static void print_preamble(void)
             }
             printf("%s", p);
             if (with_extension_flag) printf("%s", Source_Extension);
-            printf("(%d): ", ErrorReport.line_number);
+            printf("(%d)", ErrorReport.line_number);
+            
+            if (ErrorReport.orig_file) {
+                char *op;
+                if (ErrorReport.orig_file <= 0 || ErrorReport.orig_file > total_files)
+                    op = ErrorReport.orig_source;
+                else
+                    op = InputFiles[ErrorReport.orig_file-1].filename;
+                printf("|%s", op);
+                if (ErrorReport.orig_line) {
+                    printf("(%d", ErrorReport.orig_line);
+                    if (ErrorReport.orig_char) {
+                        printf(":%d", ErrorReport.orig_char);
+                    }
+                    printf(")");
+                }
+            }
+            
+            printf(": ");
             break;
 
         case 2:  /* Macintosh Programmer's Workshop error message format */
 
-            printf("File \"%s\"; Line %d\t# ", p, ErrorReport.line_number);
+            printf("File \"%s\"; Line %d", p, ErrorReport.line_number);
+            
+            if (ErrorReport.orig_file) {
+                char *op;
+                if (ErrorReport.orig_file <= 0 || ErrorReport.orig_file > total_files)
+                    op = ErrorReport.orig_source;
+                else
+                    op = InputFiles[ErrorReport.orig_file-1].filename;
+                printf(": (\"%s\"", op);
+                if (ErrorReport.orig_line) {
+                    printf("; Line %d", ErrorReport.orig_line);
+                    if (ErrorReport.orig_char) {
+                        printf("; Char %d", ErrorReport.orig_char);
+                    }
+                }
+                printf(")");
+            }
+
+            printf("\t# ");
             break;
     }
 }
@@ -113,6 +150,12 @@ static char *location_text(brief_location report_line)
     if (j <= 0 || j > total_files) p = errpos.source;
     else p = InputFiles[j-1].filename;
     
+    if (!p && errpos.line_number == 0) {
+        /* Special case */
+        strcpy(other_pos_buff, "compiler setup");
+        return other_pos_buff;
+    }
+    
     if (!p) p = "";
 
     len = 0;
index 378582ed5d08873a74273d7ce6dcd99689a22bc9..6651547081a0fb45ffa93c83ac9ff00113ded6b0 100644 (file)
@@ -450,10 +450,12 @@ static void access_memory_z(int oc, assembly_operand AO1, assembly_operand AO2,
         index_ao;
     int x = 0, y = 0, byte_flag = FALSE, read_flag = FALSE, from_module = FALSE;
 
+    INITAO(&zero_ao);
+    INITAO(&size_ao);
+    INITAO(&type_ao);
+
     if (AO1.marker == ARRAY_MV || AO1.marker == STATIC_ARRAY_MV)
     {   
-        INITAO(&zero_ao);
-
         if ((oc == loadb_zc) || (oc == storeb_zc)) byte_flag=TRUE;
         else byte_flag = FALSE;
         if ((oc == loadb_zc) || (oc == loadw_zc)) read_flag=TRUE;
@@ -821,10 +823,12 @@ static void access_memory_g(int oc, assembly_operand AO1, assembly_operand AO2,
     else 
       read_flag = FALSE;
 
+    INITAO(&zero_ao);
+    INITAO(&size_ao);
+    INITAO(&type_ao);
+    
     if (AO1.marker == ARRAY_MV || AO1.marker == STATIC_ARRAY_MV)
     {   
-        INITAO(&zero_ao);
-
         size_ao = zero_ao; size_ao.value = -1;
         for (x=0; x<no_arrays; x++)
         {   if (((AO1.marker == ARRAY_MV) == (!array_locs[x]))
index c5577db6e5145dc52cb2d638087df6ade5be2a5e..5b3c0a714f99104d565625a5450fe06fe8ab0018 100644 (file)
@@ -67,6 +67,7 @@ static int comma_allowed, arrow_allowed, superclass_allowed,
 
 extern int *variable_usage;
 
+/* Must be at least as many as keyword_group system_functions (currently 12) */
 int system_function_usage[32];
 
 static int get_next_etoken(void)
@@ -816,7 +817,7 @@ static int evaluate_term(token_data t, assembly_operand *o)
                  o->type = LONG_CONSTANT_OT;
              else
                  o->type = CONSTANT_OT;
-             o->value = compile_string(t.text, FALSE, FALSE);
+             o->value = compile_string(t.text, STRCTX_GAME);
              return(TRUE);
         case VARIABLE_TT:
              if (!glulx_mode) {
@@ -1464,11 +1465,15 @@ static void check_property_operator(int from_node)
     if ((below != -1) && (ET[below].right != -1))
     {   int n = ET[below].right, flag = FALSE;
 
+        /* Can we handle this dot operator as a native @get_prop (etc)
+           opcode? Only if we recognize the property value as a declared
+           common property constant. */
         if ((ET[n].down == -1)
                 && ((ET[n].value.type == LONG_CONSTANT_OT)
                     || (ET[n].value.type == SHORT_CONSTANT_OT))
                 && ((ET[n].value.value > 0) && (ET[n].value.value < 64))
-                && ((!module_switch) || (ET[n].value.marker == 0)))
+                && (!module_switch)
+                && (ET[n].value.marker == 0))
             flag = TRUE;
 
         if (!flag)
index 70cfc90705de86c9289e4f8e72e2c6e91593aee0..b027dd40f97916e74b90e2a8d28bf2279fa72189 100644 (file)
@@ -1303,8 +1303,38 @@ extern void output_file(void)
 
 FILE *transcript_file_handle; int transcript_open;
 
-extern void write_to_transcript_file(char *text)
-{   fputs(text, transcript_file_handle);
+extern void write_to_transcript_file(char *text, int linetype)
+{
+    if (TRANSCRIPT_FORMAT == 1) {
+        char ch = '?';
+        switch (linetype) {
+            case STRCTX_INFO:
+                ch = 'I'; break;
+            case STRCTX_GAME:
+                ch = 'G'; break;
+            case STRCTX_GAMEOPC:
+                ch = 'H'; break;
+            case STRCTX_VENEER:
+                ch = 'V'; break;
+            case STRCTX_VENEEROPC:
+                ch = 'W'; break;
+            case STRCTX_LOWSTRING:
+                ch = 'L'; break;
+            case STRCTX_ABBREV:
+                ch = 'A'; break;
+            case STRCTX_DICT:
+                ch = 'D'; break;
+            case STRCTX_OBJNAME:
+                ch = 'O'; break;
+            case STRCTX_SYMBOL:
+                ch = 'S'; break;
+            case STRCTX_INFIX:
+                ch = 'X'; break;
+        }
+        fputc(ch, transcript_file_handle);
+        fputs(": ", transcript_file_handle);
+    }
+    fputs(text, transcript_file_handle);
     fputc('\n', transcript_file_handle);
 }
 
@@ -1318,9 +1348,16 @@ extern void open_transcript_file(char *what_of)
 
     transcript_open = TRUE;
 
-    sprintf(topline_buffer, "Transcript of the text of \"%s\"\n\
-[From %s]\n", what_of, banner_line);
-    write_to_transcript_file(topline_buffer);
+    sprintf(topline_buffer, "Transcript of the text of \"%s\"", what_of);
+    write_to_transcript_file(topline_buffer, STRCTX_INFO);
+    sprintf(topline_buffer, "[From %s]", banner_line);
+    write_to_transcript_file(topline_buffer, STRCTX_INFO);
+    if (TRANSCRIPT_FORMAT == 1) {
+        write_to_transcript_file("[I:info, G:game text, V:veneer text, L:lowmem string, A:abbreviation, D:dict word, O:object name, S:symbol, X:infix]", STRCTX_INFO);
+        if (!glulx_mode)
+            write_to_transcript_file("[H:game text inline in opcode, W:veneer text inline in opcode]", STRCTX_INFO);
+    }
+    write_to_transcript_file("",  STRCTX_INFO);
 }
 
 extern void abort_transcript_file(void)
@@ -1334,9 +1371,11 @@ extern void close_transcript_file(void)
     char sn_buffer[7];
 
     write_serial_number(sn_buffer);
-    sprintf(botline_buffer, "\n[End of transcript: release %d.%s]\n",
+    sprintf(botline_buffer, "[End of transcript: release %d, serial %s]",
         release_number, sn_buffer);
-    write_to_transcript_file(botline_buffer);
+    write_to_transcript_file("",  STRCTX_INFO);
+    write_to_transcript_file(botline_buffer, STRCTX_INFO);
+    write_to_transcript_file("",  STRCTX_INFO);
 
     if (ferror(transcript_file_handle))
         fatalerror("I/O failure: couldn't write to transcript file");
index 82d064456d038bc0639685deb0ae45c975cbb773..8b05f26b9a631d99943b6e7cdbe66f32103bb962 100644 (file)
@@ -1945,6 +1945,23 @@ typedef struct operator_s
                                         how far back from the label to go
                                         to find the opmode byte to modify. */
 
+/* ------------------------------------------------------------------------- */
+/*   "String contexts"; the purpose for a given string. This info gets       */
+/*   written to the transcript file (gametext.txt).                          */
+/* ------------------------------------------------------------------------- */
+
+#define STRCTX_INFO      0  /* comment; not stored in game file */
+#define STRCTX_GAME      1  /* strings area */
+#define STRCTX_GAMEOPC   2  /* inline text in opcode (Z-code only) */
+#define STRCTX_VENEER    3  /* strings area, from veneer code */
+#define STRCTX_VENEEROPC 4  /* inline text, veneer code (Z-code only) */
+#define STRCTX_LOWSTRING 5  /* lowmem (Z-code); also dynamic-str literals */
+#define STRCTX_ABBREV    6  /* abbreviation */
+#define STRCTX_DICT      7  /* dictionary word */
+#define STRCTX_OBJNAME   8  /* object "hardware name" */
+#define STRCTX_SYMBOL    9  /* prop/attr/etc names */
+#define STRCTX_INFIX    10  /* text printed in asterisk traces */
+
 /* ========================================================================= */
 /*   Initialisation extern definitions                                       */
 /*                                                                           */
@@ -2357,7 +2374,7 @@ extern void check_temp_files(void);
 extern void remove_temp_files(void);
 
 extern void open_transcript_file(char *what_of);
-extern void write_to_transcript_file(char *text);
+extern void write_to_transcript_file(char *text, int linetype);
 extern void close_transcript_file(void);
 extern void abort_transcript_file(void);
 
@@ -2551,6 +2568,7 @@ extern int DICT_WORD_SIZE, DICT_CHAR_SIZE, DICT_WORD_BYTES;
 extern int ZCODE_HEADER_EXT_WORDS, ZCODE_HEADER_FLAGS_3;
 extern int NUM_ATTR_BYTES, GLULX_OBJECT_EXT_BYTES;
 extern int WARN_UNUSED_ROUTINES, OMIT_UNUSED_ROUTINES;
+extern int TRANSCRIPT_FORMAT;
 
 /* These macros define offsets that depend on the value of NUM_ATTR_BYTES.
    (Meaningful only for Glulx.) */
@@ -2649,6 +2667,7 @@ extern void list_symbols(int level);
 extern void assign_marked_symbol(int index, int marker, int32 value, int type);
 extern void assign_symbol(int index, int32 value, int type);
 extern void issue_unused_warnings(void);
+extern void add_config_symbol_definition(char *symbol, int32 value);
 extern void add_symbol_replacement_mapping(int original, int renamed);
 extern int find_symbol_replacement(int *value);
 extern void df_note_function_start(char *name, uint32 address, 
@@ -2787,8 +2806,8 @@ extern void  compress_game_text(void);
 /* end of the Glulx string compression stuff */
 
 extern void  ao_free_arrays(void);
-extern int32 compile_string(char *b, int in_low_memory, int is_abbrev);
-extern uchar *translate_text(uchar *p, uchar *p_limit, char *s_text);
+extern int32 compile_string(char *b, int strctx);
+extern uchar *translate_text(uchar *p, uchar *p_limit, char *s_text, int strctx);
 extern void  optimise_abbreviations(void);
 extern void  make_abbreviation(char *text);
 extern void  show_dictionary(void);
index 9b30ad3b8ff0d3610fa74c63dddeed3fff3d1b56..a72d81ef6e7a62714000768c361e59771763e68b 100644 (file)
@@ -195,6 +195,12 @@ static void select_target(int targ)
     /* MAX_NUM_ATTR_BYTES can be increased in header.h without fear. */
   }
 
+  if (MAX_ADJECTIVES > 255) {
+    MAX_ADJECTIVES = 255;
+    warning("MAX_ADJECTIVES cannot exceed 255; resetting to 255");
+    /* Only used under Grammar__Version 1, which is obsolete. */
+  }
+    
   /* Set up a few more variables that depend on the above values */
 
   if (!targ) {
@@ -1078,6 +1084,7 @@ extern void translate_temp_filename(int i)
     {   case 1: p=Temp1_Name; break;
         case 2: p=Temp2_Name; break;
         case 3: p=Temp3_Name; break;
+        default: return;
     }
     if (strlen(Temporary_Path)+strlen(Temporary_File)+6 >= PATHLEN) {
         printf ("Temporary_Path is too long.\n");
@@ -1292,15 +1299,16 @@ One or more words can be supplied as \"commands\". These may be:\n\n\
   ++dir         add this directory to Include_Path\n\
   +PATH=dir     change the PATH to this directory\n\
   ++PATH=dir    add this directory to the PATH\n\n\
-  $...          one of the following memory commands:\n");
+  $...          one of the following configuration commands:\n");
   
   printf(
-"     $list            list current memory allocation settings\n\
+"     $list            list current settings\n\
      $huge            make standard \"huge game\" settings %s\n\
      $large           make standard \"large game\" settings %s\n\
      $small           make standard \"small game\" settings %s\n\
      $?SETTING        explain briefly what SETTING is for\n\
-     $SETTING=number  change SETTING to given number\n\n",
+     $SETTING=number  change SETTING to given number\n\
+     $#SYMBOL=number  define SYMBOL as a constant in the story\n\n",
     (DEFAULT_MEMORY_SIZE==HUGE_SIZE)?"(default)":"",
     (DEFAULT_MEMORY_SIZE==LARGE_SIZE)?"(default)":"",
     (DEFAULT_MEMORY_SIZE==SMALL_SIZE)?"(default)":"");
@@ -1317,6 +1325,7 @@ One or more words can be supplied as \"commands\". These may be:\n\n\
   --size huge, --size large, --size small\n\
   --helpopt SETTING\n\
   --opt SETTING=number\n\
+  --define SETTING=number\n\
   --config filename      (setup file)\n\n");
 
 #ifndef PROMPT_INPUT
@@ -1341,15 +1350,18 @@ One or more words can be supplied as \"commands\". These may be:\n\n\
 
    printf("\
   f   frequencies mode: show how useful abbreviations are\n\
-  g   traces calls to functions (except in the library)\n\
-  g2  traces calls to all functions\n\
-  h   print this information\n");
+  g   traces calls to all game functions\n\
+  g2  traces calls to all game and library functions\n\
+  g3  traces calls to all functions (including veneer)\n\
+  h   print general help information\n\
+  h1  print help information on filenames and path options\n\
+  h2  print help information on switches (this page)\n");
 
    printf("\
   i   ignore default switches set within the file\n\
   j   list objects as constructed\n\
-  k   output Infix debugging information to \"%s\" (and switch -D on)\n\
-  l   list every statement run through Inform\n\
+  k   output debugging information to \"%s\"\n\
+  l   list every statement run through Inform (not implemented)\n\
   m   say how much memory has been allocated\n\
   n   print numbers of properties, attributes and actions\n",
           Debugging_Name);
@@ -1364,10 +1376,11 @@ One or more words can be supplied as \"commands\". These may be:\n\n\
 
    printf("\
   u   work out most useful abbreviations (very very slowly)\n\
-  v3  compile to version-3 (\"Standard\") story file\n\
-  v4  compile to version-4 (\"Plus\") story file\n\
-  v5  compile to version-5 (\"Advanced\") story file: the default\n\
-  v6  compile to version-6 (graphical) story file\n\
+  v3  compile to version-3 (\"Standard\"/\"ZIP\") story file\n\
+  v4  compile to version-4 (\"Plus\"/\"EZIP\") story file\n\
+  v5  compile to version-5 (\"Advanced\"/\"XZIP\") story file: the default\n\
+  v6  compile to version-6 (graphical/\"YZIP\") story file\n\
+  v7  compile to version-7 (expanded \"Advanced\") story file\n\
   v8  compile to version-8 (expanded \"Advanced\") story file\n\
   w   disable warning messages\n\
   x   print # for every 100 lines compiled\n\
@@ -1447,6 +1460,7 @@ extern void switches(char *p, int cmode)
         case 'g': switch(p[i+1])
                   {   case '1': trace_fns_setting=1; s=2; break;
                       case '2': trace_fns_setting=2; s=2; break;
+                      case '3': trace_fns_setting=3; s=2; break;
                       default: trace_fns_setting=1; break;
                   }
                   break;
@@ -1462,9 +1476,7 @@ extern void switches(char *p, int cmode)
         case 'k': if (cmode == 0)
                       error("The switch '-k' can't be set with 'Switches'");
                   else
-                  {   debugfile_switch = state;
-                      if (state) define_DEBUG_switch = TRUE;
-                  }
+                      debugfile_switch = state;
                   break;
         case 'l': listing_switch = state; break;
         case 'm': memout_switch = state; break;
@@ -1857,6 +1869,15 @@ static int execute_dashdash_command(char *p, char *p2)
         strcpy(cli_buff, "$?");
         strcpyupper(cli_buff+2, p2, CMD_BUF_SIZE-2);
     }
+    else if (!strcmp(p, "define")) {
+        consumed2 = TRUE;
+        if (!p2) {
+            printf("--define must be followed by \"symbol=number\"\n");
+            return consumed2;
+        }
+        strcpy(cli_buff, "$#");
+        strcpyupper(cli_buff+2, p2, CMD_BUF_SIZE-2);
+    }
     else if (!strcmp(p, "path")) {
         consumed2 = TRUE;
         if (!p2 || !strchr(p2, '=')) {
index d05310a3909704c8e3f0a048bce66e0d74716bb0..6ee0418e0a6aca0390f3ff89ec4e3c0ead4c5b03 100644 (file)
@@ -645,7 +645,7 @@ of the Inform 6 compiler knows about: it may not link in correctly", filename);
             filename, module_size/1024);
         if (linker_trace_level >= 1) printf("%s\n", link_banner);
         if (transcript_switch)
-            write_to_transcript_file(link_banner);
+            write_to_transcript_file(link_banner, STRCTX_INFO);
     }
 
     /* (4) Merge in the dictionary */
index 6b817274161d7bacaa5f61a576bfd701155bb347..a160788d9b51b3195374afa3d7e5c17e6ed2a0a0 100644 (file)
@@ -288,6 +288,7 @@ int32 MEMORY_MAP_EXTENSION;
 int ALLOC_CHUNK_SIZE;
 int WARN_UNUSED_ROUTINES; /* 0: no, 1: yes except in system files, 2: yes always */
 int OMIT_UNUSED_ROUTINES; /* 0: no, 1: yes */
+int TRANSCRIPT_FORMAT; /* 0: classic, 1: prefixed */
 
 /* The way memory sizes are set causes great nuisance for those parameters
    which have different defaults under Z-code and Glulx. We have to get
@@ -365,6 +366,7 @@ static void list_memory_sizes(void)
            (long int) MAX_STATIC_STRINGS);
     printf("|  %25s = %-7d |\n","MAX_SYMBOLS",MAX_SYMBOLS);
     printf("|  %25s = %-7d |\n","SYMBOLS_CHUNK_SIZE",SYMBOLS_CHUNK_SIZE);
+    printf("|  %25s = %-7d |\n","TRANSCRIPT_FORMAT",TRANSCRIPT_FORMAT);
     printf("|  %25s = %-7ld |\n","MAX_TRANSCRIPT_SIZE",
            (long int) MAX_TRANSCRIPT_SIZE);
     if (glulx_mode)
@@ -555,6 +557,7 @@ extern void set_memory_sizes(int size_flag)
     MAX_STACK_SIZE = 4096;
     OMIT_UNUSED_ROUTINES = 0;
     WARN_UNUSED_ROUTINES = 0;
+    TRANSCRIPT_FORMAT = 0;
 
     adjust_memory_sizes();
 }
@@ -878,6 +881,13 @@ static void explain_parameter(char *command)
   memory after the game file. (Glulx only)\n");
         return;
     }
+    if (strcmp(command,"TRANSCRIPT_FORMAT")==0)
+    {
+        printf(
+"  TRANSCRIPT_FORMAT, if set to 1, adjusts the gametext.txt transcript for \n\
+  easier machine processing; each line will be prefixed by its context.\n");
+        return;
+    }
     if (strcmp(command,"WARN_UNUSED_ROUTINES")==0)
     {
         printf(
@@ -960,6 +970,48 @@ static int parse_memory_setting(char *str, char *label, int32 *result)
     return 1;
 }
 
+static void add_predefined_symbol(char *command)
+{
+    int ix;
+    
+    int value = 0;
+    char *valpos = NULL;
+    
+    for (ix=0; command[ix]; ix++) {
+        if (command[ix] == '=') {
+            valpos = command+(ix+1);
+            command[ix] = '\0';
+            break;
+        }
+    }
+    
+    for (ix=0; command[ix]; ix++) {
+        if ((ix == 0 && isdigit(command[ix]))
+            || !(isalnum(command[ix]) || command[ix] == '_')) {
+            printf("Attempt to define invalid symbol: %s\n", command);
+            return;
+        }
+    }
+
+    if (valpos) {
+        if (!parse_memory_setting(valpos, command, &value)) {
+            return;
+        };
+    }
+
+    add_config_symbol_definition(command, value);
+}
+
+/* Handle a dollar-sign command option: $LIST, $FOO=VAL, and so on.
+   The option may come from the command line, an ICL file, or a header
+   comment.
+
+   (Unix-style command-line options are converted to dollar-sign format
+   before being sent here.)
+
+   The name of this function is outdated. Many of these settings are not
+   really about memory allocation.
+*/
 extern void memory_command(char *command)
 {   int i, k, flag=0; int32 j;
 
@@ -967,6 +1019,7 @@ extern void memory_command(char *command)
         if (islower(command[k])) command[k]=toupper(command[k]);
 
     if (command[0]=='?') { explain_parameter(command+1); return; }
+    if (command[0]=='#') { add_predefined_symbol(command+1); return; }
 
     if (strcmp(command, "HUGE")==0) { set_memory_sizes(HUGE_SIZE); return; }
     if (strcmp(command, "LARGE")==0) { set_memory_sizes(LARGE_SIZE); return; }
@@ -1114,6 +1167,12 @@ extern void memory_command(char *command)
                 /* Adjust up to a 256-byte boundary. */
                 MEMORY_MAP_EXTENSION = (MEMORY_MAP_EXTENSION + 0xFF) & (~0xFF);
             }
+            if (strcmp(command,"TRANSCRIPT_FORMAT")==0)
+            {
+                TRANSCRIPT_FORMAT=j, flag=1;
+                if (TRANSCRIPT_FORMAT > 1 || TRANSCRIPT_FORMAT < 0)
+                    TRANSCRIPT_FORMAT = 1;
+            }
             if (strcmp(command,"WARN_UNUSED_ROUTINES")==0)
             {
                 WARN_UNUSED_ROUTINES=j, flag=1;
index 242ec3cdc16fac241f4a5edf07fc8f76c0e808e8..b957073d941f73c109ecf8b760bdb9d0d8dd0c54 100644 (file)
@@ -809,7 +809,7 @@ static int write_property_block_z(char *shortname)
     {   uchar *tmp;
         if (mark+1+510 >= MAX_PROP_TABLE_SIZE)
             memoryerror("MAX_PROP_TABLE_SIZE",MAX_PROP_TABLE_SIZE);
-        tmp = translate_text(p+mark+1,p+mark+1+510,shortname);
+        tmp = translate_text(p+mark+1,p+mark+1+510,shortname,STRCTX_OBJNAME);
         if (!tmp) error ("Short name of object exceeded 765 Z-characters");
         i = subtract_pointers(tmp,(p+mark+1));
         p[mark] = i/2;
@@ -1002,7 +1002,7 @@ static void manufacture_object_g(void)
     }
 
     objectsg[no_objects].shortname = compile_string(shortname_buffer,
-      FALSE, FALSE);
+      STRCTX_OBJNAME);
 
         /*  The properties table consists simply of a sequence of property
             blocks, one for each object in order of definition, exactly as
@@ -1756,7 +1756,6 @@ extern void make_class(char * metaclass_name)
 {   int n, duplicates_to_make = 0, class_number = no_objects+1,
         metaclass_flag = (metaclass_name != NULL);
     char duplicate_name[128];
-    int class_symbol;
     debug_location_beginning beginning_debug_location =
         get_token_location_beginning();
 
@@ -1847,8 +1846,6 @@ inconvenience, please contact the maintainers.");
       full_object_g.propdata[0].marker = OBJECT_MV;
     }
 
-    class_symbol = token_value;
-
     if (!metaclass_flag)
     {   get_next_token();
         if ((token_type == SEP_TT) && (token_value == OPENB_SEP))
index 3f0e8740a09a85b90266f8d603a2e1a74fc816e4..b569fb26cd933e66974fd551aaa5b7e4460b8766 100644 (file)
@@ -308,7 +308,7 @@ static void parse_print_z(int finally_return)
               if (strlen(token_text) > 32)
               {   INITAOT(&AO, LONG_CONSTANT_OT);
                   AO.marker = STRING_MV;
-                  AO.value  = compile_string(token_text, FALSE, FALSE);
+                  AO.value  = compile_string(token_text, STRCTX_GAME);
                   assemblez_1(print_paddr_zc, AO);
                   if (finally_return)
                   {   get_next_token();
@@ -537,7 +537,7 @@ static void parse_print_g(int finally_return)
                  so this always goes into the string area. */
               {   INITAOT(&AO, CONSTANT_OT);
                   AO.marker = STRING_MV;
-                  AO.value  = compile_string(token_text, FALSE, FALSE);
+                  AO.value  = compile_string(token_text, STRCTX_GAME);
                   assembleg_1(streamstr_gc, AO);
                   if (finally_return)
                   {   get_next_token();
@@ -974,6 +974,10 @@ static void parse_statement_z(int break_label, int continue_label)
                  get_next_token();
 
                  /*  Initialisation code  */
+                 AO.type = OMITTED_OT;
+                 spare_debug_location1 = statement_debug_location;
+                 AO2.type = OMITTED_OT; flag = 0;
+                 spare_debug_location2 = statement_debug_location;
 
                  if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
                  {   put_token_back();
@@ -996,7 +1000,6 @@ static void parse_statement_z(int break_label, int continue_label)
                              assemble_label_no(ln2);
                              return;
                          }
-                         AO.type = OMITTED_OT;
                          goto ParseUpdate;
                      }
                      put_token_back();
@@ -1004,7 +1007,6 @@ static void parse_statement_z(int break_label, int continue_label)
                  }
 
                  get_next_token();
-                 AO.type = OMITTED_OT;
                  if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
                  {   put_token_back();
                      spare_debug_location1 = get_token_location();
@@ -1014,7 +1016,6 @@ static void parse_statement_z(int break_label, int continue_label)
                  get_next_token();
 
                  ParseUpdate:
-                 AO2.type = OMITTED_OT; flag = 0;
                  if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP)))
                  {   put_token_back();
                      spare_debug_location2 = get_token_location();
@@ -1609,7 +1610,9 @@ static void parse_statement_z(int break_label, int continue_label)
                  get_next_token();
                  if (token_type == DQ_TT)
                  {   INITAOT(&AO4, LONG_CONSTANT_OT);
-                     AO4.value = compile_string(token_text, TRUE, TRUE);
+                     /* This string must be in low memory so that the
+                        dynamic string table can refer to it. */
+                     AO4.value = compile_string(token_text, STRCTX_LOWSTRING);
                  }
                  else
                  {   put_token_back();
@@ -1932,6 +1935,10 @@ static void parse_statement_g(int break_label, int continue_label)
                  get_next_token();
 
                  /*  Initialisation code  */
+                 AO.type = OMITTED_OT;
+                 spare_debug_location1 = statement_debug_location;
+                 AO2.type = OMITTED_OT; flag = 0;
+                 spare_debug_location2 = statement_debug_location;
 
                  if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
                  {   put_token_back();
@@ -1954,7 +1961,6 @@ static void parse_statement_g(int break_label, int continue_label)
                              assemble_label_no(ln2);
                              return;
                          }
-                         AO.type = OMITTED_OT;
                          goto ParseUpdate;
                      }
                      put_token_back();
@@ -1962,7 +1968,6 @@ static void parse_statement_g(int break_label, int continue_label)
                  }
 
                  get_next_token();
-                 AO.type = OMITTED_OT;
                  if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
                  {   put_token_back();
                      spare_debug_location1 = get_token_location();
@@ -1972,7 +1977,6 @@ static void parse_statement_g(int break_label, int continue_label)
                  get_next_token();
 
                  ParseUpdate:
-                 AO2.type = OMITTED_OT; flag = 0;
                  if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP)))
                  {   put_token_back();
                      spare_debug_location2 = get_token_location();
@@ -2546,7 +2550,10 @@ static void parse_statement_g(int break_label, int continue_label)
                  get_next_token();
                  if (token_type == DQ_TT)
                  {   INITAOT(&AO4, CONSTANT_OT);
-                     AO4.value = compile_string(token_text, TRUE, TRUE);
+                     /* This is not actually placed in low memory; Glulx
+                        has no such concept. We use the LOWSTRING flag
+                        for compatibility with older compiler behavior. */
+                     AO4.value = compile_string(token_text, STRCTX_LOWSTRING);
                      AO4.marker = STRING_MV;
                  }
                  else
index 90ec3bfe427cdc85fa9e2586bbbc68d8ad144fbd..6d736e940832cf1893b288d8417811a57e61fd24 100644 (file)
@@ -89,6 +89,8 @@ static char** symbol_name_space_chunks; /* For chunks of memory used to hold
                                            the name strings of symbols       */
 static int no_symbol_name_space_chunks;
 
+/* Symbol replacements (used by the "Replace X Y" directive). */
+
 typedef struct value_pair_struct {
     int original_symbol;
     int renamed_symbol;
@@ -97,6 +99,18 @@ static value_pair_t *symbol_replacements;
 static int symbol_replacements_count;
 static int symbol_replacements_size; /* calloced size */
 
+/* Symbol definitions requested at compile time. (There may not be any.)
+   These are set up at command-line parse time, not in init_symbols_vars().
+   Similarly, they are not cleaned up by symbols_free_arrays(). */
+
+typedef struct keyvalue_pair_struct {
+    char *symbol;
+    int32 value;
+} keyvalue_pair_t;
+static keyvalue_pair_t *symbol_definitions = NULL;
+static int symbol_definitions_count = 0;
+static int symbol_definitions_size = 0; /* calloced size */
+
 /* ------------------------------------------------------------------------- */
 /*   The symbols table is "hash-coded" into a disjoint union of linked       */
 /*   lists, so that for any symbol i, next_entry[i] is either -1 (meaning    */
@@ -170,6 +184,28 @@ extern int strcmpcis(char *p, char *q)
     return -qc;
 }
 
+/* ------------------------------------------------------------------------- */
+
+extern void add_config_symbol_definition(char *symbol, int32 value)
+{
+    if (symbol_definitions_count == symbol_definitions_size) {
+        int oldsize = symbol_definitions_size;
+        if (symbol_definitions_size == 0) 
+            symbol_definitions_size = 4;
+        else
+            symbol_definitions_size *= 2;
+        my_recalloc(&symbol_definitions, sizeof(keyvalue_pair_t), oldsize,
+            symbol_definitions_size, "symbol definition table");
+    }
+
+    char *str = my_malloc(strlen(symbol)+1, "symbol name");
+    strcpy(str, symbol);
+    
+    symbol_definitions[symbol_definitions_count].symbol = str;
+    symbol_definitions[symbol_definitions_count].value = value;
+    symbol_definitions_count++;
+}
+
 /* ------------------------------------------------------------------------- */
 /*   Symbol finding, creating, and removing.                                 */
 /* ------------------------------------------------------------------------- */
@@ -391,7 +427,7 @@ extern void write_the_identifier_names(void)
 
     veneer_mode = TRUE;
 
-    null_value = compile_string(unknown_attribute, FALSE, FALSE);
+    null_value = compile_string(unknown_attribute, STRCTX_SYMBOL);
     for (i=0; i<NUM_ATTR_BYTES*8; i++) attribute_name_strings[i] = null_value;
 
     for (i=0; i<no_symbols; i++)
@@ -411,14 +447,14 @@ extern void write_the_identifier_names(void)
                     }
 
                     individual_name_strings[svals[i]]
-                        = compile_string(idname_string, FALSE, FALSE);
+                        = compile_string(idname_string, STRCTX_SYMBOL);
                 }
             }
             else
             {   sprintf(idname_string, "%s", (char *) symbs[i]);
 
                 individual_name_strings[svals[i]]
-                    = compile_string(idname_string, FALSE, FALSE);
+                    = compile_string(idname_string, STRCTX_SYMBOL);
             }
         }
         if (t == ATTRIBUTE_T)
@@ -436,14 +472,14 @@ extern void write_the_identifier_names(void)
                     }
 
                     attribute_name_strings[svals[i]]
-                        = compile_string(idname_string, FALSE, FALSE);
+                        = compile_string(idname_string, STRCTX_SYMBOL);
                 }
             }
             else
             {   sprintf(idname_string, "%s", (char *) symbs[i]);
 
                 attribute_name_strings[svals[i]]
-                    = compile_string(idname_string, FALSE, FALSE);
+                    = compile_string(idname_string, STRCTX_SYMBOL);
             }
         }
         if (sflags[i] & ACTION_SFLAG)
@@ -459,7 +495,7 @@ extern void write_the_identifier_names(void)
             }
 
             action_name_strings[svals[i]]
-                = compile_string(idname_string, FALSE, FALSE);
+                = compile_string(idname_string, STRCTX_SYMBOL);
         }
     }
 
@@ -470,7 +506,7 @@ extern void write_the_identifier_names(void)
 
             action_name_strings[svals[i]
                     - ((grammar_version_number==1)?256:4096) + no_actions]
-                = compile_string(idname_string, FALSE, FALSE);
+                = compile_string(idname_string, STRCTX_SYMBOL);
         }
     }
 
@@ -479,21 +515,21 @@ extern void write_the_identifier_names(void)
         sprintf(idname_string, "%s", (char *) symbs[i]);
 
         array_name_strings[j]
-            = compile_string(idname_string, FALSE, FALSE);
+            = compile_string(idname_string, STRCTX_SYMBOL);
     }
   if (define_INFIX_switch)
   { for (i=0; i<no_symbols; i++)
     {   if (stypes[i] == GLOBAL_VARIABLE_T)
         {   sprintf(idname_string, "%s", (char *) symbs[i]);
             array_name_strings[no_arrays + svals[i] -16]
-                = compile_string(idname_string, FALSE, FALSE);
+                = compile_string(idname_string, STRCTX_SYMBOL);
         }
     }
 
     for (i=0; i<no_named_routines; i++)
     {   sprintf(idname_string, "%s", (char *) symbs[named_routine_symbols[i]]);
             array_name_strings[no_arrays + no_globals + i]
-                = compile_string(idname_string, FALSE, FALSE);
+                = compile_string(idname_string, STRCTX_SYMBOL);
     }
 
     for (i=0, no_named_constants=0; i<no_symbols; i++)
@@ -503,7 +539,7 @@ extern void write_the_identifier_names(void)
         {   sprintf(idname_string, "%s", (char *) symbs[i]);
             array_name_strings[no_arrays + no_globals + no_named_routines
                 + no_named_constants++]
-                = compile_string(idname_string, FALSE, FALSE);
+                = compile_string(idname_string, STRCTX_SYMBOL);
         }
     }
   }
@@ -597,13 +633,28 @@ static void emit_debug_information_for_predefined_symbol
 
 static void create_symbol(char *p, int32 value, int type)
 {   int i = symbol_index(p, -1);
+    if (!(sflags[i] & (UNKNOWN_SFLAG + REDEFINABLE_SFLAG))) {
+        /* Symbol already defined! */
+        if (svals[i] == value && stypes[i] == type) {
+            /* Special case: the symbol was already defined with this same
+               value. We let it pass. */
+            return;
+        }
+        else {
+            ebf_symbol_error("new symbol", p, typename(stypes[i]), slines[i]);
+            return;
+        }
+    }
     svals[i] = value; stypes[i] = type; slines[i] = blank_brief_location;
-    sflags[i] = USED_SFLAG + SYSTEM_SFLAG;
+    /* If the symbol already existed with REDEFINABLE_SFLAG, we keep that. */
+    sflags[i] = USED_SFLAG + SYSTEM_SFLAG + (sflags[i] & REDEFINABLE_SFLAG);
     emit_debug_information_for_predefined_symbol(p, i, value, type);
 }
 
 static void create_rsymbol(char *p, int value, int type)
 {   int i = symbol_index(p, -1);
+    /* This is only called for a few symbols with known names.
+       They will not collide. */
     svals[i] = value; stypes[i] = type; slines[i] = blank_brief_location;
     sflags[i] = USED_SFLAG + SYSTEM_SFLAG + REDEFINABLE_SFLAG;
     emit_debug_information_for_predefined_symbol(p, i, value, type);
@@ -748,6 +799,15 @@ static void stockup_symbols(void)
         create_symbol("FLOAT_NINFINITY", 0xFF800000, CONSTANT_T);
         create_symbol("FLOAT_NAN",       0x7FC00000, CONSTANT_T);
     }
+
+    if (symbol_definitions && symbol_definitions_count) {
+        int ix;
+        for (ix=0; ix<symbol_definitions_count; ix++) {
+            char *str = symbol_definitions[ix].symbol;
+            int32 val = symbol_definitions[ix].value;
+            create_symbol(str, val, CONSTANT_T);
+        }
+    }
 }
 
 /* ------------------------------------------------------------------------- */
@@ -1052,8 +1112,10 @@ extern void locate_dead_functions(void)
        mark them as used. */
 
     func = df_functions_head;
-    if (!func || func->address != DF_NOT_IN_FUNCTION)
+    if (!func || func->address != DF_NOT_IN_FUNCTION) {
         compiler_error("DF: Global namespace entry is not at the head of the chain.");
+        return;
+    }
 
     for (ent = func->refs; ent; ent=ent->refsnext) {
         uint32 addr;
index 1f7ba01dff72d9d58c4111030a31e16dfb34a68a..4158253d8e5af79a89fc1bf38db8e6d8d301a627 100644 (file)
@@ -1242,7 +1242,7 @@ static void construct_storyfile_g(void)
             "array name strings");
 
     write_the_identifier_names();
-    threespaces = compile_string("   ", FALSE, FALSE);
+    threespaces = compile_string("   ", STRCTX_GAME);
 
     compress_game_text();
 
index 064a5da340638c267067b6d86495d63334b7847e..88ceaecba825ae552ad94f1f9fc53f69131dd06a 100644 (file)
@@ -38,10 +38,7 @@ char *all_text, *all_text_top;         /* Start and next byte free in (large)
                                           text buffer holding the entire text
                                           of the game, when it is being
                                           recorded                           */
-int is_abbreviation,                   /* When TRUE, the string being trans
-                                          is itself an abbreviation string
-                                          so can't make use of abbreviations */
-    abbrevs_lookup_table_made,         /* The abbreviations lookup table is
+int abbrevs_lookup_table_made,         /* The abbreviations lookup table is
                                           constructed when the first non-
                                           abbreviation string is translated:
                                           this flag is TRUE after that       */
@@ -213,9 +210,7 @@ extern void make_abbreviation(char *text)
     strcpy((char *)abbreviations_at
             + no_abbreviations*MAX_ABBREV_LENGTH, text);
 
-    is_abbreviation = TRUE;
-    abbrev_values[no_abbreviations] = compile_string(text, TRUE, TRUE);
-    is_abbreviation = FALSE;
+    abbrev_values[no_abbreviations] = compile_string(text, STRCTX_ABBREV);
 
     /*   The quality is the number of Z-chars saved by using this            */
     /*   abbreviation: note that it takes 2 Z-chars to print it.             */
@@ -224,30 +219,32 @@ extern void make_abbreviation(char *text)
 }
 
 /* ------------------------------------------------------------------------- */
-/*   The front end routine for text translation                              */
+/*   The front end routine for text translation.                             */
+/*   strctx indicates the purpose of the string. This is mostly used for     */
+/*   informational output (gametext.txt), but we treat some string contexts  */
+/*   specially during compilation.                                           */
 /* ------------------------------------------------------------------------- */
 
-extern int32 compile_string(char *b, int in_low_memory, int is_abbrev)
+extern int32 compile_string(char *b, int strctx)
 {   int i, j; uchar *c;
 
-    is_abbreviation = is_abbrev;
-
-    /* Put into the low memory pool (at 0x100 in the Z-machine) of strings   */
-    /* which may be wanted as possible entries in the abbreviations table    */
+    /* In Z-code, abbreviations go in the low memory pool (0x100). So
+       do strings explicitly defined with the Lowstring directive.
+       (In Glulx, the in_low_memory flag is ignored.) */
+    int in_low_memory = (strctx == STRCTX_ABBREV || strctx == STRCTX_LOWSTRING);
 
     if (!glulx_mode && in_low_memory)
     {   j=subtract_pointers(low_strings_top,low_strings);
-        low_strings_top=translate_text(low_strings_top, low_strings+MAX_LOW_STRINGS, b);
+        low_strings_top=translate_text(low_strings_top, low_strings+MAX_LOW_STRINGS, b, strctx);
         if (!low_strings_top)
             memoryerror("MAX_LOW_STRINGS", MAX_LOW_STRINGS);
-        is_abbreviation = FALSE;
         return(0x21+(j/2));
     }
 
     if (glulx_mode && done_compression)
         compiler_error("Tried to add a string after compression was done.");
 
-    c = translate_text(strings_holding_area, strings_holding_area+MAX_STATIC_STRINGS, b);
+    c = translate_text(strings_holding_area, strings_holding_area+MAX_STATIC_STRINGS, b, strctx);
     if (!c)
         memoryerror("MAX_STATIC_STRINGS",MAX_STATIC_STRINGS);
 
@@ -282,8 +279,6 @@ extern int32 compile_string(char *b, int in_low_memory, int is_abbrev)
             write_byte_to_memory_block(&static_strings_area,
                 static_strings_extent, *c);
 
-    is_abbreviation = FALSE;
-
     if (!glulx_mode) {
         return(j/scale_factor);
     }
@@ -378,11 +373,20 @@ static void write_z_char_g(int i)
 /*   Note that the source text may be corrupted by this routine.             */
 /* ------------------------------------------------------------------------- */
 
-extern uchar *translate_text(uchar *p, uchar *p_limit, char *s_text)
+extern uchar *translate_text(uchar *p, uchar *p_limit, char *s_text, int strctx)
 {   int i, j, k, in_alphabet, lookup_value;
     int32 unicode; int zscii;
     unsigned char *text_in;
 
+    /* For STRCTX_ABBREV, the string being translated is itself an
+       abbreviation string, so it can't make use of abbreviations. Set
+       the is_abbreviation flag to indicate this.
+       The compiler has historically set this flag for the Lowstring
+       directive as well -- the in_low_memory and is_abbreviation flag were
+       always the same. I am preserving that convention. */
+    int is_abbreviation = (strctx == STRCTX_ABBREV || strctx == STRCTX_LOWSTRING);
+
+
     /*  Cast the input and output streams to unsigned char: text_out_pc will
         advance as bytes of Z-coded text are written, but text_in doesn't    */
 
@@ -421,9 +425,20 @@ extern uchar *translate_text(uchar *p, uchar *p_limit, char *s_text)
         all_text_top += strlen(all_text_top);
     }
 
-    if (transcript_switch && (!veneer_mode))
-        write_to_transcript_file(s_text);
-
+    if (transcript_switch) {
+        /* Omit veneer strings, unless we're using the new transcript format, which includes everything. */
+        if ((!veneer_mode) || TRANSCRIPT_FORMAT == 1) {
+            int label = strctx;
+            if (veneer_mode) {
+                if (label == STRCTX_GAME)
+                    label = STRCTX_VENEER;
+                else if (label == STRCTX_GAMEOPC)
+                    label = STRCTX_VENEEROPC;
+            }
+            write_to_transcript_file(s_text, label);
+        }
+    }
+    
   if (!glulx_mode) {
 
     /*  The empty string of Z-text is illegal, since it can't carry an end
@@ -1495,8 +1510,8 @@ extern void optimise_abbreviations(void)
 /*   For Glulx, the form is instead: (But see below about Unicode-valued     */
 /*   dictionaries and my heinie.)                                            */
 /*                                                                           */
-/*        <plain text>      <flags>   <verbnumber>     <adjectivenumber>     */
-/*        DICT_WORD_SIZE     short       short            short              */
+/*        <tag>  <plain text>    <flags>  <verbnumber>   <adjectivenumber>   */
+/*         $60    DICT_WORD_SIZE  short    short          short              */
 /*                                                                           */
 /*   These records are stored in "accession order" (i.e. in order of their   */
 /*   first being received by these routines) and only alphabetically sorted  */
@@ -1646,7 +1661,7 @@ apostrophe in", dword);
 
     for (; i<9; i++) wd[i]=5;
 
-    /* The array of Z-chars is converted to three 2-byte blocks              */
+    /* The array of Z-chars is converted to two or three 2-byte blocks       */
 
     tot = wd[2] + wd[1]*(1<<5) + wd[0]*(1<<10);
     prepared_sort[1]=tot%0x100;
@@ -1654,7 +1669,10 @@ apostrophe in", dword);
     tot = wd[5] + wd[4]*(1<<5) + wd[3]*(1<<10);
     prepared_sort[3]=tot%0x100;
     prepared_sort[2]=(tot/0x100)%0x100;
-    tot = wd[8] + wd[7]*(1<<5) + wd[6]*(1<<10);
+    if (version_number==3)
+        tot = 0;
+    else
+        tot = wd[8] + wd[7]*(1<<5) + wd[6]*(1<<10);
     prepared_sort[5]=tot%0x100;
     prepared_sort[4]=(tot/0x100)%0x100;
 
@@ -2050,17 +2068,81 @@ extern void dictionary_set_verb_number(char *dword, int to)
 /*   by the linker.                                                          */
 /* ------------------------------------------------------------------------- */
 
-static char *d_show_to;
-static int d_show_total;
+/* In the dictionary-showing code, if d_show_buf is NULL, the text is
+   printed directly. (The "Trace dictionary" directive does this.)
+   If d_show_buf is not NULL, we add words to it (reallocing if necessary)
+   until it's a page-width. 
+*/
+static char *d_show_buf = NULL;
+static int d_show_size; /* allocated size */
+static int d_show_len;  /* current length */
 
 static void show_char(char c)
-{   if (d_show_to == NULL) printf("%c", c);
-    else
-    {   int i = strlen(d_show_to);
-        d_show_to[i] = c; d_show_to[i+1] = 0;
+{
+    if (d_show_buf == NULL) {
+        printf("%c", c);
+    }
+    else {
+        if (d_show_len+2 >= d_show_size) {
+            int newsize = 2 * d_show_len + 16;
+            my_realloc(&d_show_buf, d_show_size, newsize, "dictionary display buffer");
+            d_show_size = newsize;
+        }
+        d_show_buf[d_show_len++] = c;
+        d_show_buf[d_show_len] = '\0';
     }
 }
 
+/* Display a Unicode character in user-readable form. This uses the same
+   character encoding as the source code. */
+static void show_uchar(uint32 c)
+{
+    char buf[16];
+    int ix;
+    
+    if (c < 0x80) {
+        /* ASCII always works */
+        show_char(c);
+        return;
+    }
+    if (character_set_unicode) {
+        /* UTF-8 the character */
+        if (c < 0x80) {
+            show_char(c);
+        }
+        else if (c < 0x800) {
+            show_char((0xC0 | ((c & 0x7C0) >> 6)));
+            show_char((0x80 |  (c & 0x03F)     ));
+        }
+        else if (c < 0x10000) {
+            show_char((0xE0 | ((c & 0xF000) >> 12)));
+            show_char((0x80 | ((c & 0x0FC0) >>  6)));
+            show_char((0x80 |  (c & 0x003F)      ));
+        }
+        else if (c < 0x200000) {
+            show_char((0xF0 | ((c & 0x1C0000) >> 18)));
+            show_char((0x80 | ((c & 0x03F000) >> 12)));
+            show_char((0x80 | ((c & 0x000FC0) >>  6)));
+            show_char((0x80 |  (c & 0x00003F)      ));
+        }
+        else {
+            show_char('?');
+        }
+        return;
+    }
+    if (character_set_setting == 1 && c < 0x100) {
+        /* Fits in Latin-1 */
+        show_char(c);
+        return;
+    }
+    /* Supporting other character_set_setting is harder; not currently implemented. */
+    
+    /* Use the escaped form */
+    sprintf(buf, "@{%x}", c);
+    for (ix=0; buf[ix]; ix++)
+        show_char(buf[ix]);
+}
+
 extern void word_to_ascii(uchar *p, char *results)
 {   int i, shift, cc, zchar; uchar encoded_word[9];
     encoded_word[0] = (((int) p[0])&0x7c)/4;
@@ -2106,7 +2188,7 @@ extern void word_to_ascii(uchar *p, char *results)
 static void recursively_show_z(int node)
 {   int i, cprinted, flags; uchar *p;
     char textual_form[32];
-    int res = (version_number == 3)?4:6;
+    int res = (version_number == 3)?4:6; /* byte length of encoded text */
 
     if (dtree[node].branch[0] != VACANT)
         recursively_show_z(dtree[node].branch[0]);
@@ -2120,7 +2202,7 @@ static void recursively_show_z(int node)
     for (; cprinted < 4 + ((version_number==3)?6:9); cprinted++)
         show_char(' ');
 
-    if (d_show_to == NULL)
+    if (d_show_buf == NULL)
     {   for (i=0; i<3+res; i++) printf("%02x ",p[i]);
 
         flags = (int) p[res];
@@ -2141,12 +2223,11 @@ static void recursively_show_z(int node)
         printf("\n");
     }
 
-    if (d_show_total++ == 5)
-    {   d_show_total = 0;
-        if (d_show_to != NULL)
-        {   write_to_transcript_file(d_show_to);
-            d_show_to[0] = 0;
-        }
+    /* Show five words per line in classic TRANSCRIPT_FORMAT; one per line in the new format. */
+    if (d_show_buf && (d_show_len >= 64 || TRANSCRIPT_FORMAT == 1))
+    {
+        write_to_transcript_file(d_show_buf, STRCTX_DICT);
+        d_show_len = 0;
     }
 
     if (dtree[node].branch[1] != VACANT)
@@ -2154,8 +2235,56 @@ static void recursively_show_z(int node)
 }
 
 static void recursively_show_g(int node)
-{
-  warning("### Glulx dictionary-show not yet implemented.\n");
+{   int i, cprinted;
+    uchar *p;
+
+    if (dtree[node].branch[0] != VACANT)
+        recursively_show_g(dtree[node].branch[0]);
+
+    p = (uchar *)dictionary + 4 + DICT_ENTRY_BYTE_LENGTH*node;
+
+    for (cprinted = 0; cprinted<DICT_WORD_SIZE; cprinted++)
+    {
+        uint32 ch;
+        if (DICT_CHAR_SIZE == 1)
+            ch = p[1+cprinted];
+        else
+            ch = (p[4*cprinted+4] << 24) + (p[4*cprinted+5] << 16) + (p[4*cprinted+6] << 8) + (p[4*cprinted+7]);
+        if (!ch)
+            break;
+        show_uchar(ch);
+    }
+    for (; cprinted<DICT_WORD_SIZE+4; cprinted++)
+        show_char(' ');
+
+    if (d_show_buf == NULL)
+    {   for (i=0; i<DICT_ENTRY_BYTE_LENGTH; i++) printf("%02x ",p[i]);
+        int flagpos = (DICT_CHAR_SIZE == 1) ? (DICT_WORD_SIZE+1) : (DICT_WORD_BYTES+4);
+        int flags = (p[flagpos+0] << 8) | (p[flagpos+1]);
+        int verbnum = (p[flagpos+2] << 8) | (p[flagpos+3]);
+        if (flags & 128)
+        {   printf("noun ");
+            if (flags & 4)  printf("p"); else printf(" ");
+            printf(" ");
+        }
+        else printf("       ");
+        if (flags & 8)
+        {   printf("preposition    ");
+        }
+        if ((flags & 3) == 3) printf("metaverb:%d  ", verbnum);
+        else if ((flags & 3) == 1) printf("verb:%d  ", verbnum);
+        printf("\n");
+    }
+
+    /* Show five words per line in classic TRANSCRIPT_FORMAT; one per line in the new format. */
+    if (d_show_buf && (d_show_len >= 64 || TRANSCRIPT_FORMAT == 1))
+    {
+        write_to_transcript_file(d_show_buf, STRCTX_DICT);
+        d_show_len = 0;
+    }
+
+    if (dtree[node].branch[1] != VACANT)
+        recursively_show_g(dtree[node].branch[1]);
 }
 
 static void show_alphabet(int i)
@@ -2177,33 +2306,43 @@ static void show_alphabet(int i)
 extern void show_dictionary(void)
 {   printf("Dictionary contains %d entries:\n",dict_entries);
     if (dict_entries != 0)
-    {   d_show_total = 0; d_show_to = NULL; 
+    {   d_show_len = 0; d_show_buf = NULL; 
         if (!glulx_mode)    
             recursively_show_z(root);
         else
             recursively_show_g(root);
     }
-    printf("\nZ-machine alphabet entries:\n");
-    show_alphabet(0);
-    show_alphabet(1);
-    show_alphabet(2);
+    if (!glulx_mode)
+    {
+        printf("\nZ-machine alphabet entries:\n");
+        show_alphabet(0);
+        show_alphabet(1);
+        show_alphabet(2);
+    }
 }
 
 extern void write_dictionary_to_transcript(void)
-{   char d_buffer[81];
-
-    sprintf(d_buffer, "\n[Dictionary contains %d entries:]\n", dict_entries);
+{
+    d_show_size = 80; /* initial size */
+    d_show_buf = my_malloc(d_show_size, "dictionary display buffer");
 
-    d_buffer[0] = 0; write_to_transcript_file(d_buffer);
+    write_to_transcript_file("", STRCTX_INFO);
+    sprintf(d_show_buf, "[Dictionary contains %d entries:]", dict_entries);
+    write_to_transcript_file(d_show_buf, STRCTX_INFO);
+    
+    d_show_len = 0;
 
     if (dict_entries != 0)
-    {   d_show_total = 0; d_show_to = d_buffer; 
+    {
         if (!glulx_mode)    
             recursively_show_z(root);
         else
             recursively_show_g(root);
     }
-    if (d_show_total != 0) write_to_transcript_file(d_buffer);
+    if (d_show_len != 0) write_to_transcript_file(d_show_buf, STRCTX_DICT);
+
+    my_free(&d_show_buf, "dictionary display buffer");
+    d_show_len = 0; d_show_buf = NULL;
 }
 
 /* ========================================================================= */
@@ -2218,7 +2357,6 @@ extern void init_text_vars(void)
     grandtable = NULL;
     grandflags = NULL;
     no_chars_transcribed = 0;
-    is_abbreviation = FALSE;
 
     for (j=0; j<256; j++) abbrevs_lookup[j] = -1;
 
@@ -2273,6 +2411,10 @@ extern void text_allocate_arrays(void)
          = my_malloc(MAX_STATIC_STRINGS,"static strings holding area");
     low_strings = my_malloc(MAX_LOW_STRINGS,"low (abbreviation) strings");
 
+    d_show_buf = NULL;
+    d_show_size = 0;
+    d_show_len = 0;
+
     huff_entities = NULL;
     hufflist = NULL;
     unicode_usage_entries = NULL;
index 2caa67cb4d4e2998b042299c0a50d3c100ffdcda..962b32f847a3e9a46962745549da8488547e0ece 100644 (file)
@@ -61,6 +61,8 @@ int no_adjectives;                     /* Number of adjectives made so far   */
 /*           for example the English verbs "take" and "drop" both normally   */
 /*           correspond in a game's dictionary to the same Inform verb.  An  */
 /*           Inform verb is essentially a list of grammar lines.             */
+/*           (Calling them "English verbs" is of course out of date. Read    */
+/*           this as jargon for "dict words which are verbs".                */
 /* ------------------------------------------------------------------------- */
 /*   Arrays defined below:                                                   */
 /*                                                                           */
@@ -91,6 +93,9 @@ static char *English_verb_list,        /* First byte of first record         */
 static int English_verb_list_size;     /* Size of the list in bytes
                                           (redundant but convenient)         */
 
+/* Maximum synonyms in a single Verb/Extend directive */
+#define MAX_VERB_SYNONYMS (32)
+
 /* ------------------------------------------------------------------------- */
 /*   Arrays used by this file                                                */
 /* ------------------------------------------------------------------------- */
@@ -726,7 +731,8 @@ extern void make_verb(void)
 
     int Inform_verb, meta_verb_flag=FALSE, verb_equals_form=FALSE;
 
-    char *English_verbs_given[32]; int no_given = 0, i;
+    char *English_verbs_given[MAX_VERB_SYNONYMS];
+    int no_given = 0, i;
 
     directive_keywords.enabled = TRUE;
 
@@ -738,7 +744,12 @@ extern void make_verb(void)
     }
 
     while ((token_type == DQ_TT) || (token_type == SQ_TT))
-    {   English_verbs_given[no_given++] = token_text;
+    {
+        if (no_given >= MAX_VERB_SYNONYMS) {
+            error("Too many synonyms in a Verb directive.");
+            panic_mode_error_recovery(); return;
+        }
+        English_verbs_given[no_given++] = token_text;
         get_next_token();
     }