diff --git a/docs/final-module/2-cal.html b/docs/final-module/2-cal.html index 7d248ac3b..8904b1c9c 100644 --- a/docs/final-module/2-cal.html +++ b/docs/final-module/2-cal.html @@ -233,16 +233,29 @@ is 20. We instead compile this as } else { CodeGen::Targets::begin_array(gen, CodeGen::CL::name(con_name), format); if (hang_one) CodeGen::Targets::array_entry(gen, I"1", format); - for (int i=DATA_CONST_IFLD; i<P->W.extent; i=i+2) { - if (P->W.data[i] != DIVIDER_IVAL) { - TEMPORARY_TEXT(entry) - CodeGen::select_temporary(gen, entry); - if ((do_not_bracket == FALSE) && (P->W.data[i] != DIVIDER_IVAL)) WRITE("("); - CodeGen::CL::literal(gen, con_name, Inter::Packages::scope_of(P), P->W.data[i], P->W.data[i+1], unsub); - if ((do_not_bracket == FALSE) && (P->W.data[i] != DIVIDER_IVAL)) WRITE(")"); - CodeGen::deselect_temporary(gen); - CodeGen::Targets::array_entry(gen, entry, format); - DISCARD_TEXT(entry) + int entry_count = 0; + for (int i=DATA_CONST_IFLD; i<P->W.extent; i=i+2) + if (P->W.data[i] != DIVIDER_IVAL) + entry_count++; + if (hang_one) entry_count++; + inter_ti e = 0; int ips = FALSE; + if ((entry_count == 1) && (Inter::Symbols::read_annotation(con_name, ASSIMILATED_IANN) >= 0)) { + inter_ti val1 = P->W.data[DATA_CONST_IFLD], val2 = P->W.data[DATA_CONST_IFLD+1]; + e = CodeGen::CL::evaluate(gen, Inter::Packages::scope_of(P), val1, val2, &ips); + } + if (e > 1) { + LOG("Entry count 1 on %S masks %d blanks\n", CodeGen::CL::name(con_name), e); + CodeGen::Targets::array_entries(gen, (int) e, ips, format); + } else { + for (int i=DATA_CONST_IFLD; i<P->W.extent; i=i+2) { + if (P->W.data[i] != DIVIDER_IVAL) { + TEMPORARY_TEXT(entry) + CodeGen::select_temporary(gen, entry); + CodeGen::CL::literal(gen, con_name, Inter::Packages::scope_of(P), P->W.data[i], P->W.data[i+1], unsub); + CodeGen::deselect_temporary(gen); + CodeGen::Targets::array_entry(gen, entry, format); + DISCARD_TEXT(entry) + } } } CodeGen::Targets::end_array(gen, format); @@ -396,6 +409,47 @@ is 20. We instead compile this as printing_mode = FALSE; } +inter_ti CodeGen::CL::evaluate(code_generation *gen, inter_symbols_table *T, inter_ti val1, inter_ti val2, int *ips) { + if (val1 == LITERAL_IVAL) return val2; + if (Inter::Symbols::is_stored_in_data(val1, val2)) { + inter_symbol *aliased = InterSymbolsTables::symbol_from_data_pair_and_table(val1, val2, T); + if (aliased == NULL) internal_error("bad aliased symbol"); + inter_tree_node *D = aliased->definition; + if (D == NULL) internal_error("undefined symbol"); + switch (D->W.data[FORMAT_CONST_IFLD]) { + case CONSTANT_DIRECT: { + inter_ti dval1 = D->W.data[DATA_CONST_IFLD]; + inter_ti dval2 = D->W.data[DATA_CONST_IFLD + 1]; + inter_ti e = CodeGen::CL::evaluate(gen, Inter::Packages::scope_of(D), dval1, dval2, ips); + if (e == 0) { + text_stream *S = CodeGen::CL::name(aliased); + if (Str::eq(S, I"INDIV_PROP_START")) *ips = TRUE; + } + LOG("Eval const $3 = %d\n", aliased, e); + return e; + } + case CONSTANT_SUM_LIST: + case CONSTANT_PRODUCT_LIST: + case CONSTANT_DIFFERENCE_LIST: + case CONSTANT_QUOTIENT_LIST: { + inter_ti result = 0; + for (int i=DATA_CONST_IFLD; i<D->W.extent; i=i+2) { + inter_ti extra = CodeGen::CL::evaluate(gen, Inter::Packages::scope_of(D), D->W.data[i], D->W.data[i+1], ips); + if (i == DATA_CONST_IFLD) result = extra; + else { + if (D->W.data[FORMAT_CONST_IFLD] == CONSTANT_SUM_LIST) result = result + extra; + if (D->W.data[FORMAT_CONST_IFLD] == CONSTANT_PRODUCT_LIST) result = result * extra; + if (D->W.data[FORMAT_CONST_IFLD] == CONSTANT_DIFFERENCE_LIST) result = result - extra; + if (D->W.data[FORMAT_CONST_IFLD] == CONSTANT_QUOTIENT_LIST) result = result / extra; + } + } + return result; + } + } + } + return 0; +} + void CodeGen::CL::literal(code_generation *gen, inter_symbol *con_name, inter_symbols_table *T, inter_ti val1, inter_ti val2, int unsub) { inter_tree *I = gen->from; text_stream *OUT = CodeGen::current(gen); @@ -461,11 +515,11 @@ is 20. We instead compile this as return symb->symbol_name; } - +

§3.

-int CodeGen::CL::node_is_ref_to(inter_tree *I, inter_tree_node *P, inter_ti seek_bip) {
+int CodeGen::CL::node_is_ref_to(inter_tree *I, inter_tree_node *P, inter_ti seek_bip) {
     int reffed = FALSE;
     while (P->W.data[ID_IFLD] == REFERENCE_IST) {
         P = InterTree::first_child(P);
diff --git a/docs/final-module/2-cg.html b/docs/final-module/2-cg.html
index 105296cbd..32b7b2f9d 100644
--- a/docs/final-module/2-cg.html
+++ b/docs/final-module/2-cg.html
@@ -201,7 +201,7 @@ always be done in a way which is then undone, restoring the previous state:
 

-generated_segment *CodeGen::select(code_generation *gen, int i) {
+generated_segment *CodeGen::select(code_generation *gen, int i) {
     generated_segment *saved = gen->current_segment;
     if ((i < 0) || (i >= MAX_CG_SEGMENTS)) internal_error("out of range");
     if (gen->temporarily_diverted) internal_error("poorly timed selection");
@@ -209,7 +209,7 @@ always be done in a way which is then undone, restoring the previous state:
     return saved;
 }
 
-void CodeGen::deselect(code_generation *gen, generated_segment *saved) {
+void CodeGen::deselect(code_generation *gen, generated_segment *saved) {
     if (gen->temporarily_diverted) internal_error("poorly timed deselection");
     gen->current_segment = saved;
 }
@@ -238,7 +238,7 @@ we also have to direct it to a given text.
 

-text_stream *CodeGen::current(code_generation *gen) {
+text_stream *CodeGen::current(code_generation *gen) {
     if (gen->temporarily_diverted)
         return gen->segments[temporary_I7CGS]->generated_code;
     if (gen->current_segment == NULL) return NULL;
diff --git a/docs/final-module/2-ft.html b/docs/final-module/2-ft.html
index 3c2cdbe8c..410cb15b5 100644
--- a/docs/final-module/2-ft.html
+++ b/docs/final-module/2-ft.html
@@ -401,6 +401,7 @@ function togglePopup(material_id) {
 
 
enum BEGIN_ARRAY_MTID
 enum ARRAY_ENTRY_MTID
+enum ARRAY_ENTRIES_MTID
 enum END_ARRAY_MTID
 define WORD_ARRAY_FORMAT 1
 define BYTE_ARRAY_FORMAT 2
@@ -410,6 +411,7 @@ function togglePopup(material_id) {
 
 VOID_METHOD_TYPE(BEGIN_ARRAY_MTID, code_generation_target *cgt, code_generation *gen, text_stream *const_name, int format)
 VOID_METHOD_TYPE(ARRAY_ENTRY_MTID, code_generation_target *cgt, code_generation *gen, text_stream *entry, int format)
+VOID_METHOD_TYPE(ARRAY_ENTRIES_MTID, code_generation_target *cgt, code_generation *gen, int how_many, int plus_ips, int format)
 VOID_METHOD_TYPE(END_ARRAY_MTID, code_generation_target *cgt, code_generation *gen, int format)
 void CodeGen::Targets::begin_array(code_generation *gen, text_stream *const_name, int format) {
     VOID_METHOD_CALL(gen->target, BEGIN_ARRAY_MTID, gen, const_name, format);
@@ -417,13 +419,16 @@ function togglePopup(material_id) {
 void CodeGen::Targets::array_entry(code_generation *gen, text_stream *entry, int format) {
     VOID_METHOD_CALL(gen->target, ARRAY_ENTRY_MTID, gen, entry, format);
 }
-void CodeGen::Targets::mangled_array_entry(code_generation *gen, text_stream *entry, int format) {
+void CodeGen::Targets::array_entries(code_generation *gen, int how_many, int plus_ips, int format) {
+    VOID_METHOD_CALL(gen->target, ARRAY_ENTRIES_MTID, gen, how_many, plus_ips, format);
+}
+void CodeGen::Targets::mangled_array_entry(code_generation *gen, text_stream *entry, int format) {
     TEMPORARY_TEXT(mangled)
     CodeGen::Targets::mangle(gen, mangled, entry);
     VOID_METHOD_CALL(gen->target, ARRAY_ENTRY_MTID, gen, mangled, format);
     DISCARD_TEXT(mangled)
 }
-void CodeGen::Targets::end_array(code_generation *gen, int format) {
+void CodeGen::Targets::end_array(code_generation *gen, int format) {
     VOID_METHOD_CALL(gen->target, END_ARRAY_MTID, gen, format);
 }
 
@@ -433,7 +438,7 @@ function togglePopup(material_id) {
 VOID_METHOD_TYPE(NEW_FAKE_ACTION_MTID, code_generation_target *cgt, code_generation *gen, text_stream *name)
-void CodeGen::Targets::new_fake_action(code_generation *gen, text_stream *name) {
+void CodeGen::Targets::new_fake_action(code_generation *gen, text_stream *name) {
     VOID_METHOD_CALL(gen->target, NEW_FAKE_ACTION_MTID, gen, name);
 }
 
diff --git a/docs/final-module/4-fi6.html b/docs/final-module/4-fi6.html index ddef46cd2..8161d2255 100644 --- a/docs/final-module/4-fi6.html +++ b/docs/final-module/4-fi6.html @@ -177,10 +177,11 @@ function togglePopup(material_id) { METHOD_ADD(cgt, END_OPCODE_MTID, CodeGen::I6::end_opcode); METHOD_ADD(cgt, BEGIN_ARRAY_MTID, CodeGen::I6::begin_array); METHOD_ADD(cgt, ARRAY_ENTRY_MTID, CodeGen::I6::array_entry); - METHOD_ADD(cgt, END_ARRAY_MTID, CodeGen::I6::end_array); + METHOD_ADD(cgt, ARRAY_ENTRIES_MTID, CodeGen::I6::array_entries); + METHOD_ADD(cgt, END_ARRAY_MTID, CodeGen::I6::end_array); METHOD_ADD(cgt, OFFER_PRAGMA_MTID, CodeGen::I6::offer_pragma) METHOD_ADD(cgt, END_GENERATION_MTID, CodeGen::I6::end_generation); - METHOD_ADD(cgt, NEW_FAKE_ACTION_MTID, CodeGen::I6::new_fake_action); + METHOD_ADD(cgt, NEW_FAKE_ACTION_MTID, CodeGen::I6::new_fake_action); inform6_target = cgt; } @@ -943,13 +944,25 @@ trick called "stubbing", these being "stub definitions".) text_stream *OUT = CodeGen::current(gen); WRITE(" (%S)", entry); } +
+

§9. Alternatively, we can just specify how many entries there will be: they will +then be initialised to 0. +

-void CodeGen::I6::end_array(code_generation_target *cgt, code_generation *gen, int format) { +
+void CodeGen::I6::array_entries(code_generation_target *cgt, code_generation *gen,
+    int how_many, int plus_ips, int format) {
+    text_stream *OUT = CodeGen::current(gen);
+    if (plus_ips) WRITE(" (%d + INDIV_PROP_START)", how_many, plus_ips);
+    else WRITE(" (%d)", how_many);
+}
+
+void CodeGen::I6::end_array(code_generation_target *cgt, code_generation *gen, int format) {
     text_stream *OUT = CodeGen::current(gen);
     WRITE(";\n");
 }
 
-void CodeGen::I6::new_fake_action(code_generation_target *cgt, code_generation *gen, text_stream *name) {
+void CodeGen::I6::new_fake_action(code_generation_target *cgt, code_generation *gen, text_stream *name) {
     text_stream *OUT = CodeGen::current(gen);
     WRITE("Fake_Action %S;\n", name);
 }
diff --git a/docs/final-module/5-car.html b/docs/final-module/5-car.html
index 57b8ebffc..45101a91d 100644
--- a/docs/final-module/5-car.html
+++ b/docs/final-module/5-car.html
@@ -85,9 +85,19 @@ easy.
         case PLUS_BIP:              WRITE("("); INV_A1; WRITE(" + "); INV_A2; WRITE(")"); break;
         case MINUS_BIP:             WRITE("("); INV_A1; WRITE(" - "); INV_A2; WRITE(")"); break;
         case UNARYMINUS_BIP:        WRITE("(-("); INV_A1; WRITE("))"); break;
-        case TIMES_BIP:             WRITE("("); INV_A1; WRITE("*"); INV_A2; WRITE(")"); break;
-        case DIVIDE_BIP:            WRITE("("); INV_A1; WRITE("/"); INV_A2; WRITE(")"); break;
-        case MODULO_BIP:            WRITE("("); INV_A1; WRITE("%%"); INV_A2; WRITE(")"); break;
+        case TIMES_BIP:             WRITE("("); INV_A1; WRITE(" * "); INV_A2; WRITE(")"); break;
+        case DIVIDE_BIP:            if (CFunctionModel::inside_function(gen)) {
+                                        WRITE("glulx_div_r("); INV_A1; WRITE(", "); INV_A2; WRITE(")");
+                                    } else {
+                                        WRITE("("); INV_A1; WRITE(" / "); INV_A2; WRITE(")"); break;
+                                    }
+                                    break;
+        case MODULO_BIP:            if (CFunctionModel::inside_function(gen)) {
+                                        WRITE("glulx_mod_r("); INV_A1; WRITE(", "); INV_A2; WRITE(")");
+                                    } else {
+                                        WRITE("("); INV_A1; WRITE(" %% "); INV_A2; WRITE(")");
+                                    }
+                                    break;
         case BITWISEAND_BIP:        WRITE("(("); INV_A1; WRITE(")&("); INV_A2; WRITE("))"); break;
         case BITWISEOR_BIP:         WRITE("(("); INV_A1; WRITE(")|("); INV_A2; WRITE("))"); break;
         case BITWISENOT_BIP:        WRITE("(~("); INV_A1; WRITE("))"); break;
@@ -131,105 +141,277 @@ storing float
 

-void glulx_exp(i7val x, i7val y) {
-    printf("Unimplemented: glulx_exp.\n");
+void glulx_add(i7val x, i7val y, i7val *z) {
+    if (z) *z = x + y;
 }
 
-void glulx_fadd(i7val x, i7val y, i7val z) {
-    printf("Unimplemented: glulx_fadd.\n");
+void glulx_sub(i7val x, i7val y, i7val *z) {
+    if (z) *z = x - y;
 }
 
-void glulx_fdiv(i7val x, i7val y, i7val z) {
-    printf("Unimplemented: glulx_fdiv.\n");
+void glulx_neg(i7val x, i7val *y) {
+    if (y) *y = -x;
 }
 
-void glulx_floor(i7val x, i7val y) {
-    printf("Unimplemented: glulx_floor.\n");
+void glulx_mul(i7val x, i7val y, i7val *z) {
+    if (z) *z = x * y;
 }
 
-void glulx_fmod(i7val x, i7val y, i7val z, i7val w) {
-    printf("Unimplemented: glulx_fmod.\n");
+void glulx_div(i7val x, i7val y, i7val *z) {
+    if (y == 0) { printf("Division of %d by 0\n", x); if (z) *z = 1; return; }
+    int result, ax, ay;
+    /* Since C doesn't guarantee the results of division of negative
+       numbers, we carefully convert everything to positive values
+       first. They have to be unsigned values, too, otherwise the
+       0x80000000 case goes wonky. */
+    if (x < 0) {
+        ax = (-x);
+        if (y < 0) {
+            ay = (-y);
+            result = ax / ay;
+        } else {
+            ay = y;
+            result = -(ax / ay);
+        }
+    } else {
+        ax = x;
+        if (y < 0) {
+            ay = (-y);
+            result = -(ax / ay);
+        } else {
+            ay = y;
+            result = ax / ay;
+        }
+    }
+    if (z) *z = result;
 }
 
-void glulx_fmul(i7val x, i7val y, i7val z) {
-    printf("Unimplemented: glulx_fmul.\n");
+i7val glulx_div_r(i7val x, i7val y) {
+    i7val z;
+    glulx_div(x, y, &z);
+    return z;
 }
 
-void glulx_fsub(i7val x, i7val y, i7val z) {
-    printf("Unimplemented: glulx_fsub.\n");
+void glulx_mod(i7val x, i7val y, i7val *z) {
+    if (y == 0) { printf("Division of %d by 0\n", x); if (z) *z = 0; return; }
+    int result, ax, ay;
+    if (y < 0) {
+        ay = -y;
+    } else {
+        ay = y;
+    }
+    if (x < 0) {
+        ax = (-x);
+        result = -(ax % ay);
+    } else {
+        ax = x;
+        result = ax % ay;
+    }
+    if (z) *z = result;
 }
 
-void glulx_ftonumn(i7val x, i7val y) {
-    printf("Unimplemented: glulx_ftonumn.\n");
+i7val glulx_mod_r(i7val x, i7val y) {
+    i7val z;
+    glulx_mod(x, y, &z);
+    return z;
 }
 
-void glulx_ftonumz(i7val x, i7val y) {
-    printf("Unimplemented: glulx_ftonumz.\n");
+typedef float gfloat32;
+
+i7val encode_float(gfloat32 val) {
+    i7val res;
+    *(gfloat32 *)(&res) = val;
+    return res;
+}
+
+gfloat32 decode_float(i7val val) {
+    gfloat32 res;
+    *(i7val *)(&res) = val;
+    return res;
+}
+
+void glulx_exp(i7val x, i7val *y) {
+    *y = encode_float(expf(decode_float(x)));
+}
+
+void glulx_fadd(i7val x, i7val y, i7val *z) {
+    *z = encode_float(decode_float(x) + decode_float(y));
+}
+
+void glulx_fdiv(i7val x, i7val y, i7val *z) {
+    *z = encode_float(decode_float(x) / decode_float(y));
+}
+
+void glulx_floor(i7val x, i7val *y) {
+    *y = encode_float(floorf(decode_float(x)));
+}
+
+void glulx_fmod(i7val x, i7val y, i7val *z, i7val *w) {
+    float fx = decode_float(x);
+    float fy = decode_float(y);
+    float fquot = fmodf(fx, fy);
+    i7val quot = encode_float(fquot);
+    i7val rem = encode_float((fx-fquot) / fy);
+    if (rem == 0x0 || rem == 0x80000000) {
+        /* When the quotient is zero, the sign has been lost in the
+         shuffle. We'll set that by hand, based on the original
+         arguments. */
+        rem = (x ^ y) & 0x80000000;
+    }
+    if (z) *z = quot;
+    if (w) *w = rem;
+}
+
+void glulx_fmul(i7val x, i7val y, i7val *z) {
+    *z = encode_float(decode_float(x) * decode_float(y));
+}
+
+void glulx_fsub(i7val x, i7val y, i7val *z) {
+    *z = encode_float(decode_float(x) - decode_float(y));
+}
+
+void glulx_ftonumn(i7val x, i7val *y) {
+    float fx = decode_float(x);
+    i7val result;
+    if (!signbit(fx)) {
+        if (isnan(fx) || isinf(fx) || (fx > 2147483647.0))
+            result = 0x7FFFFFFF;
+        else
+            result = (i7val) (roundf(fx));
+    }
+    else {
+        if (isnan(fx) || isinf(fx) || (fx < -2147483647.0))
+            result = 0x80000000;
+        else
+            result = (i7val) (roundf(fx));
+    }
+    *y = result;
+}
+
+void glulx_ftonumz(i7val x, i7val *y) {
+    float fx = decode_float(x);
+    i7val result;
+    if (!signbit(fx)) {
+        if (isnan(fx) || isinf(fx) || (fx > 2147483647.0))
+            result = 0x7FFFFFFF;
+        else
+            result = (i7val) (truncf(fx));
+    }
+    else {
+        if (isnan(fx) || isinf(fx) || (fx < -2147483647.0))
+            result = 0x80000000;
+        else
+            result = (i7val) (truncf(fx));
+    }
+    *y = result;
+}
+
+void glulx_numtof(i7val x, i7val *y) {
+    *y = encode_float((float) x);
 }
 
 int glulx_jfeq(i7val x, i7val y, i7val z) {
-    printf("Unimplemented: glulx_jfeq.\n");
+    int result;
+    if ((z & 0x7F800000) == 0x7F800000 && (z & 0x007FFFFF) != 0) {
+        /* The delta is NaN, which can never match. */
+        result = 0;
+    } else if ((x == 0x7F800000 || x == 0xFF800000)
+            && (y == 0x7F800000 || y == 0xFF800000)) {
+        /* Both are infinite. Opposite infinities are never equal,
+        even if the difference is infinite, so this is easy. */
+        result = (x == y);
+    } else {
+        float fx = decode_float(y) - decode_float(x);
+        float fy = fabs(decode_float(z));
+        result = (fx <= fy && fx >= -fy);
+    }
+    if (!result) return 1;
     return 0;
 }
 
+int glulx_jfne(i7val x, i7val y, i7val z) {
+    int result;
+    if ((z & 0x7F800000) == 0x7F800000 && (z & 0x007FFFFF) != 0) {
+        /* The delta is NaN, which can never match. */
+        result = 0;
+    } else if ((x == 0x7F800000 || x == 0xFF800000)
+            && (y == 0x7F800000 || y == 0xFF800000)) {
+        /* Both are infinite. Opposite infinities are never equal,
+        even if the difference is infinite, so this is easy. */
+        result = (x == y);
+    } else {
+        float fx = decode_float(y) - decode_float(x);
+        float fy = fabs(decode_float(z));
+        result = (fx <= fy && fx >= -fy);
+    }
+    if (!result) return 1;
+}
+
 int glulx_jfge(i7val x, i7val y) {
-    printf("Unimplemented: glulx_jfge.\n");
+    if (isgreaterequal(decode_float(x), decode_float(y))) return 1;
     return 0;
 }
 
 int glulx_jflt(i7val x, i7val y) {
-    printf("Unimplemented: glulx_jflt.\n");
+    if (isless(decode_float(x), decode_float(y))) return 1;
     return 0;
 }
 
 int glulx_jisinf(i7val x) {
-    printf("Unimplemented: glulx_jisinf.\n");
+    if (isinf(decode_float(x))) return 1;
     return 0;
 }
 
 int glulx_jisnan(i7val x) {
-    printf("Unimplemented: glulx_jisnan.\n");
+    if (isnan(decode_float(x))) return 1;
     return 0;
 }
 
-void glulx_log(i7val x, i7val y) {
-    printf("Unimplemented: glulx_log.\n");
+void glulx_log(i7val x, i7val *y) {
+    *y = encode_float(logf(decode_float(x)));
 }
 
 void glulx_acos(i7val x, i7val *y) {
-    printf("Unimplemented: glulx_acos\n");
+    *y = encode_float(acosf(decode_float(x)));
 }
 
 void glulx_asin(i7val x, i7val *y) {
-    printf("Unimplemented: glulx_asin\n");
+    *y = encode_float(asinf(decode_float(x)));
 }
 
 void glulx_atan(i7val x, i7val *y) {
-    printf("Unimplemented: glulx_atan\n");
+    *y = encode_float(atanf(decode_float(x)));
 }
 
 void glulx_ceil(i7val x, i7val *y) {
-    printf("Unimplemented: glulx_ceil\n");
+    *y = encode_float(ceilf(decode_float(x)));
 }
 
 void glulx_cos(i7val x, i7val *y) {
-    printf("Unimplemented: glulx_cos\n");
+    *y = encode_float(cosf(decode_float(x)));
 }
 
 void glulx_pow(i7val x, i7val y, i7val *z) {
-    printf("Unimplemented: glulx_pow\n");
+    if (decode_float(x) == 1.0f)
+        *z = encode_float(1.0f);
+    else if ((decode_float(y) == 0.0f) || (decode_float(y) == -0.0f))
+        *z = encode_float(1.0f);
+    else if ((decode_float(x) == -1.0f) && isinf(decode_float(y)))
+        *z = encode_float(1.0f);
+    else
+        *z = encode_float(powf(decode_float(x), decode_float(y)));
 }
 
 void glulx_sin(i7val x, i7val *y) {
-    printf("Unimplemented: glulx_sin\n");
+    *y = encode_float(sinf(decode_float(x)));
 }
 
 void glulx_sqrt(i7val x, i7val *y) {
-    printf("Unimplemented: glulx_sqrt\n");
+    *y = encode_float(sqrtf(decode_float(x)));
 }
 
 void glulx_tan(i7val x, i7val *y) {
-    printf("Unimplemented: glulx_tan\n");
+    *y = encode_float(tanf(decode_float(x)));
 }
 
  • This is part of the extract file inform7_clib.h.
diff --git a/docs/final-module/5-cas.html b/docs/final-module/5-cas.html index cfa6adde0..e6b8cca3f 100644 --- a/docs/final-module/5-cas.html +++ b/docs/final-module/5-cas.html @@ -87,14 +87,17 @@ function togglePopup(material_id) { int operand_count; int operand_branches; struct inter_tree_node *operand_label; - int pointer_on_operand; + int pointer_on_operand[16]; + int pushed_result; } C_generation_assembly_data; void CAssembly::initialise_data(code_generation *gen) { C_GEN_DATA(asmdata.operand_count) = 0; C_GEN_DATA(asmdata.operand_branches) = FALSE; C_GEN_DATA(asmdata.operand_label) = NULL; - C_GEN_DATA(asmdata.pointer_on_operand) = -1; + for (int i=0; i<16; i++) + C_GEN_DATA(asmdata.pointer_on_operand[i]) = FALSE; + C_GEN_DATA(asmdata.pushed_result) = FALSE; } void CAssembly::begin(code_generation *gen) { @@ -109,14 +112,18 @@ function togglePopup(material_id) {
 i7val i7_mgl_sp = 0;
+#define I7_ASM_STACK_CAPACITY 128
+i7val i7_asm_stack[I7_ASM_STACK_CAPACITY];
+int i7_asm_stack_pointer = 0;
 
 i7val i7_pull(void) {
-    printf("Unimplemented: i7_pull.\n");
-    return (i7val) 0;
+    if (i7_asm_stack_pointer <= 0) { printf("Stack underflow\n"); return (i7val) 0; }
+    return i7_asm_stack[--i7_asm_stack_pointer];
 }
 
 void i7_push(i7val x) {
-    printf("Unimplemented: i7_push.\n");
+    if (i7_asm_stack_pointer >= I7_ASM_STACK_CAPACITY) { printf("Stack overflow\n"); return; }
+    i7_asm_stack[i7_asm_stack_pointer++] = x;
 }
 
  • This is part of the extract file inform7_clib.h.
@@ -126,6 +133,7 @@ function togglePopup(material_id) { void CAssembly::begin_opcode(code_generation_target *cgt, code_generation *gen, text_stream *opcode) { text_stream *OUT = CodeGen::current(gen); C_GEN_DATA(asmdata.operand_branches) = FALSE; + C_GEN_DATA(asmdata.pushed_result) = FALSE; C_GEN_DATA(asmdata.operand_label) = NULL; if (Str::get_at(opcode, 1) == 'j') { C_GEN_DATA(asmdata.operand_branches) = TRUE; } if (Str::eq(opcode, I"@return")) WRITE("return "); @@ -134,23 +142,44 @@ function togglePopup(material_id) { CNamespace::mangle_opcode(cgt, OUT, opcode); } WRITE("("); C_GEN_DATA(asmdata.operand_count) = 0; - C_GEN_DATA(asmdata.pointer_on_operand) = -1; - if (Str::eq(opcode, I"@acos")) C_GEN_DATA(asmdata.pointer_on_operand) = 2; - if (Str::eq(opcode, I"@aload")) C_GEN_DATA(asmdata.pointer_on_operand) = 3; - if (Str::eq(opcode, I"@aloadb")) C_GEN_DATA(asmdata.pointer_on_operand) = 3; - if (Str::eq(opcode, I"@aloads")) C_GEN_DATA(asmdata.pointer_on_operand) = 3; - if (Str::eq(opcode, I"@asin")) C_GEN_DATA(asmdata.pointer_on_operand) = 2; - if (Str::eq(opcode, I"@atan")) C_GEN_DATA(asmdata.pointer_on_operand) = 2; - if (Str::eq(opcode, I"@binarysearch")) C_GEN_DATA(asmdata.pointer_on_operand) = 8; - if (Str::eq(opcode, I"@ceil")) C_GEN_DATA(asmdata.pointer_on_operand) = 2; - if (Str::eq(opcode, I"@cos")) C_GEN_DATA(asmdata.pointer_on_operand) = 2; - if (Str::eq(opcode, I"@gestalt")) C_GEN_DATA(asmdata.pointer_on_operand) = 3; - if (Str::eq(opcode, I"@glk")) C_GEN_DATA(asmdata.pointer_on_operand) = 3; - if (Str::eq(opcode, I"@pow")) C_GEN_DATA(asmdata.pointer_on_operand) = 3; - if (Str::eq(opcode, I"@shiftl")) C_GEN_DATA(asmdata.pointer_on_operand) = 3; - if (Str::eq(opcode, I"@sin")) C_GEN_DATA(asmdata.pointer_on_operand) = 2; - if (Str::eq(opcode, I"@sqrt")) C_GEN_DATA(asmdata.pointer_on_operand) = 2; - if (Str::eq(opcode, I"@tan")) C_GEN_DATA(asmdata.pointer_on_operand) = 2; + for (int i=0; i<16; i++) + C_GEN_DATA(asmdata.pointer_on_operand[i]) = FALSE; + if (Str::eq(opcode, I"@acos")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@add")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@aload")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@aloadb")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@aloads")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@asin")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@atan")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@binarysearch")) C_GEN_DATA(asmdata.pointer_on_operand[8]) = TRUE; + if (Str::eq(opcode, I"@ceil")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@cos")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@div")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@exp")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@fadd")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@fdiv")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@floor")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@fmod")) { + C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + C_GEN_DATA(asmdata.pointer_on_operand[4]) = TRUE; + } + if (Str::eq(opcode, I"@fmul")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@fsub")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@ftonumn")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@ftonumz")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@gestalt")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@glk")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@log")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@mod")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@mul")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@neg")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@numtof")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@pow")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@shiftl")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@sin")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@sqrt")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@sub")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@tan")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; } void CAssembly::supply_operand(code_generation_target *cgt, code_generation *gen, inter_tree_node *F, int is_label) { text_stream *OUT = CodeGen::current(gen); @@ -158,17 +187,19 @@ function togglePopup(material_id) { C_GEN_DATA(asmdata.operand_label) = F; } else { if (C_GEN_DATA(asmdata.operand_count)++ > 0) WRITE(", "); - if (C_GEN_DATA(asmdata.operand_count) == C_GEN_DATA(asmdata.pointer_on_operand)) { - TEMPORARY_TEXT(write_to) - CodeGen::select_temporary(gen, write_to); - CodeGen::FC::frame(gen, F); - CodeGen::deselect_temporary(gen); - if (Str::eq(write_to, I"0")) WRITE("NULL"); + TEMPORARY_TEXT(write_to) + CodeGen::select_temporary(gen, write_to); + CodeGen::FC::frame(gen, F); + CodeGen::deselect_temporary(gen); + if (C_GEN_DATA(asmdata.pointer_on_operand[C_GEN_DATA(asmdata.operand_count)])) { + if (Str::eq(write_to, I"i7_mgl_sp")) { WRITE("&%S", write_to); C_GEN_DATA(asmdata.pushed_result) = TRUE; } + else if (Str::eq(write_to, I"0")) WRITE("NULL"); else WRITE("&%S", write_to); - DISCARD_TEXT(write_to) } else { - CodeGen::FC::frame(gen, F); + if (Str::eq(write_to, I"i7_mgl_sp")) { WRITE("i7_pull()"); } + else WRITE("%S", write_to); } + DISCARD_TEXT(write_to) } } void CAssembly::end_opcode(code_generation_target *cgt, code_generation *gen) { @@ -180,6 +211,7 @@ function togglePopup(material_id) { if (C_GEN_DATA(asmdata.operand_label) == NULL) internal_error("no branch label"); CodeGen::FC::frame(gen, C_GEN_DATA(asmdata.operand_label)); } + if (C_GEN_DATA(asmdata.pushed_result)) WRITE("; i7_push(i7_mgl_sp)"); }

§4.

@@ -201,10 +233,6 @@ function togglePopup(material_id) { printf("Unimplemented: glulx_copy.\n"); } -void glulx_div(i7val x, i7val y, i7val z) { - printf("Unimplemented: glulx_div.\n"); -} - void glulx_gestalt(i7val x, i7val y, i7val *z) { *z = 1; } @@ -238,7 +266,7 @@ function togglePopup(material_id) { } int glulx_jeq(i7val x, i7val y) { - printf("Unimplemented: glulx_jeq.\n"); + if (x == y) return 1; return 0; } @@ -248,12 +276,12 @@ function togglePopup(material_id) { } int glulx_jnz(i7val x) { - printf("Unimplemented: glulx_jnz.\n"); + if (x != 0) return 1; return 0; } int glulx_jz(i7val x) { - printf("Unimplemented: glulx_jz.\n"); + if (x == 0) return 1; return 0; } @@ -269,17 +297,6 @@ function togglePopup(material_id) { printf("Unimplemented: glulx_mfree.\n"); } -void glulx_mod(i7val x, i7val y, i7val z) { - printf("Unimplemented: glulx_mod.\n"); -} - -void glulx_neg(i7val x, i7val y) { - printf("Unimplemented: glulx_neg.\n"); -} - -void glulx_numtof(i7val x, i7val y) { - printf("Unimplemented: glulx_numtof.\n"); -} void glulx_quit(void) { printf("Unimplemented: glulx_quit.\n"); @@ -293,12 +310,14 @@ function togglePopup(material_id) { // Deliberately ignored: we are using stdout, not glk } +void i7_print_char(i7val x); void glulx_streamchar(i7val x) { - printf("%c", (int) x); + i7_print_char(x); } +void i7_print_decimal(i7val x); void glulx_streamnum(i7val x) { - printf("Unimplemented: glulx_streamnum.\n"); + i7_print_decimal(x); } void glulx_streamstr(i7val x) { @@ -306,11 +325,7 @@ function togglePopup(material_id) { } void glulx_streamunichar(i7val x) { - printf("%c", (int) x); -} - -void glulx_sub(i7val x, i7val y, i7val z) { - printf("Unimplemented: glulx_sub.\n"); + i7_print_char(x); } void glulx_ushiftr(i7val x, i7val y, i7val z) { diff --git a/docs/final-module/5-cfm.html b/docs/final-module/5-cfm.html index 66822e940..9d7c65537 100644 --- a/docs/final-module/5-cfm.html +++ b/docs/final-module/5-cfm.html @@ -92,12 +92,14 @@ function togglePopup(material_id) { struct text_stream *prototype; int argument_count; struct final_c_function *current_fcf; + int compiling_function; } C_generation_function_model_data; void CFunctionModel::initialise_data(code_generation *gen) { C_GEN_DATA(fndata.prototype) = Str::new(); C_GEN_DATA(fndata.argument_count) = 0; C_GEN_DATA(fndata.current_fcf) = NULL; + C_GEN_DATA(fndata.compiling_function) = FALSE; } void CFunctionModel::begin(code_generation *gen) { @@ -137,6 +139,43 @@ function togglePopup(material_id) { WRITE("#endif\n"); WRITE("#endif\n"); CodeGen::deselect(gen, saved); + + saved = CodeGen::select(gen, c_fundamental_types_I7CGS); + OUT = CodeGen::current(gen); + WRITE("i7val i7_gen_call(i7val fn_ref, i7val *args, int argc, int call_message);\n"); + CodeGen::deselect(gen, saved); + + saved = CodeGen::select(gen, c_stubs_at_eof_I7CGS); + OUT = CodeGen::current(gen); + WRITE("i7val i7_gen_call(i7val fn_ref, i7val *args, int argc, int call_message) {\n"); INDENT; + WRITE("switch (fn_ref) {\n"); INDENT; + final_c_function *fcf; + LOOP_OVER(fcf, final_c_function) { + WRITE("case "); + CNamespace::mangle(NULL, OUT, fcf->identifier_as_constant); + WRITE(": return fn_"); + CNamespace::mangle(NULL, OUT, fcf->identifier_as_constant); + WRITE("("); + if (fcf->uses_vararg_model) { + WRITE("2, argc, (i7varargs) { "); + for (int i=0; i<10; i++) { + if (i > 0) WRITE(", "); + WRITE("args[%d]", i); + } + WRITE(" }"); + for (int i=0; i<fcf->max_arity - 1; i++) + WRITE(", 0"); + } else { + WRITE("argc"); + for (int i=0; i<fcf->max_arity; i++) + WRITE(", args[%d]", i); + } + WRITE(");\n"); + } + OUTDENT; WRITE("}\n"); + WRITE("printf(\"function not found\\n\");\n"); + OUTDENT; WRITE("}\n"); + CodeGen::deselect(gen, saved); } typedef struct final_c_function { @@ -165,6 +204,7 @@ function togglePopup(material_id) { void CFunctionModel::make_veneer_fcf(code_generation *gen, text_stream *unmangled_name) { final_c_function *fcf = CFunctionModel::new_fcf(unmangled_name); + fcf->max_arity = 1; CFunctionModel::declare_fcf(gen, fcf); } @@ -196,6 +236,7 @@ function togglePopup(material_id) { WRITE("printf(\"called %S\\n\");\n", C_GEN_DATA(fndata.current_fcf)->identifier_as_constant); } } + C_GEN_DATA(fndata.compiling_function) = TRUE; } void CFunctionModel::place_label(code_generation_target *cgt, code_generation *gen, text_stream *label_name) { @@ -222,9 +263,15 @@ function togglePopup(material_id) { text_stream *OUT = CodeGen::current(gen); WRITE("return 1;\n"); WRITE("\n}\n"); + C_GEN_DATA(fndata.compiling_function) = FALSE; } } +int CFunctionModel::inside_function(code_generation *gen) { + if (C_GEN_DATA(fndata.compiling_function)) return TRUE; + return FALSE; +} + void CFunctionModel::begin_function_call(code_generation_target *cgt, code_generation *gen, inter_symbol *fn, int argc) { inter_tree_node *D = fn->definition; if ((D) && (D->W.data[ID_IFLD] == CONSTANT_IST) && (D->W.data[FORMAT_CONST_IFLD] == CONSTANT_DIRECT)) { @@ -323,11 +370,6 @@ function togglePopup(material_id) { i7val i7_mgl_self = 0; -i7val i7_gen_call(i7val fn_ref, i7val *args, int argc, int call_message) { - printf("Unimplemented: i7_gen_call.\n"); - return 0; -} - i7val i7_call_0(i7val fn_ref) { i7val args[10]; for (int i=0; i<10; i++) args[i] = 0; return i7_gen_call(fn_ref, args, 0, 0); diff --git a/docs/final-module/5-cgv.html b/docs/final-module/5-cgv.html index 5d0418216..f131e0302 100644 --- a/docs/final-module/5-cgv.html +++ b/docs/final-module/5-cgv.html @@ -139,7 +139,7 @@ function togglePopup(material_id) { CMemoryModel::array_entry(cgt, gen, I"0", WORD_ARRAY_FORMAT); CMemoryModel::array_entry(cgt, gen, I"0", WORD_ARRAY_FORMAT); } - CMemoryModel::end_array(cgt, gen, WORD_ARRAY_FORMAT); + CMemoryModel::end_array(cgt, gen, WORD_ARRAY_FORMAT); } } return k; diff --git a/docs/final-module/5-cim.html b/docs/final-module/5-cim.html index 4b40e3c04..05310ab2f 100644 --- a/docs/final-module/5-cim.html +++ b/docs/final-module/5-cim.html @@ -110,7 +110,7 @@ function togglePopup(material_id) { case PRINTNAME_BIP: WRITE("i7_print_name("); INV_A1; WRITE(")"); break; case PRINTOBJ_BIP: WRITE("i7_print_object("); INV_A1; WRITE(")"); break; case PRINTPROPERTY_BIP: WRITE("i7_print_property("); INV_A1; WRITE(")"); break; - case PRINTNUMBER_BIP: WRITE("printf(\"%%d\", (int) "); INV_A1; WRITE(")"); break; + case PRINTNUMBER_BIP: WRITE("i7_print_decimal("); INV_A1; WRITE(")"); break; case PRINTNLNUMBER_BIP: WRITE("i7_print_number("); INV_A1; WRITE(")"); break; case PRINTDEF_BIP: WRITE("i7_print_def_art("); INV_A1; WRITE(")"); break; case PRINTCDEF_BIP: WRITE("i7_print_cdef_art("); INV_A1; WRITE(")"); break; @@ -138,6 +138,10 @@ function togglePopup(material_id) { void i7_font(int what) { } +void i7_print_decimal(i7val x) { + printf("%d", (int) x); +} + void i7_print_char(i7val x) { printf("%c", (int) x); } diff --git a/docs/final-module/5-cmm.html b/docs/final-module/5-cmm.html index 6b2937b1c..a1d2ef951 100644 --- a/docs/final-module/5-cmm.html +++ b/docs/final-module/5-cmm.html @@ -74,7 +74,7 @@ function togglePopup(material_id) {

How arrays of all kinds are stored in C.

-
+

§1. Setting up the model.

@@ -82,7 +82,8 @@ function togglePopup(material_id) { void CMemoryModel::initialise(code_generation_target *cgt) { METHOD_ADD(cgt, BEGIN_ARRAY_MTID, CMemoryModel::begin_array); METHOD_ADD(cgt, ARRAY_ENTRY_MTID, CMemoryModel::array_entry); - METHOD_ADD(cgt, END_ARRAY_MTID, CMemoryModel::end_array); + METHOD_ADD(cgt, ARRAY_ENTRIES_MTID, CMemoryModel::array_entries); + METHOD_ADD(cgt, END_ARRAY_MTID, CMemoryModel::end_array); } typedef struct C_generation_memory_model_data { @@ -282,7 +283,7 @@ predefine when the array ends.

-void CMemoryModel::array_entry(code_generation_target *cgt, code_generation *gen,
+void CMemoryModel::array_entry(code_generation_target *cgt, code_generation *gen,
     text_stream *entry, int format) {
     generated_segment *saved = CodeGen::select(gen, c_mem_I7CGS);
     text_stream *OUT = CodeGen::current(gen);
@@ -298,7 +299,7 @@ predefine when the array ends.
 

-    WRITE("    (i7byte) %S,\n", entry);
+    WRITE("    (i7byte) %S, /* %d */\n", entry, C_GEN_DATA(memdata.himem));
     C_GEN_DATA(memdata.himem) += 1;
 
  • This code is used in §8.
@@ -312,17 +313,28 @@ and therefore if X
-    WRITE("    I7BYTE_0(%S), I7BYTE_1(%S), I7BYTE_2(%S), I7BYTE_3(%S),\n",
-        entry, entry, entry, entry);
+    WRITE("    I7BYTE_0(%S), I7BYTE_1(%S), I7BYTE_2(%S), I7BYTE_3(%S), /* %d */\n",
+        entry, entry, entry, entry, C_GEN_DATA(memdata.himem));
     C_GEN_DATA(memdata.himem) += 4;
 
  • This code is used in §8.
-

§9. When all the entries have been placed, the following is called. It does nothing +

§9. Alternatively, we can just specify how many entries there will be: they will +then be initialised to 0. +

+ +
+void CMemoryModel::array_entries(code_generation_target *cgt, code_generation *gen,
+    int how_many, int plus_ips, int format) {
+    if (plus_ips) how_many += 64;
+    for (int i=0; i<how_many; i++) CMemoryModel::array_entry(cgt, gen, I"0", format);
+}
+
+

§10. When all the entries have been placed, the following is called. It does nothing except to predeclare the extent constant, if one was used.

-void CMemoryModel::end_array(code_generation_target *cgt, code_generation *gen, int format) {
+void CMemoryModel::end_array(code_generation_target *cgt, code_generation *gen, int format) {
     if ((format == TABLE_ARRAY_FORMAT) || (format == BUFFER_ARRAY_FORMAT)) {
         generated_segment *saved = CodeGen::select(gen, c_predeclarations_I7CGS);
         text_stream *OUT = CodeGen::current(gen);
@@ -332,7 +344,7 @@ except to predeclare the extent constant, if one was used.
     }
 }
 
-

§10. Primitives for byte and word lookup. The signatures here are: +

§11. Primitives for byte and word lookup. The signatures here are:

@@ -340,44 +352,44 @@ except to predeclare the extent constant, if one was used.
 primitive !lookupbyte val val -> val
 
-int CMemoryModel::handle_store_by_ref(code_generation *gen, inter_tree_node *ref) {
+int CMemoryModel::handle_store_by_ref(code_generation *gen, inter_tree_node *ref) {
     if (CodeGen::CL::node_is_ref_to(gen->from, ref, LOOKUP_BIP)) return TRUE;
     return FALSE;
 }
 
-int CMemoryModel::compile_primitive(code_generation *gen, inter_ti bip, inter_tree_node *P) {
+int CMemoryModel::compile_primitive(code_generation *gen, inter_ti bip, inter_tree_node *P) {
     text_stream *OUT = CodeGen::current(gen);
     switch (bip) {
-        case LOOKUP_BIP:     if (CReferences::am_I_a_ref(gen)) Word value as reference10.2
-                             else Word value as value10.1;
+        case LOOKUP_BIP:     if (CReferences::am_I_a_ref(gen)) Word value as reference11.2
+                             else Word value as value11.1;
                              break;
-        case LOOKUPBYTE_BIP: Byte value as value10.3; break;
+        case LOOKUPBYTE_BIP: Byte value as value11.3; break;
         default:             return NOT_APPLICABLE;
     }
     return FALSE;
 }
 
-

§10.1. Word value as value10.1 = +

§11.1. Word value as value11.1 =

     WRITE("i7_read_word(i7mem, "); INV_A1; WRITE(", "); INV_A2; WRITE(")");
 
-
  • This code is used in §10.
-

§10.2. Word value as reference10.2 = +

  • This code is used in §11.
+

§11.2. Word value as reference11.2 =

     WRITE("i7_write_word(i7mem, "); INV_A1; WRITE(", "); INV_A2; WRITE(", ");
 
-
  • This code is used in §10.
-

§10.3. Byte value as value10.3 = +

  • This code is used in §11.
+

§11.3. Byte value as value11.3 =

     WRITE("i7mem["); INV_A1; WRITE(" + "); INV_A2; WRITE("]");
 
-
  • This code is used in §10.
+
  • This code is used in §11.
diff --git a/docs/final-module/5-com.html b/docs/final-module/5-com.html index 91d2eb7a9..0d643954b 100644 --- a/docs/final-module/5-com.html +++ b/docs/final-module/5-com.html @@ -206,14 +206,14 @@ overlap. WRITE("#define i7_max_objects %d\n", C_GEN_DATA(objdata.owner_id_count) + 1); WRITE("i7val i7_metaclass_of[] = { 0"); - for (int i=1; i<C_GEN_DATA(objdata.owner_id_count); i++) { + for (int i=1; i<=C_GEN_DATA(objdata.owner_id_count); i++) { if (C_GEN_DATA(objdata.owners)[i].is_class) WRITE(", i7_mgl_Class"); else WRITE(", i7_mgl_Object"); } WRITE(" };\n"); WRITE("i7val i7_class_of[] = { 0"); - for (int i=1; i<C_GEN_DATA(objdata.owner_id_count); i++) { + for (int i=1; i<=C_GEN_DATA(objdata.owner_id_count); i++) { WRITE(", "); CNamespace::mangle(NULL, OUT, C_GEN_DATA(objdata.owners)[i].class); } WRITE(" };\n"); @@ -345,17 +345,18 @@ only need to be unique, so the order is not significant. void CObjectModel::declare_property_by_name(code_generation *gen, text_stream *name, int used) { generated_segment *saved = CodeGen::select(gen, c_predeclarations_I7CGS); text_stream *OUT = CodeGen::current(gen); - if (used) { + if (used) { WRITE("#define "); CNamespace::mangle(NULL, OUT, name); WRITE(" %d\n", C_GEN_DATA(objdata.property_id_counter)++); - } else { + } else { WRITE("#ifndef "); CNamespace::mangle(NULL, OUT, name); WRITE("\n#define "); CNamespace::mangle(NULL, OUT, name); WRITE(" 0\n#endif\n"); } +*/ CodeGen::deselect(gen, saved); }
@@ -413,6 +414,11 @@ By fiat, that will be 0. OUTDENT; WRITE("}\n"); CodeGen::deselect(gen, saved); + + saved = CodeGen::select(gen, c_fundamental_types_I7CGS); + OUT = CodeGen::current(gen); + WRITE("i7val fn_i7_mgl_CreatePropertyOffsets(int argc);\n"); + CodeGen::deselect(gen, saved); }
@@ -542,8 +548,9 @@ property values are not stored in the memory map. i7val i7_read_prop_value(i7val owner_id, i7val prop_id) { if ((owner_id <= 0) || (owner_id >= i7_max_objects) || (prop_id < 0) || (prop_id >= i7_no_property_ids)) return 0; - while (i7_properties[(int) owner_id].value_set[(int) prop_id] == 0) + while (i7_properties[(int) owner_id].value_set[(int) prop_id] == 0) { owner_id = i7_class_of[owner_id]; + } return i7_properties[(int) owner_id].value[(int) prop_id]; } diff --git a/docs/final-module/5-cpc.html b/docs/final-module/5-cpc.html index f9c310a59..8dd2c0507 100644 --- a/docs/final-module/5-cpc.html +++ b/docs/final-module/5-cpc.html @@ -89,7 +89,7 @@ function togglePopup(material_id) { if (r != NOT_APPLICABLE) return r; r = CArithmetic::compile_primitive(gen, bip, P); if (r != NOT_APPLICABLE) return r; - r = CMemoryModel::compile_primitive(gen, bip, P); + r = CMemoryModel::compile_primitive(gen, bip, P); if (r != NOT_APPLICABLE) return r; r = CObjectModel::compile_primitive(gen, bip, P); if (r != NOT_APPLICABLE) return r; diff --git a/docs/final-module/5-crf.html b/docs/final-module/5-crf.html index be65cb121..6f52fd5b8 100644 --- a/docs/final-module/5-crf.html +++ b/docs/final-module/5-crf.html @@ -139,7 +139,7 @@ correct.

-int CReferences::am_I_a_ref(code_generation *gen) {
+int CReferences::am_I_a_ref(code_generation *gen) {
     int answer = C_GEN_DATA(memdata.next_node_is_a_ref);
     C_GEN_DATA(memdata.next_node_is_a_ref) = FALSE;
     return answer;
@@ -185,7 +185,7 @@ That's what is done by the "A1 as ref" mode set up above.
 
 
     inter_tree_node *ref = InterTree::first_child(P);
-    if ((CMemoryModel::handle_store_by_ref(gen, ref)) ||
+    if ((CMemoryModel::handle_store_by_ref(gen, ref)) ||
         (CObjectModel::handle_store_by_ref(gen, ref))) {
         Handle the ref using the incomplete-function mode4.1.1;
     } else {
diff --git a/docs/final-module/5-fnc.html b/docs/final-module/5-fnc.html
index bdbf2df14..4d3f4ba3d 100644
--- a/docs/final-module/5-fnc.html
+++ b/docs/final-module/5-fnc.html
@@ -123,6 +123,7 @@ first of those:
 
 #include <stdlib.h>
 #include <stdio.h>
+#include <math.h>
 

§3. Segmentation.

diff --git a/docs/runtime-module/5-ki.html b/docs/runtime-module/5-ki.html index 918641c77..5ad03169c 100644 --- a/docs/runtime-module/5-ki.html +++ b/docs/runtime-module/5-ki.html @@ -130,7 +130,6 @@ like variables. That's what makes them intermediate.) return kc->explicit_identifier; text_stream *invented = Str::new(); WRITE_TO(invented, "WEAK_ID_%d", kc->allocation_id); -LOG("I did make %S\n", invented); return invented; } diff --git a/inform7/Figures/memory-diagnostics.txt b/inform7/Figures/memory-diagnostics.txt index 7e7389708..419496cec 100644 --- a/inform7/Figures/memory-diagnostics.txt +++ b/inform7/Figures/memory-diagnostics.txt @@ -1,6 +1,6 @@ -Total memory consumption was 399122K = 390 MB +Total memory consumption was 398325K = 389 MB -60.3% was used for 1996022 objects, in 371151 frames in 301 x 800K = 240800K = 235 MB: +60.2% was used for 1996024 objects, in 371153 frames in 300 x 800K = 240000K = 234 MB: 10.2% inter_tree_node_array 58 x 8192 = 475136 objects, 41813824 bytes 7.0% text_stream_array 5133 x 100 = 513300 objects, 28909056 bytes @@ -96,7 +96,7 @@ Total memory consumption was 399122K = 390 MB ---- nonlocal_variable 93 objects, 20088 bytes ---- property 146 objects, 19856 bytes ---- timed_rules_rfd_data 400 objects, 19200 bytes - ---- method 390 objects, 18720 bytes + ---- method 392 objects, 18816 bytes ---- pcalc_prop_deferral 86 objects, 17888 bytes ---- instance 167 objects, 17368 bytes ---- parse_node_tree 20 objects, 17280 bytes @@ -236,9 +236,9 @@ Total memory consumption was 399122K = 390 MB ---- loop_over_scope 1 object, 40 bytes ---- I6_generation_data 1 object, 24 bytes -39.6% was used for memory not allocated for objects: +39.7% was used for memory not allocated for objects: - 21.1% text stream storage 86271368 bytes in 531005 claims + 21.1% text stream storage 86274752 bytes in 531041 claims 4.4% dictionary storage 18157056 bytes in 33232 claims ---- sorting 744 bytes in 3 claims 1.7% source text 7200000 bytes in 3 claims @@ -256,5 +256,5 @@ Total memory consumption was 399122K = 390 MB ---- code generation workspace for objects 9648 bytes in 9 claims ---- emitter array storage 161920 bytes in 2064 claims -18.7% was overhead - 76729480 bytes = 74931K = 73 MB +18.6% was overhead - 75910184 bytes = 74131K = 72 MB diff --git a/inform7/Figures/timings-diagnostics.txt b/inform7/Figures/timings-diagnostics.txt index 6734d70e4..d14fe360c 100644 --- a/inform7/Figures/timings-diagnostics.txt +++ b/inform7/Figures/timings-diagnostics.txt @@ -1,6 +1,6 @@ 100.0% in inform7 run - 55.3% in compilation to Inter - 40.1% in //Sequence::undertake_queued_tasks// + 55.4% in compilation to Inter + 40.4% in //Sequence::undertake_queued_tasks// 3.5% in //MajorNodes::pre_pass// 2.5% in //MajorNodes::pass_1// 1.5% in //RTPhrasebook::compile_entries// @@ -17,10 +17,10 @@ 0.1% in //Task::make_built_in_kind_constructors// 0.1% in //World::stages_II_and_III// 1.9% not specifically accounted for - 42.6% in running Inter pipeline - 11.0% in step preparation - 9.7% in inter step 7/14: consolidate-text - 8.1% in inter step 14/14: generate inform6 -> auto.inf + 42.5% in running Inter pipeline + 10.8% in step preparation + 9.6% in inter step 7/14: consolidate-text + 8.2% in inter step 14/14: generate inform6 -> auto.inf 8.0% in inter step 2/14: link 1.5% in inter step 10/14: make-identifiers-unique 0.4% in inter step 11/14: reconcile-verbs @@ -29,9 +29,8 @@ 0.2% in inter step 8/14: resolve-external-symbols 0.2% in inter step 9/14: inspect-plugs 0.1% in inter step 12/14: eliminate-redundant-labels - 0.1% in inter step 3/14: merge-template <- none 0.1% in inter step 4/14: parse-linked-matter 0.1% in inter step 5/14: resolve-conditional-compilation - 2.0% not specifically accounted for - 1.7% in supervisor + 2.2% not specifically accounted for + 1.6% in supervisor 0.3% not specifically accounted for diff --git a/inform7/Internal/Miscellany/inform7_clib.h b/inform7/Internal/Miscellany/inform7_clib.h index 60aca3104..edcbdf573 100644 --- a/inform7/Internal/Miscellany/inform7_clib.h +++ b/inform7/Internal/Miscellany/inform7_clib.h @@ -4,6 +4,7 @@ #include #include +#include #define i7_mgl_Grammar__Version 2 i7val i7_mgl_debug_flag = 0; @@ -99,14 +100,18 @@ i7val i7_write_word(i7byte data[], i7val array_address, i7val array_index, i7val return return_val; } i7val i7_mgl_sp = 0; +#define I7_ASM_STACK_CAPACITY 128 +i7val i7_asm_stack[I7_ASM_STACK_CAPACITY]; +int i7_asm_stack_pointer = 0; i7val i7_pull(void) { - printf("Unimplemented: i7_pull.\n"); - return (i7val) 0; + if (i7_asm_stack_pointer <= 0) { printf("Stack underflow\n"); return (i7val) 0; } + return i7_asm_stack[--i7_asm_stack_pointer]; } void i7_push(i7val x) { - printf("Unimplemented: i7_push.\n"); + if (i7_asm_stack_pointer >= I7_ASM_STACK_CAPACITY) { printf("Stack overflow\n"); return; } + i7_asm_stack[i7_asm_stack_pointer++] = x; } void glulx_accelfunc(i7val x, i7val y) { printf("Unimplemented: glulx_accelfunc.\n"); @@ -124,10 +129,6 @@ void glulx_copy(i7val x, i7val y) { printf("Unimplemented: glulx_copy.\n"); } -void glulx_div(i7val x, i7val y, i7val z) { - printf("Unimplemented: glulx_div.\n"); -} - void glulx_gestalt(i7val x, i7val y, i7val *z) { *z = 1; } @@ -161,7 +162,7 @@ void glulx_glk(i7val glk_api_selector, i7val i7varargc, i7val *z) { } int glulx_jeq(i7val x, i7val y) { - printf("Unimplemented: glulx_jeq.\n"); + if (x == y) return 1; return 0; } @@ -171,12 +172,12 @@ int glulx_jleu(i7val x, i7val y) { } int glulx_jnz(i7val x) { - printf("Unimplemented: glulx_jnz.\n"); + if (x != 0) return 1; return 0; } int glulx_jz(i7val x) { - printf("Unimplemented: glulx_jz.\n"); + if (x == 0) return 1; return 0; } @@ -192,17 +193,6 @@ void glulx_mfree(i7val x) { printf("Unimplemented: glulx_mfree.\n"); } -void glulx_mod(i7val x, i7val y, i7val z) { - printf("Unimplemented: glulx_mod.\n"); -} - -void glulx_neg(i7val x, i7val y) { - printf("Unimplemented: glulx_neg.\n"); -} - -void glulx_numtof(i7val x, i7val y) { - printf("Unimplemented: glulx_numtof.\n"); -} void glulx_quit(void) { printf("Unimplemented: glulx_quit.\n"); @@ -216,12 +206,14 @@ void glulx_setiosys(i7val x, i7val y) { // Deliberately ignored: we are using stdout, not glk } +void i7_print_char(i7val x); void glulx_streamchar(i7val x) { - printf("%c", (int) x); + i7_print_char(x); } +void i7_print_decimal(i7val x); void glulx_streamnum(i7val x) { - printf("Unimplemented: glulx_streamnum.\n"); + i7_print_decimal(x); } void glulx_streamstr(i7val x) { @@ -229,11 +221,7 @@ void glulx_streamstr(i7val x) { } void glulx_streamunichar(i7val x) { - printf("%c", (int) x); -} - -void glulx_sub(i7val x, i7val y, i7val z) { - printf("Unimplemented: glulx_sub.\n"); + i7_print_char(x); } void glulx_ushiftr(i7val x, i7val y, i7val z) { @@ -270,105 +258,277 @@ i7val fn_i7_mgl_random(int n, i7val v) { void glulx_setrandom(i7val x) { i7_seed = (int) x; } -void glulx_exp(i7val x, i7val y) { - printf("Unimplemented: glulx_exp.\n"); +void glulx_add(i7val x, i7val y, i7val *z) { + if (z) *z = x + y; } -void glulx_fadd(i7val x, i7val y, i7val z) { - printf("Unimplemented: glulx_fadd.\n"); +void glulx_sub(i7val x, i7val y, i7val *z) { + if (z) *z = x - y; } -void glulx_fdiv(i7val x, i7val y, i7val z) { - printf("Unimplemented: glulx_fdiv.\n"); +void glulx_neg(i7val x, i7val *y) { + if (y) *y = -x; } -void glulx_floor(i7val x, i7val y) { - printf("Unimplemented: glulx_floor.\n"); +void glulx_mul(i7val x, i7val y, i7val *z) { + if (z) *z = x * y; } -void glulx_fmod(i7val x, i7val y, i7val z, i7val w) { - printf("Unimplemented: glulx_fmod.\n"); +void glulx_div(i7val x, i7val y, i7val *z) { + if (y == 0) { printf("Division of %d by 0\n", x); if (z) *z = 1; return; } + int result, ax, ay; + /* Since C doesn't guarantee the results of division of negative + numbers, we carefully convert everything to positive values + first. They have to be unsigned values, too, otherwise the + 0x80000000 case goes wonky. */ + if (x < 0) { + ax = (-x); + if (y < 0) { + ay = (-y); + result = ax / ay; + } else { + ay = y; + result = -(ax / ay); + } + } else { + ax = x; + if (y < 0) { + ay = (-y); + result = -(ax / ay); + } else { + ay = y; + result = ax / ay; + } + } + if (z) *z = result; } -void glulx_fmul(i7val x, i7val y, i7val z) { - printf("Unimplemented: glulx_fmul.\n"); +i7val glulx_div_r(i7val x, i7val y) { + i7val z; + glulx_div(x, y, &z); + return z; } -void glulx_fsub(i7val x, i7val y, i7val z) { - printf("Unimplemented: glulx_fsub.\n"); +void glulx_mod(i7val x, i7val y, i7val *z) { + if (y == 0) { printf("Division of %d by 0\n", x); if (z) *z = 0; return; } + int result, ax, ay; + if (y < 0) { + ay = -y; + } else { + ay = y; + } + if (x < 0) { + ax = (-x); + result = -(ax % ay); + } else { + ax = x; + result = ax % ay; + } + if (z) *z = result; } -void glulx_ftonumn(i7val x, i7val y) { - printf("Unimplemented: glulx_ftonumn.\n"); +i7val glulx_mod_r(i7val x, i7val y) { + i7val z; + glulx_mod(x, y, &z); + return z; } -void glulx_ftonumz(i7val x, i7val y) { - printf("Unimplemented: glulx_ftonumz.\n"); +typedef float gfloat32; + +i7val encode_float(gfloat32 val) { + i7val res; + *(gfloat32 *)(&res) = val; + return res; +} + +gfloat32 decode_float(i7val val) { + gfloat32 res; + *(i7val *)(&res) = val; + return res; +} + +void glulx_exp(i7val x, i7val *y) { + *y = encode_float(expf(decode_float(x))); +} + +void glulx_fadd(i7val x, i7val y, i7val *z) { + *z = encode_float(decode_float(x) + decode_float(y)); +} + +void glulx_fdiv(i7val x, i7val y, i7val *z) { + *z = encode_float(decode_float(x) / decode_float(y)); +} + +void glulx_floor(i7val x, i7val *y) { + *y = encode_float(floorf(decode_float(x))); +} + +void glulx_fmod(i7val x, i7val y, i7val *z, i7val *w) { + float fx = decode_float(x); + float fy = decode_float(y); + float fquot = fmodf(fx, fy); + i7val quot = encode_float(fquot); + i7val rem = encode_float((fx-fquot) / fy); + if (rem == 0x0 || rem == 0x80000000) { + /* When the quotient is zero, the sign has been lost in the + shuffle. We'll set that by hand, based on the original + arguments. */ + rem = (x ^ y) & 0x80000000; + } + if (z) *z = quot; + if (w) *w = rem; +} + +void glulx_fmul(i7val x, i7val y, i7val *z) { + *z = encode_float(decode_float(x) * decode_float(y)); +} + +void glulx_fsub(i7val x, i7val y, i7val *z) { + *z = encode_float(decode_float(x) - decode_float(y)); +} + +void glulx_ftonumn(i7val x, i7val *y) { + float fx = decode_float(x); + i7val result; + if (!signbit(fx)) { + if (isnan(fx) || isinf(fx) || (fx > 2147483647.0)) + result = 0x7FFFFFFF; + else + result = (i7val) (roundf(fx)); + } + else { + if (isnan(fx) || isinf(fx) || (fx < -2147483647.0)) + result = 0x80000000; + else + result = (i7val) (roundf(fx)); + } + *y = result; +} + +void glulx_ftonumz(i7val x, i7val *y) { + float fx = decode_float(x); + i7val result; + if (!signbit(fx)) { + if (isnan(fx) || isinf(fx) || (fx > 2147483647.0)) + result = 0x7FFFFFFF; + else + result = (i7val) (truncf(fx)); + } + else { + if (isnan(fx) || isinf(fx) || (fx < -2147483647.0)) + result = 0x80000000; + else + result = (i7val) (truncf(fx)); + } + *y = result; +} + +void glulx_numtof(i7val x, i7val *y) { + *y = encode_float((float) x); } int glulx_jfeq(i7val x, i7val y, i7val z) { - printf("Unimplemented: glulx_jfeq.\n"); + int result; + if ((z & 0x7F800000) == 0x7F800000 && (z & 0x007FFFFF) != 0) { + /* The delta is NaN, which can never match. */ + result = 0; + } else if ((x == 0x7F800000 || x == 0xFF800000) + && (y == 0x7F800000 || y == 0xFF800000)) { + /* Both are infinite. Opposite infinities are never equal, + even if the difference is infinite, so this is easy. */ + result = (x == y); + } else { + float fx = decode_float(y) - decode_float(x); + float fy = fabs(decode_float(z)); + result = (fx <= fy && fx >= -fy); + } + if (!result) return 1; return 0; } +int glulx_jfne(i7val x, i7val y, i7val z) { + int result; + if ((z & 0x7F800000) == 0x7F800000 && (z & 0x007FFFFF) != 0) { + /* The delta is NaN, which can never match. */ + result = 0; + } else if ((x == 0x7F800000 || x == 0xFF800000) + && (y == 0x7F800000 || y == 0xFF800000)) { + /* Both are infinite. Opposite infinities are never equal, + even if the difference is infinite, so this is easy. */ + result = (x == y); + } else { + float fx = decode_float(y) - decode_float(x); + float fy = fabs(decode_float(z)); + result = (fx <= fy && fx >= -fy); + } + if (!result) return 1; +} + int glulx_jfge(i7val x, i7val y) { - printf("Unimplemented: glulx_jfge.\n"); + if (isgreaterequal(decode_float(x), decode_float(y))) return 1; return 0; } int glulx_jflt(i7val x, i7val y) { - printf("Unimplemented: glulx_jflt.\n"); + if (isless(decode_float(x), decode_float(y))) return 1; return 0; } int glulx_jisinf(i7val x) { - printf("Unimplemented: glulx_jisinf.\n"); + if (isinf(decode_float(x))) return 1; return 0; } int glulx_jisnan(i7val x) { - printf("Unimplemented: glulx_jisnan.\n"); + if (isnan(decode_float(x))) return 1; return 0; } -void glulx_log(i7val x, i7val y) { - printf("Unimplemented: glulx_log.\n"); +void glulx_log(i7val x, i7val *y) { + *y = encode_float(logf(decode_float(x))); } void glulx_acos(i7val x, i7val *y) { - printf("Unimplemented: glulx_acos\n"); + *y = encode_float(acosf(decode_float(x))); } void glulx_asin(i7val x, i7val *y) { - printf("Unimplemented: glulx_asin\n"); + *y = encode_float(asinf(decode_float(x))); } void glulx_atan(i7val x, i7val *y) { - printf("Unimplemented: glulx_atan\n"); + *y = encode_float(atanf(decode_float(x))); } void glulx_ceil(i7val x, i7val *y) { - printf("Unimplemented: glulx_ceil\n"); + *y = encode_float(ceilf(decode_float(x))); } void glulx_cos(i7val x, i7val *y) { - printf("Unimplemented: glulx_cos\n"); + *y = encode_float(cosf(decode_float(x))); } void glulx_pow(i7val x, i7val y, i7val *z) { - printf("Unimplemented: glulx_pow\n"); + if (decode_float(x) == 1.0f) + *z = encode_float(1.0f); + else if ((decode_float(y) == 0.0f) || (decode_float(y) == -0.0f)) + *z = encode_float(1.0f); + else if ((decode_float(x) == -1.0f) && isinf(decode_float(y))) + *z = encode_float(1.0f); + else + *z = encode_float(powf(decode_float(x), decode_float(y))); } void glulx_sin(i7val x, i7val *y) { - printf("Unimplemented: glulx_sin\n"); + *y = encode_float(sinf(decode_float(x))); } void glulx_sqrt(i7val x, i7val *y) { - printf("Unimplemented: glulx_sqrt\n"); + *y = encode_float(sqrtf(decode_float(x))); } void glulx_tan(i7val x, i7val *y) { - printf("Unimplemented: glulx_tan\n"); + *y = encode_float(tanf(decode_float(x))); } i7val fn_i7_mgl_metaclass(int n, i7val id) { if (id <= 0) return 0; @@ -415,8 +575,9 @@ void i7_write_prop_value(i7val owner_id, i7val prop_id, i7val val) { i7val i7_read_prop_value(i7val owner_id, i7val prop_id) { if ((owner_id <= 0) || (owner_id >= i7_max_objects) || (prop_id < 0) || (prop_id >= i7_no_property_ids)) return 0; - while (i7_properties[(int) owner_id].value_set[(int) prop_id] == 0) + while (i7_properties[(int) owner_id].value_set[(int) prop_id] == 0) { owner_id = i7_class_of[owner_id]; + } return i7_properties[(int) owner_id].value[(int) prop_id]; } @@ -477,11 +638,6 @@ typedef struct i7varargs { i7val i7_mgl_self = 0; -i7val i7_gen_call(i7val fn_ref, i7val *args, int argc, int call_message) { - printf("Unimplemented: i7_gen_call.\n"); - return 0; -} - i7val i7_call_0(i7val fn_ref) { i7val args[10]; for (int i=0; i<10; i++) args[i] = 0; return i7_gen_call(fn_ref, args, 0, 0); @@ -554,6 +710,10 @@ void i7_style(int what) { void i7_font(int what) { } +void i7_print_decimal(i7val x) { + printf("%d", (int) x); +} + void i7_print_char(i7val x) { printf("%c", (int) x); } diff --git a/inform7/Tests/Test Basic/BIP-ArithmeticOperations-C.txt b/inform7/Tests/Test Basic/BIP-ArithmeticOperations-C.txt new file mode 100644 index 000000000..96c10c5ab --- /dev/null +++ b/inform7/Tests/Test Basic/BIP-ArithmeticOperations-C.txt @@ -0,0 +1,83 @@ +A fruit is a kind of object. + +An apple, a pear and an orange are fruits. An fruit has a number called size. + +The size of a fruit is usually 4. The size of the apple is 7. + +A length is a kind of value. 1m specifies a length. 1km specifies a length scaled up by 1000. +An area is a kind of value. 10 sq m specifies an area. + +A length times a length specifies an area. + +A fruit has a length. An apple has length 1m. A pear has length 6m. An orange has length 3m. + +To begin: + showme 2 + 3; + showme 2 plus -3; + showme 2 - 3; + showme 2 minus -3; + showme 4 * 5; + showme -4 times 5; + showme 7 multiplied by 9; + showme 256 / 4; + showme 440 divided by -10; + showme the remainder after dividing 17 by 3; + showme 93 to the nearest 10; + showme 99 to the nearest 10; + showme the square root of 144; + showme the cube root of 64; + showme the total size of the fruits; + showme 2m + 3m; + showme 2m plus -3m; + showme 2m - 3m; + showme 2m minus -3m; + showme 4m * 5m; + showme -4m times 5m; + showme 7m multiplied by 9m; + showme 256m / 4m; + showme 440 sq m divided by 10m; + showme the remainder after dividing 17m by 3; + showme 93m to the nearest 10m; + showme 99m to the nearest 10m; + showme the square root of 144 sq m; + showme the total length of the fruits; + showme 3 divided by 2; + showme 3 divided by 2.0; + showme 3.0 divided by 2; + showme 3.0 divided by 2.0; + showme 3 + 3; + showme pi + pi; + showme pi + 3; + showme 3 + pi; + showme 3 - 3; + showme pi - pi; + showme pi - 3; + showme 3 - pi; + showme 3 * 3; + showme pi * pi; + showme pi * 3; + showme 3 * pi; + showme 3 / 3; + showme pi / pi; + showme pi / 3; + showme 3 / pi; + showme the remainder after dividing pi by 3; + showme the remainder after dividing 3.3 by 1; + showme the remainder after dividing 3.7 by 1; + showme the remainder after dividing -3.3 by 1; + showme the remainder after dividing -3.7 by 1; + showme 2 to the power 4; + showme 100 to the power 0.5; + showme 7 to the power -1; + showme pi to the power 0; + showme reciprocal of -2; + showme reciprocal of 0.1; + showme reciprocal of 7; + showme reciprocal of plus infinity; + showme real square root of 2; + showme 1.4 to the nearest whole number; + showme 1.6 to the nearest whole number; + showme -1.6 to the nearest whole number; + showme 6 x 10^23 to the nearest whole number; + showme pi to the power 4; + showme pi * pi * pi * pi; diff --git a/inform7/Tests/Test Basic/_Results_Ideal/BIP-ArithmeticOperations-C.txt b/inform7/Tests/Test Basic/_Results_Ideal/BIP-ArithmeticOperations-C.txt new file mode 100644 index 000000000..5df08f4b5 --- /dev/null +++ b/inform7/Tests/Test Basic/_Results_Ideal/BIP-ArithmeticOperations-C.txt @@ -0,0 +1,70 @@ + +"2 + 3" = number: 5 +"2 plus -3" = number: -1 +"2 - 3" = number: -1 +"2 minus -3" = number: 5 +"4 * 5" = number: 20 +"-4 times 5" = number: -20 +"7 multiplied by 9" = number: 63 +"256 / 4" = number: 64 +"440 divided by -10" = number: -44 +"remainder after dividing 17 by 3" = number: 2 +"93 to the nearest 10" = number: 90 +"99 to the nearest 10" = number: 100 +"square root of 144" = number: 12 +"cube root of 64" = number: 4 +"total size of the fruits" = number: 15 +"2m + 3m" = length: 5m +"2m plus -3m" = length: -1m +"2m - 3m" = length: -1m +"2m minus -3m" = length: 5m +"4m * 5m" = area: 20 sq m +"-4m times 5m" = area: -20 sq m +"7m multiplied by 9m" = area: 63 sq m +"256m / 4m" = number: 64 +"440 sq m divided by 10m" = length: 44m +"remainder after dividing 17m by 3" = length: 2m +"93m to the nearest 10m" = length: 90m +"99m to the nearest 10m" = length: 100m +"square root of 144 sq m" = length: 12m +"total length of the fruits" = length: 10m +"3 divided by 2" = number: 1 +"3 divided by 2.0" = real number: 1.5 +"3.0 divided by 2" = real number: 1.5 +"3.0 divided by 2.0" = real number: 1.5 +"3 + 3" = number: 6 +"pi + pi" = real number: 6.28319 +"pi + 3" = real number: 6.14159 +"3 + pi" = real number: 6.14159 +"3 - 3" = number: 0 +"pi - pi" = real number: 0.0 +"pi - 3" = real number: 0.14159 +"3 - pi" = real number: -0.14159 +"3 * 3" = number: 9 +"pi * pi" = real number: 9.8696 +"pi * 3" = real number: 9.42478 +"3 * pi" = real number: 9.42478 +"3 / 3" = number: 1 +"pi / pi" = real number: 1.0 +"pi / 3" = real number: 1.0472 +"3 / pi" = real number: 0.95493 +"remainder after dividing pi by 3" = real number: 0.14159 +"remainder after dividing 3.3 by 1" = real number: 0.3 +"remainder after dividing 3.7 by 1" = real number: 0.7 +"remainder after dividing -3.3 by 1" = real number: -0.3 +"remainder after dividing -3.7 by 1" = real number: -0.7 +"2 to the power 4" = real number: 16.0 +"100 to the power 0.5" = real number: 10.0 +"7 to the power -1" = real number: 0.14286 +"pi to the power 0" = real number: 1.0 +"reciprocal of -2" = real number: -0.5 +"reciprocal of 0.1" = real number: 10.0 +"reciprocal of 7" = real number: 0.14286 +"reciprocal of plus infinity" = real number: 0.0 +"real square root of 2" = real number: 1.41421 +"1.4 to the nearest whole number" = number: 1 +"1.6 to the nearest whole number" = number: 2 +"-1.6 to the nearest whole number" = number: -2 +"6 x 10^23 to the nearest whole number" = number: 2147483647 +"pi to the power 4" = real number: 97.4091 +"pi * pi * pi * pi" = real number: 97.4091 diff --git a/inform7/runtime-module/Chapter 5/Kind IDs.w b/inform7/runtime-module/Chapter 5/Kind IDs.w index 97dd43624..0a9a02d5e 100644 --- a/inform7/runtime-module/Chapter 5/Kind IDs.w +++ b/inform7/runtime-module/Chapter 5/Kind IDs.w @@ -38,7 +38,6 @@ text_stream *RTKindIDs::identifier_for_weak_ID(kind_constructor *kc) { return kc->explicit_identifier; text_stream *invented = Str::new(); WRITE_TO(invented, "WEAK_ID_%d", kc->allocation_id); -LOG("I did make %S\n", invented); return invented; } diff --git a/inter/final-module/Chapter 2/Constants and Literals.w b/inter/final-module/Chapter 2/Constants and Literals.w index 322b0bc47..b67fc29c5 100644 --- a/inter/final-module/Chapter 2/Constants and Literals.w +++ b/inter/final-module/Chapter 2/Constants and Literals.w @@ -159,16 +159,29 @@ void CodeGen::CL::constant(code_generation *gen, inter_tree_node *P) { } else { CodeGen::Targets::begin_array(gen, CodeGen::CL::name(con_name), format); if (hang_one) CodeGen::Targets::array_entry(gen, I"1", format); - for (int i=DATA_CONST_IFLD; iW.extent; i=i+2) { - if (P->W.data[i] != DIVIDER_IVAL) { - TEMPORARY_TEXT(entry) - CodeGen::select_temporary(gen, entry); - // if ((do_not_bracket == FALSE) && (P->W.data[i] != DIVIDER_IVAL)) WRITE("("); - CodeGen::CL::literal(gen, con_name, Inter::Packages::scope_of(P), P->W.data[i], P->W.data[i+1], unsub); - // if ((do_not_bracket == FALSE) && (P->W.data[i] != DIVIDER_IVAL)) WRITE(")"); - CodeGen::deselect_temporary(gen); - CodeGen::Targets::array_entry(gen, entry, format); - DISCARD_TEXT(entry) + int entry_count = 0; + for (int i=DATA_CONST_IFLD; iW.extent; i=i+2) + if (P->W.data[i] != DIVIDER_IVAL) + entry_count++; + if (hang_one) entry_count++; + inter_ti e = 0; int ips = FALSE; + if ((entry_count == 1) && (Inter::Symbols::read_annotation(con_name, ASSIMILATED_IANN) >= 0)) { + inter_ti val1 = P->W.data[DATA_CONST_IFLD], val2 = P->W.data[DATA_CONST_IFLD+1]; + e = CodeGen::CL::evaluate(gen, Inter::Packages::scope_of(P), val1, val2, &ips); + } + if (e > 1) { + LOG("Entry count 1 on %S masks %d blanks\n", CodeGen::CL::name(con_name), e); + CodeGen::Targets::array_entries(gen, (int) e, ips, format); + } else { + for (int i=DATA_CONST_IFLD; iW.extent; i=i+2) { + if (P->W.data[i] != DIVIDER_IVAL) { + TEMPORARY_TEXT(entry) + CodeGen::select_temporary(gen, entry); + CodeGen::CL::literal(gen, con_name, Inter::Packages::scope_of(P), P->W.data[i], P->W.data[i+1], unsub); + CodeGen::deselect_temporary(gen); + CodeGen::Targets::array_entry(gen, entry, format); + DISCARD_TEXT(entry) + } } } CodeGen::Targets::end_array(gen, format); @@ -322,6 +335,47 @@ void CodeGen::CL::exit_print_mode(void) { printing_mode = FALSE; } +inter_ti CodeGen::CL::evaluate(code_generation *gen, inter_symbols_table *T, inter_ti val1, inter_ti val2, int *ips) { + if (val1 == LITERAL_IVAL) return val2; + if (Inter::Symbols::is_stored_in_data(val1, val2)) { + inter_symbol *aliased = InterSymbolsTables::symbol_from_data_pair_and_table(val1, val2, T); + if (aliased == NULL) internal_error("bad aliased symbol"); + inter_tree_node *D = aliased->definition; + if (D == NULL) internal_error("undefined symbol"); + switch (D->W.data[FORMAT_CONST_IFLD]) { + case CONSTANT_DIRECT: { + inter_ti dval1 = D->W.data[DATA_CONST_IFLD]; + inter_ti dval2 = D->W.data[DATA_CONST_IFLD + 1]; + inter_ti e = CodeGen::CL::evaluate(gen, Inter::Packages::scope_of(D), dval1, dval2, ips); + if (e == 0) { + text_stream *S = CodeGen::CL::name(aliased); + if (Str::eq(S, I"INDIV_PROP_START")) *ips = TRUE; + } + LOG("Eval const $3 = %d\n", aliased, e); + return e; + } + case CONSTANT_SUM_LIST: + case CONSTANT_PRODUCT_LIST: + case CONSTANT_DIFFERENCE_LIST: + case CONSTANT_QUOTIENT_LIST: { + inter_ti result = 0; + for (int i=DATA_CONST_IFLD; iW.extent; i=i+2) { + inter_ti extra = CodeGen::CL::evaluate(gen, Inter::Packages::scope_of(D), D->W.data[i], D->W.data[i+1], ips); + if (i == DATA_CONST_IFLD) result = extra; + else { + if (D->W.data[FORMAT_CONST_IFLD] == CONSTANT_SUM_LIST) result = result + extra; + if (D->W.data[FORMAT_CONST_IFLD] == CONSTANT_PRODUCT_LIST) result = result * extra; + if (D->W.data[FORMAT_CONST_IFLD] == CONSTANT_DIFFERENCE_LIST) result = result - extra; + if (D->W.data[FORMAT_CONST_IFLD] == CONSTANT_QUOTIENT_LIST) result = result / extra; + } + } + return result; + } + } + } + return 0; +} + void CodeGen::CL::literal(code_generation *gen, inter_symbol *con_name, inter_symbols_table *T, inter_ti val1, inter_ti val2, int unsub) { inter_tree *I = gen->from; text_stream *OUT = CodeGen::current(gen); diff --git a/inter/final-module/Chapter 2/Final Targets.w b/inter/final-module/Chapter 2/Final Targets.w index 8e21d3c8b..847eb06b8 100644 --- a/inter/final-module/Chapter 2/Final Targets.w +++ b/inter/final-module/Chapter 2/Final Targets.w @@ -326,6 +326,7 @@ void CodeGen::Targets::end_opcode(code_generation *gen) { @e BEGIN_ARRAY_MTID @e ARRAY_ENTRY_MTID +@e ARRAY_ENTRIES_MTID @e END_ARRAY_MTID @d WORD_ARRAY_FORMAT 1 @@ -336,6 +337,7 @@ void CodeGen::Targets::end_opcode(code_generation *gen) { = VOID_METHOD_TYPE(BEGIN_ARRAY_MTID, code_generation_target *cgt, code_generation *gen, text_stream *const_name, int format) VOID_METHOD_TYPE(ARRAY_ENTRY_MTID, code_generation_target *cgt, code_generation *gen, text_stream *entry, int format) +VOID_METHOD_TYPE(ARRAY_ENTRIES_MTID, code_generation_target *cgt, code_generation *gen, int how_many, int plus_ips, int format) VOID_METHOD_TYPE(END_ARRAY_MTID, code_generation_target *cgt, code_generation *gen, int format) void CodeGen::Targets::begin_array(code_generation *gen, text_stream *const_name, int format) { VOID_METHOD_CALL(gen->target, BEGIN_ARRAY_MTID, gen, const_name, format); @@ -343,6 +345,9 @@ void CodeGen::Targets::begin_array(code_generation *gen, text_stream *const_name void CodeGen::Targets::array_entry(code_generation *gen, text_stream *entry, int format) { VOID_METHOD_CALL(gen->target, ARRAY_ENTRY_MTID, gen, entry, format); } +void CodeGen::Targets::array_entries(code_generation *gen, int how_many, int plus_ips, int format) { + VOID_METHOD_CALL(gen->target, ARRAY_ENTRIES_MTID, gen, how_many, plus_ips, format); +} void CodeGen::Targets::mangled_array_entry(code_generation *gen, text_stream *entry, int format) { TEMPORARY_TEXT(mangled) CodeGen::Targets::mangle(gen, mangled, entry); diff --git a/inter/final-module/Chapter 4/Final Inform 6.w b/inter/final-module/Chapter 4/Final Inform 6.w index 2e263969a..4eb45ec79 100644 --- a/inter/final-module/Chapter 4/Final Inform 6.w +++ b/inter/final-module/Chapter 4/Final Inform 6.w @@ -104,6 +104,7 @@ void CodeGen::I6::create_target(void) { METHOD_ADD(cgt, END_OPCODE_MTID, CodeGen::I6::end_opcode); METHOD_ADD(cgt, BEGIN_ARRAY_MTID, CodeGen::I6::begin_array); METHOD_ADD(cgt, ARRAY_ENTRY_MTID, CodeGen::I6::array_entry); + METHOD_ADD(cgt, ARRAY_ENTRIES_MTID, CodeGen::I6::array_entries); METHOD_ADD(cgt, END_ARRAY_MTID, CodeGen::I6::end_array); METHOD_ADD(cgt, OFFER_PRAGMA_MTID, CodeGen::I6::offer_pragma) METHOD_ADD(cgt, END_GENERATION_MTID, CodeGen::I6::end_generation); @@ -803,6 +804,17 @@ void CodeGen::I6::array_entry(code_generation_target *cgt, code_generation *gen, WRITE(" (%S)", entry); } +@ Alternatively, we can just specify how many entries there will be: they will +then be initialised to 0. + += +void CodeGen::I6::array_entries(code_generation_target *cgt, code_generation *gen, + int how_many, int plus_ips, int format) { + text_stream *OUT = CodeGen::current(gen); + if (plus_ips) WRITE(" (%d + INDIV_PROP_START)", how_many, plus_ips); + else WRITE(" (%d)", how_many); +} + void CodeGen::I6::end_array(code_generation_target *cgt, code_generation *gen, int format) { text_stream *OUT = CodeGen::current(gen); WRITE(";\n"); diff --git a/inter/final-module/Chapter 5/C Arithmetic.w b/inter/final-module/Chapter 5/C Arithmetic.w index bf3b39406..2c5b0d70a 100644 --- a/inter/final-module/Chapter 5/C Arithmetic.w +++ b/inter/final-module/Chapter 5/C Arithmetic.w @@ -12,9 +12,19 @@ int CArithmetic::compile_primitive(code_generation *gen, inter_ti bip, inter_tre case PLUS_BIP: WRITE("("); INV_A1; WRITE(" + "); INV_A2; WRITE(")"); break; case MINUS_BIP: WRITE("("); INV_A1; WRITE(" - "); INV_A2; WRITE(")"); break; case UNARYMINUS_BIP: WRITE("(-("); INV_A1; WRITE("))"); break; - case TIMES_BIP: WRITE("("); INV_A1; WRITE("*"); INV_A2; WRITE(")"); break; - case DIVIDE_BIP: WRITE("("); INV_A1; WRITE("/"); INV_A2; WRITE(")"); break; - case MODULO_BIP: WRITE("("); INV_A1; WRITE("%%"); INV_A2; WRITE(")"); break; + case TIMES_BIP: WRITE("("); INV_A1; WRITE(" * "); INV_A2; WRITE(")"); break; + case DIVIDE_BIP: if (CFunctionModel::inside_function(gen)) { + WRITE("glulx_div_r("); INV_A1; WRITE(", "); INV_A2; WRITE(")"); + } else { + WRITE("("); INV_A1; WRITE(" / "); INV_A2; WRITE(")"); break; + } + break; + case MODULO_BIP: if (CFunctionModel::inside_function(gen)) { + WRITE("glulx_mod_r("); INV_A1; WRITE(", "); INV_A2; WRITE(")"); + } else { + WRITE("("); INV_A1; WRITE(" %% "); INV_A2; WRITE(")"); + } + break; case BITWISEAND_BIP: WRITE("(("); INV_A1; WRITE(")&("); INV_A2; WRITE("))"); break; case BITWISEOR_BIP: WRITE("(("); INV_A1; WRITE(")|("); INV_A2; WRITE("))"); break; case BITWISENOT_BIP: WRITE("(~("); INV_A1; WRITE("))"); break; @@ -54,104 +64,276 @@ Note that floating-point numbers are stored in |i7val| values at runtime by storing |float| (not, alas, |double|) values as if they were four-byte integers. = (text to inform7_clib.h) -void glulx_exp(i7val x, i7val y) { - printf("Unimplemented: glulx_exp.\n"); +void glulx_add(i7val x, i7val y, i7val *z) { + if (z) *z = x + y; } -void glulx_fadd(i7val x, i7val y, i7val z) { - printf("Unimplemented: glulx_fadd.\n"); +void glulx_sub(i7val x, i7val y, i7val *z) { + if (z) *z = x - y; } -void glulx_fdiv(i7val x, i7val y, i7val z) { - printf("Unimplemented: glulx_fdiv.\n"); +void glulx_neg(i7val x, i7val *y) { + if (y) *y = -x; } -void glulx_floor(i7val x, i7val y) { - printf("Unimplemented: glulx_floor.\n"); +void glulx_mul(i7val x, i7val y, i7val *z) { + if (z) *z = x * y; } -void glulx_fmod(i7val x, i7val y, i7val z, i7val w) { - printf("Unimplemented: glulx_fmod.\n"); +void glulx_div(i7val x, i7val y, i7val *z) { + if (y == 0) { printf("Division of %d by 0\n", x); if (z) *z = 1; return; } + int result, ax, ay; + /* Since C doesn't guarantee the results of division of negative + numbers, we carefully convert everything to positive values + first. They have to be unsigned values, too, otherwise the + 0x80000000 case goes wonky. */ + if (x < 0) { + ax = (-x); + if (y < 0) { + ay = (-y); + result = ax / ay; + } else { + ay = y; + result = -(ax / ay); + } + } else { + ax = x; + if (y < 0) { + ay = (-y); + result = -(ax / ay); + } else { + ay = y; + result = ax / ay; + } + } + if (z) *z = result; } -void glulx_fmul(i7val x, i7val y, i7val z) { - printf("Unimplemented: glulx_fmul.\n"); +i7val glulx_div_r(i7val x, i7val y) { + i7val z; + glulx_div(x, y, &z); + return z; } -void glulx_fsub(i7val x, i7val y, i7val z) { - printf("Unimplemented: glulx_fsub.\n"); +void glulx_mod(i7val x, i7val y, i7val *z) { + if (y == 0) { printf("Division of %d by 0\n", x); if (z) *z = 0; return; } + int result, ax, ay; + if (y < 0) { + ay = -y; + } else { + ay = y; + } + if (x < 0) { + ax = (-x); + result = -(ax % ay); + } else { + ax = x; + result = ax % ay; + } + if (z) *z = result; } -void glulx_ftonumn(i7val x, i7val y) { - printf("Unimplemented: glulx_ftonumn.\n"); +i7val glulx_mod_r(i7val x, i7val y) { + i7val z; + glulx_mod(x, y, &z); + return z; } -void glulx_ftonumz(i7val x, i7val y) { - printf("Unimplemented: glulx_ftonumz.\n"); +typedef float gfloat32; + +i7val encode_float(gfloat32 val) { + i7val res; + *(gfloat32 *)(&res) = val; + return res; +} + +gfloat32 decode_float(i7val val) { + gfloat32 res; + *(i7val *)(&res) = val; + return res; +} + +void glulx_exp(i7val x, i7val *y) { + *y = encode_float(expf(decode_float(x))); +} + +void glulx_fadd(i7val x, i7val y, i7val *z) { + *z = encode_float(decode_float(x) + decode_float(y)); +} + +void glulx_fdiv(i7val x, i7val y, i7val *z) { + *z = encode_float(decode_float(x) / decode_float(y)); +} + +void glulx_floor(i7val x, i7val *y) { + *y = encode_float(floorf(decode_float(x))); +} + +void glulx_fmod(i7val x, i7val y, i7val *z, i7val *w) { + float fx = decode_float(x); + float fy = decode_float(y); + float fquot = fmodf(fx, fy); + i7val quot = encode_float(fquot); + i7val rem = encode_float((fx-fquot) / fy); + if (rem == 0x0 || rem == 0x80000000) { + /* When the quotient is zero, the sign has been lost in the + shuffle. We'll set that by hand, based on the original + arguments. */ + rem = (x ^ y) & 0x80000000; + } + if (z) *z = quot; + if (w) *w = rem; +} + +void glulx_fmul(i7val x, i7val y, i7val *z) { + *z = encode_float(decode_float(x) * decode_float(y)); +} + +void glulx_fsub(i7val x, i7val y, i7val *z) { + *z = encode_float(decode_float(x) - decode_float(y)); +} + +void glulx_ftonumn(i7val x, i7val *y) { + float fx = decode_float(x); + i7val result; + if (!signbit(fx)) { + if (isnan(fx) || isinf(fx) || (fx > 2147483647.0)) + result = 0x7FFFFFFF; + else + result = (i7val) (roundf(fx)); + } + else { + if (isnan(fx) || isinf(fx) || (fx < -2147483647.0)) + result = 0x80000000; + else + result = (i7val) (roundf(fx)); + } + *y = result; +} + +void glulx_ftonumz(i7val x, i7val *y) { + float fx = decode_float(x); + i7val result; + if (!signbit(fx)) { + if (isnan(fx) || isinf(fx) || (fx > 2147483647.0)) + result = 0x7FFFFFFF; + else + result = (i7val) (truncf(fx)); + } + else { + if (isnan(fx) || isinf(fx) || (fx < -2147483647.0)) + result = 0x80000000; + else + result = (i7val) (truncf(fx)); + } + *y = result; +} + +void glulx_numtof(i7val x, i7val *y) { + *y = encode_float((float) x); } int glulx_jfeq(i7val x, i7val y, i7val z) { - printf("Unimplemented: glulx_jfeq.\n"); + int result; + if ((z & 0x7F800000) == 0x7F800000 && (z & 0x007FFFFF) != 0) { + /* The delta is NaN, which can never match. */ + result = 0; + } else if ((x == 0x7F800000 || x == 0xFF800000) + && (y == 0x7F800000 || y == 0xFF800000)) { + /* Both are infinite. Opposite infinities are never equal, + even if the difference is infinite, so this is easy. */ + result = (x == y); + } else { + float fx = decode_float(y) - decode_float(x); + float fy = fabs(decode_float(z)); + result = (fx <= fy && fx >= -fy); + } + if (!result) return 1; return 0; } +int glulx_jfne(i7val x, i7val y, i7val z) { + int result; + if ((z & 0x7F800000) == 0x7F800000 && (z & 0x007FFFFF) != 0) { + /* The delta is NaN, which can never match. */ + result = 0; + } else if ((x == 0x7F800000 || x == 0xFF800000) + && (y == 0x7F800000 || y == 0xFF800000)) { + /* Both are infinite. Opposite infinities are never equal, + even if the difference is infinite, so this is easy. */ + result = (x == y); + } else { + float fx = decode_float(y) - decode_float(x); + float fy = fabs(decode_float(z)); + result = (fx <= fy && fx >= -fy); + } + if (!result) return 1; +} + int glulx_jfge(i7val x, i7val y) { - printf("Unimplemented: glulx_jfge.\n"); + if (isgreaterequal(decode_float(x), decode_float(y))) return 1; return 0; } int glulx_jflt(i7val x, i7val y) { - printf("Unimplemented: glulx_jflt.\n"); + if (isless(decode_float(x), decode_float(y))) return 1; return 0; } int glulx_jisinf(i7val x) { - printf("Unimplemented: glulx_jisinf.\n"); + if (isinf(decode_float(x))) return 1; return 0; } int glulx_jisnan(i7val x) { - printf("Unimplemented: glulx_jisnan.\n"); + if (isnan(decode_float(x))) return 1; return 0; } -void glulx_log(i7val x, i7val y) { - printf("Unimplemented: glulx_log.\n"); +void glulx_log(i7val x, i7val *y) { + *y = encode_float(logf(decode_float(x))); } void glulx_acos(i7val x, i7val *y) { - printf("Unimplemented: glulx_acos\n"); + *y = encode_float(acosf(decode_float(x))); } void glulx_asin(i7val x, i7val *y) { - printf("Unimplemented: glulx_asin\n"); + *y = encode_float(asinf(decode_float(x))); } void glulx_atan(i7val x, i7val *y) { - printf("Unimplemented: glulx_atan\n"); + *y = encode_float(atanf(decode_float(x))); } void glulx_ceil(i7val x, i7val *y) { - printf("Unimplemented: glulx_ceil\n"); + *y = encode_float(ceilf(decode_float(x))); } void glulx_cos(i7val x, i7val *y) { - printf("Unimplemented: glulx_cos\n"); + *y = encode_float(cosf(decode_float(x))); } void glulx_pow(i7val x, i7val y, i7val *z) { - printf("Unimplemented: glulx_pow\n"); + if (decode_float(x) == 1.0f) + *z = encode_float(1.0f); + else if ((decode_float(y) == 0.0f) || (decode_float(y) == -0.0f)) + *z = encode_float(1.0f); + else if ((decode_float(x) == -1.0f) && isinf(decode_float(y))) + *z = encode_float(1.0f); + else + *z = encode_float(powf(decode_float(x), decode_float(y))); } void glulx_sin(i7val x, i7val *y) { - printf("Unimplemented: glulx_sin\n"); + *y = encode_float(sinf(decode_float(x))); } void glulx_sqrt(i7val x, i7val *y) { - printf("Unimplemented: glulx_sqrt\n"); + *y = encode_float(sqrtf(decode_float(x))); } void glulx_tan(i7val x, i7val *y) { - printf("Unimplemented: glulx_tan\n"); + *y = encode_float(tanf(decode_float(x))); } = diff --git a/inter/final-module/Chapter 5/C Assembly.w b/inter/final-module/Chapter 5/C Assembly.w index 0199d7476..397186d38 100644 --- a/inter/final-module/Chapter 5/C Assembly.w +++ b/inter/final-module/Chapter 5/C Assembly.w @@ -15,14 +15,17 @@ typedef struct C_generation_assembly_data { int operand_count; int operand_branches; struct inter_tree_node *operand_label; - int pointer_on_operand; + int pointer_on_operand[16]; + int pushed_result; } C_generation_assembly_data; void CAssembly::initialise_data(code_generation *gen) { C_GEN_DATA(asmdata.operand_count) = 0; C_GEN_DATA(asmdata.operand_branches) = FALSE; C_GEN_DATA(asmdata.operand_label) = NULL; - C_GEN_DATA(asmdata.pointer_on_operand) = -1; + for (int i=0; i<16; i++) + C_GEN_DATA(asmdata.pointer_on_operand[i]) = FALSE; + C_GEN_DATA(asmdata.pushed_result) = FALSE; } void CAssembly::begin(code_generation *gen) { @@ -37,14 +40,18 @@ void CAssembly::end(code_generation *gen) { = (text to inform7_clib.h) i7val i7_mgl_sp = 0; +#define I7_ASM_STACK_CAPACITY 128 +i7val i7_asm_stack[I7_ASM_STACK_CAPACITY]; +int i7_asm_stack_pointer = 0; i7val i7_pull(void) { - printf("Unimplemented: i7_pull.\n"); - return (i7val) 0; + if (i7_asm_stack_pointer <= 0) { printf("Stack underflow\n"); return (i7val) 0; } + return i7_asm_stack[--i7_asm_stack_pointer]; } void i7_push(i7val x) { - printf("Unimplemented: i7_push.\n"); + if (i7_asm_stack_pointer >= I7_ASM_STACK_CAPACITY) { printf("Stack overflow\n"); return; } + i7_asm_stack[i7_asm_stack_pointer++] = x; } = @@ -54,6 +61,7 @@ void i7_push(i7val x) { void CAssembly::begin_opcode(code_generation_target *cgt, code_generation *gen, text_stream *opcode) { text_stream *OUT = CodeGen::current(gen); C_GEN_DATA(asmdata.operand_branches) = FALSE; + C_GEN_DATA(asmdata.pushed_result) = FALSE; C_GEN_DATA(asmdata.operand_label) = NULL; if (Str::get_at(opcode, 1) == 'j') { C_GEN_DATA(asmdata.operand_branches) = TRUE; } if (Str::eq(opcode, I"@return")) WRITE("return "); @@ -62,23 +70,44 @@ void CAssembly::begin_opcode(code_generation_target *cgt, code_generation *gen, CNamespace::mangle_opcode(cgt, OUT, opcode); } WRITE("("); C_GEN_DATA(asmdata.operand_count) = 0; - C_GEN_DATA(asmdata.pointer_on_operand) = -1; - if (Str::eq(opcode, I"@acos")) C_GEN_DATA(asmdata.pointer_on_operand) = 2; - if (Str::eq(opcode, I"@aload")) C_GEN_DATA(asmdata.pointer_on_operand) = 3; - if (Str::eq(opcode, I"@aloadb")) C_GEN_DATA(asmdata.pointer_on_operand) = 3; - if (Str::eq(opcode, I"@aloads")) C_GEN_DATA(asmdata.pointer_on_operand) = 3; - if (Str::eq(opcode, I"@asin")) C_GEN_DATA(asmdata.pointer_on_operand) = 2; - if (Str::eq(opcode, I"@atan")) C_GEN_DATA(asmdata.pointer_on_operand) = 2; - if (Str::eq(opcode, I"@binarysearch")) C_GEN_DATA(asmdata.pointer_on_operand) = 8; - if (Str::eq(opcode, I"@ceil")) C_GEN_DATA(asmdata.pointer_on_operand) = 2; - if (Str::eq(opcode, I"@cos")) C_GEN_DATA(asmdata.pointer_on_operand) = 2; - if (Str::eq(opcode, I"@gestalt")) C_GEN_DATA(asmdata.pointer_on_operand) = 3; - if (Str::eq(opcode, I"@glk")) C_GEN_DATA(asmdata.pointer_on_operand) = 3; - if (Str::eq(opcode, I"@pow")) C_GEN_DATA(asmdata.pointer_on_operand) = 3; - if (Str::eq(opcode, I"@shiftl")) C_GEN_DATA(asmdata.pointer_on_operand) = 3; - if (Str::eq(opcode, I"@sin")) C_GEN_DATA(asmdata.pointer_on_operand) = 2; - if (Str::eq(opcode, I"@sqrt")) C_GEN_DATA(asmdata.pointer_on_operand) = 2; - if (Str::eq(opcode, I"@tan")) C_GEN_DATA(asmdata.pointer_on_operand) = 2; + for (int i=0; i<16; i++) + C_GEN_DATA(asmdata.pointer_on_operand[i]) = FALSE; + if (Str::eq(opcode, I"@acos")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@add")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@aload")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@aloadb")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@aloads")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@asin")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@atan")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@binarysearch")) C_GEN_DATA(asmdata.pointer_on_operand[8]) = TRUE; + if (Str::eq(opcode, I"@ceil")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@cos")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@div")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@exp")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@fadd")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@fdiv")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@floor")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@fmod")) { + C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + C_GEN_DATA(asmdata.pointer_on_operand[4]) = TRUE; + } + if (Str::eq(opcode, I"@fmul")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@fsub")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@ftonumn")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@ftonumz")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@gestalt")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@glk")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@log")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@mod")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@mul")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@neg")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@numtof")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@pow")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@shiftl")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@sin")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@sqrt")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; + if (Str::eq(opcode, I"@sub")) C_GEN_DATA(asmdata.pointer_on_operand[3]) = TRUE; + if (Str::eq(opcode, I"@tan")) C_GEN_DATA(asmdata.pointer_on_operand[2]) = TRUE; } void CAssembly::supply_operand(code_generation_target *cgt, code_generation *gen, inter_tree_node *F, int is_label) { text_stream *OUT = CodeGen::current(gen); @@ -86,17 +115,19 @@ void CAssembly::supply_operand(code_generation_target *cgt, code_generation *gen C_GEN_DATA(asmdata.operand_label) = F; } else { if (C_GEN_DATA(asmdata.operand_count)++ > 0) WRITE(", "); - if (C_GEN_DATA(asmdata.operand_count) == C_GEN_DATA(asmdata.pointer_on_operand)) { - TEMPORARY_TEXT(write_to) - CodeGen::select_temporary(gen, write_to); - CodeGen::FC::frame(gen, F); - CodeGen::deselect_temporary(gen); - if (Str::eq(write_to, I"0")) WRITE("NULL"); + TEMPORARY_TEXT(write_to) + CodeGen::select_temporary(gen, write_to); + CodeGen::FC::frame(gen, F); + CodeGen::deselect_temporary(gen); + if (C_GEN_DATA(asmdata.pointer_on_operand[C_GEN_DATA(asmdata.operand_count)])) { + if (Str::eq(write_to, I"i7_mgl_sp")) { WRITE("&%S", write_to); C_GEN_DATA(asmdata.pushed_result) = TRUE; } + else if (Str::eq(write_to, I"0")) WRITE("NULL"); else WRITE("&%S", write_to); - DISCARD_TEXT(write_to) } else { - CodeGen::FC::frame(gen, F); + if (Str::eq(write_to, I"i7_mgl_sp")) { WRITE("i7_pull()"); } + else WRITE("%S", write_to); } + DISCARD_TEXT(write_to) } } void CAssembly::end_opcode(code_generation_target *cgt, code_generation *gen) { @@ -108,6 +139,7 @@ void CAssembly::end_opcode(code_generation_target *cgt, code_generation *gen) { if (C_GEN_DATA(asmdata.operand_label) == NULL) internal_error("no branch label"); CodeGen::FC::frame(gen, C_GEN_DATA(asmdata.operand_label)); } + if (C_GEN_DATA(asmdata.pushed_result)) WRITE("; i7_push(i7_mgl_sp)"); } @ @@ -129,10 +161,6 @@ void glulx_copy(i7val x, i7val y) { printf("Unimplemented: glulx_copy.\n"); } -void glulx_div(i7val x, i7val y, i7val z) { - printf("Unimplemented: glulx_div.\n"); -} - void glulx_gestalt(i7val x, i7val y, i7val *z) { *z = 1; } @@ -166,7 +194,7 @@ void glulx_glk(i7val glk_api_selector, i7val i7varargc, i7val *z) { } int glulx_jeq(i7val x, i7val y) { - printf("Unimplemented: glulx_jeq.\n"); + if (x == y) return 1; return 0; } @@ -176,12 +204,12 @@ int glulx_jleu(i7val x, i7val y) { } int glulx_jnz(i7val x) { - printf("Unimplemented: glulx_jnz.\n"); + if (x != 0) return 1; return 0; } int glulx_jz(i7val x) { - printf("Unimplemented: glulx_jz.\n"); + if (x == 0) return 1; return 0; } @@ -197,17 +225,6 @@ void glulx_mfree(i7val x) { printf("Unimplemented: glulx_mfree.\n"); } -void glulx_mod(i7val x, i7val y, i7val z) { - printf("Unimplemented: glulx_mod.\n"); -} - -void glulx_neg(i7val x, i7val y) { - printf("Unimplemented: glulx_neg.\n"); -} - -void glulx_numtof(i7val x, i7val y) { - printf("Unimplemented: glulx_numtof.\n"); -} void glulx_quit(void) { printf("Unimplemented: glulx_quit.\n"); @@ -221,12 +238,14 @@ void glulx_setiosys(i7val x, i7val y) { // Deliberately ignored: we are using stdout, not glk } +void i7_print_char(i7val x); void glulx_streamchar(i7val x) { - printf("%c", (int) x); + i7_print_char(x); } +void i7_print_decimal(i7val x); void glulx_streamnum(i7val x) { - printf("Unimplemented: glulx_streamnum.\n"); + i7_print_decimal(x); } void glulx_streamstr(i7val x) { @@ -234,11 +253,7 @@ void glulx_streamstr(i7val x) { } void glulx_streamunichar(i7val x) { - printf("%c", (int) x); -} - -void glulx_sub(i7val x, i7val y, i7val z) { - printf("Unimplemented: glulx_sub.\n"); + i7_print_char(x); } void glulx_ushiftr(i7val x, i7val y, i7val z) { diff --git a/inter/final-module/Chapter 5/C Function Model.w b/inter/final-module/Chapter 5/C Function Model.w index 63171f649..cf3d02e2e 100644 --- a/inter/final-module/Chapter 5/C Function Model.w +++ b/inter/final-module/Chapter 5/C Function Model.w @@ -20,12 +20,14 @@ typedef struct C_generation_function_model_data { struct text_stream *prototype; int argument_count; struct final_c_function *current_fcf; + int compiling_function; } C_generation_function_model_data; void CFunctionModel::initialise_data(code_generation *gen) { C_GEN_DATA(fndata.prototype) = Str::new(); C_GEN_DATA(fndata.argument_count) = 0; C_GEN_DATA(fndata.current_fcf) = NULL; + C_GEN_DATA(fndata.compiling_function) = FALSE; } void CFunctionModel::begin(code_generation *gen) { @@ -65,6 +67,43 @@ void CFunctionModel::end(code_generation *gen) { WRITE("#endif\n"); WRITE("#endif\n"); CodeGen::deselect(gen, saved); + + saved = CodeGen::select(gen, c_fundamental_types_I7CGS); + OUT = CodeGen::current(gen); + WRITE("i7val i7_gen_call(i7val fn_ref, i7val *args, int argc, int call_message);\n"); + CodeGen::deselect(gen, saved); + + saved = CodeGen::select(gen, c_stubs_at_eof_I7CGS); + OUT = CodeGen::current(gen); + WRITE("i7val i7_gen_call(i7val fn_ref, i7val *args, int argc, int call_message) {\n"); INDENT; + WRITE("switch (fn_ref) {\n"); INDENT; + final_c_function *fcf; + LOOP_OVER(fcf, final_c_function) { + WRITE("case "); + CNamespace::mangle(NULL, OUT, fcf->identifier_as_constant); + WRITE(": return fn_"); + CNamespace::mangle(NULL, OUT, fcf->identifier_as_constant); + WRITE("("); + if (fcf->uses_vararg_model) { + WRITE("2, argc, (i7varargs) { "); + for (int i=0; i<10; i++) { + if (i > 0) WRITE(", "); + WRITE("args[%d]", i); + } + WRITE(" }"); + for (int i=0; imax_arity - 1; i++) + WRITE(", 0"); + } else { + WRITE("argc"); + for (int i=0; imax_arity; i++) + WRITE(", args[%d]", i); + } + WRITE(");\n"); + } + OUTDENT; WRITE("}\n"); + WRITE("printf(\"function not found\\n\");\n"); + OUTDENT; WRITE("}\n"); + CodeGen::deselect(gen, saved); } typedef struct final_c_function { @@ -93,6 +132,7 @@ void CFunctionModel::declare_fcf(code_generation *gen, final_c_function *fcf) { void CFunctionModel::make_veneer_fcf(code_generation *gen, text_stream *unmangled_name) { final_c_function *fcf = CFunctionModel::new_fcf(unmangled_name); + fcf->max_arity = 1; CFunctionModel::declare_fcf(gen, fcf); } @@ -124,6 +164,7 @@ void CFunctionModel::begin_function_code(code_generation_target *cgt, code_gener WRITE("printf(\"called %S\\n\");\n", C_GEN_DATA(fndata.current_fcf)->identifier_as_constant); } } + C_GEN_DATA(fndata.compiling_function) = TRUE; } void CFunctionModel::place_label(code_generation_target *cgt, code_generation *gen, text_stream *label_name) { @@ -150,9 +191,15 @@ void CFunctionModel::end_function(code_generation_target *cgt, int pass, code_ge text_stream *OUT = CodeGen::current(gen); WRITE("return 1;\n"); WRITE("\n}\n"); + C_GEN_DATA(fndata.compiling_function) = FALSE; } } +int CFunctionModel::inside_function(code_generation *gen) { + if (C_GEN_DATA(fndata.compiling_function)) return TRUE; + return FALSE; +} + void CFunctionModel::begin_function_call(code_generation_target *cgt, code_generation *gen, inter_symbol *fn, int argc) { inter_tree_node *D = fn->definition; if ((D) && (D->W.data[ID_IFLD] == CONSTANT_IST) && (D->W.data[FORMAT_CONST_IFLD] == CONSTANT_DIRECT)) { @@ -250,11 +297,6 @@ typedef struct i7varargs { i7val i7_mgl_self = 0; -i7val i7_gen_call(i7val fn_ref, i7val *args, int argc, int call_message) { - printf("Unimplemented: i7_gen_call.\n"); - return 0; -} - i7val i7_call_0(i7val fn_ref) { i7val args[10]; for (int i=0; i<10; i++) args[i] = 0; return i7_gen_call(fn_ref, args, 0, 0); diff --git a/inter/final-module/Chapter 5/C Input-Output Model.w b/inter/final-module/Chapter 5/C Input-Output Model.w index 9420f7fc5..beb1d804a 100644 --- a/inter/final-module/Chapter 5/C Input-Output Model.w +++ b/inter/final-module/Chapter 5/C Input-Output Model.w @@ -36,7 +36,7 @@ int CInputOutputModel::compile_primitive(code_generation *gen, inter_ti bip, int case PRINTNAME_BIP: WRITE("i7_print_name("); INV_A1; WRITE(")"); break; case PRINTOBJ_BIP: WRITE("i7_print_object("); INV_A1; WRITE(")"); break; case PRINTPROPERTY_BIP: WRITE("i7_print_property("); INV_A1; WRITE(")"); break; - case PRINTNUMBER_BIP: WRITE("printf(\"%%d\", (int) "); INV_A1; WRITE(")"); break; + case PRINTNUMBER_BIP: WRITE("i7_print_decimal("); INV_A1; WRITE(")"); break; case PRINTNLNUMBER_BIP: WRITE("i7_print_number("); INV_A1; WRITE(")"); break; case PRINTDEF_BIP: WRITE("i7_print_def_art("); INV_A1; WRITE(")"); break; case PRINTCDEF_BIP: WRITE("i7_print_cdef_art("); INV_A1; WRITE(")"); break; @@ -64,6 +64,10 @@ void i7_style(int what) { void i7_font(int what) { } +void i7_print_decimal(i7val x) { + printf("%d", (int) x); +} + void i7_print_char(i7val x) { printf("%c", (int) x); } diff --git a/inter/final-module/Chapter 5/C Memory Model.w b/inter/final-module/Chapter 5/C Memory Model.w index 57d118ca2..64999f167 100644 --- a/inter/final-module/Chapter 5/C Memory Model.w +++ b/inter/final-module/Chapter 5/C Memory Model.w @@ -8,6 +8,7 @@ How arrays of all kinds are stored in C. void CMemoryModel::initialise(code_generation_target *cgt) { METHOD_ADD(cgt, BEGIN_ARRAY_MTID, CMemoryModel::begin_array); METHOD_ADD(cgt, ARRAY_ENTRY_MTID, CMemoryModel::array_entry); + METHOD_ADD(cgt, ARRAY_ENTRIES_MTID, CMemoryModel::array_entries); METHOD_ADD(cgt, END_ARRAY_MTID, CMemoryModel::end_array); } @@ -198,7 +199,7 @@ void CMemoryModel::array_entry(code_generation_target *cgt, code_generation *gen } @ = - WRITE(" (i7byte) %S,\n", entry); + WRITE(" (i7byte) %S, /* %d */\n", entry, C_GEN_DATA(memdata.himem)); C_GEN_DATA(memdata.himem) += 1; @ Now we see why it was important for |I7BYTE_0| and so on to be macros: they @@ -207,10 +208,20 @@ and therefore if |X| is a valid constant-context expression in C then so is |I7BYTE_0(X)|. @ = - WRITE(" I7BYTE_0(%S), I7BYTE_1(%S), I7BYTE_2(%S), I7BYTE_3(%S),\n", - entry, entry, entry, entry); + WRITE(" I7BYTE_0(%S), I7BYTE_1(%S), I7BYTE_2(%S), I7BYTE_3(%S), /* %d */\n", + entry, entry, entry, entry, C_GEN_DATA(memdata.himem)); C_GEN_DATA(memdata.himem) += 4; +@ Alternatively, we can just specify how many entries there will be: they will +then be initialised to 0. + += +void CMemoryModel::array_entries(code_generation_target *cgt, code_generation *gen, + int how_many, int plus_ips, int format) { + if (plus_ips) how_many += 64; + for (int i=0; i= i7_max_objects) || (prop_id < 0) || (prop_id >= i7_no_property_ids)) return 0; - while (i7_properties[(int) owner_id].value_set[(int) prop_id] == 0) + while (i7_properties[(int) owner_id].value_set[(int) prop_id] == 0) { owner_id = i7_class_of[owner_id]; + } return i7_properties[(int) owner_id].value[(int) prop_id]; } diff --git a/inter/final-module/Chapter 5/Final C.w b/inter/final-module/Chapter 5/Final C.w index cf5ef29c6..bed0effdc 100644 --- a/inter/final-module/Chapter 5/Final C.w +++ b/inter/final-module/Chapter 5/Final C.w @@ -48,6 +48,7 @@ first of those: #include #include +#include = @h Segmentation.