Stack improvements, stop replying of tmpfile and codegen fixes
authorRobert Pengelly <robertapengelly@hotmail.com>
Tue, 26 May 2026 04:27:43 +0000 (05:27 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Tue, 26 May 2026 04:27:43 +0000 (05:27 +0100)
int64.c
int64.h
parse.c
token.c
token.h

diff --git a/int64.c b/int64.c
index 8ad59f5d0c0bb9aa06e5c8e2bf016e35a39cfb59..dc100f8ebf060cf936f2e1b24f9f949a67d44f67 100644 (file)
--- a/int64.c
+++ b/int64.c
@@ -469,12 +469,45 @@ int gt64_signed (int64_s a, int64_s b) {
 
 }
 
-void ld_to_u64 (int64_s *out, long double x) {
+static double int64_double_2p32 (void) {
 
-    long double base = 4294967296.0L;                       /* 2^32 */
-    long double hi, lo;
+    double v;
     
-    if (x <= 0.0L) {
+    v = 65536;
+    v *= 65536;
+    
+    return v;
+
+}
+
+static double int64_double_2p63 (void) {
+
+    double v;
+    
+    v = int64_double_2p32 ();
+    v *= 2147483648UL;
+    
+    return v;
+
+}
+
+static double int64_double_2p64 (void) {
+
+    double v;
+    
+    v = int64_double_2p32 ();
+    v *= int64_double_2p32 ();
+    
+    return v;
+
+}
+
+void ld_to_u64 (int64_s *out, double x) {
+
+    double base = int64_double_2p32 ();
+    double hi, lo;
+    
+    if (x <= 0.0) {
     
         out->low = 0;
         out->high = 0;
@@ -484,7 +517,7 @@ void ld_to_u64 (int64_s *out, long double x) {
     }
     
     /* optional clamp */
-    if (x >= 18446744073709551615.0L) {                     /* 2^64 - 1 */
+    if (x >= int64_double_2p64 ()) {
     
         out->low = 0xFFFFFFFFUL;
         out->high = 0xFFFFFFFFUL;
@@ -496,14 +529,14 @@ void ld_to_u64 (int64_s *out, long double x) {
     hi = x / base;
     out->high = (unsigned long) hi;
     
-    lo = x - ((long double) out->high * base);
+    lo = x - ((double) out->high * base);
     out->low = (unsigned long) lo;
 
 }
 
-void ld_to_i64 (int64_s *out, long double x) {
+void ld_to_i64 (int64_s *out, double x) {
 
-    long double limit = 9223372036854775808.0L; /* 2^63 */
+    double limit = int64_double_2p63 ();
     
     if (x >= limit) {
     
@@ -525,7 +558,7 @@ void ld_to_i64 (int64_s *out, long double x) {
     
     }
     
-    if (x >= 0.0L) {
+    if (x >= 0.0) {
     
         ld_to_u64 (out, x);
         return;
@@ -578,23 +611,23 @@ static void norm64 (int64_s *v) {
 
 }
 
-long double u64_to_ld (int64_s v) {
+double u64_to_ld (int64_s v) {
 
     norm64 (&v);
-    return (long double) v.high * 4294967296.0L + (long double) v.low;
+    return (double) v.high * int64_double_2p32 () + (double) v.low;
 
 }
 
-long double i64_to_ld (int64_s v) {
+double i64_to_ld (int64_s v) {
 
     norm64 (&v);
 
     if (!(v.high & 0x80000000UL)) {
-        return (long double) v.high * 4294967296.0L + (long double) v.low;
+        return (double) v.high * int64_double_2p32 () + (double) v.low;
     }
 
     neg64 (&v);
-    return -((long double) v.high * 4294967296.0L + (long double) v.low);
+    return -((double) v.high * int64_double_2p32 () + (double) v.low);
 
 }
 
diff --git a/int64.h b/int64.h
index de17e05632dc3f2c28422d1eca050873db150e2f..aeeff00f1a0231fcfa964032dba980d938612542 100644 (file)
--- a/int64.h
+++ b/int64.h
@@ -53,8 +53,8 @@ int gte64_signed (int64_s a, int64_s b);
 int gt64_unsigned (int64_s a, int64_s b);
 int gt64_signed (int64_s a, int64_s b);
 
-void ld_to_u64 (int64_s *out, long double x);
-void ld_to_i64 (int64_s *out, long double x);
+void ld_to_u64 (int64_s *out, double x);
+void ld_to_i64 (int64_s *out, double x);
 
 int int64_is_negative (int64_s v);
 int int64_fits_uint (int64_s v);
@@ -65,7 +65,7 @@ void parse_string_to_i64 (int64_s *val, const char *str);
 
 #define     U32_MASK                    ((((unsigned long) 0xFFFFU) << 16) | 0xFFFFU)
 
-long double u64_to_ld (int64_s v);
-long double i64_to_ld (int64_s v);
+double u64_to_ld (int64_s v);
+double i64_to_ld (int64_s v);
 
 #endif      /* _INT64_H */
diff --git a/parse.c b/parse.c
index 38f26ec23e4c01e27bf7f534068ce8fba43746fe..91e1072bbbc1b444585199d057bc1ef23ce605a5 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -99,6 +99,9 @@ static int pending_struct_return_stack_top = 0;
 static int suppress_next_struct_return_scalar_store = 0;
 static int token_identifier_is_function_call_rhs_now (void);
 
+static int assignment32_stop_before_condition_operator = 0;
+static int assignment64_stop_before_condition_operator = 0;
+
 static int parsed_type_size = DATA_NONE;
 static int parsed_type_is_inline = 0;
 static int parsed_type_is_void = 0;
@@ -1851,6 +1854,117 @@ static char *read_tmp_file_text (FILE *fp) {
 
 }
 
+static FILE *open_scc_temp_file (char *name, size_t name_size) {
+
+    static unsigned long temp_id = 1;
+    unsigned long i;
+    
+    FILE *fp;
+    
+    if (!name || name_size == 0) {
+        return 0;
+    }
+    
+    for (i = 0; i < 1000; i++) {
+    
+        sprintf (name, "scc_tmp_%lu.tmp", temp_id++);
+        
+        if ((fp = fopen (name, "rb"))) {
+        
+            fclose (fp);
+            continue;
+        
+        }
+        
+        fp = fopen (name, "w+b");
+        
+        if (fp) {
+            return fp;
+        }
+    
+    }
+    
+    name[0] = 0;
+    return 0;
+
+}
+
+static void append_inline_text (char **dst, const char *start, size_t len);
+
+static void emit_function_frame_adjust_text (char **dst, long frame_size) {
+
+    char buf[128];
+    int n;
+    
+    if (!dst) {
+        return;
+    }
+    
+    frame_size = (frame_size + 3) & ~3L;
+    
+    if (frame_size <= 0) {
+        return;
+    }
+    
+    if (frame_size > 2147483647L) {
+        frame_size = 2147483647L;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        n = sprintf (buf, "    sub esp, %ld\n", frame_size);
+    } else {
+        n = sprintf (buf, "    subl $%ld, %%esp\n", frame_size);
+    }
+    
+    append_inline_text (dst, buf, (size_t) n);
+
+}
+
+static char *replace_function_frame_placeholder (const char *text, long frame_size) {
+
+    const char *marker = "__SCC_FRAME_PLACEHOLDER__\n";
+    const char *p;
+    const char *last;
+    
+    char *out = 0;
+    size_t marker_len;
+    
+    if (!text) {
+        return 0;
+    }
+    
+    marker_len = strlen (marker);
+    last = text;
+    
+    while ((p = strstr (last, marker)) != 0) {
+    
+        append_inline_text (&out, last, (size_t) (p - last));
+        
+        emit_function_frame_adjust_text (&out, frame_size);
+        last = p + marker_len;
+    
+    }
+    
+    append_inline_text (&out, last, strlen (last));
+    return out;
+
+}
+
+static FILE *scc_tmpfile (void) {
+
+    char name[64];
+    FILE *fp;
+
+    fp = open_scc_temp_file (name, sizeof (name));
+
+    if (fp && name[0]) {
+        remove (name);
+    }
+
+    return fp;
+
+}
+
 static void append_inline_text (char **dst, const char *start, size_t len) {
 
     size_t old_len = 0;
@@ -5732,6 +5846,15 @@ static int local_symbol_count = 0;
 static long current_local_stack_size = 0;
 static long current_block_cleanup_bytes = 0;
 
+static long current_function_frame_size = 0;
+
+static int current_function_frame_label = -1;
+static int current_function_frame_deferred = 0;
+static int current_function_frame_enabled = 0;
+static int current_function_uses_single_frame = 0;
+
+static int next_function_frame_label = 1;
+
 static long align_up_long (long value, int align) {
 
     long mask;
@@ -5796,7 +5919,11 @@ static void reset_local_symbols (void) {
     }
     
     local_symbol_count = 0;
+    
     current_local_stack_size = 0;
+    current_block_cleanup_bytes = 0;
+    current_function_frame_size = 0;
+    current_function_uses_single_frame = 0;
 
 }
 
@@ -5931,6 +6058,10 @@ static long add_local_symbol (const char *name, int size, int align, int is_unsi
     
     local_symbol_count++;
     current_local_stack_size = new_size;
+    
+    if (current_local_stack_size > current_function_frame_size) {
+        current_function_frame_size = current_local_stack_size;
+    }
 
     return -(long) new_size;
 
@@ -6455,12 +6586,20 @@ static int token_is_ms_int_type_name (void) {
 
 static int is_type_start (enum token_kind k) {
 
-    if (k == TOK_IDENT && token_is_ms_int_type_name ()) {
-        return 1;
-    }
-    
     switch (k) {
     
+        case TOK_IDENT:
+        
+            if (token_is_ms_int_type_name ()) {
+                return 1;
+            }
+            
+            if (is_current_typedef_name ()) {
+                return 1;
+            }
+            
+            return 0;
+        
         case TOK_AUTO:          case TOK_REGISTER:      case TOK_STATIC:
         case TOK_DLLEXPORT:     case TOK_EXTERN:        case TOK_TYPEDEF:       case TOK_INLINE:
         case TOK_CONST:         case TOK_VOLATILE:      case TOK_RESTRICT:
@@ -6478,10 +6617,6 @@ static int is_type_start (enum token_kind k) {
     
     }
     
-    if (k == TOK_IDENT && is_current_typedef_name ()) {
-        return 1;
-    }
-    
     return 0;
 
 }
@@ -6629,6 +6764,8 @@ int parse_cast_type_name (int *out_size, int *out_is_unsigned, int *out_is_point
 
 }
 
+static int last_deref_cast_type_is_floating = 0;
+
 static int parse_deref_cast_type_name (int *out_size) {
 
     int saved_type_size = parsed_type_size;
@@ -6655,6 +6792,9 @@ static int parse_deref_cast_type_name (int *out_size) {
     
     int size = DATA_INT & 0x1f;
     int ok = 0, i;
+    int cast_is_floating = 0;
+    
+    last_deref_cast_type_is_floating = 0;
     
     for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
         saved_fields[i] = parsed_field_sizes[i];
@@ -6670,7 +6810,9 @@ static int parse_deref_cast_type_name (int *out_size) {
         declarator_array_count = 0;
         
         parse_type_spec ();
+        
         size = parsed_type_size & 0x1f;
+        cast_is_floating = parsed_type_is_floating;
         
         if (tok.kind != TOK_RPAREN) {
         
@@ -6695,6 +6837,8 @@ static int parse_deref_cast_type_name (int *out_size) {
         
             get_token ();
             ok = 1;
+            
+            last_deref_cast_type_is_floating = cast_is_floating;
         
         } else {
             expect (TOK_RPAREN, ")");
@@ -8164,6 +8308,9 @@ static void parse_old_style_param_decls (void) {
 static void emit_extern_symbol (const char *name, int size, int is_function);
 static void emit_extern_reference_symbol (const char *name, int size);
 
+static void emit_deferred_function_frame_placeholder (void);
+static void patch_deferred_function_frame (void);
+
 static void emit_function_start (const char *name, int is_static) {
 
     const char *asm_name;
@@ -8202,12 +8349,16 @@ static void emit_function_start (const char *name, int is_static) {
         fprintf (state->ofp, "%s:\n", asm_name);
         fprintf (state->ofp, "    push ebp\n");
         fprintf (state->ofp, "    mov ebp, esp\n");
+        
+        emit_deferred_function_frame_placeholder ();
     
     } else {
     
         fprintf (state->ofp, "%s:\n", asm_name);
         fprintf (state->ofp, "    pushl %%ebp\n");
         fprintf (state->ofp, "    movl %%esp, %%ebp\n");
+        
+        emit_deferred_function_frame_placeholder ();
     
     }
 
@@ -8250,6 +8401,31 @@ static void emit_stack_adjust (long bytes, int allocate) {
 
 }
 
+static void emit_deferred_function_frame_placeholder (void) {
+
+    current_function_frame_label = -1;
+    current_function_frame_deferred = 0;
+    
+    if (!state->ofp || !current_function_frame_enabled) {
+        return;
+    }
+    
+    current_function_frame_label = next_function_frame_label++;
+    current_function_frame_deferred = 1;
+    current_function_uses_single_frame = 1;
+    
+    fprintf (state->ofp, "__SCC_FRAME_PLACEHOLDER__\n");
+
+}
+
+static void patch_deferred_function_frame (void) {
+
+    current_function_frame_deferred = 0;
+    current_function_frame_label = -1;
+    current_function_frame_enabled = 0;
+
+}
+
 static void format_intel_ebp_offset (char *buf, size_t bufsz, long offset) {
 
     if (!buf || bufsz == 0) {
@@ -8554,6 +8730,8 @@ static void emit_local_initializers (struct local_init *inits, int init_count) {
 
 static void emit_function_end (void) {
 
+    patch_deferred_function_frame ();
+    
     if (!state->ofp) {
         return;
     }
@@ -10287,6 +10465,15 @@ static void ensure_block_stack_allocated (long block_stack_start, long *block_st
         return;
     }
     
+    if (current_function_frame_deferred) {
+    
+        *block_stack_bytes = needed_stack_bytes;
+        *block_stack_emitted = (needed_stack_bytes > 0);
+        
+        return;
+    
+    }
+    
     if (!*block_stack_emitted) {
     
         *block_stack_bytes = needed_stack_bytes;
@@ -10650,6 +10837,11 @@ static void parse_block (void) {
                             int adj_i;
                             
                             current_local_stack_size += (elem_index * elem_size) - object_size;
+                            
+                            if (current_local_stack_size > current_function_frame_size) {
+                                current_function_frame_size = current_local_stack_size;
+                            }
+                            
                             new_offset = -current_local_stack_size;
                             delta = new_offset - old_offset;
                             object_offset = new_offset;
@@ -10866,9 +11058,12 @@ static void parse_block (void) {
                 if (!block_stack_emitted) {
                 
                     block_stack_bytes = needed_stack_bytes;
-                    emit_stack_adjust (block_stack_bytes, 1);
                     
-                    if (!is_function_body) {
+                    if (!current_function_frame_deferred) {
+                        emit_stack_adjust (block_stack_bytes, 1);
+                    }
+                    
+                    if (!is_function_body && !current_function_frame_deferred) {
                         current_block_cleanup_bytes += block_stack_bytes;
                     }
                     
@@ -10877,9 +11072,12 @@ static void parse_block (void) {
                 } else if (needed_stack_bytes > block_stack_bytes) {
                 
                     long extra_stack_bytes = needed_stack_bytes - block_stack_bytes;
-                    emit_stack_adjust (extra_stack_bytes, 1);
                     
-                    if (!is_function_body) {
+                    if (!current_function_frame_deferred) {
+                        emit_stack_adjust (extra_stack_bytes, 1);
+                    }
+                    
+                    if (!is_function_body && !current_function_frame_deferred) {
                         current_block_cleanup_bytes += extra_stack_bytes;
                     }
                     
@@ -10917,12 +11115,19 @@ static void parse_block (void) {
             if (!block_stack_emitted) {
             
                 block_stack_bytes = needed_stack_bytes;
-                emit_stack_adjust (block_stack_bytes, 1);
+                
+                if (!current_function_frame_deferred) {
+                    emit_stack_adjust (block_stack_bytes, 1);
+                }
+                
                 block_stack_emitted = (block_stack_bytes > 0);
             
             } else if (needed_stack_bytes > block_stack_bytes) {
             
-                emit_stack_adjust (needed_stack_bytes - block_stack_bytes, 1);
+                if (!current_function_frame_deferred) {
+                    emit_stack_adjust (needed_stack_bytes - block_stack_bytes, 1);
+                }
+                
                 block_stack_bytes = needed_stack_bytes;
             
             }
@@ -10936,7 +11141,7 @@ static void parse_block (void) {
     
     expect (TOK_RBRACE, "}");
     
-    if (!is_function_body && block_stack_emitted && block_stack_bytes > 0) {
+    if (!is_function_body && !current_function_frame_deferred && block_stack_emitted && block_stack_bytes > 0) {
     
         emit_stack_adjust (block_stack_bytes, 0);
         
@@ -18824,10 +19029,90 @@ static int emit_load_deref_assignment_expression_to_reg_now (const char *reg) {
 
 }
 
+static int source_starts_double_deref_at_now (const char *p) {
+
+    if (!p || *p != '*') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '*';
+
+}
+
+static int current_floating_token_is_nonzero_now (void) {
+
+    if (tok.kind == TOK_CFLOAT) {
+    
+        union { float f; unsigned long u; } v;
+        
+        v.u = 0;
+        v.f = tok.val.f;
+        
+        return (v.u & 0x7fffffffUL) != 0;
+    
+    }
+    
+    {
+    
+        union { double d; unsigned long u[2]; } v;
+        
+        v.u[0] = 0;
+        v.u[1] = 0;
+        
+        if (tok.kind == TOK_CLDOUBLE) {
+            v.d = tok.val.ld;
+        } else {
+            v.d = tok.val.d;
+        }
+        
+        return ((v.u[1] & 0x7fffffffUL) != 0 || v.u[0] != 0);
+    
+    }
+
+}
+
 static void emit_load_assignment_rhs_to_reg (const char *reg) {
 
     clear_rhs_last_pointer_info ();
     
+    if (tok.kind == TOK_STAR && source_starts_double_deref_at_now (tok.caret)) {
+    
+        int deref_size;
+        int inner_pointer_depth;
+        int inner_pointed_size;
+        
+        get_token ();
+        emit_load_assignment_rhs_to_reg (reg);
+        
+        inner_pointer_depth = rhs_last_pointer_depth;
+        inner_pointed_size = rhs_last_pointed_size;
+        
+        if (inner_pointer_depth > 1) {
+            deref_size = DATA_PTR & 0x1f;
+        } else if (inner_pointer_depth == 1 && inner_pointed_size > 0) {
+            deref_size = inner_pointed_size & 0x1f;
+        } else {
+            deref_size = DATA_INT & 0x1f;
+        }
+        
+        emit_load_deref_reg_now (reg, deref_size);
+        
+        if (inner_pointer_depth > 1) {
+            set_rhs_last_pointer_info (inner_pointer_depth - 1, inner_pointed_size);
+        } else {
+            clear_rhs_last_pointer_info ();
+        }
+        
+        return;
+    
+    }
+    
     if (tok.kind == TOK_LPAREN && source_starts_lparen_deref_postfix_incdec_at (tok.caret)) {
     
         get_token ();
@@ -20847,11 +21132,12 @@ static void emit_load_assignment_rhs_to_reg (const char *reg) {
         {
         
             int trailing_op = 0;
-            size_t len = tok.ident ? strlen (tok.ident) : 0;
             int64_s v;
             
+            size_t len = tok.ident ? strlen (tok.ident) : 0;
+            
+            v.low = current_floating_token_is_nonzero_now () ? 1 : 0;
             v.high = 0;
-            v.low = tok.val.ld != 0.0L ? 1 : 0;
             
             if (len > 1 && tok.ident[len - 1] == '+') {
                 trailing_op = TOK_PLUS;
@@ -22032,9 +22318,9 @@ static int64_s floating_constant_to_bits_now (int size) {
         if (tok.kind == TOK_CFLOAT) {
             f = tok.val.f;
         } else if (tok.kind == TOK_CLDOUBLE) {
-            f = (float) tok.val.ld;
+            f = (double) tok.val.ld;
         } else {
-            f = (float) tok.val.d;
+            f = tok.val.d;
         }
         
         memcpy (&bits32, &f, sizeof (f));
@@ -22076,16 +22362,16 @@ static int64_s floating_constant_to_bits_now (int size) {
 
 }
 
-static long double floating_constant_to_ld_now (void) {
+static double floating_constant_to_ld_now (void) {
 
-    long double v;
+    double v;
     
     if (tok.kind == TOK_CFLOAT) {
-        v = (long double) tok.val.f;
+        v = (float) tok.val.f;
     } else if (tok.kind == TOK_CLDOUBLE) {
-        v = tok.val.ld;
+        v = (double) tok.val.ld;
     } else {
-        v = (long double) tok.val.d;
+        v = tok.val.d;
     }
     
     get_token ();
@@ -22093,19 +22379,53 @@ static long double floating_constant_to_ld_now (void) {
 
 }
 
-static long double parse_floating_const_expr_value_now (void);
-static long double parse_floating_const_term_now (void);
-static long double parse_floating_const_primary_now (void);
+static double int64_u32_base_now (void) {
 
-static long double parse_floating_const_primary_now (void) {
+    volatile unsigned long half;
+    double d;
+    
+    /*
+     * Build 2^32 without a direct large floating literal.  The volatile word
+     * prevents the self compiler from folding this back into an LC*_flt data
+     * constant while compiling parse.c.
+     */
+    half = 65536UL;
+    
+    d = (double) half;
+    d *= (double) half;
+    
+    return d;
+
+}
+
+static double int64_to_double_now (int64_s v) {
+
+    double d;
+    
+    d = (double) v.high;
+    d *= int64_u32_base_now ();
+    d += (double) v.low;
+    
+    return d;
 
-    long double v;
+}
+
+static double parse_floating_const_expr_value_now (void);
+static double parse_floating_const_term_now (void);
+static double parse_floating_const_primary_now (void);
+
+static double parse_floating_const_primary_now (void) {
+
+    double v;
     int64_s iv;
     
     if (_accept (TOK_LPAREN)) {
+    
         v = parse_floating_const_expr_value_now ();
+        
         expect (TOK_RPAREN, ")");
         return v;
+    
     }
     
     if (_accept (TOK_PLUS)) {
@@ -22121,21 +22441,14 @@ static long double parse_floating_const_primary_now (void) {
     }
     
     iv = const64_from_current_operand ();
-    v = (long double) iv.low;
-    
-    if (iv.high != 0) {
-        v += ((long double) iv.high) * 4294967296.0L;
-    }
-    
-    return v;
+    return int64_to_double_now (iv);
 
 }
 
-static long double parse_floating_const_term_now (void) {
+static double parse_floating_const_term_now (void) {
 
-    long double v;
+    double rhs, v;
     enum token_kind op;
-    long double rhs;
     
     v = parse_floating_const_primary_now ();
     
@@ -22143,6 +22456,7 @@ static long double parse_floating_const_term_now (void) {
     
         op = tok.kind;
         get_token ();
+        
         rhs = parse_floating_const_primary_now ();
         
         if (op == TOK_STAR) {
@@ -22157,11 +22471,10 @@ static long double parse_floating_const_term_now (void) {
 
 }
 
-static long double parse_floating_const_expr_value_now (void) {
+static double parse_floating_const_expr_value_now (void) {
 
-    long double v;
+    double rhs, v;
     enum token_kind op;
-    long double rhs;
     
     v = parse_floating_const_term_now ();
     
@@ -22169,6 +22482,7 @@ static long double parse_floating_const_expr_value_now (void) {
     
         op = tok.kind;
         get_token ();
+        
         rhs = parse_floating_const_term_now ();
         
         if (op == TOK_PLUS) {
@@ -22185,7 +22499,7 @@ static long double parse_floating_const_expr_value_now (void) {
 
 static int64_s parse_floating_const_expr_bits_now (int size) {
 
-    long double acc;
+    double acc;
     int64_s r;
     
     acc = parse_floating_const_expr_value_now ();
@@ -22241,28 +22555,32 @@ static void emit_load_floating_const_bits_now (int size, int64_s v) {
     
     if (state->syntax & ASM_SYNTAX_MASM) {
     
-        fprintf (state->ofp, ".data\n");
+        switch_section (SECTION_DATA);
         
         if (size == (DATA_DOUBLE & 0x1f)) {
         
-            if (v.high & U32_MASK) {
-                fprintf (state->ofp, "LC%d_flt dq %lu%lu\n", lab, v.high & U32_MASK, v.low & U32_MASK);
-            } else {
-                fprintf (state->ofp, "LC%d_flt dd %lu\n", lab, v.low & U32_MASK);
-            }
+            /*
+             * Emit the exact IEEE bits as a 64-bit hex integer.  The old
+             * decimal concatenated the high and low dwords as text, and the
+             * high==0 branch emitted only a single dd even though the later
+             * load is fld qword ptr.  Both forms are unstable across
+             * bootstrap runs.
+             */
+            fprintf (state->ofp, "LC%d_flt dq 0%08lX%08lXh\n", lab, v.high & U32_MASK, v.low & U32_MASK);
         
         } else {
-            fprintf (state->ofp, "LC%d_flt dd %lu\n", lab, v.low & U32_MASK);
+            fprintf (state->ofp, "LC%d_flt dd 0%08lXh\n", lab, v.low & U32_MASK);
         }
         
-        fprintf (state->ofp, ".code\n");
+        switch_section (SECTION_TEXT);
         fprintf (state->ofp, "    fld %s ptr LC%d_flt\n", size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", lab);
     
     } else {
     
         if (state->syntax & ASM_SYNTAX_NASM) {
         
-            fprintf (state->ofp, "section .data\n");
+            switch_section (SECTION_DATA);
+            
             fprintf (state->ofp, "LC%d_flt:\n", lab);
             fprintf (state->ofp, "    dd %lu\n", v.low & U32_MASK);
             
@@ -22270,12 +22588,13 @@ static void emit_load_floating_const_bits_now (int size, int64_s v) {
                 fprintf (state->ofp, "    dd %lu\n", v.high & U32_MASK);
             }
             
-            fprintf (state->ofp, "section .text\n");
+            switch_section (SECTION_TEXT);
             fprintf (state->ofp, "    fld %s [LC%d_flt]\n", size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", lab);
         
         } else {
         
-            fprintf (state->ofp, ".data\n");
+            switch_section (SECTION_DATA);
+            
             fprintf (state->ofp, ".LC%d_flt:\n", lab);
             fprintf (state->ofp, "    .long %lu\n", v.low & U32_MASK);
             
@@ -22283,7 +22602,7 @@ static void emit_load_floating_const_bits_now (int size, int64_s v) {
                 fprintf (state->ofp, "    .long %lu\n", v.high & U32_MASK);
             }
             
-            fprintf (state->ofp, ".text\n");
+            switch_section (SECTION_TEXT);
             
             if (state->syntax & ASM_SYNTAX_INTEL) {
                 fprintf (state->ofp, "    fld %s ptr .LC%d_flt\n", size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", lab);
@@ -22603,6 +22922,7 @@ static void emit_floating_binary_now (enum token_kind k);
 
 static int floating_assignment_operator_supported_now (enum token_kind op);
 static int is_value_compare_operator (enum token_kind k);
+static int emit_statement_rhs_const32_to_edx_if_possible (void);
 
 static void emit_statement_label (int label);
 static void emit_statement_label_raw (int label);
@@ -22758,6 +23078,20 @@ static void emit_fild_eax_now (void) {
 
 }
 
+static void emit_load_any_deref_as_floating_now (const char *reg, int size, int is_floating) {
+
+    if (is_floating) {
+    
+        emit_load_floating_deref_reg_now (reg, size);
+        return;
+    
+    }
+    
+    emit_load_deref_reg_now (reg, size);
+    emit_fild_eax_now ();
+
+}
+
 static void emit_load_floating_rhs_operand_now (int result_size) {
 
     if (tok.kind == TOK_PLUS || tok.kind == TOK_MINUS) {
@@ -22778,6 +23112,8 @@ static void emit_load_floating_rhs_operand_now (int result_size) {
     if (tok.kind == TOK_STAR) {
     
         int deref_size = result_size;
+        int deref_is_floating = 1;
+        
         get_token ();
         
         if (tok.kind == TOK_LPAREN) {
@@ -22786,7 +23122,7 @@ static void emit_load_floating_rhs_operand_now (int result_size) {
             
             if (is_type_start (tok.kind) && parse_deref_cast_type_name (&deref_size)) {
             
-                emit_load_floating_deref_reg_now ("eax", deref_size);
+                emit_load_any_deref_as_floating_now ("eax", deref_size, last_deref_cast_type_is_floating);
                 return;
             
             }
@@ -22794,14 +23130,28 @@ static void emit_load_floating_rhs_operand_now (int result_size) {
             emit_load_assignment_rhs_expression_to_reg ("eax");
             expect (TOK_RPAREN, ")");
             
-            emit_load_floating_deref_reg_now ("eax", deref_size);
+            if (rhs_last_pointer_depth > 0 && rhs_last_pointed_size > 0) {
+            
+                deref_size = rhs_last_pointed_size;
+                deref_is_floating = (deref_size == result_size && (result_size == (DATA_FLOAT & 0x1f) || result_size == (DATA_DOUBLE & 0x1f)));
+            
+            }
+            
+            emit_load_any_deref_as_floating_now ("eax", deref_size, deref_is_floating);
             return;
         
         }
         
         emit_load_assignment_rhs_to_reg ("eax");
-        emit_load_floating_deref_reg_now ("eax", deref_size);
         
+        if (rhs_last_pointer_depth > 0 && rhs_last_pointed_size > 0) {
+        
+            deref_size = rhs_last_pointed_size;
+            deref_is_floating = (deref_size == result_size && (result_size == (DATA_FLOAT & 0x1f) || result_size == (DATA_DOUBLE & 0x1f)));
+        
+        }
+        
+        emit_load_any_deref_as_floating_now ("eax", deref_size, deref_is_floating);
         return;
     
     }
@@ -23970,7 +24320,7 @@ static void emit_call_pointer_in_reg_now (const char *fn_reg, const char *result
             
             if (state->ofp) {
             
-                arg_tmp_ofp = tmpfile ();
+                arg_tmp_ofp = scc_tmpfile ();
                 
                 if (arg_tmp_ofp) {
                 
@@ -24237,9 +24587,12 @@ static void emit_call_identifier_to_reg_now (const char *name, const char *reg,
     int expected_inline_args = 0;
     int inline_arg_bytes = 0;
     int total_arg_bytes = 0;
+    
+    int arg_is_floating, ch, i;
     int arg_bytes;
-    int arg_is_floating;
-    int ch, i;
+    
+    int saved_arg_assignment32_stop_before_condition_operator;
+    int saved_arg_assignment64_stop_before_condition_operator;
     
     struct local_symbol *saved_pending_struct_return_lhs = pending_struct_return_lhs;
     struct local_symbol *call_sym = 0;
@@ -24277,7 +24630,7 @@ static void emit_call_identifier_to_reg_now (const char *name, const char *reg,
         
         if (state->ofp) {
         
-            inline_tmp_ofp = tmpfile ();
+            inline_tmp_ofp = scc_tmpfile ();
             
             if (inline_tmp_ofp) {
             
@@ -24300,6 +24653,12 @@ static void emit_call_identifier_to_reg_now (const char *name, const char *reg,
     
     }
     
+    saved_arg_assignment32_stop_before_condition_operator = assignment32_stop_before_condition_operator;
+    saved_arg_assignment64_stop_before_condition_operator = assignment64_stop_before_condition_operator;
+    
+    assignment32_stop_before_condition_operator = 0;
+    assignment64_stop_before_condition_operator = 0;
+    
     get_token ();
     
     if (tok.kind != TOK_RPAREN) {
@@ -24323,7 +24682,7 @@ static void emit_call_identifier_to_reg_now (const char *name, const char *reg,
              */
             if (!use_inline && state->ofp) {
             
-                arg_tmp_ofp = tmpfile ();
+                arg_tmp_ofp = scc_tmpfile ();
                 
                 if (arg_tmp_ofp) {
                 
@@ -24502,6 +24861,9 @@ static void emit_call_identifier_to_reg_now (const char *name, const char *reg,
     
     expect (TOK_RPAREN, ")");
     
+    assignment32_stop_before_condition_operator = saved_arg_assignment32_stop_before_condition_operator;
+    assignment64_stop_before_condition_operator = saved_arg_assignment64_stop_before_condition_operator;
+    
     if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION && get_global_symbol_has_prototype (name) && ((get_global_symbol_is_variadic (name) && argc < get_global_symbol_param_count (name)) || (!get_global_symbol_is_variadic (name) && argc != get_global_symbol_param_count (name)))) {
         report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "wrong number of arguments to function '%s'", name);
     }
@@ -24951,10 +25313,20 @@ static void emit_goto_trampolines (void) {
         emit_statement_label_raw (goto_refs[i].ref_label);
         delta = goto_labels[label_index].defined_stack_size - goto_refs[i].stack_size;
         
-        if (delta > 0) {
-            emit_stack_adjust (delta, 1);
-        } else if (delta < 0) {
-            emit_stack_adjust (-delta, 0);
+        /*
+         * With a single fixed function frame, block-local symbols still have
+         * different logical stack depths, but ESP no longer changes when
+         * entering/leaving those blocks.  The old trampoline fixup would
+         * therefore corrupt ESP before the real jump target.
+         */
+        if (!current_function_uses_single_frame) {
+        
+            if (delta > 0) {
+                emit_stack_adjust (delta, 1);
+            } else if (delta < 0) {
+                emit_stack_adjust (-delta, 0);
+            }
+        
         }
         
         emit_statement_jump (goto_labels[label_index].label);
@@ -25122,7 +25494,7 @@ static void parse_switch_statement (void) {
     
     if (saved_ofp) {
     
-        body_tmp = tmpfile ();
+        body_tmp = scc_tmpfile ();
         
         if (body_tmp) {
             state->ofp = body_tmp;
@@ -25185,8 +25557,22 @@ static void parse_switch_statement (void) {
 
 static int is_value_compare_operator (enum token_kind k) {
 
-    return  k == TOK_LESS || k == TOK_LTEQ || k == TOK_GREATER ||
-                k == TOK_GTEQ || k == TOK_EQEQ || k == TOK_NOTEQ;
+    switch (k) {
+    
+        case TOK_LESS:
+        case TOK_LTEQ:
+        case TOK_GREATER:
+        case TOK_GTEQ:
+        case TOK_EQEQ:
+        case TOK_NOTEQ:
+        
+            return 1;
+        
+        default:
+        
+            return 0;
+
+    }
 
 }
 
@@ -25496,12 +25882,48 @@ static void emit_load_assignment_binary_expression_to_reg (const char *reg) {
 
 }
 
+static void emit_statement_const32_to_edx (int64_s v);
+
+static int is_assignment32_condition_stop_operator (enum token_kind k) {
+
+    /*
+     * Keep this as a switch rather than a chained || expression.  This guard
+     * protects statement-condition parsing from consuming compare/logical
+     * operators too early; if a self-built stage miscompiles the || chain
+     * here, ordinary conditions can degrade into:
+     *
+     *     mov eax, <rhs-constant>
+     *     test eax, eax
+     */
+    switch (k) {
+    
+        case TOK_LESS:
+        case TOK_LTEQ:
+        case TOK_GREATER:
+        case TOK_GTEQ:
+        case TOK_EQEQ:
+        case TOK_NOTEQ:
+        case TOK_LOGAND:
+        case TOK_LOGOR:
+        
+            return 1;
+        
+        default:
+        
+            return 0;
+
+    }
+
+}
+
 static void emit_load_assignment_compare_expression_to_reg (const char *reg) {
 
+    int64_s rhs_enum_value;
     enum token_kind op;
     
     int lhs_pointer_depth;
     int is_unsigned;
+    int rhs_is_enum;
     
     is_unsigned = rhs_current_operand_is_unsigned_now ();
     
@@ -25511,11 +25933,24 @@ static void emit_load_assignment_compare_expression_to_reg (const char *reg) {
     
     lhs_pointer_depth = rhs_last_pointer_depth;
     
+    if (assignment32_stop_before_condition_operator && is_assignment32_condition_stop_operator (tok.kind)) {
+        return;
+    }
+    
     if (is_value_compare_operator (tok.kind)) {
     
         op = tok.kind;
         get_token ();
         
+        rhs_is_enum = 0;
+
+        if (tok.kind == TOK_IDENT && tok.ident && !find_local_symbol (tok.ident) && find_global_symbol (tok.ident) < 0 && resolve_enum_constant (tok.ident, &rhs_enum_value)) {
+        
+            rhs_is_enum = 1;
+            get_token ();
+        
+        }
+        
         if (strcmp (reg, "eax") != 0 && state->ofp) {
         
             if (state->syntax & ASM_SYNTAX_INTEL) {
@@ -25526,13 +25961,45 @@ static void emit_load_assignment_compare_expression_to_reg (const char *reg) {
         
         }
         
+        /*
+         * Keep identifier-vs-enum comparisons structurally as a real compare.
+         * During bootstrap this path is hit when compiling ordinary tests such
+         * as:
+         *
+         *     unary_op == TOK_MINUS
+         *
+         * If the RHS enum is allowed to go through the generic expression loader,
+         * a later self-built compiler can collapse the expression into just:
+         *
+         *     mov eax, 45
+         *     test eax, eax
+         *
+         * which makes every non-zero enum comparison true.  Loading the enum
+         * directly into EDX avoids clobbering the already-loaded LHS in EAX and
+         * avoids the fragile push/pop/generic-RHS sequence entirely.
+         */
+        if (rhs_is_enum) {
+        
+            emit_statement_const32_to_edx (rhs_enum_value);
+            
+            if (lhs_pointer_depth > 0) {
+                is_unsigned = 1;
+            }
+            
+            emit_compare_eax_edx_to_reg (op, reg, is_unsigned);
+            return;
+        
+        }
+        
         emit_push_reg_now ("eax");
         
         if (rhs_current_operand_is_unsigned_now ()) {
             is_unsigned = 1;
         }
         
-        emit_load_assignment_binary_expression_to_reg ("edx");
+        if (!emit_statement_rhs_const32_to_edx_if_possible ()) {
+            emit_load_assignment_binary_expression_to_reg ("edx");
+        }
         
         if (lhs_pointer_depth > 0 || rhs_last_pointer_depth > 0) {
             is_unsigned = 1;
@@ -25629,8 +26096,6 @@ static void emit_load_assignment_rhs_expression_to_reg (const char *reg) {
     int true_label;
     int end_label;
     
-    enum token_kind logop;
-    
     if (rhs_current_operand_is_floating_now ()) {
     
         emit_load_floating_rhs_expression_now (DATA_DOUBLE & 0x1f);
@@ -25642,17 +26107,20 @@ static void emit_load_assignment_rhs_expression_to_reg (const char *reg) {
     
     emit_load_assignment_compare_expression_to_reg (reg);
     
-    while (tok.kind == TOK_LOGAND || tok.kind == TOK_LOGOR) {
+    for (;;) {
     
-        logop = tok.kind;
-        false_label = anon_label++;
-        true_label = anon_label++;
-        end_label = anon_label++;
-        
-        get_token ();
+        if (assignment32_stop_before_condition_operator && is_assignment32_condition_stop_operator (tok.kind)) {
+            break;
+        }
         
-        if (logop == TOK_LOGAND) {
+        if (tok.kind == TOK_LOGAND) {
         
+            false_label = anon_label++;
+            true_label = anon_label++;
+            end_label = anon_label++;
+            
+            get_token ();
+            
             emit_test_reg_jump_zero_now (reg, false_label);
             emit_load_assignment_compare_expression_to_reg (reg);
             emit_test_reg_jump_zero_now (reg, false_label);
@@ -25661,9 +26129,19 @@ static void emit_load_assignment_rhs_expression_to_reg (const char *reg) {
             emit_statement_label (false_label);
             emit_mov_imm_to_reg_now (reg, 0);
             emit_statement_label (end_label);
+            
+            continue;
         
-        } else {
+        }
         
+        if (tok.kind == TOK_LOGOR) {
+
+            false_label = anon_label++;
+            true_label = anon_label++;
+            end_label = anon_label++;
+            
+            get_token ();
+            
             emit_test_reg_jump_nonzero_now (reg, true_label);
             emit_load_assignment_compare_expression_to_reg (reg);
             emit_test_reg_jump_nonzero_now (reg, true_label);
@@ -25672,9 +26150,13 @@ static void emit_load_assignment_rhs_expression_to_reg (const char *reg) {
             emit_statement_label (true_label);
             emit_mov_imm_to_reg_now (reg, 1);
             emit_statement_label (end_label);
+            
+            continue;
         
         }
-    
+
+        break;
+
     }
     
     if (tok.kind == TOK_QMARK) {
@@ -25728,24 +26210,6 @@ static void emit_load_assignment_rhs_expression_to_reg (const char *reg) {
 
 static void emit_statement_cmp64_to_eax (enum token_kind op, int is_unsigned);
 
-/*
- * Statement conditions need to parse a 64-bit compare as:
- *
- *     <full lhs arithmetic> <compare> <full rhs arithmetic>
- *
- * The generic 64-bit expression loader normally treats compare/logical
- * operators as binary operators that produce a 0/1 pair.  That is fine for
- * expression values, but it is wrong when the condition emitter wants to
- * generate the final branch itself: an expression such as
- *
- *     i < width - len - additionals_len
- *
- * was consumed as ((i < width) - len - additionals_len).  Use this flag only
- * while the condition emitter is loading one side of a comparison so the
- * normal tokenizer is left sitting on the compare/logical operator.
- */
-static int assignment64_stop_before_condition_operator = 0;
-
 static int is_assignment64_condition_stop_operator (enum token_kind k) {
 
     return  k == TOK_LESS || k == TOK_LTEQ || k == TOK_GREATER ||
@@ -28572,6 +29036,7 @@ static int parse_identifier_assignment_statement (void) {
     enum token_kind op;
     struct local_symbol *lhs;
     
+    int is_simple_assign;
     int lhs_size;
     int lhs_is_floating;
     
@@ -28751,6 +29216,8 @@ static int parse_identifier_assignment_statement (void) {
         }
         
         op = tok.kind;
+        
+        is_simple_assign = (tok.kind == TOK_ASSIGN);
         get_token ();
         
         if (!lhs && global_index < 0) {
@@ -28797,7 +29264,7 @@ static int parse_identifier_assignment_statement (void) {
             
             }
             
-            if (op == TOK_ASSIGN) {
+            if (is_simple_assign) {
             
                 emit_push_reg_now ("edx");
                 
@@ -28851,7 +29318,7 @@ static int parse_identifier_assignment_statement (void) {
             
             }
             
-            if ((member_is_floating || token_is_floating_constant_now ()) && op == TOK_ASSIGN) {
+            if ((member_is_floating || token_is_floating_constant_now ()) && is_simple_assign) {
                 emit_store_floating_member_to_addr_reg_now ("edx", member_offset, member_size);
             } else {
                 emit_store_member_to_addr_reg_now ("edx", member_offset, "eax", member_size);
@@ -28945,6 +29412,8 @@ static int parse_identifier_assignment_statement (void) {
         if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
         
             op = tok.kind;
+            
+            is_simple_assign = (tok.kind == TOK_ASSIGN);
             get_token ();
             
             if (state->ofp) {
@@ -28982,11 +29451,13 @@ static int parse_identifier_assignment_statement (void) {
         }
         
         op = tok.kind;
+        
+        is_simple_assign = (tok.kind == TOK_ASSIGN);
         get_token ();
         
         if (state->ofp) {
         
-            if (op == TOK_ASSIGN) {
+            if (is_simple_assign) {
             
                 emit_push_reg_now ("edx");
                 emit_load_assignment_rhs_expression_to_reg ("eax");
@@ -29022,6 +29493,8 @@ static int parse_identifier_assignment_statement (void) {
         if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
         
             op = tok.kind;
+            
+            is_simple_assign = (tok.kind == TOK_ASSIGN);
             get_token ();
             
             lhs = find_local_symbol (name);
@@ -29065,11 +29538,13 @@ static int parse_identifier_assignment_statement (void) {
                 if (is_assignment_operator (tok.kind)) {
                 
                     op = tok.kind;
+                    
+                    is_simple_assign = (tok.kind == TOK_ASSIGN);
                     get_token ();
                     
                     if (state->ofp) {
                     
-                        if (op == TOK_ASSIGN) {
+                        if (is_simple_assign) {
                         
                             emit_push_reg_now ("edx");
                             emit_load_assignment_rhs_expression_to_reg ("eax");
@@ -29158,6 +29633,8 @@ static int parse_identifier_assignment_statement (void) {
                 if (is_assignment_operator (tok.kind)) {
                 
                     op = tok.kind;
+                    
+                    is_simple_assign = (tok.kind == TOK_ASSIGN);
                     get_token ();
                     
                     if (state->ofp) {
@@ -29168,7 +29645,7 @@ static int parse_identifier_assignment_statement (void) {
                             fprintf (state->ofp, "    movl %%eax, %%edx\n");
                         }
                         
-                        if (op == TOK_ASSIGN) {
+                        if (is_simple_assign) {
                         
                             emit_push_reg_now ("edx");
                             emit_load_assignment_rhs_expression_to_reg ("eax");
@@ -29229,7 +29706,7 @@ static int parse_identifier_assignment_statement (void) {
                             
                             if (state->ofp) {
                             
-                                arg_tmp_ofp = tmpfile ();
+                                arg_tmp_ofp = scc_tmpfile ();
                                 
                                 if (arg_tmp_ofp) {
                                     arg_saved_ofp = state->ofp;
@@ -29368,6 +29845,8 @@ static int parse_identifier_assignment_statement (void) {
     }
     
     op = tok.kind;
+    
+    is_simple_assign = (tok.kind == TOK_ASSIGN);
     get_token ();
     
     lhs = find_local_symbol (name);
@@ -29390,7 +29869,7 @@ static int parse_identifier_assignment_statement (void) {
         lhs_size = lhs ? lhs->size : get_global_symbol_size (name);
         lhs_is_floating = lhs ? lhs->is_floating : get_global_symbol_floating (name);
         
-        if (op == TOK_ASSIGN && lhs_size > (DATA_LLONG & 0x1f) && tok.kind == TOK_IDENT) {
+        if (is_simple_assign && lhs_size > (DATA_LLONG & 0x1f) && tok.kind == TOK_IDENT) {
             
             char *rhs_name = xstrdup (tok.ident);
             
@@ -29445,7 +29924,7 @@ static int parse_identifier_assignment_statement (void) {
             
             } else {
             
-                if (op == TOK_ASSIGN) {
+                if (is_simple_assign) {
                     emit_load_floating_rhs_expression_now (lhs_size);
                 } else {
                 
@@ -29461,7 +29940,7 @@ static int parse_identifier_assignment_statement (void) {
         
         } else if (lhs_size == (DATA_LLONG & 0x1f)) {
         
-            if (op == TOK_ASSIGN) {
+            if (is_simple_assign) {
                 emit_load_assignment_rhs_expression_to_pair ("eax", "edx", lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
             } else {
             
@@ -29520,7 +29999,7 @@ static int parse_identifier_assignment_statement (void) {
         
         } else {
         
-            if (op == TOK_ASSIGN) {
+            if (is_simple_assign) {
                 emit_load_assignment_rhs_expression_to_reg ("eax");
             } else {
             
@@ -29655,11 +30134,11 @@ static void emit_statement_jump (int label) {
 }
 
 static int token_is_integer_constant_now (enum token_kind k) {
-    return k == TOK_CINT || k == TOK_CLONG || k == TOK_CLLONG || k == (enum token_kind) (TOK_CINT + 1) || k == (enum token_kind) (TOK_CLONG + 1) || k == (enum token_kind) (TOK_CLLONG + 1);
+    return k == TOK_CCHAR || k == TOK_LCHAR || k == TOK_CINT || k == TOK_CUINT || k == TOK_CLONG || k == TOK_CULONG || k == TOK_CLLONG || k == TOK_CULLONG;
 }
 
 static int token_is_integer_unsigned_constant_now (enum token_kind k) {
-    return k == (enum token_kind) (TOK_CINT + 1) || k == (enum token_kind) (TOK_CLONG + 1) || k == (enum token_kind) (TOK_CLLONG + 1);
+    return k == TOK_CUINT || k == TOK_CULONG || k == TOK_CULLONG;
 }
 
 #define     MAX_INLINE_ASM_INPUTS        16
@@ -30372,6 +30851,52 @@ static int token_is_const_floating_condition_operand_now (void) {
     return token_is_floating_constant_now ();
 }
 
+static void emit_statement_const32_to_edx (int64_s v) {
+
+    flush_pending_statement_labels ();
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+       fprintf (state->ofp, "    mov edx, %lu\n", v.low & U32_MASK);
+    } else {
+        fprintf (state->ofp, "    movl $%lu, %%edx\n", v.low & U32_MASK);
+    }
+
+}
+
+static int emit_statement_rhs_const32_to_edx_if_possible (void) {
+
+    int64_s v;
+    
+    if (token_is_const_condition_operand_now ()) {
+    
+        if (current_integer_expr_is_foldable_now ()) {
+            v = const64_from_current_foldable_expr ();
+        } else {
+            v = const64_from_current_operand ();
+        }
+        
+        emit_statement_const32_to_edx (v);
+        return 1;
+    
+    }
+    
+    if (tok.kind == TOK_IDENT && tok.ident && !find_local_symbol (tok.ident) && find_global_symbol (tok.ident) < 0 && resolve_enum_constant (tok.ident, &v)) {
+        
+        get_token ();
+        
+        emit_statement_const32_to_edx (v);
+        return 1;
+    
+    }
+    
+    return 0;
+
+}
+
 static int ident_char_now (int ch) {
     return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '_';
 }
@@ -30586,7 +31111,7 @@ static int rhs_current_operand_is_floating_now (void) {
 
 }
 
-static int64_s floating_ld_to_bits_now (int size, long double value) {
+static int64_s floating_ld_to_bits_now (int size, double value) {
 
     int64_s r;
     
@@ -30632,7 +31157,7 @@ static int64_s floating_ld_to_bits_now (int size, long double value) {
 
 }
 
-static void emit_load_floating_ld_now (int size, long double value) {
+static void emit_load_floating_ld_now (int size, double value) {
     emit_load_floating_const_bits_now (size, floating_ld_to_bits_now (size, value));
 }
 
@@ -30752,46 +31277,316 @@ static int rhs_current_operand_is_unsigned_now (void) {
 }
 
 static int token_is_statement_compare_operator (enum token_kind k) {
-    return k == TOK_LESS || k == TOK_LTEQ || k == TOK_GREATER || k == TOK_GTEQ || k == TOK_EQEQ || k == TOK_NOTEQ;
+
+    switch (k) {
+    
+        case TOK_LESS:
+        case TOK_LTEQ:
+        case TOK_GREATER:
+        case TOK_GTEQ:
+        case TOK_EQEQ:
+        case TOK_NOTEQ:
+        
+            return 1;
+        
+        default:
+        
+            return 0;
+
+    }
+
 }
 
 static void emit_statement_cmp_eax_edx_jump_if_false (enum token_kind op, int is_unsigned, int label);
 static int statement_condition_emit_logical_tail (int label);
 
-static int source_condition_ident_enum_compare_now (const char *p) {
+static void emit_statement_jump_if_false (int label);
+static int emit_statement_cmp_eax_edx_jump_if_false_and_tail (enum token_kind op, int is_unsigned, int label);
+
+static int source_condition_tail_end_now (const char *p) {
+
+    if (!p) {
+        return 0;
+    }
+
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+
+    switch (*p) {
+
+        case '\0':
+        case ')':
+        case ';':
+        case '{':
+
+            return 1;
+
+        default:
+
+            break;
+
+    }
+
+    return 0;
+
+}
+
+static int source_condition_skip_rhs_const_or_enum_now (const char **pp) {
 
     char word[128];
-    int name_len, i;
+    
+    const char *p;
+    int i;
     
     int64_s ignored;
     
-    if (tok.kind != TOK_IDENT || !tok.ident || !p) {
+    if (!pp || !*pp) {
         return 0;
     }
     
-    /*
-     * Some callers have tok.caret positioned after the identifier, while
-     * others have only tok.start available.  Accept either form here.
-     * Without this, a simple condition such as
-     *
-     *     if (op == TOK_STAR)
-     *
-     * can miss this fast path and fall through to the constant-expression
-     * folder, which then tries to evaluate the local variable `op' as an
-     * integer constant expression.
-     */
-    name_len = (int) strlen (tok.ident);
+    p = *pp;
     
-    if (strncmp (p, tok.ident, (unsigned long) name_len) == 0 && !ident_char_now ((unsigned char) p[name_len])) {
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
     
-        p += name_len;
+    if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_') {
+    
+        i = 0;
+        
+        while (((p[i] >= 'A' && p[i] <= 'Z') || (p[i] >= 'a' && p[i] <= 'z') ||
+                (p[i] >= '0' && p[i] <= '9') || p[i] == '_') &&
+               i + 1 < (int) sizeof (word)) {
+            i++;
+        }
+        
+        memcpy (word, p, (unsigned long) i);
+        word[i] = 0;
+        
+        if (!resolve_enum_constant (word, &ignored)) {
+            return 0;
+        }
+        
+        p += i;
+        
+        *pp = p;
+        return 1;
+    
+    }
+    
+    if (*p == '\'') {
+    
+        p++;
+        
+        while (*p && *p != '\'') {
+        
+            if (*p == '\\' && p[1]) {
+                p += 2;
+            } else {
+                p++;
+            }
+        
+        }
+        
+        if (*p != '\'') {
+            return 0;
+        }
+        
+        p++;
+        
+        *pp = p;
+        return 1;
+    
+    }
+    
+    if (*p == '-' || *p == '+') {
+        p++;
+    }
+    
+    if (*p < '0' || *p > '9') {
+        return 0;
+    }
+    
+    while ((*p >= '0' && *p <= '9') ||
+           (*p >= 'A' && *p <= 'F') ||
+           (*p >= 'a' && *p <= 'f') ||
+           *p == 'x' || *p == 'X' ||
+           *p == 'u' || *p == 'U' ||
+           *p == 'l' || *p == 'L') {
+        p++;
+    }
+    
+    *pp = p;
+    return 1;
+
+}
+
+static int emit_statement_rhs_const32_or_enum_to_edx_if_possible (void) {
+
+    int64_s v;
+    
+    if (tok.kind == TOK_IDENT && tok.ident && resolve_enum_constant (tok.ident, &v)) {
+    
+        get_token ();
+        
+        emit_statement_const32_to_edx (v);
+        return 1;
+    
+    }
+    
+    if (token_is_const_condition_operand_now ()) {
+    
+        if (current_integer_expr_is_foldable_now ()) {
+            v = const64_from_current_foldable_expr ();
+        } else {
+            v = const64_from_current_operand ();
+        }
+        
+        emit_statement_const32_to_edx (v);
+        return 1;
+    
+    }
+    
+    return 0;
+
+}
+
+static int source_condition_logical_rhs_is_enum_compare_now (const char *p) {
+
+    if (!p) {
+        return 0;
+    }
+    
+    if ((p[0] == '&' && p[1] == '&') || (p[0] == '|' && p[1] == '|')) {
+        p += 2;
+    } else {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+        p++;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p == '(') {
+        return 0;
+    }
+    
+    for (;;) {
+    
+        if (*p == '.') {
+            p++;
+        } else if (p[0] == '-' && p[1] == '>') {
+            p += 2;
+        } else {
+            break;
+        }
         
         while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
             p++;
         }
+        
+        if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+            return 0;
+        }
+        
+        while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+            p++;
+        }
+        
+        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+            p++;
+        }
+    
+    }
+    
+    if ((p[0] == '=' && p[1] == '=') || (p[0] == '!' && p[1] == '=') ||
+        (p[0] == '<' && p[1] == '=') || (p[0] == '>' && p[1] == '=')) {
+        p += 2;
+    } else if (*p == '<' || *p == '>') {
+        p++;
+    } else {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!source_condition_skip_rhs_const_or_enum_now (&p)) {
+        return 0;
+    }
+    
+    return 1;
+
+}
+
+static const char *source_find_current_ident_on_line (const char *p) {
+
+    int name_len;
+    
+    if (tok.kind != TOK_IDENT || !tok.ident || !p) {
+        return 0;
+    }
+    
+    name_len = (int) strlen (tok.ident);
+    
+    while (*p && *p != '\n') {
+    
+        if ((p == tok.start || !ident_char_now ((unsigned char) p[-1])) &&
+            strncmp (p, tok.ident, (unsigned long) name_len) == 0 &&
+            !ident_char_now ((unsigned char) p[name_len])) {
+            return p + name_len;
+        }
+        
+        p++;
     
     }
     
+    return 0;
+
+}
+
+static int source_condition_ident_enum_compare_now (const char *p) {
+
+    if (tok.kind != TOK_IDENT || !tok.ident || !p) {
+        return 0;
+    }
+    
+    /*
+     * tok.start is usually the beginning of the source line, not the current
+     * identifier.  When compiling the compiler itself this made simple enum
+     * tests such as:
+     *
+     *     if (assign_op == TOK_ASSIGN)
+     *
+     * miss the fixed compare-emission path and fall into the generic
+     * expression folder, where later bootstrap stages reduced the condition
+     * to "mov eax, TOK_ASSIGN; test eax, eax".  Locate the current token on
+     * the line first, then inspect the text that follows it.
+     */
+    p = source_find_current_ident_on_line (p);
+    
+    if (!p) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
     if (*p == '(' || *p == '.' || (p[0] == '-' && p[1] == '>')) {
         return 0;
     }
@@ -30809,30 +31604,250 @@ static int source_condition_ident_enum_compare_now (const char *p) {
         p++;
     }
     
-    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+    if (!source_condition_skip_rhs_const_or_enum_now (&p)) {
         return 0;
     }
     
-    i = 0;
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
     
-    while (((p[i] >= 'A' && p[i] <= 'Z') || (p[i] >= 'a' && p[i] <= 'z') || (p[i] >= '0' && p[i] <= '9') || p[i] == '_') && i + 1 < (int) sizeof (word)) {
-        i++;
+    /*
+     * This fast path emits a branch-form compare, which is exactly what is
+     * needed for logical tails.  Do not send enum-token compares through the
+     * generic expression path: later self-built stages have repeatedly reduced
+     * them to "mov eax, <enum>; test eax,eax".
+     */
+    if ((*p == '&' && p[1] == '&') || (*p == '|' && p[1] == '|')) {
+        return source_condition_logical_rhs_is_enum_compare_now (p);
+    }
+    
+    return source_condition_tail_end_now (p);
+
+}
+
+static int source_condition_ident_immediate_compare_now (const char *p) {
+
+    int name_len;
+    
+    if (tok.kind != TOK_IDENT || !tok.ident || !p) {
+        return 0;
     }
     
-    memcpy (word, p, (unsigned long) i);
-    word[i] = 0;
+    name_len = (int) strlen (tok.ident);
+    p = source_find_current_ident_on_line (p);
     
-    p += i;
+    if (!p) {
+        return 0;
+    }
     
     while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
         p++;
     }
     
-    if (*p != ')') {
+    /*
+     * Only catch immediate primary/member comparisons here.  Do not claim
+     * calls, subscripts, or arithmetic expressions; those still need the
+     * ordinary expression parser.
+     */
+    if (*p == '(' || *p == '[') {
+        return 0;
+    }
+    
+    for (;;) {
+    
+        if (*p == '.') {
+            p++;
+        } else if (p[0] == '-' && p[1] == '>') {
+            p += 2;
+        } else {
+            break;
+        }
+        
+        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+            p++;
+        }
+        
+        if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+            return 0;
+        }
+        
+        while ((*p >= 'A' && *p <= 'Z') ||
+               (*p >= 'a' && *p <= 'z') ||
+               (*p >= '0' && *p <= '9') ||
+               *p == '_') {
+            p++;
+        }
+        
+        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+            p++;
+        }
+    
+    }
+    
+    if ((p[0] == '=' && p[1] == '=') ||
+        (p[0] == '!' && p[1] == '=') ||
+        (p[0] == '<' && p[1] == '=') ||
+        (p[0] == '>' && p[1] == '=')) {
+        p += 2;
+    } else if ((p[0] == '<' && p[1] != '<') ||
+               (p[0] == '>' && p[1] != '>')) {
+        p++;
+    } else {
+    
+        (void) name_len;
+        return 0;
+    
+    }
+    
+    /*
+     * This shortcut emits one cmp/jcc and returns to the statement parser.
+     * It must only claim a whole simple condition.  If the comparison is
+     * followed by a top-level logical operator, for example:
+     *
+     *     m->nargs >= 0 || m->is_variadic
+     *     ch >= 'a' && ch <= 'f'
+     *
+     * then claiming only the first comparison leaves the ||/&& tail to a
+     * parser path that expects an integer constant expression.  Let the
+     * ordinary expression parser own those full logical conditions instead.
+     */
+    {
+    
+        int paren_depth = 0;
+        int bracket_depth = 0;
+        
+        while (*p) {
+        
+            if (*p == '\'' || *p == '"') {
+            
+                int quote = *p++;
+                
+                while (*p) {
+                
+                    if (*p == '\\' && p[1]) {
+                    
+                        p += 2;
+                        continue;
+                    
+                    }
+                    
+                    if (*p == quote) {
+                    
+                        p++;
+                        break;
+                    
+                    }
+                    
+                    p++;
+                
+                }
+                
+                continue;
+            
+            }
+            
+            if (*p == '(') {
+            
+                paren_depth++;
+                p++;
+                
+                continue;
+            
+            }
+            
+            if (*p == ')') {
+            
+                if (paren_depth == 0) {
+                    break;
+                }
+                
+                paren_depth--;
+                p++;
+                
+                continue;
+            
+            }
+            
+            if (*p == '[') {
+            
+                bracket_depth++;
+                p++;
+                
+                continue;
+            
+            }
+            
+            if (*p == ']') {
+            
+                if (bracket_depth > 0) {
+                    bracket_depth--;
+                }
+                
+                p++;
+                continue;
+            
+            }
+            
+            if (paren_depth == 0 && bracket_depth == 0 &&
+                ((p[0] == '&' && p[1] == '&') ||
+                 (p[0] == '|' && p[1] == '|'))) {
+                return 0;
+            }
+            
+            p++;
+        
+        }
+    
+    }
+    
+    (void) name_len;
+    return 1;
+
+}
+
+static int emit_statement_ident_immediate_compare_jump_if_false_now (int label) {
+
+    enum token_kind op;
+    int is_unsigned;
+    
+    if (!source_condition_ident_immediate_compare_now (tok.caret) &&
+        !source_condition_ident_immediate_compare_now (tok.start)) {
         return 0;
     }
     
-    return resolve_enum_constant (word, &ignored);
+    is_unsigned = rhs_current_operand_is_unsigned_now ();
+    emit_load_assignment_rhs_to_reg ("eax");
+    
+    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+        emit_apply_postfix_member_access_to_reg_now ("eax");
+    }
+    
+    if (postfix_member_seen && postfix_member_is_unsigned) {
+        is_unsigned = 1;
+    }
+    
+    if (!token_is_statement_compare_operator (tok.kind)) {
+        return 0;
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    if (rhs_current_operand_is_unsigned_now ()) {
+        is_unsigned = 1;
+    }
+    
+    if (!emit_statement_rhs_const32_to_edx_if_possible ()) {
+    
+        emit_push_reg_now ("eax");
+        emit_load_assignment_compare_expression_to_reg ("edx");
+        emit_pop_reg_now ("eax");
+    
+    }
+    
+    emit_statement_cmp_eax_edx_jump_if_false_and_tail (op, is_unsigned, label);
+    return 1;
 
 }
 
@@ -30841,8 +31856,6 @@ static int emit_statement_ident_enum_compare_jump_if_false_now (int label) {
     enum token_kind op;
     int is_unsigned;
     
-    int64_s rhs;
-    
     if (!source_condition_ident_enum_compare_now (tok.caret) && !source_condition_ident_enum_compare_now (tok.start)) {
         return 0;
     }
@@ -30857,16 +31870,164 @@ static int emit_statement_ident_enum_compare_jump_if_false_now (int label) {
     op = tok.kind;
     get_token ();
     
-    if (tok.kind != TOK_IDENT || !resolve_enum_constant (tok.ident, &rhs)) {
+    /*
+     * This path is specifically an EAX-vs-constant statement comparison.
+     * Do not route the RHS through the generic "load constant to named
+     * register" helper here.  During bootstrap the named-register helper path
+     * is fragile: if the next-stage compiler mis-parses the string argument or
+     * folds the call badly, enum compares such as:
+     *
+     *     if (unary_op == TOK_MINUS)
+     *
+     * can degrade into:
+     *
+     *     mov eax, TOK_MINUS
+     *     test eax, eax
+     *
+     * which makes every non-zero enum condition true.  Emit the RHS into EDX
+     * directly so the following cmp/jcc sequence is structurally fixed.
+     */
+    if (!emit_statement_rhs_const32_or_enum_to_edx_if_possible ()) {
         return 0;
     }
     
+    emit_statement_cmp_eax_edx_jump_if_false_and_tail (op, is_unsigned, label);
+    return 1;
+
+}
+
+static int source_condition_member_enum_compare_now (const char *p) {
+
+    char word[128];
+    int i;
+    
+    if (tok.kind != TOK_IDENT || !tok.ident || !p) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (strncmp (p, tok.ident, (unsigned long) strlen (tok.ident)) == 0 && !ident_char_now ((unsigned char) p[strlen (tok.ident)])) {
+        p += strlen (tok.ident);
+    } else if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_') {
+    
+        while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+            p++;
+        }
+    
+    } else if (!(*p == '.' || (p[0] == '-' && p[1] == '>'))) {
+        return 0;
+    }
+    
+    for (;;) {
+    
+        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+            p++;
+        }
+        
+        if (*p == '.') {
+            p++;
+        } else if (p[0] == '-' && p[1] == '>') {
+            p += 2;
+        } else {
+            return 0;
+        }
+        
+        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+            p++;
+        }
+        
+        if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+            return 0;
+        }
+        
+        while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+            p++;
+        }
+        
+        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+            p++;
+        }
+        
+        if (!(*p == '.' || (p[0] == '-' && p[1] == '>'))) {
+            break;
+        }
+    
+    }
+    
+    if ((p[0] == '=' && p[1] == '=') || (p[0] == '!' && p[1] == '=') ||
+        (p[0] == '<' && p[1] == '=') || (p[0] == '>' && p[1] == '=')) {
+        p += 2;
+    } else if (*p == '<' || *p == '>') {
+        p++;
+    } else {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!source_condition_skip_rhs_const_or_enum_now (&p)) {
+        return 0;
+    }
+    
+    i = 0;
+    
+    while (((p[i] >= 'A' && p[i] <= 'Z') || (p[i] >= 'a' && p[i] <= 'z') || (p[i] >= '0' && p[i] <= '9') || p[i] == '_') && i + 1 < (int) sizeof (word)) {
+        i++;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if ((*p == '&' && p[1] == '&') || (*p == '|' && p[1] == '|')) {
+        return source_condition_logical_rhs_is_enum_compare_now (p);
+    }
+    
+    return source_condition_tail_end_now (p);
+
+}
+
+static int emit_statement_member_enum_compare_jump_if_false_now (int label) {
+
+    enum token_kind op;
+    int is_unsigned;
+    
+    if (!source_condition_member_enum_compare_now (tok.caret) && !source_condition_member_enum_compare_now (tok.start)) {
+        return 0;
+    }
+    
+    is_unsigned = rhs_current_operand_is_unsigned_now ();
+    emit_load_assignment_rhs_to_reg ("eax");
+    
+    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+        emit_apply_postfix_member_access_to_reg_now ("eax");
+    }
+    
+    if (postfix_member_seen && postfix_member_is_unsigned) {
+        is_unsigned = 1;
+    }
+    
+    if (!token_is_statement_compare_operator (tok.kind)) {
+        return 0;
+    }
+    
+    op = tok.kind;
     get_token ();
     
-    emit_load_const32_to_reg_now ("edx", rhs);
-    emit_statement_cmp_eax_edx_jump_if_false (op, is_unsigned, label);
+    if (rhs_current_operand_is_unsigned_now ()) {
+        is_unsigned = 1;
+    }
     
-    statement_condition_emit_logical_tail (label);
+    if (!emit_statement_rhs_const32_or_enum_to_edx_if_possible ()) {
+        return 0;
+    }
+    
+    emit_statement_cmp_eax_edx_jump_if_false_and_tail (op, is_unsigned, label);
     return 1;
 
 }
@@ -31302,7 +32463,7 @@ static void emit_statement_floating_compare_jump_if_false (enum token_kind op, i
 
 }
 
-static int statement_compare_floating_const_true (long double left, enum token_kind op, long double right) {
+static int statement_compare_floating_const_true (double left, enum token_kind op, double right) {
 
     switch (op) {
     
@@ -31332,7 +32493,7 @@ static int statement_compare_floating_const_true (long double left, enum token_k
         
         default:
         
-            return left != 0.0L;
+            return left != 0.0;
     
     }
 
@@ -31745,7 +32906,7 @@ static void parse_for_statement (void) {
     } else {
     
         if (state->ofp) {
-            step_tmp = tmpfile ();
+            step_tmp = scc_tmpfile ();
         }
         
         if (step_tmp) {
@@ -31928,59 +33089,40 @@ static void parse_do_statement (void) {
 
 }
 
-static int source_parenthesized_condition_has_logical_now (void) {
+static int statement_condition_emit_logical_tail (int label) {
 
-    const char *p = tok.caret;
-    int depth = 0;
+    int skip_label;
+    
+    if (tok.kind == TOK_LOGAND) {
+    
+        get_token ();
+        
+        emit_statement_jump_if_false (label);
+        return 1;
     
-    if (!p || *p != '(') {
-        return 0;
     }
     
-    for (; *p; p++) {
+    if (tok.kind == TOK_LOGOR) {
     
-        if (*p == '(') {
-        
-            depth++;
-            continue;
-        
-        }
+        skip_label = anon_label++;
+        get_token ();
         
-        if (*p == ')') {
+        if (state->ofp) {
         
-            depth--;
-            
-            if (depth == 0) {
-                return 0;
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    test eax, eax\n");
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), skip_label);
+            } else {
+                fprintf (state->ofp, "    testl %%eax, %%eax\n");
+                fprintf (state->ofp, "    jnz .L%d\n", skip_label);
             }
-            
-            continue;
         
         }
         
-        if (depth == 1 && ((*p == '&' && p[1] == '&') || (*p == '|' && p[1] == '|'))) {
-            return 1;
-        }
-        
-        if (*p == '"' || *p == '\'') {
-        
-            int quote = *p++;
-            
-            while (*p && *p != quote) {
-            
-                if (*p == '\\' && p[1]) {
-                    p++;
-                }
-                
-                p++;
-            
-            }
-            
-            if (!*p) {
-                return 0;
-            }
+        emit_statement_jump_if_false (label);
+        emit_statement_label (skip_label);
         
-        }
+        return 1;
     
     }
     
@@ -31988,44 +33130,72 @@ static int source_parenthesized_condition_has_logical_now (void) {
 
 }
 
-static int statement_condition_emit_logical_tail (int label) {
+static void emit_statement_eax_truth_jump_if_false_and_tail (int label) {
+
+    int skip_label;
+
+    if (tok.kind == TOK_LOGAND) {
+
+        emit_statement_test_eax_jump_if_false (label);
+        
+        get_token ();
+        emit_statement_jump_if_false (label);
+        
+        return;
+
+    }
 
+    if (tok.kind == TOK_LOGOR) {
+
+        skip_label = anon_label++;
+        emit_test_reg_jump_nonzero_now ("eax", skip_label);
+        get_token ();
+        emit_statement_jump_if_false (label);
+        emit_statement_label (skip_label);
+        return;
+
+    }
+
+    emit_statement_test_eax_jump_if_false (label);
+
+}
+
+static int emit_statement_cmp_eax_edx_jump_if_false_and_tail (enum token_kind op, int is_unsigned, int label) {
+
+    int rhs_label;
     int skip_label;
     
     if (tok.kind == TOK_LOGAND) {
     
         get_token ();
         
+        emit_statement_cmp_eax_edx_jump_if_false (op, is_unsigned, label);
         emit_statement_jump_if_false (label);
+        
         return 1;
     
     }
     
     if (tok.kind == TOK_LOGOR) {
     
+        rhs_label = anon_label++;
         skip_label = anon_label++;
-        get_token ();
-        
-        if (state->ofp) {
         
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                fprintf (state->ofp, "    test eax, eax\n");
-                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), skip_label);
-            } else {
-                fprintf (state->ofp, "    testl %%eax, %%eax\n");
-                fprintf (state->ofp, "    jnz .L%d\n", skip_label);
-            }
+        get_token ();
         
-        }
+        emit_statement_cmp_eax_edx_jump_if_false (op, is_unsigned, rhs_label);
+        emit_statement_jump (skip_label);
         
+        emit_statement_label (rhs_label);
         emit_statement_jump_if_false (label);
-        emit_statement_label (skip_label);
         
+        emit_statement_label (skip_label);
         return 1;
     
     }
     
-    return 0;
+    emit_statement_cmp_eax_edx_jump_if_false (op, is_unsigned, label);
+    return 1;
 
 }
 
@@ -32082,18 +33252,35 @@ static int source_starts_with_parenthesized_assignment_at (const char *p) {
         return 0;
     }
     
-    while (*p == '(') {
+    /*
+     * Only claim a single parenthesized assignment here.  Do not treat
+     * a parenthesized logical group whose first term is an assignment as
+     * one big assignment expression.  For example:
+     *
+     *     ((op2 = get_op (pp)) || (brackets && **pp == ')'))
+     *
+     * The old scanner consumed both leading '(' characters, parsed only
+     * the first assignment, and then tried to manage the outer group's
+     * closing ')' with parenthesized_assignment_open_parens.  That left
+     * the statement-condition parser out of sync at the final ')' before
+     * the following '{'.
+     *
+     * A real parenthesized-assignment fast path starts with exactly one
+     * '(' at the current token.  Nested/grouped logical expressions must
+     * be left to the normal expression parser.
+     */
+    parens = 1;
+    p++;
     
-        parens++;
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
         p++;
-        
-        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-            p++;
-        }
+    }
     
+    if (*p == '(') {
+        return 0;
     }
     
-    if (parens <= 0 || !((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
         return 0;
     }
     
@@ -32575,72 +33762,359 @@ static int emit_load_parenthesized_assignment_expression_to_reg_now (const char
 
 }
 
-static void emit_statement_jump_if_false (int label) {
+static int source_condition_has_top_level_compare_now (const char *p) {
 
-    enum token_kind op;
-    int is_unsigned;
-    
-    flush_pending_statement_labels ();
+    int paren_depth = 0;
+    int bracket_depth = 0;
+    int saw_operand = 0;
     
-    statement_condition_constant_known = 0;
-    statement_condition_constant_value = 0;
+    if (!p) {
+        return 0;
+    }
     
-    if (emit_statement_ident_enum_compare_jump_if_false_now (label)) {
-        return;
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
     }
     
-    if (tok.kind == TOK_LPAREN && source_parenthesized_condition_has_logical_now ()) {
+    while (*p) {
     
-        /*
-         * Parse the whole parenthesized logical expression as an expression.
-         * The older recursive condition parser stopped after the first operand
-         * of nested logical groups such as:
-         *
-         *     a && (b || c || d)
-         *
-         * and then the outer caller immediately expected the closing ')',
-         * leaving the inner '||' tokens unconsumed and reporting a false
-         * "expected )" at the first member expression.
-         */
-        get_token ();
+        if (*p == '\'' || *p == '"') {
         
-        emit_load_assignment_rhs_expression_to_reg ("eax");
-        expect (TOK_RPAREN, ")");
+            int quote = *p++;
+            
+            while (*p) {
+            
+                if (*p == '\\' && p[1]) {
+                
+                    p += 2;
+                    continue;
+                
+                }
+                
+                if (*p == quote) {
+                
+                    p++;
+                    break;
+                
+                }
+                
+                p++;
+            
+            }
+            
+            saw_operand = 1;
+            continue;
         
-        if (tok.kind == TOK_LOGOR) {
+        }
+        
+        if (*p == '(') {
         
-            int skip_label = anon_label++;
+            paren_depth++;
             
-            if (state->ofp) {
+            saw_operand = 1;
+            p++;
             
-                if (state->syntax & ASM_SYNTAX_INTEL) {
+            continue;
+        
+        }
+        
+        if (*p == ')') {
+        
+            if (paren_depth == 0) {
+                return 0;
+            }
+            
+            paren_depth--;
+            saw_operand = 1;
+            
+            p++;
+            continue;
+        
+        }
+        
+        if (*p == '[') {
+        
+            bracket_depth++;
+            
+            saw_operand = 1;
+            p++;
+            
+            continue;
+        
+        }
+        
+        if (*p == ']') {
+        
+            if (bracket_depth > 0) {
+                bracket_depth--;
+            }
+            
+            saw_operand = 1;
+            p++;
+            
+            continue;
+        
+        }
+        
+        if (paren_depth == 0 && bracket_depth == 0) {
+        
+            if ((p[0] == '&' && p[1] == '&') || (p[0] == '|' && p[1] == '|') ||
+                *p == '?' || *p == ':' || *p == ',' || *p == ';') {
+                return 0;
+            }
+            
+            if (saw_operand) {
+            
+                if ((p[0] == '=' && p[1] == '=') ||
+                    (p[0] == '!' && p[1] == '=') ||
+                    (p[0] == '<' && p[1] == '=') ||
+                    (p[0] == '>' && p[1] == '=')) {
+                    return 1;
+                }
                 
-                    fprintf (state->ofp, "    test eax, eax\n");
-                    fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), skip_label);
+                if ((p[0] == '<' && p[1] != '<') ||
+                    (p[0] == '>' && p[1] != '>')) {
+                    return 1;
+                }
+            
+            }
+        
+        }
+        
+        if (!(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')) {
+            saw_operand = 1;
+        }
+        
+        p++;
+    
+    }
+
+    return 0;
+
+}
+
+static int source_parenthesized_lhs_followed_by_compare_now (const char *p) {
+
+    int paren_depth = 0;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '(') {
+        return 0;
+    }
+    
+    while (*p) {
+    
+        if (*p == '\'' || *p == '"') {
+        
+            int quote = *p++;
+            
+            while (*p) {
+            
+                if (*p == '\\' && p[1]) {
                 
-                } else {
+                    p += 2;
+                    continue;
                 
-                    fprintf (state->ofp, "    testl %%eax, %%eax\n");
-                    fprintf (state->ofp, "    jnz .L%d\n", skip_label);
+                }
+                
+                if (*p == quote) {
+                
+                    p++;
+                    break;
                 
                 }
+                
+                p++;
             
             }
             
-            get_token ();
-            
-            emit_statement_jump_if_false (label);
-            emit_statement_label (skip_label);
+            continue;
+        
+        }
+        
+        if (*p == '(') {
+        
+            paren_depth++;
+            p++;
             
-            return;
+            continue;
         
         }
         
-        emit_statement_test_eax_jump_if_false (label);
-        statement_condition_emit_logical_tail (label);
+        if (*p == ')') {
         
+            paren_depth--;
+            p++;
+            
+            if (paren_depth == 0) {
+            
+                while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+                    p++;
+                }
+                
+                if ((p[0] == '=' && p[1] == '=') ||
+                    (p[0] == '!' && p[1] == '=') ||
+                    (p[0] == '<' && p[1] == '=') ||
+                    (p[0] == '>' && p[1] == '=')) {
+                    return 1;
+                }
+                
+                if ((p[0] == '<' && p[1] != '<') ||
+                    (p[0] == '>' && p[1] != '>')) {
+                    return 1;
+                }
+                
+                return 0;
+            
+            }
+            
+            if (paren_depth < 0) {
+                return 0;
+            }
+            
+            continue;
+        
+        }
+        
+        p++;
+    
+    }
+    
+    return 0;
+
+}
+
+static int emit_statement_parenthesized_lhs_compare_jump_if_false_now (int label) {
+
+    enum token_kind op;
+    int is_unsigned;
+    
+    if (tok.kind != TOK_LPAREN) {
+        return 0;
+    }
+    
+    if (!source_parenthesized_lhs_followed_by_compare_now (tok.caret)) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    is_unsigned = rhs_current_operand_is_unsigned_now ();
+    emit_load_assignment_rhs_expression_to_reg ("eax");
+    
+    expect (TOK_RPAREN, ")");
+    
+    if (!token_is_statement_compare_operator (tok.kind)) {
+    
+        emit_statement_eax_truth_jump_if_false_and_tail (label);
+        return 1;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    if (rhs_current_operand_is_unsigned_now ()) {
+        is_unsigned = 1;
+    }
+    
+    if (!emit_statement_rhs_const32_to_edx_if_possible ()) {
+    
+        emit_push_reg_now ("eax");
+        emit_load_assignment_compare_expression_to_reg ("edx");
+        emit_pop_reg_now ("eax");
+    
+    }
+    
+    emit_statement_cmp_eax_edx_jump_if_false_and_tail (op, is_unsigned, label);
+    return 1;
+
+}
+
+static int emit_statement_direct_compare_jump_if_false_now (int label) {
+
+    enum token_kind op;
+    
+    int is_unsigned;
+    int old_assignment32_stop_before_condition_operator;
+    
+    if (!source_condition_has_top_level_compare_now (tok.caret) &&
+        !source_condition_has_top_level_compare_now (tok.start)) {
+        return 0;
+    }
+    
+    is_unsigned = rhs_current_operand_is_unsigned_now ();
+    
+    old_assignment32_stop_before_condition_operator = assignment32_stop_before_condition_operator;
+    assignment32_stop_before_condition_operator = 1;
+    
+    if (emit_load_assignment_binary_expression_prec_to_reg ("eax", 1)) {
+        is_unsigned = 1;
+    }
+    
+    assignment32_stop_before_condition_operator = old_assignment32_stop_before_condition_operator;
+    
+    if (!token_is_statement_compare_operator (tok.kind)) {
+    
+        emit_statement_eax_truth_jump_if_false_and_tail (label);
+        return 1;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    if (rhs_current_operand_is_unsigned_now ()) {
+        is_unsigned = 1;
+    }
+    
+    if (!emit_statement_rhs_const32_to_edx_if_possible ()) {
+    
+        emit_push_reg_now ("eax");
+        emit_load_assignment_compare_expression_to_reg ("edx");
+        emit_pop_reg_now ("eax");
+    
+    }
+    
+    emit_statement_cmp_eax_edx_jump_if_false_and_tail (op, is_unsigned, label);
+    return 1;
+
+}
+
+static void emit_statement_jump_if_false (int label) {
+
+    enum token_kind op;
+    int is_unsigned;
+    
+    const char *call_start;
+    const char *call_caret;
+    
+    char *call_name;
+    unsigned long call_line;
+    
+    int old_assignment32_stop_before_condition_operator;
+    flush_pending_statement_labels ();
+    
+    statement_condition_constant_known = 0;
+    statement_condition_constant_value = 0;
+    
+    if (emit_statement_ident_immediate_compare_jump_if_false_now (label)) {
+        return;
+    }
+    
+    if (emit_statement_ident_enum_compare_jump_if_false_now (label)) {
         return;
+    }
     
+    if (emit_statement_member_enum_compare_jump_if_false_now (label)) {
+        return;
     }
     
     if (emit_load_parenthesized_assignment_expression_to_reg_now ("eax", &is_unsigned)) {
@@ -32668,21 +34142,49 @@ static void emit_statement_jump_if_false (int label) {
                 is_unsigned = 1;
             }
             
-            emit_load_assignment_rhs_expression_to_reg ("edx");
+            emit_load_assignment_compare_expression_to_reg ("edx");
             consume_parenthesized_assignment_remaining_closes ();
-            emit_statement_cmp_eax_edx_jump_if_false (op, is_unsigned, label);
+            
+            emit_statement_cmp_eax_edx_jump_if_false_and_tail (op, is_unsigned, label);
+            statement_condition_emit_logical_tail (label);
             
             return;
         
         }
         
         consume_parenthesized_assignment_remaining_closes ();
-        emit_statement_test_eax_jump_if_false (label);
+        
+        emit_statement_eax_truth_jump_if_false_and_tail (label);
         return;
     
     }
     
-    if (statement_condition_starts_with_ident_call_now ()) {
+    if (emit_statement_parenthesized_lhs_compare_jump_if_false_now (label)) {
+        return;
+    }
+    
+    if (emit_statement_direct_compare_jump_if_false_now (label)) {
+        return;
+    }
+    
+    /*
+     * Parenthesized statement conditions must be parsed as ordinary
+     * expressions here.  The older recursive/special-case paths try to split
+     * things like:
+     *
+     *     (p - q) > 2
+     *     ((*u++ = *t++) != '\n')
+     *     (toupper((unsigned char)specifier) == 'X')
+     *
+     * into a hand-emitted branch form.  That interacts badly with the
+     * stop-before-condition-operator guard and makes the inner expression
+     * parser treat non-constant subexpressions as integer constant
+     * expressions.  Let the normal expression parser consume the whole
+     * parenthesized expression, then branch on the resulting value.  If the
+     * parenthesized value is followed by a comparison, handle that comparison
+     * normally after the grouped LHS has been loaded.
+     */
+    if (tok.kind == TOK_LPAREN) {
     
         is_unsigned = rhs_current_operand_is_unsigned_now ();
         emit_load_assignment_rhs_expression_to_reg ("eax");
@@ -32696,17 +34198,82 @@ static void emit_statement_jump_if_false (int label) {
                 is_unsigned = 1;
             }
             
-            emit_load_assignment_rhs_expression_to_reg ("edx");
-            emit_statement_cmp_eax_edx_jump_if_false (op, is_unsigned, label);
+            if (!emit_statement_rhs_const32_to_edx_if_possible ()) {
             
-            statement_condition_emit_logical_tail (label);
+                emit_push_reg_now ("eax");
+                emit_load_assignment_compare_expression_to_reg ("edx");
+                emit_pop_reg_now ("eax");
+            
+            }
+            
+            emit_statement_cmp_eax_edx_jump_if_false_and_tail (op, is_unsigned, label);
             return;
         
         }
+
+        emit_statement_eax_truth_jump_if_false_and_tail (label);
+        return;
+
+    }
+    
+    if (tok.kind == TOK_LPAREN && !source_starts_with_parenthesized_assignment_now ()) {
+    
+        get_token ();
+        
+        emit_statement_jump_if_false (label);
+        expect (TOK_RPAREN, ")");
         
-        emit_statement_test_eax_jump_if_false (label);
         statement_condition_emit_logical_tail (label);
+        return;
+    }
+    
+    if (statement_condition_starts_with_ident_call_now ()) {
+    
+        is_unsigned = rhs_current_operand_is_unsigned_now ();
+        
+        if (tok.kind != TOK_IDENT) {
+            emit_load_assignment_rhs_expression_to_reg ("eax");
+        } else {
         
+            call_name = xstrdup (tok.ident);
+            call_start = tok.start;
+            call_caret = tok.caret;
+            call_line = get_line_number ();
+            
+            get_token ();
+            
+            if (!find_local_symbol (call_name)) {
+                ensure_global_function_symbol (call_name, call_start, call_caret, call_line);
+            }
+            
+            emit_call_identifier_to_reg_now (call_name, "eax", call_start, call_caret, call_line);
+            free (call_name);
+        
+        }
+        
+        if (token_is_statement_compare_operator (tok.kind)) {
+        
+            op = tok.kind;
+            get_token ();
+            
+            if (rhs_current_operand_is_unsigned_now ()) {
+                is_unsigned = 1;
+            }
+            
+            if (!emit_statement_rhs_const32_to_edx_if_possible ()) {
+            
+                emit_push_reg_now ("eax");
+                emit_load_assignment_compare_expression_to_reg ("edx");
+                emit_pop_reg_now ("eax");
+            
+            }
+            
+            emit_statement_cmp_eax_edx_jump_if_false_and_tail (op, is_unsigned, label);
+            return;
+        
+        }
+        
+        emit_statement_eax_truth_jump_if_false_and_tail (label);
         return;
     
     }
@@ -32723,7 +34290,7 @@ static void emit_statement_jump_if_false (int label) {
      */
     if (token_is_const_floating_condition_operand_now () || rhs_current_operand_is_floating_now ()) {
     
-        long double left_float = 0.0L;
+        double left_float = 0.0;
         
         int left_float_constant = 0;
         int float_size = DATA_DOUBLE & 0x1f;
@@ -32744,19 +34311,14 @@ static void emit_statement_jump_if_false (int label) {
             
             if (left_float_constant && (token_is_floating_constant_now () || token_is_const_condition_operand_now ())) {
             
-                long double right_float;
+                double right_float;
                 
                 if (token_is_floating_constant_now ()) {
                     right_float = parse_floating_const_expr_value_now ();
                 } else {
                 
                     int64_s right_int = const64_from_current_operand ();
-                    
-                    right_float = (long double) right_int.low;
-                    
-                    if (right_int.high != 0) {
-                        right_float += ((long double) right_int.high) * 4294967296.0L;
-                    }
+                    right_float = int64_to_double_now (right_int);
                 
                 }
                 
@@ -32785,7 +34347,7 @@ static void emit_statement_jump_if_false (int label) {
         if (left_float_constant) {
         
             statement_condition_constant_known = 1;
-            statement_condition_constant_value = left_float != 0.0L ? 1 : 0;
+            statement_condition_constant_value = left_float != 0.0 ? 1 : 0;
             
             if (statement_condition_fold_logical_tail (label)) {
                 return;
@@ -32795,16 +34357,27 @@ static void emit_statement_jump_if_false (int label) {
         
         }
         
-        emit_load_floating_ld_now (float_size, 0.0L);
+        emit_load_floating_ld_now (float_size, 0.0);
         emit_statement_floating_compare_jump_if_false (TOK_NOTEQ, label);
         
         return;
     
     }
     
-    if (token_is_const_condition_operand_now () || const_integer_expr_text_is_foldable_now (tok.caret) || current_integer_expr_is_foldable_now ()) {
+    /*
+     * Only take the statement-condition constant shortcut when the current
+     * token itself is a constant operand.  The old text-based fallbacks could
+     * misfire during self-compilation of enum comparisons such as:
+     *
+     *     if (assign_op == TOK_ASSIGN)
+     *
+     * and reduce the whole condition to the RHS enum value.  That generated
+     * "mov eax, 61; test eax, eax" and made every compound assignment look
+     * like a plain assignment in the next bootstrap stage.
+     */
+    if (token_is_const_condition_operand_now ()) {
     
-        int fold_whole_expr = const_integer_expr_text_is_foldable_now (tok.caret) || current_integer_expr_is_foldable_now ();
+        int fold_whole_expr = current_integer_expr_is_foldable_now ();
         int left_unsigned = rhs_current_operand_is_unsigned_now ();
         
         int64_s left;
@@ -32844,9 +34417,7 @@ static void emit_statement_jump_if_false (int label) {
                     is_unsigned = 1;
                 }
                 
-                emit_load_assignment_rhs_expression_to_reg ("edx");
-                emit_statement_cmp_eax_edx_jump_if_false (op, is_unsigned, label);
-                
+                emit_statement_cmp_eax_edx_jump_if_false_and_tail (op, is_unsigned, label);
                 return;
             
             }
@@ -32869,15 +34440,10 @@ static void emit_statement_jump_if_false (int label) {
             
             if (token_is_floating_constant_now ()) {
             
-                long double left_float;
-                long double right_float;
-                
-                left_float = (long double) left.low;
-                
-                if (left.high != 0) {
-                    left_float += ((long double) left.high) * 4294967296.0L;
-                }
+                double left_float;
+                double right_float;
                 
+                left_float = int64_to_double_now (left);
                 right_float = parse_floating_const_expr_value_now ();
                 
                 statement_condition_constant_known = 1;
@@ -32914,13 +34480,7 @@ static void emit_statement_jump_if_false (int label) {
             
             if (rhs_current_operand_is_floating_now ()) {
             
-                long double left_float;
-                
-                left_float = (long double) left.low;
-                
-                if (left.high != 0) {
-                    left_float += ((long double) left.high) * 4294967296.0L;
-                }
+                double left_float = int64_to_double_now (left);
                 
                 emit_load_floating_ld_now (DATA_DOUBLE & 0x1f, left_float);
                 emit_load_floating_rhs_expression_now (DATA_DOUBLE & 0x1f);
@@ -32933,9 +34493,7 @@ static void emit_statement_jump_if_false (int label) {
             emit_statement_const32_to_eax (left);
             emit_load_assignment_rhs_expression_to_reg ("edx");
             
-            emit_statement_cmp_eax_edx_jump_if_false (op, is_unsigned, label);
-            statement_condition_emit_logical_tail (label);
-            
+            emit_statement_cmp_eax_edx_jump_if_false_and_tail (op, is_unsigned, label);
             return;
         
         }
@@ -32961,9 +34519,8 @@ static void emit_statement_jump_if_false (int label) {
     if (tok.kind == TOK_XMARK) {
     
         emit_load_assignment_rhs_expression_to_reg ("eax");
-        emit_statement_test_eax_jump_if_false (label);
         
-        statement_condition_emit_logical_tail (label);
+        emit_statement_eax_truth_jump_if_false_and_tail (label);
         return;
     
     }
@@ -33077,7 +34634,12 @@ static void emit_statement_jump_if_false (int label) {
     }
     
     is_unsigned = rhs_current_operand_is_unsigned_now ();
+    
+    old_assignment32_stop_before_condition_operator = assignment32_stop_before_condition_operator;
+    assignment32_stop_before_condition_operator = 1;
+    
     emit_load_assignment_rhs_expression_to_reg ("eax");
+    assignment32_stop_before_condition_operator = old_assignment32_stop_before_condition_operator;
     
     if (token_is_statement_compare_operator (tok.kind)) {
     
@@ -33088,16 +34650,20 @@ static void emit_statement_jump_if_false (int label) {
             is_unsigned = 1;
         }
         
-        emit_load_assignment_rhs_expression_to_reg ("edx");
-        emit_statement_cmp_eax_edx_jump_if_false (op, is_unsigned, label);
+        if (!emit_statement_rhs_const32_to_edx_if_possible ()) {
         
-        statement_condition_emit_logical_tail (label);
+            emit_push_reg_now ("eax");
+            emit_load_assignment_compare_expression_to_reg ("edx");
+            emit_pop_reg_now ("eax");
+        
+        }
+        
+        emit_statement_cmp_eax_edx_jump_if_false_and_tail (op, is_unsigned, label);
         return;
     
     }
     
-    emit_statement_test_eax_jump_if_false (label);
-    statement_condition_emit_logical_tail (label);
+    emit_statement_eax_truth_jump_if_false_and_tail (label);
 
 }
 
@@ -33958,30 +35524,52 @@ static void parse_statement (void) {
     
     }
     
-    if (tok.kind == TOK_BREAK || tok.kind == TOK_CONTINUE) {
+    if (tok.kind == TOK_BREAK) {
     
-        enum token_kind jump_kind = tok.kind;
-        int target_label = -1;
+        int target_label = current_break_label;
+        
+        long cleanup_base = current_break_cleanup_base;
+        long cleanup_bytes;
         
         get_token ();
         
-        if (jump_kind == TOK_BREAK) {
-            target_label = current_break_label;
-        } else {
-            target_label = current_continue_label;
+        if (target_label >= 0) {
+        
+            cleanup_bytes = current_block_cleanup_bytes - cleanup_base;
+            
+            if (!current_function_uses_single_frame && cleanup_bytes > 0) {
+                emit_stack_adjust (cleanup_bytes, 0);
+            }
+            
+            emit_statement_jump (target_label);
+            statement_ends_control_flow = 1;
+        
         }
         
+        if (tok.kind != TOK_SEMI) {
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        }
+        
+        expect (TOK_SEMI, ";");
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_CONTINUE) {
+    
+        int target_label = current_continue_label;
+        
+        long cleanup_base = current_continue_cleanup_base;
+        long cleanup_bytes;
+        
+        get_token ();
+        
         if (target_label >= 0) {
         
-            {
-            
-                long cleanup_base = (jump_kind == TOK_BREAK) ? current_break_cleanup_base : current_continue_cleanup_base;
-                long cleanup_bytes = current_block_cleanup_bytes - cleanup_base;
-                
-                if (cleanup_bytes > 0) {
-                    emit_stack_adjust (cleanup_bytes, 0);
-                }
+            cleanup_bytes = current_block_cleanup_bytes - cleanup_base;
             
+            if (!current_function_uses_single_frame && cleanup_bytes > 0) {
+                emit_stack_adjust (cleanup_bytes, 0);
             }
             
             emit_statement_jump (target_label);
@@ -34086,10 +35674,14 @@ static void parse_function_body (const char *name, int storage_class, int is_inl
     int emit_inline_definition_to_output = 1;
     
     FILE *saved_ofp;
-    FILE *inline_tmp = 0;
+    FILE *function_tmp = 0;
     
     char *inline_asm_text = 0;
+    char *function_asm_text = 0;
+    char function_tmp_name[64];
+    
     int capture_inline_body = 0;
+    int capture_function_body = 0;
     
     int saved_declarator_function_param_count;
     int saved_declarator_function_has_prototype;
@@ -34104,6 +35696,7 @@ static void parse_function_body (const char *name, int storage_class, int is_inl
     int old_function_has_return_statement;
     
     char *function_filename_copy = 0;
+    function_tmp_name[0] = 0;
     
     /**
      * Inline definitions are compiled into a temporary assembler buffer so
@@ -34142,13 +35735,14 @@ static void parse_function_body (const char *name, int storage_class, int is_inl
     }
     
     capture_inline_body = is_inline && saved_ofp != 0;
+    capture_function_body = saved_ofp != 0;
     
-    if (capture_inline_body) {
+    if (capture_function_body) {
     
-        inline_tmp = tmpfile ();
+        function_tmp = open_scc_temp_file (function_tmp_name, sizeof (function_tmp_name));
         
-        if (!inline_tmp) {
-            capture_inline_body = 0;
+        if (!function_tmp) {
+            capture_function_body = 0;
         }
     
     }
@@ -34209,13 +35803,21 @@ static void parse_function_body (const char *name, int storage_class, int is_inl
     
     if (!emit_body || !should_emit) {
         state->ofp = 0;
-    } else if (capture_inline_body) {
-        state->ofp = inline_tmp;
+    } else if (capture_function_body) {
+        state->ofp = function_tmp;
     }
     
     current_return_label = anon_label++;
     pending_return_jump = 0;
     
+    /*
+     * Do not apply the whole-function frame deferral to inline-function
+     * capture.  The inline expander analyses the captured body as it was
+     * emitted, including any stack movement before parameter references.
+     * Moving all automatic storage to a synthetic prologue changes that
+     * analysis and can corrupt the self-built compiler.
+     */
+    current_function_frame_enabled = (!is_inline && capture_function_body);
     emit_function_start (name, !emit_public);
     
     parse_block ();
@@ -34226,28 +35828,64 @@ static void parse_function_body (const char *name, int storage_class, int is_inl
     }
     
     pending_return_jump = 0;
-    
     emit_function_end ();
+    
+    current_function_frame_label = -1;
+    current_function_frame_deferred = 0;
+    current_function_frame_enabled = 0;
+    
     emit_goto_trampolines ();
+    current_function_uses_single_frame = 0;
     
-    if (capture_inline_body && inline_tmp) {
+    if (capture_function_body && function_tmp) {
     
-        inline_asm_text = read_tmp_file_text (inline_tmp);
+        function_asm_text = read_tmp_file_text (function_tmp);
         
-        if (inline_asm_text) {
+        if (function_asm_text) {
         
-            if (emit_inline_definition_to_output) {
+            inline_asm_text = replace_function_frame_placeholder (function_asm_text, current_function_frame_size);
+            
+            if (!inline_asm_text) {
+            
+                inline_asm_text = function_asm_text;
+                function_asm_text = 0;
+            
+            }
+            
+            if (!capture_inline_body || emit_inline_definition_to_output) {
                 fputs (inline_asm_text, saved_ofp);
             }
             
-            remember_inline_function (name, inline_asm_text, current_return_label,
-                saved_declarator_function_param_count, saved_declarator_function_has_prototype || saved_declarator_function_param_count > 0,
-                    return_is_void, return_is_floating, return_size);
+            if (capture_inline_body) {
+            
+                remember_inline_function (name, inline_asm_text, current_return_label,
+                    saved_declarator_function_param_count, saved_declarator_function_has_prototype || saved_declarator_function_param_count > 0,
+                        return_is_void, return_is_floating, return_size);
+            
+            }
         
         }
         
-        fclose (inline_tmp);
-        inline_tmp = 0;
+        if (function_asm_text) {
+            free (function_asm_text);
+        }
+        
+        if (inline_asm_text) {
+        
+            free (inline_asm_text);
+            inline_asm_text = 0;
+        
+        }
+        
+        fclose (function_tmp);
+        function_tmp = 0;
+        
+        if (function_tmp_name[0]) {
+        
+            remove (function_tmp_name);
+            function_tmp_name[0] = 0;
+        
+        }
     
     }
     
@@ -35246,12 +36884,7 @@ static void emit_global_scalar (int64_s value, int size) {
         } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
         
             masm_emit_data_prefix ("dq");
-            
-            if (high & U32_MASK) {
-                fprintf (state->ofp, "%lu%lu", high & U32_MASK, low & U32_MASK);
-            } else {
-                fprintf (state->ofp, "%lu", low & U32_MASK);
-            }
+            fprintf (state->ofp, "0%08lX%08lXh", high & U32_MASK, low & U32_MASK);
         
         } else {
         
diff --git a/token.c b/token.c
index 869a200c7f21d6e9018e10c78fc86efb936636db..ca9b15f859f5be6115cb903153f9066be14398ef 100755 (executable)
--- a/token.c
+++ b/token.c
@@ -1180,16 +1180,22 @@ static int bn_lshift (unsigned int *bn, int shift, int or_val) {
 
 }
 
-float _strtof (const char *nptr, char **endptr) {
+float scc_strtof (const char *nptr, char **endptr) {
 
     const char *s = nptr;
-    float res = 0.0f;
+    
+    float res = 0;
+    float frac = 0;
+    float div = 1;
+    float pow10;
     
     int sign = 1;
     int exp = 0;
+    int exp_sign = 1;
     int has_digits = 0;
+    int i;
     
-    while (isspace ((unsigned char) *s)) {
+    while (isspace ((int) *s)) {
         s++;
     }
     
@@ -1203,9 +1209,11 @@ float _strtof (const char *nptr, char **endptr) {
     }
     
     /* Integer part */
-    while (isdigit ((unsigned char) *s)) {
+    while (isdigit ((int) *s)) {
     
-        res = res * 10.0f + (*s++ - '0');
+        res = (res * 10) + (*s - '0');
+        s++;
+        
         has_digits = 1;
     
     }
@@ -1213,13 +1221,14 @@ float _strtof (const char *nptr, char **endptr) {
     /* Fractional part */
     if (*s == '.') {
     
-        float factor = 0.1f;
         s++;
         
-        while (isdigit ((unsigned char) *s)) {
+        while (isdigit ((int) *s)) {
         
-            res += (*s++ - '0') * factor;
-            factor *= 0.1f;
+            frac = (frac * 10) + (*s - '0');
+            
+            div *= 10;
+            s++;
             
             has_digits = 1;
         
@@ -1233,17 +1242,17 @@ float _strtof (const char *nptr, char **endptr) {
             *endptr = (char *) nptr;
         }
         
-        return 0.0f;
+        return 0;
     
     }
     
+    res += frac / div;
+    
     /* Exponent part */
     if (*s == 'e' || *s == 'E') {
     
-        const char *backtrack = s;
-        
-        int exp_sign = 1;
-        int e_val = 0;
+        const char *exp_start = s;
+        int exp_val = 0;
         
         s++;
         
@@ -1256,168 +1265,177 @@ float _strtof (const char *nptr, char **endptr) {
             s++;
         }
         
-        if (isdigit ((unsigned char) *s)) {
+        if (isdigit ((int) *s)) {
         
-            while (isdigit ((unsigned char) *s)) {
+            while (isdigit ((int) *s)) {
             
-                e_val = e_val * 10 + (*s - '0');
+                exp_val = (exp_val * 10) + (*s - '0');
                 s++;
             
             }
             
-            exp = e_val * exp_sign;
+            exp = exp_val * exp_sign;
         
         } else {
-            s = backtrack; 
+            s = exp_start;
         }
     
     }
     
-    if (exp != 0) {
+    pow10 = 1;
+    
+    if (exp > 0) {
     
-        float base = (exp > 0) ? 10.0f : 0.1f;
-        int abs_exp = (exp > 0) ? exp : -exp;
+        for (i = 0; i < exp; i++) {
+            pow10 *= 10;
+        }
         
-        for (; abs_exp > 0; abs_exp--) {
-            res *= base;
+        res *= pow10;
+    
+    } else if (exp < 0) {
+    
+        for (i = 0; i < -exp; i++) {
+            pow10 *= 10;
         }
+        
+        res /= pow10;
+    
+    }
     
+    if (sign < 0) {
+        res = -res;
     }
     
     if (endptr) {
         *endptr = (char *) s;
     }
     
-    return res * sign;
+    return res;
 
 }
 
-long double strtold (const char *nptr, char **endptr) {
+double scc_strtod (const char *nptr, char **endptr) {
 
     const char *s = nptr;
     
-    long double res = 0.0L;
-    int sign = 1, exp = 0, has_digits = 0;
+    double x = 0;
+    double frac = 0;
+    double div = 1;
+    double pow10;
+
+    int neg = 0;
+    int exp_neg = 0;
+    int exp_val = 0;
+    int saw_digit = 0;
+    int i;
     
-    while (isspace ((unsigned char) *s)) {
+    while (isspace ((int) *s)) {
         s++;
     }
     
     if (*s == '-') {
     
-        sign = -1;
+        neg = 1;
         s++;
     
     } else if (*s == '+') {
         s++;
     }
     
-    while (isdigit ((unsigned char) *s)) {
+    while (isdigit ((int) *s)) {
     
-        res = res * 10.0L + (*s++ - '0');
-        has_digits = 1;
+        x = (x * 10) + (*s - '0');
+        s++;
+        
+        saw_digit = 1;
     
     }
     
     if (*s == '.') {
     
-        long double factor = 0.1L;
         s++;
         
-        while (isdigit ((unsigned char) *s)) {
+        while (isdigit ((int) *s)) {
+        
+            frac = (frac * 10) + (*s - '0');
             
-            res += (long double) (*s++ - '0') * factor;
-            factor *= 0.1L;
+            div *= 10;
+            s++;
             
-            has_digits = 1;
+            saw_digit = 1;
         
         }
-    
+
     }
-    
-    if (!has_digits) {
+
+    if (!saw_digit) {
     
         if (endptr) {
             *endptr = (char *) nptr;
         }
         
-        return 0.0L;
+        return 0;
     
     }
     
+    x += frac / div;
+    
     if (*s == 'e' || *s == 'E') {
     
-        const char *back = s;
-        int esign = 1, eval = 0;
-        
-        s++;
+        const char *exp_start = s++;
         
         if (*s == '-') {
         
-            esign = -1;
+            exp_neg = 1;
             s++;
         
         } else if (*s == '+') {
             s++;
         }
         
-        if (isdigit ((unsigned char) *s)) {
+        if (isdigit ((int) *s)) {
         
-            while (isdigit ((unsigned char) *s)) {
-                eval = eval * 10 + (*s++ - '0');
-            }
+            while (isdigit ((int) *s)) {
+            
+                if (exp_val < 308) {
+                    exp_val = (exp_val * 10) + (*s - '0');
+                }
+                
+                s++;
             
-            exp = eval * esign;
+            }
         
         } else {
-            s = back;
+            s = exp_start;
         }
     
     }
     
-    /* Apply exponent in safe chunks to avoid intermediate overflow/underflow */
-    if (exp != 0) {
+    pow10 = 1;
     
-        int abs_exp = (exp > 0) ? exp : -exp;
-        
-        while (abs_exp > 0) {
-        
-            int chunk = (abs_exp > 4000) ? 4000 : abs_exp;
-            
-            long double multiplier = 1.0L;
-            long double base = 10.0L;
-            
-            int i = chunk;
-            
-            /* Binary Exponentiation for the current chunk */
-            while (i > 0) {
-            
-                if (i & 1) {
-                    multiplier *= base;
-                }
-                
-                base *= base;
-                i >>= 1;
-            
-            }
-            
-            if (exp > 0) {
-                res *= multiplier;
-            } else {
-                res /= multiplier;
-            }
-            
-            abs_exp -= chunk;
-        
+    for (i = 0; i < exp_val; i++) {
+        pow10 *= 10;
+    }
+    
+    if (exp_val != 0) {
+    
+        if (exp_neg) {
+            x /= pow10;
+        } else {
+            x *= pow10;
         }
     
     }
     
+    if (neg) {
+        x = -x;
+    }
+    
     if (endptr) {
         *endptr = (char *) s;
     }
     
-    return res * sign;
+    return x;
 
 }
 
@@ -1426,7 +1444,7 @@ static void parse_number (struct token *tok) {
     const char *p = tok->ident, *q;
     
     unsigned int bn[BN_SIZE] = { 0 };
-    long double d;
+    double d;
     
     CString cstr;
     int b, t, shift, frac_bits, s, exp_val, ch;
@@ -1570,16 +1588,16 @@ static void parse_number (struct token *tok) {
             }
             
             exp_val = exp_val * s;
-            d = (long double) bn[3];
+            d = bn[3];
             
             d = ldexp (d, 32);
-            d += (long double) bn[2];
+            d += bn[2];
             
             d = ldexp (d, 32);
-            d += (long double) bn[1];
+            d += bn[1];
             
             d = ldexp (d, 32);
-            d += (long double) bn[0];
+            d += bn[0];
             
             d = ldexp (d, exp_val - frac_bits);
             t = toupper ((int) ch);
@@ -1589,7 +1607,7 @@ static void parse_number (struct token *tok) {
                 ch = *p++;
                 
                 tok->kind = TOK_CFLOAT;
-                tok->val.f = (float) d;
+                tok->val.f = d;
             
             } else if (t == 'L') {
             
@@ -1601,7 +1619,7 @@ static void parse_number (struct token *tok) {
             } else {
             
                 tok->kind = TOK_CDOUBLE;
-                tok->val.d = (double) d;
+                tok->val.d = d;
             
             }
         
@@ -1633,11 +1651,11 @@ static void parse_number (struct token *tok) {
                 
                 }
                 
-                if (ch < '0' || ch >= '9') {
+                if (ch < '0' || ch > '9') {
                     report_at (get_filename (), get_line_number (), REPORT_ERROR, "expected exponent digits");
                 }
                 
-                while (ch >= '0' && ch <=  '9') {
+                while (ch >= '0' && ch <= '9') {
                 
                     cstr_ccat (&cstr, ch);
                     ch = *p++;
@@ -1656,19 +1674,19 @@ static void parse_number (struct token *tok) {
                 ch = *p++;
                 
                 tok->kind = TOK_CFLOAT;
-                tok->val.f = _strtof (cstr.data, 0);
+                tok->val.f = scc_strtof (cstr.data, 0);
             
             } else if (t == 'L') {
             
                 ch = *p++;
                 
                 tok->kind = TOK_CLDOUBLE;
-                tok->val.ld = strtold (cstr.data, 0);
+                tok->val.ld = scc_strtod (cstr.data, 0);
             
             } else {
             
                 tok->kind = TOK_CDOUBLE;
-                tok->val.d = strtod (cstr.data, 0);
+                tok->val.d = scc_strtod (cstr.data, 0);
             
             }
         
diff --git a/token.h b/token.h
index de6372d544bbb7907260e6f13b2b05146f57e850..fafec994a24341000c1ff7127f494f468ccb1c1f 100755 (executable)
--- a/token.h
+++ b/token.h
@@ -141,7 +141,7 @@ struct token {
     
     union {
     
-        long double ld;
+        double ld;
         
         double d;
         float f;