Experimental AMD64 support
authorRobert Pengelly <robertapengelly@hotmail.com>
Mon, 15 Jun 2026 08:46:51 +0000 (09:46 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Mon, 15 Jun 2026 08:46:51 +0000 (09:46 +0100)
amd64.c [new file with mode: 0644]
cc.c
cc.h
i386.c [new file with mode: 0644]
lib.c
parse.c
parse.h

diff --git a/amd64.c b/amd64.c
new file mode 100644 (file)
index 0000000..c23555f
--- /dev/null
+++ b/amd64.c
@@ -0,0 +1,38330 @@
+/******************************************************************************
+ * @file            amd64.c
+ *****************************************************************************/
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+#include    "cc.h"
+#include    "expr.h"
+#include    "lib.h"
+#include    "parse.h"
+#include    "report.h"
+#include    "token.h"
+
+#define     SECTION_NONE                0
+#define     SECTION_TEXT                1
+#define     SECTION_DATA                2
+#define     SECTION_BSS                 3
+
+static int current_section = 0;
+static int anon_label = 1;
+
+static int pending_return_jump = 0;
+static int local_static_id = 1;
+
+#define     MAX_PENDING_STATEMENT_LABELS                    256
+
+static int pending_statement_labels[MAX_PENDING_STATEMENT_LABELS];
+static int pending_statement_label_count = 0;
+
+static void flush_pending_statement_labels (void);
+
+static int current_function_preserve_assignment64_regs = 0;
+static int current_return_label = 0;
+
+/*
+ * Track backend-emitted temporary stack use modulo 16 so AMD64 call
+ * frame reservation can compensate for any outstanding PUSH/sub rsp,8
+ * saves before a nested call.  The normal function prologue leaves RSP
+ * 16-byte aligned in this backend, so calls need the current temporary
+ * depth plus the call reservation to be a multiple of 16.
+ */
+static int amd64_temp_stack_mod16 = 0;
+
+static void amd64_note_stack_sub (int bytes) {
+
+    if (bytes > 0) {
+        amd64_temp_stack_mod16 = (amd64_temp_stack_mod16 + bytes) & 15;
+    }
+
+}
+
+static void amd64_note_stack_add (int bytes) {
+
+    if (bytes > 0) {
+        amd64_temp_stack_mod16 = (amd64_temp_stack_mod16 - (bytes & 15)) & 15;
+    }
+
+}
+
+static void amd64_emit_push_reg_now (const char *reg);
+static void amd64_emit_pop_reg_now (const char *reg);
+static int amd64_align_call_stack_bytes (int bytes);
+
+static int index_step_size (int size) {
+
+    if (size == DATA_CHAR || size == DATA_SHORT || size == DATA_INT ||
+        size == DATA_LONG || size == DATA_LLONG || size == DATA_FLOAT ||
+        size == DATA_DOUBLE) {
+        return size & 0x1f;
+    }
+    
+    if (size <= 0) {
+        return DATA_INT & 0x1f;
+    }
+    
+    return size;
+
+}
+
+static int rhs_last_pointer_depth = 0;
+static int rhs_last_pointed_size = 0;
+
+static void set_rhs_last_pointer_info (int depth, int size) {
+
+    rhs_last_pointer_depth = depth;
+    rhs_last_pointed_size = depth > 1 ? DATA_PTR : (size > 0 ? size : (DATA_INT & 0x1f));
+
+}
+
+static void clear_rhs_last_pointer_info (void) {
+
+    rhs_last_pointer_depth = 0;
+    rhs_last_pointed_size = 0;
+
+}
+
+static int current_function_has_return_statement = 0;
+static int current_parse_block_depth = 0;
+static int current_function_is_void = 0;
+static int current_function_is_floating = 0;
+static int current_function_return_size = DATA_NONE;
+static int current_function_return_is_unsigned = 0;
+static int current_function_return_pointer_depth = 0;
+static int current_function_returns_aggregate = 0;
+static int current_function_param_stack_bytes = 0;
+
+static enum token_kind current_function_calling_convention = TOK_EOF;
+static int current_function_is_variadic = 0;
+
+static struct local_symbol *pending_struct_return_lhs = 0;
+static const char *pending_struct_return_global_name = 0;
+
+static int pending_struct_return_stack_address = 0;
+static int pending_struct_return_stack_offset = 0;
+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 current_argument_starts_64bit_integer_now (void);
+static int argument_text_starts_64bit_cast_now (const char *p);
+
+static void masm_flush_data_line (void);
+static void emit_sub_rsp_now (int bytes);
+
+static int postfix_member_pointer_depth = 0;
+static int postfix_member_pointed_size = 0;
+static int postfix_member_seen = 0;
+static int postfix_copy_lvalue_size = 0;
+
+static const char *postfix_copy_lvalue_tag_name = 0;
+
+static int postfix_member_offset = 0;
+static int postfix_member_size = 0;
+
+static int postfix_member_is_floating = 0;
+static int postfix_member_is_unsigned = 0;
+
+static int find_member_info (const char *name, int *offset, int *size) {
+    return find_member_info_ex (name, offset, size, 0, 0, 0, 0);
+}
+
+static void clear_typedef_names (void) {
+
+    int i;
+    
+    for (i = 0; i < typedef_name_count; i++) {
+    
+        free (typedef_names[i].name);
+        
+        typedef_names[i].name = 0;
+        typedef_names[i].size = 0;
+        
+        typedef_names[i].tag_name = 0;
+        
+        typedef_names[i].is_aggregate = 0;
+        typedef_names[i].is_unsigned = 0;
+        
+        typedef_names[i].field_count = 0;
+        typedef_names[i].is_array = 0;
+        typedef_names[i].array_count = 1;
+        typedef_names[i].array_element_size = DATA_NONE;
+        
+        typedef_names[i].calling_convention = TOK_EOF;
+    
+    }
+    
+    typedef_name_count = 0;
+
+}
+
+static void save_typedef_name (const char *name, int size, int is_unsigned, int is_void, int is_aggregate, int is_array, long array_count, int array_element_size, enum token_kind calling_convention, const int *field_sizes, int field_count) {
+
+    struct typedef_entry *entry;
+    int i;
+    
+    if (!name || !*name) {
+        return;
+    }
+    
+    entry = find_typedef_name (name);
+    
+    if (!entry) {
+    
+        if (typedef_name_count >= MAX_TYPEDEF_NAMES) {
+        
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "too many typedef names");
+            return;
+        
+        }
+        
+        entry = &typedef_names[typedef_name_count++];
+        entry->name = xstrdup (name);
+        entry->tag_name = 0;
+        entry->calling_convention = TOK_EOF;
+    
+    }
+    
+    if (entry->tag_name) {
+    
+        free (entry->tag_name);
+        entry->tag_name = 0;
+    
+    }
+    
+    if (parsed_type_tag_name[0]) {
+        entry->tag_name = xstrdup (parsed_type_tag_name);
+    } else if (is_aggregate && name && *name) {
+        entry->tag_name = xstrdup (name);
+    }
+    
+    entry->is_void = is_void;
+    entry->size = size;
+    
+    entry->is_unsigned = is_unsigned;
+    entry->is_aggregate = is_aggregate;
+    
+    entry->field_count = 0;
+    entry->is_array = is_array ? 1 : 0;
+    entry->array_count = array_count > 0 ? array_count : 1;
+    entry->array_element_size = array_element_size > 0 ? array_element_size : DATA_INT;
+    entry->calling_convention = calling_convention;
+    
+    for (i = 0; i < field_count && i < MAX_AGG_FIELDS; i++) {
+        entry->field_sizes[entry->field_count++] = field_sizes[i];
+    }
+    
+    if (is_aggregate && !parsed_type_tag_name[0] && name && *name) {
+    
+        int mi;
+        
+        for (mi = 0; mi < member_info_count; mi++) {
+        
+            if (member_infos[mi].owner_size == size
+                && member_infos[mi].owner_tag_name == 0) {
+                member_infos[mi].owner_tag_name = xstrdup (name);
+            }
+        
+        }
+    
+    }
+
+}
+
+static void clear_enum_constants (void) {
+
+    int i;
+    
+    for (i = 0; i < enum_constant_count; i++) {
+    
+        free (enum_constants[i].name);
+        
+        enum_constants[i].name = 0;
+        enum_constants[i].value.low = 0;
+        enum_constants[i].value.high = 0;
+    
+    }
+    
+    enum_constant_count = 0;
+
+}
+
+static void clear_global_symbols (void) {
+
+    int i;
+    
+    for (i = 0; i < global_symbol_count; i++) {
+    
+        free (global_symbols[i].name);
+        
+        global_symbols[i].name = 0;
+        global_symbols[i].kind = 0;
+        global_symbols[i].size = 0;
+        
+        global_symbols[i].array_element_size = 0;
+        global_symbols[i].is_array = 0;
+        global_symbols[i].array_dimensions = 0;
+        
+        global_symbols[i].is_dllimport = 0;
+        global_symbols[i].is_extern = 0;
+        global_symbols[i].is_unsigned = 0;
+        global_symbols[i].is_floating = 0;
+        global_symbols[i].returns_void = 0;
+        
+        global_symbols[i].calling_convention = TOK_EOF;
+        
+        {
+        
+            int pi;
+            
+            for (pi = 0; pi < 128; pi++) {
+            
+                global_symbols[i].param_sizes[pi] = 0;
+                global_symbols[i].param_unsigneds[pi] = 0;
+                global_symbols[i].param_floatings[pi] = 0;
+                global_symbols[i].param_pointer_depths[pi] = 0;
+            
+            }
+        
+        }
+        
+        global_symbols[i].import_call_stack_bytes = 0;
+        global_symbols[i].param_count = 0;
+        global_symbols[i].has_prototype = 0;
+        global_symbols[i].is_variadic = 0;
+        global_symbols[i].is_implicit = 0;
+        global_symbols[i].extern_emitted = 0;
+        
+        if (global_symbols[i].tag_name) {
+        
+            free (global_symbols[i].tag_name);
+            global_symbols[i].tag_name = 0;
+        
+        }
+    
+    }
+    
+    global_symbol_count = 0;
+
+}
+
+static int asm_symbol_is_internal (const char *name) {
+
+    if (!name || !*name) {
+        return 1;
+    }
+    
+    if (name[0] == '.') {
+        return 1;
+    }
+    
+    if (name[0] == 'L') {
+    
+        if (name[1] >= '0' && name[1] <= '9') {
+            return 1;
+        }
+        
+        if (name[1] == 'C' && name[2] >= '0' && name[2] <= '9') {
+            return 1;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int global_symbol_stdcall_stack_bytes (const char *name) {
+
+    int i = find_global_symbol (name);
+    int pi;
+    int bytes = 0;
+    
+    if (i < 0 || global_symbols[i].kind != GLOBAL_SYMBOL_FUNCTION || global_symbols[i].calling_convention != TOK_STDCALL ||
+    
+        global_symbols[i].is_variadic) {
+        return 0;
+    
+    }
+    
+    for (pi = 0; pi < global_symbols[i].param_count && pi < 128; pi++) {
+    
+        int size = global_symbols[i].param_sizes[pi];
+        
+        if (size < 1) {
+            size = DATA_PTR & 0x1f;
+        }
+        
+        bytes += ((size + (DATA_PTR & 0x1f) - 1) / (DATA_PTR & 0x1f)) * (DATA_PTR & 0x1f);
+    
+    }
+    
+    if (bytes <= 0 && global_symbols[i].import_call_stack_bytes > 0) {
+        bytes = global_symbols[i].import_call_stack_bytes;
+    }
+    
+    return bytes;
+
+}
+
+static void remember_global_symbol_import_call_stack_bytes (const char *name, int bytes) {
+
+    int i = find_global_symbol (name);
+    
+    if (i < 0 || bytes <= 0) {
+        return;
+    }
+    
+    if (global_symbols[i].kind != GLOBAL_SYMBOL_FUNCTION || !global_symbols[i].is_dllimport || global_symbols[i].calling_convention != TOK_STDCALL) {
+        return;
+    }
+    
+    if (global_symbol_stdcall_stack_bytes (name) <= 0) {
+        global_symbols[i].import_call_stack_bytes = bytes;
+    }
+
+}
+
+static const char *asm_global_symbol_name (const char *name) {
+
+    static char buffers[8][512];
+    static int index = 0;
+    
+    char *out, suffix[32];
+    unsigned long avail, len;
+    
+    if (asm_symbol_is_internal (name)) {
+        return name;
+    }
+    
+    index = (index + 1) & 7;
+    
+    out = buffers[index];
+    len = strlen (name);
+    
+    /*
+     * AMD64 does not use the i386 stdcall name suffix.  __stdcall may be
+     * accepted as source syntax for compatibility, but the Microsoft x64 ABI
+     * uses one unified calling convention and symbols must not become
+     * name@bytes.
+     */
+    suffix[0] = '\0';
+    
+    avail = sizeof (buffers[0]) - 1 - strlen (suffix);
+    
+    if (!state->no_leading_underscore) {
+    
+        if (avail > 0) {
+            avail--;
+        }
+        
+        if (len > avail) {
+            len = avail;
+        }
+        
+        out[0] = '_';
+        
+        memcpy (out + 1, name, len);
+        out[len + 1] = 0;
+    
+    } else {
+    
+        if (len > avail) {
+            len = avail;
+        }
+        
+        memcpy (out, name, len);
+        out[len] = 0;
+    
+    }
+    
+    if (suffix[0]) {
+        strcat (out, suffix);
+    }
+    
+    return out;
+
+}
+
+static const char *asm_global_import_symbol_name (const char *name) {
+
+    static char buffers[8][512];
+    static int index = 0;
+    
+    const char *decorated;
+    char *out;
+    
+    unsigned long len;
+    
+    if (!(decorated = asm_global_symbol_name (name)) || asm_symbol_is_internal (name)) {
+        return decorated;
+    }
+    
+    index = (index + 1) & 7;
+    
+    out = buffers[index];
+    len = strlen (decorated);
+    
+    if (len > sizeof (buffers[0]) - 7) {
+        len = sizeof (buffers[0]) - 7;
+    }
+    
+    sprintf (out, "__imp_");
+    
+    memcpy (out + 6, decorated, len);
+    out[len + 6] = 0;
+    
+    return out;
+
+}
+
+static int get_global_symbol_kind (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].kind;
+    }
+    
+    return 0;
+
+}
+
+static void set_global_symbol_unsigned (const char *name, int is_unsigned) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        global_symbols[i].is_unsigned = is_unsigned ? 1 : 0;
+    }
+
+}
+
+static int get_global_symbol_unsigned (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].is_unsigned;
+    }
+    
+    return 0;
+
+}
+
+static void set_global_symbol_dllimport (const char *name, int is_dllimport) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+    
+        global_symbols[i].is_dllimport = is_dllimport ? 1 : 0;
+        
+        if (is_dllimport) {
+            global_symbols[i].is_extern = 1;
+        }
+    
+    }
+
+}
+
+static int get_global_symbol_dllimport (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].is_dllimport ? 1 : 0;
+    }
+    
+    return 0;
+
+}
+
+static void set_global_symbol_array (const char *name, int is_array) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        global_symbols[i].is_array = is_array ? 1 : 0;
+    }
+
+}
+
+static void set_global_symbol_array_count (const char *name, long array_count) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        global_symbols[i].array_count = array_count;
+    }
+
+}
+
+static long get_global_symbol_array_count (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].array_count;
+    }
+    
+    return 0;
+
+}
+
+static void set_global_symbol_array_dimensions (const char *name, int dims) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        global_symbols[i].array_dimensions = dims > 0 ? dims : 0;
+    }
+
+}
+
+static int get_global_symbol_array_dimensions (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].array_dimensions;
+    }
+    
+    return 0;
+
+}
+
+static void set_global_symbol_array_element_size (const char *name, int elem_size) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        global_symbols[i].array_element_size = elem_size > 0 ? elem_size : 0;
+    }
+
+}
+
+static void set_global_symbol_floating (const char *name, int is_floating) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        global_symbols[i].is_floating = is_floating ? 1 : 0;
+    }
+
+}
+
+static int get_global_symbol_floating (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].is_floating;
+    }
+    
+    return 0;
+
+}
+
+static int get_global_function_returns_floating (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i < 0 || global_symbols[i].kind != GLOBAL_SYMBOL_FUNCTION) {
+        return 0;
+    }
+    
+    if (global_symbols[i].is_floating) {
+        return 1;
+    }
+    
+    /*
+     * Do not infer floating return types from the masked object size.
+     *
+     * DATA_INT and DATA_FLOAT both have a 4-byte payload size, so checking
+     * only (size & 0x1f) makes every int-returning function look like it
+     * returns float.  That breaks expressions such as:
+     *
+     *     printf("%p", main);
+     *
+     * because the function designator gets loaded as a floating object from
+     * memory instead of as a plain code address.  The declaration/definition
+     * paths already record real floating function returns in is_floating.
+     */
+    return global_symbols[i].is_floating ? 1 : 0;
+
+}
+
+static void set_global_symbol_pointer_info (const char *name, int pointer_depth, int pointed_size) {
+
+    int i = find_global_symbol (name);
+    
+    if (pointer_depth > 0 && parsed_type_is_aggregate && parsed_type_size > (DATA_PTR & 0x1f) && pointed_size <= (DATA_PTR & 0x1f)) {
+        pointed_size = parsed_type_size;
+    }
+    
+    if (i >= 0) {
+    
+        global_symbols[i].pointer_depth = pointer_depth;
+        global_symbols[i].pointed_size = pointed_size;
+        
+        global_symbols[i].pointed_is_floating = pointer_depth > 0 ? (parsed_type_is_floating ? 1 : 0) : 0;
+        global_symbols[i].pointed_is_unsigned = pointer_depth > 0 ? (parsed_type_is_unsigned ? 1 : 0) : 0;
+    
+    }
+
+}
+
+static int get_global_symbol_pointed_is_floating (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].pointed_is_floating;
+    }
+    
+    return 0;
+
+}
+
+static int get_global_symbol_pointed_is_unsigned (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].pointed_is_unsigned;
+    }
+    
+    return 0;
+
+}
+
+static void set_global_symbol_tag_name (const char *name, const char *tag_name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+    
+        if (global_symbols[i].tag_name) {
+        
+            free (global_symbols[i].tag_name);
+            global_symbols[i].tag_name = 0;
+        
+        }
+        
+        if (tag_name && tag_name[0]) {
+            global_symbols[i].tag_name = xstrdup (tag_name);
+        }
+    
+    }
+
+}
+
+static const char *get_global_symbol_tag_name (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].tag_name;
+    }
+    
+    return 0;
+
+}
+
+static void set_global_symbol_returns_void (const char *name, int returns_void) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        global_symbols[i].returns_void = returns_void ? 1 : 0;
+    }
+
+}
+
+static void set_global_symbol_calling_convention (const char *name, enum token_kind calling_convention) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        global_symbols[i].calling_convention = calling_convention;
+    }
+
+}
+
+static int get_global_symbol_returns_void (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].returns_void;
+    }
+    
+    return 0;
+
+}
+
+static void set_global_symbol_param_count (const char *name, int param_count, int has_prototype, int is_variadic) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+    
+        global_symbols[i].param_count = param_count < 0 ? 0 : param_count;
+        global_symbols[i].has_prototype = has_prototype ? 1 : 0;
+        global_symbols[i].is_variadic = is_variadic ? 1 : 0;
+    
+    }
+
+}
+
+static int get_global_symbol_has_prototype (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].has_prototype;
+    }
+    
+    return 0;
+
+}
+
+static int get_global_symbol_is_variadic (const char *name) {
+
+    int i = find_global_symbol (name);
+
+    if (i >= 0) {
+        return global_symbols[i].is_variadic;
+    }
+
+    return 0;
+
+}
+
+static int get_global_symbol_param_count (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].param_count;
+    }
+    
+    return 0;
+
+}
+
+static int get_global_symbol_param_size (const char *name, int param_index) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0 && param_index >= 0 && param_index < 128 && global_symbols[i].param_sizes[param_index] > 0) {
+        return global_symbols[i].param_sizes[param_index];
+    }
+    
+    return DATA_PTR & 0x1f;
+
+}
+
+static int get_global_symbol_param_unsigned (const char *name, int param_index) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0 && param_index >= 0 && param_index < 128) {
+        return global_symbols[i].param_unsigneds[param_index] ? 1 : 0;
+    }
+    
+    return 0;
+
+}
+
+static int get_global_symbol_param_floating (const char *name, int param_index) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0 && param_index >= 0 && param_index < 128) {
+        return global_symbols[i].param_floatings[param_index] ? 1 : 0;
+    }
+    
+    return 0;
+
+}
+
+static void set_global_symbol_size (const char *name, int size) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        global_symbols[i].size = size;
+    }
+
+}
+
+static int add_global_symbol (const char *name, int kind, int is_extern, const char *line_start, const char *name_caret, unsigned long lineno) {
+
+    int old;
+    
+    if (!name || !*name) {
+        return 0;
+    }
+    
+    if (!line_start) {
+        line_start = tok.start;
+    }
+
+    if (!name_caret) {
+        name_caret = tok.caret;
+    }
+
+    if (lineno == 0) {
+        lineno = get_line_number ();
+    }
+    
+    old = find_global_symbol (name);
+    
+    if (old >= 0) {
+    
+        if (global_symbols[old].is_implicit) {
+        
+            global_symbols[old].is_extern = is_extern ? 1 : 0;
+            global_symbols[old].is_implicit = 0;
+            
+            global_symbols[old].kind = kind;
+            return 1;
+        
+        }
+        
+        if (is_extern) {
+            return 0;
+        }
+        
+        if (global_symbols[old].is_extern) {
+        
+            global_symbols[old].kind = kind;
+            global_symbols[old].is_extern = 0;
+            
+            return 1;
+        
+        }
+        
+        report_line_at (get_filename (), lineno, REPORT_ERROR, line_start, name_caret, "duplicate symbol '%s'", name);
+        return 0;
+    
+    }
+    
+    if (global_symbol_count >= MAX_GLOBAL_SYMBOLS) {
+    
+        report_line_at (get_filename (), lineno, REPORT_ERROR, line_start, name_caret, "too many global symbols");
+        return 0;
+    
+    }
+    
+    global_symbols[global_symbol_count].name = xstrdup (name);
+    global_symbols[global_symbol_count].kind = kind;
+    global_symbols[global_symbol_count].is_extern = is_extern;
+    global_symbols[global_symbol_count].is_dllimport = 0;
+    global_symbols[global_symbol_count].is_unsigned = 0;
+    global_symbols[global_symbol_count].is_floating = 0;
+    global_symbols[global_symbol_count].is_array = 0;
+    global_symbols[global_symbol_count].pointer_depth = 0;
+    global_symbols[global_symbol_count].pointed_size = 0;
+    global_symbols[global_symbol_count].pointed_is_floating = 0;
+    global_symbols[global_symbol_count].pointed_is_unsigned = 0;
+    global_symbols[global_symbol_count].returns_void = 0;
+    global_symbols[global_symbol_count].calling_convention = TOK_EOF;
+    
+    {
+    
+        int pi;
+        
+        for (pi = 0; pi < 128; pi++) {
+        
+            global_symbols[global_symbol_count].param_sizes[pi] = 0;
+            global_symbols[global_symbol_count].param_unsigneds[pi] = 0;
+            global_symbols[global_symbol_count].param_floatings[pi] = 0;
+            global_symbols[global_symbol_count].param_pointer_depths[pi] = 0;
+        
+        }
+    
+    }
+    
+    global_symbols[global_symbol_count].import_call_stack_bytes = 0;
+    global_symbols[global_symbol_count].param_count = 0;
+    global_symbols[global_symbol_count].has_prototype = 0;
+    global_symbols[global_symbol_count].is_variadic = 0;
+    global_symbols[global_symbol_count].is_implicit = 0;
+    global_symbols[global_symbol_count].extern_emitted = 0;
+    global_symbols[global_symbol_count].tag_name = 0;
+    
+    global_symbol_count++;
+    return 1;
+
+}
+
+static void ensure_global_function_symbol (const char *name, const char *line_start, const char *name_caret, unsigned long lineno) {
+
+    int i;
+    
+    if (!name || !*name) {
+        return;
+    }
+    
+    i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return;
+    }
+    
+    report_line_at (get_filename (), lineno, REPORT_WARNING, line_start, name_caret, "implicit declaration of function '%s'", name);
+    
+    if (add_global_symbol (name, GLOBAL_SYMBOL_FUNCTION, 1, line_start, name_caret, lineno)) {
+    
+        i = find_global_symbol (name);
+        
+        if (i >= 0) {
+        
+            global_symbols[i].calling_convention = TOK_EOF;
+            global_symbols[i].size = DATA_INT & 0x1f;
+            global_symbols[i].is_unsigned = 0;
+            global_symbols[i].is_floating = 0;
+            global_symbols[i].returns_void = 0;
+            global_symbols[i].param_count = 0;
+            global_symbols[i].has_prototype = 0;
+            global_symbols[i].is_variadic = 0;
+            global_symbols[i].is_implicit = 1;
+        
+        }
+    
+    }
+
+}
+
+#define     MAX_INLINE_FUNCTIONS        256
+
+struct inline_function_entry {
+
+    char *name;
+    char *body;
+    char *data;
+    
+    int param_count;
+    int has_prototype;
+    int returns_void;
+    int is_floating;
+    int return_size;
+    int return_label;
+    int data_emitted;
+    int expanding;
+
+    int usable;
+
+};
+
+static struct inline_function_entry inline_functions[MAX_INLINE_FUNCTIONS];
+static int inline_function_count = 0;
+
+static void clear_inline_functions (void) {
+
+    int i;
+    
+    for (i = 0; i < inline_function_count; i++) {
+    
+        free (inline_functions[i].name);
+        free (inline_functions[i].body);
+        free (inline_functions[i].data);
+        
+        inline_functions[i].name = 0;
+        inline_functions[i].body = 0;
+        inline_functions[i].data = 0;
+        inline_functions[i].param_count = 0;
+        inline_functions[i].has_prototype = 0;
+        inline_functions[i].returns_void = 0;
+        inline_functions[i].is_floating = 0;
+        inline_functions[i].return_size = 0;
+        inline_functions[i].return_label = 0;
+        inline_functions[i].data_emitted = 0;
+        inline_functions[i].expanding = 0;
+        inline_functions[i].usable = 0;
+    
+    }
+    
+    inline_function_count = 0;
+
+}
+
+static int find_inline_function (const char *name) {
+
+    int i;
+    
+    if (!name) {
+        return -1;
+    }
+    
+    for (i = 0; i < inline_function_count; i++) {
+    
+        if (strcmp (inline_functions[i].name, name) == 0) {
+            return i;
+        }
+    
+    }
+    
+    return -1;
+
+}
+
+static void remember_inline_function_signature (const char *name, int param_count, int has_prototype, int returns_void, int is_floating, int return_size) {
+
+    int i;
+    
+    if (!name || !*name) {
+        return;
+    }
+    
+    i = find_inline_function (name);
+    
+    if (i < 0) {
+    
+        if (inline_function_count >= MAX_INLINE_FUNCTIONS) {
+            return;
+        }
+        
+        i = inline_function_count++;
+        inline_functions[i].name = xstrdup (name);
+        inline_functions[i].body = 0;
+        inline_functions[i].data = 0;
+        inline_functions[i].data_emitted = 0;
+        inline_functions[i].expanding = 0;
+    
+    }
+    
+    inline_functions[i].param_count = param_count < 0 ? 0 : param_count;
+    inline_functions[i].has_prototype = has_prototype ? 1 : 0;
+    inline_functions[i].returns_void = returns_void ? 1 : 0;
+    inline_functions[i].is_floating = is_floating ? 1 : 0;
+    inline_functions[i].return_size = return_size;
+    inline_functions[i].return_label = 0;
+    inline_functions[i].data_emitted = 0;
+    inline_functions[i].expanding = 0;
+    inline_functions[i].usable = 0;
+
+}
+
+static int inline_asm_body_is_safe (const char *body) {
+
+    const char *p = body;
+    
+    if (!body) {
+        return 0;
+    }
+    
+    while (*p) {
+    
+        const char *line = p;
+        const char *eol = strchr (p, '\n');
+        
+        size_t len = eol ? (size_t) (eol - line) : strlen (line);
+        
+        while (len > 0 && (line[len - 1] == '\r' || line[len - 1] == '\n')) {
+            len--;
+        }
+        
+        while (len > 0 && (*line == ' ' || *line == '\t')) {
+        
+            line++;
+            len--;
+        
+        }
+        
+        if (len >= 4 && strncmp (line, "ret", 3) == 0) {
+            return 0;
+        }
+        
+        if (len >= 5 && strncmp (line, "leave", 5) == 0) {
+            return 0;
+        }
+        
+        if (len > 0 && line[0] == '.' && !(len >= 3 && line[1] == 'L' && line[2] >= '0' && line[2] <= '9')) {
+        
+            if (!((len == 5 && strncmp (line, ".data", 5) == 0) ||
+                  (len == 6 && strncmp (line, ".data?", 6) == 0) ||
+                  (len == 5 && strncmp (line, ".code", 5) == 0) ||
+                  (len == 5 && strncmp (line, ".text", 5) == 0) ||
+                  (len == 4 && strncmp (line, ".bss", 4) == 0))) {
+            
+                return 0;
+            
+            }
+        
+        }
+        
+        if (len >= 6 && strncmp (line, "public", 6) == 0) {
+            return 0;
+        }
+        
+        if (!eol) {
+            break;
+        }
+        
+        p = eol + 1;
+    
+    }
+    
+    return 1;
+
+}
+
+static char *extract_inline_asm_body (const char *asm_text, int return_label) {
+
+    char marker[64];
+    char *body;
+    
+    const char *start, *end;
+    size_t len;
+    
+    if (!asm_text) {
+        return 0;
+    }
+    
+    start = strstr (asm_text, "    mov rbp, rsp\n");
+    
+    if (start) {
+        start += strlen ("    mov rbp, rsp\n");
+    } else {
+    
+        start = strstr (asm_text, "    movq %rsp, %rbp\n");
+        
+        if (start) {
+            start += strlen ("    movq %rsp, %rbp\n");
+        }
+    
+    }
+    
+    if (!start) {
+        return 0;
+    }
+    
+    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+        sprintf (marker, "\nL%d:\n", return_label);
+    } else {
+        sprintf (marker, "\n.L%d:\n", return_label);
+    }
+    
+    end = strstr (start, marker);
+    
+    if (!end) {
+
+        if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+            sprintf (marker, "L%d:\n", return_label);
+        } else {
+            sprintf (marker, ".L%d:\n", return_label);
+        }
+
+        if (strncmp (start, marker, strlen (marker)) == 0) {
+            end = start;
+        } else {
+            return 0;
+        }
+
+    }
+    
+    if (*start == '\n') {
+        start++;
+    }
+    
+    len = (size_t) (end - start);
+    
+    while (len > 0 && (start[len - 1] == '\r' || start[len - 1] == '\n')) {
+        len--;
+    }
+    
+    body = xmalloc (len + 2);
+    memcpy (body, start, len);
+    
+    body[len++] = '\n';
+    body[len] = 0;
+    
+    if (!inline_asm_body_is_safe (body)) {
+    
+        free (body);
+        return 0;
+    
+    }
+    
+    return body;
+
+}
+
+static char *read_tmp_file_text (FILE *fp) {
+
+    long len;
+    char *text;
+    
+    if (!fp) {
+        return 0;
+    }
+    
+    fflush (fp);
+    
+    if (fseek (fp, 0, SEEK_END) != 0) {
+        return 0;
+    }
+    
+    len = ftell (fp);
+    
+    if (len < 0) {
+        return 0;
+    }
+    
+    if (fseek (fp, 0, SEEK_SET) != 0) {
+        return 0;
+    }
+    
+    text = xmalloc ((size_t) len + 1);
+    
+    if (len > 0 && fread (text, 1, (size_t) len, fp) != (size_t) len) {
+        free (text);
+        return 0;
+    }
+    
+    text[len] = 0;
+    return text;
+
+}
+
+static void append_inline_text (char **dst, const char *start, size_t len);
+
+static long function_frame_saved_assignment64_bytes (void) {
+
+    /*
+     * Deferred frame restoration only knows whether assignment64 register
+     * preservation was requested, not which operator triggered it.
+     *
+     * emit_preserve_assignment64_regs() saves:
+     *   - RBX only for most operators (8 bytes)
+     *   - RBX+RSI+RDI for multiply/divide/modulo paths (24 bytes)
+     *
+     * Returning a hard-coded 24 here over-allocates the frame and causes the
+     * deferred epilogue to restore registers that were never saved.
+     *
+     * Until the exact save set is tracked, defer only the always-saved RBX.
+     */
+    return current_function_preserve_assignment64_regs == 2 ? 24 : (current_function_preserve_assignment64_regs ? 8 : 0);
+
+}
+
+static void emit_function_frame_adjust_text (char **dst, long frame_size) {
+
+    char buf[128];
+    
+    long save_bytes;
+    long total_frame_bytes;
+    
+    int n;
+    
+    if (!dst) {
+        return;
+    }
+    
+    save_bytes = function_frame_saved_assignment64_bytes ();
+    
+    /*
+     * AMD64 calls must see RSP 16-byte aligned at the call instruction.
+     * After the usual "push rbp" prologue, RSP is aligned.  Any local
+     * frame allocation plus any callee-save pushes emitted here must therefore
+     * consume a multiple of 16 bytes in total.
+     *
+     * The old code rounded only the local frame to 4 bytes and ignored the
+     * optional rbx/rsi/rdi saves.  With those three pushes, a function with no
+     * locals consumed 24 bytes and every later call was misaligned.
+     */
+    if (frame_size < 0) {
+        frame_size = 0;
+    }
+    
+    total_frame_bytes = frame_size + save_bytes;
+    total_frame_bytes = (total_frame_bytes + 15) & ~15L;
+    
+    frame_size = total_frame_bytes - save_bytes;
+    
+    if (frame_size <= 0 && save_bytes <= 0) {
+        return;
+    }
+    
+    if (frame_size > 2147483647L) {
+        frame_size = 2147483647L;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (save_bytes) {
+        
+            append_inline_text (dst, "    push rbx\n", strlen ("    push rbx\n"));
+            
+            if (save_bytes == 24) {
+            
+                append_inline_text (dst, "    push rsi\n", strlen ("    push rsi\n"));
+                append_inline_text (dst, "    push rdi\n", strlen ("    push rdi\n"));
+            
+            }
+        
+        }
+        
+        if (frame_size > 0) {
+        
+            n = sprintf (buf, "    sub rsp, %ld\n", frame_size);
+            append_inline_text (dst, buf, (size_t) n);
+        
+        }
+    
+    } else {
+    
+        if (save_bytes) {
+        
+            append_inline_text (dst, "    pushq %rbx\n", strlen ("    pushq %rbx\n"));
+            
+            if (save_bytes == 24) {
+            
+                append_inline_text (dst, "    pushq %rsi\n", strlen ("    pushq %rsi\n"));
+                append_inline_text (dst, "    pushq %rdi\n", strlen ("    pushq %rdi\n"));
+            
+            }
+        
+        }
+        
+        if (frame_size > 0) {
+        
+            n = sprintf (buf, "    subq $%ld, %%rsp\n", frame_size);
+            append_inline_text (dst, buf, (size_t) n);
+        
+        }
+    
+    }
+
+}
+
+static void emit_function_frame_restore_text (char **dst, long frame_size) {
+
+    char buf[128];
+    
+    long save_bytes;
+    long total_frame_bytes;
+    
+    int n;
+    
+    if (!dst) {
+        return;
+    }
+    
+    save_bytes = function_frame_saved_assignment64_bytes ();
+    
+    if (frame_size < 0) {
+        frame_size = 0;
+    }
+    
+    total_frame_bytes = frame_size + save_bytes;
+    total_frame_bytes = (total_frame_bytes + 15) & ~15L;
+    
+    frame_size = total_frame_bytes - save_bytes;
+    
+    if (frame_size > 2147483647L) {
+        frame_size = 2147483647L;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (frame_size > 0) {
+        
+            n = sprintf (buf, "    add rsp, %ld\n", frame_size);
+            append_inline_text (dst, buf, (size_t) n);
+        
+        }
+        
+        if (save_bytes) {
+        
+            if (save_bytes == 24) {
+            
+                append_inline_text (dst, "    pop rdi\n", strlen ("    pop rdi\n"));
+                append_inline_text (dst, "    pop rsi\n", strlen ("    pop rsi\n"));
+            
+            }
+            
+            append_inline_text (dst, "    pop rbx\n", strlen ("    pop rbx\n"));
+        
+        }
+    
+    } else {
+    
+        if (frame_size > 0) {
+        
+            n = sprintf (buf, "    addq $%ld, %%rsp\n", frame_size);
+            append_inline_text (dst, buf, (size_t) n);
+        
+        }
+        
+        if (save_bytes) {
+        
+            if (save_bytes == 24) {
+            
+                append_inline_text (dst, "    popq %rdi\n", strlen ("    popq %rdi\n"));
+                append_inline_text (dst, "    popq %rsi\n", strlen ("    popq %rsi\n"));
+            
+            }
+            
+            append_inline_text (dst, "    popq %rbx\n", strlen ("    popq %rbx\n"));
+        
+        }
+    
+    }
+
+}
+
+static char *replace_function_frame_placeholder (const char *text, long frame_size) {
+
+    const char *frame_marker = "__SCC_FRAME_PLACEHOLDER__\n";
+    const char *restore_marker = "__SCC_RESTORE_ASSIGNMENT64_REGS__\n";
+    
+    const char *pr, *pf, *p;
+    const char *marker, *last;
+    
+    char *out = 0;
+    size_t marker_len;
+    
+    if (!text) {
+        return 0;
+    }
+    
+    last = text;
+    
+    for (;;) {
+    
+        pf = strstr (last, frame_marker);
+        pr = strstr (last, restore_marker);
+        
+        if (!pf && !pr) {
+            break;
+        }
+        
+        if (pf && (!pr || pf < pr)) {
+            p = pf;
+            marker = frame_marker;
+        } else {
+            p = pr;
+            marker = restore_marker;
+        }
+        
+        marker_len = strlen (marker);
+        append_inline_text (&out, last, (size_t) (p - last));
+        
+        if (marker == frame_marker) {
+            emit_function_frame_adjust_text (&out, frame_size);
+        } else {
+            emit_function_frame_restore_text (&out, frame_size);
+        }
+        
+        last = p + marker_len;
+    
+    }
+    
+    append_inline_text (&out, last, strlen (last));
+    return out;
+
+}
+
+static void append_inline_text (char **dst, const char *start, size_t len) {
+
+    size_t old_len = 0;
+    char *out;
+    
+    if (!dst || !start || len == 0) {
+        return;
+    }
+    
+    if (*dst) {
+        old_len = strlen (*dst);
+    }
+    
+    out = xmalloc (old_len + len + 1);
+    
+    if (old_len) {
+        memcpy (out, *dst, old_len);
+        free (*dst);
+    }
+    
+    memcpy (out + old_len, start, len);
+    out[old_len + len] = 0;
+    *dst = out;
+
+}
+
+static void split_inline_asm_sections (char **bodyp, char **datap) {
+
+    const char *p;
+    
+    char *body = 0;
+    char *data = 0;
+    
+    int in_data = 0;
+    
+    if (!bodyp || !*bodyp) {
+        return;
+    }
+    
+    p = *bodyp;
+    
+    while (*p) {
+    
+        const char *line = p;
+        const char *eol = strchr (p, '\n');
+        const char *next = eol ? eol + 1 : p + strlen (p);
+        
+        size_t len = (size_t) (next - line);
+        
+        const char *trim = line;
+        size_t tlen = eol ? (size_t) (eol - line) : strlen (line);
+        
+        while (tlen > 0 && (trim[tlen - 1] == '\r' || trim[tlen - 1] == '\n')) {
+            tlen--;
+        }
+        
+        while (tlen > 0 && (*trim == ' ' || *trim == '\t')) {
+        
+            trim++;
+            tlen--;
+        
+        }
+        
+        if ((tlen == 5 && strncmp (trim, ".data", 5) == 0) ||
+            (tlen == 6 && strncmp (trim, ".data?", 6) == 0) ||
+            (tlen == 4 && strncmp (trim, ".bss", 4) == 0)) {
+        
+            in_data = 1;
+            append_inline_text (&data, line, len);
+        
+        } else if ((tlen == 5 && strncmp (trim, ".code", 5) == 0) ||
+                   (tlen == 5 && strncmp (trim, ".text", 5) == 0)) {
+            in_data = 0;
+        } else if (in_data) {
+            append_inline_text (&data, line, len);
+        } else {
+            append_inline_text (&body, line, len);
+        }
+        
+        p = next;
+    
+    }
+    
+    free (*bodyp);
+    
+    *bodyp = body;
+    *datap = data;
+
+}
+
+static void remember_inline_function (const char *name, const char *asm_text, int return_label, int param_count, int has_prototype, int returns_void, int is_floating, int return_size) {
+
+    char *body;
+    char *data = 0;
+    
+    int i;
+    
+    if (!name || !*name || !asm_text) {
+        return;
+    }
+    
+    body = extract_inline_asm_body (asm_text, return_label);
+    
+    if (!body) {
+        return;
+    }
+    
+    split_inline_asm_sections (&body, &data);
+    i = find_inline_function (name);
+    
+    if (i < 0) {
+    
+        if (inline_function_count >= MAX_INLINE_FUNCTIONS) {
+        
+            free (body);
+            free (data);
+            
+            return;
+        
+        }
+        
+        i = inline_function_count++;
+        
+        inline_functions[i].name = xstrdup (name);
+        inline_functions[i].body = 0;
+        inline_functions[i].data = 0;
+        inline_functions[i].data_emitted = 0;
+        inline_functions[i].expanding = 0;
+    
+    }
+    
+    free (inline_functions[i].body);
+    free (inline_functions[i].data);
+    
+    inline_functions[i].body = body;
+    inline_functions[i].data = data;
+    inline_functions[i].data_emitted = 0;
+    inline_functions[i].param_count = param_count;
+    inline_functions[i].has_prototype = has_prototype ? 1 : 0;
+    inline_functions[i].returns_void = returns_void ? 1 : 0;
+    inline_functions[i].is_floating = is_floating ? 1 : 0;
+    inline_functions[i].return_size = return_size;
+    inline_functions[i].return_label = return_label;
+    inline_functions[i].expanding = 0;
+    inline_functions[i].usable = 1;
+
+}
+
+static void emit_inline_label_reference (int label, int return_label, int call_id) {
+
+    if (label == return_label) {
+    
+        if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+            fprintf (state->ofp, "L%d", call_id);
+        } else {
+            fprintf (state->ofp, ".L%d", call_id);
+        }
+    
+    } else {
+    
+        if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+            fprintf (state->ofp, "L%d_%d", label, call_id);
+        } else {
+            fprintf (state->ofp, ".L%d_%d", label, call_id);
+        }
+    
+    }
+
+}
+
+static int emit_inline_parameter_reference_if_any (const char **pp, int argc, int stack_bytes) {
+
+    const char *p = *pp;
+    const char *q;
+    
+    int offset = 0;
+    int param_index;
+    int stack_offset;
+    
+    if (!(state->syntax & ASM_SYNTAX_MASM)) {
+        return 0;
+    }
+    
+    if (*p != '[') {
+        return 0;
+    }
+    
+    q = p + 1;
+    
+    while (*q == ' ' || *q == '\t') {
+        q++;
+    }
+    
+    if (strncmp (q, "rbp", 3) != 0) {
+        return 0;
+    }
+    
+    q += 3;
+    
+    while (*q == ' ' || *q == '\t') {
+        q++;
+    }
+    
+    if (*q != '+') {
+        return 0;
+    }
+    
+    q++;
+    
+    while (*q == ' ' || *q == '\t') {
+        q++;
+    }
+    
+    if (*q < '0' || *q > '9') {
+        return 0;
+    }
+    
+    while (*q >= '0' && *q <= '9') {
+    
+        offset = (offset * 10) + (*q - '0');
+        q++;
+    
+    }
+    
+    while (*q == ' ' || *q == '\t') {
+        q++;
+    }
+    
+    if (*q != ']') {
+        return 0;
+    }
+    
+    if (offset < 8 || ((offset - 8) % 8) != 0) {
+        return 0;
+    }
+    
+    param_index = (offset - 8) / 8;
+    
+    if (param_index < 0 || param_index >= argc) {
+        return 0;
+    }
+    
+    /*
+     * Inline arguments are copied into a compiler-owned temporary stack
+     * area before the inline body is emitted.  Parameter 0 lives at the
+     * lowest address in that area, so [rbp + 8] maps to [rsp],
+     * [rbp + 16] maps to [rsp + 8], [rbp + 24] maps to [rsp + 16], etc.
+     * If the inlined body changes RSP temporarily, stack_bytes keeps all
+     * parameter references pointed at the same argument copies.
+     */
+    stack_offset = stack_bytes + (param_index * 8);
+    
+    if (stack_offset == 0) {
+        fprintf (state->ofp, "[rsp]");
+    } else if (stack_offset > 0) {
+        fprintf (state->ofp, "[rsp + %d]", stack_offset);
+    } else {
+        fprintf (state->ofp, "[rsp - %d]", -stack_offset);
+    }
+    
+    *pp = q + 1;
+    return 1;
+
+}
+
+static void emit_inline_line_substituted (const char *line, size_t len, int return_label, int call_id, int argc, int stack_bytes) {
+
+    const char *p = line;
+    const char *end = line + len;
+    
+    while (p < end) {
+    
+        if ((state->syntax & ASM_SYNTAX_MASM) && *p == 'L' && p + 1 < end && p[1] >= '0' && p[1] <= '9') {
+        
+            const char *q = p + 1;
+            int label = 0;
+            
+            while (q < end && *q >= '0' && *q <= '9') {
+            
+                label = (label * 10) + (*q - '0');
+                q++;
+            
+            }
+            
+            emit_inline_label_reference (label, return_label, call_id);
+            p = q;
+            
+            continue;
+        
+        }
+        
+        if (!(state->syntax & ASM_SYNTAX_MASM) && p + 2 < end && p[0] == '.' && p[1] == 'L' && p[2] >= '0' && p[2] <= '9') {
+        
+            const char *q = p + 2;
+            int label = 0;
+            
+            while (q < end && *q >= '0' && *q <= '9') {
+            
+                label = (label * 10) + (*q - '0');
+                q++;
+            
+            }
+            
+            emit_inline_label_reference (label, return_label, call_id);
+            p = q;
+            
+            continue;
+        
+        }
+        
+        if (emit_inline_parameter_reference_if_any (&p, argc, stack_bytes)) {
+            continue;
+        }
+        
+        fputc (*p++, state->ofp);
+    
+    }
+
+}
+
+static int inline_line_stack_delta (const char *line, size_t len) {
+
+    const char *p = line;
+    long n = 0;
+    int neg = 0;
+    
+    while (len > 0 && (*p == ' ' || *p == '\t')) {
+    
+        p++;
+        len--;
+    
+    }
+    
+    while (len > 0 && (p[len - 1] == '\r' || p[len - 1] == '\n' || p[len - 1] == ' ' || p[len - 1] == '\t')) {
+        len--;
+    }
+    
+    if (len >= 4 && strncmp (p, "push", 4) == 0 && (p[4] == ' ' || p[4] == '\t')) {
+        return 8;
+    }
+    
+    if (len >= 3 && strncmp (p, "pop", 3) == 0 && (p[3] == ' ' || p[3] == '\t')) {
+        return -8;
+    }
+    
+    if (len >= 8 && (strncmp (p, "sub rsp,", 8) == 0 || strncmp (p, "add rsp,", 8) == 0)) {
+    
+        neg = (p[0] == 'a');
+        
+        p += 8;
+        len -= 8;
+        
+        while (len > 0 && (*p == ' ' || *p == '\t')) {
+        
+            p++;
+            len--;
+        
+        }
+        
+        while (len > 0 && *p >= '0' && *p <= '9') {
+        
+            n = (n * 10) + (*p - '0');
+            
+            p++;
+            len--;
+        
+        }
+        
+        return neg ? -(int) n : (int) n;
+    
+    }
+    
+    if (len >= 10 && (strncmp (p, "subq $", 6) == 0 || strncmp (p, "addq $", 6) == 0)) {
+    
+        neg = (p[0] == 'a');
+        
+        p += 6;
+        len -= 6;
+        
+        while (len > 0 && *p >= '0' && *p <= '9') {
+        
+            n = (n * 10) + (*p - '0');
+            
+            p++;
+            len--;
+        
+        }
+        
+        while (len > 0 && (*p == ' ' || *p == '\t')) {
+        
+            p++;
+            len--;
+        
+        }
+        
+        if (len >= 6 && strncmp (p, ", %rsp", 6) == 0) {
+            return neg ? -(int) n : (int) n;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int inline_body_stack_delta (const char *body) {
+
+    const char *p = body;
+    int stack_bytes = 0;
+    
+    if (!body) {
+        return 0;
+    }
+    
+    while (*p) {
+    
+        const char *line = p;
+        const char *eol = strchr (p, '\n');
+        const char *next = eol ? eol + 1 : p + strlen (p);
+        size_t len = (size_t) (next - line);
+        
+        stack_bytes += inline_line_stack_delta (line, len);
+        p = next;
+    
+    }
+    
+    return stack_bytes;
+
+}
+
+static int inline_parse_mov_rax_imm (const char *line, int64_s *value) {
+
+    const char *p = line;
+    
+    char buf[128];
+    size_t len = 0;
+    
+    if (!value) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, "mov rax,", 8) != 0) {
+        return 0;
+    }
+    
+    p += 8;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (*p == '-') {
+    
+        if (len + 1 >= sizeof (buf)) {
+            return 0;
+        }
+        
+        buf[len++] = *p++;
+    
+    }
+    
+    if (*p < '0' || *p > '9') {
+        return 0;
+    }
+    
+    while (*p >= '0' && *p <= '9') {
+    
+        if (len + 1 >= sizeof (buf)) {
+            return 0;
+        }
+        
+        buf[len++] = *p++;
+    
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '\0') {
+        return 0;
+    }
+    
+    buf[len] = '\0';
+    parse_string_to_i64 (value, buf);
+    
+    return 1;
+
+}
+
+static int inline_parse_mov_rdx_imm (const char *line, int64_s *value) {
+
+    const char *p = line;
+    
+    char buf[128];
+    size_t len = 0;
+    
+    if (!value) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, "mov rdx,", 8) != 0) {
+        return 0;
+    }
+    
+    p += 8;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (*p == '-') {
+    
+        if (len + 1 >= sizeof (buf)) {
+            return 0;
+        }
+        
+        buf[len++] = *p++;
+    
+    }
+    
+    if (*p < '0' || *p > '9') {
+        return 0;
+    }
+    
+    while (*p >= '0' && *p <= '9') {
+    
+        if (len + 1 >= sizeof (buf)) {
+            return 0;
+        }
+        
+        buf[len++] = *p++;
+    
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '\0') {
+        return 0;
+    }
+    
+    buf[len] = '\0';
+    parse_string_to_i64 (value, buf);
+    
+    return 1;
+
+}
+
+static void inline_format_mov_imm64 (char *buf, size_t buf_size, const char *reg, int64_s value) {
+
+    if (!buf || buf_size == 0 || !reg) {
+        return;
+    }
+    
+    sprintf (buf, "    mov %s, 0%08lX%08lXh\n", reg, value.high & U32_MASK, value.low & U32_MASK);
+
+}
+
+static int inline_line_is_exact (const char *line, const char *text) {
+
+    const char *p = line;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, text, strlen (text)) != 0) {
+        return 0;
+    }
+    
+    p += strlen (text);
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '\0';
+
+}
+
+
+static int inline_parse_jump_label (const char *line, const char *op, char *label, size_t label_size);
+
+static void inline_i64_from_long (int64_s *out, long v) {
+    sext64 (out, v);
+}
+
+static void inline_sar64 (int64_s *a, int n) {
+
+    int fill;
+    int i;
+    
+    if (!a || n <= 0) {
+        return;
+    }
+    
+    if (n > 63) {
+        n = 63;
+    }
+    
+    fill = int64_is_negative (*a) ? 1 : 0;
+    
+    for (i = 0; i < n; i++) {
+    
+        a->low = ((a->low >> 1) | ((a->high & 1UL) << 31)) & U32_MASK;
+        a->high = ((a->high >> 1) | (fill ? 0x80000000UL : 0)) & U32_MASK;
+    
+    }
+
+}
+
+static void inline_abs64 (int64_s *v) {
+
+    if (v && int64_is_negative (*v)) {
+        neg64 (v);
+    }
+
+}
+
+static int inline_fold_binary_rax_rdx (const char *line, int64_s lhs, int64_s rhs, int64_s *out) {
+
+    int64_s r = lhs;
+    
+    if (!line || !out) {
+        return 0;
+    }
+    
+    if (inline_line_is_exact (line, "add rax, rdx")) {
+        add64 (&r, rhs);
+    } else if (inline_line_is_exact (line, "sub rax, rdx")) {
+        sub64 (&r, rhs);
+    } else if (inline_line_is_exact (line, "imul rax, rdx")) {
+        mul64 (&r, rhs);
+    } else if (inline_line_is_exact (line, "and rax, rdx")) {
+        and64 (&r, rhs);
+    } else if (inline_line_is_exact (line, "or rax, rdx")) {
+        or64 (&r, rhs);
+    } else if (inline_line_is_exact (line, "xor rax, rdx")) {
+        xor64 (&r, rhs);
+    } else {
+        return 0;
+    }
+    
+    *out = r;
+    return 1;
+
+}
+
+static int inline_fold_shift_rax_rdx (const char *line, int64_s lhs, int64_s rhs, int64_s *out) {
+
+    int64_s r = lhs;
+    unsigned int count;
+    
+    if (!line || !out) {
+        return 0;
+    }
+    
+    count = (unsigned int) (rhs.low & 63UL);
+    
+    if (inline_line_is_exact (line, "shl rax, cl")) {
+        shl64 (&r, count);
+    } else if (inline_line_is_exact (line, "sal rax, cl")) {
+        shl64 (&r, count);
+    } else if (inline_line_is_exact (line, "sar rax, cl")) {
+        inline_sar64 (&r, count);
+    } else if (inline_line_is_exact (line, "shr rax, cl")) {
+        shr64 (&r, count);
+    } else {
+        return 0;
+    }
+    
+    *out = r;
+    return 1;
+
+}
+
+static int inline_fold_div_rax_rdx (int64_s lhs, int64_s rhs, int64_s *out) {
+
+    int64_s a = lhs;
+    int64_s b = rhs;
+    
+    int neg;
+    
+    if (!out || is_zero64 (b)) {
+        return 0;
+    }
+    
+    neg = (int64_is_negative (a) ? 1 : 0) ^ (int64_is_negative (b) ? 1 : 0);
+    
+    inline_abs64 (&a);
+    inline_abs64 (&b);
+    
+    div64 (&a, b);
+    
+    if (neg) {
+        neg64 (&a);
+    }
+    
+    *out = a;
+    return 1;
+
+}
+
+static int inline_fold_mod_rax_rdx (int64_s lhs, int64_s rhs, int64_s *out) {
+
+    int64_s a = lhs;
+    int64_s b = rhs;
+    
+    int neg;
+    
+    if (!out || is_zero64 (b)) {
+        return 0;
+    }
+    
+    neg = int64_is_negative (a) ? 1 : 0;
+    
+    inline_abs64 (&a);
+    inline_abs64 (&b);
+    
+    mod64 (&a, b);
+    
+    if (neg) {
+        neg64 (&a);
+    }
+    
+    *out = a;
+    return 1;
+
+}
+
+static int inline_parse_cond_jump_label (const char *line, char *op, size_t op_size, char *label, size_t label_size) {
+
+    static const char *const ops[] = {
+        "jz", "jnz", "je", "jne", "ja", "jae", "jb", "jbe",
+        "jg", "jge", "jl", "jle", "js", "jns", 0
+    };
+    
+    int i;
+    
+    if (!op || op_size == 0) {
+        return 0;
+    }
+    
+    for (i = 0; ops[i]; i++) {
+    
+        if (inline_parse_jump_label (line, ops[i], label, label_size)) {
+        
+            strncpy (op, ops[i], op_size - 1);
+            op[op_size - 1] = '\0';
+            
+            return 1;
+        
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int inline_eval_test_jump (const char *op, int64_s value) {
+
+    if (strcmp (op, "jz") == 0 || strcmp (op, "je") == 0) {
+        return is_zero64 (value);
+    }
+    
+    if (strcmp (op, "jnz") == 0 || strcmp (op, "jne") == 0) {
+        return !is_zero64 (value);
+    }
+    
+    if (strcmp (op, "js") == 0) {
+        return int64_is_negative (value);
+    }
+    
+    if (strcmp (op, "jns") == 0) {
+        return !int64_is_negative (value);
+    }
+    
+    return 0;
+
+}
+
+static int inline_eval_cmp_jump (const char *op, int64_s lhs, int64_s rhs) {
+
+    if (strcmp (op, "jz") == 0 || strcmp (op, "je") == 0) {
+        return eq64 (lhs, rhs);
+    }
+    
+    if (strcmp (op, "jnz") == 0 || strcmp (op, "jne") == 0) {
+        return neq64 (lhs, rhs);
+    }
+    
+    if (strcmp (op, "jg") == 0) {
+        return gt64_signed (lhs, rhs);
+    }
+    
+    if (strcmp (op, "jge") == 0) {
+        return gte64_signed (lhs, rhs);
+    }
+    
+    if (strcmp (op, "jl") == 0) {
+        return lt64_signed (lhs, rhs);
+    }
+    
+    if (strcmp (op, "jle") == 0) {
+        return lte64_signed (lhs, rhs);
+    }
+    
+    if (strcmp (op, "ja") == 0) {
+        return gt64_unsigned (lhs, rhs);
+    }
+    
+    if (strcmp (op, "jae") == 0) {
+        return gte64_unsigned (lhs, rhs);
+    }
+    
+    if (strcmp (op, "jb") == 0) {
+        return lt64_unsigned (lhs, rhs);
+    }
+    
+    if (strcmp (op, "jbe") == 0) {
+        return lte64_unsigned (lhs, rhs);
+    }
+    
+    return 0;
+
+}
+
+static int inline_parse_jump_label (const char *line, const char *op, char *label, size_t label_size) {
+
+    const char *p = line;
+    size_t n = 0;
+    
+    if (!label || label_size == 0) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, op, strlen (op)) != 0) {
+        return 0;
+    }
+    
+    p += strlen (op);
+    
+    if (*p != ' ' && *p != '\t') {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_' || *p == '.')) {
+        return 0;
+    }
+    
+    while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') ||
+           (*p >= '0' && *p <= '9') || *p == '_' || *p == '.') {
+    
+        if (n + 1 < label_size) {
+            label[n++] = *p;
+        }
+        
+        p++;
+    }
+    
+    label[n] = '\0';
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '\0';
+
+}
+
+
+
+static int inline_parse_any_jump_label (const char *line, char *label, size_t label_size) {
+
+    static const char *const ops[] = {
+        "jmp", "jz", "jnz", "je", "jne", "jc", "jnc",
+        "ja", "jae", "jb", "jbe", "jg", "jge", "jl", "jle",
+        "js", "jns", "jo", "jno", "jp", "jpe", "jnp", "jpo",
+        0
+    };
+    
+    int i;
+    
+    for (i = 0; ops[i]; i++) {
+    
+        if (inline_parse_jump_label (line, ops[i], label, label_size)) {
+            return 1;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int inline_parse_label_definition (const char *line, char *label, size_t label_size) {
+
+    const char *p = line;
+    size_t n = 0;
+    
+    if (!label || label_size == 0) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_' || *p == '.')) {
+        return 0;
+    }
+    
+    while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') ||
+           (*p >= '0' && *p <= '9') || *p == '_' || *p == '.') {
+    
+        if (n + 1 < label_size) {
+            label[n++] = *p;
+        }
+        
+        p++;
+    }
+    
+    label[n] = '\0';
+    
+    if (*p != ':') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '\0';
+
+}
+
+static const char *inline_find_chain_target (char **from, char **to, int count, const char *label) {
+
+    int i;
+    
+    if (!label) {
+        return 0;
+    }
+    
+    for (i = 0; i < count; i++) {
+    
+        if (from[i] && to[i] && strcmp (from[i], label) == 0) {
+            return to[i];
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static void inline_copy_string (char *dst, const char *src, size_t dst_size) {
+
+    size_t len;
+    
+    if (!dst || dst_size == 0) {
+        return;
+    }
+    
+    if (!src) {
+    
+        dst[0] = '\0';
+        return;
+    
+    }
+    
+    len = strlen (src);
+    
+    if (len >= dst_size) {
+        len = dst_size - 1;
+    }
+    
+    memcpy (dst, src, len);
+    dst[len] = '\0';
+
+}
+
+static int inline_resolve_jump_chain (char **from, char **to, int count, const char *label, char *out, size_t out_size) {
+
+    const char *cur = label;
+    const char *next;
+    
+    int changed = 0;
+    int depth = 0;
+    
+    if (!label || !out || out_size == 0) {
+        return 0;
+    }
+    
+    while (depth++ < count) {
+    
+        next = inline_find_chain_target (from, to, count, cur);
+        
+        if (!next || strcmp (next, cur) == 0) {
+            break;
+        }
+        
+        cur = next;
+        changed = 1;
+    
+    }
+    
+    if (!changed || strcmp (cur, label) == 0) {
+        return 0;
+    }
+    
+    if (out && cur && out_size > 0) {
+        inline_copy_string (out, cur, out_size);
+    }
+    
+    return 1;
+
+}
+
+static int inline_parse_rsp_reference (const char *p, int *offset) {
+
+    const char *start = p;
+    
+    int off = 0;
+    int neg = 0;
+    
+    if (strncmp (p, "[rsp]", 5) == 0) {
+    
+        *offset = 0;
+        return 5;
+    
+    }
+    
+    if (strncmp (p, "[rsp + ", 7) == 0) {
+        p += 7;
+    } else if (strncmp (p, "[rsp+", 5) == 0) {
+        p += 5;
+    } else if (strncmp (p, "[rsp - ", 7) == 0) {
+        neg = 1;
+        p += 7;
+    } else if (strncmp (p, "[rsp-", 5) == 0) {
+        neg = 1;
+        p += 5;
+    } else {
+        return 0;
+    }
+    
+    if (*p < '0' || *p > '9') {
+        return 0;
+    }
+    
+    while (*p >= '0' && *p <= '9') {
+    
+        off = (off * 10) + (*p - '0');
+        p++;
+    
+    }
+    
+    if (*p != ']') {
+        return 0;
+    }
+    
+    *offset = neg ? -off : off;
+    return (int) ((p + 1) - start);
+
+}
+
+static int inline_parse_store_rax_to_rsp (const char *line, int *offset) {
+
+    const char *p = line;
+    int n;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, "mov qword ptr ", 14) == 0) {
+        p += 14;
+    } else if (strncmp (p, "mov qword ", 10) == 0) {
+        p += 10;
+    } else {
+        return 0;
+    }
+    
+    n = inline_parse_rsp_reference (p, offset);
+    
+    if (!n) {
+        return 0;
+    }
+    
+    p += n;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, ", rax", 5) != 0) {
+        return 0;
+    }
+    
+    p += 5;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '\0';
+
+}
+
+static int inline_parse_load_rax_from_rsp (const char *line, int *offset) {
+
+    const char *p = line;
+    int n;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, "mov rax, qword ptr ", 19) == 0) {
+        p += 19;
+    } else if (strncmp (p, "mov rax, qword ", 15) == 0) {
+        p += 15;
+    } else {
+        return 0;
+    }
+    
+    n = inline_parse_rsp_reference (p, offset);
+    
+    if (!n) {
+        return 0;
+    }
+    
+    p += n;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '\0';
+
+}
+
+static int inline_parse_load_rdx_from_rsp (const char *line, int *offset) {
+
+    const char *p = line;
+    int n;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, "mov rdx, qword ptr ", 19) == 0) {
+        p += 19;
+    } else if (strncmp (p, "mov rdx, qword ", 15) == 0) {
+        p += 15;
+    } else {
+        return 0;
+    }
+    
+    n = inline_parse_rsp_reference (p, offset);
+    
+    if (!n) {
+        return 0;
+    }
+    
+    p += n;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '\0';
+
+}
+
+static int inline_parse_addsub_rsp_imm1 (const char *line, int *offset, long *delta) {
+
+    const char *p = line;
+    int n;
+    int is_sub = 0;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, "add qword ptr ", 14) == 0) {
+        p += 14;
+    } else if (strncmp (p, "add qword ", 10) == 0) {
+        p += 10;
+    } else if (strncmp (p, "sub qword ptr ", 14) == 0) {
+    
+        is_sub = 1;
+        p += 14;
+    
+    } else if (strncmp (p, "sub qword ", 10) == 0) {
+    
+        is_sub = 1;
+        p += 10;
+    
+    } else {
+        return 0;
+    }
+    
+    n = inline_parse_rsp_reference (p, offset);
+    
+    if (!n) {
+        return 0;
+    }
+    
+    p += n;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, ", 1", 3) != 0) {
+        return 0;
+    }
+    
+    p += 3;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '\0') {
+        return 0;
+    }
+    
+    *delta = is_sub ? -1 : 1;
+    return 1;
+
+}
+
+static char *inline_dup_text_slice (const char *start, size_t len) {
+
+    char *out = (char *) malloc (len + 1);
+    
+    if (!out) {
+        return 0;
+    }
+    
+    memcpy (out, start, len);
+    out[len] = '\0';
+    
+    return out;
+
+}
+
+static void inline_clear_slots (int *slot_valid, int64_s *slot_value) {
+
+    int i;
+    
+    for (i = 0; i < 64; i++) {
+    
+        slot_valid[i] = 0;
+        slot_value[i].low = 0;
+        slot_value[i].high = 0;
+    
+    }
+
+}
+
+static void emit_inline_optimized_text (const char *text, FILE *ofp) {
+
+    const char *p = text;
+    
+    char **lines;
+    char **repl;
+    
+    int *skip;
+    int *store_slot;
+    int count = 0;
+    int i;
+    
+    int64_s slot_value[64];
+    int64_s rax_value;
+    
+    int slot_valid[64];
+    int slot_real_read[64];
+    
+    int rax_valid = 0;
+    int alloc_line = -1;
+    int free_line = -1;
+    int alloc_bytes = 0;
+    int can_remove_area = 0;
+    
+    char **chain_from = 0;
+    char **chain_to = 0;
+    
+    int *label_refs = 0;
+    
+    if (!text || !ofp) {
+        return;
+    }
+    
+    rax_value.low = 0;
+    rax_value.high = 0;
+    
+    for (p = text; *p; p++) {
+    
+        if (*p == '\n') {
+            count++;
+        }
+    
+    }
+    
+    if (p != text && p[-1] != '\n') {
+        count++;
+    }
+    
+    if (count <= 0) {
+        return;
+    }
+    
+    lines = (char **) calloc ((size_t) count, sizeof (*lines));
+    repl = (char **) calloc ((size_t) count, sizeof (*repl));
+    skip = (int *) calloc ((size_t) count, sizeof (*skip));
+    store_slot = (int *) malloc ((size_t) count * sizeof (*store_slot));
+    chain_from = (char **) calloc ((size_t) count, sizeof (*chain_from));
+    chain_to = (char **) calloc ((size_t) count, sizeof (*chain_to));
+    label_refs = (int *) calloc ((size_t) count, sizeof (*label_refs));
+    
+    if (!lines || !repl || !skip || !store_slot || !chain_from || !chain_to || !label_refs) {
+    
+        free (lines);
+        free (repl);
+        free (skip);
+        free (store_slot);
+        free (chain_from);
+        free (chain_to);
+        free (label_refs);
+        
+        fputs (text, ofp);
+        return;
+    
+    }
+    
+    for (i = 0; i < count; i++) {
+        store_slot[i] = -1;
+    }
+    
+    p = text;
+    i = 0;
+    
+    while (*p && i < count) {
+    
+        const char *line = p;
+        const char *eol = strchr (p, '\n');
+        const char *next = eol ? eol + 1 : p + strlen (p);
+        size_t len = (size_t) (next - line);
+        
+        lines[i++] = inline_dup_text_slice (line, len);
+        p = next;
+    
+    }
+    
+    count = i;
+    inline_clear_slots (slot_valid, slot_value);
+    
+    for (i = 0; i < 64; i++) {
+        slot_real_read[i] = 0;
+    }
+    
+    for (i = 0; i < count; i++) {
+    
+        char *buf = lines[i];
+        int offset;
+        int slot;
+        int64_s value;
+        long mem_delta;
+        int delta;
+        
+        if (!buf) {
+            continue;
+        }
+        
+        delta = inline_line_stack_delta (buf, strlen (buf));
+        
+        if (delta > 0 && alloc_line < 0) {
+        
+            alloc_line = i;
+            alloc_bytes = delta;
+            
+            rax_valid = 0;
+            continue;
+        
+        }
+        
+        if (delta < 0 && alloc_line >= 0 && -delta == alloc_bytes) {
+        
+            free_line = i;
+            rax_valid = 0;
+            
+            continue;
+        
+        }
+        
+        if (inline_parse_mov_rax_imm (buf, &value)) {
+        
+            rax_value = value;
+            rax_valid = 1;
+            
+            continue;
+        
+        }
+        
+        if (inline_parse_store_rax_to_rsp (buf, &offset)) {
+        
+            if (offset >= 0 && (offset % 8) == 0) {
+            
+                slot = offset / 8;
+                
+                if (slot >= 0 && slot < 64) {
+                
+                    store_slot[i] = slot;
+                    
+                    if (rax_valid) {
+                    
+                        slot_valid[slot] = 1;
+                        slot_value[slot] = rax_value;
+                    
+                    } else {
+                        slot_valid[slot] = 0;
+                    }
+                
+                }
+            
+            }
+            
+            continue;
+        
+        }
+        
+        if (inline_parse_load_rax_from_rsp (buf, &offset)) {
+        
+            if (offset >= 0 && (offset % 8) == 0) {
+            
+                slot = offset / 8;
+                
+                if (slot >= 0 && slot < 64 && slot_valid[slot]) {
+                
+                    char tmp[128];
+                    inline_format_mov_imm64 (tmp, sizeof (tmp), "rax", slot_value[slot]);
+                    
+                    repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+                    
+                    rax_value = slot_value[slot];
+                    rax_valid = 1;
+                    
+                    continue;
+                
+                }
+                
+                if (slot >= 0 && slot < 64) {
+                    slot_real_read[slot] = 1;
+                }
+            
+            }
+            
+            rax_valid = 0;
+            continue;
+        }
+        
+        if (inline_parse_load_rdx_from_rsp (buf, &offset)) {
+        
+            if (offset >= 0 && (offset % 8) == 0) {
+            
+                slot = offset / 8;
+                
+                if (slot >= 0 && slot < 64 && slot_valid[slot]) {
+                
+                    char tmp[128];
+                    inline_format_mov_imm64 (tmp, sizeof (tmp), "rdx", slot_value[slot]);
+                    
+                    repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+                    continue;
+                
+                }
+                
+                if (slot >= 0 && slot < 64) {
+                    slot_real_read[slot] = 1;
+                }
+            
+            }
+            
+            continue;
+        
+        }
+        
+        if (inline_parse_addsub_rsp_imm1 (buf, &offset, &mem_delta)) {
+        
+            if (offset >= 0 && (offset % 8) == 0) {
+            
+                slot = offset / 8;
+                
+                if (slot >= 0 && slot < 64) {
+                
+                    if (slot_valid[slot]) {
+                    
+                        int64_s delta_value;
+                        
+                        inline_i64_from_long (&delta_value, mem_delta);
+                        add64 (&slot_value[slot], delta_value);
+                        
+                        skip[i] = 1;
+                    
+                    }
+                    
+                    continue;
+                }
+            }
+            
+            rax_valid = 0;
+            continue;
+        
+        }
+        
+        if (strstr (buf, "rsp")) {
+        
+            inline_clear_slots (slot_valid, slot_value);
+            rax_valid = 0;
+        
+        } else if (strstr (buf, "rax")) {
+            rax_valid = 0;
+        }
+    
+    }
+    
+    if (alloc_line >= 0 && free_line > alloc_line && alloc_bytes > 0) {
+    
+        int any_remaining_rsp = 0;
+        int slots = alloc_bytes / 8;
+        
+        for (i = 0; i < count; i++) {
+        
+            if (i == alloc_line || i == free_line) {
+                continue;
+            }
+            
+            if (store_slot[i] >= 0 && store_slot[i] < slots && !slot_real_read[store_slot[i]]) {
+                continue;
+            }
+            
+            if (repl[i]) {
+            
+                if (strstr (repl[i], "rsp")) {
+                    any_remaining_rsp = 1;
+                    break;
+                }
+            
+            } else if (lines[i] && strstr (lines[i], "rsp")) {
+            
+                any_remaining_rsp = 1;
+                break;
+            
+            }
+        
+        }
+        
+        if (!any_remaining_rsp) {
+        
+            can_remove_area = 1;
+            skip[alloc_line] = 1;
+            skip[free_line] = 1;
+            
+            for (i = 0; i < count; i++) {
+            
+                if (store_slot[i] >= 0 && store_slot[i] < slots && !slot_real_read[store_slot[i]]) {
+                    skip[i] = 1;
+                }
+            
+            }
+            
+            /*
+             * If an argument copy was folded away, the immediately precrding
+             * constant load was only there to feed that copy.  Drop it too;
+             * otherwise multi-argument inline calls leave noise like:
+             *
+             *     mov rax, 1
+             *     mov rax, 2
+             *
+             * after both temporary argument stores have been removed.
+             */
+            for (i = 0; i < count; i++) {
+            
+                int64_s ignored_value;
+                int j;
+                
+                if (!skip[i] || store_slot[i] < 0) {
+                    continue;
+                }
+                
+                for (j = i - 1; j >= 0; j--) {
+                
+                    if (skip[j]) {
+                        continue;
+                    }
+                    
+                    if (inline_parse_mov_rax_imm (lines[j], &ignored_value)) {
+                        skip[j] = 1;
+                    }
+                    
+                    break;
+                
+                }
+            
+            }
+        
+        }
+    
+    }
+    
+    (void) can_remove_area;
+    
+    for (i = 0; i < count; i++) {
+    
+        int64_s first_value;
+        int j;
+        
+        if (skip[i] || !lines[i] || !inline_parse_mov_rax_imm (lines[i], &first_value)) {
+            continue;
+        }
+        
+        for (j = i + 1; j < count; j++) {
+        
+            int64_s next_value;
+            const char *check;
+            
+            if (skip[j]) {
+                continue;
+            }
+            
+            check = repl[j] ? repl[j] : lines[j];
+            
+            if (!check) {
+                continue;
+            }
+            
+            if (!strstr (check, "rax")) {
+                continue;
+            }
+            
+            if (inline_parse_mov_rax_imm (check, &next_value) && eq64 (next_value, first_value)) {
+                skip[i] = 1;
+            }
+            
+            break;
+        
+        }
+    
+    }
+    
+    for (i = 0; i + 3 < count; i++) {
+    
+        int64_s lhs;
+        int64_s rhs;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        
+        int taken;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        
+        if (!l0 || !l1 || !l2 || !l3) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "cmp rax, rdx")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l3, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_cmp_jump (opbuf, lhs, rhs);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[i]);
+            
+            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+        
+        } else {
+        
+            skip[i] = 1;
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+        
+        }
+    
+    }
+    
+    for (i = 0; i + 4 < count; i++) {
+    
+        int64_s lhs;
+        int64_s rhs;
+        
+        char false_label[128];
+        char true_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "cmp rax, rdx")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l3, opbuf, sizeof (opbuf), false_label, sizeof (false_label))) {
+            continue;
+        }
+        
+        if (!inline_parse_jump_label (l4, "jmp", true_label, sizeof (true_label))) {
+            continue;
+        }
+        
+        sprintf (tmp, "    jmp %s\n", inline_eval_cmp_jump (opbuf, lhs, rhs) ? false_label : true_label);
+        free (repl[i]);
+        
+        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+        
+        skip[i + 1] = 1;
+        skip[i + 2] = 1;
+        skip[i + 3] = 1;
+        skip[i + 4] = 1;
+    
+    }
+    
+    for (i = 0; i + 4 < count; i++) {
+
+        int64_s lhs;
+        int64_s rhs;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        
+        int taken;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_fold_binary_rax_rdx (l2, lhs, rhs, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l3, "test rax, rax")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l4, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_test_jump (opbuf, lhs);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[i]);
+            
+            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+        
+        } else {
+        
+            skip[i] = 1;
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+        
+        }
+    
+    }
+    
+    for (i = 0; i + 5 < count; i++) {
+    
+        int64_s lhs;
+        int64_s rhs;
+        int64_s cmp_rhs;
+        int64_s folded;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        
+        int taken;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_fold_binary_rax_rdx (l2, lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l3, &cmp_rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l4, "cmp rax, rdx")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l5, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_cmp_jump (opbuf, folded, cmp_rhs);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[i]);
+            
+            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+        
+        } else {
+        
+            skip[i] = 1;
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+        
+        }
+    
+    }
+    
+    for (i = 0; i + 5 < count; i++) {
+    
+        int64_s lhs;
+        int64_s rhs;
+        
+        char false_label[128];
+        char true_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_fold_binary_rax_rdx (l2, lhs, rhs, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l3, "test rax, rax")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l4, opbuf, sizeof (opbuf), false_label, sizeof (false_label))) {
+            continue;
+        }
+        
+        if (!inline_parse_jump_label (l5, "jmp", true_label, sizeof (true_label))) {
+            continue;
+        }
+        
+        sprintf (tmp, "    jmp %s\n", inline_eval_test_jump (opbuf, lhs) ? false_label : true_label);
+        free (repl[i]);
+        
+        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+        
+        skip[i + 1] = 1;
+        skip[i + 2] = 1;
+        skip[i + 3] = 1;
+        skip[i + 4] = 1;
+        skip[i + 5] = 1;
+    
+    }
+    
+    for (i = 0; i + 6 < count; i++) {
+    
+        int64_s lhs;
+        int64_s rhs;
+        int64_s cmp_rhs;
+        int64_s folded;
+        
+        int jump_taken = 0;
+        
+        char cond_label[128];
+        char fall_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        const char *l6;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_fold_binary_rax_rdx (l2, lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l3, &cmp_rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l4, "cmp rax, rdx")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l5, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        jump_taken = inline_eval_cmp_jump (opbuf, folded, cmp_rhs);
+        
+        if (!inline_parse_jump_label (l6, "jmp", fall_label, sizeof (fall_label))) {
+            continue;
+        }
+        
+        sprintf (tmp, "    jmp %s\n", jump_taken ? cond_label : fall_label);
+        free (repl[i]);
+        
+        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+        
+        skip[i + 1] = 1;
+        skip[i + 2] = 1;
+        skip[i + 3] = 1;
+        skip[i + 4] = 1;
+        skip[i + 5] = 1;
+        skip[i + 6] = 1;
+    
+    }
+    
+    for (i = 0; i + 5 < count; i++) {
+
+        int64_s lhs;
+        int64_s rhs;
+        int64_s folded;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        
+        int taken;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov rcx, rdx")) {
+            continue;
+        }
+        
+        if (!inline_fold_shift_rax_rdx (l3, lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l4, "test rax, rax")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l5, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_test_jump (opbuf, folded);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[i]);
+            
+            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+        
+        } else {
+        
+            skip[i] = 1;
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+        
+        }
+    
+    }
+    
+    for (i = 0; i + 6 < count; i++) {
+    
+        int64_s lhs;
+        int64_s rhs;
+        int64_s cmp_rhs;
+        int64_s folded;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        const char *l6;
+        
+        int taken;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov rcx, rdx")) {
+            continue;
+        }
+        
+        if (!inline_fold_shift_rax_rdx (l3, lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l4, &cmp_rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l5, "cmp rax, rdx")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l6, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_cmp_jump (opbuf, folded, cmp_rhs);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[i]);
+            
+            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+            skip[i + 6] = 1;
+        
+        } else {
+        
+            skip[i] = 1;
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+            skip[i + 6] = 1;
+        
+        }
+    
+    }
+    
+    for (i = 0; i + 6 < count; i++) {
+    
+        int64_s lhs;
+        int64_s rhs;
+        int64_s folded;
+        
+        char false_label[128];
+        char true_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        const char *l6;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov rcx, rdx")) {
+            continue;
+        }
+        
+        if (!inline_fold_shift_rax_rdx (l3, lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l4, "test rax, rax")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l5, opbuf, sizeof (opbuf), false_label, sizeof (false_label))) {
+            continue;
+        }
+        
+        if (!inline_parse_jump_label (l6, "jmp", true_label, sizeof (true_label))) {
+            continue;
+        }
+        
+        sprintf (tmp, "    jmp %s\n", inline_eval_test_jump (opbuf, folded) ? false_label : true_label);
+        free (repl[i]);
+        
+        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+        
+        skip[i + 1] = 1;
+        skip[i + 2] = 1;
+        skip[i + 3] = 1;
+        skip[i + 4] = 1;
+        skip[i + 5] = 1;
+        skip[i + 6] = 1;
+    
+    }
+    
+    for (i = 0; i + 7 < count; i++) {
+    
+        int64_s lhs;
+        int64_s rhs;
+        int64_s cmp_rhs;
+        int64_s folded;
+        
+        int jump_taken = 0;
+        
+        char cond_label[128];
+        char fall_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        const char *l6;
+        const char *l7;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
+        l7 = repl[i + 7] ? repl[i + 7] : lines[i + 7];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6 || !l7) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov rcx, rdx")) {
+            continue;
+        }
+        
+        if (!inline_fold_shift_rax_rdx (l3, lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l4, &cmp_rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l5, "cmp rax, rdx")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l6, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        jump_taken = inline_eval_cmp_jump (opbuf, folded, cmp_rhs);
+        
+        if (!inline_parse_jump_label (l7, "jmp", fall_label, sizeof (fall_label))) {
+            continue;
+        }
+        
+        sprintf (tmp, "    jmp %s\n", jump_taken ? cond_label : fall_label);
+        free (repl[i]);
+        
+        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+        
+        skip[i + 1] = 1;
+        skip[i + 2] = 1;
+        skip[i + 3] = 1;
+        skip[i + 4] = 1;
+        skip[i + 5] = 1;
+        skip[i + 6] = 1;
+        skip[i + 7] = 1;
+    
+    }
+    
+    for (i = 0; i + 6 < count; i++) {
+    
+        int64_s lhs;
+        int64_s rhs;
+        int64_s folded;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        const char *l6;
+        
+        int taken;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov rcx, rdx") || !inline_line_is_exact (l3, "cdq") ||
+            !inline_line_is_exact (l4, "idiv rcx")) {
+            continue;
+        }
+        
+        if (!inline_fold_div_rax_rdx (lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l5, "test rax, rax")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l6, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_test_jump (opbuf, folded);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[i]);
+            
+            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+            skip[i + 6] = 1;
+        
+        } else {
+        
+            skip[i] = 1;
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+            skip[i + 6] = 1;
+        
+        }
+    
+    }
+    
+    for (i = 0; i + 7 < count; i++) {
+    
+        int64_s lhs;
+        int64_s rhs;
+        int64_s cmp_rhs;
+        int64_s folded;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        const char *l6;
+        const char *l7;
+        
+        int taken;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
+        l7 = repl[i + 7] ? repl[i + 7] : lines[i + 7];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6 || !l7) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov rcx, rdx") || !inline_line_is_exact (l3, "cdq") ||
+            !inline_line_is_exact (l4, "idiv rcx")) {
+            continue;
+        }
+        
+        if (!inline_fold_div_rax_rdx (lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l5, &cmp_rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l6, "cmp rax, rdx")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l7, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_cmp_jump (opbuf, folded, cmp_rhs);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[i]);
+            
+            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+            skip[i + 6] = 1;
+            skip[i + 7] = 1;
+        
+        } else {
+        
+            skip[i] = 1;
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+            skip[i + 6] = 1;
+            skip[i + 7] = 1;
+        
+        }
+    
+    }
+    
+    for (i = 0; i + 7 < count; i++) {
+    
+        int64_s lhs;
+        int64_s rhs;
+        int64_s folded;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        const char *l6;
+        const char *l7;
+        
+        int taken;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
+        l7 = repl[i + 7] ? repl[i + 7] : lines[i + 7];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6 || !l7) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov rcx, rdx") || !inline_line_is_exact (l3, "cdq") ||
+            !inline_line_is_exact (l4, "idiv rcx") || !inline_line_is_exact (l5, "mov rax, rdx")) {
+            continue;
+        }
+        
+        if (!inline_fold_mod_rax_rdx (lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l6, "test rax, rax")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l7, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_test_jump (opbuf, folded);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[i]);
+            
+            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+            skip[i + 6] = 1;
+            skip[i + 7] = 1;
+        
+        } else {
+        
+            skip[i] = 1;
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+            skip[i + 6] = 1;
+            skip[i + 7] = 1;
+        
+        }
+    
+    }
+    
+    for (i = 0; i + 8 < count; i++) {
+    
+        int64_s lhs;
+        int64_s rhs;
+        int64_s cmp_rhs;
+        int64_s folded;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        const char *l6;
+        const char *l7;
+        const char *l8;
+        
+        int taken;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
+        l7 = repl[i + 7] ? repl[i + 7] : lines[i + 7];
+        l8 = repl[i + 8] ? repl[i + 8] : lines[i + 8];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6 || !l7 || !l8) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov rcx, rdx") || !inline_line_is_exact (l3, "cdq") ||
+            !inline_line_is_exact (l4, "idiv rcx") || !inline_line_is_exact (l5, "mov rax, rdx")) {
+            continue;
+        }
+        
+        if (!inline_fold_mod_rax_rdx (lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l6, &cmp_rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l7, "cmp rax, rdx")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l8, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_cmp_jump (opbuf, folded, cmp_rhs);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[i]);
+            
+            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+            skip[i + 6] = 1;
+            skip[i + 7] = 1;
+            skip[i + 8] = 1;
+        
+        } else {
+        
+            skip[i] = 1;
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+            skip[i + 6] = 1;
+            skip[i + 7] = 1;
+            skip[i + 8] = 1;
+        
+        }
+    
+    }
+    
+    for (i = 0; i + 2 < count; i++) {
+    
+        int64_s lhs;
+        int64_s rhs;
+        int64_s folded;
+        
+        char tmp[128];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        
+        if (skip[i] || skip[i + 1] || skip[i + 2]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        
+        if (!l0 || !l1 || !l2) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_fold_binary_rax_rdx (l2, lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        inline_format_mov_imm64 (tmp, sizeof (tmp), "rax", folded);
+        free (repl[i]);
+        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+        
+        skip[i + 1] = 1;
+        skip[i + 2] = 1;
+    
+    }
+    
+    for (i = 0; i + 3 < count; i++) {
+    
+        int64_s lhs;
+        int64_s rhs;
+        int64_s folded;
+        
+        char tmp[128];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        
+        if (skip[i] || skip[i + 1] || skip[i + 2] || skip[i + 3]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        
+        if (!l0 || !l1 || !l2 || !l3) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov rcx, rdx")) {
+            continue;
+        }
+        
+        if (!inline_fold_shift_rax_rdx (l3, lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        inline_format_mov_imm64 (tmp, sizeof (tmp), "rax", folded);
+        free (repl[i]);
+        
+        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+        
+        skip[i + 1] = 1;
+        skip[i + 2] = 1;
+        skip[i + 3] = 1;
+    
+    }
+    
+    for (i = 0; i + 4 < count; i++) {
+    
+        int64_s lhs;
+        int64_s rhs;
+        int64_s folded;
+        
+        char tmp[128];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        
+        if (skip[i] || skip[i + 1] || skip[i + 2] || skip[i + 3] || skip[i + 4]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov rcx, rdx") || !inline_line_is_exact (l3, "cdq") ||
+            !inline_line_is_exact (l4, "idiv rcx")) {
+            continue;
+        }
+        
+        if (!inline_fold_div_rax_rdx (lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        inline_format_mov_imm64 (tmp, sizeof (tmp), "rax", folded);
+        free (repl[i]);
+        
+        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+        
+        skip[i + 1] = 1;
+        skip[i + 2] = 1;
+        skip[i + 3] = 1;
+        skip[i + 4] = 1;
+    
+    }
+    
+    for (i = 0; i + 5 < count; i++) {
+    
+        int64_s lhs;
+        int64_s rhs;
+        int64_s folded;
+        
+        char tmp[128];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        
+        if (skip[i] || skip[i + 1] || skip[i + 2] || skip[i + 3] || skip[i + 4] || skip[i + 5]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov rcx, rdx") || !inline_line_is_exact (l3, "cdq") ||
+            !inline_line_is_exact (l4, "idiv rcx") || !inline_line_is_exact (l5, "mov rax, rdx")) {
+            continue;
+        }
+        
+        if (!inline_fold_mod_rax_rdx (lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        inline_format_mov_imm64 (tmp, sizeof (tmp), "rax", folded);
+        free (repl[i]);
+        
+        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+        
+        skip[i + 1] = 1;
+        skip[i + 2] = 1;
+        skip[i + 3] = 1;
+        skip[i + 4] = 1;
+        skip[i + 5] = 1;
+    
+    }
+    
+    /*
+     * Some compound-expression folds, such as x += 1, are reduced only by
+     * the late arithmetic pass above.  Run the constant compare/branch fold
+     * again here so newly-created sequences like:
+     *
+     *     mov rax, 9
+     *     mov rdx, 9
+     *     cmp rax, rdx
+     *     jne Lx
+     *
+     * are folded after the arithmetic result becomes visible.
+     */
+    for (i = 0; i + 3 < count; i++) {
+    
+        int64_s lhs;
+        int64_s rhs;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        
+        int taken;
+        
+        if (skip[i] || skip[i + 1] || skip[i + 2] || skip[i + 3]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        
+        if (!l0 || !l1 || !l2 || !l3) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "cmp rax, rdx")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l3, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_cmp_jump (opbuf, lhs, rhs);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[i]);
+            
+            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+        
+        } else {
+        
+            skip[i] = 1;
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+        
+        }
+    
+    }
+    
+    /*
+     * A late fold can leave useful instructions separated by skipped source
+     * lines.  For example x += 1 followed by == may become:
+     *
+     *     mov rax, 9
+     *     ; skipped old rhs/op lines
+     *     mov rdx, 9
+     *     cmp rax, rdx
+     *     jne Lx
+     *
+     * The normal adjacent compare fold cannot see through the skipped lines,
+     * so do one compacting pass over the remaining live instructions.
+     */
+    for (i = 0; i < count; i++) {
+    
+        int j0;
+        int j1;
+        int j2;
+        int j3;
+        
+        int64_s lhs;
+        int64_s rhs;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        
+        int taken;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        j0 = i;
+        j1 = j0 + 1;
+        
+        while (j1 < count && skip[j1]) {
+            j1++;
+        }
+        
+        j2 = j1 + 1;
+        
+        while (j2 < count && skip[j2]) {
+            j2++;
+        }
+        
+        j3 = j2 + 1;
+        
+        while (j3 < count && skip[j3]) {
+            j3++;
+        }
+        
+        if (j1 >= count || j2 >= count || j3 >= count) {
+            continue;
+        }
+        
+        l0 = repl[j0] ? repl[j0] : lines[j0];
+        l1 = repl[j1] ? repl[j1] : lines[j1];
+        l2 = repl[j2] ? repl[j2] : lines[j2];
+        l3 = repl[j3] ? repl[j3] : lines[j3];
+        
+        if (!l0 || !l1 || !l2 || !l3) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_rdx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "cmp rax, rdx")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l3, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_cmp_jump (opbuf, lhs, rhs);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[j0]);
+            
+            repl[j0] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[j1] = 1;
+            skip[j2] = 1;
+            skip[j3] = 1;
+        
+        } else {
+        
+            skip[j0] = 1;
+            skip[j1] = 1;
+            skip[j2] = 1;
+            skip[j3] = 1;
+        
+        }
+    
+    }
+    
+    for (i = 0; i < count; i++) {
+    
+        char label[128];
+        char target[128];
+        const char *line;
+        int j;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        line = repl[i] ? repl[i] : lines[i];
+        
+        if (!line || !inline_parse_label_definition (line, label, sizeof (label))) {
+            continue;
+        }
+        
+        for (j = i + 1; j < count; j++) {
+        
+            const char *next_line;
+            
+            if (skip[j]) {
+                continue;
+            }
+            
+            next_line = repl[j] ? repl[j] : lines[j];
+            
+            if (!next_line) {
+                continue;
+            }
+            
+            if (inline_parse_jump_label (next_line, "jmp", target, sizeof (target))) {
+            
+                if (strcmp (label, target) != 0) {
+                
+                    chain_from[i] = inline_dup_text_slice (label, strlen (label));
+                    chain_to[i] = inline_dup_text_slice (target, strlen (target));
+                
+                }
+            
+            }
+            
+            break;
+        
+        }
+    
+    }
+    
+    for (i = 0; i < count; i++) {
+    
+        char target[128];
+        char resolved[128];
+        char tmp[192];
+        const char *line;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        line = repl[i] ? repl[i] : lines[i];
+        
+        if (!line || !inline_parse_jump_label (line, "jmp", target, sizeof (target))) {
+            continue;
+        }
+        
+        if (!inline_resolve_jump_chain (chain_from, chain_to, count, target, resolved, sizeof (resolved))) {
+            continue;
+        }
+        
+        sprintf (tmp, "    jmp %s\n", resolved);
+        free (repl[i]);
+        
+        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+    
+    }
+    
+    for (i = 0; i < count; i++) {
+    
+        char target[128];
+        const char *line;
+        int j;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        line = repl[i] ? repl[i] : lines[i];
+        
+        if (!line || !inline_parse_any_jump_label (line, target, sizeof (target))) {
+            continue;
+        }
+        
+        for (j = 0; j < count; j++) {
+        
+            char label[128];
+            const char *def;
+            
+            if (skip[j]) {
+                continue;
+            }
+            
+            def = repl[j] ? repl[j] : lines[j];
+            
+            if (def && inline_parse_label_definition (def, label, sizeof (label)) && strcmp (label, target) == 0) {
+            
+                label_refs[j]++;
+                break;
+            
+            }
+        
+        }
+    
+    }
+    
+    for (i = 0; i < count; i++) {
+    
+        char target[128];
+        const char *line;
+        int j;
+        int target_line = -1;
+        int can_delete = 1;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        line = repl[i] ? repl[i] : lines[i];
+        
+        if (!line || !inline_parse_jump_label (line, "jmp", target, sizeof (target))) {
+            continue;
+        }
+        
+        for (j = i + 1; j < count; j++) {
+        
+            char label[128];
+            const char *check;
+            
+            if (skip[j]) {
+                continue;
+            }
+            
+            check = repl[j] ? repl[j] : lines[j];
+            
+            if (check && inline_parse_label_definition (check, label, sizeof (label)) && strcmp (label, target) == 0) {
+            
+                target_line = j;
+                break;
+            
+            }
+        
+        }
+        
+        if (target_line < 0) {
+            continue;
+        }
+        
+        for (j = i + 1; j < target_line; j++) {
+        
+            char label[128];
+            const char *check;
+            
+            if (skip[j]) {
+                continue;
+            }
+            
+            check = repl[j] ? repl[j] : lines[j];
+            
+            if (check && inline_parse_label_definition (check, label, sizeof (label)) && label_refs[j] > 0) {
+            
+                can_delete = 0;
+                break;
+            
+            }
+        
+        }
+        
+        if (!can_delete) {
+            continue;
+        }
+        
+        for (j = i + 1; j < target_line; j++) {
+            skip[j] = 1;
+        }
+    
+    }
+    
+    for (i = 0; i < count; i++) {
+    
+        char target[128];
+        const char *line;
+        int j;
+        int target_line = -1;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        line = repl[i] ? repl[i] : lines[i];
+        
+        if (!line || !inline_parse_jump_label (line, "jmp", target, sizeof (target))) {
+            continue;
+        }
+        
+        for (j = i + 1; j < count; j++) {
+        
+            char label[128];
+            const char *check;
+            
+            if (skip[j]) {
+                continue;
+            }
+            
+            check = repl[j] ? repl[j] : lines[j];
+            
+            if (!check) {
+                continue;
+            }
+            
+            if (inline_parse_label_definition (check, label, sizeof (label))) {
+            
+                if (strcmp (label, target) == 0) {
+                    target_line = j;
+                }
+                
+                break;
+            
+            }
+            
+            break;
+        
+        }
+        
+        if (target_line >= 0) {
+            skip[i] = 1;
+        }
+    
+    }
+    
+    /*
+     * Branch folding can create new unreachable ranges after the earlier
+     * jump cleanup has already run.  Recompute label references from the
+     * current non-skipped text and remove dead fall-through ranges between
+     * an unconditional jump and its later target.  This deliberately keeps
+     * referenced labels, so externally reachable or still-jumped-to blocks
+     * are not discarded.
+     */
+    {
+    
+        int changed;
+        int pass;
+        
+        for (pass = 0; pass < count; pass++) {
+        
+            changed = 0;
+            
+            for (i = 0; i < count; i++) {
+                label_refs[i] = 0;
+            }
+            
+            for (i = 0; i < count; i++) {
+            
+                char target[128];
+                const char *line;
+                int j;
+                
+                if (skip[i]) {
+                    continue;
+                }
+                
+                line = repl[i] ? repl[i] : lines[i];
+                
+                if (!line || !inline_parse_any_jump_label (line, target, sizeof (target))) {
+                    continue;
+                }
+                
+                for (j = 0; j < count; j++) {
+                
+                    char label[128];
+                    const char *def;
+                    
+                    if (skip[j]) {
+                        continue;
+                    }
+                    
+                    def = repl[j] ? repl[j] : lines[j];
+                    
+                    if (def && inline_parse_label_definition (def, label, sizeof (label)) && strcmp (label, target) == 0) {
+                    
+                        label_refs[j]++;
+                        break;
+                    
+                    }
+                
+                }
+            
+            }
+            
+            for (i = 0; i < count; i++) {
+            
+                char target[128];
+                const char *line;
+                int j;
+                int target_line = -1;
+                int can_delete = 1;
+                
+                if (skip[i]) {
+                    continue;
+                }
+                
+                line = repl[i] ? repl[i] : lines[i];
+                
+                if (!line || !inline_parse_jump_label (line, "jmp", target, sizeof (target))) {
+                    continue;
+                }
+                
+                for (j = i + 1; j < count; j++) {
+                
+                    char label[128];
+                    const char *check;
+                    
+                    if (skip[j]) {
+                        continue;
+                    }
+                    
+                    check = repl[j] ? repl[j] : lines[j];
+                    
+                    if (check && inline_parse_label_definition (check, label, sizeof (label)) && strcmp (label, target) == 0) {
+                    
+                        target_line = j;
+                        break;
+                    
+                    }
+                
+                }
+                
+                if (target_line < 0) {
+                    continue;
+                }
+                
+                for (j = i + 1; j < target_line; j++) {
+                
+                    char label[128];
+                    const char *check;
+                    
+                    if (skip[j]) {
+                        continue;
+                    }
+                    
+                    check = repl[j] ? repl[j] : lines[j];
+                    
+                    if (check && inline_parse_label_definition (check, label, sizeof (label)) && label_refs[j] > 0) {
+                    
+                        can_delete = 0;
+                        break;
+                    
+                    }
+                
+                }
+                
+                if (!can_delete) {
+                    continue;
+                }
+                
+                for (j = i + 1; j < target_line; j++) {
+                
+                    if (!skip[j]) {
+                    
+                        skip[j] = 1;
+                        changed = 1;
+                    
+                    }
+                
+                }
+            
+            }
+            
+            if (!changed) {
+                break;
+            }
+        
+        }
+    
+    }
+    
+    /*
+     * The second unreachable-code pass can expose a new fall-through jump,
+     * for example "jmp L9" immediately followed by "L9:".  Run this small
+     * cleanup again at the end so later branch/unreachable optimisations do
+     * not leave the already-handled form behind.
+     */
+    for (i = 0; i < count; i++) {
+    
+        char target[128];
+        const char *line;
+        int j;
+        int target_line = -1;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        line = repl[i] ? repl[i] : lines[i];
+        
+        if (!line || !inline_parse_jump_label (line, "jmp", target, sizeof (target))) {
+            continue;
+        }
+        
+        for (j = i + 1; j < count; j++) {
+        
+            char label[128];
+            const char *check;
+            
+            if (skip[j]) {
+                continue;
+            }
+            
+            check = repl[j] ? repl[j] : lines[j];
+            
+            if (!check) {
+                continue;
+            }
+            
+            if (inline_parse_label_definition (check, label, sizeof (label))) {
+            
+                if (strcmp (label, target) == 0) {
+                    target_line = j;
+                }
+                
+                break;
+            
+            }
+            
+            break;
+        
+        }
+        
+        if (target_line >= 0) {
+            skip[i] = 1;
+        }
+    
+    }
+    
+    for (i = 0; i < count; i++) {
+    
+        if (!skip[i]) {
+            fputs (repl[i] ? repl[i] : (lines[i] ? lines[i] : ""), ofp);
+        }
+        
+        free (lines[i]);
+        free (repl[i]);
+    
+    }
+    
+    for (i = 0; i < count; i++) {
+    
+        free (chain_from[i]);
+        free (chain_to[i]);
+    
+    }
+    
+    free (lines);
+    free (repl);
+    free (skip);
+    free (store_slot);
+    free (chain_from);
+    free (chain_to);
+    free (label_refs);
+
+}
+
+static void finish_inline_buffer (FILE **tmp, FILE **saved, int optimize) {
+
+    FILE *out;
+    long size;
+    char *buf;
+    
+    if (!tmp || !saved || !*tmp || !*saved) {
+        return;
+    }
+    
+    out = *saved;
+    
+    fflush (*tmp);
+    fseek (*tmp, 0, SEEK_END);
+    
+    size = ftell (*tmp);
+    fseek (*tmp, 0, SEEK_SET);
+    
+    if (size > 0) {
+    
+        buf = (char *) malloc ((size_t) size + 1);
+        
+        if (buf) {
+        
+            if (fread (buf, 1, (size_t) size, *tmp) == (size_t) size) {
+            
+                buf[size] = '\0';
+                
+                if (optimize) {
+                    emit_inline_optimized_text (buf, out);
+                } else {
+                    fwrite (buf, 1, (size_t) size, out);
+                }
+            
+            }
+            
+            free (buf);
+        
+        }
+    
+    }
+    
+    scc_close (*tmp);
+    
+    *tmp = 0;
+    *saved = 0;
+    
+    state->ofp = out;
+
+}
+
+static void emit_inline_body_substituted (const char *body, int return_label, int argc) {
+
+    const char *p = body;
+    
+    int call_id = anon_label++;
+    int stack_bytes = 0;
+    
+    if (!body || !state->ofp) {
+        return;
+    }
+    
+    while (*p) {
+    
+        const char *line = p;
+        const char *eol = strchr (p, '\n');
+        const char *next = eol ? eol + 1 : p + strlen (p);
+        size_t len = (size_t) (next - line);
+        
+        emit_inline_line_substituted (line, len, return_label, call_id, argc, stack_bytes);
+        stack_bytes += inline_line_stack_delta (line, len);
+        p = next;
+    
+    }
+    
+    if (body[0] && body[strlen (body) - 1] != '\n') {
+        fputc ('\n', state->ofp);
+    }
+    
+    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+        fprintf (state->ofp, "L%d:\n", call_id);
+    } else {
+        fprintf (state->ofp, ".L%d:\n", call_id);
+    }
+
+}
+
+static int emit_inline_call_if_possible (const char *name, int argc, const char *reg) {
+
+    int i = find_inline_function (name);
+    
+    if (i < 0 || !inline_functions[i].usable) {
+        return 0;
+    }
+    
+    if (argc != inline_functions[i].param_count) {
+        return 0;
+    }
+    
+    if (inline_functions[i].is_floating) {
+        return 0;
+    }
+    
+    if (inline_functions[i].expanding) {
+        return 0;
+    }
+    
+    if (!state->ofp) {
+        return 1;
+    }
+    
+    if (!inline_functions[i].body && !inline_functions[i].returns_void) {
+        return 0;
+    }
+    
+    if (inline_functions[i].body && inline_body_stack_delta (inline_functions[i].body) != 0) {
+        return 0;
+    }
+    
+    if (inline_functions[i].data && !inline_functions[i].data_emitted) {
+    
+        fputs (inline_functions[i].data, state->ofp);
+        
+        if (inline_functions[i].data[0] && inline_functions[i].data[strlen (inline_functions[i].data) - 1] != '\n') {
+            fputc ('\n', state->ofp);
+        }
+        
+        if (state->syntax & ASM_SYNTAX_MASM) {
+            fprintf (state->ofp, ".code\n");
+        } else if (state->syntax & ASM_SYNTAX_NASM) {
+            fprintf (state->ofp, "section .text\n");
+        } else {
+            fprintf (state->ofp, ".text\n");
+        }
+        
+        inline_functions[i].data_emitted = 1;
+    
+    }
+    
+    if (inline_functions[i].body) {
+    
+        inline_functions[i].expanding = 1;
+        emit_inline_body_substituted (inline_functions[i].body, inline_functions[i].return_label, argc);
+        inline_functions[i].expanding = 0;
+    
+    }
+    
+    if (!inline_functions[i].returns_void && strcmp (reg, "rax") != 0) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    mov %s, rax\n", reg);
+        } else {
+            fprintf (state->ofp, "    movq %%rax, %%%s\n", reg);
+        }
+    
+    }
+    
+    return 1;
+
+}
+
+static int local_array_pointer_step_size (const struct local_symbol *sym);
+static int global_array_pointer_step_size (const char *name);
+
+static int aggregate_tag_size_or_zero (const char *tag_name) {
+
+    struct aggregate_tag_entry *entry;
+    
+    if (!tag_name || !tag_name[0]) {
+        return 0;
+    }
+    
+    entry = find_aggregate_tag (tag_name, 0);
+    
+    if (entry && entry->size > 0) {
+        return entry->size;
+    }
+    
+    return 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 void reset_local_symbols (void) {
+
+    int i;
+    
+    for (i = 0; i < local_symbol_count; i++) {
+    
+        if (local_symbols[i].name) {
+        
+            free (local_symbols[i].name);
+            local_symbols[i].name = 0;
+        
+        }
+        
+        if (local_symbols[i].static_label) {
+        
+            free (local_symbols[i].static_label);
+            local_symbols[i].static_label = 0;
+        
+        }
+        
+        if (local_symbols[i].pointed_tag_name) {
+        
+            free (local_symbols[i].pointed_tag_name);
+            local_symbols[i].pointed_tag_name = 0;
+        
+        }
+        
+        if (local_symbols[i].tag_name) {
+        
+            free (local_symbols[i].tag_name);
+            local_symbols[i].tag_name = 0;
+        
+        }
+    
+    }
+    
+    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;
+    current_function_preserve_assignment64_regs = 0;
+    current_function_is_variadic = 0;
+
+}
+
+static void truncate_local_symbols (int count, long stack_size) {
+
+    int i;
+    
+    if (count < 0) {
+        count = 0;
+    }
+    
+    for (i = count; i < local_symbol_count; i++) {
+    
+        if (local_symbols[i].name) {
+        
+            free (local_symbols[i].name);
+            local_symbols[i].name = 0;
+        
+        }
+        
+        if (local_symbols[i].static_label) {
+        
+            free (local_symbols[i].static_label);
+            local_symbols[i].static_label = 0;
+        
+        }
+        
+        if (local_symbols[i].pointed_tag_name) {
+        
+            free (local_symbols[i].pointed_tag_name);
+            local_symbols[i].pointed_tag_name = 0;
+        
+        }
+        
+        if (local_symbols[i].tag_name) {
+        
+            free (local_symbols[i].tag_name);
+            local_symbols[i].tag_name = 0;
+        
+        }
+    
+    }
+    
+    local_symbol_count = count;
+    current_local_stack_size = stack_size;
+
+}
+
+static int local_symbol_exists_in_current_scope (const char *name, int start_count) {
+
+    int i;
+    
+    if (!name) {
+        return 0;
+    }
+    
+    for (i = start_count; i < local_symbol_count; i++) {
+    
+        if (local_symbols[i].name && strcmp (local_symbols[i].name, name) == 0) {
+            return 1;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static long add_local_symbol (const char *name, int size, int align, int is_unsigned, int scope_start_count, int line, const char *start, const char *caret) {
+
+    long new_size;
+    
+    if (!name) {
+        return 0;
+    }
+    
+    if (size < 1) {
+        size = 1;
+    }
+    
+    if (align < 1) {
+        align = 1;
+    }
+    
+    if (local_symbol_exists_in_current_scope (name, scope_start_count)) {
+    
+        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "duplicate local symbol '%s'", name);
+        return 0;
+    
+    }
+    
+    if (local_symbol_count >= MAX_LOCAL_SYMBOLS) {
+    
+        report_line_at (get_filename (), line, REPORT_ERROR, start, caret,  "too many local symbols");
+        return 0;
+    
+    }
+    
+    new_size = align_up_long (current_local_stack_size + size, align);
+    
+    /*
+     * EBP-relative locals must be backed by whole stack slots.  Without this,
+     * a byte-sized local following two pointer locals can be assigned offset
+     * -9(%rbp), while the emitted stack adjustment has only reserved 8 bytes.
+     * That is exactly what happened in cpplib/lex.c's _cpp_skip_block_comment:
+     *
+     *     cpp_mffc *mffc;   -> -4
+     *     const char *pos;  -> -8
+     *     char c;           -> -9, outside the reserved frame
+     *
+     * Keep the object's real size for loads/stores, but round the frame growth
+     * so subsequent stack allocation reserves enough bytes before the local is
+     * used.
+     */
+    new_size = align_up_long (new_size, 8);
+    
+    local_symbols[local_symbol_count].name = xstrdup (name);
+    local_symbols[local_symbol_count].size = size;
+    local_symbols[local_symbol_count].align = align;
+    local_symbols[local_symbol_count].offset = -(int) new_size;
+    local_symbols[local_symbol_count].is_static = 0;
+    local_symbols[local_symbol_count].static_label = 0;
+    local_symbols[local_symbol_count].is_unsigned = is_unsigned ? 1 : 0;
+    local_symbols[local_symbol_count].is_floating = 0;
+    local_symbols[local_symbol_count].is_array = 0;
+    local_symbols[local_symbol_count].array_element_size = 0;
+    local_symbols[local_symbol_count].array_dimensions = 0;
+    local_symbols[local_symbol_count].pointer_depth = 0;
+    local_symbols[local_symbol_count].pointed_size = 0;
+    local_symbols[local_symbol_count].pointed_is_floating = 0;
+    local_symbols[local_symbol_count].pointed_is_unsigned = 0;
+    local_symbols[local_symbol_count].pointed_tag_name = 0;
+    local_symbols[local_symbol_count].tag_name = 0;
+    
+    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;
+
+}
+
+static void add_static_local_symbol (const char *name, const char *label, int size, int align, int is_unsigned, int scope_start_count, int line, const char *start, const char *caret) {
+
+    if (!name || !label) {
+        return;
+    }
+    
+    if (size < 1) {
+        size = 1;
+    }
+    
+    if (align < 1) {
+        align = 1;
+    }
+    
+    if (local_symbol_exists_in_current_scope (name, scope_start_count)) {
+    
+        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "duplicate local symbol '%s'", name);
+        return;
+    
+    }
+    
+    if (local_symbol_count >= MAX_LOCAL_SYMBOLS) {
+    
+        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "too many local symbols");
+        return;
+    
+    }
+    
+    local_symbols[local_symbol_count].name = xstrdup (name);
+    local_symbols[local_symbol_count].static_label = xstrdup (label);
+    local_symbols[local_symbol_count].size = size;
+    local_symbols[local_symbol_count].align = align;
+    local_symbols[local_symbol_count].offset = 0;
+    local_symbols[local_symbol_count].is_static = 1;
+    local_symbols[local_symbol_count].is_unsigned = is_unsigned ? 1 : 0;
+    local_symbols[local_symbol_count].is_floating = 0;
+    local_symbols[local_symbol_count].is_array = 0;
+    local_symbols[local_symbol_count].array_element_size = 0;
+    local_symbols[local_symbol_count].array_dimensions = 0;
+    local_symbols[local_symbol_count].pointer_depth = 0;
+    local_symbols[local_symbol_count].pointed_size = 0;
+    local_symbols[local_symbol_count].pointed_is_floating = 0;
+    local_symbols[local_symbol_count].pointed_is_unsigned = 0;
+    local_symbols[local_symbol_count].pointed_tag_name = 0;
+    local_symbols[local_symbol_count].tag_name = 0;
+       
+    local_symbol_count++;
+
+}
+
+static void set_local_symbol_array (const char *name, int is_array) {
+
+    struct local_symbol *sym = find_local_symbol (name);
+    
+    if (sym) {
+        sym->is_array = is_array ? 1 : 0;
+    }
+
+}
+
+static void set_local_symbol_array_element_size (const char *name, int elem_size) {
+
+    struct local_symbol *sym = find_local_symbol (name);
+    
+    if (sym) {
+        sym->array_element_size = elem_size > 0 ? elem_size : 0;
+    }
+
+}
+
+static void set_local_symbol_array_dimensions (const char *name, int dims) {
+
+    struct local_symbol *sym = find_local_symbol (name);
+    
+    if (sym) {
+        sym->array_dimensions = dims > 0 ? dims : 0;
+    }
+
+}
+
+static void set_local_symbol_floating (const char *name, int is_floating) {
+
+    int i;
+    
+    if (!name) {
+        return;
+    }
+    
+    for (i = local_symbol_count - 1; i >= 0; i--) {
+    
+        if (local_symbols[i].name && strcmp (local_symbols[i].name, name) == 0) {
+        
+            local_symbols[i].is_floating = is_floating ? 1 : 0;
+            return;
+        
+        }
+    
+    }
+
+}
+
+static int local_symbol_exists_in_current_scope (const char *name, int start_count);
+
+static int find_pending_param (const char *name) {
+    return find_pending_param_from (name, 0);
+}
+
+static void update_pending_param (const char *name, int size, int align, int is_unsigned, int is_floating, int pointer_depth, int pointed_size, int pointed_is_unsigned) {
+
+    int i = find_pending_param (name);
+    
+    if (i < 0) {
+        return;
+    }
+    
+    if (pointer_depth > 0 && parsed_type_is_aggregate && parsed_type_size > (DATA_PTR & 0x1f) && pointed_size <= (DATA_PTR & 0x1f)) {
+        pointed_size = parsed_type_size;
+    }
+    
+    if (size < 1) {
+        size = DATA_INT & 0x1f;
+    }
+    
+    if (align < 1) {
+        align = type_alignment (size);
+    }
+    
+    pending_params[i].size = size;
+    pending_params[i].align = align;
+    pending_params[i].is_unsigned = is_unsigned ? 1 : 0;
+    pending_params[i].is_floating = is_floating ? 1 : 0;
+    pending_params[i].pointer_depth = pointer_depth;
+    pending_params[i].pointed_size = pointed_size > 0 ? pointed_size : 0;
+    pending_params[i].pointed_is_floating = pointer_depth > 0 ? (parsed_type_is_floating ? 1 : 0) : 0;
+    pending_params[i].pointed_is_unsigned = pointer_depth > 0 ? (pointed_is_unsigned ? 1 : 0) : 0;
+    
+    if (pending_params[i].pointed_tag_name) {
+    
+        free (pending_params[i].pointed_tag_name);
+        pending_params[i].pointed_tag_name = 0;
+    
+    }
+    
+    if (pointer_depth > 0 && parsed_type_tag_name[0]) {
+        pending_params[i].pointed_tag_name = xstrdup (parsed_type_tag_name);
+    }
+
+}
+
+static int mark_pending_param_knr_declared (const char *name, const char *name_start, const char *name_caret, unsigned long name_line) {
+
+    int i = find_pending_param (name);
+    
+    if (i < 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "K&R parameter '%s' is not in function parameter list", name);
+        return 0;
+    
+    }
+    
+    if (pending_params[i].knr_declared) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "duplicate K&R parameter declaration for '%s'", name);
+        return 0;
+    
+    }
+    
+    pending_params[i].knr_declared = 1;
+    return 1;
+
+}
+
+static void remove_duplicate_pending_params (void) {
+
+    int i;
+    
+    for (i = 0; i < pending_param_count; i++) {
+    
+        int j;
+        
+        if (!pending_params[i].name) {
+            continue;
+        }
+        
+        j = i + 1;
+        
+        while (j < pending_param_count) {
+        
+            if (pending_params[j].name && strcmp (pending_params[i].name, pending_params[j].name) == 0) {
+            
+                int k;
+                
+                if (pending_params[j].name) {
+                    free (pending_params[j].name);
+                }
+                
+                if (pending_params[j].pointed_tag_name) {
+                    free (pending_params[j].pointed_tag_name);
+                }
+                
+                for (k = j; k + 1 < pending_param_count; k++) {
+                    pending_params[k] = pending_params[k + 1];
+                }
+                
+                pending_param_count--;
+                
+                pending_params[pending_param_count].name = 0;
+                pending_params[pending_param_count].size = 0;
+                pending_params[pending_param_count].align = 0;
+                pending_params[pending_param_count].is_unsigned = 0;
+                pending_params[pending_param_count].is_floating = 0;
+                pending_params[pending_param_count].pointer_depth = 0;
+                pending_params[pending_param_count].pointed_size = 0;
+                pending_params[pending_param_count].pointed_tag_name = 0;
+                
+                continue;
+            
+            }
+            
+            j++;
+        
+        }
+    
+    }
+
+}
+
+static void copy_pending_params_to_global_symbol (const char *name) {
+
+    int i = find_global_symbol (name);
+    int pi;
+    
+    if (i < 0) {
+        return;
+    }
+    
+    for (pi = 0; pi < 128; pi++) {
+    
+        global_symbols[i].param_sizes[pi] = 0;
+        global_symbols[i].param_unsigneds[pi] = 0;
+        global_symbols[i].param_floatings[pi] = 0;
+        global_symbols[i].param_pointer_depths[pi] = 0;
+    
+    }
+    
+    for (pi = 0; pi < pending_param_count && pi < 128; pi++) {
+    
+        global_symbols[i].param_sizes[pi] = pending_params[pi].size;
+        global_symbols[i].param_unsigneds[pi] = pending_params[pi].is_unsigned;
+        global_symbols[i].param_floatings[pi] = pending_params[pi].is_floating;
+        global_symbols[i].param_pointer_depths[pi] = pending_params[pi].pointer_depth;
+    
+    }
+
+}
+
+static void set_local_symbol_pointer_info (const char *name, int pointer_depth, int pointed_size) {
+
+    struct local_symbol *sym = find_local_symbol (name);
+    
+    if (pointer_depth > 0 && parsed_type_is_aggregate && parsed_type_size > (DATA_PTR & 0x1f) && pointed_size <= (DATA_PTR & 0x1f)) {
+        pointed_size = parsed_type_size;
+    }
+    
+    if (sym) {
+    
+        sym->pointer_depth = pointer_depth;
+        sym->pointed_size = pointed_size;
+        
+        sym->pointed_is_floating = pointer_depth > 0 ? (parsed_type_is_floating ? 1 : 0) : 0;
+        sym->pointed_is_unsigned = pointer_depth > 0 ? (parsed_type_is_unsigned ? 1 : 0) : 0;
+        
+        if (sym->pointed_tag_name) {
+        
+            free (sym->pointed_tag_name);
+            sym->pointed_tag_name = 0;
+        
+        }
+        
+        if ((pointer_depth > 0 || sym->is_array) && parsed_type_tag_name[0]) {
+            sym->pointed_tag_name = xstrdup (parsed_type_tag_name);
+        }
+    
+    }
+
+}
+
+static void install_pending_params_as_locals (void) {
+
+    long offset = current_function_returns_aggregate ? 24 : 16;
+    int i;
+    
+    for (i = 0; i < pending_param_count; i++) {
+    
+        int slot_size;
+        
+        if (!pending_params[i].name) {
+            continue;
+        }
+        
+        if (local_symbol_count >= MAX_LOCAL_SYMBOLS) {
+        
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "too many local symbols");
+            break;
+        
+        }
+        
+        if (local_symbol_exists_in_current_scope (pending_params[i].name, 0)) {
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate parameter '%s'", pending_params[i].name);
+        }
+        
+        local_symbols[local_symbol_count].name = xstrdup (pending_params[i].name);
+        local_symbols[local_symbol_count].size = pending_params[i].size;
+        local_symbols[local_symbol_count].align = pending_params[i].align;
+        local_symbols[local_symbol_count].offset = (int) offset;
+        local_symbols[local_symbol_count].is_static = 0;
+        local_symbols[local_symbol_count].static_label = 0;
+        local_symbols[local_symbol_count].is_unsigned = pending_params[i].is_unsigned;
+        local_symbols[local_symbol_count].is_floating = pending_params[i].is_floating;
+        local_symbols[local_symbol_count].pointer_depth = pending_params[i].pointer_depth;
+        local_symbols[local_symbol_count].pointed_is_floating = pending_params[i].pointed_is_floating;
+        local_symbols[local_symbol_count].pointed_is_unsigned = pending_params[i].pointed_is_unsigned;
+        local_symbols[local_symbol_count].is_array = 0;
+        local_symbols[local_symbol_count].array_element_size = 0;
+        local_symbols[local_symbol_count].array_dimensions = 0;
+        local_symbols[local_symbol_count].pointed_size = pending_params[i].pointed_size;
+        local_symbols[local_symbol_count].pointed_tag_name = pending_params[i].pointed_tag_name ? xstrdup (pending_params[i].pointed_tag_name) : 0;
+        local_symbols[local_symbol_count].tag_name = 0;
+        
+        local_symbol_count++;
+        slot_size = pending_params[i].size;
+        
+        if (slot_size < DATA_PTR) {
+            slot_size = DATA_PTR;
+        }
+        
+        slot_size = (int) align_up_long (slot_size, DATA_PTR);
+        offset += slot_size;
+    
+    }
+
+}
+
+#define     MAX_LOCAL_INITS             1024
+
+#define     LOCAL_INIT_CONST            0
+#define     LOCAL_INIT_ADDRESS          1
+#define     LOCAL_INIT_STACK            2
+#define     LOCAL_INIT_GLOBAL           3
+
+struct local_init {
+
+    long offset;
+    
+    int size;
+    int kind;
+    
+    char *symbol;
+    int64_s value;
+    
+    long source_offset;
+    int source_size;
+
+};
+
+static void switch_section (int sec) {
+
+    if (!state->ofp || current_section == sec) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+        masm_flush_data_line ();
+    }
+    
+    if (sec == SECTION_TEXT) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+            fprintf (state->ofp, "section .text\n");
+        } else {
+            fprintf (state->ofp, "%s\n", (state->syntax & ASM_SYNTAX_MASM ? ".code" : ".text"));
+        }
+    
+    } else if (sec == SECTION_DATA) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+            fprintf (state->ofp, "section .data\n");
+        } else {
+            fprintf (state->ofp, ".data\n");
+        }
+    
+    } else if (sec == SECTION_BSS) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+            fprintf (state->ofp, "section .bss\n");
+        } else {
+            fprintf (state->ofp, "%s\n", (state->syntax & ASM_SYNTAX_MASM ? ".data?" : ".bss"));
+        }
+    
+    }
+    
+    current_section = sec;
+
+}
+
+static int current_token_spells_identifier_now (const char *name) {
+
+    const char *p;
+    size_t len;
+    
+    if (!name || !*name) {
+        return 0;
+    }
+    
+    if (tok.ident && strcmp (tok.ident, name) == 0) {
+        return 1;
+    }
+    
+    /*
+     * Some declaration modifiers are real tokens rather than TOK_IDENT.
+     * Use the original source spelling as a generic fallback so the
+     * declaration parser can accept them in either specifier position:
+     *
+     *     __dllexport void f(void);
+     *     void __dllexport f(void);
+     */
+    p = tok.caret ? tok.caret : tok.start;
+    
+    if (!p) {
+       return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    len = strlen (name);
+    
+    if (strncmp (p, name, len) != 0) {
+        return 0;
+    }
+    
+    if ((p[len] >= 'A' && p[len] <= 'Z') ||
+        (p[len] >= 'a' && p[len] <= 'z') ||
+        (p[len] >= '0' && p[len] <= '9') ||
+        p[len] == '_') {
+        return 0;
+    }
+    
+    return 1;
+
+}
+
+static void consume_post_type_declaration_modifiers_now (int *out_dllimport, int *out_dllexport) {
+
+    for (;;) {
+    
+        if (current_token_spells_identifier_now ("__dllimport")) {
+        
+            if (out_dllimport) {
+                *out_dllimport = 1;
+            }
+            
+            parsed_dllimport = 1;
+            get_token ();
+            
+            continue;
+        
+        }
+        
+        if (current_token_spells_identifier_now ("__dllexport")) {
+        
+            if (out_dllexport) {
+                *out_dllexport = 1;
+            }
+            
+            parsed_dllexport = 1;
+            get_token ();
+            
+            continue;
+        
+        }
+        
+        break;
+    
+    }
+
+}
+
+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;
+    int saved_storage_class = parsed_storage_class;
+    int saved_is_aggregate = parsed_type_is_aggregate;
+    int saved_is_void = parsed_type_is_void;
+    int saved_is_unsigned = parsed_type_is_unsigned;
+    int saved_is_floating = parsed_type_is_floating;
+    int saved_has_tag = parsed_type_has_tag;
+    int saved_is_inline = parsed_type_is_inline;
+    int saved_field_count = parsed_field_count;
+    int saved_fields[MAX_AGG_FIELDS];
+    int saved_declarator_is_pointer = declarator_is_pointer;
+    int saved_declarator_pointer_depth = declarator_pointer_depth;
+    int saved_declarator_has_array = declarator_has_array;
+    int saved_declarator_has_function = declarator_has_function;
+    int saved_declarator_array_unsized = declarator_array_unsized;
+    int saved_declarator_array_dimensions = declarator_array_dimensions;
+    
+    long saved_declarator_array_count = declarator_array_count;
+    long saved_declarator_first_array_count = declarator_first_array_count;
+    
+    char *name = 0;
+    
+    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];
+    }
+    
+    if (is_type_start (tok.kind)) {
+    
+        declarator_is_pointer = 0;
+        declarator_pointer_depth = 0;
+        declarator_has_array = 0;
+        declarator_has_function = 0;
+        declarator_array_unsized = 0;
+        declarator_array_count = 0;
+        
+        parse_type_spec ();
+        
+        size = parsed_type_size & 0x1f;
+        cast_is_floating = parsed_type_is_floating;
+        
+        if (tok.kind != TOK_RPAREN) {
+        
+            parse_declarator (&name);
+            
+            /*
+             * This parser is called after a leading unary '*', for forms such
+             * as *(DATA_LLONG *)p.  The '*' outside the cast performs the
+             * dereference, so the size needed by the caller is the pointed-at
+             * object size, not DATA_PTR.  However, forms produced by va_arg()
+             * for pointer types are one level deeper, e.g. char * becomes
+             * *(char **).  In that case the dereferenced object is itself a
+             * pointer and must be loaded with pointer width.
+             */
+            if (declarator_is_pointer && declarator_pointer_depth > 1) {
+                size = DATA_PTR;
+            }
+        
+        }
+        
+        if (tok.kind == TOK_RPAREN) {
+        
+            get_token ();
+            ok = 1;
+            
+            last_deref_cast_type_is_floating = cast_is_floating;
+        
+        } else {
+            expect (TOK_RPAREN, ")");
+        }
+        
+        if (name) {
+            free (name);
+        }
+    
+    }
+    
+    parsed_type_size = saved_type_size;
+    parsed_storage_class = saved_storage_class;
+    parsed_type_is_aggregate = saved_is_aggregate;
+    parsed_type_is_void = saved_is_void;
+    parsed_type_is_unsigned = saved_is_unsigned;
+    parsed_type_is_floating = saved_is_floating;
+    parsed_type_has_tag = saved_has_tag;
+    parsed_type_is_inline = saved_is_inline;
+    
+    clear_parsed_fields ();
+    
+    for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
+        parsed_field_sizes[i] = saved_fields[i];
+    }
+    
+    parsed_field_count = saved_field_count;
+    
+    declarator_is_pointer = saved_declarator_is_pointer;
+    declarator_pointer_depth = saved_declarator_pointer_depth;
+    declarator_has_array = saved_declarator_has_array;
+    declarator_has_function = saved_declarator_has_function;
+    declarator_array_unsized = saved_declarator_array_unsized;
+    declarator_array_count = saved_declarator_array_count;
+    declarator_first_array_count = saved_declarator_first_array_count;
+    declarator_array_dimensions = saved_declarator_array_dimensions;
+    
+    if (out_size) {
+        *out_size = size;
+    }
+    
+    return ok;
+
+}
+
+static void emit_load_assignment_rhs_expression_to_reg (const char *reg);
+static void emit_load_floating_rhs_expression_now (int result_size);
+static void emit_store_floating_to_local_now (long offset, int size);
+
+static void consume_comma_expression_tail_before_semi (void) {
+
+    while (tok.kind == TOK_COMMA) {
+    
+        get_token ();
+        emit_load_assignment_rhs_expression_to_reg ("rax");
+    
+    }
+
+}
+
+static void expect_semi_or_recover (void) {
+
+    consume_comma_expression_tail_before_semi ();
+    
+    if (expect (TOK_SEMI, ";")) {
+        return;
+    }
+    
+    skip_balanced_until (TOK_SEMI, TOK_RBRACE, TOK_EOF);
+    
+    if (tok.kind == TOK_SEMI) {
+        get_token ();
+    }
+
+}
+
+static int current_ident_is_known_value (void) {
+
+    int64_s ignored;
+    
+    if (tok.kind != TOK_IDENT) {
+        return 0;
+    }
+    
+    if (find_local_symbol (tok.ident)) {
+        return 1;
+    }
+    
+    if (find_global_symbol (tok.ident) >= 0) {
+        return 1;
+    }
+    
+    if (resolve_enum_constant (tok.ident, &ignored)) {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static int recover_unknown_rhs_identifier (void) {
+
+    const char *name;
+    const char *start;
+    const char *caret;
+    
+    unsigned long line;
+    
+    if (tok.kind != TOK_IDENT || current_ident_is_known_value ()) {
+        return 0;
+    }
+    
+    name = tok.ident ? tok.ident : "";
+    start = tok.start;
+    caret = tok.caret;
+    line = get_line_number ();
+    
+    report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "unknown symbol '%s'", name);
+    get_token ();
+    
+    if (tok.kind == TOK_LPAREN) {
+    
+        get_token ();
+        skip_balanced_until (TOK_RPAREN, TOK_SEMI, TOK_EOF);
+        
+        if (tok.kind == TOK_RPAREN) {
+            get_token ();
+        }
+    
+    }
+    
+    return 1;
+
+}
+
+/*static void consume_redundant_rparens_before_statement (void) {
+
+    while (tok.kind == TOK_RPAREN) {
+        get_token ();
+    }
+
+}*/
+
+static void skip_initializer (void) {
+
+    if (tok.kind == TOK_LBRACE) {
+        skip_balanced_until (TOK_COMMA, TOK_SEMI, TOK_EOF);
+    } else {
+        skip_balanced_until (TOK_COMMA, TOK_SEMI, TOK_EOF);
+    }
+
+}
+
+static void apply_typedef_array_to_declarator (void) {
+
+    if (parsed_type_is_array_typedef && !declarator_is_pointer && !declarator_has_array && !declarator_has_function) {
+    
+        declarator_has_array = 1;
+        
+        declarator_array_count = parsed_type_array_count > 0 ? parsed_type_array_count : 1;
+        declarator_first_array_count = declarator_array_count;
+        declarator_last_array_count = declarator_array_count;
+        declarator_array_dimensions = 1;
+        
+        if (parsed_type_array_element_size > 0) {
+            parsed_type_size = parsed_type_array_element_size;
+        }
+    
+    }
+
+}
+
+static void parse_old_style_param_decls (void) {
+
+    while (is_type_start (tok.kind)) {
+    
+        int param_base_size;
+        
+        parse_type_spec ();
+        param_base_size = parsed_type_size;
+        
+        for (;;) {
+        
+            char *name = 0;
+            
+            int param_size;
+            int param_pointer_depth;
+            
+            preserve_pending_params++;
+            parse_declarator (&name);
+            preserve_pending_params--;
+            
+            if (name) {
+            
+                param_size = (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef) ? DATA_PTR : declarator_object_size (param_base_size);
+                param_pointer_depth = declarator_pointer_depth;
+                
+                if ((declarator_has_array || declarator_has_function || parsed_type_is_array_typedef) && param_pointer_depth < 1) {
+                    param_pointer_depth = 1;
+                }
+                
+                if (mark_pending_param_knr_declared (name, last_declarator_name_start, last_declarator_name_caret, last_declarator_name_line)) {
+                
+                    update_pending_param (name, param_size, type_alignment (param_size),
+                        (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef ? 0 : parsed_type_is_unsigned),
+                            (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef ? 0 : parsed_type_is_floating),
+                                param_pointer_depth, parsed_type_is_aggregate ? parsed_type_size : (parsed_type_size & 0x1f), parsed_type_is_unsigned);
+                
+                }
+                
+                free (name);
+            
+            }
+            
+            if (_accept (TOK_ASSIGN)) {
+                skip_initializer ();
+            }
+            
+            if (!_accept (TOK_COMMA)) {
+                break;
+            }
+        
+        }
+        
+        expect (TOK_SEMI, ";");
+    
+    }
+
+}
+
+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 const char *amd64_integer_arg_reg (int index);
+static const char *amd64_xmm_arg_reg (int index);
+static void amd64_emit_load_xmm0_to_floating_stack_now (int size);
+
+static void emit_home_incoming_parameter_regs (void) {
+
+    int hidden = current_function_returns_aggregate ? 1 : 0;
+    int i;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    /*
+     * Microsoft x64 passes the first four argument slots in registers.  The
+     * caller reserves home space, but it does not populate it.  This backend
+     * represents parameters as positive [rbp + N] locations, so home the
+     * incoming registers at function entry before normal parameter loads can
+     * read them.
+     *
+     * After push rbp / mov rbp,rsp:
+     *   [rbp + 8]  = return address
+     *   [rbp + 16] = argument slot 0 home area
+     *   [rbp + 24] = argument slot 1 home area
+     *   [rbp + 32] = argument slot 2 home area
+     *   [rbp + 40] = argument slot 3 home area
+     */
+    if (current_function_returns_aggregate) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov qword [rbp + 16], rcx\n" : "    mov qword ptr [rbp + 16], rcx\n");
+        } else {
+            fprintf (state->ofp, "    movq %%rcx, 16(%%rbp)\n");
+        }
+    
+    }
+    
+    /*
+     * pending_params has already been converted into local_symbols by the
+     * time emit_function_start() calls us.  The old loop used
+     * pending_param_count here, which is zero after clear_pending_params(),
+     * so no incoming RCX/RDX/R8/R9 values were ever copied to the positive
+     * [rbp+N] parameter slots.  The generated function bodies then read
+     * stale/zero home slots such as [rbp+16], causing crashes in routines
+     * like strchr().
+     *
+     * At this point local_symbols contains only the installed parameters;
+     * block locals are parsed later.
+     */
+    for (i = 0; i < local_symbol_count; i++) {
+    
+        int arg_index = i + hidden;
+        int offset = local_symbols[i].offset;
+        
+        const char *ireg = amd64_integer_arg_reg (arg_index);
+        const char *xreg = amd64_xmm_arg_reg (arg_index);
+        
+        if (arg_index >= 4) {
+            break;
+        }
+        
+        if (local_symbols[i].is_floating && xreg) {
+        
+            /*
+             * Microsoft x64 / EFI floating parameters arrive in XMM0-XMM3.
+             * Home only the ABI boundary value here; the rest of the backend
+             * can continue to load the parameter normally from its [rbp+N]
+             * slot and use x87 internally.
+             */
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                if (local_symbols[i].size == (DATA_FLOAT & 0x1f)) {
+                    fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    movss dword [rbp + %d], %s\n" : "    movss dword ptr [rbp + %d], %s\n", offset, xreg);
+                } else {
+                    fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    movsd qword [rbp + %d], %s\n" : "    movsd qword ptr [rbp + %d], %s\n", offset, xreg);
+                }
+            
+            } else {
+            
+                if (local_symbols[i].size == (DATA_FLOAT & 0x1f)) {
+                    fprintf (state->ofp, "    movss %%%s, %d(%%rbp)\n", xreg, offset);
+                } else {
+                    fprintf (state->ofp, "    movsd %%%s, %d(%%rbp)\n", xreg, offset);
+                }
+            
+            }
+            
+            continue;
+        
+        }
+        
+        if (ireg) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov qword [rbp + %d], %s\n" : "    mov qword ptr [rbp + %d], %s\n", offset, ireg);
+            } else {
+                fprintf (state->ofp, "    movq %%%s, %d(%%rbp)\n", ireg, offset);
+            }
+        
+        }
+    
+    }
+    
+    /*
+     * For Microsoft x64 varargs, va_start/va_arg walks the register home
+     * area.  The caller reserves that area but does not store the register
+     * values there, so the callee must home the register arguments that may
+     * be reached through the ellipsis.  Do not overwrite fixed floating
+     * parameters already homed above; start after the declared fixed
+     * parameters.
+     */
+    if (current_function_is_variadic) {
+    
+        for (i = local_symbol_count + hidden; i < 4; i++) {
+        
+            const char *ireg = amd64_integer_arg_reg (i);
+            int offset = 16 + i * 8;
+            
+            if (!ireg) {
+                continue;
+            }
+            
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov qword [rbp + %d], %s\n" : "    mov qword ptr [rbp + %d], %s\n", offset, ireg);
+            } else {
+                fprintf (state->ofp, "    movq %%%s, %d(%%rbp)\n", ireg, offset);
+            }
+        
+        }
+    
+    }
+
+}
+
+static void emit_function_start (const char *name, int is_static) {
+
+    const char *asm_name;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    asm_name = asm_global_symbol_name (name);
+    switch_section (SECTION_TEXT);
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+    
+        masm_flush_data_line ();
+        
+        if (!is_static) {
+            fprintf (state->ofp, "public %s\n", asm_name);
+        }
+    
+    } else if (state->syntax & ASM_SYNTAX_NASM) {
+    
+        if (!is_static) {
+            fprintf (state->ofp, "global %s\n", asm_name);
+        }
+    
+    } else {
+    
+        if (!is_static) {
+            fprintf (state->ofp, ".globl %s\n", asm_name);
+        }
+    
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "%s:\n", asm_name);
+        fprintf (state->ofp, "    push rbp\n");
+        fprintf (state->ofp, "    mov rbp, rsp\n");
+        
+        amd64_temp_stack_mod16 = 0;
+        
+        emit_home_incoming_parameter_regs ();
+        emit_deferred_function_frame_placeholder ();
+    
+    } else {
+    
+        fprintf (state->ofp, "%s:\n", asm_name);
+        fprintf (state->ofp, "    pushq %%rbp\n");
+        fprintf (state->ofp, "    movq %%rsp, %%rbp\n");
+        
+        emit_home_incoming_parameter_regs ();
+        emit_deferred_function_frame_placeholder ();
+    
+    }
+
+}
+
+static void emit_pending_return_jump (void) {
+
+    if (!pending_return_jump) {
+        return;
+    }
+    
+    if (!state->ofp) {
+    
+        pending_return_jump = 0;
+        return;
+    
+    }
+    
+    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+        fprintf (state->ofp, "    jmp L%d\n", current_return_label);
+    } else {
+        fprintf (state->ofp, "    jmp .L%d\n", current_return_label);
+    }
+    
+    pending_return_jump = 0;
+
+}
+
+static void emit_stack_adjust (long bytes, int allocate) {
+
+    if (!state->ofp || bytes <= 0) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    %s rsp, %ld\n", allocate ? "sub" : "add", bytes);
+    } else {
+        fprintf (state->ofp, "    %s $%ld, %%rsp\n", allocate ? "subq" : "addq", bytes);
+    }
+
+}
+
+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_rbp_offset (char *buf, size_t bufsz, long offset) {
+
+    if (!buf || bufsz == 0) {
+        return;
+    }
+    
+    if (offset < 0) {
+        sprintf (buf, "[rbp - %ld]", -offset);
+    } else if (offset > 0) {
+        sprintf (buf, "[rbp + %ld]", offset);
+    } else {
+        sprintf (buf, "[rbp]");
+    }
+
+}
+
+static const char *format_nasm_memory_operand (char *buf, size_t bufsz, const char *operand) {
+
+    if (!operand) {
+        return operand;
+    }
+    
+    if (!(state->syntax & ASM_SYNTAX_NASM)) {
+        return operand;
+    }
+    
+    if (operand[0] == '[') {
+        return operand;
+    }
+    
+    if (buf && bufsz > 0) {
+    
+        sprintf (buf, "[%s]", operand);
+        return buf;
+    
+    }
+    
+    return operand;
+
+}
+
+static void emit_local_store_const (long offset, int size, int64_s value) {
+
+    char memref[64];
+    unsigned long high, low;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    low = value.low;
+    high = value.high;
+    
+    if (size > 8 && low == 0 && high == 0) {
+    
+        long pos;
+        
+        for (pos = 0; pos < size; pos += 4) {
+            emit_local_store_const (offset + pos, DATA_INT, value);
+        }
+        
+        return;
+    
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_rbp_offset (memref, sizeof (memref), offset);
+        
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov byte %s, %lu\n" : "    mov byte ptr %s, %lu\n"), memref, low & ((1 << 8) - 1));
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov word %s, %lu\n" : "    mov word ptr %s, %lu\n"), memref, low & ((1 << 16) - 1));
+        } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
+        
+            fprintf (state->ofp, "    mov rax, 0%08lX%08lXh\n", high & U32_MASK, low & U32_MASK);
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov qword %s, rax\n" : "    mov qword ptr %s, rax\n"), memref);
+        
+        } else {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword %s, %lu\n" : "    mov dword ptr %s, %lu\n"), memref, low & U32_MASK);
+        }
+    
+    } else {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, "    movb $%lu, %ld(%%rbp)\n", low & 0xffUL, offset);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, "    movw $%lu, %ld(%%rbp)\n", low & 0xffffUL, offset);
+        } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
+        
+            fprintf (state->ofp, "    movabsq $0x%08lX%08lX, %%rax\n", high & U32_MASK, low & U32_MASK);
+            fprintf (state->ofp, "    movq %%rax, %ld(%%rbp)\n", offset);
+        
+        } else {
+            fprintf (state->ofp, "    movl $%lu, %ld(%%rbp)\n", low & U32_MASK, offset);
+        }
+    
+    }
+
+}
+
+static void emit_store_floating_to_local_now (long offset, int size) {
+
+    char memref[64];
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_rbp_offset (memref, sizeof (memref), offset);
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fstp %s %s\n" : "    fstp %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", memref);
+    
+    } else {
+        fprintf (state->ofp, "    fstp%s %ld(%%rbp)\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", offset);
+    }
+
+}
+
+static void emit_local_store_address (long offset, const char *symbol) {
+
+    const char *asm_symbol;
+    char memref[64];
+    
+    if (!state->ofp || !symbol) {
+        return;
+    }
+    
+    emit_extern_reference_symbol (symbol, DATA_PTR);
+    asm_symbol = asm_global_symbol_name (symbol);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_rbp_offset (memref, sizeof (memref), offset);
+        
+        if (state->syntax & ASM_SYNTAX_NASM) {
+        
+            fprintf (state->ofp, "    mov rax, %s\n", asm_symbol);
+            fprintf (state->ofp, "    mov qword %s, rax\n", memref);
+        
+        } else {
+        
+            fprintf (state->ofp, "    mov rax, offset %s\n", asm_symbol);
+            fprintf (state->ofp, "    mov qword ptr %s, rax\n", memref);
+        
+        }
+    
+    } else {
+    
+        fprintf (state->ofp, "    leaq %s(%%rip), %%rax\n", asm_symbol);
+        fprintf (state->ofp, "    movq %%rax, %ld(%%rbp)\n", offset);
+    
+    }
+
+}
+
+static void emit_local_store_stack (long dst_offset, int dst_size, long src_offset, int src_size) {
+
+    char dst[64];
+    char src[64];
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_rbp_offset (dst, sizeof (dst), dst_offset);
+        format_intel_rbp_offset (src, sizeof (src), src_offset);
+
+        if (dst_size == (DATA_CHAR & 0x1f)) {
+        
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov al, byte %s\n" : "    mov al, byte ptr %s\n"), src);
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov byte %s, al\n" : "    mov byte ptr %s, al\n"), dst);
+        
+        } else if (dst_size == (DATA_SHORT & 0x1f)) {
+        
+            if (src_size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movzx ax, byte %s\n" : "    movzx ax, byte ptr %s\n"), src);
+            } else {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov ax, word %s\n" : "    mov ax, word ptr %s\n"), src);
+            }
+            
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov word %s, ax\n" : "    mov word ptr %s, ax\n"), dst);
+        
+        } else {
+        
+            if (src_size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movzx eax, byte %s\n" : "    movzx eax, byte ptr %s\n"), src);
+            } else if (src_size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movzx eax, word %s\n" : "    movzx eax, word ptr %s\n"), src);
+            } else if (src_size == (DATA_LLONG & 0x1f) || src_size == (DATA_PTR & 0x1f)) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov rax, qword %s\n" : "    mov rax, qword ptr %s\n"), src);
+            } else {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov eax, dword %s\n" : "    mov eax, dword ptr %s\n"), src);
+            }
+            
+            if (dst_size == (DATA_LLONG & 0x1f) || dst_size == (DATA_PTR & 0x1f)) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov qword %s, rax\n" : "    mov qword ptr %s, rax\n"), dst);
+            } else {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword %s, eax\n" : "    mov dword ptr %s, eax\n"), dst);
+            }
+        
+        }
+    
+    } else {
+    
+        if (dst_size == (DATA_CHAR & 0x1f)) {
+        
+            fprintf (state->ofp, "    movb %ld(%%rbp), %%al\n", src_offset);
+            fprintf (state->ofp, "    movb %%al, %ld(%%rbp)\n", dst_offset);
+        
+        } else if (dst_size == (DATA_SHORT & 0x1f)) {
+        
+            fprintf (state->ofp, "    movw %ld(%%rbp), %%ax\n", src_offset);
+            fprintf (state->ofp, "    movw %%ax, %ld(%%rbp)\n", dst_offset);
+        
+        } else {
+        
+            if (src_size == (DATA_LLONG & 0x1f) || src_size == (DATA_PTR & 0x1f)) {
+                fprintf (state->ofp, "    movq %ld(%%rbp), %%rax\n", src_offset);
+            } else {
+                fprintf (state->ofp, "    movl %ld(%%rbp), %%eax\n", src_offset);
+            }
+            
+            if (dst_size == (DATA_LLONG & 0x1f) || dst_size == (DATA_PTR & 0x1f)) {
+                fprintf (state->ofp, "    movq %%rax, %ld(%%rbp)\n", dst_offset);
+            } else {
+                fprintf (state->ofp, "    movl %%eax, %ld(%%rbp)\n", dst_offset);
+            }
+        
+        }
+    
+    }
+
+}
+
+static void emit_local_store_global (long dst_offset, int dst_size, const char *symbol) {
+
+    const char *asm_symbol;
+    char dst[64];
+    
+    if (!state->ofp || !symbol) {
+        return;
+    }
+    
+    emit_extern_reference_symbol (symbol, get_global_symbol_size (symbol));
+    asm_symbol = asm_global_symbol_name (symbol);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_rbp_offset (dst, sizeof (dst), dst_offset);
+        
+        if (dst_size == (DATA_CHAR & 0x1f)) {
+        
+            if (state->syntax & ASM_SYNTAX_NASM) {
+            
+                fprintf (state->ofp, "    mov al, byte [%s]\n", asm_symbol);
+                fprintf (state->ofp, "    mov byte %s, al\n", dst);
+            
+            } else {
+            
+                fprintf (state->ofp, "    mov al, byte ptr %s\n", asm_symbol);
+                fprintf (state->ofp, "    mov byte ptr %s, al\n", dst);
+            
+            }
+        
+        } else if (dst_size == (DATA_SHORT & 0x1f)) {
+        
+            if (state->syntax & ASM_SYNTAX_NASM) {
+            
+                fprintf (state->ofp, "    mov ax, word [%s]\n", asm_symbol);
+                fprintf (state->ofp, "    mov word %s, ax\n", dst);
+            
+            } else {
+            
+                fprintf (state->ofp, "    mov ax, word ptr %s\n", asm_symbol);
+                fprintf (state->ofp, "    mov word ptr %s, ax\n", dst);
+            
+            }
+        
+        } else if (dst_size == (DATA_LLONG & 0x1f) || dst_size == (DATA_PTR & 0x1f) || dst_size == (DATA_DOUBLE & 0x1f)) {
+        
+            if (state->syntax & ASM_SYNTAX_NASM) {
+            
+                fprintf (state->ofp, "    mov rax, qword [%s]\n", asm_symbol);
+                fprintf (state->ofp, "    mov qword %s, rax\n", dst);
+            
+            } else {
+            
+                fprintf (state->ofp, "    mov rax, qword ptr %s\n", asm_symbol);
+                fprintf (state->ofp, "    mov qword ptr %s, rax\n", dst);
+            
+            }
+        
+        } else {
+        
+            if (state->syntax & ASM_SYNTAX_NASM) {
+            
+                fprintf (state->ofp, "    mov eax, dword [%s]\n", asm_symbol);
+                fprintf (state->ofp, "    mov dword %s, eax\n", dst);
+            
+            } else {
+            
+                fprintf (state->ofp, "    mov eax, dword ptr %s\n", asm_symbol);
+                fprintf (state->ofp, "    mov dword ptr %s, eax\n", dst);
+            
+            }
+        
+        }
+    
+    } else {
+    
+        if (dst_size == (DATA_CHAR & 0x1f)) {
+        
+            fprintf (state->ofp, "    movb %s(%%rip), %%al\n", asm_symbol);
+            fprintf (state->ofp, "    movb %%al, %ld(%%rbp)\n", dst_offset);
+        
+        } else if (dst_size == (DATA_SHORT & 0x1f)) {
+        
+            fprintf (state->ofp, "    movw %s(%%rip), %%ax\n", asm_symbol);
+            fprintf (state->ofp, "    movw %%ax, %ld(%%rbp)\n", dst_offset);
+        
+        } else if (dst_size == (DATA_LLONG & 0x1f) || dst_size == (DATA_PTR & 0x1f) || dst_size == (DATA_DOUBLE & 0x1f)) {
+        
+            fprintf (state->ofp, "    movq %s(%%rip), %%rax\n", asm_symbol);
+            fprintf (state->ofp, "    movq %%rax, %ld(%%rbp)\n", dst_offset);
+        
+        } else {
+        
+            fprintf (state->ofp, "    movl %s(%%rip), %%eax\n", asm_symbol);
+            fprintf (state->ofp, "    movl %%eax, %ld(%%rbp)\n", dst_offset);
+        
+        }
+    
+    }
+
+}
+
+static void emit_local_initializers (struct local_init *inits, int init_count) {
+
+    int i;
+    
+    for (i = 0; i < init_count; i++) {
+    
+        if (inits[i].kind == LOCAL_INIT_ADDRESS) {
+            emit_local_store_address (inits[i].offset, inits[i].symbol);
+        } else if (inits[i].kind == LOCAL_INIT_STACK) {
+            emit_local_store_stack (inits[i].offset, inits[i].size, inits[i].source_offset, inits[i].source_size);
+        } else if (inits[i].kind == LOCAL_INIT_GLOBAL) {
+            emit_local_store_global (inits[i].offset, inits[i].size, inits[i].symbol);
+        } else {
+            emit_local_store_const (inits[i].offset, inits[i].size, inits[i].value);
+        }
+        
+        if (inits[i].symbol) {
+        
+            free (inits[i].symbol);
+            inits[i].symbol = 0;
+        
+        }
+    
+    }
+
+}
+
+static void emit_function_end (void) {
+
+    patch_deferred_function_frame ();
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+    
+        fprintf (state->ofp, "L%d:\n", current_return_label);
+        
+        if (current_function_returns_aggregate) {
+        
+            if (state->syntax & ASM_SYNTAX_NASM) {
+                fprintf (state->ofp, "    mov rax, qword [rbp + 16]\n");
+            } else {
+                fprintf (state->ofp, "    mov rax, qword ptr [rbp + 16]\n");
+            }
+        
+        }
+        
+        if (current_function_preserve_assignment64_regs) {
+            fprintf (state->ofp, "__SCC_RESTORE_ASSIGNMENT64_REGS__\n");
+        }
+        
+        fprintf (state->ofp, "    leave\n");
+        fprintf (state->ofp, "    ret\n");
+    
+    } else {
+    
+        fprintf (state->ofp, ".L%d:\n", current_return_label);
+        
+        if (current_function_returns_aggregate) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    mov rax, qword ptr [rbp + 16]\n");
+            } else {
+                fprintf (state->ofp, "    movq 16(%%rbp), %%rax\n");
+            }
+        
+        }
+        
+        if (current_function_preserve_assignment64_regs) {
+            fprintf (state->ofp, "__SCC_RESTORE_ASSIGNMENT64_REGS__\n");
+        }
+        
+        fprintf (state->ofp, "    leave\n");
+        fprintf (state->ofp, "    ret\n");
+    
+    }
+
+}
+
+static void emit_preserve_assignment64_regs (enum token_kind op) {
+
+    if (current_function_frame_deferred) {
+    
+        int needed = (op == TOK_STAREQ || op == TOK_STAR ||
+            op == TOK_SLASHEQ || op == TOK_BSLASH ||
+                op == TOK_MODEQ || op == TOK_MOD) ? 2 : 1;
+        
+        if (needed > current_function_preserve_assignment64_regs) {
+            current_function_preserve_assignment64_regs = needed;
+        }
+        
+        return;
+    
+    }
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    push rbx\n");
+        
+        if (op == TOK_STAREQ || op == TOK_STAR || op == TOK_SLASHEQ || op == TOK_BSLASH || op == TOK_MODEQ || op == TOK_MOD) {
+        
+            fprintf (state->ofp, "    push rsi\n");
+            fprintf (state->ofp, "    push rdi\n");
+        
+        }
+    
+    } else {
+    
+        fprintf (state->ofp, "    pushq %%rbx\n");
+        
+        if (op == TOK_STAREQ || op == TOK_STAR || op == TOK_SLASHEQ || op == TOK_BSLASH || op == TOK_MODEQ || op == TOK_MOD) {
+        
+            fprintf (state->ofp, "    pushq %%rsi\n");
+            fprintf (state->ofp, "    pushq %%rdi\n");
+        
+        }
+    
+    }
+
+}
+
+static void emit_restore_assignment64_regs (enum token_kind op) {
+
+    if (current_function_frame_deferred) {
+        return;
+    }
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (op == TOK_STAREQ || op == TOK_STAR || op == TOK_SLASHEQ || op == TOK_BSLASH || op == TOK_MODEQ || op == TOK_MOD) {
+        
+            fprintf (state->ofp, "    pop rdi\n");
+            fprintf (state->ofp, "    pop rsi\n");
+        
+        }
+        
+        fprintf (state->ofp, "    pop rbx\n");
+    
+    } else {
+    
+        if (op == TOK_STAREQ || op == TOK_STAR || op == TOK_SLASHEQ || op == TOK_BSLASH || op == TOK_MODEQ || op == TOK_MOD) {
+        
+            fprintf (state->ofp, "    popq %%rdi\n");
+            fprintf (state->ofp, "    popq %%rsi\n");
+        
+        }
+        
+        fprintf (state->ofp, "    popq %%rbx\n");
+    
+    }
+
+}
+
+static int sizeof_text_skip_space_now (const char **pp) {
+
+    const char *p;
+    
+    if (!pp || !*pp) {
+        return 0;
+    }
+    
+    p = *pp;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    *pp = p;
+    return 1;
+
+}
+
+static int sizeof_text_simple_identifier_now (const char *p, char *name, size_t name_size, int *parenthesized) {
+
+    const char *q;
+    int paren = 0;
+    size_t n = 0;
+    
+    if (!p || !name || name_size == 0) {
+        return 0;
+    }
+    
+    name[0] = 0;
+    
+    if (parenthesized) {
+        *parenthesized = 0;
+    }
+    
+    sizeof_text_skip_space_now (&p);
+    
+    if (strncmp (p, "sizeof", 6) != 0 ||
+        ((p[6] >= 'A' && p[6] <= 'Z') || (p[6] >= 'a' && p[6] <= 'z') ||
+         (p[6] >= '0' && p[6] <= '9') || p[6] == '_')) {
+        return 0;
+    }
+    
+    p += 6;
+    sizeof_text_skip_space_now (&p);
+    
+    if (*p == '(') {
+    
+        paren = 1;
+        p++;
+        
+        sizeof_text_skip_space_now (&p);
+    
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    q = p;
+    
+    while ((*q >= 'A' && *q <= 'Z') || (*q >= 'a' && *q <= 'z') ||
+           (*q >= '0' && *q <= '9') || *q == '_') {
+    
+        if (n + 1 < name_size) {
+            name[n++] = *q;
+        }
+        
+        q++;
+    
+    }
+    
+    name[n] = 0;
+    p = q;
+    
+    sizeof_text_skip_space_now (&p);
+    
+    if (paren) {
+    
+        if (*p != ')') {
+            return 0;
+        }
+        
+        p++;
+        sizeof_text_skip_space_now (&p);
+    
+    }
+    
+    if (!(*p == 0 || *p == ';' || *p == ',' || *p == ')' || *p == ']' || *p == '}' ||
+          *p == '+' || *p == '-' || *p == '*' || *p == '/' || *p == '%' ||
+          *p == '<' || *p == '>' || *p == '=' || *p == '?' || *p == ':' ||
+          *p == '&' || *p == '|' || *p == '^')) {
+        return 0;
+    }
+    
+    if (parenthesized) {
+        *parenthesized = paren;
+    }
+    
+    return name[0] != 0;
+
+}
+
+static int sizeof_symbol_object_now (const char *name, int *sizep) {
+
+    struct local_symbol *sym;
+    int global_index;
+    int size;
+    
+    if (!name || !*name || !sizep) {
+        return 0;
+    }
+    
+    sym = find_local_symbol (name);
+    
+    if (sym) {
+    
+        size = sym->size;
+        
+        if (size < 1) {
+            size = DATA_INT & 0x1f;
+        }
+        
+        *sizep = size;
+        return 1;
+    
+    }
+    
+    global_index = find_global_symbol (name);
+    
+    if (global_index >= 0 && get_global_symbol_kind (name) != GLOBAL_SYMBOL_FUNCTION) {
+    
+        size = get_global_symbol_size (name);
+        
+        if (size < 1) {
+            size = DATA_INT & 0x1f;
+        }
+        
+        *sizep = size;
+        return 1;
+    
+    }
+    
+    return 0;
+
+}
+
+static void sizeof_consume_simple_identifier_now (int parenthesized) {
+
+    get_token ();
+    
+    if (parenthesized && tok.kind == TOK_LPAREN) {
+        get_token ();
+    }
+    
+    if (tok.kind == TOK_IDENT) {
+        get_token ();
+    }
+    
+    if (parenthesized && tok.kind == TOK_RPAREN) {
+        get_token ();
+    }
+
+}
+
+static int64_s sizeof_from_current_token (void) {
+
+    int64_s v;
+    int size;
+    
+    char name[256];
+    int parenthesized;
+    
+    zext64 (&v, 0);
+    
+    /*
+     * parse_sizeof_value() handles sizeof(type), but the backend also uses
+     * sizeof while parsing normal expressions after macro expansion.  In that
+     * path, sizeof(object) must be accepted as an object-size expression, not
+     * routed into expr_const64() as if the identifier inside the parentheses
+     * were an integer constant expression.
+     */
+    if (sizeof_text_simple_identifier_now (tok.start, name, sizeof (name), &parenthesized) && sizeof_symbol_object_now (name, &size)) {
+    
+        sizeof_consume_simple_identifier_now (parenthesized);
+        
+        zext64 (&v, (unsigned long) size);
+        return v;
+    
+    }
+    
+    get_token ();
+    
+    size = parse_sizeof_value ();
+    zext64 (&v, (unsigned long) size);
+    
+    return v;
+
+}
+
+static int64_s const64_from_current_expr (void) {
+
+    enum token_kind kill[6];
+    int64_s v;
+    
+    kill[0] = TOK_SEMI;
+    kill[1] = TOK_COMMA;
+    kill[2] = TOK_RPAREN;
+    kill[3] = TOK_RBRACK;
+    kill[4] = TOK_RBRACE;
+    kill[5] = 0;
+    
+    v = expr_const64 (kill);
+    return v;
+
+}
+
+static int64_s const64_from_current_operand (void) {
+
+    enum token_kind kill[26];
+    
+    if (token_is_sizeof_keyword ()) {
+        return sizeof_from_current_token ();
+    }
+    
+    kill[0] = TOK_PLUS;
+    kill[1] = TOK_MINUS;
+    kill[2] = TOK_STAR;
+    kill[3] = TOK_BSLASH;
+    kill[4] = TOK_MOD;
+    kill[5] = TOK_LSH;
+    kill[6] = TOK_RSH;
+    kill[7] = TOK_AMPER;
+    kill[8] = TOK_PIPE;
+    kill[9] = TOK_CARET;
+    kill[10] = TOK_LESS;
+    kill[11] = TOK_LTEQ;
+    kill[12] = TOK_GREATER;
+    kill[13] = TOK_GTEQ;
+    kill[14] = TOK_EQEQ;
+    kill[15] = TOK_NOTEQ;
+    kill[16] = TOK_LOGAND;
+    kill[17] = TOK_LOGOR;
+    kill[18] = TOK_QMARK;
+    kill[19] = TOK_COLON;
+    kill[20] = TOK_SEMI;
+    kill[21] = TOK_COMMA;
+    kill[22] = TOK_RPAREN;
+    kill[23] = TOK_RBRACK;
+    kill[24] = TOK_RBRACE;
+    kill[25] = 0;
+    
+    return expr_const64 (kill);
+
+}
+
+static int64_s const64_from_current_foldable_expr (void) {
+
+    enum token_kind kill[17];
+    
+    if (token_is_sizeof_keyword ()) {
+        return sizeof_from_current_token ();
+    }
+    
+    kill[0] = TOK_LESS;
+    kill[1] = TOK_LTEQ;
+    kill[2] = TOK_GREATER;
+    kill[3] = TOK_GTEQ;
+    kill[4] = TOK_EQEQ;
+    kill[5] = TOK_NOTEQ;
+    kill[6] = TOK_LOGAND;
+    kill[7] = TOK_LOGOR;
+    kill[8] = TOK_QMARK;
+    kill[9] = TOK_COLON;
+    kill[10] = TOK_SEMI;
+    kill[11] = TOK_COMMA;
+    kill[12] = TOK_RPAREN;
+    kill[13] = TOK_RBRACK;
+    kill[14] = TOK_RBRACE;
+    kill[15] = 0;
+    kill[16] = 0;
+    
+    return expr_const64 (kill);
+
+}
+
+static long const_from_current_case_expr (void) {
+
+    enum token_kind kill[7];
+    int64_s v;
+    
+    if (token_is_sizeof_keyword ()) {
+    
+        v = sizeof_from_current_token ();
+        return (long) v.low;
+    
+    }
+    
+    kill[0] = TOK_COLON;
+    kill[1] = TOK_SEMI;
+    kill[2] = TOK_COMMA;
+    kill[3] = TOK_RPAREN;
+    kill[4] = TOK_RBRACK;
+    kill[5] = TOK_RBRACE;
+    kill[6] = 0;
+    
+    v = expr_const64 (kill);
+    return (long) v.low;
+
+}
+
+static int declarator_element_size_from_fields (int base_size, const int *field_sizes, int field_count);
+
+static int declarator_pointed_size_now (void) {
+
+    if (declarator_pointer_depth > 1) {
+        return DATA_PTR;
+    }
+    
+    if (parsed_type_is_aggregate) {
+        return parsed_type_size;
+    }
+    
+    return parsed_type_size & 0x1f;
+
+}
+
+static struct aggregate_tag_entry *hidden_typedef_pointer_entry_now (void) {
+
+    if (declarator_pointer_depth != 0 || declarator_is_pointer ||
+        declarator_has_array || declarator_has_function) {
+        return 0;
+    }
+    
+    if ((parsed_type_size & 0x1f) != (DATA_PTR & 0x1f) ||
+        !parsed_type_tag_name[0]) {
+        return 0;
+    }
+    
+    return find_aggregate_tag (parsed_type_tag_name, 0);
+
+}
+
+static int declarator_effective_pointer_depth_now (void) {
+
+    if (declarator_pointer_depth > 0) {
+        return declarator_pointer_depth;
+    }
+    
+    return hidden_typedef_pointer_entry_now () ? 1 : 0;
+
+}
+
+static int declarator_effective_pointed_size_now (int base_size, const int *field_sizes, int field_count) {
+
+    struct aggregate_tag_entry *entry;
+    
+    if (declarator_pointer_depth > 0 || declarator_is_pointer) {
+        return declarator_pointed_size_now ();
+    }
+    
+    entry = hidden_typedef_pointer_entry_now ();
+    
+    if (entry) {
+        return entry->size;
+    }
+    
+    return declarator_element_size_from_fields (base_size, field_sizes, field_count);
+
+}
+
+static int declarator_element_size_from_fields (int base_size, const int *field_sizes, int field_count) {
+
+    int total = 0;
+    int i;
+    
+    if (field_sizes && field_count > 0) {
+    
+        for (i = 0; i < field_count; i++) {
+            total += field_sizes[i] & 0x1f;
+        }
+        
+        if (total > 0) {
+            return total;
+        }
+    
+    }
+    
+    if (parsed_type_is_aggregate) {
+        return base_size;
+    }
+    
+    return base_size & 0x1f;
+
+}
+
+static int declarator_array_element_size_now (int base_size) {
+
+    int object_size;
+    
+    if (!declarator_has_array) {
+        return 0;
+    }
+    
+    if (declarator_is_pointer) {
+        return DATA_PTR;
+    }
+    
+    /*
+     * For an array object, the element reached by one subscript is the
+     * complete row after the first dimension, not always the scalar base
+     * type.  For example, with:
+     *
+     *     static const char wday_name[7][3];
+     *
+     * wday_name[i] has type char [3] and decays to the address of that
+     * three-byte row when passed to %.3s.  Recording element size as char
+     * made expression code emit a byte load from wday_name + i instead of
+     * the row address wday_name + i * 3.
+     */
+    if (declarator_array_dimensions > 1 && declarator_first_array_count > 0) {
+    
+        object_size = declarator_object_size (base_size);
+        
+        if (object_size > 0) {
+            return object_size / declarator_first_array_count;
+        }
+    
+    }
+    
+    /*
+     * For a one-dimensional array, the size of the element reached by one
+     * subscript is the declared base object size, not the total flattened
+     * initializer field size.  make_declarator_fields() expands objects like
+     *
+     *     char parmbuf[410];
+     *
+     * into 410 byte fields for initialization/copying purposes.  Feeding that
+     * field total back here made parmbuf[i] scale by 410 and store a dword far
+     * beyond the stack object.
+     */
+    if (parsed_type_is_aggregate) {
+        return base_size;
+    }
+    
+    return base_size & 0x1f;
+
+}
+
+static int count_brace_initializer_elements_from_assign_now (void) {
+
+    const char *p;
+    
+    int brace_depth = 0;
+    int paren_depth = 0;
+    int bracket_depth = 0;
+    int count = 0;
+    int saw_element = 0;
+    
+    if (tok.kind != TOK_ASSIGN || !tok.start) {
+        return 0;
+    }
+    
+    p = tok.start;
+    
+    while (*p && *p != '=') {
+        p++;
+    }
+    
+    if (*p != '=') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '{') {
+        return 0;
+    }
+    
+    p++;
+    brace_depth = 1;
+    
+    while (*p && brace_depth > 0) {
+    
+        if (*p == '\'' || *p == '"') {
+        
+            int quote = *p++;
+            saw_element = 1;
+            
+            while (*p && *p != quote) {
+            
+                if (*p == '\\' && p[1]) {
+                    p += 2;
+                } else {
+                    p++;
+                }
+            
+            }
+            
+            if (*p == quote) {
+                p++;
+            }
+            
+            continue;
+        
+        }
+        
+        if (*p == '{') {
+        
+            brace_depth++;
+            saw_element = 1;
+        
+        } else if (*p == '}') {
+        
+            if (brace_depth == 1 && paren_depth == 0 && bracket_depth == 0) {
+                break;
+            }
+            
+            brace_depth--;
+        
+        } else if (*p == '(') {
+        
+            paren_depth++;
+            saw_element = 1;
+        
+        } else if (*p == ')') {
+        
+            if (paren_depth > 0) {
+                paren_depth--;
+            }
+        
+        } else if (*p == '[') {
+        
+            bracket_depth++;
+            saw_element = 1;
+        
+        } else if (*p == ']') {
+        
+            if (bracket_depth > 0) {
+                bracket_depth--;
+            }
+        
+        } else if (*p == ',' && brace_depth == 1 && paren_depth == 0 && bracket_depth == 0) {
+        
+            if (saw_element) {
+            
+                count++;
+                saw_element = 0;
+            
+            }
+        
+        } else if (!(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')) {
+            saw_element = 1;
+        }
+        
+        p++;
+    
+    }
+    
+    if (saw_element) {
+        count++;
+    }
+    
+    return count;
+
+}
+
+static void make_declarator_fields (int *out_fields, int *out_count, const int *base_fields, int base_count, int base_size, int base_is_aggregate) {
+
+    int i;
+    long r;
+    
+    *out_count = 0;
+    
+    if (declarator_is_pointer) {
+    
+        out_fields[(*out_count)++] = DATA_PTR;
+        return;
+    
+    }
+    
+    if (declarator_has_array) {
+    
+        if (base_is_aggregate && base_count > 0) {
+        
+            for (r = 0; r < declarator_array_count && *out_count < MAX_AGG_FIELDS; r++) {
+            
+                for (i = 0; i < base_count && *out_count < MAX_AGG_FIELDS; i++) {
+                    out_fields[(*out_count)++] = base_fields[i];
+                }
+            
+            }
+        
+        } else {
+        
+            for (r = 0; r < declarator_array_count && *out_count < MAX_AGG_FIELDS; r++) {
+                out_fields[(*out_count)++] = (base_size & 0x1f);
+            }
+        
+        }
+        
+        return;
+
+    }
+    
+    for (i = 0; i < base_count && *out_count < MAX_AGG_FIELDS; i++) {
+        out_fields[(*out_count)++] = base_fields[i];
+    }
+    
+    if (*out_count == 0) {
+        out_fields[(*out_count)++] = (base_size & 0x1f);
+    }
+
+}
+
+static void parse_statement (void);
+
+static void emit_load_assignment_rhs_expression_to_pair (const char *lo, const char *hi, int is_unsigned);
+static void emit_load_assignment_rhs_expression_to_reg (const char *reg);
+
+static void amd64_emit_load_assignment_rhs_expression_to_rax64 (int is_unsigned);
+
+static void emit_store_rax_to_local64 (long offset);
+static void emit_incdec_symbol_now (struct local_symbol *sym, const char *name, enum token_kind op, int line, const char *start, const char *caret);
+
+static int current_expression_mentions_64bit_symbol_now (void);
+static int rhs_current_operand_is_unsigned_now (void);
+
+static int64_s parse_floating_const_expr_bits_now (int size);
+
+static int initializer_contains_runtime_call_now (void) {
+
+    const char *p = tok.start;
+    
+    int paren_depth = 0;
+    int bracket_depth = 0;
+    int brace_depth = 0;
+    
+    while (*p) {
+    
+        if (paren_depth == 0 && bracket_depth == 0 && brace_depth == 0 && (*p == ';' || *p == ',' || *p == '}')) {
+            break;
+        }
+        
+        if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_') {
+        
+            const char *q = p + 1;
+            
+            while ((*q >= 'A' && *q <= 'Z') || (*q >= 'a' && *q <= 'z') || (*q >= '0' && *q <= '9') || *q == '_') {
+                q++;
+            }
+            
+            while (*q == ' ' || *q == '\t' || *q == '\r' || *q == '\n') {
+                q++;
+            }
+            
+            if (*q == '(') {
+                return 1;
+            }
+            
+            p = q;
+            continue;
+        
+        }
+        
+        if (*p == '\'' || *p == '"') {
+        
+            int quote = *p++;
+            
+            while (*p && *p != quote) {
+            
+                if (*p == '\\' && p[1]) {
+                    p += 2;
+                } else {
+                    p++;
+                }
+            
+            }
+            
+            if (*p == quote) {
+                p++;
+            }
+            
+            continue;
+        
+        }
+        
+        if (*p == '(') {
+            paren_depth++;
+        } else if (*p == ')') {
+        
+            if (paren_depth > 0) {
+                paren_depth--;
+            }
+        
+        } else if (*p == '[') {
+            bracket_depth++;
+        } else if (*p == ']') {
+        
+            if (bracket_depth > 0) {
+                bracket_depth--;
+            }
+        
+        } else if (*p == '{') {
+            brace_depth++;
+        } else if (*p == '}') {
+        
+            if (brace_depth > 0) {
+                brace_depth--;
+            }
+        
+        }
+        
+        p++;
+    
+    }
+    
+    return 0;
+
+}
+
+static int auto_init_ident_char_now (int ch) {
+    return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '_';
+}
+
+static int auto_init_expr_continues_after_ident_now (void) {
+
+    const char *p;
+    const char *q;
+    
+    if (tok.kind != TOK_IDENT) {
+        return 1;
+    }
+    
+    p = tok.start;
+    q = p;
+    
+    while (auto_init_ident_char_now ((unsigned char) *q)) {
+        q++;
+    }
+    
+    while (*q == ' ' || *q == '\t' || *q == '\r' || *q == '\n') {
+        q++;
+    }
+    
+    return !(*q == ';' || *q == ',' || *q == '}');
+
+}
+
+static int auto_initializer_needs_runtime_now (void) {
+
+    const char *p = tok.start;
+    int paren_depth = 0;
+    int bracket_depth = 0;
+    int brace_depth = 0;
+    
+    if (initializer_contains_runtime_call_now () || tok.kind == TOK_LPAREN) {
+        return 1;
+    }
+    
+    if (tok.kind == TOK_IDENT) {
+        return auto_init_expr_continues_after_ident_now ();
+    }
+    
+    if (tok.kind == TOK_AMPER) {
+    
+        p++;
+        
+        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+            p++;
+        }
+        
+        if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+            return 1;
+        }
+        
+        while (auto_init_ident_char_now ((unsigned char) *p)) {
+            p++;
+        }
+        
+        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+            p++;
+        }
+        
+        return !(*p == ';' || *p == ',' || *p == '}');
+    
+    }
+    
+    p = tok.start;
+    
+    while (*p) {
+    
+        if (paren_depth == 0 && bracket_depth == 0 && brace_depth == 0 && (*p == ';' || *p == ',' || *p == '}')) {
+            break;
+        }
+        
+        if (*p == '[' || *p == ']' || *p == '*') {
+            return 1;
+        }
+        
+        if (*p == '(') {
+            paren_depth++;
+        } else if (*p == ')') {
+            if (paren_depth > 0) paren_depth--;
+        } else if (*p == '[') {
+            bracket_depth++;
+        } else if (*p == ']') {
+            if (bracket_depth > 0) bracket_depth--;
+        } else if (*p == '{') {
+            brace_depth++;
+        } else if (*p == '}') {
+            if (brace_depth > 0) brace_depth--;
+        }
+        
+        if (((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_') && p[0] != 'L') {
+            return 1;
+        }
+        
+        p++;
+    
+    }
+    
+    return 0;
+
+}
+
+static void parse_local_initializer_value (struct local_init *init, int object_size, int object_is_floating) {
+
+    init->kind = LOCAL_INIT_CONST;
+    init->symbol = 0;
+    init->value.low = 0;
+    init->value.high = 0;
+    init->source_offset = 0;
+    init->source_size = 0;
+    
+    if (tok.kind == TOK_LBRACE) {
+    
+        get_token ();
+        parse_local_initializer_value (init, object_size, object_is_floating);
+        
+        while (_accept (TOK_COMMA)) {
+            skip_initializer ();
+        }
+        
+        expect (TOK_RBRACE, "}");
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_AMPER) {
+    
+        get_token ();
+        
+        if (tok.kind != TOK_IDENT) {
+        
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after '&'");
+            return;
+        
+        }
+        
+        init->kind = LOCAL_INIT_ADDRESS;
+        init->symbol = xstrdup (tok.ident);
+        
+        get_token ();
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_IDENT) {
+    
+        struct local_symbol *src = find_local_symbol (tok.ident);
+        
+        if (src) {
+        
+            if (src->is_static && src->static_label) {
+            
+                init->kind = LOCAL_INIT_GLOBAL;
+                init->symbol = xstrdup (src->static_label);
+            
+            } else {
+            
+                init->kind = LOCAL_INIT_STACK;
+                
+                init->source_offset = src->offset;
+                init->source_size = src->size;
+            
+            }
+            
+            get_token ();
+            return;
+        
+        }
+        
+        if (find_global_symbol (tok.ident) >= 0) {
+        
+            init->kind = LOCAL_INIT_GLOBAL;
+            init->symbol = xstrdup (tok.ident);
+            
+            get_token ();
+            return;
+        
+        }
+    
+    }
+    
+    if (object_is_floating) {
+        init->value = parse_floating_const_expr_bits_now (object_size);
+    } else {
+        init->value = const64_from_current_expr ();
+    }
+
+}
+
+static void parse_local_string_field_initializer (struct local_init *inits, int *init_count, int max_inits, long base_offset, int field_size) {
+
+    int64_s values[MAX_STRING_INIT_BYTES];
+    int value_count = 0, i;
+    
+    parse_string_initializer_values (values, MAX_STRING_INIT_BYTES, &value_count);
+    
+    for (i = 0; i < field_size; i++) {
+    
+        if (*init_count >= max_inits) {
+            continue;
+        }
+        
+        inits[*init_count].offset = base_offset + i;
+        inits[*init_count].size = 1;
+        inits[*init_count].kind = LOCAL_INIT_CONST;
+        inits[*init_count].symbol = 0;
+        inits[*init_count].value.low = (i < value_count) ? (values[i].low & 0xffUL) : 0;
+        inits[*init_count].value.high = 0;
+        inits[*init_count].source_offset = 0;
+        inits[*init_count].source_size = 0;
+        
+        (*init_count)++;
+    
+    }
+
+}
+
+static void parse_local_aggregate_initializer_values (struct local_init *inits, int *init_count, int max_inits, long base_offset, const int *fields, int field_count) {
+
+    int field_index = 0;
+    long field_offset = 0;
+    int braced = 0;
+    
+    if (tok.kind == TOK_LBRACE) {
+        braced = 1;
+        get_token ();
+    }
+    
+    while (field_index < field_count) {
+    
+        int field_size = fields[field_index];
+        
+        if (field_size < 0) {
+        
+            field_offset += -field_size;
+            
+            field_index++;
+            continue;
+        
+        }
+        
+        if (braced && tok.kind == TOK_RBRACE) {
+        
+            if (*init_count < max_inits) {
+            
+                inits[*init_count].offset = base_offset + field_offset;
+                inits[*init_count].size = field_size;
+                inits[*init_count].kind = LOCAL_INIT_CONST;
+                inits[*init_count].symbol = 0;
+                inits[*init_count].value.low = 0;
+                inits[*init_count].value.high = 0;
+                inits[*init_count].source_offset = 0;
+                inits[*init_count].source_size = 0;
+                
+                (*init_count)++;
+            
+            }
+            
+            field_offset += field_size;
+            field_index++;
+            
+            continue;
+        
+        }
+        
+        if (*init_count < max_inits) {
+        
+            if (is_string_token ()) {
+                parse_local_string_field_initializer (inits, init_count, max_inits, base_offset + field_offset, field_size);
+            } else {
+            
+                inits[*init_count].offset = base_offset + field_offset;
+                inits[*init_count].size = field_size;
+                
+                parse_local_initializer_value (&inits[*init_count], 0, 0);
+                (*init_count)++;
+            
+            }
+        
+        } else {
+            skip_initializer ();
+        }
+        
+        field_offset += field_size;
+        field_index++;
+        
+        if (braced) {
+        
+            if (!_accept (TOK_COMMA)) {
+                break;
+            }
+            
+            if (tok.kind == TOK_RBRACE) {
+                break;
+            }
+        
+        } else {
+            break;
+        }
+    
+    }
+    
+    if (braced) {
+    
+        while (field_index < field_count) {
+        
+            int field_size = fields[field_index];
+            
+            if (field_size < 0) {
+            
+                field_offset += -field_size;
+                
+                field_index++;
+                continue;
+            
+            }
+            
+            if (*init_count < max_inits) {
+            
+                inits[*init_count].offset = base_offset + field_offset;
+                inits[*init_count].size = field_size;
+                inits[*init_count].kind = LOCAL_INIT_CONST;
+                inits[*init_count].symbol = 0;
+                inits[*init_count].value.low = 0;
+                inits[*init_count].value.high = 0;
+                inits[*init_count].source_offset = 0;
+                inits[*init_count].source_size = 0;
+                
+                (*init_count)++;
+            
+            }
+            
+            field_offset += field_size;
+            field_index++;
+        
+        }
+        
+        while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
+        
+            skip_initializer ();
+            
+            if (!_accept (TOK_COMMA)) {
+                break;
+            }
+        }
+        
+        expect (TOK_RBRACE, "}");
+    
+    }
+
+}
+
+static void make_local_static_label (char *buf, size_t bufsz, const char *name) {
+
+    if (!buf || bufsz == 0) {
+        return;
+    }
+    
+    if (!name) {
+        name = "anon";
+    }
+    
+    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+        sprintf (buf, "LC%d_%s", local_static_id++, name);
+    } else {
+        sprintf (buf, ".LC%d_%s", local_static_id++, name);
+    }
+
+}
+
+static void emit_global_object (const char *name, int size, int is_array, long array_count, const int *field_sizes, int field_count, const int64_s *values, char **symbols, int value_count, int is_aggregate, int is_static);
+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_block_static_object (const char *label, int size, int is_array, long array_count, const int *field_sizes, int field_count, const int64_s *values, char **symbols, int value_count, int is_aggregate) {
+    
+    emit_global_object (label, size, is_array, array_count, field_sizes, field_count, values, symbols, value_count, is_aggregate, 1);
+    
+    /**
+     * We may have switched to .data/.data? to emit the static object while
+     * parsing a function body.  The following statements still belong in
+     * .code/.text.
+     */
+    switch_section (SECTION_TEXT);
+
+}
+
+static char *emit_string_literal_global (void);
+
+static void ensure_block_stack_allocated (long block_stack_start, long *block_stack_bytes, int *block_stack_emitted) {
+
+    long needed_stack_bytes = align_up_long (current_local_stack_size - block_stack_start, 4);
+    
+    /*
+     * The parser can emit code while it is still inside a declaration list
+     * containing comma-separated declarators and runtime initializers.  Keep
+     * one word of conservative headroom once a block frame exists, so a
+     * subsequently-discovered automatic slot in the same declaration phase is
+     * not allowed to overlap the caller frame before the next adjustment is
+     * emitted.  This fixes cases like:
+     *
+     *     cpp_mffc *old = reader->mffc;
+     *     struct if_stack *ifs, *next_ifs;
+     *     ... next_ifs = ifs->next;
+     *
+     * where generated code used -12(%rbp) after reserving only 8 bytes.
+     */
+    if (needed_stack_bytes > 0) {
+        needed_stack_bytes = align_up_long (needed_stack_bytes + 4, 4);
+    }
+    
+    if (!block_stack_bytes || !block_stack_emitted) {
+        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;
+        emit_stack_adjust (*block_stack_bytes, 1);
+        
+        if (current_parse_block_depth > 1) {
+            current_block_cleanup_bytes += *block_stack_bytes;
+        }
+        
+        *block_stack_emitted = (*block_stack_bytes > 0);
+    
+    } 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 (current_parse_block_depth > 1) {
+            current_block_cleanup_bytes += extra_stack_bytes;
+        }
+        
+        *block_stack_bytes = needed_stack_bytes;
+    
+    }
+
+}
+
+static void parse_global_initializer_values (int64_s *values, char **symbols, int max_values, int *count);
+
+static int aggregate_initializer_value_field_count (const int *field_sizes, int field_count);
+static void parse_global_initializer_values_padded_elements (int64_s *values, char **symbols, int max_values, int *count, int element_field_count);
+
+static void parse_char_array_initializer_values (int64_s *values, int max_values, int *count, long row_width);
+static int64_s parse_floating_const_expr_bits_now (int size);
+
+static void emit_store_pair_to_local64 (long offset, const char *lo, const char *hi);
+static void emit_store_reg_to_local (long offset, int size, const char *reg);
+
+static void emit_load_local_address_to_reg_now (const char *reg, long offset);
+static int emit_aggregate_copy_from_current_rhs_to_addr_reg_now (const char *addr_reg, int offset, int size);
+
+static void parse_block (void) {
+
+    int declaration_phase = 1, is_function_body = (current_parse_block_depth == 0);
+    
+    int block_local_start = local_symbol_count;
+    int block_stack_emitted = 0;
+    
+    long block_stack_start = current_local_stack_size;
+    long block_stack_bytes = 0;
+    
+    struct local_init inits[MAX_LOCAL_INITS];
+    int block_scope_start, init_count = 0;
+    
+    block_scope_start = is_function_body ? 0 : block_local_start;
+    current_parse_block_depth++;;
+    
+    expect (TOK_LBRACE, "{");
+    
+    while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
+    
+        if (is_type_start (tok.kind)) {
+        
+            if (!declaration_phase) {
+            
+                if (state->std == 90) {
+                    report_line_at (get_filename (), get_line_number (), (state->pedantic ? REPORT_ERROR : REPORT_WARNING), tok.start, tok.caret, "ISO C90 forbids mixed declarations and code");
+                }
+            
+            }
+            
+            parse_type_spec ();
+            
+            for (;;) {
+            
+                long object_offset = 0;
+                
+                int object_init_size = 0;
+                int object_is_auto = 0;
+                
+                char *name = 0;
+                unsigned long name_line;
+                
+                const char *name_start, *name_caret;
+                int object_align, object_size = 0;
+                
+                int object_fields[MAX_AGG_FIELDS];
+                int object_field_count = 0;
+                int init_value_count = 0;
+                
+                int64_s init_values[MAX_AGG_FIELDS];
+                int i;
+                
+                char *init_symbols[MAX_AGG_FIELDS];
+                char static_label[128];
+                
+                int declaration_dllimport = parsed_dllimport;
+                
+                for (i = 0; i < MAX_AGG_FIELDS; i++) {
+                    init_symbols[i] = 0;
+                }
+                
+                parse_declarator (&name);
+                
+                declaration_dllimport = declaration_dllimport || parsed_dllimport || declarator_dllimport;
+                apply_typedef_array_to_declarator ();
+                
+                if (declarator_has_array && declarator_array_unsized && tok.kind == TOK_ASSIGN) {
+                
+                    int inferred_count = count_brace_initializer_elements_from_assign_now ();
+                    
+                    if (inferred_count > 0) {
+                        declarator_array_count = inferred_count;
+                    }
+                
+                }
+                
+                name_line = last_declarator_name_line;
+                name_start = last_declarator_name_start;
+                name_caret = last_declarator_name_caret;
+                
+                make_declarator_fields (object_fields, &object_field_count, parsed_field_sizes, parsed_field_count, parsed_type_size, parsed_type_is_aggregate);
+                
+                if (parsed_type_is_void && !declarator_is_pointer && !declarator_has_function) {
+                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "variable '%s' declared void", name ? name : "");
+                }
+                
+                if (declarator_is_pointer) {
+                
+                    object_field_count = 1;
+                    object_fields[0] = DATA_PTR;
+                
+                }
+                
+                if (parsed_storage_class == STORAGE_TYPEDEF && name) {
+                
+                    save_typedef_name (name, declarator_object_size (parsed_type_size),
+                        (declarator_is_pointer ? 0 : parsed_type_is_unsigned),
+                            (declarator_is_pointer ? 0 : parsed_type_is_void),
+                                (!declarator_is_pointer && (parsed_type_is_aggregate || declarator_has_array)),
+                                    (!declarator_is_pointer && declarator_has_array),
+                                        declarator_array_count, parsed_type_size,
+                                            (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention,
+                                                object_fields, object_field_count);
+                
+                } else if (name && (parsed_storage_class == STORAGE_EXTERN || declaration_dllimport)) {
+                
+                    add_global_symbol (name, (declarator_has_function && !declarator_function_is_pointer) ? GLOBAL_SYMBOL_FUNCTION : GLOBAL_SYMBOL_OBJECT, 1, name_start, name_caret, name_line);
+                    
+                    if (find_global_symbol (name) >= 0) {
+                    
+                        set_global_symbol_size (name, (declarator_has_function && !declarator_is_pointer && !declarator_function_is_pointer) ? parsed_type_size : ((declarator_has_function || declarator_is_pointer) ? DATA_PTR : declarator_object_size (parsed_type_size)));
+                        set_global_symbol_pointer_info (name, declarator_effective_pointer_depth_now (),
+                            declarator_effective_pointed_size_now (parsed_type_size, object_fields, object_field_count));
+                        set_global_symbol_tag_name (name, parsed_type_tag_name);
+                        set_global_symbol_unsigned (name, (declarator_is_pointer || declarator_has_function) ? 0 : parsed_type_is_unsigned);
+                        set_global_symbol_floating (name, (declarator_is_pointer || (declarator_has_function && declarator_function_is_pointer)) ? 0 : parsed_type_is_floating);
+                        set_global_symbol_returns_void (name, declarator_has_function && parsed_type_is_void && !declarator_is_pointer && !declarator_function_is_pointer);
+                        
+                        if (declarator_has_function) {
+                        
+                            set_global_symbol_param_count (name, declarator_function_param_count, declarator_function_has_prototype || declarator_function_param_count > 0, declarator_function_is_variadic);
+                            
+                            set_global_symbol_calling_convention (name, (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention);
+                            set_global_symbol_dllimport (name, declaration_dllimport);
+                            
+                            copy_pending_params_to_global_symbol (name);
+                        
+                        }
+                        
+                        set_global_symbol_dllimport (name, declaration_dllimport);
+                        switch_section (SECTION_TEXT);
+                    
+                    }
+                
+                } else if (name && parsed_storage_class != STORAGE_STATIC) {
+                
+                    object_size = declarator_object_size (parsed_type_size);
+                    object_align = declarator_is_pointer ? type_alignment (DATA_PTR) : type_alignment (parsed_type_is_aggregate ? DATA_PTR : parsed_type_size);
+                    
+                    object_offset = add_local_symbol (name, object_size, object_align,
+                        (declarator_is_pointer ? 0 : parsed_type_is_unsigned),
+                            block_scope_start, name_line, name_start, name_caret);
+                    
+                    /*
+                     * Reserve stack space as soon as an automatic local receives
+                     * an EBP-relative slot.  Some blocks start with declarations
+                     * and then immediately execute statements that write those
+                     * locals, for example:
+                     *
+                     *     if (...) { location_t loc; unsigned int i; loc.file = ...; }
+                     *
+                     * Waiting until the declaration phase is exited proved too
+                     * fragile after runtime initializer handling was added: code
+                     * could use -4/-8/-12(%rbp) before any sub rsp had been
+                     * emitted.  Keep block_stack_bytes in sync here so the later
+                     * declaration-phase transition is a no-op unless a later
+                     * unsized aggregate expands the frame.
+                     */
+                    ensure_block_stack_allocated (block_stack_start, &block_stack_bytes, &block_stack_emitted);
+                    
+                    set_local_symbol_floating (name, declarator_is_pointer ? 0 : parsed_type_is_floating);
+                    set_local_symbol_array (name, declarator_has_array);
+                    set_local_symbol_array_dimensions (name, declarator_has_array ? declarator_array_dimensions : 0);
+                    set_local_symbol_array_element_size (name, declarator_array_element_size_now (parsed_type_size));
+                    set_local_symbol_pointer_info (name, declarator_effective_pointer_depth_now (),
+                        declarator_effective_pointed_size_now (parsed_type_size, object_fields, object_field_count));
+                    
+                    if (!declarator_is_pointer && parsed_type_tag_name[0]) {
+                    
+                        struct local_symbol *lsym = find_local_symbol (name);
+                        
+                        if (lsym) {
+                            lsym->tag_name = xstrdup (parsed_type_tag_name);
+                        }
+                    
+                    }
+                    
+                    object_init_size = declarator_is_pointer ? DATA_PTR : (parsed_type_size & 0x1f);
+                    object_is_auto = 1;
+                    
+                    /*
+                     * If an earlier automatic declaration in this block had a
+                     * runtime initializer, stack space has already been emitted.
+                     * Any later automatic declaration extends current_local_stack_size,
+                     * and its initializer may immediately store to the new slot.
+                     * Reserve the extra bytes before parsing/emitting that initializer;
+                     * otherwise code can write to -8(%rbp), -12(%rbp), etc. after
+                     * only the first 4 bytes were allocated.
+                     */
+                    if (block_stack_emitted) {
+                        ensure_block_stack_allocated (block_stack_start, &block_stack_bytes, &block_stack_emitted);
+                    }
+                
+                }
+                
+                if (_accept (TOK_ASSIGN)) {
+                
+                    /*
+                     * Reserve the stack slot before parsing an automatic initializer.
+                     *
+                     * Some initializer forms which are not compile-time constants
+                     * can still reach code emission through parse_local_initializer_value().
+                     * If the stack adjustment is delayed until the first following
+                     * statement, those stores use offsets that have not yet been
+                     * reserved.  In create_definition(), this affected:
+                     *
+                     *     cpp_token *saved_cur_token = reader->cur_token;
+                     *
+                     * The generated code stored to -64(%rbp) while only -60 bytes
+                     * had been allocated, so the following call overwrote the saved
+                     * value and reader->cur_token was restored with garbage.
+                     */
+                    if (object_is_auto) {
+                        ensure_block_stack_allocated (block_stack_start, &block_stack_bytes, &block_stack_emitted);
+                    }
+                    
+                    if ((parsed_storage_class == STORAGE_EXTERN || parsed_dllimport)) {
+                    
+                        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "extern declaration '%s' is initialized", name ? name : "");
+                        skip_initializer ();
+                    
+                    } else if (parsed_storage_class == STORAGE_STATIC && name) {
+                    
+                        if (declarator_has_array && !declarator_is_pointer && (parsed_type_size & 0x1f) == (DATA_CHAR & 0x1f) && (is_string_token () || tok.kind == TOK_LBRACE)) {
+                        
+                            if (is_string_token ()) {
+                                parse_string_initializer_values (init_values, MAX_AGG_FIELDS, &init_value_count);
+                            } else {
+                                parse_char_array_initializer_values (init_values, MAX_AGG_FIELDS, &init_value_count, declarator_last_array_count);
+                            }
+                            
+                            if (declarator_array_unsized) {
+                                declarator_array_count = init_value_count;
+                            }
+                        
+                        } else if (declarator_is_pointer && is_string_token ()) {
+                        
+                            init_values[0].low = 0;
+                            init_values[0].high = 0;
+                            
+                            init_symbols[0] = emit_string_literal_global ();
+                            init_value_count = 1;
+                        
+                        } else if (!declarator_is_pointer && parsed_type_is_floating) {
+                        
+                            init_values[0] = parse_floating_const_expr_bits_now (parsed_type_size);
+                            init_symbols[0] = 0;
+                            init_value_count = 1;
+                        
+                        } else {
+                        
+                            {
+                            
+                                int saved_accept_symbol_addresses = global_initializer_accept_symbol_addresses;
+                                global_initializer_accept_symbol_addresses = declarator_is_pointer || parsed_type_is_aggregate || declarator_has_array;
+                                
+                                if (declarator_has_array && !declarator_is_pointer && parsed_type_is_aggregate && parsed_field_count > 0 && tok.kind == TOK_LBRACE) {
+                                    parse_global_initializer_values_padded_elements (init_values, init_symbols, MAX_AGG_FIELDS, &init_value_count, aggregate_initializer_value_field_count (parsed_field_sizes, parsed_field_count));
+                                } else {
+                                    parse_global_initializer_values (init_values, init_symbols, MAX_AGG_FIELDS, &init_value_count);
+                                }
+                                
+                                global_initializer_accept_symbol_addresses = saved_accept_symbol_addresses;
+                            
+                            }
+                            
+                            if (declarator_has_array && declarator_array_unsized) {
+                            
+                                if (parsed_type_is_aggregate && object_field_count > 0) {
+                                    declarator_array_count = (init_value_count + object_field_count - 1) / object_field_count;
+                                } else {
+                                    declarator_array_count = init_value_count;
+                                }
+                            
+                            }
+                        
+                        }
+                    
+                    } else if (object_is_auto && declarator_has_array && declarator_is_pointer && tok.kind == TOK_LBRACE) {
+                    
+                        int elem_index = 0;
+                        int elem_size = DATA_PTR;
+                        int first_init_index = init_count;
+                        
+                        get_token ();
+                        
+                        while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
+                        
+                            if (init_count < MAX_LOCAL_INITS) {
+                            
+                                inits[init_count].offset = object_offset + (elem_index * elem_size);
+                                inits[init_count].size = elem_size;
+                                
+                                if (is_string_token ()) {
+                                
+                                    inits[init_count].kind = LOCAL_INIT_ADDRESS;
+                                    inits[init_count].symbol = emit_string_literal_global ();
+                                    inits[init_count].value.low = 0;
+                                    inits[init_count].value.high = 0;
+                                    inits[init_count].source_offset = 0;
+                                    inits[init_count].source_size = 0;
+                                    
+                                    switch_section (SECTION_TEXT);
+                                
+                                } else {
+                                    parse_local_initializer_value (&inits[init_count], elem_size, 0);
+                                }
+                                
+                                init_count++;
+                            
+                            } else {
+                                skip_initializer ();
+                            }
+                            
+                            elem_index++;
+                            
+                            if (!_accept (TOK_COMMA)) {
+                                break;
+                            }
+                            
+                            if (tok.kind == TOK_RBRACE) {
+                                break;
+                            }
+                        
+                        }
+                        
+                        if (declarator_array_unsized && elem_index > 0 && (elem_index * elem_size) > object_size) {
+                        
+                            long old_offset = object_offset;
+                            long new_offset;
+                            long delta;
+                            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;
+                            object_size = elem_index * elem_size;
+                            
+                            if (local_symbol_count > 0 && name && local_symbols[local_symbol_count - 1].name
+                                && strcmp (local_symbols[local_symbol_count - 1].name, name) == 0) {
+                            
+                                local_symbols[local_symbol_count - 1].offset = object_offset;
+                                local_symbols[local_symbol_count - 1].size = object_size;
+                            
+                            }
+                            
+                            for (adj_i = first_init_index; adj_i < init_count; adj_i++) {
+                                inits[adj_i].offset += delta;
+                            }
+                        
+                        }
+                        
+                        expect (TOK_RBRACE, "}");
+                    
+                    } else if (object_is_auto && declarator_has_array && !declarator_is_pointer && (parsed_type_size & 0x1f) == (DATA_CHAR & 0x1f) && is_string_token ()) {
+                    
+                        int first_init_index = init_count;
+                        int value_count = 0;
+                        
+                        int64_s values[MAX_STRING_INIT_BYTES];
+                        int i;
+                        
+                        parse_string_initializer_values (values, MAX_STRING_INIT_BYTES, &value_count);
+                        
+                        if (declarator_array_unsized && value_count > 0 && value_count > object_size) {
+                        
+                            long old_offset = object_offset;
+                            long new_offset;
+                            long delta;
+                            
+                            int adj_i;
+                            current_local_stack_size += value_count - 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;
+                            declarator_array_count = value_count;
+                            
+                            if (local_symbol_count > 0 && name && local_symbols[local_symbol_count - 1].name && strcmp (local_symbols[local_symbol_count - 1].name, name) == 0) {
+                            
+                                local_symbols[local_symbol_count - 1].offset = object_offset;
+                                local_symbols[local_symbol_count - 1].size = object_size;
+                            
+                            }
+                            
+                            for (adj_i = first_init_index; adj_i < init_count; adj_i++) {
+                                inits[adj_i].offset += delta;
+                            }
+                        
+                        }
+                        
+                        for (i = 0; i < object_size; i++) {
+                        
+                            if (init_count >= MAX_LOCAL_INITS) {
+                                continue;
+                            }
+                            
+                            inits[init_count].offset = object_offset + i;
+                            inits[init_count].size = 1;
+                            inits[init_count].kind = LOCAL_INIT_CONST;
+                            inits[init_count].symbol = 0;
+                            inits[init_count].value.low = (i < value_count) ? (values[i].low & 0xffUL) : 0;
+                            inits[init_count].value.high = 0;
+                            inits[init_count].source_offset = 0;
+                            inits[init_count].source_size = 0;
+                            
+                            init_count++;
+                        
+                        }
+                    
+                    } else if (object_is_auto && !declarator_is_pointer && (parsed_type_is_aggregate || declarator_has_array) && tok.kind == TOK_LBRACE) {
+                        parse_local_aggregate_initializer_values (inits, &init_count, MAX_LOCAL_INITS, object_offset, object_fields, object_field_count);
+                    } else if (object_is_auto && auto_initializer_needs_runtime_now ()) {
+                    
+                        long needed_stack_bytes = align_up_long (current_local_stack_size - block_stack_start, 4);
+                        
+                        if (!block_stack_emitted) {
+                        
+                            block_stack_bytes = needed_stack_bytes;
+                            emit_stack_adjust (block_stack_bytes, 1);
+                            
+                            if (!is_function_body) {
+                                current_block_cleanup_bytes += block_stack_bytes;
+                            }
+                            
+                            block_stack_emitted = (block_stack_bytes > 0);
+                        
+                        } 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) {
+                                current_block_cleanup_bytes += extra_stack_bytes;
+                            }
+                            
+                            block_stack_bytes = needed_stack_bytes;
+                        
+                        }
+                        
+                        emit_local_initializers (inits, init_count);
+                        init_count = 0;
+                        
+                        if (!declarator_is_pointer && (parsed_type_is_aggregate || declarator_has_array)) {
+                        
+                            emit_load_local_address_to_reg_now ("rdx", object_offset);
+                            
+                            if (!emit_aggregate_copy_from_current_rhs_to_addr_reg_now ("rdx", 0, object_size)) {
+                            
+                                if (tok.kind == TOK_IDENT && token_identifier_is_function_call_rhs_now () &&
+                                    get_global_symbol_kind (tok.ident) == GLOBAL_SYMBOL_FUNCTION &&
+                                    get_global_symbol_size (tok.ident) > (DATA_LLONG & 0x1f)) {
+                                
+                                    pending_struct_return_lhs = find_local_symbol (name);
+                                    pending_struct_return_global_name = 0;
+                                    
+                                    emit_load_assignment_rhs_expression_to_reg ("rax");
+                                
+                                } else if (object_init_size == (DATA_LLONG & 0x1f) && !parsed_type_is_floating && !declarator_has_array) {
+                                
+                                    amd64_emit_load_assignment_rhs_expression_to_rax64 (parsed_type_is_unsigned);
+                                    emit_store_rax_to_local64 (object_offset);
+                                
+                                } else {
+                                
+                                    emit_load_assignment_rhs_expression_to_reg ("rax");
+                                    emit_store_reg_to_local (object_offset, object_init_size, "rax");
+                                
+                                }
+                            
+                            }
+                        
+                        } else if (!declarator_is_pointer && parsed_type_is_floating) {
+                        
+                            emit_load_floating_rhs_expression_now (object_init_size);
+                            emit_store_floating_to_local_now (object_offset, object_init_size);
+                        
+                        } else if (object_init_size == (DATA_LLONG & 0x1f) && !parsed_type_is_floating && !declarator_is_pointer) {
+                        
+                            amd64_emit_load_assignment_rhs_expression_to_rax64 (parsed_type_is_unsigned);
+                            emit_store_rax_to_local64 (object_offset);
+                        
+                        } else {
+                        
+                            emit_load_assignment_rhs_expression_to_reg ("rax");
+                            emit_store_reg_to_local (object_offset, object_init_size, "rax");
+                        
+                        }
+                    
+                    } else if (object_is_auto && init_count < MAX_LOCAL_INITS) {
+                    
+                        inits[init_count].offset = object_offset;
+                        inits[init_count].size = object_init_size;
+                        
+                        if (declarator_is_pointer && is_string_token ()) {
+                        
+                            inits[init_count].kind = LOCAL_INIT_ADDRESS;
+                            inits[init_count].symbol = emit_string_literal_global ();
+                            inits[init_count].value.low = 0;
+                            inits[init_count].value.high = 0;
+                            inits[init_count].source_offset = 0;
+                            inits[init_count].source_size = 0;
+                            
+                            switch_section (SECTION_TEXT);
+                        
+                        } else {
+                            parse_local_initializer_value (&inits[init_count], object_init_size, (!declarator_is_pointer && parsed_type_is_floating));
+                        }
+                        
+                        init_count++;
+                    
+                    } else {
+                        skip_initializer ();
+                    }
+                
+                }
+                
+                if (name && parsed_storage_class == STORAGE_STATIC) {
+                
+                    make_local_static_label (static_label, sizeof (static_label), name);
+                    
+                    if (add_global_symbol (static_label, GLOBAL_SYMBOL_OBJECT, 0, name_start, name_caret, name_line)) {
+                    
+                        set_global_symbol_size (static_label, declarator_is_pointer ? DATA_PTR : declarator_object_size (parsed_type_size));
+                        set_global_symbol_pointer_info (static_label, declarator_pointer_depth,
+                            declarator_is_pointer ? declarator_pointed_size_now () :
+                                declarator_element_size_from_fields (parsed_type_size, object_fields, object_field_count));
+                        set_global_symbol_unsigned (static_label, (declarator_is_pointer || declarator_has_function) ? 0 : parsed_type_is_unsigned);
+                        set_global_symbol_floating (static_label, (declarator_is_pointer || declarator_has_function) ? 0 : parsed_type_is_floating);
+                        set_global_symbol_array (static_label, declarator_has_array);
+                        set_global_symbol_array_count (static_label, declarator_has_array ? declarator_array_count : 0);
+                        set_global_symbol_array_dimensions (static_label, declarator_has_array ? declarator_array_dimensions : 0);
+                        set_global_symbol_array_element_size (static_label, declarator_array_element_size_now (parsed_type_size));
+                        
+                        emit_block_static_object (static_label,
+                            declarator_is_pointer ? DATA_PTR : (parsed_type_is_aggregate ? parsed_type_size : (parsed_type_size & 0x1f)),
+                                declarator_has_array, declarator_array_count,
+                                    object_fields, object_field_count,
+                                        init_values, init_symbols, init_value_count,
+                                            (!declarator_is_pointer && parsed_type_is_aggregate));
+                    
+                    }
+                    
+                    add_static_local_symbol (name, static_label,
+                        declarator_object_size (parsed_type_size),
+                            type_alignment (declarator_is_pointer ? DATA_PTR : parsed_type_size),
+                                (declarator_is_pointer ? 0 : parsed_type_is_unsigned),
+                                    block_scope_start, name_line, name_start, name_caret);
+                    
+                    set_local_symbol_floating (name, declarator_is_pointer ? 0 : parsed_type_is_floating);
+                    set_local_symbol_array (name, declarator_has_array);
+                    set_local_symbol_array_dimensions (name, declarator_has_array ? declarator_array_dimensions : 0);
+                    set_local_symbol_array_element_size (name, declarator_array_element_size_now (parsed_type_size));
+                    set_local_symbol_pointer_info (name, declarator_effective_pointer_depth_now (),
+                        declarator_effective_pointed_size_now (parsed_type_size, object_fields, object_field_count));
+                    
+                    if (!declarator_is_pointer && parsed_type_tag_name[0]) {
+                    
+                        struct local_symbol *lsym = find_local_symbol (name);
+                        
+                        if (lsym) {
+                            lsym->tag_name = xstrdup (parsed_type_tag_name);
+                        }
+                    
+                    }
+                
+                }
+                
+                for (i = 0; i < MAX_AGG_FIELDS; i++) {
+                
+                    if (init_symbols[i]) {
+                    
+                        free (init_symbols[i]);
+                        init_symbols[i] = 0;
+                    
+                    }
+                
+                }
+                
+                if (name) {
+                    free (name);
+                }
+                
+                if (!_accept (TOK_COMMA)) {
+                    break;
+                }
+            
+            }
+            
+            expect (TOK_SEMI, ";");
+            
+            if (block_stack_emitted) {
+                ensure_block_stack_allocated (block_stack_start, &block_stack_bytes, &block_stack_emitted);
+            }
+            
+            continue;
+        
+        }
+        
+        if (declaration_phase) {
+        
+            declaration_phase = 0;
+            
+            {
+            
+                long needed_stack_bytes = align_up_long (current_local_stack_size - block_stack_start, 4);
+                
+                if (!block_stack_emitted) {
+                
+                    block_stack_bytes = needed_stack_bytes;
+                    
+                    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;
+                    }
+                    
+                    block_stack_emitted = (block_stack_bytes > 0);
+                
+                } else if (needed_stack_bytes > block_stack_bytes) {
+                
+                    long extra_stack_bytes = needed_stack_bytes - block_stack_bytes;
+                    
+                    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;
+                    }
+                    
+                    block_stack_bytes = needed_stack_bytes;
+                
+                }
+            
+            }
+            
+            emit_local_initializers (inits, init_count);
+            init_count = 0;
+        
+        }
+        
+        parse_statement ();
+    
+    }
+    
+    if (declaration_phase) {
+    
+        /**
+         * The block contained declarations only.  We still need to reserve
+         * stack space for those automatic objects, otherwise a function like
+         *
+         *     void f(void) { int a; }
+         *
+         * would produce no `sub rsp, ...` at all.
+         */
+        declaration_phase = 0;
+        
+        {
+        
+            long needed_stack_bytes = align_up_long (current_local_stack_size - block_stack_start, 4);
+            
+            if (!block_stack_emitted) {
+            
+                block_stack_bytes = needed_stack_bytes;
+                
+                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) {
+            
+                if (!current_function_frame_deferred) {
+                    emit_stack_adjust (needed_stack_bytes - block_stack_bytes, 1);
+                }
+                
+                block_stack_bytes = needed_stack_bytes;
+            
+            }
+        
+        }
+        
+        emit_local_initializers (inits, init_count);
+        init_count = 0;
+    
+    }
+    
+    expect (TOK_RBRACE, "}");
+    
+    if (!is_function_body && !current_function_frame_deferred && block_stack_emitted && block_stack_bytes > 0) {
+    
+        emit_stack_adjust (block_stack_bytes, 0);
+        
+        if (current_block_cleanup_bytes >= block_stack_bytes) {
+            current_block_cleanup_bytes -= block_stack_bytes;
+        } else {
+            current_block_cleanup_bytes = 0;
+        }
+    
+    }
+    
+    current_parse_block_depth--;
+    truncate_local_symbols (block_local_start, block_stack_start);
+
+}
+
+static int is_assignment_operator (enum token_kind k) {
+
+    switch (k) {
+    
+        case TOK_ASSIGN:
+        case TOK_PLUSEQ:
+        case TOK_MINUSEQ:
+        case TOK_STAREQ:
+        case TOK_SLASHEQ:
+        case TOK_MODEQ:
+        case TOK_ANDEQ:
+        case TOK_OREQ:
+        case TOK_XOREQ:
+        case TOK_LSHEQ:
+        case TOK_RSHEQ:
+        
+            return 1;
+        
+        default:
+        
+            return 0;
+    
+    }
+
+}
+
+static int amd64_reg_is_qword_name (const char *reg) {
+
+    if (!reg) {
+        return 0;
+    }
+    
+    return strcmp (reg, "rax") == 0 || strcmp (reg, "rbx") == 0 ||
+        strcmp (reg, "rcx") == 0 || strcmp (reg, "rdx") == 0 ||
+        strcmp (reg, "rsi") == 0 || strcmp (reg, "rdi") == 0 ||
+        strcmp (reg, "r8") == 0 || strcmp (reg, "r9") == 0 ||
+        strcmp (reg, "r10") == 0 || strcmp (reg, "r11") == 0 ||
+        strcmp (reg, "r12") == 0 || strcmp (reg, "r13") == 0 ||
+        strcmp (reg, "r14") == 0 || strcmp (reg, "r15") == 0;
+
+}
+
+static const char *amd64_qword_reg_name_from_any (const char *reg) {
+
+    if (!reg) {
+        return reg;
+    }
+    
+    if (strcmp (reg, "rax") == 0 || strcmp (reg, "eax") == 0) return "rax";
+    if (strcmp (reg, "rbx") == 0 || strcmp (reg, "ebx") == 0) return "rbx";
+    if (strcmp (reg, "rcx") == 0 || strcmp (reg, "ecx") == 0) return "rcx";
+    if (strcmp (reg, "rdx") == 0 || strcmp (reg, "edx") == 0) return "rdx";
+    if (strcmp (reg, "rsi") == 0 || strcmp (reg, "esi") == 0) return "rsi";
+    if (strcmp (reg, "rdi") == 0 || strcmp (reg, "edi") == 0) return "rdi";
+    if (strcmp (reg, "r8") == 0 || strcmp (reg, "r8d") == 0) return "r8";
+    if (strcmp (reg, "r9") == 0 || strcmp (reg, "r9d") == 0) return "r9";
+    if (strcmp (reg, "r10") == 0 || strcmp (reg, "r10d") == 0) return "r10";
+    if (strcmp (reg, "r11") == 0 || strcmp (reg, "r11d") == 0) return "r11";
+    if (strcmp (reg, "r12") == 0 || strcmp (reg, "r12d") == 0) return "r12";
+    if (strcmp (reg, "r13") == 0 || strcmp (reg, "r13d") == 0) return "r13";
+    if (strcmp (reg, "r14") == 0 || strcmp (reg, "r14d") == 0) return "r14";
+    if (strcmp (reg, "r15") == 0 || strcmp (reg, "r15d") == 0) return "r15";
+    
+    return reg;
+
+}
+
+static const char *amd64_dword_reg_name_from_any (const char *reg) {
+
+    if (!reg) {
+        return reg;
+    }
+    
+    if (strcmp (reg, "rax") == 0) return "eax";
+    if (strcmp (reg, "rbx") == 0) return "ebx";
+    if (strcmp (reg, "rcx") == 0) return "ecx";
+    if (strcmp (reg, "rdx") == 0) return "edx";
+    if (strcmp (reg, "rsi") == 0) return "esi";
+    if (strcmp (reg, "rdi") == 0) return "edi";
+    if (strcmp (reg, "r8") == 0) return "r8d";
+    if (strcmp (reg, "r9") == 0) return "r9d";
+    if (strcmp (reg, "r10") == 0) return "r10d";
+    if (strcmp (reg, "r11") == 0) return "r11d";
+    if (strcmp (reg, "r12") == 0) return "r12d";
+    if (strcmp (reg, "r13") == 0) return "r13d";
+    if (strcmp (reg, "r14") == 0) return "r14d";
+    if (strcmp (reg, "r15") == 0) return "r15d";
+    
+    return reg;
+
+}
+
+static const char *amd64_word_reg_name_from_any (const char *reg) {
+
+    if (!reg) {
+        return reg;
+    }
+    
+    if (strcmp (reg, "rax") == 0 || strcmp (reg, "eax") == 0) return "ax";
+    if (strcmp (reg, "rbx") == 0 || strcmp (reg, "ebx") == 0) return "bx";
+    if (strcmp (reg, "rcx") == 0 || strcmp (reg, "ecx") == 0) return "cx";
+    if (strcmp (reg, "rdx") == 0 || strcmp (reg, "edx") == 0) return "dx";
+    if (strcmp (reg, "rsi") == 0 || strcmp (reg, "esi") == 0) return "si";
+    if (strcmp (reg, "rdi") == 0 || strcmp (reg, "edi") == 0) return "di";
+    if (strcmp (reg, "r8") == 0 || strcmp (reg, "r8d") == 0) return "r8w";
+    if (strcmp (reg, "r9") == 0 || strcmp (reg, "r9d") == 0) return "r9w";
+    if (strcmp (reg, "r10") == 0 || strcmp (reg, "r10d") == 0) return "r10w";
+    if (strcmp (reg, "r11") == 0 || strcmp (reg, "r11d") == 0) return "r11w";
+    if (strcmp (reg, "r12") == 0 || strcmp (reg, "r12d") == 0) return "r12w";
+    if (strcmp (reg, "r13") == 0 || strcmp (reg, "r13d") == 0) return "r13w";
+    if (strcmp (reg, "r14") == 0 || strcmp (reg, "r14d") == 0) return "r14w";
+    if (strcmp (reg, "r15") == 0 || strcmp (reg, "r15d") == 0) return "r15w";
+    
+    return reg;
+
+}
+
+static const char *amd64_byte_reg_name_from_any (const char *reg) {
+
+    if (!reg) {
+        return reg;
+    }
+    
+    if (strcmp (reg, "rax") == 0 || strcmp (reg, "eax") == 0 || strcmp (reg, "ax") == 0) return "al";
+    if (strcmp (reg, "rbx") == 0 || strcmp (reg, "ebx") == 0 || strcmp (reg, "bx") == 0) return "bl";
+    if (strcmp (reg, "rcx") == 0 || strcmp (reg, "ecx") == 0 || strcmp (reg, "cx") == 0) return "cl";
+    if (strcmp (reg, "rdx") == 0 || strcmp (reg, "edx") == 0 || strcmp (reg, "dx") == 0) return "dl";
+    if (strcmp (reg, "rsi") == 0 || strcmp (reg, "esi") == 0 || strcmp (reg, "si") == 0) return "sil";
+    if (strcmp (reg, "rdi") == 0 || strcmp (reg, "edi") == 0 || strcmp (reg, "di") == 0) return "dil";
+    if (strcmp (reg, "r8") == 0 || strcmp (reg, "r8d") == 0 || strcmp (reg, "r8w") == 0) return "r8b";
+    if (strcmp (reg, "r9") == 0 || strcmp (reg, "r9d") == 0 || strcmp (reg, "r9w") == 0) return "r9b";
+    if (strcmp (reg, "r10") == 0 || strcmp (reg, "r10d") == 0 || strcmp (reg, "r10w") == 0) return "r10b";
+    if (strcmp (reg, "r11") == 0 || strcmp (reg, "r11d") == 0 || strcmp (reg, "r11w") == 0) return "r11b";
+    if (strcmp (reg, "r12") == 0 || strcmp (reg, "r12d") == 0 || strcmp (reg, "r12w") == 0) return "r12b";
+    if (strcmp (reg, "r13") == 0 || strcmp (reg, "r13d") == 0 || strcmp (reg, "r13w") == 0) return "r13b";
+    if (strcmp (reg, "r14") == 0 || strcmp (reg, "r14d") == 0 || strcmp (reg, "r14w") == 0) return "r14b";
+    if (strcmp (reg, "r15") == 0 || strcmp (reg, "r15d") == 0 || strcmp (reg, "r15w") == 0) return "r15b";
+    
+    return reg;
+
+}
+
+static int amd64_scalar_size_is_qword (int size) {
+    return size == (DATA_PTR & 0x1f);
+}
+
+static void emit_load_local_to_reg_ex (const char *reg, long offset, int size, int is_unsigned) {
+
+    const char *dreg;
+    char memref[64];
+    
+    size &= 0x1f;
+    
+    if (!state->ofp || !reg) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_rbp_offset (memref, sizeof (memref), offset);
+        
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s %s, byte %s\n" : "    %s %s, byte ptr %s\n"), is_unsigned ? "movzx" : "movsx", (is_unsigned && amd64_reg_is_qword_name (reg)) ? amd64_dword_reg_name_from_any (reg) : reg, memref);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s %s, word %s\n" : "    %s %s, word ptr %s\n"), is_unsigned ? "movzx" : "movsx", (is_unsigned && amd64_reg_is_qword_name (reg)) ? amd64_dword_reg_name_from_any (reg) : reg, memref);
+        } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_PTR & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, qword %s\n" : "    mov %s, qword ptr %s\n"), amd64_qword_reg_name_from_any (reg), memref);
+        } else if (amd64_reg_is_qword_name (reg)) {
+        
+            if (is_unsigned) {
+            
+                dreg = amd64_dword_reg_name_from_any (reg);
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword %s\n" : "    mov %s, dword ptr %s\n"), dreg, memref);
+            
+            } else {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movsxd %s, dword %s\n" : "    movsxd %s, dword ptr %s\n"), reg, memref);
+            }
+        
+        } else {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword %s\n" : "    mov %s, dword ptr %s\n"), reg, memref);
+        }
+    
+    } else {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+        
+            if (amd64_reg_is_qword_name (reg)) {
+                fprintf (state->ofp, "    %s %ld(%%rbp), %%%s\n", is_unsigned ? "movzbl" : "movsbq", offset, is_unsigned ? amd64_dword_reg_name_from_any (reg) : reg);
+            } else {
+                fprintf (state->ofp, "    %s %ld(%%rbp), %%%s\n", is_unsigned ? "movzbl" : "movsbl", offset, reg);
+            }
+        
+        } else if (size == (DATA_SHORT & 0x1f)) {
+        
+            if (amd64_reg_is_qword_name (reg)) {
+                fprintf (state->ofp, "    %s %ld(%%rbp), %%%s\n", is_unsigned ? "movzwl" : "movswq", offset, is_unsigned ? amd64_dword_reg_name_from_any (reg) : reg);
+            } else {
+                fprintf (state->ofp, "    %s %ld(%%rbp), %%%s\n", is_unsigned ? "movzwl" : "movswl", offset, reg);
+            }
+        
+        } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_PTR & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
+            fprintf (state->ofp, "    movq %ld(%%rbp), %%%s\n", offset, amd64_qword_reg_name_from_any (reg));
+        } else if (amd64_reg_is_qword_name (reg)) {
+        
+            if (is_unsigned) {
+                fprintf (state->ofp, "    movl %ld(%%rbp), %%%s\n", offset, amd64_dword_reg_name_from_any (reg));
+            } else {
+                fprintf (state->ofp, "    movslq %ld(%%rbp), %%%s\n", offset, reg);
+            }
+        
+        } else {
+            fprintf (state->ofp, "    movl %ld(%%rbp), %%%s\n", offset, reg);
+        }
+    
+    }
+
+}
+
+static void emit_load_local_to_reg (const char *reg, long offset, int size) {
+    emit_load_local_to_reg_ex (reg, offset, size, 0);
+}
+
+static void emit_load_global_to_reg_ex (const char *reg, const char *symbol, int size, int is_unsigned) {
+
+    const char *asm_symbol, *dreg;
+    size &= 0x1f;
+    
+    if (!state->ofp || !reg || !symbol) {
+        return;
+    }
+    
+    emit_extern_reference_symbol (symbol, size);
+    
+    if (get_global_symbol_dllimport (symbol) && get_global_symbol_kind (symbol) == GLOBAL_SYMBOL_OBJECT) {
+    
+        asm_symbol = asm_global_import_symbol_name (symbol);
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, qword [%s]\n" : "    mov %s, qword ptr %s\n"), amd64_qword_reg_name_from_any (reg), asm_symbol);
+            
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s %s, byte [%s]\n" : "    %s %s, byte ptr [%s]\n"), is_unsigned ? "movzx" : "movsx", (is_unsigned && amd64_reg_is_qword_name (reg)) ? amd64_dword_reg_name_from_any (reg) : reg, amd64_qword_reg_name_from_any (reg));
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s %s, word [%s]\n" : "    %s %s, word ptr [%s]\n"), is_unsigned ? "movzx" : "movsx", (is_unsigned && amd64_reg_is_qword_name (reg)) ? amd64_dword_reg_name_from_any (reg) : reg, amd64_qword_reg_name_from_any (reg));
+            } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_PTR & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, qword [%s]\n" : "    mov %s, qword ptr [%s]\n"), amd64_qword_reg_name_from_any (reg), amd64_qword_reg_name_from_any (reg));
+            } else if (amd64_reg_is_qword_name (reg)) {
+            
+                if (is_unsigned) {
+                
+                    dreg = amd64_dword_reg_name_from_any (reg);
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [%s]\n" : "    mov %s, dword ptr [%s]\n"), dreg, amd64_qword_reg_name_from_any (reg));
+                
+                } else {
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movsxd %s, dword [%s]\n" : "    movsxd %s, dword ptr [%s]\n"), reg, amd64_qword_reg_name_from_any (reg));
+                }
+            
+            } else {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [%s]\n" : "    mov %s, dword ptr [%s]\n"), reg, amd64_qword_reg_name_from_any (reg));
+            }
+        
+        } else {
+        
+            fprintf (state->ofp, "    movq %s(%%rip), %%%s\n", asm_symbol, amd64_qword_reg_name_from_any (reg));
+            
+            if (size == (DATA_CHAR & 0x1f)) {
+            
+                if (amd64_reg_is_qword_name (reg)) {
+                    fprintf (state->ofp, "    %s (%%%s), %%%s\n", is_unsigned ? "movzbl" : "movsbq", reg, is_unsigned ? amd64_dword_reg_name_from_any (reg) : reg);
+                } else {
+                    fprintf (state->ofp, "    %s (%%%s), %%%s\n", is_unsigned ? "movzbl" : "movsbl", reg, reg);
+                }
+            
+            } else if (size == (DATA_SHORT & 0x1f)) {
+            
+                if (amd64_reg_is_qword_name (reg)) {
+                    fprintf (state->ofp, "    %s (%%%s), %%%s\n", is_unsigned ? "movzwl" : "movswq", reg, is_unsigned ? amd64_dword_reg_name_from_any (reg) : reg);
+                } else {
+                    fprintf (state->ofp, "    %s (%%%s), %%%s\n", is_unsigned ? "movzwl" : "movswl", reg, reg);
+                }
+            
+            } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_PTR & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
+                fprintf (state->ofp, "    movq (%%%s), %%%s\n", reg, amd64_qword_reg_name_from_any (reg));
+            } else if (amd64_reg_is_qword_name (reg)) {
+            
+                if (is_unsigned) {
+                    fprintf (state->ofp, "    movl (%%%s), %%%s\n", reg, amd64_dword_reg_name_from_any (reg));
+                } else {
+                    fprintf (state->ofp, "    movslq (%%%s), %%%s\n", reg, reg);
+                }
+            
+            } else {
+                fprintf (state->ofp, "    movl (%%%s), %%%s\n", reg, reg);
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    asm_symbol = asm_global_symbol_name (symbol);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s %s, byte [%s]\n" : "    %s %s, byte ptr %s\n"), is_unsigned ? "movzx" : "movsx", (is_unsigned && amd64_reg_is_qword_name (reg)) ? amd64_dword_reg_name_from_any (reg) : reg, asm_symbol);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s %s, word [%s]\n" : "    %s %s, word ptr %s\n"), is_unsigned ? "movzx" : "movsx", (is_unsigned && amd64_reg_is_qword_name (reg)) ? amd64_dword_reg_name_from_any (reg) : reg, asm_symbol);
+        } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_PTR & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, qword [%s]\n" : "    mov %s, qword ptr %s\n"), amd64_qword_reg_name_from_any (reg), asm_symbol);
+        } else if (amd64_reg_is_qword_name (reg)) {
+        
+            if (is_unsigned) {
+            
+                dreg = amd64_dword_reg_name_from_any (reg);
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [%s]\n" : "    mov %s, dword ptr %s\n"), dreg, asm_symbol);
+            
+            } else {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movsxd %s, dword [%s]\n" : "    movsxd %s, dword ptr %s\n"), reg, asm_symbol);
+            }
+        
+        } else {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [%s]\n" : "    mov %s, dword ptr %s\n"), reg, asm_symbol);
+        }
+    
+    } else {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+        
+            if (amd64_reg_is_qword_name (reg)) {
+                fprintf (state->ofp, "    %s %s(%%rip), %%%s\n", is_unsigned ? "movzbl" : "movsbq", asm_symbol, is_unsigned ? amd64_dword_reg_name_from_any (reg) : reg);
+            } else {
+                fprintf (state->ofp, "    %s %s(%%rip), %%%s\n", is_unsigned ? "movzbl" : "movsbl", asm_symbol, reg);
+            }
+        
+        } else if (size == (DATA_SHORT & 0x1f)) {
+        
+            if (amd64_reg_is_qword_name (reg)) {
+                fprintf (state->ofp, "    %s %s(%%rip), %%%s\n", is_unsigned ? "movzwl" : "movswq", asm_symbol, is_unsigned ? amd64_dword_reg_name_from_any (reg) : reg);
+            } else {
+                fprintf (state->ofp, "    %s %s(%%rip), %%%s\n", is_unsigned ? "movzwl" : "movswl", asm_symbol, reg);
+            }
+        
+        } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_PTR & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
+            fprintf (state->ofp, "    movq %s(%%rip), %%%s\n", asm_symbol, amd64_qword_reg_name_from_any (reg));
+        } else if (amd64_reg_is_qword_name (reg)) {
+        
+            if (is_unsigned) {
+                fprintf (state->ofp, "    movl %s(%%rip), %%%s\n", asm_symbol, amd64_dword_reg_name_from_any (reg));
+            } else {
+                fprintf (state->ofp, "    movslq %s(%%rip), %%%s\n", asm_symbol, reg);
+            }
+        
+        } else {
+            fprintf (state->ofp, "    movl %s(%%rip), %%%s\n", asm_symbol, reg);
+        }
+    
+    }
+
+}
+
+static void emit_load_global_to_reg (const char *reg, const char *symbol, int size) {
+    emit_load_global_to_reg_ex (reg, symbol, size, 0);
+}
+
+static void emit_store_reg_to_local (long offset, int size, const char *reg) {
+
+    char memref[64];
+    
+    const char *breg;
+    const char *wreg;
+    const char *dreg;
+    const char *qreg;
+    
+    if (!state->ofp || !reg) {
+        return;
+    }
+    
+    breg = amd64_byte_reg_name_from_any (reg);
+    wreg = amd64_word_reg_name_from_any (reg);
+    dreg = amd64_dword_reg_name_from_any (reg);
+    qreg = amd64_qword_reg_name_from_any (reg);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_rbp_offset (memref, sizeof (memref), offset);
+        
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov byte %s, %s\n" : "    mov byte ptr %s, %s\n"), memref, breg);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov word %s, %s\n" : "    mov word ptr %s, %s\n"), memref, wreg);
+        } else if (amd64_scalar_size_is_qword (size)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov qword %s, %s\n" : "    mov qword ptr %s, %s\n"), memref, qreg);
+        } else {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword %s, %s\n" : "    mov dword ptr %s, %s\n"), memref, dreg);
+        }
+    
+    } else {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, "    movb %%%s, %ld(%%rbp)\n", breg, offset);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, "    movw %%%s, %ld(%%rbp)\n", wreg, offset);
+        } else if (amd64_scalar_size_is_qword (size)) {
+            fprintf (state->ofp, "    movq %%%s, %ld(%%rbp)\n", qreg, offset);
+        } else {
+            fprintf (state->ofp, "    movl %%%s, %ld(%%rbp)\n", dreg, offset);
+        }
+    
+    }
+
+}
+
+static void emit_store_reg_to_global (const char *symbol, int size, const char *reg) {
+
+    const char *asm_symbol;
+    
+    const char *breg;
+    const char *wreg;
+    const char *dreg;
+    const char *qreg;
+    
+    if (!state->ofp || !symbol || !reg) {
+        return;
+    }
+    
+    breg = amd64_byte_reg_name_from_any (reg);
+    wreg = amd64_word_reg_name_from_any (reg);
+    dreg = amd64_dword_reg_name_from_any (reg);
+    qreg = amd64_qword_reg_name_from_any (reg);
+    
+    if (get_global_symbol_dllimport (symbol) && get_global_symbol_kind (symbol) == GLOBAL_SYMBOL_OBJECT) {
+    
+        const char *addr_reg = (strcmp (qreg, "rcx") == 0) ? "rdx" : "rcx";
+        
+        asm_symbol = asm_global_import_symbol_name (symbol);
+        emit_extern_reference_symbol (symbol, size);
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, qword [%s]\n" : "    mov %s, qword ptr %s\n"), addr_reg, asm_symbol);
+            
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov byte [%s], %s\n" : "    mov byte ptr [%s], %s\n"), addr_reg, breg);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov word [%s], %s\n" : "    mov word ptr [%s], %s\n"), addr_reg, wreg);
+            } else if (amd64_scalar_size_is_qword (size)) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov qword [%s], %s\n" : "    mov qword ptr [%s], %s\n"), addr_reg, qreg);
+            } else {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword [%s], %s\n" : "    mov dword ptr [%s], %s\n"), addr_reg, dreg);
+            }
+        
+        } else {
+        
+            fprintf (state->ofp, "    movq %s(%%rip), %%%s\n", asm_symbol, addr_reg);
+            
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    movb %%%s, (%%%s)\n", breg, addr_reg);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    movw %%%s, (%%%s)\n", wreg, addr_reg);
+            } else if (amd64_scalar_size_is_qword (size)) {
+                fprintf (state->ofp, "    movq %%%s, (%%%s)\n", qreg, addr_reg);
+            } else {
+                fprintf (state->ofp, "    movl %%%s, (%%%s)\n", dreg, addr_reg);
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    asm_symbol = asm_global_symbol_name (symbol);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov byte [%s], %s\n" : "    mov byte ptr %s, %s\n"), asm_symbol, breg);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov word [%s], %s\n" : "    mov word ptr %s, %s\n"), asm_symbol, wreg);
+        } else if (amd64_scalar_size_is_qword (size)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov qword [%s], %s\n" : "    mov qword ptr %s, %s\n"), asm_symbol, qreg);
+        } else {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword [%s], %s\n" : "    mov dword ptr %s, %s\n"), asm_symbol, dreg);
+        }
+    
+    } else {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, "    movb %%%s, %s(%%rip)\n", breg, asm_symbol);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, "    movw %%%s, %s(%%rip)\n", wreg, asm_symbol);
+        } else if (amd64_scalar_size_is_qword (size)) {
+            fprintf (state->ofp, "    movq %%%s, %s(%%rip)\n", qreg, asm_symbol);
+        } else {
+            fprintf (state->ofp, "    movl %%%s, %s(%%rip)\n", dreg, asm_symbol);
+        }
+    
+    }
+
+}
+
+static void emit_load_local64_to_pair (long offset, const char *lo, const char *hi) {
+
+    const char *qlo;
+    char memref_lo[64], memref_hi[64];
+    
+    if (!state->ofp || !lo || !hi) {
+        return;
+    }
+    
+    if ((strcmp (lo, "rax") == 0 && strcmp (hi, "rdx") == 0) || (strcmp (lo, "rbx") == 0 && strcmp (hi, "rcx") == 0) || (strcmp (lo, "rax") == 0 && strcmp (hi, "r10") == 0)) {
+    
+        qlo = (strcmp (lo, "rbx") == 0) ? "rbx" : "rax";
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            format_intel_rbp_offset (memref_lo, sizeof (memref_lo), offset);
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, qword %s\n" : "    mov %s, qword ptr %s\n"), qlo, memref_lo);
+        
+        } else {
+            fprintf (state->ofp, "    movq %ld(%%rbp), %%%s\n", offset, qlo);
+        }
+        
+        return;
+    
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_rbp_offset (memref_lo, sizeof (memref_lo), offset);
+        format_intel_rbp_offset (memref_hi, sizeof (memref_hi), offset + 4);
+        
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword %s\n" : "    mov %s, dword ptr %s\n"), amd64_dword_reg_name_from_any (lo), memref_lo);
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword %s\n" : "    mov %s, dword ptr %s\n"), amd64_dword_reg_name_from_any (hi), memref_hi);
+    
+    } else {
+    
+        fprintf (state->ofp, "    movl %ld(%%rbp), %%%s\n", offset, amd64_dword_reg_name_from_any (lo));
+        fprintf (state->ofp, "    movl %ld(%%rbp), %%%s\n", offset + 4, amd64_dword_reg_name_from_any (hi));
+    
+    }
+
+}
+
+static void emit_store_pair_to_local64 (long offset, const char *lo, const char *hi) {
+
+    char memref_lo[64];
+    
+    if (!state->ofp || !lo || !hi) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_rbp_offset (memref_lo, sizeof (memref_lo), offset);
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov qword %s, %s\n" : "    mov qword ptr %s, %s\n"), memref_lo, amd64_qword_reg_name_from_any (lo));
+    
+    } else {
+        fprintf (state->ofp, "    movq %%%s, %ld(%%rbp)\n", amd64_qword_reg_name_from_any (lo), offset);
+    }
+
+}
+
+static void emit_store_rax_to_local64 (long offset) {
+
+    char memref[64];
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_rbp_offset (memref, sizeof (memref), offset);
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov qword %s, rax\n" : "    mov qword ptr %s, rax\n"), memref);
+    
+    } else {
+        fprintf (state->ofp, "    movq %%rax, %ld(%%rbp)\n", offset);
+    }
+
+}
+
+static void emit_load_local64_to_rax (long offset) {
+
+    char memref[64];
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_rbp_offset (memref, sizeof (memref), offset);
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov rax, qword %s\n" : "    mov rax, qword ptr %s\n"), memref);
+    
+    } else {
+        fprintf (state->ofp, "    movq %ld(%%rbp), %%rax\n", offset);
+    }
+
+}
+
+static void emit_load_global64_to_rax (const char *symbol) {
+
+    const char *asm_symbol;
+    
+    if (!state->ofp || !symbol) {
+        return;
+    }
+    
+    emit_extern_reference_symbol (symbol, DATA_LLONG & 0x1f);
+    asm_symbol = asm_global_symbol_name (symbol);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov rax, qword [%s]\n" : "    mov rax, qword ptr %s\n"), asm_symbol);
+    } else {
+        fprintf (state->ofp, "    movq %s(%%rip), %%rax\n", asm_symbol);
+    }
+
+}
+
+static void emit_load_global64_to_pair (const char *lo, const char *hi, const char *symbol) {
+
+    const char *qlo;
+    const char *asm_symbol;
+    
+    if (!state->ofp || !lo || !hi || !symbol) {
+        return;
+    }
+    
+    emit_extern_reference_symbol (symbol, DATA_LLONG & 0x1f);
+    asm_symbol = asm_global_symbol_name (symbol);
+    
+    if ((strcmp (lo, "rax") == 0 && strcmp (hi, "rdx") == 0) || (strcmp (lo, "rbx") == 0 && strcmp (hi, "rcx") == 0) || (strcmp (lo, "rax") == 0 && strcmp (hi, "r10") == 0)) {
+    
+        qlo = (strcmp (lo, "rbx") == 0) ? "rbx" : "rax";
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, qword [%s]\n" : "    mov %s, qword ptr %s\n"), qlo, asm_symbol);
+        } else {
+            fprintf (state->ofp, "    movq %s(%%rip), %%%s\n", asm_symbol, qlo);
+        }
+        
+        return;
+    
+    }
+    
+    (void) hi;
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, qword [%s]\n" : "    mov %s, qword ptr %s\n"), amd64_qword_reg_name_from_any (lo), asm_symbol);
+    } else {
+        fprintf (state->ofp, "    movq %s(%%rip), %%%s\n", asm_symbol, amd64_qword_reg_name_from_any (lo));
+    }
+
+}
+
+static void emit_store_pair_to_global64 (const char *symbol, const char *lo, const char *hi) {
+
+    const char *asm_symbol;
+    
+    if (!state->ofp || !symbol || !lo || !hi) {
+        return;
+    }
+    
+    emit_extern_reference_symbol (symbol, DATA_LLONG & 0x1f);
+    asm_symbol = asm_global_symbol_name (symbol);
+    
+    (void) hi;
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov qword [%s], %s\n" : "    mov qword ptr %s, %s\n"), asm_symbol, amd64_qword_reg_name_from_any (lo));
+    } else {
+        fprintf (state->ofp, "    movq %%%s, %s(%%rip)\n", amd64_qword_reg_name_from_any (lo), asm_symbol);
+    }
+
+}
+
+static void emit_call_identifier_to_reg_now (const char *name, const char *reg, const char *name_start, const char *name_caret, unsigned long name_line);
+
+static int emit_push_aggregate_from_addr_reg_now (const char *reg, int size) {
+
+    int offset;
+    int chunk;
+    
+    if (!reg || size <= (DATA_PTR & 0x1f)) {
+        return 0;
+    }
+    
+    if (!state->ofp) {
+        return 1;
+    }
+    
+    for (offset = size; offset > 0; ) {
+    
+        if (offset >= 8) {
+        
+            chunk = 8;
+            offset -= 8;
+        
+        } else if (offset >= 4) {
+        
+            chunk = 4;
+            offset -= 4;
+        
+        } else if (offset >= 2) {
+        
+            chunk = 2;
+            offset -= 2;
+        
+        } else {
+        
+            chunk = 1;
+            offset -= 1;
+        
+        }
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            if (state->syntax & ASM_SYNTAX_NASM) {
+            
+                if (chunk == 8) {
+                    fprintf (state->ofp, "    push qword [%s + %d]\n", reg, offset);
+                } else if (chunk == 4) {
+                
+                    fprintf (state->ofp, "    sub rsp, 8\n");
+                    
+                    fprintf (state->ofp, "    xor rax, rax\n");
+                    fprintf (state->ofp, "    mov eax, dword [%s + %d]\n", reg, offset);
+                    fprintf (state->ofp, "    mov qword [rsp], rax\n");
+                
+                } else if (chunk == 2) {
+                
+                    fprintf (state->ofp, "    movzx edx, word [%s + %d]\n", reg, offset);
+                    fprintf (state->ofp, "    push rdx\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    movzx edx, byte [%s + %d]\n", reg, offset);
+                    fprintf (state->ofp, "    push rdx\n");
+                
+                }
+            
+            } else {
+            
+                if (chunk == 8) {
+                    fprintf (state->ofp, "    push qword ptr [%s + %d]\n", reg, offset);
+                } else if (chunk == 4) {
+                
+                    fprintf (state->ofp, "    sub rsp, 8\n");
+                    
+                    fprintf (state->ofp, "    xor rax, rax\n");
+                    fprintf (state->ofp, "    mov eax, dword ptr [%s + %d]\n", reg, offset);
+                    fprintf (state->ofp, "    mov qword ptr [rsp], rax\n");
+                
+                } else if (chunk == 2) {
+                
+                    fprintf (state->ofp, "    movzx edx, word ptr [%s + %d]\n", reg, offset);
+                    fprintf (state->ofp, "    push rdx\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    movzx edx, byte ptr [%s + %d]\n", reg, offset);
+                    fprintf (state->ofp, "    push rdx\n");
+                
+                }
+            
+            }
+        
+        } else {
+        
+            if (chunk == 8) {
+                fprintf (state->ofp, "    pushq %d(%%%s)\n", offset, reg);
+            } else if (chunk == 4) {
+            
+                fprintf (state->ofp, "    subq $8, %%rsp\n");
+                
+                fprintf (state->ofp, "    xorq %%rax, %%rax\n");
+                fprintf (state->ofp, "    movl %d(%%%s), %%eax\n", offset, reg);
+                fprintf (state->ofp, "    movq %%rax, (%%rsp)\n");
+            
+            } else if (chunk == 2) {
+            
+                fprintf (state->ofp, "    movzwl %d(%%%s), %%edx\n", offset, reg);
+                fprintf (state->ofp, "    pushq %%rdx\n");
+            
+            } else {
+            
+                fprintf (state->ofp, "    movzbl %d(%%%s), %%edx\n", offset, reg);
+                fprintf (state->ofp, "    pushq %%rdx\n");
+            
+            }
+        
+        }
+    
+    }
+    
+    return 1;
+
+}
+
+static void emit_call_pointer_in_reg_now (const char *fn_reg, const char *result_reg);
+
+static void amd64_emit_sub_rsp_bytes (int bytes);
+static void amd64_emit_add_rsp_bytes (int bytes);
+
+static void amd64_emit_store_rax_to_home_arg (int index);
+static void amd64_emit_load_home_arg_to_reg (int index);
+
+static void amd64_emit_store_rax_to_stack_arg (int slot);
+static void amd64_emit_move_rax_to_arg_reg (int index);
+static void amd64_emit_move_st0_to_arg (int index, int size, int duplicate_gp);
+
+static int is_arithmetic_binary_operator (enum token_kind k) {
+
+    return  k == TOK_PLUS || k == TOK_MINUS || k == TOK_STAR || k == TOK_BSLASH ||
+                k == TOK_MOD || k == TOK_AMPER || k == TOK_PIPE || k == TOK_CARET ||
+                    k == TOK_LSH || k == TOK_RSH;
+
+}
+
+static const char *amd64_qreg_name (const char *reg) {
+
+    if (!reg) return reg;
+    if (strcmp (reg, "rax") == 0 || strcmp (reg, "eax") == 0) return "rax";
+    if (strcmp (reg, "rbx") == 0 || strcmp (reg, "ebx") == 0) return "rbx";
+    if (strcmp (reg, "rcx") == 0 || strcmp (reg, "ecx") == 0) return "rcx";
+    if (strcmp (reg, "rdx") == 0 || strcmp (reg, "edx") == 0) return "rdx";
+    if (strcmp (reg, "rsi") == 0 || strcmp (reg, "esi") == 0) return "rsi";
+    if (strcmp (reg, "rdi") == 0 || strcmp (reg, "edi") == 0) return "rdi";
+    if (strcmp (reg, "r8") == 0 || strcmp (reg, "r8d") == 0) return "r8";
+    if (strcmp (reg, "r9") == 0 || strcmp (reg, "r9d") == 0) return "r9";
+    if (strcmp (reg, "r10") == 0 || strcmp (reg, "r10d") == 0) return "r10";
+    if (strcmp (reg, "r11") == 0 || strcmp (reg, "r11d") == 0) return "r11";
+    if (strcmp (reg, "r12") == 0 || strcmp (reg, "r12d") == 0) return "r12";
+    if (strcmp (reg, "r13") == 0 || strcmp (reg, "r13d") == 0) return "r13";
+    if (strcmp (reg, "r14") == 0 || strcmp (reg, "r14d") == 0) return "r14";
+    if (strcmp (reg, "r15") == 0 || strcmp (reg, "r15d") == 0) return "r15";
+    return reg;
+
+}
+
+static void emit_push_reg_now (const char *reg) {
+
+    reg = amd64_qreg_name (reg);
+    
+    if (!state->ofp || !reg) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    push %s\n", reg);
+    } else {
+        fprintf (state->ofp, "    pushq %%%s\n", reg);
+    }
+    
+    amd64_note_stack_sub (DATA_PTR & 0x1f);
+
+}
+
+static void emit_pop_reg_now (const char *reg) {
+
+    reg = amd64_qreg_name (reg);
+    
+    if (!state->ofp || !reg) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    pop %s\n", reg);
+    } else {
+        fprintf (state->ofp, "    popq %%%s\n", reg);
+    }
+    
+    amd64_note_stack_add (DATA_PTR & 0x1f);
+
+}
+
+static void emit_mov_reg_to_reg_now (const char *dst, const char *src) {
+
+    dst = amd64_qreg_name (dst);
+    src = amd64_qreg_name (src);
+    
+    if (!state->ofp || !dst || !src || strcmp (dst, src) == 0) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    mov %s, %s\n", dst, src);
+    } else {
+        fprintf (state->ofp, "    movq %%%s, %%%s\n", src, dst);
+    }
+
+}
+
+static void emit_load_indexed_pointer_to_reg_now (const char *base_reg, const char *index_reg) {
+
+    if (!state->ofp || !base_reg || !index_reg) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+            fprintf (state->ofp, "    mov %s, qword [%s + %s * 8]\n", base_reg, base_reg, index_reg);
+        } else {
+            fprintf (state->ofp, "    mov %s, qword ptr [%s + %s * 8]\n", base_reg, base_reg, index_reg);
+        }
+    
+    } else {
+        fprintf (state->ofp, "    movq (%%%s,%%%s,8), %%%s\n", base_reg, index_reg, base_reg);
+    }
+
+}
+
+static void emit_load_indexed_char_to_reg_now (const char *base_reg, const char *index_reg, const char *dst_reg, int is_unsigned) {
+
+    if (!state->ofp || !base_reg || !index_reg || !dst_reg) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+            fprintf (state->ofp, "    %s %s, byte [%s + %s]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg);
+        } else {
+            fprintf (state->ofp, "    %s %s, byte ptr [%s + %s]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg);
+        }
+    
+    } else {
+    
+        if (amd64_reg_is_qword_name (dst_reg)) {
+            fprintf (state->ofp, "    %s (%%%s,%%%s), %%%s\n", is_unsigned ? "movzbl" : "movsbq", base_reg, index_reg, is_unsigned ? amd64_dword_reg_name_from_any (dst_reg) : dst_reg);
+        } else {
+            fprintf (state->ofp, "    %s (%%%s,%%%s), %%%s\n", is_unsigned ? "movzbl" : "movsbl", base_reg, index_reg, dst_reg);
+        }
+    
+    }
+
+}
+
+static void emit_load_indexed_sized_to_reg_ex_now (const char *base_reg, const char *index_reg, const char *dst_reg, int elem_size, int is_unsigned) {
+
+    int scale = 1;
+    
+    const char *gasop = is_unsigned ? "movzbl" : "movsbl";
+    const char *atype = "byte";
+    
+    if (!state->ofp || !base_reg || !index_reg || !dst_reg) {
+        return;
+    }
+    
+    elem_size &= 0x1f;
+    
+    if (elem_size == (DATA_SHORT & 0x1f)) {
+    
+        scale = 2;
+        
+        gasop = is_unsigned ? "movzwl" : "movswl";
+        atype = "word";
+    
+    } else if (elem_size == (DATA_INT & 0x1f) || elem_size == (DATA_LONG & 0x1f)) {
+    
+        scale = 4;
+        
+        gasop = is_unsigned ? "movl" : "movslq";
+        atype = "dword";
+    
+    } else if (elem_size == (DATA_LLONG & 0x1f) || elem_size == (DATA_PTR & 0x1f) || elem_size == (DATA_DOUBLE & 0x1f)) {
+    
+        scale = 8;
+        
+        atype = "qword";
+        gasop = "movq";
+    
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (elem_size == (DATA_CHAR & 0x1f)) {
+            emit_load_indexed_char_to_reg_now (base_reg, index_reg, dst_reg, is_unsigned);
+        } else if (scale == 1) {
+        
+            if (strcmp (atype, "byte") == 0) {
+            
+                if (state->syntax & ASM_SYNTAX_NASM) {
+                    fprintf (state->ofp, "    %s %s, byte [%s + %s]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg);
+                } else {
+                    fprintf (state->ofp, "    %s %s, byte ptr [%s + %s]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg);
+                }
+            
+            } else if (elem_size == (DATA_SHORT & 0x1f)) {
+            
+                if (state->syntax & ASM_SYNTAX_NASM) {
+                    fprintf (state->ofp, "    %s %s, word [%s + %s]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg);
+                } else {
+                    fprintf (state->ofp, "    %s %s, word ptr [%s + %s]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg);
+                }
+            
+            } else if (strcmp (atype, "dword") == 0 && amd64_reg_is_qword_name (dst_reg)) {
+            
+                if (is_unsigned) {
+                
+                    const char *dreg = amd64_dword_reg_name_from_any (dst_reg);
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [%s + %s]\n" : "    mov %s, dword ptr [%s + %s]\n"), dreg, base_reg, index_reg);
+                
+                } else {
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movsxd %s, dword [%s + %s]\n" : "    movsxd %s, dword ptr [%s + %s]\n"), dst_reg, base_reg, index_reg);
+                }
+            
+            } else if (state->syntax & ASM_SYNTAX_NASM) {
+                fprintf (state->ofp, "    mov %s, %s [%s + %s]\n", dst_reg, atype, base_reg, index_reg);
+            } else {
+                fprintf (state->ofp, "    mov %s, %s ptr [%s + %s]\n", dst_reg, atype, base_reg, index_reg);
+            }
+        
+        } else {
+        
+            if (strcmp (atype, "byte") == 0) {
+            
+                if (state->syntax & ASM_SYNTAX_NASM) {
+                    fprintf (state->ofp, "    %s %s, byte [%s + %s * %d]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg, scale);
+                } else {
+                    fprintf (state->ofp, "    %s %s, byte ptr [%s + %s * %d]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg, scale);
+                }
+            
+            } else if (elem_size == (DATA_SHORT & 0x1f)) {
+
+                if (state->syntax & ASM_SYNTAX_NASM) {
+                    fprintf (state->ofp, "    %s %s, word [%s + %s * %d]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg, scale);
+                } else {
+                    fprintf (state->ofp, "    %s %s, word ptr [%s + %s * %d]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg, scale);
+                }
+
+            } else if (strcmp (atype, "dword") == 0 && amd64_reg_is_qword_name (dst_reg)) {
+            
+                if (is_unsigned) {
+                
+                    const char *dreg = amd64_dword_reg_name_from_any (dst_reg);
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [%s + %s * %d]\n" : "    mov %s, dword ptr [%s + %s * %d]\n"), dreg, base_reg, index_reg, scale);
+                
+                } else {
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movsxd %s, dword [%s + %s * %d]\n" : "    movsxd %s, dword ptr [%s + %s * %d]\n"), dst_reg, base_reg, index_reg, scale);
+                }
+            
+            } else if (state->syntax & ASM_SYNTAX_NASM) {
+                fprintf (state->ofp, "    mov %s, %s [%s + %s * %d]\n", dst_reg, atype, base_reg, index_reg, scale);
+            } else {
+                fprintf (state->ofp, "    mov %s, %s ptr [%s + %s * %d]\n", dst_reg, atype, base_reg, index_reg, scale);
+            }
+        
+        }
+    
+    } else {
+    
+        const char *att_dst_reg = dst_reg;
+        const char *att_op = gasop;
+        
+        if (amd64_reg_is_qword_name (dst_reg)) {
+        
+            if (elem_size == (DATA_CHAR & 0x1f)) {
+            
+                if (is_unsigned) {
+                
+                    att_dst_reg = amd64_dword_reg_name_from_any (dst_reg);
+                    att_op = "movzbl";
+                
+                } else {
+                    att_op = "movsbq";
+                }
+            
+            } else if (elem_size == (DATA_SHORT & 0x1f)) {
+            
+                if (is_unsigned) {
+                
+                    att_dst_reg = amd64_dword_reg_name_from_any (dst_reg);
+                    att_op = "movzwl";
+                
+                } else {
+                    att_op = "movswq";
+                }
+            
+            } else if (elem_size == (DATA_INT & 0x1f) || elem_size == (DATA_LONG & 0x1f)) {
+            
+                if (is_unsigned) {
+                
+                    att_dst_reg = amd64_dword_reg_name_from_any (dst_reg);
+                    att_op = "movl";
+                
+                } else {
+                    att_op = "movslq";
+                }
+            
+            }
+        
+        }
+        
+        if (scale == 1) {
+            fprintf (state->ofp, "    %s (%%%s,%%%s), %%%s\n", att_op, base_reg, index_reg, att_dst_reg);
+        } else {
+            fprintf (state->ofp, "    %s (%%%s,%%%s,%d), %%%s\n", att_op, base_reg, index_reg, scale, att_dst_reg);
+        }
+    
+    }
+
+}
+
+static void emit_load_indexed_sized_to_reg_now (const char *base_reg, const char *index_reg, const char *dst_reg, int elem_size) {
+    emit_load_indexed_sized_to_reg_ex_now (base_reg, index_reg, dst_reg, elem_size, 0);
+}
+
+static void emit_load_indexed_unsigned_sized_to_reg_now (const char *base_reg, const char *index_reg, const char *dst_reg, int elem_size) {
+    emit_load_indexed_sized_to_reg_ex_now (base_reg, index_reg, dst_reg, elem_size, 1);
+}
+
+static const char *amd64_full_reg_name (const char *reg) {
+
+    if (!reg) {
+        return reg;
+    }
+    
+    if (strcmp (reg, "rax") == 0) {
+        return "rax";
+    }
+    
+    if (strcmp (reg, "rbx") == 0) {
+        return "rbx";
+    }
+    
+    if (strcmp (reg, "rcx") == 0) {
+        return "rcx";
+    }
+    
+    if (strcmp (reg, "rdx") == 0) {
+        return "rdx";
+    }
+    
+    if (strcmp (reg, "rsi") == 0) {
+        return "rsi";
+    }
+    
+    if (strcmp (reg, "rdi") == 0) {
+        return "rdi";
+    }
+    
+    if (strcmp (reg, "ebp") == 0) {
+        return "rbp";
+    }
+    
+    if (strcmp (reg, "esp") == 0) {
+        return "rsp";
+    }
+    
+    return reg;
+
+}
+
+static void emit_load_symbol_address_to_reg_now (const char *reg, const char *symbol, long offset, int is_local) {
+
+    const char *asm_symbol;
+    
+    if (!state->ofp || !reg) {
+        return;
+    }
+    
+    if (is_local) {
+    
+        const char *addr_reg = amd64_full_reg_name (reg);
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    lea %s, [rbp%+ld]\n", addr_reg, offset);
+        } else {
+            fprintf (state->ofp, "    leaq %ld(%%rbp), %%%s\n", offset, addr_reg);
+        }
+        
+        return;
+    
+    }
+    
+    if (!symbol) {
+        return;
+    }
+    
+    emit_extern_reference_symbol (symbol, DATA_PTR);
+    asm_symbol = asm_global_symbol_name (symbol);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        const char *addr_reg = amd64_full_reg_name (reg);
+        
+        if (state->syntax & ASM_SYNTAX_NASM) {
+            fprintf (state->ofp, "    lea %s, [%s]\n", addr_reg, asm_symbol);
+        } else {
+            fprintf (state->ofp, "    lea %s, %s\n", addr_reg, asm_symbol);
+        }
+    
+    } else {
+        fprintf (state->ofp, "    leaq %s(%%rip), %%%s\n", asm_symbol, amd64_full_reg_name (reg));
+    }
+
+}
+
+static void emit_add_indexed_scaled_address_to_reg_now (const char *base_reg, const char *index_reg, int elem_size) {
+
+    int raw_elem_size = elem_size;
+    int scale = 1;
+    
+    if (!state->ofp || !base_reg || !index_reg) {
+        return;
+    }
+    
+    if (raw_elem_size == DATA_SHORT || raw_elem_size == (DATA_SHORT & 0x1f)) {
+    
+        elem_size = DATA_SHORT & 0x1f;
+        scale = 2;
+    
+    } else if (raw_elem_size == DATA_INT || raw_elem_size == DATA_LONG || raw_elem_size == (DATA_INT & 0x1f)) {
+    
+        elem_size = DATA_INT & 0x1f;
+        scale = 4;
+    
+    } else if (raw_elem_size == DATA_PTR || raw_elem_size == (DATA_PTR & 0x1f)) {
+    
+        elem_size = DATA_PTR & 0x1f;
+        scale = 8;
+    
+    } else if (elem_size > 1) {
+        scale = 0;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (scale == 0) {
+        
+            fprintf (state->ofp, "    imul %s, %d\n", index_reg, elem_size);
+            fprintf (state->ofp, "    lea %s, [%s + %s]\n", base_reg, base_reg, index_reg);
+        
+        } else if (scale == 1) {
+            fprintf (state->ofp, "    lea %s, [%s + %s]\n", base_reg, base_reg, index_reg);
+        } else {
+            fprintf (state->ofp, "    lea %s, [%s + %s * %d]\n", base_reg, base_reg, index_reg, scale);
+        }
+    
+    } else {
+    
+        if (scale == 0) {
+        
+            fprintf (state->ofp, "    imulq $%d, %%%s, %%%s\n", elem_size, index_reg, index_reg);
+            fprintf (state->ofp, "    leaq (%%%s,%%%s), %%%s\n", base_reg, index_reg, base_reg);
+        
+        } else if (scale == 1) {
+            fprintf (state->ofp, "    leaq (%%%s,%%%s), %%%s\n", base_reg, index_reg, base_reg);
+        } else {
+            fprintf (state->ofp, "    leaq (%%%s,%%%s,%d), %%%s\n", base_reg, index_reg, scale, base_reg);
+        }
+    
+    }
+
+}
+
+static void emit_load_subscript_index_to_reg_now (const char *index_reg) {
+
+    if (current_expression_mentions_64bit_symbol_now ()) {
+    
+        int is_unsigned = rhs_current_operand_is_unsigned_now ();
+        emit_load_assignment_rhs_expression_to_pair ("rax", "rdx", is_unsigned);
+        
+        if (index_reg && strcmp (index_reg, "rax") != 0) {
+            emit_mov_reg_to_reg_now (index_reg, "rax");
+        }
+        
+        return;
+    
+    }
+    
+    emit_load_assignment_rhs_expression_to_reg (index_reg);
+
+}
+
+static int emit_parse_postfix_subscript_scaled_address_to_reg_now (const char *reg, int elem_size) {
+
+    const char *index_reg;
+    int saw_subscript = 0;
+    
+    if (!reg) {
+        reg = "rax";
+    }
+    
+    index_reg = (strcmp (reg, "rcx") == 0) ? "rdx" : "rcx";
+    
+    while (tok.kind == TOK_LBRACK) {
+    
+        saw_subscript = 1;
+        get_token ();
+        
+        emit_push_reg_now (reg);
+        emit_load_subscript_index_to_reg_now (index_reg);
+        expect (TOK_RBRACK, "]");
+        emit_pop_reg_now (reg);
+        
+        if (tok.kind == TOK_LBRACK) {
+            emit_load_indexed_pointer_to_reg_now (reg, index_reg);
+        } else {
+            emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
+        }
+    
+    }
+    
+    return saw_subscript;
+
+}
+
+static int emit_parse_postfix_subscripts_to_reg_now (const char *reg, int elem_size, int pointer_depth, int pointed_size) {
+
+    const char *index_reg;
+    int saw_subscript = 0;
+    
+    if (!reg) {
+        reg = "rax";
+    }
+    
+    index_reg = (strcmp (reg, "rcx") == 0) ? "rdx" : "rcx";
+    
+    while (tok.kind == TOK_LBRACK) {
+    
+        saw_subscript = 1;
+        get_token ();
+        
+        emit_push_reg_now (reg);
+        emit_load_subscript_index_to_reg_now (index_reg);
+        
+        expect (TOK_RBRACK, "]");
+        emit_pop_reg_now (reg);
+        
+        if (tok.kind == TOK_LBRACK) {
+        
+            if (pointer_depth == 0 && pointed_size > 0 && elem_size > pointed_size) {
+            
+                /*
+                 * This is a real multidimensional array row, not an array of
+                 * pointers.  For char a[7][3], a[i] is the address of the
+                 * three-byte row.  The old code treated every further subscript
+                 * as pointer traversal and loaded *(a + i), which turns the
+                 * first bytes of the row into a bogus pointer.
+                 */
+                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
+                elem_size = index_step_size (pointed_size);
+            
+            } else {
+            
+                emit_load_indexed_pointer_to_reg_now (reg, index_reg);
+                
+                if (pointer_depth > 0) {
+                    pointer_depth--;
+                }
+                
+                if (pointed_size > 0) {
+                    elem_size = (pointer_depth > 1) ? (DATA_PTR & 0x1f) : index_step_size (pointed_size);
+                }
+            
+            }
+        
+        } else {
+        
+            if (pointer_depth == 0 && pointed_size > 0 && elem_size > pointed_size) {
+                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
+            } else if (index_step_size (elem_size) > (DATA_PTR & 0x1f)) {
+                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
+            } else {
+                emit_load_indexed_sized_to_reg_now (reg, index_reg, reg, elem_size);
+            }
+        
+        }
+    
+    }
+
+    return saw_subscript;
+
+}
+
+static int emit_parse_postfix_subscripts_to_reg_dims_now (const char *reg, int elem_size, int pointer_depth, int pointed_size, int array_dimensions, int is_unsigned) {
+
+    const char *index_reg;
+    int saw_subscript = 0;
+    
+    if (!reg) {
+        reg = "rax";
+    }
+    
+    index_reg = (strcmp (reg, "rcx") == 0) ? "rdx" : "rcx";
+    
+    while (tok.kind == TOK_LBRACK) {
+    
+        int dims_before = array_dimensions;
+        
+        saw_subscript = 1;
+        get_token ();
+        
+        emit_push_reg_now (reg);
+        emit_load_subscript_index_to_reg_now (index_reg);
+        
+        expect (TOK_RBRACK, "]");
+        emit_pop_reg_now (reg);
+        
+        if (array_dimensions > 0) {
+            array_dimensions--;
+        }
+        
+        if (tok.kind == TOK_LBRACK) {
+        
+            if (pointer_depth == 0 && pointed_size > 0 && elem_size > pointed_size) {
+            
+                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
+                elem_size = index_step_size (pointed_size);
+            
+            } else {
+            
+                emit_load_indexed_pointer_to_reg_now (reg, index_reg);
+                
+                if (pointer_depth > 0) {
+                    pointer_depth--;
+                }
+                
+                if (pointed_size > 0) {
+                    elem_size = (pointer_depth > 1) ? (DATA_PTR & 0x1f) : index_step_size (pointed_size);
+                }
+            
+            }
+        
+        } else {
+        
+            if (pointer_depth == 0 && dims_before > 1) {
+                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
+            } else if (pointer_depth == 0 && pointed_size > 0 && elem_size > pointed_size) {
+                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
+            } else if (index_step_size (elem_size) > (DATA_PTR & 0x1f)) {
+                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
+            } else {
+            
+                if (is_unsigned) {
+                    emit_load_indexed_unsigned_sized_to_reg_now (reg, index_reg, reg, elem_size);
+                } else {
+                    emit_load_indexed_sized_to_reg_now (reg, index_reg, reg, elem_size);
+                }
+            
+            }
+        
+        }
+    
+    }
+
+    return saw_subscript;
+
+}
+
+static int parse_incdec_identifier_now (enum token_kind *op, char **name, const char **name_start, const char **name_caret, unsigned long *name_line) {
+
+    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
+        return 0;
+    }
+    
+    *op = tok.kind;
+    get_token ();
+    
+    if (tok.kind != TOK_IDENT) {
+    
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after %s", *op == TOK_INCR ? "++" : "--");
+        
+        *name = 0;
+        return 1;
+    }
+    
+    *name = xstrdup (tok.ident);
+    *name_start = tok.start;
+    *name_caret = tok.caret;
+    *name_line = get_line_number ();
+    
+    get_token ();
+    return 1;
+
+}
+
+static void emit_apply_postfix_member_access_to_reg_now (const char *reg);
+static void emit_apply_postfix_member_incdec_now (const char *reg, enum token_kind op);
+static void emit_load_member_from_addr_reg_now (const char *dst_reg, const char *addr_reg, int offset, int size);
+
+static struct token *clone_current_token_now (void);
+static void emit_store_reg_to_deref_reg_now (const char *addr_reg, const char *value_reg, int size);
+
+static int source_starts_prefix_incdec_parenthesized_deref_at (const char *p) {
+
+    if (!p) {
+        return 0;
+    }
+    
+    if (!((p[0] == '+' && p[1] == '+') || (p[0] == '-' && p[1] == '-'))) {
+        return 0;
+    }
+    
+    p += 2;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '*') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    p++;
+    
+    while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+        p++;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == ')';
+
+}
+
+static int emit_load_prefix_incdec_parenthesized_deref_to_reg_now (const char *reg) {
+
+    enum token_kind op;
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    struct local_symbol *sym;
+    
+    int global_index;
+    int pointer_depth = 0;
+    int pointed_size = DATA_INT & 0x1f;
+    int lvalue_size = DATA_INT & 0x1f;
+    int step = 1;
+    
+    const char *addr_reg;
+    
+    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
+        return 0;
+    }
+    
+    if (!source_starts_prefix_incdec_parenthesized_deref_at (tok.caret)) {
+        return 0;
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    expect (TOK_LPAREN, "(");
+    expect (TOK_STAR, "*");
+    
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    get_token ();
+    
+    expect (TOK_RPAREN, ")");
+    
+    sym = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (sym) {
+    
+        pointer_depth = sym->pointer_depth;
+        pointed_size = sym->pointed_size;
+    
+    } else if (global_index >= 0) {
+    
+        pointer_depth = get_global_symbol_pointer_depth (name);
+        pointed_size = get_global_symbol_pointed_size (name);
+    
+    } else {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (pointer_depth <= 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid indirection of non-pointer '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (pointed_size <= 0) {
+        pointed_size = DATA_INT & 0x1f;
+    }
+    
+    if (pointer_depth > 1) {
+    
+        lvalue_size = DATA_PTR & 0x1f;
+        step = pointer_depth > 2 ? (DATA_PTR & 0x1f) : index_step_size (pointed_size);
+    
+    } else {
+    
+        lvalue_size = pointed_size & 0x1f;
+        step = 1;
+    
+    }
+    
+    if (!reg) {
+        reg = "rax";
+    }
+    
+    addr_reg = (strcmp (reg, "rdx") == 0) ? "rcx" : "rdx";
+    
+    if (sym) {
+    
+        if (sym->is_static && sym->static_label) {
+            emit_load_global_to_reg (addr_reg, sym->static_label, DATA_PTR);
+        } else {
+            emit_load_local_to_reg (addr_reg, sym->offset, DATA_PTR);
+        }
+    
+    } else {
+        emit_load_global_to_reg (addr_reg, name, DATA_PTR);
+    }
+    
+    emit_load_member_from_addr_reg_now (reg, addr_reg, 0, lvalue_size);
+    
+    if (state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, op == TOK_INCR ? "    add %s, %d\n" : "    sub %s, %d\n", reg, step);
+        } else {
+            fprintf (state->ofp, op == TOK_INCR ? "    addq $%d, %%%s\n" : "    subq $%d, %%%s\n", step, reg);
+        }
+    
+    }
+    
+    emit_store_reg_to_deref_reg_now (addr_reg, reg, lvalue_size);
+    
+    if (pointer_depth > 1) {
+        set_rhs_last_pointer_info (pointer_depth - 1, pointed_size);
+    } else {
+        clear_rhs_last_pointer_info ();
+    }
+    
+    free (name);
+    return 1;
+
+}
+
+static int emit_load_prefix_incdec_deref_to_reg_now (const char *reg) {
+
+    enum token_kind op;
+    
+    struct token *saved_tok;
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    
+    struct local_symbol *sym;
+    
+    int global_index;
+    int deref_size = DATA_INT & 0x1f;
+    
+    const char *addr_reg;
+    
+    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
+        return 0;
+    }
+    
+    saved_tok = clone_current_token_now ();
+    op = tok.kind;
+    
+    get_token ();
+    
+    if (tok.kind != TOK_STAR) {
+    
+        unget_token (saved_tok);
+        return 0;
+    
+    }
+    
+    get_token ();
+    
+    if (tok.kind != TOK_IDENT) {
+    
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after *");
+        
+        free (saved_tok->ident);
+        free ((char *) saved_tok->start);
+        free (saved_tok);
+        
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    get_token ();
+    
+    sym = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (sym) {
+    
+        if (sym->pointer_depth > 1) {
+            deref_size = DATA_PTR & 0x1f;
+        } else if (sym->pointer_depth == 1 && sym->pointed_size > 0) {
+            deref_size = sym->pointed_size & 0x1f;
+        }
+    
+    } else if (global_index >= 0) {
+    
+        if (get_global_symbol_pointer_depth (name) > 1) {
+            deref_size = DATA_PTR & 0x1f;
+        } else if (get_global_symbol_pointer_depth (name) == 1 && get_global_symbol_pointed_size (name) > 0) {
+            deref_size = get_global_symbol_pointed_size (name) & 0x1f;
+        }
+    
+    } else {
+
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        free (name);
+        free (saved_tok->ident);
+        
+        free ((char *) saved_tok->start);
+        free (saved_tok);
+        
+        return 1;
+    
+    }
+    
+    if (!reg) {
+        reg = "rax";
+    }
+    
+    addr_reg = (strcmp (reg, "rdx") == 0) ? "rcx" : "rdx";
+    
+    if (sym) {
+    
+        if (sym->is_static && sym->static_label) {
+            emit_load_global_to_reg (addr_reg, sym->static_label, DATA_PTR);
+        } else {
+            emit_load_local_to_reg (addr_reg, sym->offset, DATA_PTR);
+        }
+    
+    } else {
+        emit_load_global_to_reg (addr_reg, name, DATA_PTR);
+    }
+    
+    emit_load_member_from_addr_reg_now (reg, addr_reg, 0, deref_size);
+    
+    if (state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, op == TOK_INCR ? "    add %s, 1\n" : "    sub %s, 1\n", reg);
+        } else {
+            fprintf (state->ofp, op == TOK_INCR ? "    addq $1, %%%s\n" : "    subq $1, %%%s\n", reg);
+        }
+    
+    }
+    
+    emit_store_reg_to_deref_reg_now (addr_reg, reg, deref_size);
+    
+    free (name);
+    
+    free (saved_tok->ident);
+    free ((char *) saved_tok->start);
+    
+    free (saved_tok);
+    return 1;
+
+}
+
+static int emit_load_prefix_incdec_to_reg_now (const char *reg) {
+
+    enum token_kind op;
+    char *name;
+    
+    const char *name_start, *name_caret;
+    unsigned long name_line;
+    
+    struct local_symbol *sym;
+    
+    if (emit_load_prefix_incdec_parenthesized_deref_to_reg_now (reg)) {
+        return 1;
+    }
+    
+    if (emit_load_prefix_incdec_deref_to_reg_now (reg)) {
+        return 1;
+    }
+    
+    if (!parse_incdec_identifier_now (&op, &name, &name_start, &name_caret, &name_line)) {
+        return 0;
+    }
+    
+    if (!name) {
+        return 1;
+    }
+    
+    sym = find_local_symbol (name);
+    emit_incdec_symbol_now (sym, name, op, name_line, name_start, name_caret);
+    
+    if (sym) {
+    
+        if (sym->is_static && sym->static_label) {
+            emit_load_global_to_reg_ex (reg, sym->static_label, sym->size, sym->is_unsigned);
+        } else {
+            emit_load_local_to_reg_ex (reg, sym->offset, sym->size, sym->is_unsigned);
+        }
+    
+    } else if (find_global_symbol (name) >= 0) {
+        emit_load_global_to_reg_ex (reg, name, get_global_symbol_size (name), get_global_symbol_unsigned (name));
+    }
+    
+    free (name);
+    return 1;
+
+}
+
+static int emit_load_prefix_incdec_member_to_reg_now (const char *reg) {
+
+    struct token *saved_tok;
+    
+    enum token_kind op;
+    enum token_kind member_op = TOK_EOF;
+    
+    char *member;
+    
+    const char *member_start;
+    const char *member_caret;
+    
+    unsigned long member_line;
+    
+    int offset = 0;
+    int size = DATA_INT & 0x1f;
+    
+    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
+        return 0;
+    }
+    
+    saved_tok = clone_current_token_now ();
+    get_token ();
+    
+    if (tok.kind == TOK_STAR) {
+    
+        unget_token (saved_tok);
+        return 0;
+    
+    }
+    
+    unget_token (saved_tok);
+    
+    if (emit_load_prefix_incdec_parenthesized_deref_to_reg_now (reg)) {
+        return 1;
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    if (tok.kind != TOK_LPAREN) {
+    
+        char *name;
+        
+        const char *name_start;
+        const char *name_caret;
+        
+        unsigned long name_line;
+        struct local_symbol *sym;
+        
+        int global_index;
+        
+        if (tok.kind != TOK_IDENT) {
+        
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after %s", op == TOK_INCR ? "++" : "--");
+            return 1;
+        
+        }
+        
+        name = xstrdup (tok.ident);
+        name_start = tok.start;
+        name_caret = tok.caret;
+        name_line = get_line_number ();
+        
+        get_token ();
+        
+        sym = find_local_symbol (name);
+        global_index = find_global_symbol (name);
+        
+        if (tok.kind == TOK_ARROW) {
+        
+            member_op = tok.kind;
+            get_token ();
+            
+            member_start = tok.start;
+            member_caret = tok.caret;
+            member_line = get_line_number ();
+            
+            if (tok.kind != TOK_IDENT) {
+            
+                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+                
+                free (name);
+                return 1;
+            
+            }
+            
+            member = xstrdup (tok.ident);
+            get_token ();
+            
+            if (!find_member_info (member, &offset, &size)) {
+            
+                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+                
+                free (member);
+                free (name);
+                
+                return 1;
+            
+            }
+            
+            free (member);
+            
+            if (sym) {
+            
+                if (sym->is_static && sym->static_label) {
+                    emit_load_global_to_reg (reg, sym->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg (reg, sym->offset, DATA_PTR);
+                }
+            
+            } else if (global_index >= 0) {
+                emit_load_global_to_reg (reg, name, DATA_PTR);
+            } else {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            }
+            
+            free (name);
+            goto emit_member_incdec;
+        
+        }
+        
+        emit_incdec_symbol_now (sym, name, op, name_line, name_start, name_caret);
+        
+        if (sym) {
+        
+            if (sym->is_static && sym->static_label) {
+                emit_load_global_to_reg_ex (reg, sym->static_label, sym->size, sym->is_unsigned);
+            } else {
+                emit_load_local_to_reg_ex (reg, sym->offset, sym->size, sym->is_unsigned);
+            }
+        
+        } else if (find_global_symbol (name) >= 0) {
+            emit_load_global_to_reg_ex (reg, name, get_global_symbol_size (name), get_global_symbol_unsigned (name));
+        }
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    get_token ();
+    
+    emit_load_assignment_rhs_expression_to_reg (reg);
+    expect (TOK_RPAREN, ")");
+    
+    if (postfix_member_seen && tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
+    
+        emit_apply_postfix_member_incdec_now (reg, op);
+        emit_load_member_from_addr_reg_now (reg, "rdx", postfix_member_offset, postfix_member_size);
+        
+        return 1;
+    
+    }
+    
+    if (tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
+    
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected member after %s", op == TOK_INCR ? "++" : "--");
+        return 1;
+    
+    }
+    
+    member_op = tok.kind;
+    get_token ();
+    
+    member_start = tok.start;
+    member_caret = tok.caret;
+    member_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT) {
+    
+        report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+        return 1;
+    
+    }
+    
+    member = xstrdup (tok.ident);
+    get_token ();
+    
+    if (!find_member_info (member, &offset, &size)) {
+    
+        report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+        
+        free (member);
+        return 1;
+    
+    }
+    
+    free (member);
+    
+emit_member_incdec:
+    
+    if (!state->ofp) {
+        return 1;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        const char *insn = op == TOK_INCR ? "inc" : "dec";
+        const char *opsize = "dword";
+        
+        const char *dreg = amd64_dword_reg_name_from_any (reg);
+        int qword = (size == (DATA_LLONG & 0x1f) || size == (DATA_PTR & 0x1f));
+        
+        if (size == (DATA_CHAR & 0x1f)) {
+            opsize = "byte";
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            opsize = "word";
+        } else if (qword) {
+            opsize = "qword";
+        }
+        
+        if (state->syntax & ASM_SYNTAX_NASM) {
+        
+            fprintf (state->ofp, "    %s %s [%s + %d]\n", insn, opsize, reg, offset);
+            
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    movzx %s, byte [%s + %d]\n", dreg, reg, offset);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    movzx %s, word [%s + %d]\n", dreg, reg, offset);
+            } else if (qword) {
+                fprintf (state->ofp, "    mov %s, qword [%s + %d]\n", reg, reg, offset);
+            } else {
+                fprintf (state->ofp, "    movsxd %s, dword [%s + %d]\n", reg, reg, offset);
+            }
+        
+        } else {
+        
+            fprintf (state->ofp, "    %s %s ptr [%s + %d]\n", insn, opsize, reg, offset);
+            
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    movzx %s, byte ptr [%s + %d]\n", dreg, reg, offset);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    movzx %s, word ptr [%s + %d]\n", dreg, reg, offset);
+            } else if (qword) {
+                fprintf (state->ofp, "    mov %s, qword ptr [%s + %d]\n", reg, reg, offset);
+            } else {
+                fprintf (state->ofp, "    movsxd %s, dword ptr [%s + %d]\n", reg, reg, offset);
+            }
+        
+        }
+    
+    } else {
+    
+        const char *suffix = "l";
+        int qword = (size == (DATA_LLONG & 0x1f) || size == (DATA_PTR & 0x1f));
+        
+        if (size == (DATA_CHAR & 0x1f)) {
+            suffix = "b";
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            suffix = "w";
+        } else if (qword) {
+            suffix = "q";
+        }
+        
+        fprintf (state->ofp, "    %s%s %d(%%%s)\n", op == TOK_INCR ? "inc" : "dec", suffix, offset, reg);
+        
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, "    movzbl %d(%%%s), %%%s\n", offset, reg, amd64_dword_reg_name_from_any (reg));
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, "    movzwl %d(%%%s), %%%s\n", offset, reg, amd64_dword_reg_name_from_any (reg));
+        } else if (qword) {
+            fprintf (state->ofp, "    movq %d(%%%s), %%%s\n", offset, reg, reg);
+        } else {
+            fprintf (state->ofp, "    movslq %d(%%%s), %%%s\n", offset, reg, reg);
+        }
+    
+    }
+    
+    return 1;
+
+}
+
+static int emit_load_prefix_incdec_to_pair_now (const char *lo, const char *hi) {
+
+    enum token_kind op;
+    char *name;
+    
+    const char *name_start, *name_caret;
+    unsigned long name_line;
+    
+    struct local_symbol *sym;
+    
+    if (!parse_incdec_identifier_now (&op, &name, &name_start, &name_caret, &name_line)) {
+        return 0;
+    }
+    
+    if (!name) {
+        return 1;
+    }
+    
+    sym = find_local_symbol (name);
+    emit_incdec_symbol_now (sym, name, op, name_line, name_start, name_caret);
+    
+    if (sym) {
+    
+        if (sym->size == (DATA_LLONG & 0x1f) && !sym->is_floating) {
+        
+            if (sym->is_static && sym->static_label) {
+                emit_load_global64_to_pair (lo, hi, sym->static_label);
+            } else {
+                emit_load_local64_to_pair (sym->offset, lo, hi);
+            }
+        
+        } else {
+        
+            if (sym->is_static && sym->static_label) {
+                emit_load_global_to_reg_ex (lo, sym->static_label, sym->size, sym->is_unsigned);
+            } else {
+                emit_load_local_to_reg_ex (lo, sym->offset, sym->size, sym->is_unsigned);
+            }
+            
+            if (state->ofp) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
+                } else {
+                    fprintf (state->ofp, "    xorq %%%s, %%%s\n", hi, hi);
+                }
+            
+            }
+        
+        }
+    
+    } else if (find_global_symbol (name) >= 0) {
+    
+        if (get_global_symbol_size (name) == (DATA_LLONG & 0x1f) && !get_global_symbol_floating (name)) {
+            emit_load_global64_to_pair (lo, hi, name);
+        } else {
+        
+            emit_load_global_to_reg_ex (lo, name, get_global_symbol_size (name), get_global_symbol_unsigned (name));
+            
+            if (state->ofp) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
+                } else {
+                    fprintf (state->ofp, "    xorq %%%s, %%%s\n", hi, hi);
+                }
+            
+            }
+        
+        }
+    
+    }
+    
+    free (name);
+    return 1;
+
+}
+
+static int expression_text_mentions_64bit_symbol (const char *p) {
+
+    char name[256];
+    int depth = 0;
+    int i;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    while (*p) {
+    
+        if (*p == '(') {
+        
+            depth++;
+            p++;
+            
+            continue;
+        
+        }
+        
+        if (*p == ')') {
+        
+            if (depth <= 0) {
+                return 0;
+            }
+            
+            depth--;
+            p++;
+            
+            continue;
+        
+        }
+        
+        if (*p == ';' || *p == '{' || *p == '}') {
+            return 0;
+        }
+        
+        if ((unsigned char) *p == '_' || ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z'))) {
+        
+            i = 0;
+            
+            while ((unsigned char) *p == '_' || ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z')) || (*p >= '0' && *p <= '9')) {
+            
+                if (i + 1 < (int) sizeof (name)) {
+                    name[i++] = *p;
+                }
+                
+                p++;
+            
+            }
+            
+            name[i] = 0;
+            
+            while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+                p++;
+            }
+            
+            if (*p == '.' || (p[0] == '-' && p[1] == '>')) {
+                continue;
+            }
+            
+            {
+            
+                struct local_symbol *sym = find_local_symbol (name);
+                
+                if (sym && sym->size == (DATA_LLONG & 0x1f) && !sym->is_floating) {
+                    return 1;
+                }
+            
+            }
+            
+            if (find_global_symbol (name) >= 0 && get_global_symbol_size (name) == (DATA_LLONG & 0x1f) && !get_global_symbol_floating (name)) {
+                return 1;
+            }
+            
+            continue;
+        
+        }
+        
+        p++;
+    
+    }
+    
+    return 0;
+
+}
+
+static int current_expression_mentions_64bit_symbol_now (void) {
+
+    if (expression_text_mentions_64bit_symbol (tok.start)) {
+        return 1;
+    }
+    
+    if (expression_text_mentions_64bit_symbol (tok.caret)) {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static const char *reg8_name_for_32 (const char *reg) {
+    return amd64_byte_reg_name_from_any (reg);
+}
+
+static const char *reg16_name_for_32 (const char *reg) {
+    return amd64_word_reg_name_from_any (reg);
+}
+
+static void emit_extend_pair_high_from_low (const char *lo, const char *hi, int size, int is_unsigned) {
+
+    const char *dlo;
+    const char *dhi;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    dlo = amd64_dword_reg_name_from_any (lo);
+    dhi = amd64_dword_reg_name_from_any (hi);
+
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+
+        if (is_unsigned) {
+        
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    movzx %s, %s\n", dlo, reg8_name_for_32 (lo));
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    movzx %s, %s\n", dlo, reg16_name_for_32 (lo));
+            }
+            
+            fprintf (state->ofp, "    xor %s, %s\n", dhi, dhi);
+        
+        } else {
+
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    movsx %s, %s\n", dlo, reg8_name_for_32 (lo));
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    movsx %s, %s\n", dlo, reg16_name_for_32 (lo));
+            }
+
+            fprintf (state->ofp, "    mov %s, %s\n", dhi, dlo);
+            fprintf (state->ofp, "    sar %s, 31\n", dhi);
+
+        }
+
+    } else {
+
+        if (is_unsigned) {
+        
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    movzbl %%%s, %%%s\n", reg8_name_for_32 (lo), dlo);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    movzwl %%%s, %%%s\n", reg16_name_for_32 (lo), dlo);
+            }
+            
+            fprintf (state->ofp, "    xorl %%%s, %%%s\n", dhi, dhi);
+        
+        } else {
+
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    movsbl %%%s, %%%s\n", reg8_name_for_32 (lo), dlo);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    movswl %%%s, %%%s\n", reg16_name_for_32 (lo), dlo);
+            }
+
+            fprintf (state->ofp, "    movl %%%s, %%%s\n", dlo, dhi);
+            fprintf (state->ofp, "    sarl $31, %%%s\n", dhi);
+
+        }
+
+    }
+
+}
+
+static void emit_apply_integer_cast_to_reg_now (const char *reg, int size, int is_unsigned) {
+
+    const char *dreg;
+    const char *qreg;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (size != (DATA_CHAR & 0x1f) && size != (DATA_SHORT & 0x1f)) {
+        return;
+    }
+    
+    dreg = amd64_dword_reg_name_from_any (reg);
+    qreg = amd64_qword_reg_name_from_any (reg);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, is_unsigned ? "    movzx %s, %s\n" : "    movsx %s, %s\n", is_unsigned ? dreg : qreg, reg8_name_for_32 (reg));
+        } else {
+            fprintf (state->ofp, is_unsigned ? "    movzx %s, %s\n" : "    movsx %s, %s\n", is_unsigned ? dreg : qreg, reg16_name_for_32 (reg));
+        }
+    
+    } else {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, is_unsigned ? "    movzbl %%%s, %%%s\n" : "    movsbq %%%s, %%%s\n", reg8_name_for_32 (reg), is_unsigned ? dreg : qreg);
+        } else {
+            fprintf (state->ofp, is_unsigned ? "    movzwl %%%s, %%%s\n" : "    movswq %%%s, %%%s\n", reg16_name_for_32 (reg), is_unsigned ? dreg : qreg);
+        }
+    
+    }
+
+}
+
+static int fold_text_starts_with_type_name_only_before_rparen (const char *p) {
+
+    int saw_type = 0;
+    char word[64];
+    int i;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    for (;;) {
+    
+        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+            p++;
+        }
+        
+        if (*p == '*') {
+        
+            saw_type = 1;
+            
+            p++;
+            continue;
+        
+        }
+        
+        if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+            break;
+        }
+        
+        i = 0;
+        
+        while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+        
+            if (i + 1 < (int) sizeof (word)) {
+                word[i++] = *p;
+            }
+            
+            p++;
+        
+        }
+        
+        word[i] = 0;
+        
+        if (strcmp (word, "char") != 0 &&
+            strcmp (word, "short") != 0 &&
+            strcmp (word, "int") != 0 &&
+            strcmp (word, "long") != 0 &&
+            strcmp (word, "signed") != 0 &&
+            strcmp (word, "unsigned") != 0 &&
+            strcmp (word, "void") != 0) {
+            return 0;
+        }
+        
+        saw_type = 1;
+    
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return saw_type && *p == ')';
+
+}
+
+static int const_integer_expr_text_is_foldable_now (const char *p) {
+
+    int saw_value_token = 0;
+    int saw_token = 0;
+    
+    char word[64];
+    int depth = 0, ch, i;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    {
+    
+        const char *q = p;
+        int parens = 0;
+        
+        while (*q == ' ' || *q == '\t' || *q == '\r' || *q == '\n') {
+            q++;
+        }
+        
+        while (*q == '(') {
+        
+            parens = 1;
+            q++;
+            
+            while (*q == ' ' || *q == '\t' || *q == '\r' || *q == '\n') {
+                q++;
+            }
+        
+        }
+        
+        if (fold_text_starts_with_type_name_only_before_rparen (p) || (parens && fold_text_starts_with_type_name_only_before_rparen (q))) {
+            return 0;
+        }
+    
+    }
+    
+    while (*p) {
+    
+        ch = (unsigned char) *p;
+        
+        if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') {
+        
+            p++;
+            continue;
+        
+        }
+        
+        if (depth == 0) {
+        
+            if (*p == ';' || *p == ',' || *p == '}' || *p == ']') {
+                break;
+            }
+            
+            /*
+             * This helper is only for folding a complete integer expression
+             * operand.  Do not claim that a leading parenthesized constant is
+             * foldable when it is followed by a lower-precedence operator such
+             * as the '<' in:
+             *
+             *     ((3) < (1 + n)) ? ...
+             *
+             * Returning true there makes the caller consume only '(3)' and then
+             * expect a closing parenthesis while the current token is '<'.
+             */
+            if (*p == ':' || *p == '?') {
+                return 0;
+            }
+            
+            if (*p == '<' || *p == '>' || *p == '=' || (*p == '!' && p[1] == '=')) {
+            
+                if ((p[0] == '<' && p[1] == '<') || (p[0] == '>' && p[1] == '>')) {
+                
+                    saw_token = 1;
+                    
+                    p += 2;
+                    continue;
+                
+                } else {
+                    return 0;
+                }
+            }
+            
+            if ((p[0] == '&' && p[1] == '&') || (p[0] == '|' && p[1] == '|')) {
+                return 0;
+            }
+        
+        }
+        
+        if (*p == '(') {
+        
+            depth++;
+            
+            saw_token = 1;
+            p++;
+            
+            continue;
+        
+        }
+        
+        if (*p == ')') {
+        
+            if (depth == 0) {
+            
+                /*
+                 * If the caller asks about text that starts inside a cast, the
+                 * scanner can see only the type-name prefix, for example:
+                 *
+                 *     unsigned char) ch
+                 *
+                 * That is not an integer constant expression.  Returning true
+                 * here sends the parser down expr_const64(), which then reports
+                 * "integer constant expression expected" at the cast.
+                 */
+                if (!saw_value_token) {
+                    return 0;
+                }
+                
+                break;
+            
+            }
+            
+            depth--;
+            p++;
+            
+            continue;
+        
+        }
+        
+        if (*p >= '0' && *p <= '9') {
+        
+            saw_value_token = 1;
+            saw_token = 1;
+            
+            p++;
+            
+            while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+                p++;
+            }
+            
+            continue;
+        
+        }
+        
+        if (*p == '\'') {
+        
+            saw_value_token = 1;
+            saw_token = 1;
+            
+            p++;
+            
+            while (*p && *p != '\'') {
+            
+                if (*p == '\\' && p[1]) {
+                    p += 2;
+                } else {
+                    p++;
+                }
+            
+            }
+            
+            if (*p == '\'') {
+                p++;
+            }
+            
+            continue;
+        
+        }
+        
+        if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_') {
+        
+            i = 0;
+            
+            while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+            
+                if (i + 1 < (int) sizeof (word)) {
+                    word[i++] = *p;
+                }
+                
+                p++;
+            
+            }
+            
+            word[i] = 0;
+            
+            if (strcmp (word, "sizeof") == 0) {
+                saw_value_token = 1;
+            }
+            
+            if (strcmp (word, "sizeof") != 0 &&
+                strcmp (word, "char") != 0 &&
+                strcmp (word, "short") != 0 &&
+                strcmp (word, "int") != 0 &&
+                strcmp (word, "long") != 0 &&
+                strcmp (word, "signed") != 0 &&
+                strcmp (word, "unsigned") != 0 &&
+                strcmp (word, "void") != 0) {
+                return 0;
+            }
+            
+            saw_token = 1;
+            continue;
+        
+        }
+        
+        if (*p == '+' || *p == '-' || *p == '*' || *p == '/' || *p == '%' || *p == '&' || *p == '|' || *p == '^' || *p == '~' || *p == '!' || *p == '<' || *p == '>') {
+        
+            saw_token = 1;
+            p++;
+            
+            continue;
+        
+        }
+        
+        return 0;
+    
+    }
+    
+    return saw_token;
+
+}
+
+static int token_kind_is_integer_constant_now (enum token_kind kind) {
+
+    return kind == TOK_CCHAR || kind == TOK_LCHAR ||
+           kind == TOK_CINT || kind == TOK_CUINT ||
+           kind == TOK_CLONG || kind == TOK_CULONG ||
+           kind == TOK_CLLONG || kind == TOK_CULLONG;
+
+}
+
+static int token_kind_is_binary_expression_operator_now (enum token_kind kind) {
+
+    return kind == TOK_PLUS || kind == TOK_MINUS || kind == TOK_STAR ||
+           kind == TOK_FSLASH || kind == TOK_MOD ||
+           kind == TOK_AMPER || kind == TOK_PIPE || kind == TOK_CARET ||
+           kind == TOK_LSH || kind == TOK_RSH ||
+           kind == TOK_LESS || kind == TOK_LTEQ ||
+           kind == TOK_GREATER || kind == TOK_GTEQ ||
+           kind == TOK_EQEQ || kind == TOK_NOTEQ ||
+           kind == TOK_LOGAND || kind == TOK_LOGOR;
+
+}
+
+static int const_integer_expr_text_contains_sizeof_now (const char *p) {
+
+    char quote;
+    char word[64];
+    int i;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    while (*p) {
+    
+        if (*p == '\'' || *p == '"') {
+        
+            quote = *p++;
+            
+            while (*p) {
+            
+                if (*p == '\\') {
+                
+                    p++;
+                    
+                    if (*p) {
+                        p++;
+                    }
+                    
+                    continue;
+                
+                }
+                
+                if (*p == quote) {
+                
+                    p++;
+                    break;
+                
+                }
+                
+                p++;
+            
+            }
+            
+            continue;
+        
+        }
+        
+        if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_') {
+        
+            i = 0;
+            
+            while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') ||
+                   (*p >= '0' && *p <= '9') || *p == '_') {
+            
+                if (i + 1 < (int) sizeof (word)) {
+                    word[i++] = *p;
+                }
+                
+                p++;
+            
+            }
+            
+            word[i] = 0;
+            
+            if (strcmp (word, "sizeof") == 0) {
+                return 1;
+            }
+            
+            continue;
+        
+        }
+        
+        p++;
+    
+    }
+    
+    return 0;
+
+}
+
+static int current_integer_expr_is_foldable_now (void) {
+
+    struct token *saved_tok;
+    
+    enum token_kind first_kind;
+    enum token_kind next_kind;
+    
+    if (!const_integer_expr_text_is_foldable_now (tok.start)) {
+        return 0;
+    }
+    
+    /*
+     * The backend-side constant folder delegates to expr_const64(), and that
+     * parser does not understand the full sizeof-expression grammar.  It is
+     * safe to fold a single leading sizeof through const64_from_current_operand(),
+     * but it is not safe to fold a whole expression such as:
+     *
+     *     sizeof x < 8 ? 8 : sizeof x
+     *
+     * because a later sizeof token would be handed to expr_const64() and produce
+     * a bogus "integer constant expression expected" diagnostic.  Leave these
+     * expressions to the normal expression emitter, which already has a real
+     * token-level sizeof path.
+     */
+    if (const_integer_expr_text_contains_sizeof_now (tok.start)) {
+        return 0;
+    }
+    
+    /*
+     * Macro-expanded integer tokens can have tok.start/tok.caret pointing at
+     * only the replacement text (for example "16") rather than the complete
+     * source expression that follows it.  Do not hand such a prefix to
+     * expr_const64() as though it described the whole expression when the real
+     * token stream continues with a binary operator:
+     *
+     *     MEMMGR_ALIGN - (size_t)buffer % MEMMGR_ALIGN
+     *
+     * The normal expression parser can still handle this; this guard only
+     * disables the whole-expression constant-folder for that unsafe prefix.
+     */
+    if (!token_kind_is_integer_constant_now (tok.kind)) {
+        return 1;
+    }
+    
+    first_kind = tok.kind;
+    
+    saved_tok = clone_current_token_now ();
+    get_token ();
+    
+    next_kind = tok.kind;
+    unget_token (saved_tok);
+    
+    if (token_kind_is_integer_constant_now (first_kind) && token_kind_is_binary_expression_operator_now (next_kind)) {
+        return 0;
+    }
+    
+    return 1;
+
+}
+
+static void amd64_emit_mov_i64_to_qword_reg_now (const char *reg, int64_s v) {
+
+    const char *qreg = amd64_qword_reg_name_from_any (reg);
+    
+    if (!state->ofp || !qreg) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    mov %s, 0%08lX%08lXh\n", qreg, v.high & U32_MASK, v.low & U32_MASK);
+    } else {
+        fprintf (state->ofp, "    movabsq $0x%08lX%08lX, %%%s\n", v.high & U32_MASK, v.low & U32_MASK, qreg);
+    }
+
+}
+
+static void emit_load_const64_to_pair_now (const char *lo, const char *hi, int64_s v) {
+
+    const char *qlo = amd64_qword_reg_name_from_any (lo);
+    
+    if (!state->ofp || !lo) {
+        return;
+    }
+    
+    if (amd64_reg_is_qword_name (qlo)) {
+    
+        amd64_emit_mov_i64_to_qword_reg_now (qlo, v);
+        return;
+    
+    }
+    
+    {
+    
+        const char *dlo = amd64_dword_reg_name_from_any (lo);
+        const char *dhi = amd64_dword_reg_name_from_any (hi);
+        
+        if (!dlo || !dhi) {
+            return;
+        }
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, "    mov %s, %lu\n", dlo, v.low & U32_MASK);
+            fprintf (state->ofp, "    mov %s, %lu\n", dhi, v.high & U32_MASK);
+        
+        } else {
+        
+            fprintf (state->ofp, "    movl $%lu, %%%s\n", v.low & U32_MASK, dlo);
+            fprintf (state->ofp, "    movl $%lu, %%%s\n", v.high & U32_MASK, dhi);
+        
+        }
+    
+    }
+
+}
+
+static void emit_load_const32_to_reg_now (const char *reg, int64_s v) {
+
+    const char *dreg = amd64_dword_reg_name_from_any (reg);
+    flush_pending_statement_labels ();
+    
+    if (!state->ofp || !dreg) {
+        return;
+    }
+    
+    /*
+     * A 32-bit integer constant loaded through the dword register form
+     * zero-extends the upper half of the AMD64 register.  Do not use a
+     * qword immediate move here: assemblers may choose a sign-extended
+     * imm32 encoding for values with bit 31 set, which is wrong for plain
+     * unsigned 32-bit constants promoted into a 64-bit register.
+     */
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    mov %s, %lu\n", dreg, v.low & U32_MASK);
+    } else {
+        fprintf (state->ofp, "    movl $%lu, %%%s\n", v.low & U32_MASK, dreg);
+    }
+
+}
+
+static void emit_load_address_to_reg_now (const char *reg, const char *symbol) {
+
+    const char *asm_symbol;
+    const char *addr_reg;
+    
+    flush_pending_statement_labels ();
+    
+    if (!state->ofp || !symbol || !*symbol) {
+        return;
+    }
+    
+    emit_extern_reference_symbol (symbol, DATA_PTR);
+    
+    asm_symbol = asm_global_symbol_name (symbol);
+    addr_reg = amd64_full_reg_name (reg);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+            fprintf (state->ofp, "    lea %s, [%s]\n", addr_reg, asm_symbol);
+        } else {
+            fprintf (state->ofp, "    mov %s, offset %s\n", addr_reg, asm_symbol);
+        }
+    
+    } else {
+        fprintf (state->ofp, "    leaq %s(%%rip), %%%s\n", asm_symbol, addr_reg);
+    }
+
+}
+
+static void emit_load_deref_reg_ex_now (const char *reg, int size, int is_unsigned);
+static void emit_load_deref_reg_now (const char *reg, int size);
+
+static int emit_load_parenthesized_indirect_member_to_reg_now (const char *reg);
+static int emit_parse_postfix_copy_source_address_now (const char *reg, struct local_symbol *src, const char *src_name, const char *name_start, const char *name_caret, unsigned long name_line);
+
+static void emit_load_postfix_lvalue_address_to_pair_ex_now (const char *lo, const char *hi, int size, int is_unsigned) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (size > (DATA_PTR & 0x1f)) {
+    
+        emit_push_reg_now (lo);
+        
+        emit_load_deref_reg_now (lo, DATA_PTR & 0x1f);
+        emit_pop_reg_now (hi);
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            const char *dhi = amd64_dword_reg_name_from_any (hi);
+            const char *qhi = amd64_qword_reg_name_from_any (hi);
+            
+            if (state->syntax & ASM_SYNTAX_NASM) {
+                fprintf (state->ofp, "    mov %s, dword [%s + 4]\n", dhi, qhi);
+            } else {
+                fprintf (state->ofp, "    mov %s, dword ptr [%s + 4]\n", dhi, qhi);
+            }
+        
+        } else {
+            fprintf (state->ofp, "    movl 4(%%%s), %%%s\n", amd64_qword_reg_name_from_any (hi), amd64_dword_reg_name_from_any (hi));
+        }
+    
+    } else {
+    
+        emit_load_deref_reg_ex_now (lo, size, is_unsigned);
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
+        } else {
+            fprintf (state->ofp, "    xorq %%%s, %%%s\n", hi, hi);
+        }
+    
+    }
+
+}
+
+static void emit_store_pair_to_deref_reg_now (const char *addr_reg, const char *lo, const char *hi) {
+
+    (void) hi;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+            fprintf (state->ofp, "    mov qword [%s], %s\n", addr_reg, amd64_qword_reg_name_from_any (lo));
+        } else {
+            fprintf (state->ofp, "    mov qword ptr [%s], %s\n", addr_reg, amd64_qword_reg_name_from_any (lo));
+        }
+    
+    } else {
+        fprintf (state->ofp, "    movq %%%s, (%%%s)\n", amd64_qword_reg_name_from_any (lo), addr_reg);
+    }
+
+}
+
+static void emit_load_pair_from_deref_reg_now (const char *lo, const char *hi, const char *addr_reg) {
+
+    (void) hi;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+            fprintf (state->ofp, "    mov %s, qword [%s]\n", amd64_qword_reg_name_from_any (lo), addr_reg);
+        } else {
+            fprintf (state->ofp, "    mov %s, qword ptr [%s]\n", amd64_qword_reg_name_from_any (lo), addr_reg);
+        }
+    
+    } else {
+        fprintf (state->ofp, "    movq (%%%s), %%%s\n", addr_reg, amd64_qword_reg_name_from_any (lo));
+    }
+
+}
+
+static void emit_copy_reg_now (const char *dst, const char *src) {
+
+    if (!state->ofp || !dst || !src || strcmp (dst, src) == 0) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    mov %s, %s\n", dst, src);
+    } else {
+        fprintf (state->ofp, "    movq %%%s, %%%s\n", src, dst);
+    }
+
+}
+
+static int emit_parse_builtin_va_arg_address_to_reg_now (const char *reg, int *out_size, int *out_unsigned, int *out_pointer, int *out_floating);
+static int rhs_current_operand_is_floating_now (void);
+static int token_is_floating_constant_now (void);
+
+static void emit_store_floating_member_to_addr_reg_now (const char *addr_reg, int offset, int size);
+static void emit_load_floating_rhs_expression_now (int result_size);
+static void emit_load_assignment_rhs_to_reg (const char *reg);
+static void emit_floating_stack_to_int_pair_now (const char *lo, const char *hi);
+static void emit_integer_pair_to_floating_stack_now (const char *lo, const char *hi, int size);
+
+static void emit_load_assignment_rhs_to_pair (const char *lo, const char *hi) {
+
+    if (_accept (TOK_LPAREN)) {
+    
+        if (token_starts_type_name ()) {
+        
+            int cast_size = 0;
+            int cast_is_unsigned = 0;
+            int cast_is_pointer = 0;
+            
+            if (parse_cast_type_name (&cast_size, &cast_is_unsigned, &cast_is_pointer)) {
+            
+                if (!cast_is_pointer && !last_cast_type_is_floating && rhs_current_operand_is_floating_now ()) {
+                
+                    emit_load_floating_rhs_expression_now (DATA_DOUBLE & 0x1f);
+                    
+                    if (floating_rhs_result_in_eax_bool) {
+                    
+                        if (strcmp (lo, "rax") != 0 && state->ofp) {
+                        
+                            if (state->syntax & ASM_SYNTAX_INTEL) {
+                                fprintf (state->ofp, "    mov %s, rax\n", lo);
+                            } else {
+                                fprintf (state->ofp, "    movq %%rax, %%%s\n", lo);
+                            }
+                        
+                        }
+                        
+                        emit_extend_pair_high_from_low (lo, hi, cast_size, cast_is_unsigned);
+                        floating_rhs_result_in_eax_bool = 0;
+                    
+                    } else {
+                    
+                        emit_floating_stack_to_int_pair_now (lo, hi);
+                        
+                        if ((cast_size & 0x1f) != (DATA_LLONG & 0x1f)) {
+                            emit_extend_pair_high_from_low (lo, hi, cast_size, cast_is_unsigned);
+                        }
+                    
+                    }
+                    
+                    return;
+                
+                }
+                
+                emit_load_assignment_rhs_to_pair (lo, hi);
+                
+                {
+                
+                    int applied_postfix = 0;
+                    
+                    if (cast_is_pointer) {
+                        set_rhs_last_pointer_info (1, cast_size > 0 ? cast_size : (DATA_INT & 0x1f));
+                    } else {
+                        emit_extend_pair_high_from_low (lo, hi, cast_size, cast_is_unsigned);
+                    }
+                    
+                    postfix_member_seen = 0;
+                    
+                    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+                    
+                        applied_postfix = 1;
+                        emit_apply_postfix_member_access_to_reg_now (lo);
+                    
+                    }
+                    
+                    if (applied_postfix && postfix_member_seen) {
+                    
+                        if (postfix_member_size == (DATA_LLONG & 0x1f) && !postfix_member_is_floating) {
+                        
+                            const char *addr_reg = (strcmp (lo, "rcx") != 0 && strcmp (hi, "rcx") != 0) ? "rcx" : "rsi";
+                            
+                            emit_copy_reg_now (addr_reg, lo);
+                            emit_load_pair_from_deref_reg_now (lo, hi, addr_reg);
+                        
+                        } else {
+                            emit_extend_pair_high_from_low (lo, hi, postfix_member_size, postfix_member_is_unsigned);
+                        }
+                    
+                    }
+                
+                }
+                
+                return;
+            
+            }
+        
+        }
+        
+        if (tok.kind != TOK_LPAREN && current_integer_expr_is_foldable_now ()) {
+        
+            int64_s v = const64_from_current_foldable_expr ();
+            expect (TOK_RPAREN, ")");
+            
+            emit_load_const64_to_pair_now (lo, hi, v);
+            return;
+        
+        }
+        
+        if (emit_load_parenthesized_indirect_member_to_reg_now (lo)) {
+        
+            emit_extend_pair_high_from_low (lo, hi, DATA_INT & 0x1f, 1);
+            return;
+        
+        }
+        
+        emit_load_assignment_rhs_expression_to_pair (lo, hi, 1);
+        expect (TOK_RPAREN, ")");
+        
+        {
+        
+            int applied_postfix = 0;
+            postfix_member_seen = 0;
+            
+            while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+            
+                applied_postfix = 1;
+                emit_apply_postfix_member_access_to_reg_now (lo);
+            
+            }
+            
+            if (applied_postfix && postfix_member_seen) {
+            
+                if (postfix_member_size == (DATA_LLONG & 0x1f) && !postfix_member_is_floating) {
+                
+                    const char *addr_reg = (strcmp (lo, "rcx") != 0 && strcmp (hi, "rcx") != 0) ? "rcx" : "rsi";
+                    
+                    emit_copy_reg_now (addr_reg, lo);
+                    emit_load_pair_from_deref_reg_now (lo, hi, addr_reg);
+                
+                } else {
+                    emit_extend_pair_high_from_low (lo, hi, postfix_member_size, postfix_member_is_unsigned);
+                }
+            
+            }
+        
+        }
+            
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_PLUS || tok.kind == TOK_MINUS || tok.kind == TOK_TILDE || tok.kind == TOK_XMARK) {
+    
+        enum token_kind unary_op = tok.kind;
+        get_token ();
+        
+        emit_load_assignment_rhs_to_pair (lo, hi);
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                if (unary_op == TOK_MINUS) {
+                
+                    fprintf (state->ofp, "    not %s\n", lo);
+                    fprintf (state->ofp, "    not %s\n", hi);
+                    
+                    fprintf (state->ofp, "    add %s, 1\n", lo);
+                    fprintf (state->ofp, "    adc %s, 0\n", hi);
+                
+                } else if (unary_op == TOK_TILDE) {
+                
+                    fprintf (state->ofp, "    not %s\n", lo);
+                    fprintf (state->ofp, "    not %s\n", hi);
+                
+                } else if (unary_op == TOK_XMARK) {
+                
+                    fprintf (state->ofp, "    or %s, %s\n", lo, hi);
+                    fprintf (state->ofp, "    setz al\n");
+                    fprintf (state->ofp, "    movzx eax, al\n");
+                    
+                    if (strcmp (lo, "rax") != 0) {
+                        fprintf (state->ofp, "    mov %s, rax\n", lo);
+                    }
+                    
+                    fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
+                
+                }
+            
+            } else {
+            
+                if (unary_op == TOK_MINUS) {
+                
+                    fprintf (state->ofp, "    notq %%%s\n", lo);
+                    fprintf (state->ofp, "    notq %%%s\n", hi);
+                    
+                    fprintf (state->ofp, "    addq $1, %%%s\n", lo);
+                    fprintf (state->ofp, "    adcq $0, %%%s\n", hi);
+                
+                } else if (unary_op == TOK_TILDE) {
+                
+                    fprintf (state->ofp, "    notq %%%s\n", lo);
+                    fprintf (state->ofp, "    notq %%%s\n", hi);
+                
+                } else if (unary_op == TOK_XMARK) {
+                
+                    fprintf (state->ofp, "    orq %%%s, %%%s\n", hi, lo);
+                    fprintf (state->ofp, "    setz %%al\n");
+                    fprintf (state->ofp, "    movzbl %%al, %%eax\n");
+                    
+                    if (strcmp (lo, "rax") != 0) {
+                        fprintf (state->ofp, "    movq %%rax, %%%s\n", lo);
+                    }
+                    
+                    fprintf (state->ofp, "    xorq %%%s, %%%s\n", hi, hi);
+                
+                }
+            
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (emit_load_prefix_incdec_to_pair_now (lo, hi)) {
+        return;
+    }
+    
+    if (tok.kind == TOK_AMPER) {
+    
+        /*
+         * Address-of is a valid pointer-valued operand in 64-bit contexts.
+         *
+         * The 32-bit RHS path already handles &object, &(postfix),
+         * &object.member and &object[index].  The pair path used for 64-bit
+         * / pointer-sized expressions did not, so expressions such as:
+         *
+         *     (char *)&format + n
+         *
+         * fell through to const64_from_current_operand().  That helper delegates
+         * to expr_const64(), which quite rightly rejects the identifier after
+         * '&' as not being an integer constant expression.
+         *
+         * Reuse the normal scalar address-of parser, then widen the pointer
+         * value into the requested pair result.  This keeps the fix generic:
+         * it is not tied to va_start, sizeof, or any particular macro.
+         */
+        emit_load_assignment_rhs_to_reg (lo);
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
+            } else {
+                fprintf (state->ofp, "    xorq %%%s, %%%s\n", hi, hi);
+            }
+        
+        }
+        
+        set_rhs_last_pointer_info (1, DATA_INT & 0x1f);
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_STAR) {
+    
+        char *name;
+        
+        const char *name_start;
+        const char *name_caret;
+        
+        unsigned long name_line;
+        struct local_symbol *src;
+        
+        int global_index;
+        
+        int deref_size = DATA_INT & 0x1f;
+        int deref_unsigned = 1;
+        
+        int postfix_incdec = 0;
+        
+        enum token_kind postfix_op = TOK_EOF;
+        get_token ();
+        
+        name_start = tok.start;
+        name_caret = tok.caret;
+        name_line = get_line_number ();
+        
+        if (tok.kind == TOK_LPAREN) {
+        
+            const char *addr_reg = (strcmp (lo, "rcx") != 0 && strcmp (hi, "rcx") != 0) ? "rcx" : "rsi";
+            int cast_deref_size = DATA_INT & 0x1f;
+            
+            get_token ();
+            
+            if (is_type_start (tok.kind) && parse_deref_cast_type_name (&cast_deref_size)) {
+            
+                emit_load_assignment_rhs_to_reg (lo);
+                
+                if ((cast_deref_size & 0x1f) == (DATA_LLONG & 0x1f)) {
+                
+                    emit_copy_reg_now (addr_reg, lo);
+                    emit_load_pair_from_deref_reg_now (lo, hi, addr_reg);
+                
+                } else {
+                
+                    emit_load_deref_reg_now (lo, cast_deref_size);
+                    emit_extend_pair_high_from_low (lo, hi, cast_deref_size, 1);
+                
+                }
+                
+                return;
+            
+            }
+            
+            emit_load_assignment_rhs_expression_to_reg (lo);
+            expect (TOK_RPAREN, ")");
+            
+            emit_load_deref_reg_now (lo, DATA_INT & 0x1f);
+            emit_extend_pair_high_from_low (lo, hi, DATA_INT & 0x1f, 1);
+            
+            return;
+        
+        }
+        
+        if (tok.kind != TOK_IDENT || !tok.ident) {
+        
+            int64_s zero;
+            
+            zero.low = 0;
+            zero.high = 0;
+            
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
+            
+            emit_load_const64_to_pair_now (lo, hi, zero);
+            return;
+        
+        }
+        
+        name = xstrdup (tok.ident);
+        get_token ();
+        
+        src = find_local_symbol (name);
+        global_index = find_global_symbol (name);
+        
+        if (!src && global_index >= 0 && tok.kind == TOK_LPAREN &&
+            get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION) {
+        
+            const char *addr_reg = (strcmp (lo, "rcx") != 0 && strcmp (hi, "rcx") != 0) ? "rcx" : "rsi";
+            int fptr_depth = get_global_symbol_pointer_depth (name);
+            int fpointed_size = get_global_symbol_pointed_size (name);
+            
+            if (get_global_symbol_returns_void (name)) {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "void function '%s' used as a value", name);
+            }
+            
+            emit_call_identifier_to_reg_now (name, lo, name_start, name_caret, name_line);
+            
+            if (fptr_depth > 1) {
+                deref_size = DATA_PTR & 0x1f;
+            } else if (fptr_depth == 1 && fpointed_size > 0) {
+                deref_size = fpointed_size & 0x1f;
+            }
+            
+            if (deref_size == (DATA_LLONG & 0x1f)) {
+            
+                emit_copy_reg_now (addr_reg, lo);
+                emit_load_pair_from_deref_reg_now (lo, hi, addr_reg);
+            
+            } else {
+            
+                emit_load_deref_reg_now (lo, deref_size);
+                emit_extend_pair_high_from_low (lo, hi, deref_size, 1);
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+        
+            postfix_incdec = 1;
+            postfix_op = tok.kind;
+            
+            get_token ();
+        
+        }
+        
+        if (src) {
+        
+            if (src->pointer_depth > 1) {
+                deref_size = DATA_PTR & 0x1f;
+            } else if (src->pointer_depth == 1 && src->pointed_size > 0) {
+                deref_size = src->pointed_size & 0x1f;
+            }
+            
+            if (src->is_static && src->static_label) {
+                emit_load_global_to_reg (lo, src->static_label, DATA_PTR);
+            } else {
+                emit_load_local_to_reg (lo, src->offset, DATA_PTR);
+            }
+        
+        } else if (global_index >= 0) {
+        
+            if (get_global_symbol_pointer_depth (name) > 1) {
+                deref_size = DATA_PTR & 0x1f;
+            } else if (get_global_symbol_pointer_depth (name) == 1 && get_global_symbol_pointed_size (name) > 0) {
+                deref_size = get_global_symbol_pointed_size (name) & 0x1f;
+            }
+            
+            emit_load_global_to_reg (lo, name, DATA_PTR);
+        
+        } else {
+        
+            int64_s zero;
+            
+            zero.low = 0;
+            zero.high = 0;
+            
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            
+            emit_load_const64_to_pair_now (lo, hi, zero);
+            free (name);
+            
+            return;
+        
+        }
+        
+        if (deref_size == (DATA_LLONG & 0x1f)) {
+        
+            emit_push_reg_now (lo);
+            
+            emit_load_deref_reg_now (lo, DATA_INT & 0x1f);
+            emit_pop_reg_now (hi);
+            
+            if (state->ofp) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    const char *dhi = amd64_dword_reg_name_from_any (hi);
+                    const char *qhi = amd64_qword_reg_name_from_any (hi);
+                    
+                    if (state->syntax & ASM_SYNTAX_NASM) {
+                        fprintf (state->ofp, "    mov %s, dword [%s + 4]\n", dhi, qhi);
+                    } else {
+                        fprintf (state->ofp, "    mov %s, dword ptr [%s + 4]\n", dhi, qhi);
+                    }
+                
+                } else {
+                    fprintf (state->ofp, "    movl 4(%%%s), %%%s\n", amd64_qword_reg_name_from_any (hi), amd64_dword_reg_name_from_any (hi));
+                }
+            
+            }
+        
+        } else {
+        
+            emit_load_deref_reg_now (lo, deref_size);
+            emit_extend_pair_high_from_low (lo, hi, deref_size, deref_unsigned);
+        
+        }
+        
+        if (postfix_incdec) {
+        
+            emit_push_reg_now (lo);
+            emit_push_reg_now (hi);
+            
+            emit_incdec_symbol_now (src, name, postfix_op, name_line, name_start, name_caret);
+            
+            emit_pop_reg_now (hi);
+            emit_pop_reg_now (lo);
+        
+        }
+        
+        free (name);
+        return;
+    
+    }
+    
+    if (token_is_sizeof_keyword ()) {
+    
+        int64_s v = sizeof_from_current_token ();
+        
+        emit_load_const64_to_pair_now (lo, hi, v);
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_SCC_BUILTIN_VA_ARG) {
+    
+        int va_size = DATA_INT & 0x1f;
+        int va_unsigned = 1;
+        int va_pointer = 0;
+        int va_floating = 0;
+        
+        const char *addr_reg = (strcmp (lo, "rcx") != 0 && strcmp (hi, "rcx") != 0) ? "rcx" : "rsi";
+        
+        get_token ();
+        emit_parse_builtin_va_arg_address_to_reg_now (addr_reg, &va_size, &va_unsigned, &va_pointer, &va_floating);
+        
+        if (va_size == (DATA_LLONG & 0x1f) && va_pointer == 0) {
+            emit_load_pair_from_deref_reg_now (lo, hi, addr_reg);
+        } else {
+        
+            emit_copy_reg_now (lo, addr_reg);
+            emit_load_deref_reg_now (lo, va_size);
+            
+            emit_extend_pair_high_from_low (lo, hi, va_size, va_unsigned);
+        
+        }
+        
+        return;
+    
+    }
+
+    if (tok.kind == TOK_IDENT) {
+    
+        enum token_kind postfix_op = TOK_EOF;
+        char *name = xstrdup (tok.ident);
+        
+        const char *name_start = tok.start, *name_caret = tok.caret;
+        unsigned long name_line = get_line_number ();
+        
+        int postfix_incdec = 0;
+        
+        struct local_symbol *src;
+        int64_s enum_value;
+        
+        get_token ();
+        
+        if (strcmp (name, "__scc_builtin_va_arg") == 0 && tok.kind == TOK_LPAREN) {
+        
+            int va_size = DATA_INT & 0x1f;
+            int va_unsigned = 1;
+            int va_pointer = 0;
+            int va_floating = 0;
+            
+            const char *addr_reg = (strcmp (lo, "rcx") != 0 && strcmp (hi, "rcx") != 0) ? "rcx" : "rsi";
+            emit_parse_builtin_va_arg_address_to_reg_now (addr_reg, &va_size, &va_unsigned, &va_pointer, &va_floating);
+            
+            if (va_size == (DATA_LLONG & 0x1f) && !va_floating && va_pointer == 0) {
+                emit_load_pair_from_deref_reg_now (lo, hi, addr_reg);
+            } else {
+            
+                emit_copy_reg_now (lo, addr_reg);
+                emit_load_deref_reg_now (lo, va_size);
+                emit_extend_pair_high_from_low (lo, hi, va_size, va_unsigned);
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (!find_local_symbol (name) && find_global_symbol (name) < 0 && resolve_enum_constant (name, &enum_value)) {
+        
+            emit_load_const64_to_pair_now (lo, hi, enum_value);
+            
+            free (name);
+            return;
+        
+        }
+
+        if (tok.kind == TOK_LPAREN) {
+        
+            if (!find_local_symbol (name)) {
+                ensure_global_function_symbol (name, name_start, name_caret, name_line);
+            }
+            
+            if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION && get_global_symbol_returns_void (name)) {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "void function '%s' used as a value", name);
+            }
+            
+            emit_call_identifier_to_reg_now (name, "rax", name_start, name_caret, name_line);
+            
+            if (get_global_function_returns_floating (name)) {
+            
+                if (state->ofp) {
+                
+                    if (get_global_symbol_size (name) == (DATA_FLOAT & 0x1f)) {
+                    
+                        if (state->syntax & ASM_SYNTAX_INTEL) {
+                        
+                            /*
+                             * Keep the temporary XMM0 spill slot 8 bytes wide.
+                             * Using a 4-byte stack adjustment leaves RSP misaligned
+                             * while copying a float return value into the integer
+                             * return pair used by the rest of this backend.
+                             */
+                            fprintf (state->ofp, "    sub rsp, 8\n");
+                            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    movss dword [rsp], xmm0\n" : "    movss dword ptr [rsp], xmm0\n");
+                            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [rsp]\n" : "    mov %s, dword ptr [rsp]\n", amd64_dword_reg_name_from_any (lo));
+                            fprintf (state->ofp, "    xor %s, %s\n", amd64_dword_reg_name_from_any (hi), amd64_dword_reg_name_from_any (hi));
+                            fprintf (state->ofp, "    add rsp, 8\n");
+                        
+                        } else {
+                        
+                            /* Keep the temporary XMM0 spill slot 8 bytes wide and preserve stack alignment. */
+                            fprintf (state->ofp, "    subq $8, %%rsp\n");
+                            fprintf (state->ofp, "    movss %%xmm0, (%%rsp)\n");
+                            fprintf (state->ofp, "    movl (%%rsp), %%%s\n", amd64_dword_reg_name_from_any (lo));
+                            fprintf (state->ofp, "    xorl %%%s, %%%s\n", amd64_dword_reg_name_from_any (hi), amd64_dword_reg_name_from_any (hi));
+                            fprintf (state->ofp, "    addq $8, %%rsp\n");
+                        
+                        }
+                    
+                    } else if (state->syntax & ASM_SYNTAX_INTEL) {
+                    
+                        fprintf (state->ofp, "    sub rsp, 8\n");
+                        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    movsd qword [rsp], xmm0\n" : "    movsd qword ptr [rsp], xmm0\n");
+                        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [rsp]\n" : "    mov %s, dword ptr [rsp]\n", amd64_dword_reg_name_from_any (lo));
+                        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [rsp + 4]\n" : "    mov %s, dword ptr [rsp + 4]\n", amd64_dword_reg_name_from_any (hi));
+                        fprintf (state->ofp, "    add rsp, 8\n");
+                    
+                    } else {
+                    
+                        fprintf (state->ofp, "    subq $8, %%rsp\n");
+                        fprintf (state->ofp, "    movsd %%xmm0, (%%rsp)\n");
+                        fprintf (state->ofp, "    movl (%%rsp), %%%s\n", amd64_dword_reg_name_from_any (lo));
+                        fprintf (state->ofp, "    movl 4(%%rsp), %%%s\n", amd64_dword_reg_name_from_any (hi));
+                        fprintf (state->ofp, "    addq $8, %%rsp\n");
+                    
+                    }
+                
+                }
+                
+                free (name);
+                return;
+            }
+            
+            if (state->ofp) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    if (strcmp (lo, "rax") != 0) {
+                        fprintf (state->ofp, "    mov %s, rax\n", lo);
+                    }
+                    
+                    if (strcmp (hi, "rdx") != 0) {
+                        fprintf (state->ofp, "    mov %s, rdx\n", hi);
+                    }
+                
+                } else {
+                
+                    if (strcmp (lo, "rax") != 0) {
+                        fprintf (state->ofp, "    movq %%rax, %%%s\n", lo);
+                    }
+                    
+                    if (strcmp (hi, "rdx") != 0) {
+                        fprintf (state->ofp, "    movq %%rdx, %%%s\n", hi);
+                    }
+                
+                }
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+        
+            postfix_incdec = 1;
+            postfix_op = tok.kind;
+            
+            get_token ();
+        
+        }
+
+        src = find_local_symbol (name);
+        
+        if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT || tok.kind == TOK_LBRACK) {
+        
+            int source_size;
+            
+            if (src || find_global_symbol (name) >= 0) {
+            
+                if (tok.kind == TOK_ARROW || tok.kind == TOK_LBRACK) {
+                
+                    if (src) {
+                    
+                        postfix_copy_lvalue_size = src->pointer_depth > 0 ? src->pointed_size : src->size;
+                        postfix_copy_lvalue_tag_name = src->pointer_depth > 0 ? src->pointed_tag_name : src->tag_name;
+                    
+                    } else {
+                    
+                        postfix_copy_lvalue_size = get_global_symbol_pointer_depth (name) > 0 ? get_global_symbol_pointed_size (name) : get_global_symbol_size (name);
+                        postfix_copy_lvalue_tag_name = 0;
+                    
+                    }
+                
+                } else if (src) {
+                
+                    postfix_copy_lvalue_size = src->size;
+                    postfix_copy_lvalue_tag_name = src->tag_name;
+                
+                } else {
+                
+                    postfix_copy_lvalue_size = get_global_symbol_size (name);
+                    postfix_copy_lvalue_tag_name = get_global_symbol_tag_name (name);
+                
+                }
+                
+                if (!emit_parse_postfix_copy_source_address_now (lo, src, name, name_start, name_caret, name_line)) {
+                
+                    free (name);
+                    return;
+                
+                }
+                
+                source_size = postfix_copy_lvalue_size;
+                
+                if (source_size <= 0) {
+                    source_size = DATA_INT & 0x1f;
+                }
+                
+                if (is_assignment_operator (tok.kind)) {
+                
+                    enum token_kind assign_op = tok.kind;
+                    
+                    const char *addr_reg = (strcmp (lo, "rcx") != 0 && strcmp (hi, "rcx") != 0) ? "rcx" : "rdx";
+                    int lvalue_size = index_step_size (source_size);
+                    
+                    get_token ();
+                    
+                    if (assign_op == TOK_ASSIGN && (postfix_member_is_floating || token_is_floating_constant_now () || rhs_current_operand_is_floating_now ())) {
+                    
+                        emit_push_reg_now (lo);
+                        emit_load_floating_rhs_expression_now (lvalue_size);
+                        
+                        emit_pop_reg_now (addr_reg);
+                        emit_store_floating_member_to_addr_reg_now (addr_reg, 0, lvalue_size);
+                        
+                        free (name);
+                        return;
+                    }
+                    
+                    if (assign_op == TOK_ASSIGN && lvalue_size == (DATA_LLONG & 0x1f)) {
+                    
+                        emit_push_reg_now (lo);
+                        
+                        emit_load_assignment_rhs_expression_to_pair (lo, hi, 1);
+                        emit_pop_reg_now (addr_reg);
+                        
+                        emit_store_pair_to_deref_reg_now (addr_reg, lo, hi);
+                        
+                        free (name);
+                        return;
+                    
+                    }
+                    
+                    if (assign_op == TOK_ASSIGN) {
+                    
+                        emit_push_reg_now (lo);
+                        
+                        emit_load_assignment_rhs_expression_to_reg (lo);
+                        emit_extend_pair_high_from_low (lo, hi, lvalue_size, 1);
+                        
+                        emit_pop_reg_now (addr_reg);
+                        emit_store_reg_to_deref_reg_now (addr_reg, lo, lvalue_size);
+                        
+                        free (name);
+                        return;
+                    
+                    }
+                    
+                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "compound member assignment expression not implemented in 64-bit context");
+                    
+                    free (name);
+                    return;
+                
+                }
+                
+                emit_load_postfix_lvalue_address_to_pair_ex_now (lo, hi, source_size, src ? (src->pointer_depth > 0 ? src->pointed_is_unsigned : src->is_unsigned) : (get_global_symbol_pointer_depth (name) > 0 ? get_global_symbol_pointed_is_unsigned (name) : get_global_symbol_unsigned (name)));
+                
+                free (name);
+                return;
+            
+            }
+        
+        }
+        
+        if (src) {
+        
+            if (src->size == (DATA_LLONG & 0x1f) && !src->is_floating) {
+            
+                if (src->is_static && src->static_label) {
+                    emit_load_global64_to_pair (lo, hi, src->static_label);
+                } else {
+                    emit_load_local64_to_pair (src->offset, lo, hi);
+                }
+            
+            } else {
+            
+                if (src->is_static && src->static_label) {
+                    emit_load_global_to_reg_ex (lo, src->static_label, src->size, src->is_unsigned);
+                } else {
+                    emit_load_local_to_reg_ex (lo, src->offset, src->size, src->is_unsigned);
+                }
+                
+                emit_extend_pair_high_from_low (lo, hi, src->size, src->is_unsigned);
+            
+            }
+            
+            if (postfix_incdec) {
+            
+                emit_push_reg_now (lo);
+                emit_push_reg_now (hi);
+                
+                emit_incdec_symbol_now (src, name, postfix_op, name_line, name_start, name_caret);
+                
+                emit_pop_reg_now (hi);
+                emit_pop_reg_now (lo);
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (find_global_symbol (name) >= 0) {
+        
+            if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION ||
+                get_global_symbol_array (name) ||
+                (!get_global_symbol_pointer_depth (name) &&
+                    get_global_symbol_size (name) > (DATA_PTR & 0x1f))) {
+            
+                /*
+                 * In a 64-bit/pair context, an array/function/aggregate
+                 * expression still decays to its address.  The 32-bit RHS
+                 * path already handled this, but this path was used when
+                 * the caller requested rax:rdx (for example a mis-sized
+                 * pointer return).  Loading the first word of the global
+                 * table produced bogus pseudo-op table pointers such as the
+                 * first string pointer instead of &table.
+                 */
+                emit_load_address_to_reg_now (lo, name);
+                if (state->ofp) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
+                    } else {
+                        fprintf (state->ofp, "    xorq %%%s, %%%s\n", hi, hi);
+                    }
+                
+                }
+            
+            } else if (get_global_symbol_size (name) == (DATA_LLONG & 0x1f) && !get_global_symbol_floating (name)) {
+                emit_load_global64_to_pair (lo, hi, name);
+            } else {
+            
+                emit_load_global_to_reg_ex (lo, name, get_global_symbol_size (name), get_global_symbol_unsigned (name));
+                emit_extend_pair_high_from_low (lo, hi, get_global_symbol_size (name), get_global_symbol_unsigned (name));
+            
+            }
+            
+            if (postfix_incdec) {
+            
+                emit_push_reg_now (lo);
+                emit_push_reg_now (hi);
+                
+                emit_incdec_symbol_now (0, name, postfix_op, name_line, name_start, name_caret);
+                
+                emit_pop_reg_now (hi);
+                emit_pop_reg_now (lo);
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        free (name);
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                fprintf (state->ofp, "    xor %s, %s\n", lo, lo);
+                fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
+            
+            } else {
+            
+                fprintf (state->ofp, "    xorq %%%s, %%%s\n", lo, lo);
+                fprintf (state->ofp, "    xorq %%%s, %%%s\n", hi, hi);
+            
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (recover_unknown_rhs_identifier ()) {
+    
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                fprintf (state->ofp, "    xor %s, %s\n", lo, lo);
+                fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
+            
+            } else {
+            
+                fprintf (state->ofp, "    xorq %%%s, %%%s\n", lo, lo);
+                fprintf (state->ofp, "    xorq %%%s, %%%s\n", hi, hi);
+            
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    {
+    
+        int64_s v = const64_from_current_operand ();
+        emit_load_const64_to_pair_now (lo, hi, v);
+    
+    }
+
+}
+
+static void emit_assignment_divmod64 (int is_unsigned, int want_mod) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    /*
+     * AMD64 has native 64-bit division.  Do not emit the old i386
+     * software 64/64 divide helper here.  The 64-bit binary-expression
+     * path leaves the dividend in RAX and the divisor in RBX.  DIV/IDIV
+     * produces quotient in RAX and remainder in RDX.
+     */
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (is_unsigned) {
+        
+            fprintf (state->ofp, "    xor rdx, rdx\n");
+            fprintf (state->ofp, "    div rbx\n");
+        
+        } else {
+        
+            fprintf (state->ofp, "    cqo\n");
+            fprintf (state->ofp, "    idiv rbx\n");
+        
+        }
+        
+        if (want_mod) {
+            fprintf (state->ofp, "    mov rax, rdx\n");
+        }
+    
+    } else {
+    
+        if (is_unsigned) {
+        
+            fprintf (state->ofp, "    xorq %%rdx, %%rdx\n");
+            fprintf (state->ofp, "    divq %%rbx\n");
+        
+        } else {
+        
+            fprintf (state->ofp, "    cqto\n");
+            fprintf (state->ofp, "    idivq %%rbx\n");
+        
+        }
+        
+        if (want_mod) {
+            fprintf (state->ofp, "    movq %%rdx, %%rax\n");
+        }
+    
+    }
+
+}
+
+static void emit_assignment_binary_op64 (enum token_kind op, int is_unsigned) {
+
+    int l1, l2;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        switch (op) {
+        
+            case TOK_PLUS:      case TOK_PLUSEQ:
+            
+                fprintf (state->ofp, "    add rax, rbx\n");
+                break;
+            
+            case TOK_MINUS:     case TOK_MINUSEQ:
+            
+                fprintf (state->ofp, "    sub rax, rbx\n");
+                break;
+            
+            case TOK_STAR:      case TOK_STAREQ:
+            
+                fprintf (state->ofp, "    imul rax, rbx\n");
+                break;
+            
+            case TOK_BSLASH:    case TOK_SLASHEQ:
+            
+                emit_assignment_divmod64 (is_unsigned, 0);
+                break;
+            
+            case TOK_MOD:       case TOK_MODEQ:
+            
+                emit_assignment_divmod64 (is_unsigned, 1);
+                break;
+            
+            case TOK_AMPER:     case TOK_ANDEQ:
+            
+                fprintf (state->ofp, "    and rax, rbx\n");
+                break;
+            
+            case TOK_PIPE:      case TOK_OREQ:
+            
+                fprintf (state->ofp, "    or rax, rbx\n");
+                break;
+            
+            case TOK_CARET:     case TOK_XOREQ:
+            
+                fprintf (state->ofp, "    xor rax, rbx\n");
+                break;
+            
+            case TOK_LSH:       case TOK_LSHEQ:
+            
+                l1 = anon_label++;
+                l2 = anon_label++;
+                
+                fprintf (state->ofp, "    mov rcx, rbx\n");
+                fprintf (state->ofp, "    cmp rcx, 64\n");
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jae L%d\n" : "    jae .L%d\n"), l1);
+                fprintf (state->ofp, "    shl rax, cl\n");
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jmp L%d\n" : "    jmp .L%d\n"), l2);
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), l1);
+                fprintf (state->ofp, "    xor rax, rax\n");
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), l2);
+                
+                break;
+            
+            case TOK_RSH:       case TOK_RSHEQ:
+            
+                l1 = anon_label++;
+                l2 = anon_label++;
+                
+                fprintf (state->ofp, "    mov rcx, rbx\n");
+                fprintf (state->ofp, "    cmp rcx, 64\n");
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jae L%d\n" : "    jae .L%d\n"), l1);
+                fprintf (state->ofp, is_unsigned ? "    shr rax, cl\n" : "    sar rax, cl\n");
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jmp L%d\n" : "    jmp .L%d\n"), l2);
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), l1);
+                fprintf (state->ofp, is_unsigned ? "    xor rax, rax\n" : "    sar rax, 63\n");
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), l2);
+                
+                break;
+            
+            default:
+            
+                break;
+        
+        }
+    
+    } else {
+    
+        switch (op) {
+        
+            case TOK_PLUS:      case TOK_PLUSEQ:
+            
+                fprintf (state->ofp, "    addq %%rbx, %%rax\n");
+                break;
+            
+            case TOK_MINUS:     case TOK_MINUSEQ:
+            
+                fprintf (state->ofp, "    subq %%rbx, %%rax\n");
+                break;
+            
+            case TOK_STAR:      case TOK_STAREQ:
+            
+                fprintf (state->ofp, "    imulq %%rbx, %%rax\n");
+                break;
+            
+            case TOK_BSLASH:    case TOK_SLASHEQ:
+            
+                emit_assignment_divmod64 (is_unsigned, 0);
+                break;
+            
+            case TOK_MOD:       case TOK_MODEQ:
+            
+                emit_assignment_divmod64 (is_unsigned, 1);
+                break;
+            
+            case TOK_AMPER:     case TOK_ANDEQ:
+            
+                fprintf (state->ofp, "    andq %%rbx, %%rax\n");
+                break;
+            
+            case TOK_PIPE:      case TOK_OREQ:
+            
+                fprintf (state->ofp, "    orq %%rbx, %%rax\n");
+                break;
+            
+            case TOK_CARET:     case TOK_XOREQ:
+            
+                fprintf (state->ofp, "    xorq %%rbx, %%rax\n");
+                break;
+            
+            case TOK_LSH:       case TOK_LSHEQ:
+            
+                l1 = anon_label++;
+                l2 = anon_label++;
+                
+                fprintf (state->ofp, "    movq %%rbx, %%rcx\n");
+                fprintf (state->ofp, "    cmpq $64, %%rcx\n");
+                fprintf (state->ofp, "    jae .L%d\n", l1);
+                fprintf (state->ofp, "    shlq %%cl, %%rax\n");
+                fprintf (state->ofp, "    jmp .L%d\n", l2);
+                fprintf (state->ofp, ".L%d:\n", l1);
+                fprintf (state->ofp, "    xorq %%rax, %%rax\n");
+                fprintf (state->ofp, ".L%d:\n", l2);
+                
+                break;
+            
+            case TOK_RSH:       case TOK_RSHEQ:
+            
+                l1 = anon_label++;
+                l2 = anon_label++;
+                
+                fprintf (state->ofp, "    movq %%rbx, %%rcx\n");
+                fprintf (state->ofp, "    cmpq $64, %%rcx\n");
+                fprintf (state->ofp, "    jae .L%d\n", l1);
+                fprintf (state->ofp, is_unsigned ? "    shrq %%cl, %%rax\n" : "    sarq %%cl, %%rax\n");
+                fprintf (state->ofp, "    jmp .L%d\n", l2);
+                fprintf (state->ofp, ".L%d:\n", l1);
+                fprintf (state->ofp, is_unsigned ? "    xorq %%rax, %%rax\n" : "    sarq $63, %%rax\n");
+                fprintf (state->ofp, ".L%d:\n", l2);
+                
+                break;
+            
+            default:
+            
+                break;
+        
+        }
+    
+    }
+
+}
+
+static void amd64_emit_load_xmm0_to_floating_stack_now (int size) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (size == (DATA_FLOAT & 0x1f)) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, "    sub rsp, 8\n");
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movss dword [rsp], xmm0\n" : "    movss dword ptr [rsp], xmm0\n"));
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fld dword [rsp]\n" : "    fld dword ptr [rsp]\n"));
+            fprintf (state->ofp, "    add rsp, 8\n");
+        
+        } else {
+        
+            fprintf (state->ofp, "    subq $8, %%rsp\n");
+            fprintf (state->ofp, "    movss %%xmm0, (%%rsp)\n");
+            fprintf (state->ofp, "    flds (%%rsp)\n");
+            fprintf (state->ofp, "    addq $8, %%rsp\n");
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    sub rsp, 8\n");
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movsd qword [rsp], xmm0\n" : "    movsd qword ptr [rsp], xmm0\n"));
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fld qword [rsp]\n" : "    fld qword ptr [rsp]\n"));
+        fprintf (state->ofp, "    add rsp, 8\n");
+    
+    } else {
+    
+        fprintf (state->ofp, "    subq $8, %%rsp\n");
+        fprintf (state->ofp, "    movsd %%xmm0, (%%rsp)\n");
+        fprintf (state->ofp, "    fldl (%%rsp)\n");
+        fprintf (state->ofp, "    addq $8, %%rsp\n");
+    
+    }
+
+}
+
+static void emit_call_identifier_to_reg_now (const char *name, const char *reg, const char *name_start, const char *name_caret, unsigned long name_line);
+static void emit_assignment_binary_op (enum token_kind op, int is_unsigned);
+static void emit_store_member_to_addr_reg_now (const char *addr_reg, int offset, const char *value_reg, int size);
+static void emit_store_reg_to_deref_reg_now (const char *addr_reg, const char *value_reg, int size);
+static void emit_load_deref_reg_now (const char *reg, int size);
+
+static void emit_store_floating_member_to_addr_reg_now (const char *addr_reg, int offset, int size);
+static void emit_load_floating_rhs_expression_now (int result_size);
+
+static int emit_load_parenthesized_assignment_expression_to_reg_now (const char *reg, int *out_is_unsigned);
+static int token_is_floating_constant_now (void);
+
+static void emit_load_local_address_to_reg_now (const char *reg, long offset) {
+
+    char memref[64];
+    
+    if (!state->ofp || !reg) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_rbp_offset (memref, sizeof (memref), offset);
+        fprintf (state->ofp, "    lea %s, %s\n", reg, memref);
+    
+    } else {
+        fprintf (state->ofp, "    leaq %ld(%%rbp), %%%s\n", offset, reg);
+    }
+
+}
+
+static void emit_apply_postfix_member_access_to_reg_now (const char *reg) {
+
+    postfix_member_pointer_depth = 0;
+    postfix_member_pointed_size = 0;
+    postfix_member_seen = 0;
+    postfix_member_offset = 0;
+    postfix_member_size = 0;
+    postfix_member_is_floating = 0;
+    postfix_member_is_unsigned = 0;
+    
+    postfix_member_calling_convention = TOK_EOF;
+
+    {
+    
+        const char *current_object_tag_name = postfix_copy_lvalue_tag_name;
+        int current_object_size = postfix_copy_lvalue_size;
+        
+        if (current_object_size <= 0 && rhs_last_pointed_size > 0) {
+            current_object_size = rhs_last_pointed_size;
+        }
+        
+        while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+        
+            enum token_kind op = tok.kind;
+            char *member;
+            
+            const char *member_start;
+            const char *member_caret;
+            
+            unsigned long member_line;
+            
+            int offset = 0;
+            int size = DATA_INT & 0x1f;
+            int elem_size = DATA_INT & 0x1f;
+            int pointer_depth = 0;
+            int is_array = 0;
+            int is_floating = 0;
+            int is_unsigned = 0;
+            
+            get_token ();
+            
+            member_start = tok.start;
+            member_caret = tok.caret;
+            member_line = get_line_number ();
+            
+            if (tok.kind != TOK_IDENT) {
+            
+                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", op == TOK_ARROW ? "->" : ".");
+                return;
+            
+            }
+            
+            member = xstrdup (tok.ident);
+            get_token ();
+            
+            if (!find_member_info_ex_bounded (member, current_object_size, current_object_tag_name, &offset, &size, &elem_size, &pointer_depth, &is_array, &is_floating)) {
+            
+                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+                
+                free (member);
+                return;
+            
+            }
+            
+            is_unsigned = last_found_member_is_unsigned;
+            
+            {
+            
+                const char *member_tag_name = last_found_member_tag_name;
+                
+                /*
+                 * For an array member whose element type is a pointer, the
+                 * subscript step is always one pointer.  Keep this independent
+                 * of the pointed aggregate size; otherwise expressions like
+                 * ic->heads[i] scale by sizeof(*heads[i]) and are later passed
+                 * as an aggregate instead of one pointer.
+                 */
+                if (is_array && pointer_depth > 0) {
+                    elem_size = DATA_PTR;
+                } else if (pointer_depth > 1) {
+                    elem_size = DATA_PTR;
+                } else if (pointer_depth == 1 && member_tag_name) {
+                
+                    struct aggregate_tag_entry *entry = find_aggregate_tag (member_tag_name, 0);
+                    
+                    if (entry) {
+                        elem_size = entry->size;
+                    }
+                
+                }
+                
+                current_object_tag_name = member_tag_name;
+            
+            }
+            
+            free (member);
+            
+            postfix_member_seen = 1;
+            postfix_member_pointer_depth = is_array ? 1 : pointer_depth;
+            postfix_member_pointed_size = elem_size;
+            postfix_member_offset = offset;
+            postfix_member_size = size;
+            postfix_member_is_floating = is_floating;
+            postfix_member_is_unsigned = is_unsigned;
+            postfix_member_calling_convention = last_found_member_calling_convention;
+            
+            if (pointer_depth > 0 || is_array) {
+                current_object_size = elem_size;
+            } else {
+                current_object_size = size;
+            }
+            
+            if (tok.kind == TOK_LBRACK) {
+            
+                enum token_kind assign_op;
+                int subscript_elem_size;
+                
+                if (!is_array && pointer_depth > 0) {
+                    emit_load_member_from_addr_reg_now (reg, reg, offset, DATA_PTR & 0x1f);
+                } else if (state->ofp && offset != 0) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+                    } else {
+                        fprintf (state->ofp, "    addq $%d, %%%s\n", offset, reg);
+                    }
+                
+                }
+                
+                subscript_elem_size = index_step_size (elem_size);
+                
+                if (subscript_elem_size <= 0) {
+                    subscript_elem_size = DATA_INT & 0x1f;
+                }
+                
+                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, subscript_elem_size);
+                
+                if (tok.kind == TOK_ARROW && subscript_elem_size <= (DATA_PTR & 0x1f)) {
+                
+                    emit_load_deref_reg_now (reg, DATA_PTR & 0x1f);
+                    
+                    postfix_member_pointer_depth = 0;
+                    postfix_member_size = DATA_PTR & 0x1f;
+                    
+                    continue;
+                
+                }
+                
+                if (is_assignment_operator (tok.kind)) {
+                
+                    assign_op = tok.kind;
+                    get_token ();
+                    
+                    if (assign_op == TOK_ASSIGN && subscript_elem_size > (DATA_LLONG & 0x1f)
+                        && tok.kind == TOK_IDENT && tok.ident
+                        && get_global_symbol_kind (tok.ident) == GLOBAL_SYMBOL_FUNCTION) {
+                    
+                        char *rhs_name = xstrdup (tok.ident);
+                        
+                        const char *rhs_start = tok.start;
+                        const char *rhs_caret = tok.caret;
+                        
+                        unsigned long rhs_line = get_line_number ();
+                        emit_push_reg_now (reg);
+                        
+                        pending_struct_return_lhs = 0;
+                        pending_struct_return_global_name = 0;
+                        pending_struct_return_stack_address = 1;
+                        pending_struct_return_stack_offset = 0;
+                        
+                        get_token ();
+                        emit_call_identifier_to_reg_now (rhs_name, reg, rhs_start, rhs_caret, rhs_line);
+                        
+                        pending_struct_return_stack_address = 0;
+                        pending_struct_return_stack_offset = 0;
+                        
+                        emit_pop_reg_now ("rdx");
+                        free (rhs_name);
+                        
+                        postfix_member_seen = 0;
+                        return;
+                    
+                    }
+                    
+                    emit_push_reg_now (reg);
+                    
+                    if (assign_op == TOK_ASSIGN) {
+                    
+                        if (subscript_elem_size > (DATA_LLONG & 0x1f)) {
+                        
+                            pending_struct_return_lhs = 0;
+                            pending_struct_return_global_name = 0;
+                            pending_struct_return_stack_address = 1;
+                            pending_struct_return_stack_offset = 0;
+                            
+                            emit_load_assignment_rhs_expression_to_reg (reg);
+                            
+                            pending_struct_return_stack_address = 0;
+                            pending_struct_return_stack_offset = 0;
+                            
+                            emit_pop_reg_now ("rdx");
+                            
+                            postfix_member_seen = 0;
+                            return;
+                        
+                        }
+                        
+                        emit_load_assignment_rhs_expression_to_reg (reg);
+                    
+                    } else {
+                    
+                        emit_load_deref_reg_now (reg, subscript_elem_size);
+                        emit_push_reg_now (reg);
+                        emit_load_assignment_rhs_expression_to_reg ("rdx");
+                        emit_pop_reg_now (reg);
+                        emit_assignment_binary_op (assign_op, 0);
+                    
+                    }
+                    
+                    emit_pop_reg_now ("rdx");
+                    emit_store_reg_to_deref_reg_now ("rdx", reg, subscript_elem_size);
+                    
+                    postfix_member_seen = 0;
+                    return;
+                
+                }
+                
+                if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+                
+                    current_object_size = elem_size;
+                    continue;
+                
+                }
+                
+                /**
+                 * The expression now denotes the subscripted element, not the
+                 * whole member array.  Keep the postfix-member metadata in
+                 * step with the value in REG so argument passing does not
+                 * mistake e.g. ic->heads[i] for the entire heads[] aggregate
+                 * and push multiple words.
+                 *
+                 * If the element itself is an aggregate, REG must remain the
+                 * address of that element.  Loading *(REG) would fetch the
+                 * first word of the struct and later aggregate argument
+                 * passing would treat that word as a pointer, as happened for
+                 * instruction.types[instruction.operands].
+                 */
+                postfix_member_size = subscript_elem_size;
+                
+                /*
+                 * Subscript of an array member whose element type is a pointer
+                 * yields the pointer stored in that array slot.  The generic
+                 * aggregate-subscript path deliberately keeps struct elements as
+                 * addresses, but pointer elements must still be loaded before a
+                 * following -> member access.  Otherwise expressions such as
+                 * instruction.regs[operand]->type.reg_rex treat the address of
+                 * the regs[] slot as if it were a struct reg_entry *.
+                 */
+                if (is_array && (pointer_depth > 0 || (tok.kind == TOK_ARROW && subscript_elem_size == (DATA_PTR & 0x1f)))) {
+                
+                    emit_load_deref_reg_now (reg, DATA_PTR & 0x1f);
+                    
+                    postfix_member_pointer_depth = pointer_depth > 0 ? pointer_depth - 1 : 0;
+                    postfix_member_size = DATA_PTR & 0x1f;
+                    
+                    if (postfix_member_pointer_depth == 0 && current_object_tag_name) {
+                    
+                        struct aggregate_tag_entry *entry = find_aggregate_tag (current_object_tag_name, 0);
+                        
+                        if (entry) {
+                            current_object_size = entry->size;
+                        }
+                    
+                    }
+                    
+                    continue;
+                
+                }
+                
+                if (postfix_member_pointer_depth > 0) {
+                    postfix_member_pointer_depth--;
+                }
+                
+                if (postfix_member_pointer_depth != 0
+                    || postfix_member_size <= (DATA_PTR & 0x1f)) {
+                    emit_load_deref_reg_now (reg, subscript_elem_size);
+                }
+                
+                continue;
+            
+            }
+            
+            if (is_array && tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
+            
+                if (state->ofp && offset != 0) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+                    } else {
+                        fprintf (state->ofp, "    addq $%d, %%%s\n", offset, reg);
+                    }
+                
+                }
+                
+                /*
+                 * A bare array member expression decays to a pointer when used
+                 * as an rvalue/function argument.  Keep REG as the element
+                 * address, but do not leave aggregate element metadata behind or
+                 * the call argument path will push the first element by value.
+                 * This broke calls such as _cpp_add_unknown2_direct(...,
+                 * macro->tokens, token_count), where tokens[0] is a struct.
+                 */
+                postfix_member_size = DATA_PTR & 0x1f;
+                postfix_member_pointer_depth = 1;
+                postfix_member_pointed_size = elem_size;
+                
+                continue;
+            
+            }
+            
+            if ((tok.kind == TOK_ARROW || tok.kind == TOK_DOT) && pointer_depth == 0) {
+            
+                if (state->ofp && offset != 0) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+                    } else {
+                        fprintf (state->ofp, "    addq $%d, %%%s\n", offset, reg);
+                    }
+                
+                }
+                
+                continue;
+            
+            }
+            
+            if (size > (DATA_PTR & 0x1f) && tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
+            
+                if (state->ofp && offset != 0) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+                    } else {
+                        fprintf (state->ofp, "    addq $%d, %%%s\n", offset, reg);
+                    }
+                
+                }
+                
+                continue;
+            
+            }
+            
+            if (state->ofp) {
+            
+                if (strcmp (reg, "rdx") != 0) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    mov rdx, %s\n", reg);
+                    } else {
+                        fprintf (state->ofp, "    movq %%%s, %%rdx\n", reg);
+                    }
+                
+                }
+                
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    const char *dreg = amd64_dword_reg_name_from_any (reg);
+                    int qword = (size == (DATA_PTR & 0x1f) || size == (DATA_LLONG & 0x1f));
+                    
+                    if (state->syntax & ASM_SYNTAX_NASM) {
+                    
+                        if (size == 1) {
+                            fprintf (state->ofp, "    movzx %s, byte [%s + %d]\n", dreg, reg, offset);
+                        } else if (size == 2) {
+                            fprintf (state->ofp, "    movzx %s, word [%s + %d]\n", dreg, reg, offset);
+                        } else {
+                        
+                            if (qword) {
+                                fprintf (state->ofp, "    mov %s, qword [%s + %d]\n", reg, reg, offset);
+                            } else {
+                                fprintf (state->ofp, "    movsxd %s, dword [%s + %d]\n", reg, reg, offset);
+                            }
+                        
+                        }
+                    
+                    } else {
+                    
+                        if (size == 1) {
+                            fprintf (state->ofp, "    movzx %s, byte ptr [%s + %d]\n", dreg, reg, offset);
+                        } else if (size == 2) {
+                            fprintf (state->ofp, "    movzx %s, word ptr [%s + %d]\n", dreg, reg, offset);
+                        } else {
+                        
+                            if (qword) {
+                                fprintf (state->ofp, "    mov %s, qword ptr [%s + %d]\n", reg, reg, offset);
+                            } else {
+                                fprintf (state->ofp, "    movsxd %s, dword ptr [%s + %d]\n", reg, reg, offset);
+                            }
+                        
+                        }
+                    
+                    }
+                
+                } else {
+                
+                    if (size == 1) {
+                        fprintf (state->ofp, "    movzbl %d(%%%s), %%%s\n", offset, reg, amd64_dword_reg_name_from_any (reg));
+                    } else if (size == 2) {
+                        fprintf (state->ofp, "    movzwl %d(%%%s), %%%s\n", offset, reg, amd64_dword_reg_name_from_any (reg));
+                    } else if (size == (DATA_PTR & 0x1f) || size == (DATA_LLONG & 0x1f)) {
+                        fprintf (state->ofp, "    movq %d(%%%s), %%%s\n", offset, reg, reg);
+                    } else {
+                        fprintf (state->ofp, "    movslq %d(%%%s), %%%s\n", offset, reg, reg);
+                    }
+                
+                }
+            
+            }
+        
+        }
+    
+    }
+
+}
+
+static void emit_apply_postfix_member_incdec_now (const char *reg, enum token_kind op) {
+
+    if (!postfix_member_seen) {
+        return;
+    }
+    
+    if (state->ofp) {
+    
+        const char *insn = op == TOK_INCR ? "inc" : "dec";
+        (void) reg;
+        
+        if (postfix_member_pointer_depth > 0) {
+        
+            int step = postfix_member_pointed_size;
+            const char *arith = op == TOK_INCR ? "add" : "sub";
+            
+            if (step <= 0) {
+                step = 1;
+            }
+            
+            if (step == 1) {
+                /* Falling through keeps the compact inc/dec form for char *. */
+            } else if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                if (state->syntax & ASM_SYNTAX_NASM) {
+                    fprintf (state->ofp, "    %s qword [rdx + %d], %d\n", arith, postfix_member_offset, step);
+                } else {
+                    fprintf (state->ofp, "    %s qword ptr [rdx + %d], %d\n", arith, postfix_member_offset, step);
+                }
+                
+                return;
+            
+            } else {
+            
+                fprintf (state->ofp, "    %sq $%d, %d(%%rdx)\n", arith, step, postfix_member_offset);
+                return;
+            }
+        
+        }
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            const char *opsize = "dword";
+            int qword = (postfix_member_size == (DATA_LLONG & 0x1f) || postfix_member_size == (DATA_PTR & 0x1f));
+            
+            if (postfix_member_size == 1) {
+                opsize = "byte";
+            } else if (postfix_member_size == 2) {
+                opsize = "word";
+            } else if (qword) {
+                opsize = "qword";
+            }
+            
+            if (state->syntax & ASM_SYNTAX_NASM) {
+                fprintf (state->ofp, "    %s %s [rdx + %d]\n", insn, opsize, postfix_member_offset);
+            } else {
+                fprintf (state->ofp, "    %s %s ptr [rdx + %d]\n", insn, opsize, postfix_member_offset);
+            }
+        
+        } else {
+        
+            if (postfix_member_size == 1) {
+                fprintf (state->ofp, "    %sb %d(%%rdx)\n", insn, postfix_member_offset);
+            } else if (postfix_member_size == 2) {
+                fprintf (state->ofp, "    %sw %d(%%rdx)\n", insn, postfix_member_offset);
+            } else if (postfix_member_size == (DATA_LLONG & 0x1f) || postfix_member_size == (DATA_PTR & 0x1f)) {
+                fprintf (state->ofp, "    %sq %d(%%rdx)\n", insn, postfix_member_offset);
+            } else {
+                fprintf (state->ofp, "    %sl %d(%%rdx)\n", insn, postfix_member_offset);
+            }
+        
+        }
+    
+    }
+
+}
+
+static int rhs_text_is_plain_aggregate_lvalue_now (const char *p) {
+
+    int paren_depth = 0;
+    int bracket_depth = 0;
+    int saw_ident = 0;
+    
+    if (!p) {
+        return 1;
+    }
+    
+    while (*p) {
+    
+        unsigned char ch = (unsigned char) *p;
+        
+        if (ch == '\'' || ch == '"') {
+        
+            int quote = ch;
+            p++;
+            
+            while (*p && *p != quote) {
+            
+                if (*p == '\\' && p[1]) {
+                    p += 2;
+                } else {
+                    p++;
+                }
+            
+            }
+            
+            if (*p == quote) {
+                p++;
+            }
+            
+            continue;
+        
+        }
+        
+        if (ch == '(') {
+        
+            paren_depth++;
+            p++;
+            
+            continue;
+        
+        }
+        
+        if (ch == ')') {
+        
+            if (paren_depth == 0 && bracket_depth == 0) {
+                break;
+            }
+            
+            if (paren_depth > 0) {
+                paren_depth--;
+            }
+            
+            p++;
+            continue;
+        
+        }
+        
+        if (ch == '[') {
+        
+            bracket_depth++;
+            p++;
+            
+            continue;
+        
+        }
+        
+        if (ch == ']') {
+        
+            if (bracket_depth > 0) {
+                bracket_depth--;
+            }
+            
+            p++;
+            continue;
+        
+        }
+        
+        if (paren_depth == 0 && bracket_depth == 0) {
+        
+            if (ch == ';' || ch == ',') {
+                break;
+            }
+            
+            if (ch == '-' && p[1] == '>') {
+            
+                p += 2;
+                continue;
+            
+            }
+            
+            if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%' ||
+                ch == '&' || ch == '|' || ch == '^' || ch == '?' || ch == ':') {
+                return 0;
+            }
+        
+        }
+        
+        if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '_') {
+            saw_ident = 1;
+        }
+        
+        p++;
+    
+    }
+
+    return saw_ident;
+
+}
+
+static int emit_aggregate_copy_from_current_rhs_to_addr_reg_now (const char *addr_reg, int offset, int size);
+static int emit_parse_postfix_copy_source_address_now (const char *reg, struct local_symbol *src, const char *src_name, const char *name_start, const char *name_caret, unsigned long name_line);
+
+static int emit_store_assignment_to_aggregate_address_now (const char *addr_reg, int size, const char *name_start, const char *name_caret, unsigned long name_line) {
+
+    enum token_kind op;
+    
+    if (!is_assignment_operator (tok.kind) || size <= (DATA_LLONG & 0x1f)) {
+        return 0;
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    if (op == TOK_ASSIGN && tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now ()) {
+    
+        char *rhs_name = xstrdup (tok.ident);
+        
+        const char *rhs_start = tok.start ? tok.start : name_start;
+        const char *rhs_caret = tok.caret ? tok.caret : name_caret;
+        
+        unsigned long rhs_line = get_line_number ();
+        emit_push_reg_now (addr_reg);
+        
+        pending_struct_return_lhs = 0;
+        pending_struct_return_global_name = 0;
+        pending_struct_return_stack_address = 1;
+        pending_struct_return_stack_offset = 0;
+        
+        get_token ();
+        emit_call_identifier_to_reg_now (rhs_name, "rax", rhs_start, rhs_caret, rhs_line);
+        
+        pending_struct_return_stack_address = 0;
+        pending_struct_return_stack_offset = 0;
+        
+        emit_pop_reg_now ("rdx");
+        free (rhs_name);
+        
+        return 1;
+    
+    }
+    
+    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "aggregate assignment expression not implemented");
+    
+    skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+    return 1;
+
+}
+
+static int rhs_current_operand_is_floating_now (void);
+
+static int emit_store_assignment_to_postfix_member_now (const char *reg) {
+
+    enum token_kind op;
+    int assign_member_offset;
+    int assign_member_size;
+    
+    if (!postfix_member_seen || !is_assignment_operator (tok.kind)) {
+        return 0;
+    }
+    
+    op = tok.kind;
+    assign_member_offset = postfix_member_offset;
+    assign_member_size = postfix_member_size;
+    
+    get_token ();
+    
+    if (state->ofp) {
+    
+        if (op == TOK_ASSIGN) {
+        
+            if (postfix_member_is_floating || token_is_floating_constant_now () || rhs_current_operand_is_floating_now ()) {
+            
+                emit_push_reg_now ("rdx");
+                emit_load_floating_rhs_expression_now (assign_member_size);
+                
+                emit_pop_reg_now ("rdx");
+                emit_store_floating_member_to_addr_reg_now ("rdx", assign_member_offset, assign_member_size);
+                
+                return 1;
+            
+            }
+            
+            if (assign_member_size > (DATA_LLONG & 0x1f) &&
+                tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now ()) {
+            
+                char *rhs_name = xstrdup (tok.ident);
+                
+                const char *rhs_start = tok.start;
+                const char *rhs_caret = tok.caret;
+                
+                unsigned long rhs_line = get_line_number ();
+                emit_push_reg_now ("rdx");
+                
+                pending_struct_return_lhs = 0;
+                pending_struct_return_global_name = 0;
+                pending_struct_return_stack_address = 1;
+                pending_struct_return_stack_offset = assign_member_offset;
+                
+                get_token ();
+                emit_call_identifier_to_reg_now (rhs_name, reg, rhs_start, rhs_caret, rhs_line);
+                
+                pending_struct_return_stack_address = 0;
+                pending_struct_return_stack_offset = 0;
+                
+                emit_pop_reg_now ("rdx");
+                free (rhs_name);
+                
+                return 1;
+            
+            }
+            
+            if (emit_aggregate_copy_from_current_rhs_to_addr_reg_now ("rdx", assign_member_offset, assign_member_size)) {
+                return 1;
+            }
+            
+            emit_push_reg_now ("rdx");
+            
+            emit_load_assignment_rhs_expression_to_reg (reg);
+            emit_pop_reg_now ("rdx");
+        
+        } else {
+        
+            emit_push_reg_now ("rdx");
+            emit_push_reg_now (reg);
+            
+            emit_load_assignment_rhs_expression_to_reg ("rdx");
+            emit_pop_reg_now (reg);
+            
+            emit_assignment_binary_op (op, 0);
+            emit_pop_reg_now ("rdx");
+        
+        }
+        
+        emit_store_member_to_addr_reg_now ("rdx", assign_member_offset, reg, assign_member_size);
+    
+    } else {
+        emit_load_assignment_rhs_expression_to_reg (reg);
+    }
+    
+    return 1;
+
+}
+
+static int parenthesized_function_designator_call_now (void) {
+
+    const char *p;
+    
+    if (tok.kind != TOK_IDENT || !tok.caret || !tok.ident) {
+        return 0;
+    }
+    
+    p = tok.caret + strlen (tok.ident);
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (*p != ')') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    return *p == '(';
+
+}
+
+static void emit_load_deref_reg_ex_now (const char *reg, int size, int is_unsigned) {
+
+    const char *op8;
+    const char *op16;
+    const char *qreg;
+    const char *dreg;
+    const char *att_dst_reg;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    op8 = is_unsigned ? "movzx" : "movsx";
+    op16 = is_unsigned ? "movzx" : "movsx";
+    
+    qreg = amd64_qword_reg_name_from_any (reg);
+    dreg = amd64_dword_reg_name_from_any (reg);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+        
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    %s %s, byte [%s]\n", op8, is_unsigned ? dreg : qreg, qreg);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    %s %s, word [%s]\n", op16, is_unsigned ? dreg : qreg, qreg);
+            } else if (amd64_scalar_size_is_qword (size)) {
+                fprintf (state->ofp, "    mov %s, qword [%s]\n", qreg, qreg);
+            } else if (is_unsigned) {
+                fprintf (state->ofp, "    mov %s, dword [%s]\n", dreg, qreg);
+            } else {
+                fprintf (state->ofp, "    movsxd %s, dword [%s]\n", qreg, qreg);
+            }
+        
+        } else {
+        
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    %s %s, byte ptr [%s]\n", op8, is_unsigned ? dreg : qreg, qreg);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    %s %s, word ptr [%s]\n", op16, is_unsigned ? dreg : qreg, qreg);
+            } else if (amd64_scalar_size_is_qword (size)) {
+                fprintf (state->ofp, "    mov %s, qword ptr [%s]\n", qreg, qreg);
+            } else if (is_unsigned) {
+                fprintf (state->ofp, "    mov %s, dword ptr [%s]\n", dreg, qreg);
+            } else {
+                fprintf (state->ofp, "    movsxd %s, dword ptr [%s]\n", qreg, qreg);
+            }
+        
+        }
+    
+    } else {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+        
+            att_dst_reg = is_unsigned ? dreg : qreg;
+            fprintf (state->ofp, "    %s (%%%s), %%%s\n", is_unsigned ? "movzbl" : "movsbq", qreg, att_dst_reg);
+        
+        } else if (size == (DATA_SHORT & 0x1f)) {
+        
+            att_dst_reg = is_unsigned ? dreg : qreg;
+            fprintf (state->ofp, "    %s (%%%s), %%%s\n", is_unsigned ? "movzwl" : "movswq", qreg, att_dst_reg);
+        
+        } else if (amd64_scalar_size_is_qword (size)) {
+            fprintf (state->ofp, "    movq (%%%s), %%%s\n", qreg, qreg);
+        } else if (is_unsigned) {
+            fprintf (state->ofp, "    movl (%%%s), %%%s\n", qreg, dreg);
+        } else {
+            fprintf (state->ofp, "    movslq (%%%s), %%%s\n", qreg, qreg);
+        }
+    
+    }
+
+}
+
+static void emit_load_deref_reg_now (const char *reg, int size) {
+    emit_load_deref_reg_ex_now (reg, size, 0);
+}
+
+static void emit_store_reg_to_deref_reg_now (const char *addr_reg, const char *value_reg, int size) {
+
+    const char *breg;
+    const char *wreg;
+    const char *dreg;
+    const char *qreg;
+    
+    if (suppress_next_struct_return_scalar_store) {
+    
+        suppress_next_struct_return_scalar_store = 0;
+        return;
+    
+    }
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    breg = amd64_byte_reg_name_from_any (value_reg);
+    wreg = amd64_word_reg_name_from_any (value_reg);
+    dreg = amd64_dword_reg_name_from_any (value_reg);
+    qreg = amd64_qword_reg_name_from_any (value_reg);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+        
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    mov byte [%s], %s\n", addr_reg, breg);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    mov word [%s], %s\n", addr_reg, wreg);
+            } else if (amd64_scalar_size_is_qword (size)) {
+                fprintf (state->ofp, "    mov qword [%s], %s\n", addr_reg, qreg);
+            } else {
+                fprintf (state->ofp, "    mov dword [%s], %s\n", addr_reg, dreg);
+            }
+        
+        } else {
+        
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    mov byte ptr [%s], %s\n", addr_reg, breg);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    mov word ptr [%s], %s\n", addr_reg, wreg);
+            } else if (amd64_scalar_size_is_qword (size)) {
+                fprintf (state->ofp, "    mov qword ptr [%s], %s\n", addr_reg, qreg);
+            } else {
+                fprintf (state->ofp, "    mov dword ptr [%s], %s\n", addr_reg, dreg);
+            }
+        
+        }
+    
+    } else {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, "    movb %%%s, (%%%s)\n", breg, addr_reg);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, "    movw %%%s, (%%%s)\n", wreg, addr_reg);
+        } else if (amd64_scalar_size_is_qword (size)) {
+            fprintf (state->ofp, "    movq %%%s, (%%%s)\n", qreg, addr_reg);
+        } else {
+            fprintf (state->ofp, "    movl %%%s, (%%%s)\n", dreg, addr_reg);
+        }
+    
+    }
+
+}
+
+static int emit_handle_subscript_after_loaded_pointer_to_reg_now (const char *reg, int pointer_depth, int pointed_size, int pointed_is_unsigned) {
+
+    int subscript_elem_size;
+    
+    if (tok.kind != TOK_LBRACK) {
+        return 0;
+    }
+    
+    subscript_elem_size = pointer_depth > 1 ? (DATA_PTR & 0x1f) : pointed_size;
+    
+    if (subscript_elem_size <= 0) {
+        subscript_elem_size = DATA_INT & 0x1f;
+    }
+    
+    emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, subscript_elem_size);
+    
+    if (is_assignment_operator (tok.kind)) {
+    
+        enum token_kind assign_op = tok.kind;
+        
+        get_token ();
+        emit_push_reg_now (reg);
+        
+        if (assign_op == TOK_ASSIGN) {
+            emit_load_assignment_rhs_expression_to_reg (reg);
+        } else {
+        
+            emit_load_deref_reg_now (reg, subscript_elem_size);
+            emit_push_reg_now (reg);
+            
+            emit_load_assignment_rhs_expression_to_reg ("rdx");
+            emit_pop_reg_now (reg);
+            
+            emit_assignment_binary_op (assign_op, 0);
+        
+        }
+        
+        emit_pop_reg_now ("rdx");
+        
+        emit_store_reg_to_deref_reg_now ("rdx", reg, subscript_elem_size);
+        clear_rhs_last_pointer_info ();
+        
+        return 1;
+    
+    }
+    
+    emit_load_deref_reg_ex_now (reg, subscript_elem_size, pointer_depth <= 1 ? pointed_is_unsigned : 0);
+    
+    if (pointer_depth > 1) {
+        set_rhs_last_pointer_info (pointer_depth - 1, pointed_size);
+    } else {
+        clear_rhs_last_pointer_info ();
+    }
+    
+    return 1;
+
+}
+
+static void emit_load_member_from_addr_reg_now (const char *dst_reg, const char *addr_reg, int offset, int size) {
+
+    const char *qreg;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    qreg = amd64_qword_reg_name_from_any (dst_reg);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+        
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    movsx %s, byte [%s + %d]\n", qreg, addr_reg, offset);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    movsx %s, word [%s + %d]\n", qreg, addr_reg, offset);
+            } else if (amd64_scalar_size_is_qword (size)) {
+                fprintf (state->ofp, "    mov %s, qword [%s + %d]\n", qreg, addr_reg, offset);
+            } else {
+                fprintf (state->ofp, "    movsxd %s, dword [%s + %d]\n", qreg, addr_reg, offset);
+            }
+        
+        } else {
+        
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    movsx %s, byte ptr [%s + %d]\n", qreg, addr_reg, offset);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    movsx %s, word ptr [%s + %d]\n", qreg, addr_reg, offset);
+            } else if (amd64_scalar_size_is_qword (size)) {
+                fprintf (state->ofp, "    mov %s, qword ptr [%s + %d]\n", qreg, addr_reg, offset);
+            } else {
+                fprintf (state->ofp, "    movsxd %s, dword ptr [%s + %d]\n", qreg, addr_reg, offset);
+            }
+        
+        }
+    
+    } else {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, "    movsbq %d(%%%s), %%%s\n", offset, addr_reg, qreg);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, "    movswq %d(%%%s), %%%s\n", offset, addr_reg, qreg);
+        } else if (amd64_scalar_size_is_qword (size)) {
+            fprintf (state->ofp, "    movq %d(%%%s), %%%s\n", offset, addr_reg, qreg);
+        } else {
+            fprintf (state->ofp, "    movslq %d(%%%s), %%%s\n", offset, addr_reg, qreg);
+        }
+    
+    }
+
+}
+
+static int emit_load_address_of_parenthesized_postfix_to_reg_now (const char *reg) {
+
+    char *name;
+    
+    enum token_kind member_op;
+    struct local_symbol *src;
+    
+    int global_index;
+    
+    const char *current_object_tag_name = 0;
+    int current_object_size = 0;
+    
+    if (tok.kind != TOK_LPAREN) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    if (tok.kind == TOK_LPAREN) {
+    
+        int64_s offset_value;
+        
+        if (parse_constexpr_null_member_address_after_lparen (&offset_value)) {
+        
+            emit_load_const32_to_reg_now (reg, offset_value);
+            return 1;
+        
+        }
+    
+    }
+    
+    if (tok.kind != TOK_IDENT) {
+    
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after '&('");
+        
+        expect (TOK_RPAREN, ")");
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    get_token ();
+    
+    src = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (src) {
+    
+        if (src->is_array) {
+        
+            current_object_size = src->pointed_size > 0 ? src->pointed_size : src->size;
+            current_object_tag_name = src->pointed_tag_name;
+            
+            if (src->is_static && src->static_label) {
+                emit_load_symbol_address_to_reg_now (reg, src->static_label, 0, 0);
+            } else {
+                emit_load_symbol_address_to_reg_now (reg, 0, src->offset, 1);
+            }
+        
+        } else if (src->pointer_depth > 0) {
+        
+            current_object_size = src->pointed_size > 0 ? src->pointed_size : DATA_PTR;
+            current_object_tag_name = src->pointed_tag_name;
+            
+            if (src->is_static && src->static_label) {
+                emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
+            
+            } else {
+                emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+            }
+        
+        } else if (src->is_static && src->static_label) {
+        
+            current_object_size = src->size;
+            emit_load_address_to_reg_now (reg, src->static_label);
+        
+        } else {
+        
+            current_object_size = src->size;
+            
+            /**
+             * A typedef such as section_t can hide the pointer depth from this
+             * older parser.  For &(p->member), the base must be the pointer
+             * value stored in the local, not the address of the local slot.
+             *
+             * Keep the pointed aggregate tag as well.  Without that, address-of
+             * member expressions such as &symbol->next can fall back to an
+             * unqualified member-name lookup and pick another struct's "next"
+             * field.  That emitted symbol + 24 instead of symbol + 36 for
+             * struct symbol::next, corrupting symbol->section in pdas.
+             */
+            if (tok.kind == TOK_ARROW && src->size == (DATA_PTR & 0x1f)) {
+            
+                if (src->pointed_tag_name) {
+                
+                    struct aggregate_tag_entry *entry = find_aggregate_tag (src->pointed_tag_name, 0);
+                    current_object_tag_name = src->pointed_tag_name;
+                    
+                    if (entry) {
+                        current_object_size = entry->size;
+                    }
+                
+                }
+                
+                emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+            
+            } else {
+                emit_load_local_address_to_reg_now (reg, src->offset);
+            }
+        
+        }
+    
+    } else if (global_index >= 0) {
+    
+        if (get_global_symbol_array (name)) {
+        
+            current_object_size = get_global_symbol_pointed_size (name);
+            emit_load_symbol_address_to_reg_now (reg, name, 0, 0);
+        
+        } else if (get_global_symbol_pointer_depth (name) > 0 || (tok.kind == TOK_ARROW && get_global_symbol_size (name) == (DATA_PTR & 0x1f))) {
+        
+            current_object_size = get_global_symbol_pointed_size (name);
+            
+            if (current_object_size <= 0) {
+                current_object_size = DATA_PTR & 0x1f;
+            }
+            
+            emit_load_global_to_reg (reg, name, DATA_PTR);
+        
+        } else {
+        
+            current_object_size = get_global_symbol_size (name);
+            emit_load_address_to_reg_now (reg, name);
+        
+        }
+    
+    } else {
+    
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "unknown symbol '%s'", name);
+        free (name);
+        
+        expect (TOK_RPAREN, ")");
+        return 1;
+    
+    }
+    
+    if (tok.kind == TOK_LBRACK) {
+    
+        int elem_size = DATA_INT & 0x1f;
+        
+        if (src) {
+        
+            elem_size = src->is_array ? (src->pointer_depth ? DATA_PTR : (src->array_element_size > 0 ? src->array_element_size : src->pointed_size)) :
+                (src->pointer_depth > 1 ? DATA_PTR : src->pointed_size);
+        
+        } else if (global_index >= 0) {
+        
+            elem_size = get_global_symbol_array (name) ?
+                (get_global_symbol_pointer_depth (name) ? DATA_PTR : (get_global_symbol_array_element_size (name) > 0 ? get_global_symbol_array_element_size (name) : get_global_symbol_pointed_size (name))) :
+                    (get_global_symbol_pointer_depth (name) > 1 ? DATA_PTR : get_global_symbol_pointed_size (name));
+        
+        }
+        
+        if (elem_size <= 0) {
+            elem_size = DATA_INT & 0x1f;
+        }
+        
+        emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
+    
+    }
+    
+    free (name);
+    
+    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+    
+        char *member;
+        
+        const char *member_start;
+        const char *member_caret;
+        
+        unsigned long member_line;
+        
+        int offset;
+        int size;
+        int elem_size;
+        int pointer_depth;
+        
+        member_op = tok.kind;
+        get_token ();
+        
+        member_start = tok.start;
+        member_caret = tok.caret;
+        member_line = get_line_number ();
+        
+        if (tok.kind != TOK_IDENT) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+            
+            expect (TOK_RPAREN, ")");
+            return 1;
+        
+        }
+        
+        member = xstrdup (tok.ident);
+        get_token ();
+        
+        offset = 0;
+        size = DATA_INT & 0x1f;
+        elem_size = DATA_INT & 0x1f;
+        pointer_depth = 0;
+        
+        if (!find_member_info_ex_bounded (member, current_object_size, current_object_tag_name, &offset, &size, &elem_size, &pointer_depth, 0, 0)) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+            
+            free (member);
+            expect (TOK_RPAREN, ")");
+            
+            return 1;
+        
+        }
+        
+        current_object_tag_name = last_found_member_tag_name;
+        free (member);
+        
+        if (tok.kind == TOK_LBRACK) {
+        
+            if (pointer_depth > 0) {
+            
+                emit_load_member_from_addr_reg_now (reg, reg, offset, DATA_PTR & 0x1f);
+                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
+            
+            } else {
+            
+                if (state->ofp && offset != 0) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+                    } else {
+                        fprintf (state->ofp, "    addq $%d, %%%s\n", offset, reg);
+                    }
+                
+                }
+                
+                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
+            
+            }
+        
+        } else {
+        
+            if (state->ofp && offset != 0) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+                } else {
+                    fprintf (state->ofp, "    addq $%d, %%%s\n", offset, reg);
+                }
+            
+            }
+        
+        }
+        
+        if (pointer_depth > 0) {
+            current_object_size = elem_size > 0 ? elem_size : DATA_PTR;
+        } else {
+            current_object_size = size;
+        }
+    
+    }
+    
+    expect (TOK_RPAREN, ")");
+    return 1;
+
+}
+
+static void emit_store_member_to_addr_reg_now (const char *addr_reg, int offset, const char *value_reg, int size) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (offset != 0) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    add %s, %d\n", addr_reg, offset);
+        } else {
+            fprintf (state->ofp, "    addq $%d, %%%s\n", offset, addr_reg);
+        }
+    
+    }
+    
+    emit_store_reg_to_deref_reg_now (addr_reg, value_reg, size);
+
+}
+
+static void emit_store_floating_member_to_addr_reg_now (const char *addr_reg, int offset, int size) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (offset != 0) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    add %s, %d\n", addr_reg, offset);
+        } else {
+            fprintf (state->ofp, "    addq $%d, %%%s\n", offset, addr_reg);
+        }
+    
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fstp %s [%s]\n" : "    fstp %s ptr [%s]\n", size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", addr_reg);
+    } else {
+        fprintf (state->ofp, "    fstp%s (%%%s)\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", addr_reg);
+    }
+
+}
+
+static void emit_load_symbol_address_for_copy_now (const char *reg, struct local_symbol *sym, const char *name) {
+
+    if (sym) {
+    
+        if (sym->is_static && sym->static_label) {
+            emit_load_address_to_reg_now (reg, sym->static_label);
+        } else {
+            emit_load_local_address_to_reg_now (reg, sym->offset);
+        }
+    
+    } else {
+        emit_load_address_to_reg_now (reg, name);
+    }
+
+}
+
+static void emit_copy_fixed_size_now (int size) {
+
+    int offset = 0;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    while (size - offset >= 4) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov ecx, dword [rax + %d]\n" : "    mov ecx, dword ptr [rax + %d]\n", offset);
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov dword [rdx + %d], ecx\n" : "    mov dword ptr [rdx + %d], ecx\n", offset);
+        
+        } else {
+        
+            fprintf (state->ofp, "    movl %d(%%rax), %%ecx\n", offset);
+            fprintf (state->ofp, "    movl %%ecx, %d(%%rdx)\n", offset);
+        
+        }
+        
+        offset += 4;
+    
+    }
+    
+    while (size - offset >= 2) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov cx, word [rax + %d]\n" : "    mov cx, word ptr [rax + %d]\n", offset);
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov word [rdx + %d], cx\n" : "    mov word ptr [rdx + %d], cx\n", offset);
+        
+        } else {
+        
+            fprintf (state->ofp, "    movw %d(%%rax), %%cx\n", offset);
+            fprintf (state->ofp, "    movw %%cx, %d(%%rdx)\n", offset);
+        
+        }
+        
+        offset += 2;
+    
+    }
+    
+    while (size - offset >= 1) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov cl, byte [rax + %d]\n" : "    mov cl, byte ptr [rax + %d]\n", offset);
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov byte [rdx + %d], cl\n" : "    mov byte ptr [rdx + %d], cl\n", offset);
+        
+        } else {
+        
+            fprintf (state->ofp, "    movb %d(%%rax), %%cl\n", offset);
+            fprintf (state->ofp, "    movb %%cl, %d(%%rdx)\n", offset);
+        
+        }
+        
+        offset++;
+    
+    }
+
+}
+
+static void emit_memcpy_symbol_to_symbol_now (struct local_symbol *dst, const char *dst_name, struct local_symbol *src, const char *src_name, int size) {
+
+    emit_load_symbol_address_for_copy_now ("rax", src, src_name);
+    emit_load_symbol_address_for_copy_now ("rdx", dst, dst_name);
+    emit_copy_fixed_size_now (size);
+
+}
+
+static int token_identifier_is_function_call_rhs_now (void) {
+
+    struct token *saved_tok;
+    int is_call;
+    
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+        return 0;
+    }
+    
+    /**
+     * Do not inspect tok.start/tok.caret to decide whether this identifier is
+     * followed by a call.  After macro substitution the spelling in the source
+     * can be a different length from tok.ident, e.g.
+     *
+     *     #define cc_parse_type ccpartype
+     *     member.type = cc_parse_type(reader);
+     *
+     * tok.ident is "ccpartype" but tok.caret still points into the original
+     * text "cc_parse_type(reader)".  The old spelling-based test missed the
+     * '(' and the aggregate-copy fast path treated the function symbol as an
+     * object, leaving the argument list unconsumed and producing "expected ;".
+     */
+    saved_tok = xmalloc (sizeof (*saved_tok));
+    *saved_tok = tok;
+    
+    if (tok.ident) {
+        saved_tok->ident = xstrdup (tok.ident);
+    }
+    
+    if (tok.start) {
+    
+        const char *old_start = tok.start;
+        const char *old_caret = tok.caret;
+        
+        saved_tok->start = xstrdup (old_start);
+        
+        if (old_caret && old_caret >= old_start) {
+            saved_tok->caret = saved_tok->start + (old_caret - old_start);
+        } else {
+            saved_tok->caret = saved_tok->start;
+        }
+    
+    }
+    
+    get_token ();
+    
+    is_call = (tok.kind == TOK_LPAREN);
+    unget_token (saved_tok);
+    
+    return is_call;
+
+}
+
+static struct token *clone_current_token_now (void) {
+
+    struct token *saved_tok = xmalloc (sizeof (*saved_tok));
+    *saved_tok = tok;
+    
+    if (tok.ident) {
+        saved_tok->ident = xstrdup (tok.ident);
+    }
+    
+    if (tok.start) {
+    
+        const char *old_start = tok.start;
+        const char *old_caret = tok.caret;
+        
+        saved_tok->start = xstrdup (old_start);
+        
+        if (old_caret && old_caret >= old_start) {
+            saved_tok->caret = saved_tok->start + (old_caret - old_start);
+        } else {
+            saved_tok->caret = saved_tok->start;
+        }
+    
+    }
+    
+    return saved_tok;
+
+}
+
+static int emit_aggregate_copy_from_current_rhs_to_addr_reg_now (const char *addr_reg, int offset, int size) {
+
+    struct local_symbol *rhs_sym;
+    char *rhs_name;
+    
+    const char *rhs_start;
+    const char *rhs_caret;
+    
+    unsigned long rhs_line;
+    
+    int rhs_global_index;
+    int rhs_size;
+    
+    int source_size;
+    int source_ready;
+    
+    /*
+     * Only use the aggregate-copy fast path when the destination is
+     * itself an aggregate object.  Pointer members can legally be assigned
+     * an array object, e.g. fp->intBuffer = buffer1; in pdpclib.  The RHS
+     * symbol then has a large array size, but the LHS is only a pointer, so
+     * emitting a fixed-size aggregate copy corrupts the FILE object.
+     */
+    if (size < (DATA_LLONG & 0x1f)) {
+        return 0;
+    }
+    
+    if (tok.kind == TOK_STAR) {
+    
+        struct token *saved_tok = clone_current_token_now ();
+        struct local_symbol *ptr_sym;
+        
+        char *ptr_name;
+        
+        int ptr_global_index;
+        int ptr_depth;
+        int ptr_pointed_size;
+        
+        get_token ();
+        
+        if (tok.kind != TOK_IDENT || !tok.ident) {
+        
+            unget_token (saved_tok);
+            return 0;
+        
+        }
+        
+        ptr_name = xstrdup (tok.ident);
+        ptr_sym = find_local_symbol (ptr_name);
+        ptr_global_index = find_global_symbol (ptr_name);
+        
+        if (!ptr_sym && ptr_global_index < 0) {
+        
+            free (ptr_name);
+            
+            unget_token (saved_tok);
+            return 0;
+        
+        }
+        
+        ptr_depth = ptr_sym ? ptr_sym->pointer_depth : get_global_symbol_pointer_depth (ptr_name);
+        ptr_pointed_size = ptr_sym ? ptr_sym->pointed_size : get_global_symbol_pointed_size (ptr_name);
+        
+        if (!ptr_sym && ptr_global_index >= 0
+            && get_global_symbol_kind (ptr_name) == GLOBAL_SYMBOL_FUNCTION) {
+        
+            const char *call_start = tok.start;
+            const char *call_caret = tok.caret;
+            unsigned long call_line = get_line_number ();
+            
+            get_token ();
+            
+            if (tok.kind != TOK_LPAREN || ptr_depth <= 0
+                || (ptr_depth == 1 && ptr_pointed_size > 0 && ptr_pointed_size < size)) {
+            
+                free (ptr_name);
+                
+                unget_token (saved_tok);
+                return 0;
+            
+            }
+            
+            emit_push_reg_now (addr_reg);
+            emit_call_identifier_to_reg_now (ptr_name, "rax", call_start, call_caret, call_line);
+            emit_pop_reg_now ("rdx");
+            
+            if (offset != 0 && state->ofp) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    add rdx, %d\n", offset);
+                } else {
+                    fprintf (state->ofp, "    addq $%d, %%rdx\n", offset);
+                }
+            
+            }
+            
+            emit_copy_fixed_size_now (size);
+            
+            free (ptr_name);
+            return 1;
+        
+        }
+        
+        /*
+         * For aggregate initialization from a dereferenced pointer, keep the
+         * full pointed-to object size.  The old code masked pointed_size with
+         * 0x1f as if it were a DATA_* scalar type.  That turns e.g.
+         *
+         *     struct hashtab old_hashtab = *hashtab;
+         *
+         * from a 44-byte copy into a rejected aggregate fast path because
+         * 44 & 0x1f == 12.  The initializer then falls back to scalar code
+         * and copies only the first word, leaving old_hashtab mostly
+         * uninitialized and crashing in rehash().
+         */
+        source_size = ptr_depth > 1 ? (DATA_PTR & 0x1f) : ptr_pointed_size;
+        
+        if (ptr_depth <= 0 || source_size < size) {
+        
+            free (ptr_name);
+            
+            unget_token (saved_tok);
+            return 0;
+        
+        }
+        
+        emit_push_reg_now (addr_reg);
+        
+        if (ptr_sym) {
+        
+            if (ptr_sym->is_static && ptr_sym->static_label) {
+                emit_load_global_to_reg ("rax", ptr_sym->static_label, DATA_PTR);
+            } else {
+                emit_load_local_to_reg ("rax", ptr_sym->offset, DATA_PTR);
+            }
+        
+        } else {
+            emit_load_global_to_reg ("rax", ptr_name, DATA_PTR);
+        }
+        
+        get_token ();
+        
+        if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+        
+            enum token_kind member_op = tok.kind;
+            char *member;
+            
+            int member_offset = 0;
+            int member_size = DATA_INT & 0x1f;
+            int member_elem_size = DATA_INT & 0x1f;
+            int member_pointer_depth = 0;
+            int member_is_array = 0;
+            int member_incdec = 0;
+            
+            enum token_kind member_incdec_op = TOK_EOF;
+            const char *object_tag_name = ptr_sym ? ptr_sym->pointed_tag_name : 0;
+            
+            int object_size = ptr_sym ? ptr_sym->pointed_size : get_global_symbol_pointed_size (ptr_name);
+            get_token ();
+            
+            if (tok.kind != TOK_IDENT || !tok.ident) {
+            
+                free (ptr_name);
+                
+                unget_token (saved_tok);
+                return 0;
+            
+            }
+            
+            member = xstrdup (tok.ident);
+            get_token ();
+            
+            if (!find_member_info_ex_bounded (member, object_size, object_tag_name,
+                                              &member_offset, &member_size, &member_elem_size,
+                                              &member_pointer_depth, &member_is_array, 0)) {
+            
+                free (member);
+                free (ptr_name);
+                
+                unget_token (saved_tok);
+                return 0;
+            
+            }
+            
+            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+            
+                member_incdec = 1;
+                member_incdec_op = tok.kind;
+                
+                get_token ();
+            
+            }
+            
+            if (member_op != TOK_ARROW || member_pointer_depth <= 0 || member_elem_size < size) {
+            
+                free (member);
+                free (ptr_name);
+                
+                unget_token (saved_tok);
+                return 0;
+            
+            }
+            
+            emit_push_reg_now (addr_reg);
+            
+            if (ptr_sym) {
+            
+                if (ptr_sym->is_static && ptr_sym->static_label) {
+                    emit_load_global_to_reg ("rcx", ptr_sym->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg ("rcx", ptr_sym->offset, DATA_PTR);
+                }
+            
+            } else {
+                emit_load_global_to_reg ("rcx", ptr_name, DATA_PTR);
+            }
+            
+            if (state->ofp) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ?
+                        "    mov rax, qword [rcx + %d]\n" :
+                        "    mov rax, qword ptr [rcx + %d]\n", member_offset);
+                    
+                    if (member_incdec) {
+                    
+                        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ?
+                            "    %s qword [rcx + %d], %d\n" :
+                            "    %s qword ptr [rcx + %d], %d\n",
+                            member_incdec_op == TOK_INCR ? "add" : "sub",
+                            member_offset, member_elem_size);
+                    
+                    }
+                
+                } else {
+                
+                    fprintf (state->ofp, "    movq %d(%%rcx), %%rax\n", member_offset);
+                    
+                    if (member_incdec) {
+                    
+                        fprintf (state->ofp, "    %sq $%d, %d(%%rcx)\n",
+                            member_incdec_op == TOK_INCR ? "add" : "sub",
+                            member_elem_size, member_offset);
+                    
+                    }
+                
+                }
+            
+            }
+            
+            emit_pop_reg_now ("rdx");
+            
+            if (offset != 0 && state->ofp) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    add rdx, %d\n", offset);
+                } else {
+                    fprintf (state->ofp, "    addq $%d, %%rdx\n", offset);
+                }
+            
+            }
+            
+            emit_copy_fixed_size_now (size);
+            
+            free (member);
+            free (ptr_name);
+            
+            return 1;
+        
+        }
+        
+        emit_pop_reg_now ("rdx");
+        
+        if (offset != 0 && state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    add rdx, %d\n", offset);
+            } else {
+                fprintf (state->ofp, "    addq $%d, %%rdx\n", offset);
+            }
+        
+        }
+        
+        emit_copy_fixed_size_now (size);
+        
+        free (ptr_name);
+        return 1;
+    
+    }
+    
+    if (tok.kind == TOK_LPAREN) {
+    
+        struct token *saved_tok = clone_current_token_now ();
+        struct local_symbol *ptr_sym;
+        
+        char *ptr_name;
+        
+        const char *ptr_start;
+        const char *ptr_caret;
+        
+        unsigned long ptr_line;
+        
+        int ptr_global_index;
+        int ptr_depth;
+        
+        const char *ptr_tag_name;
+        
+        int current_object_size;
+        int have_direct_object_pointer;
+        
+        get_token ();
+        
+        if (tok.kind != TOK_STAR) {
+        
+            unget_token (saved_tok);
+            return 0;
+        
+        }
+        
+        get_token ();
+        
+        if (tok.kind != TOK_IDENT || !tok.ident) {
+        
+            unget_token (saved_tok);
+            return 0;
+        
+        }
+        
+        ptr_name = xstrdup (tok.ident);
+        ptr_start = tok.start;
+        ptr_caret = tok.caret;
+        ptr_line = get_line_number ();
+        ptr_sym = find_local_symbol (ptr_name);
+        ptr_global_index = find_global_symbol (ptr_name);
+        
+        if (!ptr_sym && ptr_global_index < 0) {
+        
+            free (ptr_name);
+            
+            unget_token (saved_tok);
+            return 0;
+        
+        }
+        
+        ptr_depth = ptr_sym ? ptr_sym->pointer_depth : get_global_symbol_pointer_depth (ptr_name);
+        ptr_tag_name = ptr_sym ? ptr_sym->pointed_tag_name : 0;
+        
+        current_object_size = ptr_sym ? ptr_sym->pointed_size : get_global_symbol_pointed_size (ptr_name);
+        source_size = current_object_size;
+        
+        if (ptr_tag_name) {
+        
+            struct aggregate_tag_entry *entry = find_aggregate_tag (ptr_tag_name, 0);
+            
+            if (entry) {
+            
+                current_object_size = entry->size;
+                source_size = current_object_size;
+            
+            }
+        
+        }
+        
+        get_token ();
+        
+        if (tok.kind != TOK_RPAREN || ptr_depth <= 0) {
+        
+            free (ptr_name);
+            
+            unget_token (saved_tok);
+            return 0;
+        
+        }
+        
+        get_token ();
+        
+        if (tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
+        
+            free (ptr_name);
+            
+            unget_token (saved_tok);
+            return 0;
+        
+        }
+        
+        emit_push_reg_now (addr_reg);
+        
+        if (ptr_sym) {
+        
+            if (ptr_sym->is_static && ptr_sym->static_label) {
+                emit_load_global_to_reg ("rax", ptr_sym->static_label, DATA_PTR);
+            } else {
+                emit_load_local_to_reg ("rax", ptr_sym->offset, DATA_PTR);
+            }
+        
+        } else {
+            emit_load_global_to_reg ("rax", ptr_name, DATA_PTR);
+        }
+        
+        emit_load_deref_reg_now ("rax", DATA_PTR);
+        have_direct_object_pointer = 1;
+        
+        while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT || tok.kind == TOK_LBRACK) {
+        
+            if (tok.kind == TOK_LBRACK) {
+            
+                emit_parse_postfix_subscript_scaled_address_to_reg_now ("rax", DATA_PTR);
+                
+                current_object_size = DATA_PTR;
+                continue;
+            
+            }
+            
+            {
+            
+                enum token_kind member_op = tok.kind;
+                char *member;
+                
+                int member_offset = 0;
+                int member_size = DATA_INT & 0x1f;
+                int member_elem_size = DATA_INT & 0x1f;
+                int member_pointer_depth = 0;
+                int member_is_array = 0;
+                
+                get_token ();
+                
+                if (tok.kind != TOK_IDENT || !tok.ident) {
+                
+                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret,
+                        "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+                    
+                    free (ptr_name);
+                    return 0;
+                
+                }
+                
+                member = xstrdup (tok.ident);
+                get_token ();
+                
+                if (!find_member_info_ex_bounded (member, current_object_size, ptr_tag_name,
+                                                  &member_offset, &member_size, &member_elem_size,
+                                                  &member_pointer_depth, &member_is_array, 0)) {
+                
+                    report_line_at (get_filename (), ptr_line, REPORT_ERROR, ptr_start, ptr_caret,
+                        "unknown member '%s'", member);
+                    
+                    free (member);
+                    free (ptr_name);
+                    
+                    return 0;
+                
+                }
+                
+                ptr_tag_name = last_found_member_tag_name;
+                
+                if (member_op == TOK_ARROW) {
+                
+                    if (have_direct_object_pointer) {
+                        have_direct_object_pointer = 0;
+                    } else {
+                        emit_load_deref_reg_now ("rax", DATA_PTR);
+                    }
+                
+                } else {
+                    have_direct_object_pointer = 0;
+                }
+                
+                if (member_offset != 0 && state->ofp) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    add rax, %d\n", member_offset);
+                    } else {
+                        fprintf (state->ofp, "    addq $%d, %%rax\n", member_offset);
+                    }
+                
+                }
+                
+                current_object_size = member_size;
+                source_size = member_size;
+                
+                free (member);
+            
+            }
+        
+        }
+        
+        if (source_size < size) {
+        
+            free (ptr_name);
+            return 0;
+        
+        }
+        
+        emit_pop_reg_now ("rdx");
+        
+        if (offset != 0 && state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    add rdx, %d\n", offset);
+            } else {
+                fprintf (state->ofp, "    addq $%d, %%rdx\n", offset);
+            }
+        
+        }
+        
+        emit_copy_fixed_size_now (size);
+        
+        free (ptr_name);
+        return 1;
+    
+    }
+    
+    if (tok.kind != TOK_IDENT) {
+        return 0;
+    }
+    
+    /*
+     * A function-call RHS that returns a struct/union must be parsed by
+     * the normal expression code.  The aggregate-copy fast path is only
+     * for copying an already-existing aggregate object by address.
+     */
+    if (token_identifier_is_function_call_rhs_now ()) {
+        return 0;
+    }
+    
+    if (!rhs_text_is_plain_aggregate_lvalue_now (tok.caret ? tok.caret : tok.start)) {
+        return 0;
+    }
+    
+    rhs_name = xstrdup (tok.ident);
+    rhs_start = tok.start;
+    rhs_caret = tok.caret;
+    rhs_line = get_line_number ();
+
+    rhs_sym = find_local_symbol (rhs_name);
+    rhs_global_index = find_global_symbol (rhs_name);
+    
+    if (!rhs_sym && rhs_global_index < 0) {
+    
+        free (rhs_name);
+        return 0;
+    
+    }
+    
+    rhs_size = rhs_sym ? rhs_sym->size : get_global_symbol_size (rhs_name);
+    
+    {
+    
+        struct token *saved_rhs_tok = clone_current_token_now ();
+        get_token ();
+        
+        if (rhs_size <= (DATA_LLONG & 0x1f) && tok.kind != TOK_DOT && tok.kind != TOK_ARROW && tok.kind != TOK_LBRACK) {
+        
+            free (rhs_name);
+            
+            unget_token (saved_rhs_tok);
+            return 0;
+        
+        }
+        
+        unget_token (saved_rhs_tok);
+    
+    }
+    
+    emit_push_reg_now (addr_reg);
+    get_token ();
+    
+    source_ready = 0;
+    source_size = rhs_size;
+    
+    if (tok.kind == TOK_DOT || tok.kind == TOK_ARROW || tok.kind == TOK_LBRACK) {
+    
+        if (!emit_parse_postfix_copy_source_address_now ("rax", rhs_sym, rhs_name, rhs_start, rhs_caret, rhs_line)) {
+        
+            free (rhs_name);
+            return 0;
+        
+        }
+        
+        source_size = postfix_copy_lvalue_size;
+        source_ready = 1;
+    
+    }
+    
+    if (source_size < size) {
+    
+        free (rhs_name);
+        return 0;
+    
+    }
+    
+    if (!source_ready) {
+        emit_load_symbol_address_for_copy_now ("rax", rhs_sym, rhs_name);
+    }
+    
+    emit_pop_reg_now ("rdx");
+    
+    if (offset != 0 && state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    add rdx, %d\n", offset);
+        } else {
+            fprintf (state->ofp, "    addq $%d, %%rdx\n", offset);
+        }
+    
+    }
+    
+    emit_copy_fixed_size_now (size);
+    
+    free (rhs_name);
+    return 1;
+
+}
+
+static void emit_load_member_address_for_copy_now (const char *reg, struct local_symbol *sym, const char *name, enum token_kind member_op, int offset) {
+
+    if (sym) {
+    
+        if (member_op == TOK_DOT || sym->is_array) {
+        
+            if (sym->is_static && sym->static_label) {
+                emit_load_address_to_reg_now (reg, sym->static_label);
+            } else {
+                emit_load_local_address_to_reg_now (reg, sym->offset);
+            }
+        
+        } else if (sym->is_static && sym->static_label) {
+            emit_load_global_to_reg (reg, sym->static_label, DATA_PTR);
+        } else {
+            emit_load_local_to_reg (reg, sym->offset, DATA_PTR);
+        }
+    
+    } else {
+    
+        if (member_op == TOK_DOT || get_global_symbol_array (name)) {
+            emit_load_address_to_reg_now (reg, name);
+        } else {
+            emit_load_global_to_reg (reg, name, DATA_PTR);
+        }
+    
+    }
+    
+    if (offset != 0 && state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+        } else {
+            fprintf (state->ofp, "    addq $%d, %%%s\n", offset, reg);
+        }
+    
+    }
+
+}
+
+static int emit_parse_postfix_copy_source_address_now (const char *reg, struct local_symbol *src, const char *src_name, const char *name_start, const char *name_caret, unsigned long name_line) {
+
+    int have_address = 0;
+    int have_direct_object_pointer = 0;
+    int last_elem_size = DATA_INT & 0x1f;
+    int last_lvalue_size = DATA_INT & 0x1f;
+    
+    const char *current_object_tag_name = 0;
+    int current_object_size = 0;
+    
+    postfix_copy_lvalue_size = DATA_INT & 0x1f;
+    
+    if (!reg) {
+        reg = "rax";
+    }
+    
+    if (tok.kind == TOK_LPAREN) {
+    
+        if (src) {
+            return 0;
+        }
+        
+        ensure_global_function_symbol (src_name, name_start, name_caret, name_line);
+        emit_call_identifier_to_reg_now (src_name, reg, name_start, name_caret, name_line);
+        
+        have_address = 1;
+        have_direct_object_pointer = 1;
+    
+    }
+    
+    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+    
+        enum token_kind postfix_op = tok.kind;
+        
+        int pointer_depth;
+        int pointed_size;
+        
+        get_token ();
+        
+        if (tok.kind != TOK_LBRACK) {
+            return 0;
+        }
+        
+        if (src) {
+        
+            pointer_depth = src->pointer_depth;
+            pointed_size = src->pointed_size;
+            
+            if (src->is_static && src->static_label) {
+                emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
+            } else {
+                emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+            }
+        
+        } else if (find_global_symbol (src_name) >= 0) {
+        
+            pointer_depth = get_global_symbol_pointer_depth (src_name);
+            pointed_size = get_global_symbol_pointed_size (src_name);
+            
+            emit_load_global_to_reg (reg, src_name, DATA_PTR);
+        
+        } else {
+        
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", src_name);
+            return 0;
+        
+        }
+        
+        if (pointer_depth <= 0) {
+        
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "subscripted value is not a pointer");
+            return 0;
+        }
+        
+        last_elem_size = pointer_depth > 1 ? (DATA_PTR & 0x1f) : (pointed_size > 0 ? (pointed_size & 0x1f) : (DATA_INT & 0x1f));
+        last_lvalue_size = last_elem_size;
+        
+        have_address = 1;
+        have_direct_object_pointer = 0;
+        
+        emit_incdec_symbol_now (src, src_name, postfix_op, name_line, name_start, name_caret);
+    
+    }
+    
+    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT || tok.kind == TOK_LBRACK) {
+    
+        if (tok.kind == TOK_LBRACK) {
+        
+            int elem_size = last_elem_size;
+            
+            if (!have_address) {
+            
+                if (src) {
+                
+                    if (src->is_array) {
+                        emit_load_symbol_address_for_copy_now (reg, src, src_name);
+                    } else if (src->is_static && src->static_label) {
+                        emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+                    }
+                
+                    elem_size = src->is_array ? (src->pointer_depth ? DATA_PTR : (src->array_element_size > 0 ? src->array_element_size : src->pointed_size)) :
+                        (src->pointer_depth > 1 ? DATA_PTR : src->pointed_size);
+                    
+                    if (src->is_array && !src->pointer_depth) {
+                        current_object_tag_name = src->tag_name;
+                    } else if (!src->is_array && src->pointer_depth > 0) {
+                        current_object_tag_name = src->pointed_tag_name;
+                    }
+                
+                } else {
+                
+                    if (get_global_symbol_array (src_name)) {
+                        emit_load_address_to_reg_now (reg, src_name);
+                    } else {
+                        emit_load_global_to_reg (reg, src_name, DATA_PTR);
+                    }
+                    
+                    elem_size = get_global_symbol_array (src_name) ?
+                        (get_global_symbol_pointer_depth (src_name) ? DATA_PTR : (get_global_symbol_array_element_size (src_name) > 0 ? get_global_symbol_array_element_size (src_name) : get_global_symbol_pointed_size (src_name))) :
+                            (get_global_symbol_pointer_depth (src_name) > 1 ? DATA_PTR : get_global_symbol_pointed_size (src_name));
+                    
+                    if (get_global_symbol_array (src_name) && !get_global_symbol_pointer_depth (src_name)) {
+                        current_object_tag_name = get_global_symbol_tag_name (src_name);
+                    } else if (!get_global_symbol_array (src_name) && get_global_symbol_pointer_depth (src_name) > 0) {
+                        current_object_tag_name = get_global_symbol_tag_name (src_name);
+                    }
+                
+                }
+                
+                if (elem_size <= 0) {
+                    elem_size = DATA_INT & 0x1f;
+                }
+                
+                have_address = 1;
+            
+            }
+            
+            emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
+            
+            last_elem_size = elem_size;
+            last_lvalue_size = elem_size;
+            
+            current_object_size = elem_size;
+            continue;
+        
+        }
+        
+        {
+        
+            enum token_kind member_op = tok.kind;
+            char *member;
+            
+            const char *member_start;
+            const char *member_caret;
+            
+            unsigned long member_line;
+            
+            int member_offset = 0;
+            int member_size = DATA_INT & 0x1f;
+            int member_elem_size = DATA_INT & 0x1f;
+            int member_pointer_depth = 0;
+            int member_is_array = 0;
+            
+            get_token ();
+            
+            member_start = tok.start;
+            member_caret = tok.caret;
+            member_line = get_line_number ();
+            
+            if (tok.kind != TOK_IDENT) {
+            
+                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret,
+                    "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+                
+                return 0;
+            
+            }
+            
+            member = xstrdup (tok.ident);
+            get_token ();
+            
+            if (current_object_size <= 0) {
+            
+                if (src) {
+                
+                    if (member_op == TOK_ARROW && src->pointer_depth > 0) {
+                    
+                        current_object_size = src->pointed_size;
+                        current_object_tag_name = src->pointed_tag_name;
+                    
+                    } else {
+                    
+                        current_object_size = src->size;
+                        current_object_tag_name = src->tag_name;
+                    
+                    }
+                
+                } else {
+                
+                    if (member_op == TOK_ARROW && get_global_symbol_pointer_depth (src_name) > 0) {
+                    
+                        current_object_size = get_global_symbol_pointed_size (src_name);
+                        current_object_tag_name = get_global_symbol_tag_name (src_name);
+                    
+                    } else {
+                    
+                        current_object_size = get_global_symbol_size (src_name);
+                        current_object_tag_name = get_global_symbol_tag_name (src_name);
+                    
+                    }
+                
+                }
+            
+            }
+            
+            if (!find_member_info_ex_bounded (member, current_object_size, current_object_tag_name, &member_offset, &member_size, &member_elem_size, &member_pointer_depth, &member_is_array, 0)) {
+            
+                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret,
+                    "unknown member '%s'", member);
+                
+                free (member);
+                return 0;
+            
+            }
+            
+            {
+            
+                const char *member_tag_name = last_found_member_tag_name;
+                
+                if (member_is_array && member_pointer_depth > 0) {
+                
+                    /*
+                     * For an array member whose element type is a pointer,
+                     * the subscript step is one pointer.  Do not replace it
+                     * with the pointed aggregate size from the member tag.
+                     */
+                    member_elem_size = DATA_PTR;
+                
+                } else if (member_pointer_depth > 1) {
+                    member_elem_size = DATA_PTR;
+                } else if (member_pointer_depth == 1 && member_tag_name) {
+                
+                    struct aggregate_tag_entry *entry = find_aggregate_tag (member_tag_name, 0);
+                    
+                    if (entry) {
+                        member_elem_size = entry->size;
+                    }
+                
+                }
+                
+                current_object_tag_name = member_tag_name;
+            
+            }
+            
+            free (member);
+            
+            if (!have_address) {
+            
+                emit_load_member_address_for_copy_now (reg, src, src_name, member_op, 0);
+                have_address = 1;
+            
+            } else if (member_op == TOK_ARROW) {
+            
+                if (have_direct_object_pointer) {
+                    have_direct_object_pointer = 0;
+                } else {
+                    emit_load_deref_reg_now (reg, DATA_PTR);
+                }
+            
+            } else {
+                have_direct_object_pointer = 0;
+            }
+            
+            if (tok.kind == TOK_LBRACK && member_pointer_depth > 0 && !member_is_array) {
+                emit_load_member_from_addr_reg_now (reg, reg, member_offset, DATA_PTR & 0x1f);
+            } else if (state->ofp && member_offset != 0) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    add %s, %d\n", reg, member_offset);
+                } else {
+                    fprintf (state->ofp, "    addq $%d, %%%s\n", member_offset, reg);
+                }
+            
+            }
+            
+            last_elem_size = member_elem_size;
+            last_lvalue_size = member_size;
+            
+            if (member_pointer_depth > 0 || member_is_array) {
+                current_object_size = member_elem_size;
+            } else {
+                current_object_size = member_size;
+            }
+        
+        }
+    
+    }
+    
+    postfix_copy_lvalue_size = last_lvalue_size;
+    return have_address;
+
+}
+
+static void emit_load_floating_deref_reg_now (const char *reg, int size) {
+
+    if (!state->ofp) {
+        return;
+    }
+
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+
+        if (size == (DATA_FLOAT & 0x1f)) {
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fld dword [%s]\n" : "    fld dword ptr [%s]\n", reg);
+        } else {
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fld qword [%s]\n" : "    fld qword ptr [%s]\n", reg);
+        }
+
+    } else {
+
+        if (size == (DATA_FLOAT & 0x1f)) {
+            fprintf (state->ofp, "    flds (%%%s)\n", reg);
+        } else {
+            fprintf (state->ofp, "    fldl (%%%s)\n", reg);
+        }
+
+    }
+
+}
+
+static void emit_add_const_to_reg_now (const char *reg, int offset) {
+
+    if (!state->ofp || !reg || offset == 0) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+    } else {
+        fprintf (state->ofp, "    addq $%d, %%%s\n", offset, reg);
+    }
+
+}
+
+static void emit_load_floating_member_from_addr_reg_now (const char *reg, int offset, int size) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (size == (DATA_FLOAT & 0x1f)) {
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fld dword [%s + %d]\n" : "    fld dword ptr [%s + %d]\n", reg, offset);
+        } else {
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fld qword [%s + %d]\n" : "    fld qword ptr [%s + %d]\n", reg, offset);
+        }
+    
+    } else {
+    
+        if (size == (DATA_FLOAT & 0x1f)) {
+            fprintf (state->ofp, "    flds %d(%%%s)\n", offset, reg);
+        } else {
+            fprintf (state->ofp, "    fldl %d(%%%s)\n", offset, reg);
+        }
+    
+    }
+
+}
+
+static void save_parse_type_state_now (
+
+    int *saved_type_size,
+    int *saved_storage_class,
+    int *saved_is_aggregate,
+    int *saved_is_void,
+    int *saved_is_unsigned,
+    int *saved_is_floating,
+    int *saved_has_tag,
+    int *saved_is_inline,
+    int *saved_field_count,
+    int saved_fields[MAX_AGG_FIELDS],
+    int *saved_declarator_is_pointer,
+    int *saved_declarator_pointer_depth,
+    int *saved_declarator_has_array,
+    int *saved_declarator_has_function,
+    int *saved_declarator_array_unsized,
+    int *saved_declarator_array_dimensions,
+    long *saved_declarator_array_count,
+    long *saved_declarator_first_array_count) {
+
+    int i;
+    
+    *saved_type_size = parsed_type_size;
+    *saved_storage_class = parsed_storage_class;
+    *saved_is_aggregate = parsed_type_is_aggregate;
+    *saved_is_void = parsed_type_is_void;
+    *saved_is_unsigned = parsed_type_is_unsigned;
+    *saved_is_floating = parsed_type_is_floating;
+    *saved_has_tag = parsed_type_has_tag;
+    *saved_is_inline = parsed_type_is_inline;
+    *saved_field_count = parsed_field_count;
+    
+    for (i = 0; i < *saved_field_count && i < MAX_AGG_FIELDS; i++) {
+        saved_fields[i] = parsed_field_sizes[i];
+    }
+    
+    *saved_declarator_is_pointer = declarator_is_pointer;
+    *saved_declarator_pointer_depth = declarator_pointer_depth;
+    *saved_declarator_has_array = declarator_has_array;
+    *saved_declarator_has_function = declarator_has_function;
+    *saved_declarator_array_unsized = declarator_array_unsized;
+    *saved_declarator_array_dimensions = declarator_array_dimensions;
+    *saved_declarator_array_count = declarator_array_count;
+    *saved_declarator_first_array_count = declarator_first_array_count;
+
+}
+
+static void restore_parse_type_state_now (
+    int saved_type_size,
+    int saved_storage_class,
+    int saved_is_aggregate,
+    int saved_is_void,
+    int saved_is_unsigned,
+    int saved_is_floating,
+    int saved_has_tag,
+    int saved_is_inline,
+    int saved_field_count,
+    int saved_fields[MAX_AGG_FIELDS],
+    int saved_declarator_is_pointer,
+    int saved_declarator_pointer_depth,
+    int saved_declarator_has_array,
+    int saved_declarator_has_function,
+    int saved_declarator_array_unsized,
+    int saved_declarator_array_dimensions,
+    long saved_declarator_array_count,
+    long saved_declarator_first_array_count) {
+
+    int i;
+    
+    parsed_type_size = saved_type_size;
+    parsed_storage_class = saved_storage_class;
+    parsed_type_is_aggregate = saved_is_aggregate;
+    parsed_type_is_void = saved_is_void;
+    parsed_type_is_unsigned = saved_is_unsigned;
+    parsed_type_is_floating = saved_is_floating;
+    parsed_type_has_tag = saved_has_tag;
+    parsed_type_is_inline = saved_is_inline;
+    
+    clear_parsed_fields ();
+    
+    for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
+        parsed_field_sizes[i] = saved_fields[i];
+    }
+    
+    parsed_field_count = saved_field_count;
+    declarator_is_pointer = saved_declarator_is_pointer;
+    declarator_pointer_depth = saved_declarator_pointer_depth;
+    declarator_has_array = saved_declarator_has_array;
+    declarator_has_function = saved_declarator_has_function;
+    declarator_array_unsized = saved_declarator_array_unsized;
+    declarator_array_dimensions = saved_declarator_array_dimensions;
+    declarator_array_count = saved_declarator_array_count;
+    declarator_first_array_count = saved_declarator_first_array_count;
+
+}
+
+static int parse_builtin_va_arg_type_now (int *out_size, int *out_unsigned, int *out_pointer, int *out_floating) {
+
+    int saved_type_size;
+    int saved_storage_class;
+    int saved_is_aggregate;
+    int saved_is_void;
+    int saved_is_unsigned;
+    int saved_is_floating;
+    int saved_has_tag;
+    int saved_is_inline;
+    int saved_field_count;
+    int saved_fields[MAX_AGG_FIELDS];
+    int saved_declarator_is_pointer;
+    int saved_declarator_pointer_depth;
+    int saved_declarator_has_array;
+    int saved_declarator_has_function;
+    int saved_declarator_array_unsized;
+    int saved_declarator_array_dimensions;
+    
+    long saved_declarator_array_count;
+    long saved_declarator_first_array_count;
+    
+    char *type_name = 0;
+    
+    int base_size;
+    int pointer_depth;
+    int is_unsigned;
+    int is_floating;
+    
+    save_parse_type_state_now (&saved_type_size, &saved_storage_class,
+        &saved_is_aggregate, &saved_is_void, &saved_is_unsigned,
+        &saved_is_floating, &saved_has_tag, &saved_is_inline,
+        &saved_field_count, saved_fields, &saved_declarator_is_pointer,
+        &saved_declarator_pointer_depth, &saved_declarator_has_array,
+        &saved_declarator_has_function, &saved_declarator_array_unsized,
+        &saved_declarator_array_dimensions, &saved_declarator_array_count,
+        &saved_declarator_first_array_count);
+    
+    declarator_is_pointer = 0;
+    declarator_pointer_depth = 0;
+    declarator_has_array = 0;
+    declarator_has_function = 0;
+    declarator_array_unsized = 0;
+    declarator_array_count = 0;
+    declarator_first_array_count = 1;
+    declarator_array_dimensions = 0;
+    
+    parse_type_spec ();
+    base_size = parsed_type_size & 0x1f;
+    
+    is_unsigned = parsed_type_is_unsigned;
+    is_floating = parsed_type_is_floating;
+    
+    if (tok.kind != TOK_RPAREN) {
+        parse_declarator (&type_name);
+    }
+    
+    pointer_depth = declarator_is_pointer ? (declarator_pointer_depth > 0 ? declarator_pointer_depth : 1) : 0;
+    
+    if (type_name) {
+        free (type_name);
+    }
+    
+    if (out_pointer) {
+        *out_pointer = pointer_depth;
+    }
+    
+    if (out_unsigned) {
+        *out_unsigned = is_unsigned;
+    }
+    
+    if (out_floating) {
+        *out_floating = is_floating;
+    }
+    
+    if (out_size) {
+        *out_size = pointer_depth > 0 ? (DATA_PTR & 0x1f) : base_size;
+    }
+    
+    restore_parse_type_state_now (saved_type_size, saved_storage_class,
+        saved_is_aggregate, saved_is_void, saved_is_unsigned,
+        saved_is_floating, saved_has_tag, saved_is_inline,
+        saved_field_count, saved_fields, saved_declarator_is_pointer,
+        saved_declarator_pointer_depth, saved_declarator_has_array,
+        saved_declarator_has_function, saved_declarator_array_unsized,
+        saved_declarator_array_dimensions, saved_declarator_array_count,
+        saved_declarator_first_array_count);
+    
+    return 1;
+
+}
+
+static int emit_parse_builtin_va_arg_address_to_reg_now (const char *reg, int *out_size, int *out_unsigned, int *out_pointer, int *out_floating) {
+
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    const char *scratch_reg;
+    
+    unsigned long name_line;
+    unsigned long inc;
+    
+    struct local_symbol *src;
+    
+    int global_index;
+    int size = DATA_INT & 0x1f;
+    int is_unsigned = 1;
+    int pointer_depth = 0;
+    int is_floating = 0;
+    int deref_lvalue = 0;
+    int paren_lvalue = 0;
+    
+    if (tok.kind != TOK_LPAREN) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    if (tok.kind == TOK_LPAREN) {
+    
+        paren_lvalue = 1;
+        get_token ();
+    
+    }
+    
+    if (tok.kind == TOK_STAR) {
+    
+        deref_lvalue = 1;
+        get_token ();
+    
+    }
+    
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected va_list object in __scc_builtin_va_arg");
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    get_token ();
+    
+    if (paren_lvalue) {
+        expect (TOK_RPAREN, ")");
+    }
+    
+    expect (TOK_COMMA, ",");
+    
+    if (!is_type_start (tok.kind)) {
+    
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected type name in __scc_builtin_va_arg");
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    parse_builtin_va_arg_type_now (&size, &is_unsigned, &pointer_depth, &is_floating);
+    expect (TOK_RPAREN, ")");
+    
+    if (size <= 0) {
+        size = DATA_INT & 0x1f;
+    }
+    
+    /*
+     * AMD64 varargs are slot based.  Even small integer types occupy an
+     * 8-byte argument slot in the register home/overflow area, so advancing
+     * by the C object size makes the next va_arg read from the middle of the
+     * previous slot.
+     */
+    inc = (unsigned long) align_up_long ((size > 0 ? size : (DATA_INT & 0x1f)), DATA_PTR & 0x1f);
+    
+    if (inc < (unsigned long) (DATA_PTR & 0x1f)) {
+        inc = DATA_PTR & 0x1f;
+    }
+    
+    src = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (!src && global_index < 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (deref_lvalue) {
+    
+        scratch_reg = strcmp (reg, "rdx") == 0 ? "rcx" : "rdx";
+        
+        if (src) {
+        
+            if (src->is_static && src->static_label) {
+                emit_load_global_to_reg (scratch_reg, src->static_label, DATA_PTR);
+            } else {
+                emit_load_local_to_reg (scratch_reg, src->offset, DATA_PTR);
+            }
+        
+        } else {
+            emit_load_global_to_reg (scratch_reg, name, DATA_PTR);
+        }
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov %s, qword [%s]\n" : "    mov %s, qword ptr [%s]\n", reg, scratch_reg);
+                fprintf (state->ofp, "    push %s\n", reg);
+                fprintf (state->ofp, "    add %s, %lu\n", reg, inc);
+                fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov qword [%s], %s\n" : "    mov qword ptr [%s], %s\n", scratch_reg, reg);
+                fprintf (state->ofp, "    pop %s\n", reg);
+            
+            } else {
+            
+                fprintf (state->ofp, "    movq (%%%s), %%%s\n", scratch_reg, reg);
+                fprintf (state->ofp, "    pushq %%%s\n", reg);
+                fprintf (state->ofp, "    addq $%lu, %%%s\n", inc, reg);
+                fprintf (state->ofp, "    movq %%%s, (%%%s)\n", reg, scratch_reg);
+                fprintf (state->ofp, "    subq $%lu, %%%s\n", inc, reg);
+                fprintf (state->ofp, "    popq %%%s\n", reg);
+            
+            }
+        
+        }
+    
+    } else {
+    
+        if (src) {
+        
+            if (src->is_static && src->static_label) {
+                emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
+            } else {
+                emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+            }
+        
+        } else {
+            emit_load_global_to_reg (reg, name, DATA_PTR);
+        }
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                fprintf (state->ofp, "    push %s\n", reg);
+                fprintf (state->ofp, "    add %s, %lu\n", reg, inc);
+            
+            } else {
+            
+                fprintf (state->ofp, "    pushq %%%s\n", reg);
+                fprintf (state->ofp, "    addq $%lu, %%%s\n", inc, reg);
+            
+            }
+        
+        }
+        
+        if (src) {
+        
+            if (src->is_static && src->static_label) {
+                emit_store_reg_to_global (src->static_label, DATA_PTR, reg);
+            } else {
+                emit_store_reg_to_local (src->offset, DATA_PTR, reg);
+            }
+        
+        } else {
+            emit_store_reg_to_global (name, DATA_PTR, reg);
+        }
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    pop %s\n", reg);
+            } else {
+                fprintf (state->ofp, "    popq %%%s\n", reg);
+            }
+        
+        }
+    
+    }
+    
+    if (out_size) {
+        *out_size = size;
+    }
+    
+    if (out_unsigned) {
+        *out_unsigned = is_unsigned;
+    }
+    
+    if (out_pointer) {
+        *out_pointer = pointer_depth;
+    }
+    
+    if (out_floating) {
+        *out_floating = is_floating;
+    }
+    
+    free (name);
+    return 1;
+
+}
+
+static int emit_load_parenthesized_indirect_member_to_reg_now (const char *reg) {
+
+    const char *p;
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    struct local_symbol *src;
+    
+    int global_index;
+    int current_object_size;
+    
+    const char *current_tag_name;
+    
+    int first_member;
+    int last_member_size;
+    int last_member_pointer_depth;
+    int last_member_elem_size;
+    
+    if (tok.kind != TOK_STAR || !tok.caret) {
+        return 0;
+    }
+    
+    p = tok.caret + 1;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    p++;
+    
+    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;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '.' && !(*p == '-' && p[1] == '>')) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    get_token ();
+    
+    expect (TOK_RPAREN, ")");
+    
+    src = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (src) {
+    
+        if (src->is_static && src->static_label) {
+            emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
+        } else {
+            emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+        }
+        
+        current_object_size = src->pointed_size;
+        current_tag_name = src->pointed_tag_name;
+    
+    } else if (global_index >= 0) {
+    
+        emit_load_global_to_reg (reg, name, DATA_PTR);
+        
+        current_object_size = get_global_symbol_pointed_size (name);
+        current_tag_name = 0;
+    
+    } else {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    free (name);
+    
+    emit_load_deref_reg_now (reg, DATA_PTR);
+    first_member = 1;
+    
+    last_member_size = DATA_INT & 0x1f;
+    last_member_pointer_depth = 0;
+    last_member_elem_size = DATA_INT & 0x1f;
+    
+    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+    
+        enum token_kind member_op = tok.kind;
+        char *member;
+        
+        const char *member_start;
+        const char *member_caret;
+        
+        unsigned long member_line;
+        
+        int member_offset = 0;
+        int member_size = DATA_INT & 0x1f;
+        int member_elem_size = DATA_INT & 0x1f;
+        int member_pointer_depth = 0;
+        int member_is_array = 0;
+        
+        get_token ();
+        
+        member_start = tok.start;
+        member_caret = tok.caret;
+        member_line = get_line_number ();
+        
+        if (tok.kind != TOK_IDENT || !tok.ident) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+            return 1;
+        
+        }
+        
+        member = xstrdup (tok.ident);
+        get_token ();
+        
+        if (!find_member_info_ex_bounded (member, current_object_size, current_tag_name, &member_offset, &member_size, &member_elem_size, &member_pointer_depth, &member_is_array, 0)) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+            
+            free (member);
+            return 1;
+        
+        }
+        
+        free (member);
+        
+        if (!first_member && member_op == TOK_ARROW) {
+            emit_load_deref_reg_now (reg, DATA_PTR);
+        }
+        
+        if (member_offset != 0 && state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    add %s, %d\n", reg, member_offset);
+            } else {
+                fprintf (state->ofp, "    addq $%d, %%%s\n", member_offset, reg);
+            }
+        
+        }
+        
+        current_object_size = member_size;
+        current_tag_name = last_found_member_tag_name;
+        
+        last_member_size = member_size;
+        last_member_pointer_depth = member_pointer_depth;
+        last_member_elem_size = member_elem_size;
+        
+        first_member = 0;
+    
+    }
+    
+    emit_load_deref_reg_now (reg, last_member_size);
+    
+    if (last_member_pointer_depth > 0) {
+        set_rhs_last_pointer_info (last_member_pointer_depth, last_member_elem_size);
+    } else {
+        clear_rhs_last_pointer_info ();
+    }
+    
+    return 1;
+
+}
+
+static int source_starts_parenthesized_deref_postfix_incdec_subscript_at (const char *p) {
+
+    if (!p || *p != '*') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    p++;
+    
+    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;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((p[0] == '+' && p[1] == '+') || (p[0] == '-' && p[1] == '-'))) {
+        return 0;
+    }
+    
+    p += 2;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return 1;
+
+}
+
+static int source_starts_lparen_deref_subscript_at (const char *p) {
+
+    if (!p || *p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '*') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    p++;
+    
+    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;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '[';
+
+}
+
+static int source_starts_lparen_deref_postfix_incdec_at (const char *p) {
+
+    if (!p) {
+        return 0;
+    }
+    
+    /*
+     * Most callers pass the caret at the opening parenthesis, but some
+     * token paths leave it just after the '('.  Accept both positions so
+     * a statement such as:
+     *
+     *     (*parameter_count)++;
+     *
+     * is always routed through the dereferenced-object inc/dec emitter, not
+     * the ordinary pointer-variable inc/dec path.  The latter scales by the
+     * pointed-to size and would emit addq $4 for int *, corrupting counts.
+     */
+    if (*p == '(') {
+        p++;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '*') {
+        return 0;
+    }
+    
+    return source_starts_parenthesized_deref_postfix_incdec_subscript_at (p);
+
+}
+
+static int emit_load_parenthesized_deref_postfix_incdec_subscript_to_reg_now (const char *reg) {
+
+    enum token_kind op;
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    struct local_symbol *src;
+    
+    int global_index;
+    int pointer_depth = 0;
+    int pointed_size = DATA_INT & 0x1f;
+    int elem_size = DATA_INT & 0x1f;
+    int lvalue_size = DATA_INT & 0x1f;
+    int step = 1;
+    
+    const char *addr_reg;
+    
+    if (tok.kind != TOK_STAR) {
+        return 0;
+    }
+    
+    if (!source_starts_parenthesized_deref_postfix_incdec_subscript_at (tok.caret)) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    get_token ();
+    
+    if (tok.kind != TOK_RPAREN) {
+    
+        free (name);
+        return 0;
+    
+    }
+    
+    get_token ();
+    
+    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
+    
+        free (name);
+        return 0;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    src = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (src) {
+    
+        pointer_depth = src->pointer_depth;
+        pointed_size = src->pointed_size;
+    
+    } else if (global_index >= 0) {
+    
+        pointer_depth = get_global_symbol_pointer_depth (name);
+        pointed_size = get_global_symbol_pointed_size (name);
+    
+    } else {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (pointer_depth <= 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid indirection of non-pointer '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (pointed_size <= 0) {
+        pointed_size = DATA_INT & 0x1f;
+    }
+    
+    if (pointer_depth > 1) {
+    
+        lvalue_size = DATA_PTR & 0x1f;
+        
+        elem_size = (pointer_depth > 2) ? (DATA_PTR & 0x1f) : index_step_size (pointed_size);
+        step = elem_size;
+    
+    } else {
+    
+        lvalue_size = pointed_size & 0x1f;
+        
+        elem_size = pointed_size & 0x1f;
+        step = 1;
+    
+    }
+    
+    if (!reg) {
+        reg = "rax";
+    }
+    
+    addr_reg = (strcmp (reg, "rdx") == 0) ? "rcx" : "rdx";
+    
+    if (src) {
+    
+        if (src->is_static && src->static_label) {
+            emit_load_global_to_reg (addr_reg, src->static_label, DATA_PTR);
+        } else {
+            emit_load_local_to_reg (addr_reg, src->offset, DATA_PTR);
+        }
+    
+    } else {
+        emit_load_global_to_reg (addr_reg, name, DATA_PTR);
+    }
+    
+    emit_load_member_from_addr_reg_now (reg, addr_reg, 0, lvalue_size);
+    emit_push_reg_now (reg);
+    
+    if (state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, op == TOK_INCR ? "    add %s, %d\n" : "    sub %s, %d\n", reg, step);
+        } else {
+            fprintf (state->ofp, op == TOK_INCR ? "    addq $%d, %%%s\n" : "    subq $%d, %%%s\n", step, reg);
+        }
+    
+    }
+    
+    emit_store_reg_to_deref_reg_now (addr_reg, reg, lvalue_size);
+    emit_pop_reg_now (reg);
+    
+    if (tok.kind == TOK_LBRACK) {
+        emit_parse_postfix_subscripts_to_reg_now (reg, elem_size, pointer_depth - 1, pointed_size);
+    }
+    
+    if (pointer_depth > 1) {
+        set_rhs_last_pointer_info (pointer_depth - 1, pointed_size);
+    } else {
+        clear_rhs_last_pointer_info ();
+    }
+    
+    free (name);
+    return 1;
+
+}
+
+static int source_starts_deref_parenthesized_deref_postfix_incdec_assignment_at (const char *p) {
+
+    if (!p) {
+        return 0;
+    }
+    
+    if (*p == '*') {
+        p++;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '*') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    p++;
+    
+    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;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((p[0] == '+' && p[1] == '+') || (p[0] == '-' && p[1] == '-'))) {
+        return 0;
+    }
+    
+    p += 2;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '=';
+
+}
+
+static int source_starts_deref_parenthesized_deref_postfix_incdec_value_at (const char *p) {
+
+    if (!p || *p != '*') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '*') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    p++;
+    
+    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;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((p[0] == '+' && p[1] == '+') || (p[0] == '-' && p[1] == '-'))) {
+        return 0;
+    }
+    
+    p += 2;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == ')';
+
+}
+
+static int emit_load_deref_parenthesized_deref_postfix_incdec_to_reg_now (const char *reg) {
+
+    enum token_kind op;
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    struct local_symbol *src;
+    
+    int global_index;
+    int pointer_depth = 0;
+    int pointed_size = DATA_INT & 0x1f;
+    int deref_size = DATA_INT & 0x1f;
+    int step = DATA_PTR & 0x1f;
+    
+    if (tok.kind != TOK_STAR) {
+        return 0;
+    }
+    
+    if (!source_starts_deref_parenthesized_deref_postfix_incdec_value_at (tok.caret)) {
+        return 0;
+    }
+    
+    expect (TOK_STAR, "*");
+    expect (TOK_LPAREN, "(");
+    expect (TOK_LPAREN, "(");
+    expect (TOK_STAR, "*");
+    
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    get_token ();
+    
+    expect (TOK_RPAREN, ")");
+    
+    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
+    
+        free (name);
+        return 0;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    expect (TOK_RPAREN, ")");
+    
+    src = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (src) {
+    
+        pointer_depth = src->pointer_depth;
+        pointed_size = src->pointed_size;
+    
+    } else if (global_index >= 0) {
+    
+        pointer_depth = get_global_symbol_pointer_depth (name);
+        pointed_size = get_global_symbol_pointed_size (name);
+    
+    } else {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (pointer_depth <= 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid indirection of non-pointer '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (pointed_size <= 0) {
+        pointed_size = DATA_INT & 0x1f;
+    }
+    
+    deref_size = pointer_depth > 1 ? (pointed_size & 0x1f) : (DATA_INT & 0x1f);
+    step = pointer_depth > 2 ? (DATA_PTR & 0x1f) : index_step_size (pointed_size);
+    
+    if (deref_size <= 0) {
+        deref_size = DATA_INT & 0x1f;
+    }
+    
+    if (step <= 0) {
+        step = DATA_PTR & 0x1f;
+    }
+    
+    if (!reg) {
+        reg = "rax";
+    }
+    
+    if (src) {
+    
+        if (src->is_static && src->static_label) {
+            emit_load_global_to_reg ("rcx", src->static_label, DATA_PTR);
+        } else {
+            emit_load_local_to_reg ("rcx", src->offset, DATA_PTR);
+        }
+    
+    } else {
+        emit_load_global_to_reg ("rcx", name, DATA_PTR);
+    }
+    
+    emit_load_member_from_addr_reg_now (reg, "rcx", 0, DATA_PTR & 0x1f);
+    emit_push_reg_now (reg);
+    
+    if (state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, op == TOK_INCR ? "    add %s, %d\n" : "    sub %s, %d\n", reg, step);
+        } else {
+            fprintf (state->ofp, op == TOK_INCR ? "    addq $%d, %%%s\n" : "    subq $%d, %%%s\n", step, reg);
+        }
+    
+    }
+    
+    emit_store_reg_to_deref_reg_now ("rcx", reg, DATA_PTR & 0x1f);
+    emit_pop_reg_now (reg);
+    emit_load_deref_reg_now (reg, deref_size);
+    
+    if (pointer_depth > 2) {
+        set_rhs_last_pointer_info (pointer_depth - 2, pointed_size);
+    } else {
+        clear_rhs_last_pointer_info ();
+    }
+    
+    free (name);
+    return 1;
+
+}
+
+static int emit_store_to_deref_parenthesized_deref_postfix_incdec_now (const char *reg) {
+
+    enum token_kind op;
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    struct local_symbol *src;
+    
+    int global_index;
+    int pointer_depth = 0;
+    int pointed_size = DATA_INT & 0x1f;
+    int store_size = DATA_INT & 0x1f;
+    int step = DATA_PTR & 0x1f;
+    
+    if (tok.kind != TOK_STAR) {
+        return 0;
+    }
+    
+    if (!source_starts_deref_parenthesized_deref_postfix_incdec_assignment_at (tok.caret)) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    expect (TOK_LPAREN, "(");
+    expect (TOK_STAR, "*");
+    
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    get_token ();
+    
+    expect (TOK_RPAREN, ")");
+    
+    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
+    
+        free (name);
+        return 0;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    expect (TOK_ASSIGN, "=");
+    
+    src = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (src) {
+    
+        pointer_depth = src->pointer_depth;
+        pointed_size = src->pointed_size;
+    
+    } else if (global_index >= 0) {
+    
+        pointer_depth = get_global_symbol_pointer_depth (name);
+        pointed_size = get_global_symbol_pointed_size (name);
+    
+    } else {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (pointer_depth <= 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid indirection of non-pointer '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (pointed_size <= 0) {
+        pointed_size = DATA_INT & 0x1f;
+    }
+    
+    store_size = pointed_size & 0x1f;
+    step = pointed_size & 0x1f;
+    
+    if (step <= 0) {
+        step = DATA_PTR & 0x1f;
+    }
+    
+    if (!reg) {
+        reg = "rax";
+    }
+    
+    if (src) {
+    
+        if (src->is_static && src->static_label) {
+            emit_load_global_to_reg ("rcx", src->static_label, DATA_PTR);
+        } else {
+            emit_load_local_to_reg ("rcx", src->offset, DATA_PTR);
+        }
+    
+    } else {
+        emit_load_global_to_reg ("rcx", name, DATA_PTR);
+    }
+    
+    emit_load_member_from_addr_reg_now ("rdx", "rcx", 0, DATA_PTR & 0x1f);
+    emit_push_reg_now ("rdx");
+    
+    if (state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, op == TOK_INCR ? "    add rdx, %d\n" : "    sub rdx, %d\n", step);
+        } else {
+            fprintf (state->ofp, op == TOK_INCR ? "    addq $%d, %%rdx\n" : "    subq $%d, %%rdx\n", step);
+        }
+    
+    }
+    
+    emit_store_reg_to_deref_reg_now ("rcx", "rdx", DATA_PTR & 0x1f);
+    
+    emit_load_assignment_rhs_expression_to_reg (reg);
+    emit_pop_reg_now ("rdx");
+    emit_store_reg_to_deref_reg_now ("rdx", reg, store_size);
+    
+    free (name);
+    return 1;
+
+}
+
+static void emit_scale_reg_by_const_now (const char *reg, int scale);
+
+static int source_starts_deref_assignment_at_now (const char *p) {
+
+    if (!p || *p != '*') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    p++;
+    
+    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[1] != '=') {
+        return 1;
+    }
+    
+    if ((p[0] == '+' || p[0] == '-' || p[0] == '*' || p[0] == '/' ||
+         p[0] == '%' || p[0] == '&' || p[0] == '^' || p[0] == '|') &&
+        p[1] == '=') {
+        return 1;
+    }
+    
+    if ((p[0] == '<' && p[1] == '<' && p[2] == '=') ||
+        (p[0] == '>' && p[1] == '>' && p[2] == '=')) {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static int emit_load_deref_assignment_expression_to_reg_now (const char *reg) {
+
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    
+    struct local_symbol *sym;
+    int global_index;
+    
+    enum token_kind op;
+    
+    int pointer_depth = 0;
+    int pointed_size = DATA_INT & 0x1f;
+    int value_pointer_depth = 0;
+    int store_size = DATA_INT & 0x1f;
+    
+    if (tok.kind != TOK_STAR) {
+        return 0;
+    }
+    
+    if (!source_starts_deref_assignment_at_now (tok.caret)) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    get_token ();
+    
+    if (!is_assignment_operator (tok.kind)) {
+    
+        free (name);
+        return 0;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    sym = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (sym) {
+    
+        pointer_depth = sym->pointer_depth;
+        pointed_size = sym->pointed_size;
+        
+        if (sym->is_static && sym->static_label) {
+            emit_load_global_to_reg ("rcx", sym->static_label, DATA_PTR);
+        } else {
+            emit_load_local_to_reg ("rcx", sym->offset, DATA_PTR);
+        }
+    
+    } else if (global_index >= 0) {
+    
+        pointer_depth = get_global_symbol_pointer_depth (name);
+        pointed_size = get_global_symbol_pointed_size (name);
+        
+        emit_load_global_to_reg ("rcx", name, DATA_PTR);
+    
+    } else {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (pointer_depth <= 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid indirection of non-pointer '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    value_pointer_depth = pointer_depth - 1;
+    
+    if (value_pointer_depth > 0) {
+        store_size = DATA_PTR & 0x1f;
+    } else if (pointed_size > 0) {
+        store_size = pointed_size & 0x1f;
+    }
+    
+    if (store_size <= 0) {
+        store_size = DATA_INT & 0x1f;
+    }
+    
+    emit_push_reg_now ("rcx");
+    
+    if (op == TOK_ASSIGN) {
+        emit_load_assignment_rhs_expression_to_reg ("rax");
+    } else {
+    
+        emit_load_deref_reg_now ("rcx", store_size);
+        
+        emit_push_reg_now ("rcx");
+        emit_load_assignment_rhs_expression_to_reg ("rdx");
+        
+        emit_pop_reg_now ("rax");
+        
+        if ((op == TOK_PLUSEQ || op == TOK_MINUSEQ) && value_pointer_depth > 0 &&
+            index_step_size (pointed_size) > 1) {
+            emit_scale_reg_by_const_now ("rdx", index_step_size (pointed_size));
+        }
+        
+        emit_assignment_binary_op (op, 0);
+    
+    }
+    
+    emit_pop_reg_now ("rcx");
+    emit_store_reg_to_deref_reg_now ("rcx", "rax", store_size);
+    
+    if (reg && strcmp (reg, "rax") != 0 && state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    mov %s, rax\n", reg);
+        } else {
+            fprintf (state->ofp, "    movq %%rax, %%%s\n", reg);
+        }
+    
+    }
+    
+    expect (TOK_RPAREN, ")");
+    
+    if (value_pointer_depth > 0) {
+        set_rhs_last_pointer_info (value_pointer_depth, pointed_size);
+    } else {
+        clear_rhs_last_pointer_info ();
+    }
+    
+    free (name);
+    return 1;
+
+}
+
+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 ();
+        
+        if (emit_load_parenthesized_deref_postfix_incdec_subscript_to_reg_now (reg)) {
+            return;
+        }
+    
+    }
+    
+    /*
+     * Do not special-case parenthesized assignment expressions here.
+     *
+     * The normal parenthesized-expression path below already recurses back
+     * into emit_load_assignment_rhs_expression_to_reg(), and the identifier
+     * operand parser below already _accepts assignment operators.  Using the
+     * old source-text detector here was wrong for nested grouping such as:
+     *
+     *     ((((reta <<= 1)) & 0x10))
+     *
+     * because it grerdily treated all leading '(' tokens as belonging to the
+     * assignment expression, including parentheses that actually enclose the
+     * later binary '&' expression.
+     */
+    if (_accept (TOK_LPAREN)) {
+    
+        char *paren_call_name = 0;
+        
+        const char *paren_call_start = 0;
+        const char *paren_call_caret = 0;
+        
+        unsigned long paren_call_line = 0;
+        
+        if (emit_load_deref_assignment_expression_to_reg_now (reg)) {
+            return;
+        }
+        
+        /*
+         * Function pointer call designator: (*fp)(args).
+         *
+         * If this is left to the normal parenthesized-expression path, the
+         * inner unary * path treats *fp as a data dereference and emits:
+         *
+         *     movq off(%rbp), %rax
+         *     movq (%rax), %rax
+         *
+         * That is correct for reading *p as an object, but wrong for a
+         * function designator.  In a call, the value of fp is already the
+         * target address, so load fp and call through it without the extra
+         * data load.  Keep this narrow: only handle the exact token form
+         * (*identifier)(...), and let every other parenthesized expression use
+         * the existing parser.
+         */
+        if (tok.kind == TOK_STAR && tok.caret) {
+        
+            const char *p = tok.caret + 1;
+            const char *name_start;
+            const char *name_caret;
+            
+            unsigned long name_line;
+            char *name;
+            
+            struct local_symbol *src;
+            
+            int global_index;
+            int looks_like_call = 0;
+            
+            if (emit_load_parenthesized_deref_postfix_incdec_subscript_to_reg_now (reg)) {
+                return;
+            }
+            
+            while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+                p++;
+            }
+            
+            if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_') {
+            
+                p++;
+                
+                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++;
+                    
+                    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+                        p++;
+                    }
+                    
+                    looks_like_call = (*p == '(');
+                
+                }
+            
+            }
+            
+            if (looks_like_call) {
+            
+                get_token ();
+                
+                name_start = tok.start;
+                name_caret = tok.caret;
+                name_line = get_line_number ();
+                
+                if (tok.kind != TOK_IDENT || !tok.ident) {
+                
+                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
+                    return;
+                
+                }
+                
+                name = xstrdup (tok.ident);
+                get_token ();
+                
+                expect (TOK_RPAREN, ")");
+                
+                src = find_local_symbol (name);
+                global_index = find_global_symbol (name);
+                
+                if (src) {
+                
+                    if (src->is_static && src->static_label) {
+                        emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+                    }
+                
+                } else if (global_index >= 0) {
+                    emit_load_global_to_reg (reg, name, DATA_PTR);
+                } else {
+                
+                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+                    
+                    free (name);
+                    return;
+                
+                }
+                
+                free (name);
+                
+                emit_call_pointer_in_reg_now (reg, reg);
+                clear_rhs_last_pointer_info ();
+                
+                return;
+            
+            }
+        
+        }
+        
+        if (emit_load_parenthesized_indirect_member_to_reg_now (reg)) {
+            return;
+        }
+        
+        if (tok.kind == TOK_IDENT && tok.ident &&
+        
+            find_global_symbol (tok.ident) >= 0 &&
+            get_global_symbol_kind (tok.ident) == GLOBAL_SYMBOL_FUNCTION) {
+        
+            paren_call_name = xstrdup (tok.ident);
+            paren_call_start = tok.start;
+            paren_call_caret = tok.caret;
+            paren_call_line = get_line_number ();
+        
+        }
+        
+        if (!is_type_start (tok.kind) && parenthesized_function_designator_call_now ()) {
+        
+            char *call_name = xstrdup (tok.ident);
+            
+            const char *call_start = tok.start;
+            const char *call_caret = tok.caret;
+            
+            unsigned long call_line = get_line_number ();
+            get_token ();
+            
+            expect (TOK_RPAREN, ")");
+            
+            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, reg, call_start, call_caret, call_line);
+            free (call_name);
+            
+            return;
+        
+        }
+        
+        if (is_type_start (tok.kind)) {
+        
+            int saved_type_size = parsed_type_size;
+            int saved_storage_class = parsed_storage_class;
+            int saved_is_aggregate = parsed_type_is_aggregate;
+            int saved_is_void = parsed_type_is_void;
+            int saved_is_unsigned = parsed_type_is_unsigned;
+            int saved_is_floating = parsed_type_is_floating;
+            int saved_has_tag = parsed_type_has_tag;
+            int saved_is_inline = parsed_type_is_inline;
+            int saved_field_count = parsed_field_count;
+            int saved_fields[MAX_AGG_FIELDS];
+            int saved_declarator_is_pointer = declarator_is_pointer;
+            int saved_declarator_pointer_depth = declarator_pointer_depth;
+            int saved_declarator_has_array = declarator_has_array;
+            int saved_declarator_has_function = declarator_has_function;
+            int saved_declarator_array_unsized = declarator_array_unsized;
+            int saved_declarator_array_dimensions = declarator_array_dimensions;
+            
+            long saved_declarator_array_count = declarator_array_count;
+            long saved_declarator_first_array_count = declarator_first_array_count;
+            
+            char *cast_name = 0;
+            
+            int cast_base_size;
+            int cast_is_unsigned = 0;
+            int cast_pointer_depth = 0;
+            int cast_pointed_size = 0;
+            
+            int i;
+            
+            for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
+                saved_fields[i] = parsed_field_sizes[i];
+            }
+            
+            declarator_is_pointer = 0;
+            declarator_pointer_depth = 0;
+            declarator_has_array = 0;
+            declarator_has_function = 0;
+            declarator_array_unsized = 0;
+            declarator_array_count = 0;
+            declarator_first_array_count = 1;
+            
+            parse_type_spec ();
+            
+            cast_base_size = parsed_type_size & 0x1f;
+            cast_is_unsigned = parsed_type_is_unsigned;
+            
+            if (tok.kind != TOK_RPAREN) {
+                parse_declarator (&cast_name);
+            }
+            
+            if (declarator_is_pointer) {
+            
+                cast_pointer_depth = declarator_pointer_depth > 0 ? declarator_pointer_depth : 1;
+                cast_pointed_size = cast_pointer_depth > 1 ? (DATA_PTR & 0x1f) : cast_base_size;
+                
+                if (cast_pointed_size <= 0) {
+                    cast_pointed_size = DATA_INT & 0x1f;
+                }
+            
+            }
+            
+            if (cast_name) {
+                free (cast_name);
+            }
+            
+            expect (TOK_RPAREN, ")");
+            
+            parsed_type_size = saved_type_size;
+            parsed_storage_class = saved_storage_class;
+            parsed_type_is_aggregate = saved_is_aggregate;
+            parsed_type_is_void = saved_is_void;
+            parsed_type_is_unsigned = saved_is_unsigned;
+            parsed_type_is_floating = saved_is_floating;
+            parsed_type_has_tag = saved_has_tag;
+            parsed_type_is_inline = saved_is_inline;
+            
+            clear_parsed_fields ();
+            
+            for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
+                parsed_field_sizes[i] = saved_fields[i];
+            }
+            
+            parsed_field_count = saved_field_count;
+            
+            declarator_is_pointer = saved_declarator_is_pointer;
+            declarator_pointer_depth = saved_declarator_pointer_depth;
+            declarator_has_array = saved_declarator_has_array;
+            declarator_has_function = saved_declarator_has_function;
+            declarator_array_unsized = saved_declarator_array_unsized;
+            declarator_array_count = saved_declarator_array_count;
+            declarator_first_array_count = saved_declarator_first_array_count;
+            declarator_array_dimensions = saved_declarator_array_dimensions;
+            
+            emit_load_assignment_rhs_to_reg (reg);
+            
+            while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+                emit_apply_postfix_member_access_to_reg_now (reg);
+            }
+            
+            if (tok.kind == TOK_LBRACK) {
+            
+                int cast_subscript_elem_size = cast_pointer_depth > 1 ? (DATA_PTR & 0x1f) : cast_pointed_size;
+                
+                if (cast_subscript_elem_size <= 0) {
+                    cast_subscript_elem_size = DATA_INT & 0x1f;
+                }
+                
+                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, cast_subscript_elem_size);
+                emit_load_deref_reg_now (reg, cast_subscript_elem_size);
+            
+            }
+            
+            if (cast_pointer_depth > 0) {
+                set_rhs_last_pointer_info (cast_pointer_depth, cast_pointed_size);
+            } else {
+            
+                emit_apply_integer_cast_to_reg_now (reg, cast_base_size, cast_is_unsigned);
+                clear_rhs_last_pointer_info ();
+            
+            }
+            
+            return;
+        
+        }
+        
+        if (tok.kind != TOK_LPAREN && current_integer_expr_is_foldable_now ()) {
+        
+            int64_s v = const64_from_current_foldable_expr ();
+            expect (TOK_RPAREN, ")");
+            
+            emit_load_const32_to_reg_now (reg, v);
+            return;
+        
+        }
+        
+        emit_load_assignment_rhs_expression_to_reg (reg);
+        
+        if (postfix_member_seen && (tok.kind == TOK_INCR || tok.kind == TOK_DECR)) {
+        
+            enum token_kind postfix_op = tok.kind;
+            get_token ();
+            emit_apply_postfix_member_incdec_now (reg, postfix_op);
+        
+        }
+        
+        while (tok.kind == TOK_COMMA) {
+        
+            get_token ();
+            emit_load_assignment_rhs_expression_to_reg (reg);
+        
+        }
+        
+        if (is_assignment_operator (tok.kind)) {
+        
+            get_token ();
+            emit_load_assignment_rhs_expression_to_reg (reg);
+        
+        }
+        
+        if (paren_call_name && tok.kind == TOK_RPAREN) {
+        
+            get_token ();
+            
+            if (tok.kind == TOK_LPAREN) {
+            
+                if (!find_local_symbol (paren_call_name)) {
+                    ensure_global_function_symbol (paren_call_name, paren_call_start, paren_call_caret, paren_call_line);
+                }
+                
+                emit_call_identifier_to_reg_now (paren_call_name, reg, paren_call_start, paren_call_caret, paren_call_line);
+                free (paren_call_name);
+                
+                return;
+            
+            }
+        
+        } else {
+            expect (TOK_RPAREN, ")");
+        }
+        
+        if (paren_call_name) {
+            free (paren_call_name);
+        }
+        
+        if (tok.kind == TOK_LBRACK) {
+        
+            int subscript_pointer_depth = rhs_last_pointer_depth;
+            int subscript_elem_size = rhs_last_pointed_size;
+            
+            if (subscript_elem_size <= 0) {
+                subscript_elem_size = DATA_INT & 0x1f;
+            }
+            
+            emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, subscript_elem_size);
+            
+            if (is_assignment_operator (tok.kind)) {
+            
+                enum token_kind assign_op = tok.kind;
+                
+                get_token ();
+                emit_push_reg_now (reg);
+                
+                if (assign_op == TOK_ASSIGN && subscript_elem_size > (DATA_LLONG & 0x1f) &&
+                    tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now ()) {
+                
+                    char *rhs_name = xstrdup (tok.ident);
+                    
+                    const char *rhs_start = tok.start;
+                    const char *rhs_caret = tok.caret;
+                    
+                    unsigned long rhs_line = get_line_number ();
+                    
+                    pending_struct_return_lhs = 0;
+                    pending_struct_return_global_name = 0;
+                    pending_struct_return_stack_address = 1;
+                    pending_struct_return_stack_offset = 0;
+                    
+                    get_token ();
+                    emit_call_identifier_to_reg_now (rhs_name, reg, rhs_start, rhs_caret, rhs_line);
+                    
+                    pending_struct_return_stack_address = 0;
+                    pending_struct_return_stack_offset = 0;
+                    
+                    emit_pop_reg_now ("rdx");
+                    free (rhs_name);
+                    
+                    set_rhs_last_pointer_info (0, 0);
+                    return;
+                
+                } else if (assign_op == TOK_ASSIGN) {
+                
+                    if (subscript_elem_size > (DATA_LLONG & 0x1f)) {
+                    
+                        pending_struct_return_lhs = 0;
+                        pending_struct_return_global_name = 0;
+                        pending_struct_return_stack_address = 1;
+                        pending_struct_return_stack_offset = 0;
+                        
+                        emit_load_assignment_rhs_expression_to_reg (reg);
+                        
+                        pending_struct_return_stack_address = 0;
+                        pending_struct_return_stack_offset = 0;
+                        
+                        emit_pop_reg_now ("rdx");
+                        set_rhs_last_pointer_info (0, 0);
+                        
+                        return;
+                    
+                    }
+                    
+                    emit_load_assignment_rhs_expression_to_reg (reg);
+                
+                } else {
+                
+                    emit_load_deref_reg_now (reg, subscript_elem_size);
+                    emit_push_reg_now (reg);
+                    
+                    emit_load_assignment_rhs_expression_to_reg ("rdx");
+                    emit_pop_reg_now (reg);
+                    
+                    emit_assignment_binary_op (assign_op, 0);
+                
+                }
+                
+                emit_pop_reg_now ("rdx");
+                
+                emit_store_reg_to_deref_reg_now ("rdx", reg, subscript_elem_size);
+                set_rhs_last_pointer_info (0, 0);
+                
+                return;
+            
+            }
+            
+            emit_load_deref_reg_now (reg, subscript_elem_size);
+            
+            if (subscript_pointer_depth > 0) {
+                subscript_pointer_depth--;
+            }
+            
+            if (subscript_pointer_depth > 0) {
+                set_rhs_last_pointer_info (subscript_pointer_depth, subscript_elem_size);
+            } else {
+                set_rhs_last_pointer_info (0, 0);
+            }
+        
+        }
+        
+        if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+            emit_apply_postfix_member_access_to_reg_now (reg);
+        }
+        
+        if (postfix_member_seen && tok.kind == TOK_LPAREN) {
+        
+            emit_call_pointer_in_reg_now (reg, reg);
+            
+            set_rhs_last_pointer_info (0, 0);
+            return;
+        
+        }
+        
+        if (postfix_member_seen) {
+        
+            set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
+            
+            if (is_assignment_operator (tok.kind)) {
+            
+                enum token_kind op = tok.kind;
+                
+                int assign_member_offset = postfix_member_offset;
+                int assign_member_size = postfix_member_size;
+                
+                get_token ();
+                
+                if (state->ofp) {
+                
+                    if (op == TOK_ASSIGN) {
+                    
+                        if (postfix_member_is_floating || token_is_floating_constant_now () || rhs_current_operand_is_floating_now ()) {
+                        
+                            emit_push_reg_now ("rdx");
+                            emit_load_floating_rhs_expression_now (assign_member_size);
+                            
+                            emit_pop_reg_now ("rdx");
+                            emit_store_floating_member_to_addr_reg_now ("rdx", assign_member_offset, assign_member_size);
+                            
+                            return;
+                        
+                        }
+                        
+                        if (assign_member_size > (DATA_LLONG & 0x1f) &&
+                            tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now ()) {
+                        
+                            char *rhs_name = xstrdup (tok.ident);
+                            
+                            const char *rhs_start = tok.start;
+                            const char *rhs_caret = tok.caret;
+                            
+                            unsigned long rhs_line = get_line_number ();
+                            emit_push_reg_now ("rdx");
+                            
+                            pending_struct_return_lhs = 0;
+                            pending_struct_return_global_name = 0;
+                            pending_struct_return_stack_address = 1;
+                            pending_struct_return_stack_offset = assign_member_offset;
+                            
+                            get_token ();
+                            emit_call_identifier_to_reg_now (rhs_name, reg, rhs_start, rhs_caret, rhs_line);
+                            
+                            pending_struct_return_stack_address = 0;
+                            pending_struct_return_stack_offset = 0;
+                            
+                            emit_pop_reg_now ("rdx");
+                            free (rhs_name);
+                            
+                            return;
+                        
+                        }
+                        
+                        if (emit_aggregate_copy_from_current_rhs_to_addr_reg_now ("rdx", assign_member_offset, assign_member_size)) {
+                            return;
+                        }
+                        
+                        emit_push_reg_now ("rdx");
+                        
+                        emit_load_assignment_rhs_expression_to_reg (reg);
+                        emit_pop_reg_now ("rdx");
+                    
+                    } else {
+                    
+                        /*
+                         * emit_apply_postfix_member_access_to_reg_now() has already
+                         * loaded the member value into reg and left the containing
+                         * object address in rdx.  Do not load the member again from
+                         * reg: for p->m |= x that treats the old value of m as a
+                         * pointer and dereferences it, which corrupts/segfaults code
+                         * such as section->symbol->flags |= SYMBOL_FLAG_SECTION_SYMBOL.
+                         */
+                        emit_push_reg_now ("rdx");
+                        emit_push_reg_now (reg);
+                        
+                        emit_load_assignment_rhs_expression_to_reg ("rdx");
+                        emit_pop_reg_now (reg);
+                        
+                        emit_assignment_binary_op (op, 0);
+                        emit_pop_reg_now ("rdx");
+                    
+                    }
+                    
+                    emit_store_member_to_addr_reg_now ("rdx", assign_member_offset, reg, assign_member_size);
+                
+                } else {
+                    emit_load_assignment_rhs_expression_to_reg (reg);
+                }
+            
+            }
+        
+        }
+        
+        /*
+         * This routine parses one primary operand for the outer binary
+         * expression parser.  After returning, the caller can still consume
+         * any trailing operator, e.g. the / b in:
+         *
+         *     (a + b - 1) / b
+         */
+        return;
+    
+    } else if (tok.kind == TOK_AMPER) {
+    
+        char *name;
+        
+        const char *name_start;
+        const char *name_caret;
+        
+        unsigned long name_line;
+        struct local_symbol *src;
+        
+        get_token ();
+        
+        if (tok.kind == TOK_LPAREN) {
+        
+            if (emit_load_address_of_parenthesized_postfix_to_reg_now (reg)) {
+                return;
+            }
+        
+        }
+        
+        name_start = tok.start;
+        name_caret = tok.caret;
+        name_line = get_line_number ();
+        
+        if (tok.kind != TOK_IDENT) {
+        
+            int64_s zero;
+            
+            zero.low = 0;
+            zero.high = 0;
+            
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after '&'");
+            
+            emit_load_const32_to_reg_now (reg, zero);
+            return;
+        
+        }
+        
+        name = xstrdup (tok.ident);
+        get_token ();
+        
+        src = find_local_symbol (name);
+        
+        if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+        
+            int global_index = find_global_symbol (name);
+            
+            const char *current_object_tag_name = 0;
+            int current_object_size = 0;
+            
+            if (src) {
+            
+                if (tok.kind == TOK_DOT || src->is_array) {
+                
+                    current_object_size = src->is_array && src->pointed_size > 0 ? src->pointed_size : src->size;
+                    current_object_tag_name = src->is_array ? (src->pointed_tag_name ? src->pointed_tag_name : src->tag_name) : 0;
+                    
+                    if (src->is_static && src->static_label) {
+                        emit_load_address_to_reg_now (reg, src->static_label);
+                    } else {
+                        emit_load_local_address_to_reg_now (reg, src->offset);
+                    }
+                
+                } else if (src->is_static && src->static_label) {
+                
+                    current_object_size = src->pointed_size > 0 ? src->pointed_size : DATA_PTR;
+                    current_object_tag_name = src->pointed_tag_name;
+                    
+                    emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
+                
+                } else {
+                
+                    current_object_size = src->pointed_size > 0 ? src->pointed_size : DATA_PTR;
+                    current_object_tag_name = src->pointed_tag_name;
+                    
+                    emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+                
+                }
+            
+            } else if (global_index >= 0) {
+            
+                if (tok.kind == TOK_DOT || get_global_symbol_array (name)) {
+                
+                    current_object_size = get_global_symbol_array (name) && get_global_symbol_pointed_size (name) > 0 ? get_global_symbol_pointed_size (name) : get_global_symbol_size (name);
+                    current_object_tag_name = get_global_symbol_tag_name (name);
+                    
+                    emit_load_address_to_reg_now (reg, name);
+                
+                } else {
+                
+                    current_object_size = get_global_symbol_pointed_size (name) > 0 ? get_global_symbol_pointed_size (name) : DATA_PTR;
+                    current_object_tag_name = get_global_symbol_tag_name (name);
+                    
+                    emit_load_global_to_reg (reg, name, DATA_PTR);
+                
+                }
+            
+            } else {
+            
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+                
+                free (name);
+                return;
+            
+            }
+            
+            while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+            
+                enum token_kind member_op = tok.kind;
+                char *member;
+                
+                const char *member_start;
+                const char *member_caret;
+                
+                unsigned long member_line;
+                
+                int offset = 0;
+                int member_size = DATA_INT & 0x1f;
+                int elem_size = DATA_INT & 0x1f;
+                int pointer_depth = 0;
+                
+                get_token ();
+                
+                member_start = tok.start;
+                member_caret = tok.caret;
+                member_line = get_line_number ();
+                
+                if (tok.kind != TOK_IDENT) {
+                
+                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+                    
+                    free (name);
+                    return;
+                
+                }
+                
+                member = xstrdup (tok.ident);
+                get_token ();
+                
+                if (!find_member_info_ex_bounded (member, current_object_size, current_object_tag_name, &offset, &member_size, &elem_size, &pointer_depth, 0, 0)) {
+                
+                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+                    
+                    free (member);
+                    free (name);
+                    
+                    return;
+                
+                }
+                
+                current_object_tag_name = last_found_member_tag_name;
+                free (member);
+                
+                if (state->ofp && offset != 0) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+                    } else {
+                        fprintf (state->ofp, "    addq $%d, %%%s\n", offset, reg);
+                    }
+                
+                }
+                
+                if (tok.kind == TOK_LBRACK) {
+                
+                    if (pointer_depth > 0) {
+                    
+                        emit_load_member_from_addr_reg_now (reg, reg, 0, DATA_PTR & 0x1f);
+                        emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
+                    
+                    } else {
+                        emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
+                    }
+                
+                } else if (pointer_depth > 0 && (tok.kind == TOK_ARROW || tok.kind == TOK_DOT)) {
+                    emit_load_member_from_addr_reg_now (reg, reg, 0, DATA_PTR & 0x1f);
+                }
+                
+                if (pointer_depth > 0) {
+                    current_object_size = elem_size > 0 ? elem_size : DATA_PTR;
+                } else {
+                    current_object_size = member_size;
+                }
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_LBRACK) {
+        
+            if (src) {
+            
+                int elem_size = src->is_array ? (src->pointer_depth ? DATA_PTR : (src->array_element_size > 0 ? src->array_element_size : src->pointed_size)) :
+                    (src->pointer_depth > 1 ? DATA_PTR : src->pointed_size);
+                
+                if (elem_size <= 0) {
+                    elem_size = DATA_INT & 0x1f;
+                }
+                
+                if (src->is_array) {
+                
+                    if (src->is_static && src->static_label) {
+                        emit_load_address_to_reg_now (reg, src->static_label);
+                    } else {
+                        emit_load_local_address_to_reg_now (reg, src->offset);
+                    }
+                
+                } else if (src->is_static && src->static_label) {
+                    emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+                }
+                
+                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
+                
+                if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+                
+                    const char *current_object_tag_name = src->is_array ? (src->tag_name ? src->tag_name : src->pointed_tag_name) : src->pointed_tag_name;
+                    int current_object_size = elem_size;
+                    
+                    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+                    
+                        enum token_kind member_op = tok.kind;
+                        char *member;
+                        
+                        const char *member_start;
+                        const char *member_caret;
+                        
+                        unsigned long member_line;
+                        
+                        int offset = 0;
+                        int member_size = DATA_INT & 0x1f;
+                        int member_elem_size = DATA_INT & 0x1f;
+                        int member_pointer_depth = 0;
+                        
+                        get_token ();
+                        
+                        member_start = tok.start;
+                        member_caret = tok.caret;
+                        member_line = get_line_number ();
+                        
+                        if (tok.kind != TOK_IDENT) {
+                        
+                            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+                            
+                            free (name);
+                            return;
+                        
+                        }
+                        
+                        member = xstrdup (tok.ident);
+                        get_token ();
+                        
+                        if (!find_member_info_ex_bounded (member, current_object_size, current_object_tag_name, &offset, &member_size, &member_elem_size, &member_pointer_depth, 0, 0)) {
+                        
+                            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+                            
+                            free (member);
+                            free (name);
+                            
+                            return;
+                        
+                        }
+                        
+                        current_object_tag_name = last_found_member_tag_name;
+                        free (member);
+                        
+                        if (state->ofp && offset != 0) {
+                        
+                            if (state->syntax & ASM_SYNTAX_INTEL) {
+                                fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+                            } else {
+                                fprintf (state->ofp, "    addq $%d, %%%s\n", offset, reg);
+                            }
+                        
+                        }
+                        
+                        if (tok.kind == TOK_LBRACK) {
+                        
+                            if (member_pointer_depth > 0) {
+                                emit_load_member_from_addr_reg_now (reg, reg, 0, DATA_PTR & 0x1f);
+                            }
+                            
+                            emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, member_elem_size > 0 ? member_elem_size : DATA_INT & 0x1f);
+                        
+                        } else if (member_pointer_depth > 0 && (tok.kind == TOK_ARROW || tok.kind == TOK_DOT)) {
+                            emit_load_member_from_addr_reg_now (reg, reg, 0, DATA_PTR & 0x1f);
+                        }
+                        
+                        if (member_pointer_depth > 0) {
+                            current_object_size = member_elem_size > 0 ? member_elem_size : DATA_PTR;
+                        } else {
+                            current_object_size = member_size;
+                        }
+                    
+                    }
+                
+                }
+                
+                free (name);
+                return;
+            
+            }
+            
+            if (find_global_symbol (name) >= 0) {
+            
+                int elem_size = get_global_symbol_array (name) ?
+                    (get_global_symbol_pointer_depth (name) ? DATA_PTR : (get_global_symbol_array_element_size (name) > 0 ? get_global_symbol_array_element_size (name) : get_global_symbol_pointed_size (name))) :
+                        (get_global_symbol_pointer_depth (name) > 1 ? DATA_PTR : get_global_symbol_pointed_size (name));
+                
+                if (elem_size <= 0) {
+                    elem_size = DATA_INT & 0x1f;
+                }
+                
+                if (get_global_symbol_array (name)) {
+                    emit_load_address_to_reg_now (reg, name);
+                } else {
+                    emit_load_global_to_reg (reg, name, DATA_PTR);
+                }
+                
+                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
+                
+                free (name);
+                return;
+            
+            }
+        
+        }
+        
+        if (src) {
+        
+            if (src->is_static && src->static_label) {
+                emit_load_address_to_reg_now (reg, src->static_label);
+            } else {
+                emit_load_local_address_to_reg_now (reg, src->offset);
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (find_global_symbol (name) >= 0) {
+        
+            emit_load_address_to_reg_now (reg, name);
+            
+            free (name);
+            return;
+        
+        }
+        
+        {
+        
+            int64_s zero;
+            
+            zero.low = 0;
+            zero.high = 0;
+            
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            
+            free (name);
+            emit_load_const32_to_reg_now (reg, zero);
+        
+        }
+        
+        return;
+    
+    } else if (tok.kind == TOK_STAR) {
+    
+        int deref_had_parens = 0;
+        int deref_size = DATA_CHAR & 0x1f;
+        int deref_pointer_depth = 0;
+        int deref_pointed_size = 0;
+        
+        if (emit_load_deref_parenthesized_deref_postfix_incdec_to_reg_now (reg)) {
+            return;
+        }
+        
+        if (emit_store_to_deref_parenthesized_deref_postfix_incdec_now (reg)) {
+            return;
+        }
+        
+        get_token ();
+        
+        if (tok.kind == TOK_IDENT) {
+        
+            char *lhs_name = xstrdup (tok.ident);
+            
+            const char *lhs_start = tok.start;
+            const char *lhs_caret = tok.caret;
+            
+            unsigned long lhs_line = get_line_number ();
+            struct local_symbol *lhs_sym;
+            
+            enum token_kind lhs_postfix_op = TOK_EOF;
+            enum token_kind member_op = TOK_EOF;
+            
+            char *member;
+            
+            const char *member_start;
+            const char *member_caret;
+            
+            unsigned long member_line;
+            
+            int lhs_has_postfix = 0;
+            int offset = 0;
+            
+            int member_size = DATA_PTR & 0x1f;
+            int member_elem_size = DATA_INT & 0x1f;
+            int member_pointer_depth = 0;
+            int member_load_size = DATA_PTR & 0x1f;
+            
+            get_token ();
+            
+            if (tok.kind == TOK_LPAREN &&
+                find_global_symbol (lhs_name) >= 0 &&
+                get_global_symbol_kind (lhs_name) == GLOBAL_SYMBOL_FUNCTION) {
+            
+                int fptr_depth = get_global_symbol_pointer_depth (lhs_name);
+                int fpointed_size = get_global_symbol_pointed_size (lhs_name);
+                
+                emit_call_identifier_to_reg_now (lhs_name, reg, lhs_start, lhs_caret, lhs_line);
+                
+                if (fptr_depth > 1) {
+                    deref_size = DATA_PTR;
+                } else if (fptr_depth == 1 && fpointed_size > 0) {
+                    deref_size = fpointed_size;
+                }
+                
+                emit_load_deref_reg_now (reg, deref_size);
+                
+                free (lhs_name);
+                return;
+            
+            }
+            
+            if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+            
+                member_op = tok.kind;
+                get_token ();
+                
+                member_start = tok.start;
+                member_caret = tok.caret;
+                member_line = get_line_number ();
+                
+                if (tok.kind != TOK_IDENT) {
+                
+                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+                    
+                    free (lhs_name);
+                    return;
+                
+                }
+                
+                member = xstrdup (tok.ident);
+                get_token ();
+                
+                if (!find_member_info_ex (member, &offset, &member_size, &member_elem_size, &member_pointer_depth, 0, 0)) {
+                
+                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+                    
+                    free (member);
+                    free (lhs_name);
+                    
+                    return;
+                
+                }
+                
+                free (member);
+                
+                if (member_pointer_depth > 0) {
+                    member_load_size = DATA_PTR & 0x1f;
+                } else {
+                    member_load_size = member_size;
+                }
+                
+                if (member_pointer_depth > 1) {
+                    deref_size = DATA_PTR;
+                } else if (member_pointer_depth == 1 && member_elem_size > 0) {
+                    deref_size = member_elem_size;
+                }
+                
+                if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+                
+                    lhs_has_postfix = 1;
+                    lhs_postfix_op = tok.kind;
+                    
+                    get_token ();
+                
+                }
+                
+                if (tok.kind == TOK_ASSIGN) {
+                
+                    lhs_sym = find_local_symbol (lhs_name);
+                    
+                    if (lhs_sym) {
+                    
+                        if (lhs_sym->is_static && lhs_sym->static_label) {
+                            emit_load_global_to_reg ("rdx", lhs_sym->static_label, DATA_PTR);
+                        } else {
+                            emit_load_local_to_reg ("rdx", lhs_sym->offset, DATA_PTR);
+                        }
+                    
+                    } else if (find_global_symbol (lhs_name) >= 0) {
+                        emit_load_global_to_reg ("rdx", lhs_name, DATA_PTR);
+                    } else {
+                        report_line_at (get_filename (), lhs_line, REPORT_ERROR, lhs_start, lhs_caret, "unknown symbol '%s'", lhs_name);
+                    }
+                    
+                    if (state->ofp && offset != 0) {
+                    
+                        if (state->syntax & ASM_SYNTAX_INTEL) {
+                            fprintf (state->ofp, "    add rdx, %d\n", offset);
+                        } else {
+                            fprintf (state->ofp, "    addq $%d, %%rdx\n", offset);
+                        }
+                    
+                    }
+                    
+                    emit_push_reg_now ("rdx");
+                    get_token ();
+                    
+                    emit_load_assignment_rhs_expression_to_reg (reg);
+                    
+                    emit_pop_reg_now ("rdx");
+                    emit_store_reg_to_deref_reg_now ("rdx", reg, member_load_size);
+                    
+                    free (lhs_name);
+                    return;
+                
+                }
+                
+                lhs_sym = find_local_symbol (lhs_name);
+                
+                if (lhs_sym) {
+                
+                    if (member_op == TOK_DOT) {
+                    
+                        if (lhs_sym->is_static && lhs_sym->static_label) {
+                            emit_load_address_to_reg_now (reg, lhs_sym->static_label);
+                        } else {
+                            emit_load_local_address_to_reg_now (reg, lhs_sym->offset);
+                        }
+                    
+                    } else if (lhs_sym->is_static && lhs_sym->static_label) {
+                        emit_load_global_to_reg (reg, lhs_sym->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg (reg, lhs_sym->offset, DATA_PTR);
+                    }
+                
+                } else if (find_global_symbol (lhs_name) >= 0) {
+                
+                    if (member_op == TOK_DOT) {
+                        emit_load_address_to_reg_now (reg, lhs_name);
+                    } else {
+                        emit_load_global_to_reg (reg, lhs_name, DATA_PTR);
+                    }
+                
+                } else {
+                    report_line_at (get_filename (), lhs_line, REPORT_ERROR, lhs_start, lhs_caret, "unknown symbol '%s'", lhs_name);
+                }
+                
+                if (member_size > (DATA_PTR & 0x1f) && member_pointer_depth == 0) {
+                
+                    if (state->ofp && offset != 0) {
+                    
+                        if (state->syntax & ASM_SYNTAX_INTEL) {
+                            fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+                        } else {
+                            fprintf (state->ofp, "    addq $%d, %%%s\n", offset, reg);
+                        }
+                    
+                    }
+                
+                } else {
+                    emit_load_member_from_addr_reg_now (reg, reg, offset, member_load_size);
+                }
+                
+                if (lhs_has_postfix) {
+                    /* Already applied above only for assignment forms. */
+                }
+                
+                if (member_pointer_depth > 0) {
+                    set_rhs_last_pointer_info (member_pointer_depth, member_elem_size);
+                } else {
+                    clear_rhs_last_pointer_info ();
+                }
+                
+                free (lhs_name);
+                return;
+            
+            }
+            
+            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+            
+                lhs_has_postfix = 1;
+                lhs_postfix_op = tok.kind;
+                
+                get_token ();
+            
+            }
+            
+            if (tok.kind == TOK_ASSIGN) {
+            
+                int lhs_deref_is_unsigned = 1;
+                lhs_sym = find_local_symbol (lhs_name);
+                
+                if (lhs_sym) {
+                
+                    if (lhs_sym->pointer_depth > 1) {
+                        deref_size = DATA_PTR & 0x1f;
+                    } else if (lhs_sym->pointer_depth == 1 && lhs_sym->pointed_size > 0) {
+                    
+                        /**
+                         * Keep the full pointed-to object size here.  This
+                         * assignment path also handles aggregate lvalues such
+                         * as *hashtab = old_hashtab;  Masking with 0x1f turns
+                         * a 44-byte struct hashtab into 12 and emits a partial
+                         * copy, corrupting pdas hashtab state during rehash().
+                         */
+                        deref_size = lhs_sym->pointed_size;
+                    
+                    }
+                    
+                    if (member_op == TOK_DOT) {
+                    
+                        if (lhs_sym->is_static && lhs_sym->static_label) {
+                            emit_load_address_to_reg_now ("rdx", lhs_sym->static_label);
+                        } else {
+                            emit_load_local_address_to_reg_now ("rdx", lhs_sym->offset);
+                        }
+                    
+                    } else if (lhs_sym->is_static && lhs_sym->static_label) {
+                        emit_load_global_to_reg ("rdx", lhs_sym->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg ("rdx", lhs_sym->offset, DATA_PTR);
+                    }
+                
+                } else if (find_global_symbol (lhs_name) >= 0) {
+                
+                    if (get_global_symbol_pointer_depth (lhs_name) > 1) {
+                        deref_size = DATA_PTR & 0x1f;
+                    } else if (get_global_symbol_pointer_depth (lhs_name) == 1 && get_global_symbol_pointed_size (lhs_name) > 0) {
+                        deref_size = get_global_symbol_pointed_size (lhs_name);
+                    }
+                    
+                    if (member_op == TOK_DOT) {
+                        emit_load_address_to_reg_now ("rdx", lhs_name);
+                    } else {
+                        emit_load_global_to_reg ("rdx", lhs_name, DATA_PTR);
+                    }
+                
+                } else {
+                    report_line_at (get_filename (), lhs_line, REPORT_ERROR, lhs_start, lhs_caret, "unknown symbol '%s'", lhs_name);
+                }
+                
+                emit_push_reg_now ("rdx");
+                
+                if (lhs_has_postfix) {
+                    emit_incdec_symbol_now (lhs_sym, lhs_name, lhs_postfix_op, lhs_line, lhs_start, lhs_caret);
+                }
+                
+                get_token ();
+                
+                if (deref_size > (DATA_LLONG & 0x1f)) {
+                
+                    emit_pop_reg_now ("rdx");
+                    
+                    if (!emit_store_assignment_to_aggregate_address_now ("rdx", deref_size, lhs_start, lhs_caret, lhs_line)) {
+                        report_line_at (get_filename (), lhs_line, REPORT_ERROR, lhs_start, lhs_caret, "aggregate assignment expression not implemented");
+                    }
+                
+                } else if (deref_size == (DATA_LLONG & 0x1f)) {
+                
+                    emit_load_assignment_rhs_expression_to_pair ("rax", "rdx", lhs_deref_is_unsigned);
+                    emit_pop_reg_now ("rcx");
+                    
+                    emit_store_pair_to_deref_reg_now ("rcx", "rax", "rdx");
+                
+                } else {
+                
+                    emit_load_assignment_rhs_expression_to_reg (reg);
+                    emit_pop_reg_now ("rdx");
+                    
+                    emit_store_reg_to_deref_reg_now ("rdx", reg, deref_size);
+                
+                }
+                
+                free (lhs_name);
+                return;
+            
+            }
+            
+            lhs_sym = find_local_symbol (lhs_name);
+            
+            if (lhs_sym) {
+            
+                if (lhs_sym->is_static && lhs_sym->static_label) {
+                    emit_load_global_to_reg (reg, lhs_sym->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg (reg, lhs_sym->offset, DATA_PTR);
+                }
+                
+                if (lhs_has_postfix) {
+                
+                    emit_push_reg_now (reg);
+                    emit_incdec_symbol_now (lhs_sym, lhs_name, lhs_postfix_op, lhs_line, lhs_start, lhs_caret);
+                    emit_pop_reg_now (reg);
+                
+                }
+                
+                if (lhs_sym->pointer_depth > 1) {
+                    deref_size = DATA_PTR;
+                } else if (lhs_sym->pointer_depth == 1) {
+                    deref_size = lhs_sym->pointed_size;
+                }
+                
+                emit_load_deref_reg_now (reg, deref_size);
+                
+                if (lhs_sym->pointer_depth > 1) {
+                    set_rhs_last_pointer_info (lhs_sym->pointer_depth - 1, lhs_sym->pointed_size);
+                } else {
+                    clear_rhs_last_pointer_info ();
+                }
+                
+                if (emit_handle_subscript_after_loaded_pointer_to_reg_now (reg, lhs_sym->pointer_depth > 0 ? lhs_sym->pointer_depth - 1 : 0, lhs_sym->pointed_size, lhs_sym->pointed_is_unsigned)) {
+                
+                    free (lhs_name);
+                    return;
+                
+                }
+                
+                free (lhs_name);
+                return;
+            
+            }
+            
+            if (find_global_symbol (lhs_name) >= 0) {
+            
+                emit_load_global_to_reg (reg, lhs_name, DATA_PTR);
+                
+                if (lhs_has_postfix) {
+                
+                    emit_push_reg_now (reg);
+                    
+                    emit_incdec_symbol_now (0, lhs_name, lhs_postfix_op, lhs_line, lhs_start, lhs_caret);
+                    emit_pop_reg_now (reg);
+                
+                }
+                
+                if (get_global_symbol_pointer_depth (lhs_name) > 1) {
+                    deref_size = DATA_PTR;
+                } else if (get_global_symbol_pointer_depth (lhs_name) == 1) {
+                    deref_size = get_global_symbol_pointed_size (lhs_name);
+                }
+                
+                emit_load_deref_reg_now (reg, deref_size);
+                
+                if (get_global_symbol_pointer_depth (lhs_name) > 1) {
+                    set_rhs_last_pointer_info (get_global_symbol_pointer_depth (lhs_name) - 1, get_global_symbol_pointed_size (lhs_name));
+                } else {
+                    clear_rhs_last_pointer_info ();
+                }
+                
+                if (emit_handle_subscript_after_loaded_pointer_to_reg_now (reg, get_global_symbol_pointer_depth (lhs_name) > 0 ? get_global_symbol_pointer_depth (lhs_name) - 1 : 0, get_global_symbol_pointed_size (lhs_name), get_global_symbol_pointed_is_unsigned (lhs_name))) {
+                
+                    free (lhs_name);
+                    return;
+                
+                }
+                
+                free (lhs_name);
+                return;
+            
+            }
+            
+            report_line_at (get_filename (), lhs_line, REPORT_ERROR, lhs_start, lhs_caret, "unknown symbol '%s'", lhs_name);
+            free (lhs_name);
+            
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_LPAREN) {
+        
+            deref_had_parens = 1;
+            get_token ();
+            
+            if (is_type_start (tok.kind)) {
+            
+                if (parse_deref_cast_type_name (&deref_size)) {
+                
+                    /*
+                     * parse_deref_cast_type_name() consumes the cast parentheses
+                     * only.  Do not consume a following ')' here: in expressions
+                     * such as:
+                     *
+                     *     __munmap(ptr, *(size_t *)ptr + sizeof(size_t))
+                     *
+                     * that ')' belongs to the surrounding call.  Consuming it
+                     * here makes the caller report a false "expected )".
+                     */
+                    
+                    if (tok.kind == TOK_ASSIGN) {
+                    
+                        get_token ();
+                        
+                        emit_push_reg_now (reg);
+                        emit_load_assignment_rhs_expression_to_reg (reg);
+                        
+                        emit_pop_reg_now ("rdx");
+                        emit_store_reg_to_deref_reg_now ("rdx", reg, deref_size);
+                        
+                        return;
+                    
+                    }
+                    
+                    /*
+                     * parse_deref_cast_type_name() consumes only the cast type
+                     * parentheses.  The operand being cast is still the current
+                     * token, e.g. the ptr in:
+                     *
+                     *     *(size_t *)ptr + sizeof(size_t)
+                     *
+                     * Load that address expression before applying the outer
+                     * unary '*'.  Otherwise the caller sees the unconsumed
+                     * identifier/operator and reports a false "expected )".
+                     */
+                    emit_load_assignment_rhs_to_reg (reg);
+                    goto dereference_loaded_address;
+                
+                }
+            
+            }
+            
+            if (tok.kind == TOK_AMPER) {
+            
+                char *name;
+                
+                const char *name_start;
+                const char *name_caret;
+                
+                unsigned long name_line;
+                struct local_symbol *dst;
+                
+                int global_index;
+                int dst_size;
+                
+                get_token ();
+                
+                name_start = tok.start;
+                name_caret = tok.caret;
+                name_line = get_line_number ();
+                
+                if (tok.kind == TOK_IDENT) {
+                
+                    name = xstrdup (tok.ident);
+                    
+                    get_token ();
+                    expect (TOK_RPAREN, ")");
+                    
+                    if (is_assignment_operator (tok.kind)) {
+                    
+                        get_token ();
+                        emit_load_assignment_rhs_expression_to_reg (reg);
+                        
+                        dst = find_local_symbol (name);
+                        global_index = find_global_symbol (name);
+                        
+                        if (dst) {
+                        
+                            dst_size = dst->size;
+                            
+                            if (dst->is_static && dst->static_label) {
+                                emit_store_reg_to_global (dst->static_label, dst_size, reg);
+                            } else {
+                                emit_store_reg_to_local (dst->offset, dst_size, reg);
+                            }
+                        
+                        } else if (global_index >= 0) {
+                        
+                            dst_size = get_global_symbol_size (name);
+                            emit_store_reg_to_global (name, dst_size, reg);
+                        
+                        } else {
+                            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+                        }
+                        
+                        free (name);
+                        return;
+                    
+                    }
+                    
+                    if (find_local_symbol (name) || find_global_symbol (name) >= 0) {
+                    
+                        dst = find_local_symbol (name);
+                        
+                        if (dst) {
+                        
+                            if (dst->is_static && dst->static_label) {
+                                emit_load_address_to_reg_now (reg, dst->static_label);
+                            } else {
+                                emit_load_local_address_to_reg_now (reg, dst->offset);
+                            }
+                        
+                        } else {
+                            emit_load_address_to_reg_now (reg, name);
+                        }
+                        
+                        free (name);
+                        goto dereference_loaded_address;
+                    
+                    }
+                    
+                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+                    free (name);
+                    
+                    return;
+                
+                }
+            
+            }
+        
+        }
+        
+        if (deref_had_parens) {
+        
+            emit_load_assignment_rhs_expression_to_reg (reg);
+            
+            if (rhs_last_pointer_depth > 1) {
+                deref_size = DATA_PTR;
+            } else if (rhs_last_pointer_depth == 1) {
+                deref_size = rhs_last_pointed_size;
+            }
+            
+            expect (TOK_RPAREN, ")");
+            
+            /*
+             * A parenthesized dereferenced function pointer is still a function
+             * designator when it is followed by an argument list.  For example:
+             *
+             *     (*generate_func)(outfile, pos)
+             *
+             * The inner expression already loaded the function pointer value into
+             * reg.  Do not dereference that value as data before the call; call
+             * through it directly.
+             */
+            if (tok.kind == TOK_LPAREN) {
+            
+                emit_call_pointer_in_reg_now (reg, reg);
+                
+                clear_rhs_last_pointer_info ();
+                return;
+            
+            }
+            
+            if (is_assignment_operator (tok.kind)) {
+            
+                enum token_kind assign_op = tok.kind;
+                
+                emit_push_reg_now (reg);
+                get_token ();
+                
+                if (assign_op == TOK_ASSIGN) {
+                    emit_load_assignment_rhs_expression_to_reg (reg);
+                } else {
+                
+                    emit_load_deref_reg_now (reg, deref_size);
+                    
+                    emit_push_reg_now (reg);
+                    emit_load_assignment_rhs_expression_to_reg ("rdx");
+                    
+                    emit_pop_reg_now (reg);
+                    emit_assignment_binary_op (assign_op, 0);
+                
+                }
+                
+                emit_pop_reg_now ("rdx");
+                emit_store_reg_to_deref_reg_now ("rdx", reg, deref_size);
+                
+                return;
+            
+            }
+            
+            if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+            
+                enum token_kind member_op = tok.kind;
+                enum token_kind postfix_op = TOK_EOF;
+                
+                char *member;
+                
+                const char *member_start;
+                const char *member_caret;
+                
+                unsigned long member_line;
+                
+                int offset = 0;
+                int member_size = DATA_PTR & 0x1f;
+                int member_elem_size = DATA_INT & 0x1f;
+                int member_pointer_depth = 0;
+                
+                get_token ();
+                
+                member_start = tok.start;
+                member_caret = tok.caret;
+                member_line = get_line_number ();
+                
+                if (tok.kind != TOK_IDENT) {
+                
+                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+                    return;
+                
+                }
+                
+                member = xstrdup (tok.ident);
+                get_token ();
+                
+                if (!find_member_info_ex (member, &offset, &member_size, &member_elem_size, &member_pointer_depth, 0, 0)) {
+                
+                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+                    
+                    free (member);
+                    return;
+                
+                }
+                
+                free (member);
+                
+                if (member_pointer_depth > 1) {
+                    deref_size = DATA_PTR;
+                } else if (member_pointer_depth == 1 && member_elem_size > 0) {
+                    deref_size = member_elem_size;
+                }
+                
+                if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+                
+                    postfix_op = tok.kind;
+                    get_token ();
+                
+                }
+                
+                if (state->ofp) {
+                
+                    int member_qword = (member_size == (DATA_PTR & 0x1f) || member_size == (DATA_LLONG & 0x1f));
+                    
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                    
+                        if (member_size == (DATA_CHAR & 0x1f)) {
+                        
+                            if (state->syntax & ASM_SYNTAX_NASM) {
+                                fprintf (state->ofp, member_pointer_depth || member_elem_size == (DATA_CHAR & 0x1f) ? "    movzx edx, byte [%s + %d]\n" : "    movsx rdx, byte [%s + %d]\n", reg, offset);
+                            } else {
+                                fprintf (state->ofp, member_pointer_depth || member_elem_size == (DATA_CHAR & 0x1f) ? "    movzx edx, byte ptr [%s + %d]\n" : "    movsx rdx, byte ptr [%s + %d]\n", reg, offset);
+                            }
+                            
+                            if (postfix_op == TOK_INCR || postfix_op == TOK_DECR) {
+                                fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    %s byte [%s + %d]\n" : "    %s byte ptr [%s + %d]\n", postfix_op == TOK_INCR ? "inc" : "dec", reg, offset);
+                            }
+                        
+                        } else if (member_size == (DATA_SHORT & 0x1f)) {
+                        
+                            if (state->syntax & ASM_SYNTAX_NASM) {
+                                fprintf (state->ofp, member_pointer_depth || member_elem_size == (DATA_SHORT & 0x1f) ? "    movzx edx, word [%s + %d]\n" : "    movsx rdx, word [%s + %d]\n", reg, offset);
+                            } else {
+                                fprintf (state->ofp, member_pointer_depth || member_elem_size == (DATA_SHORT & 0x1f) ? "    movzx edx, word ptr [%s + %d]\n" : "    movsx rdx, word ptr [%s + %d]\n", reg, offset);
+                            }
+                            
+                            if (postfix_op == TOK_INCR || postfix_op == TOK_DECR) {
+                                fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    %s word [%s + %d]\n" : "    %s word ptr [%s + %d]\n", postfix_op == TOK_INCR ? "inc" : "dec", reg, offset);
+                            }
+                        
+                        } else if (member_qword) {
+                        
+                            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov rdx, qword [%s + %d]\n" : "    mov rdx, qword ptr [%s + %d]\n", reg, offset);
+                            
+                            if (postfix_op == TOK_INCR || postfix_op == TOK_DECR) {
+                                fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    %s qword [%s + %d]\n" : "    %s qword ptr [%s + %d]\n", postfix_op == TOK_INCR ? "inc" : "dec", reg, offset);
+                            }
+                        
+                        } else {
+                        
+                            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    movsxd rdx, dword [%s + %d]\n" : "    movsxd rdx, dword ptr [%s + %d]\n", reg, offset);
+                            
+                            if (postfix_op == TOK_INCR || postfix_op == TOK_DECR) {
+                                fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    %s dword [%s + %d]\n" : "    %s dword ptr [%s + %d]\n", postfix_op == TOK_INCR ? "inc" : "dec", reg, offset);
+                            }
+                        
+                        }
+                    
+                    } else {
+                    
+                        if (member_size == (DATA_CHAR & 0x1f)) {
+                            fprintf (state->ofp, "    movsbq %d(%%%s), %%rdx\n", offset, reg);
+                        } else if (member_size == (DATA_SHORT & 0x1f)) {
+                            fprintf (state->ofp, "    movswq %d(%%%s), %%rdx\n", offset, reg);
+                        } else if (member_qword) {
+                            fprintf (state->ofp, "    movq %d(%%%s), %%rdx\n", offset, reg);
+                        } else {
+                            fprintf (state->ofp, "    movslq %d(%%%s), %%rdx\n", offset, reg);
+                        }
+                        
+                        if (postfix_op == TOK_INCR || postfix_op == TOK_DECR) {
+                        
+                            if (member_size == (DATA_CHAR & 0x1f)) {
+                                fprintf (state->ofp, "    %sb %d(%%%s)\n", postfix_op == TOK_INCR ? "inc" : "dec", offset, reg);
+                            } else if (member_size == (DATA_SHORT & 0x1f)) {
+                                fprintf (state->ofp, "    %sw %d(%%%s)\n", postfix_op == TOK_INCR ? "inc" : "dec", offset, reg);
+                            } else if (member_qword) {
+                                fprintf (state->ofp, "    %sq %d(%%%s)\n", postfix_op == TOK_INCR ? "inc" : "dec", offset, reg);
+                            } else {
+                                fprintf (state->ofp, "    %sl %d(%%%s)\n", postfix_op == TOK_INCR ? "inc" : "dec", offset, reg);
+                            }
+                        
+                        }
+                    
+                    }
+                
+                }
+                
+                if (tok.kind == TOK_ASSIGN) {
+                
+                    emit_push_reg_now ("rdx");
+                    get_token ();
+                    
+                    emit_load_assignment_rhs_expression_to_reg (reg);
+                    emit_pop_reg_now ("rdx");
+                    emit_store_reg_to_deref_reg_now ("rdx", reg, deref_size);
+                    
+                    return;
+                
+                }
+                
+                if (state->ofp && strcmp (reg, "rdx") != 0) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    mov %s, rdx\n", reg);
+                    } else {
+                        fprintf (state->ofp, "    movq %%rdx, %%%s\n", reg);
+                    }
+                
+                }
+                
+                goto dereference_loaded_address;
+            
+            }
+        
+        } else {
+            emit_load_assignment_rhs_to_reg (reg);
+        }
+        
+    dereference_loaded_address:
+        
+        deref_pointer_depth = rhs_last_pointer_depth;
+        deref_pointed_size = rhs_last_pointed_size;
+        
+        emit_load_deref_reg_now (reg, deref_size);
+        
+        if (deref_pointer_depth > 1) {
+            set_rhs_last_pointer_info (deref_pointer_depth - 1, deref_pointed_size);
+        } else {
+            clear_rhs_last_pointer_info ();
+        }
+        
+        if (tok.kind == TOK_LBRACK) {
+        
+            int subscript_pointer_depth = deref_pointer_depth > 0 ? deref_pointer_depth - 1 : 0;
+            int subscript_elem_size = subscript_pointer_depth > 1 ? (DATA_PTR & 0x1f) : deref_pointed_size;
+            
+            if (subscript_elem_size <= 0) {
+                subscript_elem_size = DATA_INT & 0x1f;
+            }
+            
+            emit_parse_postfix_subscripts_to_reg_now (reg, subscript_elem_size, subscript_pointer_depth, deref_pointed_size);
+            
+            if (is_assignment_operator (tok.kind)) {
+            
+                enum token_kind assign_op = tok.kind;
+                
+                get_token ();
+                emit_push_reg_now (reg);
+                
+                if (assign_op == TOK_ASSIGN && subscript_elem_size > (DATA_LLONG & 0x1f) &&
+                    tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now ()) {
+                
+                    char *rhs_name = xstrdup (tok.ident);
+                    
+                    const char *rhs_start = tok.start;
+                    const char *rhs_caret = tok.caret;
+                    
+                    unsigned long rhs_line = get_line_number ();
+                    
+                    pending_struct_return_lhs = 0;
+                    pending_struct_return_global_name = 0;
+                    pending_struct_return_stack_address = 1;
+                    pending_struct_return_stack_offset = 0;
+                    
+                    get_token ();
+                    emit_call_identifier_to_reg_now (rhs_name, reg, rhs_start, rhs_caret, rhs_line);
+                    
+                    pending_struct_return_stack_address = 0;
+                    pending_struct_return_stack_offset = 0;
+                    
+                    emit_pop_reg_now ("rdx");
+                    free (rhs_name);
+                    
+                    set_rhs_last_pointer_info (0, 0);
+                    return;
+                
+                } else if (assign_op == TOK_ASSIGN) {
+                
+                    if (subscript_elem_size > (DATA_LLONG & 0x1f)) {
+                    
+                        pending_struct_return_lhs = 0;
+                        pending_struct_return_global_name = 0;
+                        pending_struct_return_stack_address = 1;
+                        pending_struct_return_stack_offset = 0;
+                        
+                        emit_load_assignment_rhs_expression_to_reg (reg);
+                        
+                        pending_struct_return_stack_address = 0;
+                        pending_struct_return_stack_offset = 0;
+                        
+                        emit_pop_reg_now ("rdx");
+                        set_rhs_last_pointer_info (0, 0);
+                        return;
+                    
+                    }
+                    
+                    emit_load_assignment_rhs_expression_to_reg (reg);
+                
+                } else {
+                
+                    emit_load_deref_reg_now (reg, subscript_elem_size);
+                    emit_push_reg_now (reg);
+                    
+                    emit_load_assignment_rhs_expression_to_reg ("rdx");
+                    emit_pop_reg_now (reg);
+                    
+                    emit_assignment_binary_op (assign_op, 0);
+                
+                }
+                
+                emit_pop_reg_now ("rdx");
+                
+                emit_store_reg_to_deref_reg_now ("rdx", reg, subscript_elem_size);
+                clear_rhs_last_pointer_info ();
+                
+                return;
+            
+            }
+            
+            emit_load_deref_reg_now (reg, subscript_elem_size);
+            
+            if (subscript_pointer_depth > 1) {
+                set_rhs_last_pointer_info (subscript_pointer_depth - 1, deref_pointed_size);
+            } else {
+                clear_rhs_last_pointer_info ();
+            }
+        
+        }
+        
+        return;
+    
+    } else if (tok.kind == TOK_TILDE) {
+    
+        get_token ();
+        emit_load_assignment_rhs_to_reg (reg);
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    not %s\n", reg);
+            } else {
+                fprintf (state->ofp, "    notq %%%s\n", reg);
+            }
+        
+        }
+        
+        return;
+    
+    } else if (tok.kind == TOK_XMARK) {
+    
+        get_token ();
+        emit_load_assignment_rhs_to_reg (reg);
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                fprintf (state->ofp, "    test %s, %s\n", reg, reg);
+                
+                if (strcmp (reg, "rax") != 0) {
+                
+                    fprintf (state->ofp, "    setz al\n");
+                    fprintf (state->ofp, "    movzx eax, al\n");
+                    fprintf (state->ofp, "    mov %s, rax\n", reg);
+                
+                } else {
+                
+                    fprintf (state->ofp, "    setz al\n");
+                    fprintf (state->ofp, "    movzx eax, al\n");
+                
+                }
+            
+            } else {
+            
+                fprintf (state->ofp, "    testq %%%s, %%%s\n", reg, reg);
+                fprintf (state->ofp, "    setz %%al\n");
+                fprintf (state->ofp, "    movzbl %%al, %%eax\n");
+                
+                if (strcmp (reg, "rax") != 0) {
+                    fprintf (state->ofp, "    movq %%rax, %%%s\n", reg);
+                }
+            
+            }
+        
+        }
+        
+        return;
+    
+    } else if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+    
+        if (emit_load_prefix_incdec_member_to_reg_now (reg)) {
+            return;
+        }
+        
+        if (emit_load_prefix_incdec_to_reg_now (reg)) {
+            return;
+        }
+    
+    }
+    
+    if (tok.kind == TOK_PLUS || tok.kind == TOK_MINUS) {
+    
+        int negate = 0;
+        
+        while (tok.kind == TOK_PLUS || tok.kind == TOK_MINUS) {
+        
+            if (tok.kind == TOK_MINUS) {
+                negate = !negate;
+            }
+            
+            get_token ();
+        
+        }
+        
+        emit_load_assignment_rhs_to_reg (reg);
+        
+        if (negate && state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    neg %s\n", reg);
+            } else {
+                fprintf (state->ofp, "    negl %%%s\n", reg);
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (token_is_sizeof_keyword ()) {
+    
+        int64_s v = sizeof_from_current_token ();
+        
+        if (state->ofp) {
+        
+            const char *dreg = amd64_dword_reg_name_from_any (reg);
+            
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    mov %s, %lu\n", dreg, v.low & U32_MASK);
+            } else {
+                fprintf (state->ofp, "    movl $%lu, %%%s\n", v.low & U32_MASK, dreg);
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (is_string_token ()) {
+    
+        char *label = emit_string_literal_global ();
+        
+        switch_section (SECTION_TEXT);
+        emit_load_address_to_reg_now (reg, label);
+        
+        free (label);
+        
+        /*
+         * A string literal is a primary expression and may still have
+         * postfix operators applied to it.  In particular, macro-expanded
+         * string constants are commonly subscripted in calls, e.g.
+         *
+         *     tebc (LINKAGE_EDITOR_PROGRAM_NAME[i])
+         *
+         * where LINKAGE_EDITOR_PROGRAM_NAME expands to a string literal.
+         * The old path returned immediately after loading the literal
+         * address, leaving the '[' token for the caller and causing a false
+         * "expected )".  Treat the literal as a char array here and consume
+         * any following subscripts.
+         */
+        if (tok.kind == TOK_LBRACK) {
+        
+            emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, DATA_CHAR & 0x1f);
+            emit_load_deref_reg_now (reg, DATA_CHAR & 0x1f);
+            
+            set_rhs_last_pointer_info (0, 0);
+        
+        } else {
+            set_rhs_last_pointer_info (1, DATA_CHAR & 0x1f);
+        }
+        
+        return;
+    
+    }
+    
+    switch (tok.kind) {
+    
+        case TOK_CCHAR:     case TOK_CINT:      case TOK_CUINT:     case TOK_CULONG:
+        case TOK_CLONG:     case TOK_CLLONG:    case TOK_CULLONG:   case TOK_LCHAR:
+        {
+        
+            int64_s v;
+            
+            int trailing_op = 0;
+            size_t len = tok.ident ? strlen (tok.ident) : 0;
+            
+            v.high = tok.val.i.high;
+            v.low = tok.val.i.low;
+            
+            if (len > 1 && tok.ident[len - 1] == '+') {
+                trailing_op = TOK_PLUS;
+            } else if (len > 1 && tok.ident[len - 1] == '-') {
+                trailing_op = TOK_MINUS;
+            }
+            
+            if (trailing_op) {
+            
+                free (tok.ident);
+                
+                tok.ident = xstrdup (trailing_op == TOK_PLUS ? "+" : "-");
+                tok.kind = (enum token_kind) trailing_op;
+                
+                if (tok.caret) {
+                    tok.caret--;
+                }
+            
+            } else {
+                get_token ();
+            }
+            
+            emit_load_const32_to_reg_now (reg, v);
+            return;
+        
+        }
+        
+        case TOK_CFLOAT:    case TOK_CDOUBLE:    case TOK_CLDOUBLE:
+        {
+        
+            int trailing_op = 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;
+            
+            if (len > 1 && tok.ident[len - 1] == '+') {
+                trailing_op = TOK_PLUS;
+            } else if (len > 1 && tok.ident[len - 1] == '-') {
+                trailing_op = TOK_MINUS;
+            }
+            
+            if (trailing_op) {
+            
+                free (tok.ident);
+                
+                tok.ident = xstrdup (trailing_op == TOK_PLUS ? "+" : "-");
+                tok.kind = (enum token_kind) trailing_op;
+                
+                if (tok.caret) {
+                    tok.caret--;
+                }
+            
+            } else {
+                get_token ();
+            }
+            
+            emit_load_const32_to_reg_now (reg, v);
+            return;
+        
+        }
+        
+        default:
+        
+            break;
+    
+    }
+    
+    if (tok.kind == TOK_SCC_BUILTIN_VA_ARG) {
+    
+        int va_size = DATA_INT & 0x1f;
+        int va_unsigned = 1;
+        int va_pointer = 0;
+        int va_floating = 0;
+        
+        get_token ();
+        
+        emit_parse_builtin_va_arg_address_to_reg_now (reg, &va_size, &va_unsigned, &va_pointer, &va_floating);
+        emit_load_deref_reg_now (reg, va_size);
+        
+        if (va_pointer > 0) {
+            set_rhs_last_pointer_info (va_pointer, DATA_INT & 0x1f);
+        } else {
+        
+            emit_apply_integer_cast_to_reg_now (reg, va_size, va_unsigned);
+            clear_rhs_last_pointer_info ();
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_IDENT) {
+    
+        enum token_kind postfix_op = TOK_EOF;
+        char *name = xstrdup (tok.ident);
+        
+        const char *name_start = tok.start, *name_caret = tok.caret;
+        unsigned long name_line = get_line_number ();
+        
+        struct local_symbol *src;
+        int postfix_incdec = 0;
+        
+        get_token ();
+        
+        if (strcmp (name, "__scc_builtin_va_arg") == 0 && tok.kind == TOK_LPAREN) {
+        
+            int va_size = DATA_INT & 0x1f;
+            int va_unsigned = 1;
+            int va_pointer = 0;
+            int va_floating = 0;
+            
+            emit_parse_builtin_va_arg_address_to_reg_now (reg, &va_size, &va_unsigned, &va_pointer, &va_floating);
+            emit_load_deref_reg_now (reg, va_size);
+            
+            if (va_pointer > 0) {
+                set_rhs_last_pointer_info (va_pointer, DATA_INT & 0x1f);
+            } else {
+            
+                emit_apply_integer_cast_to_reg_now (reg, va_size, va_unsigned);
+                clear_rhs_last_pointer_info ();
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        {
+        
+            int64_s enum_value;
+            
+            if (!find_local_symbol (name) && find_global_symbol (name) < 0 && resolve_enum_constant (name, &enum_value)) {
+            
+                emit_load_const32_to_reg_now (reg, enum_value);
+                
+                set_rhs_last_pointer_info (0, DATA_INT & 0x1f);
+                free (name);
+                
+                return;
+            
+            }
+        
+        }
+        
+        if (tok.kind == TOK_LBRACK) {
+        
+            src = find_local_symbol (name);
+            
+            if (src) {
+            
+                int saw_subscript;
+                int elem_size;
+                
+                {
+                
+                    elem_size = src->is_array ? (src->pointer_depth ? DATA_PTR : (src->array_element_size > 0 ? src->array_element_size : src->pointed_size)) :
+                        (src->pointer_depth > 1 ? DATA_PTR : src->pointed_size);
+                    
+                    if (src->is_array && src->pointer_depth == 0 && elem_size <= (DATA_PTR & 0x1f)) {
+                    
+                        int aggregate_elem_size = aggregate_tag_size_or_zero (src->tag_name ? src->tag_name : src->pointed_tag_name);
+                        
+                        if (aggregate_elem_size > (DATA_PTR & 0x1f)) {
+                            elem_size = aggregate_elem_size;
+                        }
+                    
+                    }
+                    
+                    if (src->is_array) {
+                    
+                        if (src->is_static && src->static_label) {
+                            emit_load_symbol_address_to_reg_now (reg, src->static_label, 0, 0);
+                        } else {
+                            emit_load_symbol_address_to_reg_now (reg, 0, src->offset, 1);
+                        }
+                    
+                    } else if (src->is_static && src->static_label) {
+                        emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+                    }
+                    
+                    saw_subscript = emit_parse_postfix_subscripts_to_reg_dims_now (reg, elem_size, src->pointer_depth, src->pointed_size, src->array_dimensions, src->pointer_depth > 0 ? src->pointed_is_unsigned : src->is_unsigned);
+                    
+                    postfix_copy_lvalue_size = index_step_size (elem_size);
+                    postfix_copy_lvalue_tag_name = src->is_array ? (src->tag_name ? src->tag_name : src->pointed_tag_name) : src->pointed_tag_name;
+                
+                }
+                
+                emit_apply_postfix_member_access_to_reg_now (reg);
+                postfix_copy_lvalue_tag_name = 0;
+                
+                if (!postfix_member_seen && emit_store_assignment_to_aggregate_address_now (reg, elem_size, name_start, name_caret, name_line)) {
+                
+                    free (name);
+                    return;
+                
+                }
+                
+                if (!postfix_member_seen && saw_subscript && elem_size > (DATA_PTR & 0x1f)) {
+                
+                    postfix_member_seen = 1;
+                    postfix_member_pointer_depth = 0;
+                    postfix_member_pointed_size = elem_size;
+                    postfix_member_size = elem_size;
+                    postfix_member_is_floating = src->is_floating;
+                    postfix_member_is_unsigned = src->is_unsigned;
+                
+                }
+                
+                if (postfix_member_seen) {
+                    set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
+                } else {
+                    set_rhs_last_pointer_info (src->pointer_depth > 0 ? src->pointer_depth - 1 : 0, src->pointed_size);
+                }
+                
+                free (name);
+                return;
+            
+            }
+            
+            if (find_global_symbol (name) >= 0) {
+            
+                int saw_subscript;
+                int elem_size;
+                
+                {
+                
+                    elem_size = get_global_symbol_array (name) ?
+                        (get_global_symbol_pointer_depth (name) ? DATA_PTR :
+                            (get_global_symbol_array_element_size (name) > 0 ? get_global_symbol_array_element_size (name) : get_global_symbol_pointed_size (name))) :
+                                (get_global_symbol_pointer_depth (name) > 1 ? DATA_PTR : get_global_symbol_pointed_size (name));
+                    
+                    if (get_global_symbol_array (name) && get_global_symbol_pointer_depth (name) == 0 && elem_size <= (DATA_PTR & 0x1f)) {
+                    
+                        int aggregate_elem_size = aggregate_tag_size_or_zero (get_global_symbol_tag_name (name));
+                        
+                        if (aggregate_elem_size > (DATA_PTR & 0x1f)) {
+                            elem_size = aggregate_elem_size;
+                        }
+                    
+                    }
+                    
+                    if (get_global_symbol_array (name)) {
+                        emit_load_symbol_address_to_reg_now (reg, name, 0, 0);
+                    } else {
+                        emit_load_global_to_reg (reg, name, DATA_PTR);
+                    }
+                    
+                    saw_subscript = emit_parse_postfix_subscripts_to_reg_dims_now (reg, elem_size, get_global_symbol_pointer_depth (name), get_global_symbol_pointed_size (name), get_global_symbol_array_dimensions (name), get_global_symbol_pointer_depth (name) > 0 ? get_global_symbol_pointed_is_unsigned (name) : get_global_symbol_unsigned (name));
+                    
+                    postfix_copy_lvalue_size = index_step_size (elem_size);
+                    postfix_copy_lvalue_tag_name = get_global_symbol_array (name) ? get_global_symbol_tag_name (name) : 0;
+                
+                }
+                
+                emit_apply_postfix_member_access_to_reg_now (reg);
+                postfix_copy_lvalue_tag_name = 0;
+                
+                if (!postfix_member_seen && emit_store_assignment_to_aggregate_address_now (reg, elem_size, name_start, name_caret, name_line)) {
+                
+                    free (name);
+                    return;
+                
+                }
+                
+                if (!postfix_member_seen && saw_subscript && elem_size > (DATA_PTR & 0x1f)) {
+                
+                    postfix_member_seen = 1;
+                    postfix_member_pointer_depth = 0;
+                    postfix_member_pointed_size = elem_size;
+                    postfix_member_size = elem_size;
+                    postfix_member_is_floating = get_global_symbol_floating (name);
+                    postfix_member_is_unsigned = get_global_symbol_unsigned (name);
+                
+                }
+                
+                free (name);
+                return;
+            
+            }
+        
+        }
+        
+        if (tok.kind == TOK_LPAREN) {
+        
+            if (!find_local_symbol (name)) {
+                ensure_global_function_symbol (name, name_start, name_caret, name_line);
+            }
+            
+            if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION && get_global_symbol_returns_void (name)) {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "void function '%s' used as a value", name);
+            }
+            
+            emit_call_identifier_to_reg_now (name, reg, name_start, name_caret, name_line);
+            
+            if (tok.kind == TOK_LBRACK) {
+            
+                int subscript_pointer_depth = get_global_symbol_pointer_depth (name);
+                int subscript_elem_size = get_global_symbol_pointed_size (name);
+                
+                if (subscript_elem_size <= 0) {
+                    subscript_elem_size = DATA_INT & 0x1f;
+                }
+                
+                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, subscript_elem_size);
+                
+                if (is_assignment_operator (tok.kind)) {
+                
+                    enum token_kind assign_op = tok.kind;
+                    
+                    get_token ();
+                    emit_push_reg_now (reg);
+                    
+                    if (assign_op == TOK_ASSIGN) {
+                    
+                        if (subscript_elem_size > (DATA_LLONG & 0x1f)) {
+                        
+                            pending_struct_return_lhs = 0;
+                            pending_struct_return_global_name = 0;
+                            pending_struct_return_stack_address = 1;
+                            pending_struct_return_stack_offset = 0;
+                            
+                            emit_load_assignment_rhs_expression_to_reg (reg);
+                            
+                            pending_struct_return_stack_address = 0;
+                            pending_struct_return_stack_offset = 0;
+                            
+                            emit_pop_reg_now ("rdx");
+                            postfix_member_seen = 0;
+                            
+                            return;
+                        
+                        }
+                        
+                        emit_load_assignment_rhs_expression_to_reg (reg);
+                    
+                    } else {
+                    
+                        emit_load_deref_reg_now (reg, subscript_elem_size);
+                        emit_push_reg_now (reg);
+                        
+                        emit_load_assignment_rhs_expression_to_reg ("rdx");
+                        emit_pop_reg_now (reg);
+                        
+                        emit_assignment_binary_op (assign_op, 0);
+                    
+                    }
+                    
+                    emit_pop_reg_now ("rdx");
+                    emit_store_member_to_addr_reg_now ("rdx", 0, reg, subscript_elem_size);
+                    set_rhs_last_pointer_info (0, 0);
+                    
+                    free (name);
+                    return;
+                
+                }
+                
+                emit_load_deref_reg_now (reg, subscript_elem_size);
+                
+                if (subscript_pointer_depth > 0) {
+                    subscript_pointer_depth--;
+                }
+                
+                if (subscript_pointer_depth > 0) {
+                    set_rhs_last_pointer_info (subscript_pointer_depth, subscript_elem_size);
+                } else {
+                    set_rhs_last_pointer_info (0, 0);
+                }
+            
+            }
+            
+            emit_apply_postfix_member_access_to_reg_now (reg);
+            
+            if (postfix_member_seen && tok.kind == TOK_LPAREN) {
+            
+                emit_call_pointer_in_reg_now (reg, reg);
+                
+                set_rhs_last_pointer_info (0, 0);
+                free (name);
+                
+                return;
+            
+            }
+            
+            if (postfix_member_seen) {
+                set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (is_assignment_operator (tok.kind)) {
+        
+            enum token_kind assign_op = tok.kind;
+            struct local_symbol *dst;
+            int global_index;
+            int dst_size;
+            int dst_is_floating;
+            
+            get_token ();
+            
+            dst = find_local_symbol (name);
+            global_index = find_global_symbol (name);
+            
+            if (!dst && global_index < 0) {
+            
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+                
+                if (state->ofp) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    xor %s, %s\n", reg, reg);
+                    } else {
+                        fprintf (state->ofp, "    xorq %%%s, %%%s\n", reg, reg);
+                    }
+                
+                }
+                
+                free (name);
+                return;
+            
+            }
+            
+            dst_size = dst ? dst->size : get_global_symbol_size (name);
+            dst_is_floating = dst ? dst->is_floating : get_global_symbol_floating (name);
+            
+            if (dst_is_floating) {
+            
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "floating assignment expression not implemented");
+                skip_balanced_until (TOK_RPAREN, TOK_SEMI, TOK_EOF);
+                
+                free (name);
+                return;
+            
+            }
+            
+            if (dst_size == (DATA_LLONG & 0x1f)) {
+            
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "64-bit assignment expression not implemented");
+                skip_balanced_until (TOK_RPAREN, TOK_SEMI, TOK_EOF);
+                
+                free (name);
+                return;
+            
+            }
+            
+            if (assign_op == TOK_ASSIGN) {
+                emit_load_assignment_rhs_expression_to_reg (reg);
+            } else {
+            
+                if (dst) {
+                
+                    if (dst->is_static && dst->static_label) {
+                        emit_load_global_to_reg_ex (reg, dst->static_label, dst->size, dst->is_unsigned);
+                    } else {
+                        emit_load_local_to_reg_ex (reg, dst->offset, dst->size, dst->is_unsigned);
+                    }
+                
+                } else {
+                    emit_load_global_to_reg_ex (reg, name, dst_size, get_global_symbol_unsigned (name));
+                }
+                
+                emit_load_assignment_rhs_expression_to_reg ("rdx");
+                
+                if (strcmp (reg, "rax") != 0 && state->ofp) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    mov rax, %s\n", reg);
+                    } else {
+                        fprintf (state->ofp, "    movq %%%s, %%rax\n", reg);
+                    }
+                
+                }
+                
+                emit_assignment_binary_op (assign_op, dst ? dst->is_unsigned : get_global_symbol_unsigned (name));
+                
+                if (strcmp (reg, "rax") != 0 && state->ofp) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    mov %s, rax\n", reg);
+                    } else {
+                        fprintf (state->ofp, "    movq %%rax, %%%s\n", reg);
+                    }
+                
+                }
+            
+            }
+            
+            if (dst) {
+            
+                if (dst->is_static && dst->static_label) {
+                    emit_store_reg_to_global (dst->static_label, dst->size, reg);
+                } else {
+                    emit_store_reg_to_local (dst->offset, dst->size, reg);
+                }
+                
+                if (dst->is_array || dst->pointer_depth > 0) {
+                    set_rhs_last_pointer_info (dst->is_array ? 1 : dst->pointer_depth, dst->is_array ? local_array_pointer_step_size (dst) : dst->pointed_size);
+                } else {
+                    clear_rhs_last_pointer_info ();
+                }
+            
+            } else {
+            
+                emit_store_reg_to_global (name, dst_size, reg);
+                
+                if (get_global_symbol_array (name) || get_global_symbol_pointer_depth (name) > 0) {
+                    set_rhs_last_pointer_info (get_global_symbol_array (name) ? 1 : get_global_symbol_pointer_depth (name), get_global_symbol_array (name) ? global_array_pointer_step_size (name) : get_global_symbol_pointed_size (name));
+                } else {
+                    clear_rhs_last_pointer_info ();
+                }
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+        
+            postfix_incdec = 1;
+            postfix_op = tok.kind;
+            
+            get_token ();
+        
+        }
+        
+        src = find_local_symbol (name);
+        
+        if (postfix_incdec && tok.kind == TOK_LBRACK) {
+        
+            int pointer_depth = 0;
+            int pointed_size = 0;
+            int elem_size = DATA_INT & 0x1f;
+            int is_unsigned = 1;
+            int known = 0;
+            
+            if (src) {
+            
+                known = 1;
+                
+                pointer_depth = src->pointer_depth;
+                pointed_size = src->pointed_size;
+                
+                is_unsigned = src->is_unsigned;
+                
+                if (src->is_static && src->static_label) {
+                    emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+                }
+            
+            } else if (find_global_symbol (name) >= 0) {
+            
+                known = 1;
+                
+                pointer_depth = get_global_symbol_pointer_depth (name);
+                pointed_size = get_global_symbol_pointed_size (name);
+                
+                is_unsigned = get_global_symbol_unsigned (name);
+                emit_load_global_to_reg (reg, name, DATA_PTR);
+            
+            }
+            
+            if (!known) {
+            
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+                
+                free (name);
+                return;
+            
+            }
+            
+            if (pointer_depth <= 0) {
+            
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "subscripted value is not a pointer");
+                
+                free (name);
+                return;
+            
+            }
+            
+            if (pointer_depth > 1) {
+                elem_size = DATA_PTR & 0x1f;
+            } else if (pointed_size > 0) {
+                elem_size = pointed_size & 0x1f;
+            }
+            
+            emit_push_reg_now (reg);
+            
+            emit_incdec_symbol_now (src, name, postfix_op, name_line, name_start, name_caret);
+            emit_pop_reg_now (reg);
+            
+            emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
+            
+            if (is_assignment_operator (tok.kind)) {
+            
+                enum token_kind assign_op = tok.kind;
+                get_token ();
+                
+                emit_push_reg_now (reg);
+                
+                if (assign_op == TOK_ASSIGN) {
+                    emit_load_assignment_rhs_expression_to_reg (reg);
+                } else {
+                
+                    emit_load_deref_reg_now (reg, elem_size);
+                    emit_push_reg_now (reg);
+                    
+                    emit_load_assignment_rhs_expression_to_reg ("rdx");
+                    emit_pop_reg_now (reg);
+                    
+                    emit_assignment_binary_op (assign_op, is_unsigned);
+                
+                }
+                
+                emit_pop_reg_now ("rdx");
+                emit_store_reg_to_deref_reg_now ("rdx", reg, elem_size);
+                
+                clear_rhs_last_pointer_info ();
+                free (name);
+                
+                return;
+            
+            }
+            
+            emit_load_deref_reg_now (reg, elem_size);
+            
+            if (pointer_depth > 1) {
+                set_rhs_last_pointer_info (pointer_depth - 1, pointed_size);
+            } else {
+                clear_rhs_last_pointer_info ();
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (src) {
+        
+            if (src->is_array) {
+            
+                if (src->is_static && src->static_label) {
+                    emit_load_address_to_reg_now (reg, src->static_label);
+                } else {
+                    emit_load_local_address_to_reg_now (reg, src->offset);
+                }
+            
+            } else if (tok.kind == TOK_DOT) {
+            
+                if (src->is_static && src->static_label) {
+                    emit_load_address_to_reg_now (reg, src->static_label);
+                } else {
+                    emit_load_local_address_to_reg_now (reg, src->offset);
+                }
+            
+            } else if (src->is_static && src->static_label) {
+                emit_load_global_to_reg_ex (reg, src->static_label, src->size, src->is_unsigned);
+            } else {
+                emit_load_local_to_reg_ex (reg, src->offset, src->size, src->is_unsigned);
+            }
+            
+            if (src->pointer_depth > 0) {
+            
+                /*
+                 * Keep the pointed-to aggregate information even when the
+                 * arrow is not immediately visible.  Macro expansions commonly
+                 * parenthesize pointer operands, e.g. ((unknown)->type).
+                 * The inner expression sees ')' after 'unknown', and the
+                 * outer parenthesized path sees the later '->'.  If we clear
+                 * the tag here, that later member lookup falls back to an
+                 * unrelated member named 'type' and emits offset 0 instead of
+                 * the struct cpp_unknown offset.
+                 */
+                postfix_copy_lvalue_size = src->pointed_size;
+                postfix_copy_lvalue_tag_name = src->pointed_tag_name;
+            
+            } else {
+            
+                postfix_copy_lvalue_size = src->size;
+                postfix_copy_lvalue_tag_name = src->tag_name;
+            
+            }
+            
+            emit_apply_postfix_member_access_to_reg_now (reg);
+            
+            if (postfix_member_seen && tok.kind == TOK_LPAREN) {
+            
+                emit_call_pointer_in_reg_now (reg, reg);
+                
+                set_rhs_last_pointer_info (0, 0);
+                free (name);
+                
+                return;
+            
+            }
+            
+            if (emit_store_assignment_to_postfix_member_now (reg)) {
+            
+                set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
+                
+                free (name);
+                return;
+            
+            }
+            
+            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+            
+                postfix_incdec = 1;
+                postfix_op = tok.kind;
+                
+                get_token ();
+            
+            }
+            
+            if (postfix_incdec) {
+            
+                if (postfix_member_seen) {
+                    emit_apply_postfix_member_incdec_now (reg, postfix_op);
+                } else {
+                
+                    emit_push_reg_now (reg);
+                    emit_incdec_symbol_now (src, name, postfix_op, name_line, name_start, name_caret);
+                    emit_pop_reg_now (reg);
+                
+                }
+            
+            }
+            
+            if (postfix_member_seen) {
+                set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
+            } else {
+                set_rhs_last_pointer_info (src->is_array ? 1 : src->pointer_depth, src->is_array ? local_array_pointer_step_size (src) : src->pointed_size);
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (find_global_symbol (name) >= 0) {
+        
+            if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION ||
+                get_global_symbol_array (name) ||
+                (!get_global_symbol_pointer_depth (name) &&
+                    get_global_symbol_size (name) > (DATA_PTR & 0x1f)) ||
+                tok.kind == TOK_DOT) {
+                emit_load_address_to_reg_now (reg, name);
+            } else {
+                emit_load_global_to_reg_ex (reg, name, get_global_symbol_size (name), get_global_symbol_unsigned (name));
+            }
+            
+            if (tok.kind == TOK_ARROW && get_global_symbol_pointer_depth (name) > 0) {
+            
+                postfix_copy_lvalue_size = get_global_symbol_pointed_size (name);
+                postfix_copy_lvalue_tag_name = get_global_symbol_tag_name (name);
+            
+            } else {
+            
+                postfix_copy_lvalue_size = get_global_symbol_size (name);
+                postfix_copy_lvalue_tag_name = get_global_symbol_tag_name (name);
+            
+            }
+            
+            emit_apply_postfix_member_access_to_reg_now (reg);
+            
+            if (postfix_member_seen && tok.kind == TOK_LPAREN) {
+            
+                emit_call_pointer_in_reg_now (reg, reg);
+                
+                set_rhs_last_pointer_info (0, 0);
+                free (name);
+                
+                return;
+            
+            }
+            
+            if (emit_store_assignment_to_postfix_member_now (reg)) {
+            
+                set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
+                
+                free (name);
+                return;
+            
+            }
+            
+            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+            
+                postfix_incdec = 1;
+                postfix_op = tok.kind;
+                
+                get_token ();
+            
+            }
+            
+            if (postfix_incdec) {
+            
+                if (postfix_member_seen) {
+                    emit_apply_postfix_member_incdec_now (reg, postfix_op);
+                } else {
+                
+                    emit_push_reg_now (reg);
+                    emit_incdec_symbol_now (0, name, postfix_op, name_line, name_start, name_caret);
+                    emit_pop_reg_now (reg);
+                
+                }
+            
+            }
+            
+            if (postfix_member_seen) {
+                set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
+            } else {
+                set_rhs_last_pointer_info (get_global_symbol_array (name) ? 1 : get_global_symbol_pointer_depth (name), get_global_symbol_array (name) ? global_array_pointer_step_size (name) : get_global_symbol_pointed_size (name));
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        free (name);
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    xor %s, %s\n", reg, reg);
+            } else {
+                fprintf (state->ofp, "    xorq %%%s, %%%s\n", reg, reg);
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (recover_unknown_rhs_identifier ()) {
+    
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    xor %s, %s\n", reg, reg);
+            } else {
+                fprintf (state->ofp, "    xorq %%%s, %%%s\n", reg, reg);
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    {
+    
+        int64_s v = const64_from_current_operand ();
+        
+        if (state->ofp) {
+        
+            const char *dreg = amd64_dword_reg_name_from_any (reg);
+            
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    mov %s, %lu\n", dreg, v.low & U32_MASK);
+            } else {
+                fprintf (state->ofp, "    movl $%lu, %%%s\n", v.low & U32_MASK, dreg);
+            }
+        
+        }
+    
+    }
+
+}
+
+static int local_array_pointer_step_size (const struct local_symbol *sym) {
+
+    if (!sym || !sym->is_array) {
+        return 0;
+    }
+    
+    if (sym->array_element_size > 0) {
+        return index_step_size (sym->array_element_size);
+    }
+    
+    if (sym->pointed_size > 0 && sym->pointed_size < sym->size) {
+        return index_step_size (sym->pointed_size);
+    }
+    
+    return index_step_size (sym->size);
+
+}
+
+static int global_array_pointer_step_size (const char *name) {
+
+    long count;
+    int pointed_size;
+    
+    if (!name || !get_global_symbol_array (name)) {
+        return 0;
+    }
+    
+    if (get_global_symbol_array_element_size (name) > 0) {
+        return get_global_symbol_array_element_size (name);
+    }
+    
+    count = get_global_symbol_array_count (name);
+    
+    if (count > 0) {
+        return (int) (get_global_symbol_size (name) / count);
+    }
+    
+    pointed_size = get_global_symbol_pointed_size (name);
+    
+    if (pointed_size > 0 && pointed_size < get_global_symbol_size (name)) {
+        return index_step_size (pointed_size);
+    }
+    
+    return index_step_size (get_global_symbol_size (name));
+
+}
+
+static void emit_scale_reg_by_const_now (const char *reg, int scale) {
+
+    if (!state->ofp || scale <= 1) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    imul %s, %d\n", reg, scale);
+    } else {
+        fprintf (state->ofp, "    imulq $%d, %%%s, %%%s\n", scale, reg, reg);
+    }
+
+}
+
+static void emit_divide_rax_by_const_now (int divisor) {
+
+    if (!state->ofp || divisor <= 1) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    mov ecx, %d\n", divisor);
+        fprintf (state->ofp, "    cqo\n");
+        fprintf (state->ofp, "    idiv rcx\n");
+    
+    } else {
+    
+        fprintf (state->ofp, "    movl $%d, %%ecx\n", divisor);
+        fprintf (state->ofp, "    cqto\n");
+        fprintf (state->ofp, "    idivq %%rcx\n");
+    
+    }
+
+}
+
+static void emit_assignment_binary_op (enum token_kind op, int is_unsigned) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        switch (op) {
+        
+            case TOK_PLUS:      case TOK_PLUSEQ:
+            
+                fprintf (state->ofp, "    add rax, rdx\n");
+                break;
+            
+            case TOK_MINUS:     case TOK_MINUSEQ:
+            
+                fprintf (state->ofp, "    sub rax, rdx\n");
+                break;
+            
+            case TOK_STAR:      case TOK_STAREQ:
+            
+                fprintf (state->ofp, "    imul rax, rdx\n");
+                break;
+            
+            case TOK_BSLASH:    case TOK_SLASHEQ:
+            
+                fprintf (state->ofp, "    mov rcx, rdx\n");
+                
+                if (is_unsigned) {
+                
+                    fprintf (state->ofp, "    xor rdx, rdx\n");
+                    fprintf (state->ofp, "    div rcx\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    cqo\n");
+                    fprintf (state->ofp, "    idiv rcx\n");
+                
+                }
+                
+                break;
+            
+            case TOK_MOD:
+            
+                fprintf (state->ofp, "    mov rcx, rdx\n");
+                
+                if (is_unsigned) {
+                
+                    fprintf (state->ofp, "    xor rdx, rdx\n");
+                    fprintf (state->ofp, "    div rcx\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    cqo\n");
+                    fprintf (state->ofp, "    idiv rcx\n");
+                
+                }
+                
+                fprintf (state->ofp, "    mov rax, rdx\n");
+                break;
+            
+            case TOK_MODEQ:
+            
+                fprintf (state->ofp, "    mov rcx, rdx\n");
+                
+                if (is_unsigned) {
+                
+                    fprintf (state->ofp, "    xor rdx, rdx\n");
+                    fprintf (state->ofp, "    div rcx\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    cqo\n");
+                    fprintf (state->ofp, "    idiv rcx\n");
+                
+                }
+                
+                fprintf (state->ofp, "    mov rax, rdx\n");
+                break;
+            
+            case TOK_AMPER:     case TOK_ANDEQ:
+            
+                fprintf (state->ofp, "    and rax, rdx\n");
+                break;
+            
+            case TOK_PIPE:      case TOK_OREQ:
+            
+                fprintf (state->ofp, "    or rax, rdx\n");
+                break;
+            
+            case TOK_CARET:     case TOK_XOREQ:
+            
+                fprintf (state->ofp, "    xor rax, rdx\n");
+                break;
+            
+            case TOK_LSH:       case TOK_LSHEQ:
+            
+                fprintf (state->ofp, "    mov rcx, rdx\n");
+                fprintf (state->ofp, "    shl rax, cl\n");
+                
+                break;
+            
+            case TOK_RSH:       case TOK_RSHEQ:
+            
+                fprintf (state->ofp, "    mov rcx, rdx\n");
+                fprintf (state->ofp, is_unsigned ? "    shr rax, cl\n" : "    sar rax, cl\n");
+                
+                break;
+            
+            default:
+            
+                break;
+        
+        }
+    
+    } else {
+    
+        switch (op) {
+        
+            case TOK_PLUS:      case TOK_PLUSEQ:
+            
+                fprintf (state->ofp, "    addq %%rdx, %%rax\n");
+                break;
+            
+            case TOK_MINUS:     case TOK_MINUSEQ:
+            
+                fprintf (state->ofp, "    subq %%rdx, %%rax\n");
+                break;
+            
+            case TOK_STAR:      case TOK_STAREQ:
+            
+                fprintf (state->ofp, "    imulq %%rdx, %%rax\n");
+                break;
+            
+            case TOK_BSLASH:    case TOK_SLASHEQ:
+            
+                fprintf (state->ofp, "    movq %%rdx, %%rcx\n");
+                
+                if (is_unsigned) {
+                
+                    fprintf (state->ofp, "    xorq %%rdx, %%rdx\n");
+                    fprintf (state->ofp, "    divq %%rcx\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    cqto\n");
+                    fprintf (state->ofp, "    idivq %%rcx\n");
+                
+                }
+                
+                break;
+            
+            case TOK_MOD:
+            
+                fprintf (state->ofp, "    movq %%rdx, %%rcx\n");
+                
+                if (is_unsigned) {
+                
+                    fprintf (state->ofp, "    xorq %%rdx, %%rdx\n");
+                    fprintf (state->ofp, "    divq %%rcx\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    cqto\n");
+                    fprintf (state->ofp, "    idivq %%rcx\n");
+                
+                }
+                
+                fprintf (state->ofp, "    movq %%rdx, %%rax\n");
+                break;
+            
+            case TOK_MODEQ:
+            
+                fprintf (state->ofp, "    movq %%rdx, %%rcx\n");
+                
+                if (is_unsigned) {
+                
+                    fprintf (state->ofp, "    xorq %%rdx, %%rdx\n");
+                    fprintf (state->ofp, "    divq %%rcx\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    cqto\n");
+                    fprintf (state->ofp, "    idivq %%rcx\n");
+                
+                }
+                
+                fprintf (state->ofp, "    movq %%rdx, %%rax\n");
+                break;
+            
+            case TOK_AMPER:     case TOK_ANDEQ:
+            
+                fprintf (state->ofp, "    andq %%rdx, %%rax\n");
+                break;
+            
+            case TOK_PIPE:      case TOK_OREQ:
+            
+                fprintf (state->ofp, "    orq %%rdx, %%rax\n");
+                break;
+            
+            case TOK_CARET:     case TOK_XOREQ:
+            
+                fprintf (state->ofp, "    xorq %%rdx, %%rax\n");
+                break;
+            
+            case TOK_LSH:       case TOK_LSHEQ:
+            
+                fprintf (state->ofp, "    movq %%rdx, %%rcx\n");
+                fprintf (state->ofp, "    salq %%cl, %%rax\n");
+                
+                break;
+            
+            case TOK_RSH:       case TOK_RSHEQ:
+            
+                fprintf (state->ofp, "    movq %%rdx, %%rcx\n");
+                fprintf (state->ofp, is_unsigned ? "    shrq %%cl, %%rax\n" : "    sarq %%cl, %%rax\n");
+                
+                break;
+            
+            default:
+            
+                break;
+        
+        }
+    
+    }
+
+}
+
+static int token_is_floating_constant_now (void) {
+    return tok.kind == TOK_CFLOAT || tok.kind == TOK_CDOUBLE || tok.kind == TOK_CLDOUBLE;
+}
+
+static int64_s floating_constant_to_bits_now (int size) {
+
+    int64_s r;
+    
+    unsigned long bits32;
+    unsigned char bytes[8];
+    
+    int i;
+    
+    r.low = 0;
+    r.high = 0;
+    
+    if (size == (DATA_FLOAT & 0x1f)) {
+    
+        float f;
+        
+        if (tok.kind == TOK_CFLOAT) {
+            f = tok.val.f;
+        } else if (tok.kind == TOK_CLDOUBLE) {
+            f = (double) tok.val.ld;
+        } else {
+            f = tok.val.d;
+        }
+        
+        memcpy (&bits32, &f, sizeof (f));
+        
+        r.low = bits32;
+        get_token ();
+        
+        return r;
+    
+    }
+    
+    {
+    
+        double d;
+        
+        if (tok.kind == TOK_CFLOAT) {
+            d = (double) tok.val.f;
+        } else if (tok.kind == TOK_CLDOUBLE) {
+            d = (double) tok.val.ld;
+        } else {
+            d = tok.val.d;
+        }
+        
+        memset (bytes, 0, sizeof (bytes));
+        memcpy (bytes, &d, sizeof (d));
+        
+        for (i = 0; i < 4; i++) {
+            r.low |= ((unsigned long) bytes[i]) << (i * 8);
+        }
+        
+        for (i = 0; i < 4; i++) {
+            r.high |= ((unsigned long) bytes[i + 4]) << (i * 8);
+        }
+        
+        get_token ();
+        return r;
+    
+    }
+
+}
+
+static double floating_constant_to_ld_now (void) {
+
+    double v;
+    
+    if (tok.kind == TOK_CFLOAT) {
+        v = (float) tok.val.f;
+    } else if (tok.kind == TOK_CLDOUBLE) {
+        v = (double) tok.val.ld;
+    } else {
+        v = tok.val.d;
+    }
+    
+    get_token ();
+    return v;
+
+}
+
+static double int64_u32_base_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;
+
+}
+
+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)) {
+        return parse_floating_const_primary_now ();
+    }
+    
+    if (_accept (TOK_MINUS)) {
+        return -parse_floating_const_primary_now ();
+    }
+    
+    if (token_is_floating_constant_now ()) {
+        return floating_constant_to_ld_now ();
+    }
+    
+    iv = const64_from_current_operand ();
+    return int64_to_double_now (iv);
+
+}
+
+static double parse_floating_const_term_now (void) {
+
+    double rhs, v;
+    enum token_kind op;
+    
+    v = parse_floating_const_primary_now ();
+    
+    while (tok.kind == TOK_STAR || tok.kind == TOK_BSLASH) {
+    
+        op = tok.kind;
+        get_token ();
+        
+        rhs = parse_floating_const_primary_now ();
+        
+        if (op == TOK_STAR) {
+            v *= rhs;
+        } else {
+            v /= rhs;
+        }
+    
+    }
+    
+    return v;
+
+}
+
+static double parse_floating_const_expr_value_now (void) {
+
+    double rhs, v;
+    enum token_kind op;
+    
+    v = parse_floating_const_term_now ();
+    
+    while (tok.kind == TOK_PLUS || tok.kind == TOK_MINUS) {
+    
+        op = tok.kind;
+        get_token ();
+        
+        rhs = parse_floating_const_term_now ();
+        
+        if (op == TOK_PLUS) {
+            v += rhs;
+        } else {
+            v -= rhs;
+        }
+    
+    }
+    
+    return v;
+
+}
+
+static int64_s parse_floating_const_expr_bits_now (int size) {
+
+    double acc;
+    int64_s r;
+    
+    acc = parse_floating_const_expr_value_now ();
+    r.low = 0;
+    r.high = 0;
+    
+    if (size == (DATA_FLOAT & 0x1f)) {
+    
+        float f;
+        unsigned long bits32;
+        
+        f = (float) acc;
+        bits32 = 0;
+        memcpy (&bits32, &f, sizeof (f));
+        r.low = bits32;
+        return r;
+    
+    }
+    
+    {
+    
+        unsigned char bytes[8];
+        
+        double d = (double) acc;
+        int i;
+        
+        memset (bytes, 0, sizeof (bytes));
+        memcpy (bytes, &d, sizeof (d));
+        
+        for (i = 0; i < 4; i++) {
+            r.low |= ((unsigned long) bytes[i]) << (i * 8);
+        }
+        
+        for (i = 0; i < 4; i++) {
+            r.high |= ((unsigned long) bytes[i + 4]) << (i * 8);
+        }
+        
+        return r;
+    
+    }
+
+}
+
+static void emit_load_floating_const_bits_now (int size, int64_s v) {
+
+    int lab;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    lab = anon_label++;
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+    
+        switch_section (SECTION_DATA);
+        
+        if (size == (DATA_DOUBLE & 0x1f)) {
+        
+            /*
+             * 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 0%08lXh\n", lab, v.low & U32_MASK);
+        }
+        
+        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) {
+        
+            switch_section (SECTION_DATA);
+            
+            fprintf (state->ofp, "LC%d_flt:\n", lab);
+            fprintf (state->ofp, "    dd %lu\n", v.low & U32_MASK);
+            
+            if (size == (DATA_DOUBLE & 0x1f)) {
+                fprintf (state->ofp, "    dd %lu\n", v.high & U32_MASK);
+            }
+            
+            switch_section (SECTION_TEXT);
+            fprintf (state->ofp, "    fld %s [LC%d_flt]\n", size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", lab);
+        
+        } else {
+        
+            switch_section (SECTION_DATA);
+            
+            fprintf (state->ofp, ".LC%d_flt:\n", lab);
+            fprintf (state->ofp, "    .long %lu\n", v.low & U32_MASK);
+            
+            if (size == (DATA_DOUBLE & 0x1f)) {
+                fprintf (state->ofp, "    .long %lu\n", v.high & U32_MASK);
+            }
+            
+            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);
+            } else {
+                fprintf (state->ofp, "    fld%s .LC%d_flt\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", lab);
+            }
+        
+        }
+    
+    }
+
+}
+
+static void emit_load_floating_symbol_now (struct local_symbol *sym, const char *name, int size) {
+
+    char memref[64];
+    const char *label;
+    const char *asm_name;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    asm_name = asm_global_symbol_name (name);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (sym) {
+        
+            if (sym->is_static && sym->static_label) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fld %s [%s]\n" : "    fld %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", sym->static_label);
+            } else {
+            
+                format_intel_rbp_offset (memref, sizeof (memref), sym->offset);
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fld %s %s\n" : "    fld %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", memref);
+            
+            }
+        
+        } else {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fld %s [%s]\n" : "    fld %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", asm_name);
+        }
+    
+    } else {
+    
+        if (sym) {
+        
+            label = (sym->is_static && sym->static_label) ? sym->static_label : 0;
+            
+            if (label) {
+                fprintf (state->ofp, "    fld%s %s\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", label);
+            } else {
+                fprintf (state->ofp, "    fld%s %ld(%%rbp)\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", sym->offset);
+            }
+        
+        } else {
+            fprintf (state->ofp, "    fld%s %s\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", asm_name);
+        }
+    
+    }
+
+}
+
+static void emit_load_floating_member_symbol_now (struct local_symbol *sym, const char *name, int offset, int size) {
+
+    char memref[64];
+    char labelref[256];
+    
+    const char *label;
+    const char *asm_name;
+    const char *opsize;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    opsize = size == (DATA_FLOAT & 0x1f) ? "dword" : "qword";
+    asm_name = asm_global_symbol_name (name);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (sym) {
+        
+            if (sym->is_static && sym->static_label) {
+            
+                if (offset) {
+                
+                    sprintf (labelref, "%s + %d", sym->static_label, offset);
+                    label = labelref;
+                
+                } else {
+                    label = sym->static_label;
+                }
+                
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fld %s [%s]\n" : "    fld %s ptr %s\n"), opsize, label);
+            
+            } else {
+            
+                format_intel_rbp_offset (memref, sizeof (memref), sym->offset + offset);
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fld %s %s\n" : "    fld %s ptr %s\n"), opsize, memref);
+            
+            }
+        
+        } else {
+        
+            if (offset) {
+            
+                sprintf (labelref, "%s + %d", asm_name, offset);
+                label = labelref;
+            
+            } else {
+                label = asm_name;
+            }
+            
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fld %s [%s]\n" : "    fld %s ptr %s\n"), opsize, label);
+        
+        }
+    
+    } else {
+    
+        if (sym) {
+        
+            label = (sym->is_static && sym->static_label) ? sym->static_label : 0;
+            
+            if (label) {
+            
+                if (offset) {
+                
+                    sprintf (labelref, "%s+%d", label, offset);
+                    label = labelref;
+                
+                }
+                
+                fprintf (state->ofp, "    fld%s %s\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", label);
+            
+            } else {
+                fprintf (state->ofp, "    fld%s %ld(%%rbp)\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", sym->offset + offset);
+            }
+        
+        } else {
+        
+            if (offset) {
+            
+                sprintf (labelref, "%s+%d", asm_name, offset);
+                asm_name = labelref;
+            
+            }
+            
+            fprintf (state->ofp, "    fld%s %s\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", asm_name);
+        
+        }
+    
+    }
+
+}
+
+static void emit_duplicate_floating_stack_top_now (void) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_NASM) {
+        fprintf (state->ofp, "    fld st0\n");
+    } else if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    fld st(0)\n");
+    } else {
+        fprintf (state->ofp, "    fld %%st(0)\n");
+    }
+
+}
+
+static void emit_store_floating_symbol_now (struct local_symbol *sym, const char *name, int size) {
+
+    char memref[64];
+    const char *label;
+    const char *asm_name;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    asm_name = asm_global_symbol_name (name);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (sym) {
+        
+            if (sym->is_static && sym->static_label) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fstp %s [%s]\n" : "    fstp %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", sym->static_label);
+            } else {
+            
+                format_intel_rbp_offset (memref, sizeof (memref), sym->offset);
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fstp %s %s\n" : "    fstp %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", memref);
+            
+            }
+        
+        } else {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fstp %s [%s]\n" : "    fstp %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", asm_name);
+        }
+    
+    } else {
+    
+        if (sym) {
+        
+            label = (sym->is_static && sym->static_label) ? sym->static_label : 0;
+            
+            if (label) {
+                fprintf (state->ofp, "    fstp%s %s\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", label);
+            } else {
+                fprintf (state->ofp, "    fstp%s %ld(%%rbp)\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", sym->offset);
+            }
+        
+        } else {
+            fprintf (state->ofp, "    fstp%s %s\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", asm_name);
+        }
+    
+    }
+
+}
+
+static void emit_load_any_symbol_as_floating_now (struct local_symbol *src, const char *name, int size, int is_floating) {
+
+    if (is_floating) {
+    
+        emit_load_floating_symbol_now (src, name, size);
+        return;
+    
+    }
+    
+    if (src) {
+    
+        if (src->is_static && src->static_label) {
+            emit_load_global_to_reg_ex ("rax", src->static_label, src->size, src->is_unsigned);
+        } else {
+            emit_load_local_to_reg_ex ("rax", src->offset, src->size, src->is_unsigned);
+        }
+    
+    } else {
+        emit_load_global_to_reg_ex ("rax", name, size, get_global_symbol_unsigned (name));
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    sub rsp, 8\n");
+        
+        if (state->syntax & ASM_SYNTAX_NASM) {
+        
+            fprintf (state->ofp, "    mov dword [rsp], eax\n");
+            fprintf (state->ofp, "    fild dword [rsp]\n");
+        
+        } else {
+        
+            fprintf (state->ofp, "    mov dword ptr [rsp], eax\n");
+            fprintf (state->ofp, "    fild dword ptr [rsp]\n");
+        
+        }
+        
+        fprintf (state->ofp, "    add rsp, 8\n");
+    
+    } else {
+    
+        fprintf (state->ofp, "    subq $8, %%rsp\n");
+        fprintf (state->ofp, "    movl %%eax, (%%rsp)\n");
+        fprintf (state->ofp, "    fildl (%%rsp)\n");
+        fprintf (state->ofp, "    addq $8, %%rsp\n");
+    
+    }
+
+}
+
+static int emit_load_floating_prefix_incdec_now (void) {
+
+    enum token_kind op;
+    char *name;
+    
+    const char *name_start, *name_caret;
+    unsigned long name_line;
+    
+    struct local_symbol *sym;
+    int size;
+    int is_floating;
+    
+    if (!parse_incdec_identifier_now (&op, &name, &name_start, &name_caret, &name_line)) {
+        return 0;
+    }
+    
+    if (!name) {
+        return 1;
+    }
+    
+    sym = find_local_symbol (name);
+    emit_incdec_symbol_now (sym, name, op, name_line, name_start, name_caret);
+    
+    if (sym) {
+    
+        size = sym->size;
+        is_floating = sym->is_floating;
+        
+        emit_load_any_symbol_as_floating_now (sym, name, size, is_floating);
+    
+    } else if (find_global_symbol (name) >= 0) {
+    
+        size = get_global_symbol_size (name);
+        is_floating = get_global_symbol_floating (name);
+        
+        emit_load_any_symbol_as_floating_now (0, name, size, is_floating);
+    
+    }
+    
+    free (name);
+    return 1;
+
+}
+
+static void emit_load_floating_rhs_expression_now (int result_size);
+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_rdx_if_possible (void);
+
+static void emit_statement_label (int label);
+static void emit_statement_label_raw (int label);
+static void emit_statement_jump (int label);
+
+static void emit_rax_bool_to_floating_stack_now (void) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    sub rsp, 8\n");
+        
+        if (state->syntax & ASM_SYNTAX_NASM) {
+        
+            fprintf (state->ofp, "    mov dword [rsp], eax\n");
+            fprintf (state->ofp, "    fild dword [rsp]\n");
+        
+        } else {
+        
+            fprintf (state->ofp, "    mov dword ptr [rsp], eax\n");
+            fprintf (state->ofp, "    fild dword ptr [rsp]\n");
+        
+        }
+        
+        fprintf (state->ofp, "    add rsp, 8\n");
+    
+    } else {
+    
+        fprintf (state->ofp, "    subq $8, %%rsp\n");
+        fprintf (state->ofp, "    movl %%eax, (%%rsp)\n");
+        fprintf (state->ofp, "    fildl (%%rsp)\n");
+        fprintf (state->ofp, "    addq $8, %%rsp\n");
+    
+    }
+    
+    floating_rhs_result_in_eax_bool = 0;
+
+}
+
+static const char *floating_compare_true_setcc_now (enum token_kind op) {
+
+    switch (op) {
+    
+        case TOK_LESS:
+        
+            return "setb";
+        
+        case TOK_LTEQ:
+        
+            return "setbe";
+        
+        case TOK_GREATER:
+        
+            return "seta";
+        
+        case TOK_GTEQ:
+        
+            return "setae";
+        
+        case TOK_EQEQ:
+        
+            return "sete";
+        
+        case TOK_NOTEQ:
+        
+            return "setne";
+        
+        default:
+        
+            return "setz";
+    
+    }
+
+}
+
+static void emit_floating_compare_to_rax_now (enum token_kind op) {
+
+    const char *setcc;
+    
+    if (!state->ofp) {
+    
+        floating_rhs_result_in_eax_bool = 1;
+        return;
+    
+    }
+    
+    setcc = floating_compare_true_setcc_now (op);
+    
+    if (state->syntax & ASM_SYNTAX_NASM) {
+    
+        fprintf (state->ofp, "    fxch st1\n");
+        fprintf (state->ofp, "    fcompp\n");
+        fprintf (state->ofp, "    fnstsw ax\n");
+        fprintf (state->ofp, "    sahf\n");
+        fprintf (state->ofp, "    %s al\n", setcc);
+        fprintf (state->ofp, "    movzx eax, al\n");
+    
+    } else if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    fxch st(1)\n");
+        fprintf (state->ofp, "    fcompp\n");
+        fprintf (state->ofp, "    fnstsw ax\n");
+        fprintf (state->ofp, "    sahf\n");
+        fprintf (state->ofp, "    %s al\n", setcc);
+        fprintf (state->ofp, "    movzx eax, al\n");
+    
+    } else {
+    
+        fprintf (state->ofp, "    fxch %%st(1)\n");
+        fprintf (state->ofp, "    fcompp\n");
+        fprintf (state->ofp, "    fnstsw %%ax\n");
+        fprintf (state->ofp, "    sahf\n");
+        fprintf (state->ofp, "    %s %%al\n", setcc);
+        fprintf (state->ofp, "    movzbl %%al, %%eax\n");
+    
+    }
+    
+    floating_rhs_result_in_eax_bool = 1;
+
+}
+
+static void emit_floating_truth_to_rax_now (void) {
+
+    if (!state->ofp) {
+    
+        floating_rhs_result_in_eax_bool = 1;
+        return;
+    
+    }
+    
+    /*
+     * A floating value used as a condition is true when it compares != 0.0.
+     * Testing the stored IEEE bits is wrong for values such as -0.0, whose
+     * bit pattern is non-zero but whose C truth value is false.
+     */
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    fldz\n");
+    } else {
+        fprintf (state->ofp, "    fldz\n");
+    }
+    
+    emit_floating_compare_to_rax_now (TOK_NOTEQ);
+
+}
+
+static void emit_fild_rax_now (void) {
+
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    sub rsp, 8\n");
+        
+        if (state->syntax & ASM_SYNTAX_NASM) {
+        
+            fprintf (state->ofp, "    mov dword [rsp], eax\n");
+            fprintf (state->ofp, "    fild dword [rsp]\n");
+        
+        } else {
+        
+            fprintf (state->ofp, "    mov dword ptr [rsp], eax\n");
+            fprintf (state->ofp, "    fild dword ptr [rsp]\n");
+        
+        }
+        
+        fprintf (state->ofp, "    add rsp, 8\n");
+    
+    } else {
+    
+        fprintf (state->ofp, "    subq $8, %%rsp\n");
+        fprintf (state->ofp, "    movl %%eax, (%%rsp)\n");
+        fprintf (state->ofp, "    fildl (%%rsp)\n");
+        fprintf (state->ofp, "    addq $8, %%rsp\n");
+    
+    }
+
+}
+
+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_rax_now ();
+
+}
+
+static void emit_load_floating_rhs_operand_now (int result_size) {
+
+    if (tok.kind == TOK_PLUS || tok.kind == TOK_MINUS) {
+    
+        enum token_kind unary_op = tok.kind;
+        get_token ();
+        
+        emit_load_floating_rhs_operand_now (result_size);
+        
+        if (unary_op == TOK_MINUS) {
+            fprintf (state->ofp, "    fchs\n");
+        }
+        
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_STAR) {
+    
+        int deref_size = result_size;
+        int deref_is_floating = 1;
+        
+        get_token ();
+        
+        if (tok.kind == TOK_LPAREN) {
+        
+            get_token ();
+            
+            if (is_type_start (tok.kind) && parse_deref_cast_type_name (&deref_size)) {
+            
+                emit_load_any_deref_as_floating_now ("rax", deref_size, last_deref_cast_type_is_floating);
+                return;
+            
+            }
+            
+            emit_load_assignment_rhs_expression_to_reg ("rax");
+            expect (TOK_RPAREN, ")");
+            
+            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 ("rax", deref_size, deref_is_floating);
+            return;
+        
+        }
+        
+        emit_load_assignment_rhs_to_reg ("rax");
+        
+        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 ("rax", deref_size, deref_is_floating);
+        return;
+    
+    }
+    
+    if (_accept (TOK_LPAREN)) {
+    
+        if (token_starts_type_name ()) {
+        
+            int cast_size = 0;
+            int cast_is_unsigned = 0;
+            int cast_is_pointer = 0;
+            
+            if (parse_cast_type_name (&cast_size, &cast_is_unsigned, &cast_is_pointer)) {
+            
+                if (!cast_is_pointer && !last_cast_type_is_floating) {
+                
+                    if (rhs_current_operand_is_floating_now ()) {
+                    
+                        emit_load_floating_rhs_operand_now (result_size);
+                        
+                        if (floating_rhs_result_in_eax_bool) {
+                        
+                            emit_extend_pair_high_from_low ("rax", "rdx", cast_size, cast_is_unsigned);
+                            floating_rhs_result_in_eax_bool = 0;
+                        
+                        } else {
+                            emit_floating_stack_to_int_pair_now ("rax", "rdx");
+                        }
+                        
+                        if ((cast_size & 0x1f) != (DATA_LLONG & 0x1f)) {
+                            emit_extend_pair_high_from_low ("rax", "rdx", cast_size, cast_is_unsigned);
+                        }
+                    
+                    } else {
+                        emit_load_assignment_rhs_to_pair ("rax", "rdx");
+                    }
+                    
+                    emit_integer_pair_to_floating_stack_now ("rax", "rdx", cast_size);
+                    return;
+                
+                }
+                
+                emit_load_floating_rhs_operand_now (result_size);
+                return;
+            
+            }
+        
+        }
+        
+        emit_load_floating_rhs_expression_now (result_size);
+        expect (TOK_RPAREN, ")");
+        
+        if (floating_rhs_result_in_eax_bool && tok.kind != TOK_QMARK) {
+            emit_rax_bool_to_floating_stack_now ();
+        }
+        
+        return;
+    
+    }
+    
+    if (emit_load_floating_prefix_incdec_now ()) {
+        return;
+    }
+    
+    if (token_is_sizeof_keyword ()) {
+    
+        int64_s v = sizeof_from_current_token ();
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, "    sub rsp, 8\n");
+            
+            if (state->syntax & ASM_SYNTAX_NASM) {
+                
+                fprintf (state->ofp, "    mov dword [rsp], %lu\n", v.low & U32_MASK);
+                fprintf (state->ofp, "    fild dword [rsp]\n");
+            
+            } else {
+            
+                fprintf (state->ofp, "    mov dword ptr [rsp], %lu\n", v.low & U32_MASK);
+                fprintf (state->ofp, "    fild dword ptr [rsp]\n");
+            
+            }
+            
+            fprintf (state->ofp, "    add rsp, 8\n");
+        
+        } else {
+        
+            fprintf (state->ofp, "    subq $8, %%rsp\n");
+            fprintf (state->ofp, "    movl $%lu, (%%rsp)\n", v.low & U32_MASK);
+            fprintf (state->ofp, "    fildl (%%rsp)\n");
+            fprintf (state->ofp, "    addq $8, %%rsp\n");
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_SCC_BUILTIN_VA_ARG) {
+    
+        int va_size = DATA_DOUBLE & 0x1f;
+        int va_unsigned = 0;
+        int va_pointer = 0;
+        int va_floating = 0;
+        
+        get_token ();
+        
+        emit_parse_builtin_va_arg_address_to_reg_now ("rax", &va_size, &va_unsigned, &va_pointer, &va_floating);
+        emit_load_floating_deref_reg_now ("rax", va_size);
+        
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_IDENT) {
+    
+        char *name = xstrdup (tok.ident);
+        
+        const char *name_start = tok.start, *name_caret = tok.caret;
+        unsigned long name_line = get_line_number ();
+        
+        struct local_symbol *src = find_local_symbol (name);
+        get_token ();
+        
+        if (strcmp (name, "__scc_builtin_va_arg") == 0 && tok.kind == TOK_LPAREN) {
+        
+            int va_size = DATA_DOUBLE & 0x1f;
+            int va_unsigned = 0;
+            int va_pointer = 0;
+            int va_floating = 0;
+            
+            emit_parse_builtin_va_arg_address_to_reg_now ("rax", &va_size, &va_unsigned, &va_pointer, &va_floating);
+            emit_load_floating_deref_reg_now ("rax", va_size);
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (is_assignment_operator (tok.kind)) {
+        
+            enum token_kind assign_op = tok.kind;
+            
+            int dst_size = 0;
+            int dst_is_floating = 0;
+            int have_dst = 0;
+            
+            if (src) {
+            
+                dst_size = src->size;
+                
+                dst_is_floating = src->is_floating;
+                have_dst = 1;
+            
+            } else if (find_global_symbol (name) >= 0) {
+            
+                dst_size = get_global_symbol_size (name);
+                
+                dst_is_floating = get_global_symbol_floating (name);
+                have_dst = 1;
+            
+            }
+            
+            if (have_dst && dst_is_floating && floating_assignment_operator_supported_now (assign_op)) {
+            
+                get_token ();
+                
+                if (assign_op == TOK_ASSIGN) {
+                    emit_load_floating_rhs_expression_now (dst_size);
+                } else {
+                
+                    emit_load_floating_symbol_now (src, name, dst_size);
+                    emit_load_floating_rhs_expression_now (dst_size);
+                    
+                    emit_floating_binary_now (assign_op);
+                
+                }
+                
+                emit_duplicate_floating_stack_top_now ();
+                emit_store_floating_symbol_now (src, name, dst_size);
+                
+                free (name);
+                return;
+            
+            }
+        
+        }
+        
+        if (tok.kind == TOK_LPAREN) {
+        
+            if (!find_local_symbol (name)) {
+                ensure_global_function_symbol (name, name_start, name_caret, name_line);
+            }
+            
+            if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION && get_global_symbol_returns_void (name)) {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "void function '%s' used as a value", name);
+            }
+            
+            emit_call_identifier_to_reg_now (name, "rax", name_start, name_caret, name_line);
+            
+            if (!get_global_function_returns_floating (name)) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    fprintf (state->ofp, "    sub rsp, 8\n");
+                    
+                    if (state->syntax & ASM_SYNTAX_NASM) {
+                    
+                        fprintf (state->ofp, "    mov dword [rsp], eax\n");
+                        fprintf (state->ofp, "    fild dword [rsp]\n");
+                    
+                    } else {
+                    
+                        fprintf (state->ofp, "    mov dword ptr [rsp], eax\n");
+                        fprintf (state->ofp, "    fild dword ptr [rsp]\n");
+                    
+                    }
+                    
+                    fprintf (state->ofp, "    add rsp, 8\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    subq $8, %%rsp\n");
+                    fprintf (state->ofp, "    movl %%eax, (%%rsp)\n");
+                    fprintf (state->ofp, "    fildl (%%rsp)\n");
+                    fprintf (state->ofp, "    addq $8, %%rsp\n");
+                
+                }
+            
+            } else {
+                amd64_emit_load_xmm0_to_floating_stack_now (get_global_symbol_size (name));
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_LBRACK && (src || find_global_symbol (name) >= 0)) {
+        
+            int elem_size;
+            int pointer_depth;
+            int pointed_size;
+            
+            if (src) {
+            
+                elem_size = src->is_array ?
+                    (src->pointer_depth ? DATA_PTR : (src->array_element_size > 0 ? src->array_element_size : src->pointed_size)) :
+                    (src->pointer_depth > 1 ? DATA_PTR : src->pointed_size);
+                
+                pointer_depth = src->pointer_depth;
+                pointed_size = src->pointed_size;
+                
+                if (src->is_array) {
+                
+                    if (src->is_static && src->static_label) {
+                        emit_load_symbol_address_to_reg_now ("rax", src->static_label, 0, 0);
+                    } else {
+                        emit_load_symbol_address_to_reg_now ("rax", 0, src->offset, 1);
+                    }
+                
+                } else if (src->is_static && src->static_label) {
+                    emit_load_global_to_reg ("rax", src->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg ("rax", src->offset, DATA_PTR);
+                }
+            
+            } else {
+            
+                elem_size = get_global_symbol_array (name) ?
+                    (get_global_symbol_pointer_depth (name) ? DATA_PTR :
+                        (get_global_symbol_array_element_size (name) > 0 ? get_global_symbol_array_element_size (name) : get_global_symbol_pointed_size (name))) :
+                    (get_global_symbol_pointer_depth (name) > 1 ? DATA_PTR : get_global_symbol_pointed_size (name));
+                
+                pointer_depth = get_global_symbol_pointer_depth (name);
+                pointed_size = get_global_symbol_pointed_size (name);
+                
+                if (get_global_symbol_array (name)) {
+                    emit_load_symbol_address_to_reg_now ("rax", name, 0, 0);
+                } else {
+                    emit_load_global_to_reg ("rax", name, DATA_PTR);
+                }
+            
+            }
+            
+            if (elem_size <= 0) {
+                elem_size = DATA_INT & 0x1f;
+            }
+            
+            emit_parse_postfix_subscripts_to_reg_now ("rax", elem_size, pointer_depth, pointed_size);
+            
+            if ((elem_size & 0x1f) > DATA_PTR) {
+                emit_load_floating_deref_reg_now ("rax", elem_size);
+            } else {
+                emit_fild_rax_now ();
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_ARROW && (src || find_global_symbol (name) >= 0)) {
+        
+            char *member;
+            
+            const char *member_start;
+            const char *member_caret;
+            
+            unsigned long member_line;
+            
+            int member_offset = 0;
+            int member_size = result_size;
+            int member_elem_size = result_size;
+            int member_pointer_depth = 0;
+            int member_is_array = 0;
+            int member_is_floating = 0;
+            int base_size;
+            
+            const char *base_tag_name;
+            
+            if (src) {
+            
+                base_size = src->pointed_size;
+                base_tag_name = src->pointed_tag_name;
+            
+            } else {
+            
+                base_size = get_global_symbol_pointed_size (name);
+                base_tag_name = get_global_symbol_tag_name (name);
+            
+            }
+            
+            get_token ();
+            
+            member_start = tok.start;
+            member_caret = tok.caret;
+            member_line = get_line_number ();
+            
+            if (tok.kind != TOK_IDENT) {
+            
+                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after ->");
+                
+                free (name);
+                return;
+            
+            }
+            
+            member = xstrdup (tok.ident);
+            get_token ();
+            
+            if (!find_member_info_ex_bounded (member, base_size, base_tag_name, &member_offset, &member_size, &member_elem_size, &member_pointer_depth, &member_is_array, &member_is_floating)) {
+            
+                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+                
+                free (member);
+                free (name);
+                
+                return;
+            
+            }
+            
+            free (member);
+            
+            if (src) {
+            
+                if (src->is_static && src->static_label) {
+                    emit_load_global_to_reg ("rax", src->static_label, DATA_PTR & 0x1f);
+                } else {
+                    emit_load_local_to_reg ("rax", src->offset, DATA_PTR & 0x1f);
+                }
+            
+            } else {
+                emit_load_global_to_reg ("rax", name, DATA_PTR & 0x1f);
+            }
+            
+            if (member_is_floating) {
+                emit_load_floating_member_from_addr_reg_now ("rax", member_offset, member_size);
+            } else {
+            
+                emit_load_member_from_addr_reg_now ("rax", "rax", member_offset, member_size);
+                emit_rax_bool_to_floating_stack_now ();
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_DOT && (src || find_global_symbol (name) >= 0)) {
+        
+            char *member;
+            
+            const char *member_start;
+            const char *member_caret;
+            const char *current_tag_name;
+            
+            unsigned long member_line;
+            
+            int member_offset = 0;
+            int member_size = result_size;
+            int member_elem_size = result_size;
+            int member_pointer_depth = 0;
+            int member_is_array = 0;
+            int member_is_floating = 0;
+            int current_size;
+            
+            if (src) {
+            
+                current_size = src->size;
+                current_tag_name = src->tag_name;
+            
+            } else {
+            
+                current_size = get_global_symbol_size (name);
+                current_tag_name = get_global_symbol_tag_name (name);
+            
+            }
+            
+            get_token ();
+            
+            member_start = tok.start;
+            member_caret = tok.caret;
+            member_line = get_line_number ();
+            
+            if (tok.kind != TOK_IDENT) {
+            
+                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after .");
+                
+                free (name);
+                return;
+            
+            }
+            
+            member = xstrdup (tok.ident);
+            get_token ();
+            
+            if (!find_member_info_ex_bounded (member, current_size, current_tag_name, &member_offset, &member_size, &member_elem_size, &member_pointer_depth, &member_is_array, &member_is_floating)) {
+            
+                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+                
+                free (member);
+                free (name);
+                
+                return;
+            
+            }
+            
+            free (member);
+            
+            if (tok.kind != TOK_DOT && tok.kind != TOK_ARROW && member_is_floating) {
+            
+                emit_load_floating_member_symbol_now (src, name, member_offset, member_size);
+                
+                free (name);
+                return;
+            
+            }
+            
+            emit_load_symbol_address_for_copy_now ("rax", src, name);
+            emit_add_const_to_reg_now ("rax", member_offset);
+            
+            current_tag_name = last_found_member_tag_name;
+            
+            if (member_pointer_depth > 0 || member_is_array) {
+                current_size = member_elem_size;
+            } else {
+                current_size = member_size;
+            }
+            
+            while (tok.kind == TOK_DOT || tok.kind == TOK_ARROW) {
+            
+                enum token_kind member_op = tok.kind;
+                
+                get_token ();
+                
+                member_start = tok.start;
+                member_caret = tok.caret;
+                member_line = get_line_number ();
+                
+                if (tok.kind != TOK_IDENT) {
+                
+                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+                    
+                    free (name);
+                    return;
+                
+                }
+                
+                member = xstrdup (tok.ident);
+                get_token ();
+                
+                if (!find_member_info_ex_bounded (member, current_size, current_tag_name, &member_offset, &member_size, &member_elem_size, &member_pointer_depth, &member_is_array, &member_is_floating)) {
+                
+                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+                    
+                    free (member);
+                    free (name);
+                    
+                    return;
+                
+                }
+                
+                free (member);
+                
+                if (member_op == TOK_ARROW) {
+                    emit_load_deref_reg_now ("rax", DATA_PTR & 0x1f);
+                }
+                
+                emit_add_const_to_reg_now ("rax", member_offset);
+                
+                current_tag_name = last_found_member_tag_name;
+                
+                if (member_pointer_depth > 0 || member_is_array) {
+                    current_size = member_elem_size;
+                } else {
+                    current_size = member_size;
+                }
+            
+            }
+            
+            if (member_is_floating) {
+                emit_load_floating_member_from_addr_reg_now ("rax", 0, member_size);
+            } else {
+            
+                emit_load_deref_reg_now ("rax", member_size);
+                emit_rax_bool_to_floating_stack_now ();
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (src) {
+        
+            if (src->is_floating) {
+                emit_load_floating_symbol_now (src, name, src->size);
+            } else {
+            
+                if (src->is_static && src->static_label) {
+                    emit_load_global_to_reg_ex ("rax", src->static_label, src->size, src->is_unsigned);
+                } else {
+                    emit_load_local_to_reg_ex ("rax", src->offset, src->size, src->is_unsigned);
+                }
+                
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    fprintf (state->ofp, "    sub rsp, 8\n");
+                    
+                    if (state->syntax & ASM_SYNTAX_NASM) {
+                    
+                        fprintf (state->ofp, "    mov dword [rsp], eax\n");
+                        fprintf (state->ofp, "    fild dword [rsp]\n");
+                    
+                    } else {
+                    
+                        fprintf (state->ofp, "    mov dword ptr [rsp], eax\n");
+                        fprintf (state->ofp, "    fild dword ptr [rsp]\n");
+                    
+                    }
+                    
+                    fprintf (state->ofp, "    add rsp, 8\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    subq $8, %%rsp\n");
+                    fprintf (state->ofp, "    movl %%eax, (%%rsp)\n");
+                    fprintf (state->ofp, "    fildl (%%rsp)\n");
+                    fprintf (state->ofp, "    addq $8, %%rsp\n");
+                
+                }
+            
+            }
+            
+            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+            
+                enum token_kind postfix_op = tok.kind;
+                get_token ();
+                
+                emit_incdec_symbol_now (src, name, postfix_op, name_line, name_start, name_caret);
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (find_global_symbol (name) >= 0) {
+        
+            if (get_global_symbol_floating (name)) {
+                emit_load_floating_symbol_now (0, name, get_global_symbol_size (name));
+            } else {
+            
+                emit_load_global_to_reg_ex ("rax", name, get_global_symbol_size (name), get_global_symbol_unsigned (name));
+                
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    fprintf (state->ofp, "    sub rsp, 8\n");
+                    
+                    if (state->syntax & ASM_SYNTAX_NASM) {
+                    
+                        fprintf (state->ofp, "    mov dword [rsp], eax\n");
+                        fprintf (state->ofp, "    fild dword [rsp]\n");
+                    
+                    } else {
+                    
+                        fprintf (state->ofp, "    mov dword ptr [rsp], eax\n");
+                        fprintf (state->ofp, "    fild dword ptr [rsp]\n");
+                    
+                    }
+                    
+                    fprintf (state->ofp, "    add rsp, 8\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    subq $8, %%rsp\n");
+                    fprintf (state->ofp, "    movl %%eax, (%%rsp)\n");
+                    fprintf (state->ofp, "    fildl (%%rsp)\n");
+                    fprintf (state->ofp, "    addq $8, %%rsp\n");
+                
+                }
+            
+            }
+            
+            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+            
+                enum token_kind postfix_op = tok.kind;
+                get_token ();
+                
+                emit_incdec_symbol_now (0, name, postfix_op, name_line, name_start, name_caret);
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        free (name);
+    
+    }
+    
+    if (token_is_floating_constant_now ()) {
+    
+        emit_load_floating_const_bits_now (result_size, floating_constant_to_bits_now (result_size));
+        return;
+    
+    }
+    
+    if (recover_unknown_rhs_identifier ()) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    fldz\n");
+        } else {
+            fprintf (state->ofp, "    fldz\n");
+        }
+        return;
+    
+    }
+    
+    {
+    
+        int64_s v = const64_from_current_operand ();
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, "    sub rsp, 8\n");
+            
+            if (state->syntax & ASM_SYNTAX_NASM) {
+            
+                fprintf (state->ofp, "    mov dword [rsp], %lu\n", v.low & U32_MASK);
+                fprintf (state->ofp, "    fild dword [rsp]\n");
+            
+            } else {
+            
+                fprintf (state->ofp, "    mov dword ptr [rsp], %lu\n", v.low & U32_MASK);
+                fprintf (state->ofp, "    fild dword ptr [rsp]\n");
+            
+            }
+            
+            fprintf (state->ofp, "    add rsp, 8\n");
+        
+        } else {
+        
+            fprintf (state->ofp, "    subq $8, %%rsp\n");
+            fprintf (state->ofp, "    movl $%lu, (%%rsp)\n", v.low & U32_MASK);
+            fprintf (state->ofp, "    fildl (%%rsp)\n");
+            fprintf (state->ofp, "    addq $8, %%rsp\n");
+        
+        }
+    
+    }
+
+}
+
+static int token_is_floating_binary_now (enum token_kind k) {
+    return k == TOK_PLUS || k == TOK_MINUS || k == TOK_STAR || k == TOK_BSLASH;
+}
+
+static void emit_floating_binary_now (enum token_kind k) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    switch (k) {
+    
+        case TOK_PLUS:      case TOK_PLUSEQ:
+        
+            fprintf (state->ofp, "    faddp\n");
+            break;
+        
+        case TOK_MINUS:     case TOK_MINUSEQ:
+        
+            fprintf (state->ofp, "    fsubrp\n");
+            break;
+        
+        case TOK_STAR:      case TOK_STAREQ:
+        
+            fprintf (state->ofp, "    fmulp\n");
+            break;
+        
+        case TOK_BSLASH:    case TOK_SLASHEQ:
+        
+            fprintf (state->ofp, "    fdivrp\n");
+            break;
+        
+        default:
+        
+            break;
+    
+    }
+
+}
+
+static void emit_scale_reg_for_pointer_compound_assignment_now (const char *reg, struct local_symbol *lhs, const char *name, enum token_kind op) {
+
+    int pointer_depth;
+    int pointed_size;
+    int elem_size;
+    
+    if (op != TOK_PLUSEQ && op != TOK_MINUSEQ) {
+        return;
+    }
+    
+    pointer_depth = lhs ? lhs->pointer_depth : get_global_symbol_pointer_depth (name);
+    pointed_size = lhs ? lhs->pointed_size : get_global_symbol_pointed_size (name);
+    
+    if (pointer_depth <= 0) {
+        return;
+    }
+    
+    elem_size = pointer_depth > 1 ? DATA_PTR : pointed_size;
+    
+    if (elem_size > 1) {
+        emit_scale_reg_by_const_now (reg, elem_size);
+    }
+
+}
+
+static int floating_assignment_operator_supported_now (enum token_kind op) {
+    return op == TOK_ASSIGN || op == TOK_PLUSEQ || op == TOK_MINUSEQ || op == TOK_STAREQ || op == TOK_SLASHEQ;
+}
+
+static void emit_load_floating_rhs_expression_now (int result_size) {
+
+    enum token_kind op;
+    
+    int false_label;
+    int end_label;
+    
+    floating_rhs_result_in_eax_bool = 0;
+    emit_load_floating_rhs_operand_now (result_size);
+    
+    while (token_is_floating_binary_now (tok.kind)) {
+    
+        if (floating_rhs_result_in_eax_bool) {
+            emit_rax_bool_to_floating_stack_now ();
+        }
+        
+        op = tok.kind;
+        get_token ();
+        
+        emit_load_floating_rhs_operand_now (result_size);
+        
+        if (floating_rhs_result_in_eax_bool) {
+            emit_rax_bool_to_floating_stack_now ();
+        }
+        
+        emit_floating_binary_now (op);
+    
+    }
+    
+    if (is_value_compare_operator (tok.kind)) {
+    
+        op = tok.kind;
+        get_token ();
+        
+        emit_load_floating_rhs_operand_now (result_size);
+        
+        while (token_is_floating_binary_now (tok.kind)) {
+        
+            enum token_kind rhs_op = tok.kind;
+            get_token ();
+            
+            emit_load_floating_rhs_operand_now (result_size);
+            emit_floating_binary_now (rhs_op);
+        
+        }
+        
+        emit_floating_compare_to_rax_now (op);
+    
+    }
+    
+    if (tok.kind == TOK_QMARK) {
+    
+        false_label = anon_label++;
+        end_label = anon_label++;
+        
+        if (!floating_rhs_result_in_eax_bool) {
+            emit_floating_truth_to_rax_now ();
+        }
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    test rax, rax\n");
+            } else {
+                fprintf (state->ofp, "    testq %%rax, %%rax\n");
+            }
+        
+        }
+        
+        if (state->ofp) {
+        
+            if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+                fprintf (state->ofp, "    jz L%d\n", false_label);
+            } else {
+                fprintf (state->ofp, "    jz .L%d\n", false_label);
+            }
+        
+        }
+        
+        floating_rhs_result_in_eax_bool = 0;
+        get_token ();
+        
+        emit_load_floating_rhs_expression_now (result_size);
+        expect (TOK_COLON, ":");
+        
+        emit_statement_jump (end_label);
+        emit_statement_label (false_label);
+        
+        emit_load_floating_rhs_expression_now (result_size);
+        emit_statement_label (end_label);
+        
+        floating_rhs_result_in_eax_bool = 0;
+    
+    }
+
+}
+
+static void emit_load_assignment_rhs_expression_to_reg (const char *reg);
+
+static int current_argument_is_bare_identifier_now (void) {
+
+    const char *p;
+    
+    if (tok.kind != TOK_IDENT || !tok.caret) {
+        return 0;
+    }
+    
+    p = tok.caret + tok.len;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == ',' || *p == ')';
+
+}
+
+static int emit_push_aggregate_argument_now (const char *name, struct local_symbol *sym) {
+
+    int size;
+    int offset;
+    int chunk;
+    
+    char memref[64];
+    
+    if (!name || !sym || sym->is_array || sym->pointer_depth > 0 || sym->is_floating) {
+        return 0;
+    }
+    
+    /**
+     * Struct/union locals keep their real byte size here.  Masking with
+     * 0x1f is only valid for scalar DATA_* encodings; it turns e.g. a
+     * 72-byte struct cpu_flags argument into an 8-byte argument.
+     */
+    size = sym->size;
+    
+    /*
+     * Do not treat plain 64-bit scalar locals as aggregate arguments.
+     * The old test used only size > 4, so a call such as:
+     *
+     *     bytearray_write_4_bytes (..., result, endianess)
+     *
+     * where result is uint_fast64_t/address_type pushed both halves of
+     * result.  The callee expects an unsigned long here, so the extra high
+     * word shifted the following arguments and pdld wrote broken relocation
+     * bytes.  Real structs/unions either carry an aggregate tag here, or are
+     * larger than the built-in DATA_LLONG scalar size.
+     */
+    if (size <= (DATA_PTR & 0x1f) || (size <= (DATA_LLONG & 0x1f) && !sym->tag_name)) {
+        return 0;
+    }
+    
+    if (!state->ofp) {
+        return 1;
+    }
+    
+    for (offset = size; offset > 0; ) {
+    
+        if (offset >= 8) {
+        
+            chunk = 8;
+            offset -= 8;
+        
+        } else if (offset >= 4) {
+        
+            chunk = 4;
+            offset -= 4;
+        
+        } else if (offset >= 2) {
+        
+            chunk = 2;
+            offset -= 2;
+        
+        } else {
+        
+            chunk = 1;
+            offset -= 1;
+        
+        }
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            if (sym->is_static && sym->static_label) {
+            
+                if (chunk == 8) {
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    push qword [%s + %d]\n" : "    push qword ptr [%s + %d]\n"), asm_global_symbol_name (sym->static_label), offset);
+                } else if (chunk == 4) {
+                
+                    fprintf (state->ofp, "    sub rsp, 8\n");
+                    
+                    if (state->syntax & ASM_SYNTAX_NASM) {
+                    
+                        fprintf (state->ofp, "    xor rax, rax\n");
+                        fprintf (state->ofp, "    mov eax, dword [%s + %d]\n", asm_global_symbol_name (sym->static_label), offset);
+                        fprintf (state->ofp, "    mov qword [rsp], rax\n");
+                    
+                    } else {
+                    
+                        fprintf (state->ofp, "    xor rax, rax\n");
+                        fprintf (state->ofp, "    mov eax, dword ptr [%s + %d]\n", asm_global_symbol_name (sym->static_label), offset);
+                        fprintf (state->ofp, "    mov qword ptr [rsp], rax\n");
+                    
+                    }
+                
+                } else if (chunk == 2) {
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movzx eax, word [%s + %d]\n" : "    movzx eax, word ptr [%s + %d]\n"), asm_global_symbol_name (sym->static_label), offset); fprintf (state->ofp, "    push rax\n");
+                } else {
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movzx eax, byte [%s + %d]\n" : "    movzx eax, byte ptr [%s + %d]\n"), asm_global_symbol_name (sym->static_label), offset); fprintf (state->ofp, "    push rax\n");
+                }
+            
+            } else {
+            
+                format_intel_rbp_offset (memref, sizeof (memref), sym->offset + offset);
+                
+                if (chunk == 8) {
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    push qword %s\n" : "    push qword ptr %s\n"), memref);
+                } else if (chunk == 4) {
+                
+                    fprintf (state->ofp, "    sub rsp, 8\n");
+                    
+                    if (state->syntax & ASM_SYNTAX_NASM) {
+                    
+                        fprintf (state->ofp, "    xor rax, rax\n");
+                        fprintf (state->ofp, "    mov eax, dword %s\n", memref);
+                        fprintf (state->ofp, "    mov qword [rsp], rax\n");
+                    
+                    } else {
+                    
+                        fprintf (state->ofp, "    xor rax, rax\n");
+                        fprintf (state->ofp, "    mov eax, dword ptr %s\n", memref);
+                        fprintf (state->ofp, "    mov qword ptr [rsp], rax\n");
+                    
+                    }
+                
+                } else if (chunk == 2) {
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movzx eax, word %s\n" : "    movzx eax, word ptr %s\n"), memref); fprintf (state->ofp, "    push rax\n");
+                } else {
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movzx eax, byte %s\n" : "    movzx eax, byte ptr %s\n"), memref); fprintf (state->ofp, "    push rax\n");
+                }
+            
+            }
+        
+        } else {
+        
+            if (sym->is_static && sym->static_label) {
+            
+                if (chunk == 8) {
+                    fprintf (state->ofp, "    pushq %s+%d(%%rip)\n", asm_global_symbol_name (sym->static_label), offset);
+                } else if (chunk == 4) {
+                
+                    fprintf (state->ofp, "    subq $8, %%rsp\n");
+                    
+                    fprintf (state->ofp, "    xorq %%rax, %%rax\n");
+                    fprintf (state->ofp, "    movl %s+%d(%%rip), %%eax\n", asm_global_symbol_name (sym->static_label), offset);
+                    fprintf (state->ofp, "    movq %%rax, (%%rsp)\n");
+                
+                } else if (chunk == 2) {
+                    fprintf (state->ofp, "    movzwl %s+%d(%%rip), %%eax\n", asm_global_symbol_name (sym->static_label), offset); fprintf (state->ofp, "    pushq %%rax\n");
+                } else {
+                    fprintf (state->ofp, "    movzbl %s+%d(%%rip), %%eax\n", asm_global_symbol_name (sym->static_label), offset); fprintf (state->ofp, "    pushq %%rax\n");
+                }
+            
+            } else {
+            
+                if (chunk == 8) {
+                    fprintf (state->ofp, "    pushq %ld(%%rbp)\n", sym->offset + offset);
+                } else if (chunk == 4) {
+                
+                    fprintf (state->ofp, "    subq $8, %%rsp\n");
+                    
+                    fprintf (state->ofp, "    xorq %%rax, %%rax\n");
+                    fprintf (state->ofp, "    movl %ld(%%rbp), %%eax\n", sym->offset + offset);
+                    fprintf (state->ofp, "    movq %%rax, (%%rsp)\n");
+                
+                } else if (chunk == 2) {
+                    fprintf (state->ofp, "    movzwl %ld(%%rbp), %%eax\n", sym->offset + offset); fprintf (state->ofp, "    pushq %%rax\n");
+                } else {
+                    fprintf (state->ofp, "    movzbl %ld(%%rbp), %%eax\n", sym->offset + offset); fprintf (state->ofp, "    pushq %%rax\n");
+                }
+            
+            }
+        
+        }
+    
+    }
+    
+    return 1;
+
+}
+
+static int emit_push_global_aggregate_argument_now (const char *name) {
+
+    int size;
+    int offset;
+    int chunk;
+
+    if (!name || get_global_symbol_kind (name) != GLOBAL_SYMBOL_OBJECT ||
+        get_global_symbol_array (name) || get_global_symbol_pointer_depth (name) > 0 ||
+        get_global_symbol_floating (name)) {
+        return 0;
+    }
+    
+    size = get_global_symbol_size (name);
+    
+    if (size <= (DATA_PTR & 0x1f)) {
+        return 0;
+    }
+    
+    if (!state->ofp) {
+        return 1;
+    }
+    
+    for (offset = size; offset > 0; ) {
+    
+        if (offset >= 8) {
+        
+            chunk = 8;
+            offset -= 8;
+        
+        } else if (offset >= 4) {
+        
+            chunk = 4;
+            offset -= 4;
+        
+        } else if (offset >= 2) {
+        
+            chunk = 2;
+            offset -= 2;
+        
+        } else {
+        
+            chunk = 1;
+            offset -= 1;
+        
+        }
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            if (chunk == 8) {
+            
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ?
+                    "    push qword [%s + %d]\n" :
+                    "    push qword ptr [%s + %d]\n"), asm_global_symbol_name (name), offset);
+            
+            } else if (chunk == 4) {
+            
+                fprintf (state->ofp, "    sub rsp, 8\n");
+                
+                if (state->syntax & ASM_SYNTAX_NASM) {
+                
+                    fprintf (state->ofp, "    xor rax, rax\n");
+                    fprintf (state->ofp, "    mov eax, dword [%s + %d]\n", asm_global_symbol_name (name), offset);
+                    fprintf (state->ofp, "    mov qword [rsp], rax\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    xor rax, rax\n");
+                    fprintf (state->ofp, "    mov eax, dword ptr [%s + %d]\n", asm_global_symbol_name (name), offset);
+                    fprintf (state->ofp, "    mov qword ptr [rsp], rax\n");
+                
+                }
+             
+            } else if (chunk == 2) {
+            
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ?
+                    "    movzx eax, word [%s + %d]\n" :
+                    "    movzx eax, word ptr [%s + %d]\n"), asm_global_symbol_name (name), offset);
+                fprintf (state->ofp, "    push rax\n");
+            
+            } else {
+            
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ?
+                    "    movzx eax, byte [%s + %d]\n" :
+                    "    movzx eax, byte ptr [%s + %d]\n"), asm_global_symbol_name (name), offset);
+                fprintf (state->ofp, "    push rax\n");
+            
+            }
+        
+        } else {
+        
+            if (chunk == 8) {
+                fprintf (state->ofp, "    pushq %s+%d(%%rip)\n", asm_global_symbol_name (name), offset);
+            } else if (chunk == 4) {
+            
+                fprintf (state->ofp, "    subq $8, %%rsp\n");
+                
+                fprintf (state->ofp, "    xorq %%rax, %%rax\n");
+                fprintf (state->ofp, "    movl %s+%d(%%rip), %%eax\n", asm_global_symbol_name (name), offset);
+                fprintf (state->ofp, "    movq %%rax, (%%rsp)\n");
+            
+            } else if (chunk == 2) {
+            
+                fprintf (state->ofp, "    movzwl %s+%d(%%rip), %%eax\n", asm_global_symbol_name (name), offset);
+                fprintf (state->ofp, "    pushq %%rax\n");
+            
+            } else {
+            
+                fprintf (state->ofp, "    movzbl %s+%d(%%rip), %%eax\n", asm_global_symbol_name (name), offset);
+                fprintf (state->ofp, "    pushq %%rax\n");
+            
+            }
+        
+        }
+    
+    }
+    
+    return 1;
+
+}
+
+static void emit_call_pointer_in_reg_now (const char *fn_reg, const char *result_reg) {
+
+    int argc = 0;
+    int total_arg_bytes = 0;
+    int arg_bytes;
+    int arg_is_floating;
+    int i;
+    int ch;
+    
+    int amd64_call_stack_bytes = 0;
+    int saved_pointer_offset = 0;
+    
+    FILE **arg_tmp_ofps = 0;
+    FILE **new_arg_tmp_ofps = 0;
+    
+    int *arg_tmp_floating = 0;
+    int *new_arg_tmp_floating = 0;
+    int *arg_tmp_float_sizes = 0;
+    int *new_arg_tmp_float_sizes = 0;
+    
+    int arg_saved_stack_mod16 = 0;
+    
+    FILE *arg_saved_ofp = 0;
+    FILE *arg_tmp_ofp = 0;
+    
+    int saved_arg_assignment32_stop_before_condition_operator;
+    int saved_arg_assignment64_stop_before_condition_operator;
+    
+    if (tok.kind != TOK_LPAREN) {
+        return;
+    }
+    
+    if (state->ofp) {
+        amd64_emit_push_reg_now (fn_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) {
+    
+        for (;;) {
+        
+            arg_saved_ofp = 0;
+            arg_tmp_ofp = 0;
+            arg_is_floating = 0;
+            arg_bytes = DATA_PTR;
+            
+            if (state->ofp) {
+            
+                arg_tmp_ofp = scc_tmpfile ();
+                
+                if (arg_tmp_ofp) {
+                
+                    arg_saved_stack_mod16 = amd64_temp_stack_mod16;
+                    arg_saved_ofp = state->ofp;
+                    
+                    amd64_temp_stack_mod16 = 0;
+                    state->ofp = arg_tmp_ofp;
+                
+                }
+            
+            }
+            
+            postfix_member_seen = 0;
+            postfix_member_size = 0;
+            postfix_member_pointer_depth = 0;
+            postfix_member_pointed_size = 0;
+            
+            if (tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && find_local_symbol (tok.ident) && emit_push_aggregate_argument_now (tok.ident, find_local_symbol (tok.ident))) {
+            
+                struct local_symbol *arg_sym = find_local_symbol (tok.ident);
+                
+                arg_bytes = arg_sym ? arg_sym->size : DATA_PTR;
+                arg_is_floating = 0;
+                
+                get_token ();
+            
+            } else if (tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && !find_local_symbol (tok.ident) && emit_push_global_aggregate_argument_now (tok.ident)) {
+            
+                arg_bytes = get_global_symbol_size (tok.ident);
+                arg_is_floating = 0;
+                
+                get_token ();
+            
+            } else if (tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now () &&
+                       get_global_symbol_kind (tok.ident) == GLOBAL_SYMBOL_FUNCTION &&
+                       get_global_symbol_size (tok.ident) > (DATA_LLONG & 0x1f)) {
+            
+                char *arg_call_name = xstrdup (tok.ident);
+                
+                const char *arg_call_start = tok.start;
+                const char *arg_call_caret = tok.caret;
+                
+                unsigned long arg_call_line = get_line_number ();
+                
+                arg_bytes = get_global_symbol_size (arg_call_name);
+                arg_is_floating = 0;
+                
+                emit_sub_rsp_now (arg_bytes);
+                
+                pending_struct_return_lhs = 0;
+                pending_struct_return_global_name = 0;
+                pending_struct_return_stack_address = 0;
+                pending_struct_return_stack_offset = 0;
+                pending_struct_return_stack_top = 1;
+                
+                get_token ();
+                emit_call_identifier_to_reg_now (arg_call_name, "rax", arg_call_start, arg_call_caret, arg_call_line);
+                
+                pending_struct_return_stack_top = 0;
+                free (arg_call_name);
+            
+            } else {
+            
+                arg_is_floating = rhs_current_operand_is_floating_now ();
+                
+                /*
+                 * A call through a function pointer currently has no recorded
+                 * parameter prototype in this backend path.  Treat it like an
+                 * unprototyped call for floating arguments: C default argument
+                 * promotions make float become double, and the Microsoft x64
+                 * ABI then passes that promoted double in XMMn plus the matching
+                 * GP register.  Fixed float parameters are handled by the
+                 * direct-call prototype path, not here.
+                 */
+                arg_bytes = arg_is_floating ? (DATA_DOUBLE & 0x1f) : DATA_PTR;
+                
+                /*
+                 * Function-pointer calls do not have a direct prototype in
+                 * the global-symbol table, but the AMD64 ABI still passes
+                 * integer/pointer arguments in 64-bit register/stack slots.
+                 * The generic scalar loader may leave a long long expression
+                 * in the old i386 EDX:EAX form or otherwise only materialise
+                 * the low half.  Match the normal-call path for source
+                 * arguments that are visibly 64-bit integers so replaying the
+                 * temporary argument block can move the complete value from
+                 * RAX into RCX/RDX/R8/R9 or the overflow stack slot.
+                 */
+                if (!arg_is_floating && current_argument_starts_64bit_integer_now ()) {
+                
+                    arg_bytes = DATA_LLONG & 0x1f;
+                    amd64_emit_load_assignment_rhs_expression_to_rax64 (rhs_current_operand_is_unsigned_now ());
+                
+                } else if (arg_is_floating) {
+                    emit_load_floating_rhs_expression_now (arg_bytes);
+                } else {
+                    emit_load_assignment_rhs_expression_to_reg ("rax");
+                }
+                
+                if (state->ofp) {
+                
+                    if (!arg_is_floating && postfix_member_seen && postfix_member_pointer_depth == 0 && postfix_member_size > (DATA_PTR & 0x1f)) {
+                    
+                        arg_bytes = postfix_member_size;
+                        emit_push_aggregate_from_addr_reg_now ("rax", arg_bytes);
+                    
+                    } else if (!arg_is_floating && postfix_member_size > (DATA_PTR & 0x1f)) {
+                    
+                        arg_bytes = postfix_member_size;
+                        emit_push_aggregate_from_addr_reg_now ("rax", arg_bytes);
+                    
+                    } else if (arg_is_floating) {
+                        /* Keep ST(0) live; amd64_emit_move_st0_to_arg() places it. */
+                    } else {
+                        /* Keep RAX live; the AMD64 call replay moves it to the proper slot. */
+                    }
+                
+                }
+            
+            }
+            
+            total_arg_bytes += arg_bytes;
+            
+            if (arg_saved_ofp) {
+            
+                fflush (arg_tmp_ofp);
+                
+                amd64_temp_stack_mod16 = arg_saved_stack_mod16;
+                state->ofp = arg_saved_ofp;
+                
+                new_arg_tmp_ofps = (FILE **) xrealloc (arg_tmp_ofps, sizeof (*arg_tmp_ofps) * (argc + 1));
+                
+                if (new_arg_tmp_ofps) {
+                
+                    arg_tmp_ofps = new_arg_tmp_ofps;
+                    arg_tmp_ofps[argc] = arg_tmp_ofp;
+                    arg_tmp_ofp = 0;
+                
+                }
+                
+                new_arg_tmp_floating = (int *) xrealloc (arg_tmp_floating, sizeof (*arg_tmp_floating) * (argc + 1));
+                
+                if (new_arg_tmp_floating) {
+                
+                    arg_tmp_floating = new_arg_tmp_floating;
+                    arg_tmp_floating[argc] = arg_is_floating;
+                
+                }
+                
+                new_arg_tmp_float_sizes = (int *) xrealloc (arg_tmp_float_sizes, sizeof (*arg_tmp_float_sizes) * (argc + 1));
+                
+                if (new_arg_tmp_float_sizes) {
+                
+                    arg_tmp_float_sizes = new_arg_tmp_float_sizes;
+                    arg_tmp_float_sizes[argc] = arg_is_floating ? arg_bytes : 0;
+                
+                }
+            
+            }
+            
+            if (arg_tmp_ofp) {
+            
+                scc_close (arg_tmp_ofp);
+                arg_tmp_ofp = 0;
+            
+            }
+            
+            argc++;
+            
+            if (!_accept (TOK_COMMA)) {
+                break;
+            }
+        
+        }
+    
+    }
+    
+    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 (state->ofp) {
+    
+        /*
+         * The function pointer itself was saved before evaluating arguments,
+         * because argument evaluation is allowed to clobber its register.
+         * For the Microsoft x64 ABI, reserve the 32-byte home area plus any
+         * overflow argument slots, then replay each argument left-to-right into
+         * RCX/RDX/R8/R9 or the overflow stack area.
+         */
+        amd64_call_stack_bytes = 32;
+        
+        if (argc > 4) {
+            amd64_call_stack_bytes += (argc - 4) * 8;
+        }
+        
+        /*
+         * The saved function pointer is already on the stack above this
+         * reservation.  Account for that extra 8-byte push when choosing the
+         * call-frame size; otherwise indirect calls enter with RSP 8 bytes off
+         * the Microsoft x64 16-byte call-site alignment.
+         */
+        amd64_call_stack_bytes = amd64_align_call_stack_bytes (amd64_call_stack_bytes);
+        amd64_emit_sub_rsp_bytes (amd64_call_stack_bytes);
+        
+        for (i = 0; i < argc; i++) {
+        
+            if (arg_tmp_ofps && arg_tmp_ofps[i]) {
+            
+                fseek (arg_tmp_ofps[i], 0, SEEK_SET);
+                
+                while ((ch = fgetc (arg_tmp_ofps[i])) != EOF) {
+                    fputc (ch, state->ofp);
+                }
+                
+                if (arg_tmp_floating && arg_tmp_floating[i]) {
+                    amd64_emit_move_st0_to_arg (i, (arg_tmp_float_sizes && arg_tmp_float_sizes[i]) ? arg_tmp_float_sizes[i] : (DATA_DOUBLE & 0x1f), 1);
+                } else if (i < 4) {
+                    amd64_emit_store_rax_to_home_arg (i);
+                } else {
+                    amd64_emit_store_rax_to_stack_arg (i - 4);
+                }
+                
+                scc_close (arg_tmp_ofps[i]);
+                arg_tmp_ofps[i] = 0;
+            
+            }
+        
+        }
+        
+        for (i = 0; i < argc && i < 4; i++) {
+        
+            if (!(arg_tmp_floating && arg_tmp_floating[i])) {
+                amd64_emit_load_home_arg_to_reg (i);
+            }
+        
+        }
+        
+        if (arg_tmp_ofps) {
+        
+            free (arg_tmp_ofps);
+            arg_tmp_ofps = 0;
+        
+        }
+        
+        if (arg_tmp_floating) {
+        
+            free (arg_tmp_floating);
+            arg_tmp_floating = 0;
+        
+        }
+        
+        if (arg_tmp_float_sizes) {
+        
+            free (arg_tmp_float_sizes);
+            arg_tmp_float_sizes = 0;
+        
+        }
+        
+        saved_pointer_offset = amd64_call_stack_bytes;
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            if (state->syntax & ASM_SYNTAX_NASM) {
+                fprintf (state->ofp, "    mov r11, qword [rsp + %d]\n", saved_pointer_offset);
+            } else {
+                fprintf (state->ofp, "    mov r11, qword ptr [rsp + %d]\n", saved_pointer_offset);
+            }
+            
+            fprintf (state->ofp, "    call r11\n");
+            amd64_emit_add_rsp_bytes (amd64_call_stack_bytes + (DATA_PTR & 0x1f));
+            
+            if (strcmp (result_reg, "rax") != 0) {
+                fprintf (state->ofp, "    mov %s, rax\n", result_reg);
+            }
+        
+        } else {
+        
+            fprintf (state->ofp, "    movq %d(%%rsp), %%r11\n", saved_pointer_offset);
+            fprintf (state->ofp, "    call *%%r11\n");
+            
+            amd64_emit_add_rsp_bytes (amd64_call_stack_bytes + (DATA_PTR & 0x1f));
+            
+            if (strcmp (result_reg, "rax") != 0) {
+                fprintf (state->ofp, "    movq %%rax, %%%s\n", result_reg);
+            }
+        
+        }
+    
+    }
+    
+    if (arg_tmp_ofps) {
+    
+        for (i = 0; i < argc; i++) {
+        
+            if (arg_tmp_ofps[i]) {
+                scc_close (arg_tmp_ofps[i]);
+            }
+        
+        }
+        
+        free (arg_tmp_ofps);
+    
+    }
+    
+    if (arg_tmp_floating) {
+        free (arg_tmp_floating);
+    }
+    
+    if (arg_tmp_float_sizes) {
+        free (arg_tmp_float_sizes);
+    }
+
+}
+
+static void emit_sub_rsp_now (int bytes) {
+    amd64_emit_sub_rsp_bytes (bytes);
+}
+
+static void emit_load_pending_struct_return_address_to_rax_now (int stack_arg_bytes) {
+
+    if (!state->ofp || (!pending_struct_return_lhs && !pending_struct_return_global_name && !pending_struct_return_stack_address && !pending_struct_return_stack_top)) {
+        return;
+    }
+    
+    if (pending_struct_return_stack_top) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            if (state->syntax & ASM_SYNTAX_NASM) {
+                fprintf (state->ofp, "    lea rax, [rsp + %d]\n", stack_arg_bytes);
+            } else {
+                fprintf (state->ofp, "    lea rax, [rsp + %d]\n", stack_arg_bytes);
+            }
+        
+        } else {
+            fprintf (state->ofp, "    leaq %d(%%rsp), %%rax\n", stack_arg_bytes);
+        }
+    
+    } else if (pending_struct_return_stack_address) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            if (state->syntax & ASM_SYNTAX_NASM) {
+                fprintf (state->ofp, "    mov rax, qword [rsp + %d]\n", stack_arg_bytes);
+            } else {
+                fprintf (state->ofp, "    mov rax, qword ptr [rsp + %d]\n", stack_arg_bytes);
+            }
+            
+            if (pending_struct_return_stack_offset) {
+                fprintf (state->ofp, "    add rax, %d\n", pending_struct_return_stack_offset);
+            }
+        
+        } else {
+        
+            fprintf (state->ofp, "    movq %d(%%rsp), %%rax\n", stack_arg_bytes);
+            
+            if (pending_struct_return_stack_offset) {
+                fprintf (state->ofp, "    addq $%d, %%rax\n", pending_struct_return_stack_offset);
+            }
+        
+        }
+    
+    } else if (pending_struct_return_lhs) {
+    
+        if (pending_struct_return_lhs->is_static && pending_struct_return_lhs->static_label) {
+            emit_load_address_to_reg_now ("rax", pending_struct_return_lhs->static_label);
+        } else {
+            emit_load_local_address_to_reg_now ("rax", pending_struct_return_lhs->offset);
+        }
+    
+    } else {
+        emit_load_address_to_reg_now ("rax", pending_struct_return_global_name);
+    }
+
+}
+
+
+
+static int current_argument_is_bare_64bit_identifier_now (void) {
+
+    struct local_symbol *sym;
+    
+    if (tok.kind != TOK_IDENT || !tok.ident || !current_argument_is_bare_identifier_now ()) {
+        return 0;
+    }
+    
+    sym = find_local_symbol (tok.ident);
+    
+    if (sym) {
+        return sym->size == (DATA_LLONG & 0x1f) && !sym->is_floating;
+    }
+    
+    if (find_global_symbol (tok.ident) >= 0) {
+        return get_global_symbol_size (tok.ident) == (DATA_LLONG & 0x1f) && !get_global_symbol_floating (tok.ident);
+    }
+    
+    return 0;
+
+}
+
+static int argument_text_skip_quoted_literal_now (const char **pp);
+
+static int argument_text_skip_balanced_parens_now (const char **pp) {
+
+    const char *p;
+    int depth = 0;
+    
+    if (!pp || !*pp || **pp != '(') {
+        return 0;
+    }
+    
+    p = *pp;
+    
+    while (*p) {
+    
+        if (*p == '\'' || *p == '"') {
+        
+            argument_text_skip_quoted_literal_now (&p);
+            continue;
+        
+        }
+        
+        if (*p == '(') {
+            depth++;
+        } else if (*p == ')') {
+        
+            depth--;
+            
+            if (depth == 0) {
+            
+                *pp = p + 1;
+                return 1;
+            
+            }
+        
+        }
+        
+        p++;
+    
+    }
+    
+    return 0;
+
+}
+
+static int argument_text_skip_quoted_literal_now (const char **pp) {
+
+    const char *p;
+    char quote;
+    
+    if (!pp || !*pp || (**pp != '\'' && **pp != '"')) {
+        return 0;
+    }
+    
+    p = *pp;
+    quote = *p++;
+    
+    while (*p) {
+    
+        if (*p == '\\') {
+        
+            p++;
+            
+            if (*p) {
+                p++;
+            }
+            
+            continue;
+        
+        }
+        
+        if (*p == quote) {
+        
+            *pp = p + 1;
+            return 1;
+        
+        }
+        
+        p++;
+    
+    }
+    
+    *pp = p;
+    return 1;
+
+}
+
+static int argument_text_mentions_64bit_symbol_now (const char *p) {
+
+    char name[256];
+    int depth = 0;
+    int i;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    while (*p) {
+    
+        if (depth == 0 && *p == ',') {
+            return 0;
+        }
+        
+        if (depth == 0 && (*p == ')' || *p == ';' || *p == '{' || *p == '}')) {
+            return 0;
+        }
+        
+        if (*p == '\'' || *p == '"') {
+        
+            argument_text_skip_quoted_literal_now (&p);
+            continue;
+        
+        }
+        
+        if (*p == '(' || *p == '[') {
+        
+            depth++;
+            p++;
+            
+            continue;
+        
+        }
+        
+        if (*p == ')' || *p == ']') {
+        
+            if (depth <= 0) {
+                return 0;
+            }
+            
+            depth--;
+            p++;
+            
+            continue;
+        
+        }
+        
+        if ((unsigned char) *p == '_' || ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z'))) {
+        
+            i = 0;
+            
+            while ((unsigned char) *p == '_' || ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9'))) {
+            
+                if (i + 1 < (int) sizeof (name)) {
+                    name[i++] = *p;
+                }
+                
+                p++;
+            
+            }
+            
+            name[i] = 0;
+            
+            while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+                p++;
+            }
+            
+            /*
+             * Do not let long-long arguments of a nested call upgrade the
+             * enclosing argument.  For example, in:
+             *
+             *     fp (g (ll));
+             *
+             * the argument passed to fp has the type returned by g(), not the
+             * type of ll.  The old text scan walked through the inner call's
+             * argument list and treated the outer argument as a visible
+             * long-long expression.  Only the nested call's own return type is
+             * relevant here; its parameters are not.
+             */
+            if (*p == '(') {
+            
+                if (find_global_symbol (name) >= 0 &&
+                    get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION &&
+                    get_global_symbol_size (name) == (DATA_LLONG & 0x1f) &&
+                    !get_global_symbol_floating (name)) {
+                    return 1;
+                }
+                
+                if (!argument_text_skip_balanced_parens_now (&p)) {
+                    return 0;
+                }
+                
+                continue;
+            
+            }
+            
+            if (*p == '.' || (p[0] == '-' && p[1] == '>')) {
+                continue;
+            }
+            
+            {
+            
+                struct local_symbol *sym = find_local_symbol (name);
+                
+                if (sym && sym->size == (DATA_LLONG & 0x1f) && !sym->is_floating) {
+                    return 1;
+                }
+            
+            }
+            
+            if (find_global_symbol (name) >= 0 && get_global_symbol_size (name) == (DATA_LLONG & 0x1f) && !get_global_symbol_floating (name)) {
+                return 1;
+            }
+            
+            continue;
+        
+        }
+        
+        p++;
+    
+    }
+    
+    return 0;
+
+}
+
+static int argument_text_current_argument_end_now (const char *p, const char **endp) {
+
+    const char *q;
+    int depth = 0;
+    
+    if (!p || !endp) {
+        return 0;
+    }
+    
+    q = p;
+    
+    while (*q) {
+    
+        if (depth == 0 && (*q == ',' || *q == ';' || *q == '{' || *q == '}')) {
+        
+            *endp = q;
+            return 1;
+        
+        }
+        
+        if (depth == 0 && *q == ')') {
+        
+            *endp = q;
+            return 1;
+        
+        }
+        
+        if (*q == '\'' || *q == '"') {
+        
+            const char *literal = q;
+            
+            argument_text_skip_quoted_literal_now (&literal);
+            q = literal;
+            
+            continue;
+        
+        }
+        
+        if (*q == '(' || *q == '[') {
+            depth++;
+        } else if (*q == ')' || *q == ']') {
+        
+            if (depth <= 0) {
+            
+                *endp = q;
+                return 1;
+            
+            }
+            
+            depth--;
+        
+        }
+        
+        q++;
+    
+    }
+    
+    *endp = q;
+    return 1;
+
+}
+
+static int argument_text_strip_outer_parens_now (const char **startp, const char **endp) {
+
+    const char *p;
+    const char *q;
+    const char *end;
+    int depth;
+    
+    if (!startp || !*startp || !endp || !*endp) {
+        return 0;
+    }
+    
+    p = *startp;
+    end = *endp;
+    
+    while (p < end && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')) {
+        p++;
+    }
+    
+    while (end > p && (end[-1] == ' ' || end[-1] == '\t' || end[-1] == '\r' || end[-1] == '\n')) {
+        end--;
+    }
+    
+    if (p >= end || *p != '(') {
+        return 0;
+    }
+    
+    depth = 0;
+    q = p;
+    
+    while (q < end) {
+    
+        if (*q == '\'' || *q == '"') {
+        
+            argument_text_skip_quoted_literal_now (&q);
+            continue;
+        
+        }
+        
+        if (*q == '(') {
+            depth++;
+        } else if (*q == ')') {
+        
+            depth--;
+            
+            if (depth == 0) {
+            
+                q++;
+                
+                while (q < end && (*q == ' ' || *q == '\t' || *q == '\r' || *q == '\n')) {
+                    q++;
+                }
+                
+                if (q == end) {
+                
+                    *startp = p + 1;
+                    *endp = end - 1;
+                    
+                    return 1;
+                
+                }
+                
+                return 0;
+            
+            }
+        
+        }
+        
+        q++;
+    
+    }
+    
+    return 0;
+
+}
+
+static int argument_text_has_int_result_operator_now (const char *p) {
+
+    const char *start;
+    const char *end;
+    int depth = 0;
+    
+    if (!p || !argument_text_current_argument_end_now (p, &end)) {
+        return 0;
+    }
+    
+    while (argument_text_strip_outer_parens_now (&p, &end)) {
+        ;
+    }
+    
+    start = p;
+    
+    while (p < end) {
+    
+        if (*p == '\'' || *p == '"') {
+        
+            argument_text_skip_quoted_literal_now (&p);
+            continue;
+        
+        }
+        
+        if (*p == '(' || *p == '[') {
+        
+            depth++;
+            p++;
+            
+            continue;
+        
+        }
+        
+        if (*p == ')' || *p == ']') {
+        
+            if (depth > 0) {
+                depth--;
+            }
+            
+            p++;
+            continue;
+        
+        }
+        
+        if (depth == 0) {
+        
+            if ((p + 1) < end && ((p[0] == '=' && p[1] == '=') ||
+                                  (p[0] == '!' && p[1] == '=') ||
+                                  (p[0] == '&' && p[1] == '&') ||
+                                  (p[0] == '|' && p[1] == '|') ||
+                                  (p[0] == '<' && p[1] == '=') ||
+                                  (p[0] == '>' && p[1] == '='))) {
+                return 1;
+            }
+            
+            if (*p == '<') {
+            
+                if (!((p + 1) < end && p[1] == '<') && !(p > start && p[-1] == '<')) {
+                    return 1;
+                }
+            
+            }
+            
+            if (*p == '>') {
+            
+                if (!((p + 1) < end && p[1] == '>') && !(p > start && p[-1] == '>') && !(p > start && p[-1] == '-')) {
+                    return 1;
+                }
+            
+            }
+            
+            if (*p == '!') {
+            
+                if (!((p + 1) < end && p[1] == '=')) {
+                    return 1;
+                }
+            
+            }
+        
+        }
+        
+        p++;
+    
+    }
+    
+    return 0;
+
+}
+
+static int current_argument_has_int_result_operator_now (void) {
+
+    if (argument_text_has_int_result_operator_now (tok.start)) {
+        return 1;
+    }
+    
+    if (argument_text_has_int_result_operator_now (tok.caret)) {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static char *argument_text_copy_range_now (const char *start, const char *end) {
+
+    char *out;
+    size_t len;
+    
+    if (!start || !end || end < start) {
+        return 0;
+    }
+    
+    while (start < end && (*start == ' ' || *start == '\t' || *start == '\r' || *start == '\n')) {
+        start++;
+    }
+    
+    while (end > start && (end[-1] == ' ' || end[-1] == '\t' || end[-1] == '\r' || end[-1] == '\n')) {
+        end--;
+    }
+    
+    len = (size_t) (end - start);
+    out = xmalloc (len + 1);
+    
+    if (len > 0) {
+        memcpy (out, start, len);
+    }
+    
+    out[len] = 0;
+    return out;
+
+}
+
+static int argument_text_range_mentions_64bit_symbol_now (const char *start, const char *end) {
+
+    char *copy;
+    int result;
+    
+    copy = argument_text_copy_range_now (start, end);
+    
+    if (!copy) {
+        return 0;
+    }
+    
+    result = argument_text_mentions_64bit_symbol_now (copy);
+    free (copy);
+    
+    return result;
+
+}
+
+static int argument_text_range_starts_64bit_cast_now (const char *start, const char *end) {
+
+    char *copy;
+    int result;
+    
+    copy = argument_text_copy_range_now (start, end);
+    
+    if (!copy) {
+        return 0;
+    }
+    
+    result = argument_text_starts_64bit_cast_now (copy);
+    free (copy);
+    
+    return result;
+
+}
+
+static int argument_text_range_has_int_result_operator_now (const char *start, const char *end) {
+
+    char *copy;
+    int result;
+    
+    copy = argument_text_copy_range_now (start, end);
+    
+    if (!copy) {
+        return 0;
+    }
+    
+    result = argument_text_has_int_result_operator_now (copy);
+    free (copy);
+    
+    return result;
+
+}
+
+static int argument_text_conditional_result_is_64bit_now (const char *p, int *seen_conditional) {
+
+    const char *start;
+    const char *end;
+    const char *qmark = 0;
+    const char *colon = 0;
+    int depth = 0;
+    
+    if (seen_conditional) {
+        *seen_conditional = 0;
+    }
+    
+    if (!p || !argument_text_current_argument_end_now (p, &end)) {
+        return 0;
+    }
+    
+    while (argument_text_strip_outer_parens_now (&p, &end)) {
+        ;
+    }
+    
+    start = p;
+    
+    while (p < end) {
+    
+        if (*p == '\'' || *p == '"') {
+        
+            argument_text_skip_quoted_literal_now (&p);
+            continue;
+        
+        }
+        
+        if (*p == '(' || *p == '[') {
+        
+            depth++;
+            p++;
+            
+            continue;
+        
+        }
+        
+        if (*p == ')' || *p == ']') {
+        
+            if (depth > 0) {
+                depth--;
+            }
+            
+            p++;
+            continue;
+        
+        }
+        
+        if (depth == 0 && *p == '?') {
+        
+            qmark = p;
+            break;
+        
+        }
+        
+        p++;
+    
+    }
+    
+    if (!qmark) {
+        return 0;
+    }
+    
+    if (seen_conditional) {
+        *seen_conditional = 1;
+    }
+    
+    p = qmark + 1;
+    depth = 0;
+    
+    while (p < end) {
+    
+        if (*p == '\'' || *p == '"') {
+        
+            argument_text_skip_quoted_literal_now (&p);
+            continue;
+        
+        }
+        
+        if (*p == '(' || *p == '[') {
+        
+            depth++;
+            p++;
+            
+            continue;
+        
+        }
+        
+        if (*p == ')' || *p == ']') {
+        
+            if (depth > 0) {
+                depth--;
+            }
+            
+            p++;
+            continue;
+        
+        }
+        
+        if (depth == 0 && *p == ':') {
+        
+            colon = p;
+            break;
+        
+        }
+        
+        p++;
+    
+    }
+    
+    if (!colon) {
+        return 0;
+    }
+    
+    /*
+     * The condition expression controls only the branch selection.  It does
+     * not decide the value type of the conditional operator.  Do not let a
+     * long-long used only in the condition make an unprototyped/function-
+     * pointer call replay the whole argument as 64-bit:
+     *
+     *     fp (ll ? 1 : 2);
+     *
+     * Only the second and third operands decide whether the conditional
+     * result itself needs 64-bit integer handling.
+     */
+    if (argument_text_range_starts_64bit_cast_now (qmark + 1, colon) ||
+        argument_text_range_starts_64bit_cast_now (colon + 1, end)) {
+        return 1;
+    }
+    
+    if ((!argument_text_range_has_int_result_operator_now (qmark + 1, colon) &&
+         argument_text_range_mentions_64bit_symbol_now (qmark + 1, colon)) ||
+        (!argument_text_range_has_int_result_operator_now (colon + 1, end) &&
+         argument_text_range_mentions_64bit_symbol_now (colon + 1, end))) {
+        return 1;
+    }
+    
+    (void) start;
+    return 0;
+
+}
+
+static int current_argument_conditional_result_is_64bit_now (int *seen_conditional) {
+
+    if (argument_text_conditional_result_is_64bit_now (tok.start, seen_conditional)) {
+        return 1;
+    }
+    
+    if (seen_conditional && *seen_conditional) {
+        return 0;
+    }
+    
+    if (argument_text_conditional_result_is_64bit_now (tok.caret, seen_conditional)) {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static int current_argument_mentions_64bit_symbol_now (void) {
+
+    if (argument_text_mentions_64bit_symbol_now (tok.start)) {
+        return 1;
+    }
+    
+    if (argument_text_mentions_64bit_symbol_now (tok.caret)) {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static int argument_text_starts_64bit_cast_now (const char *p) {
+
+    int saw_long = 0;
+    char word[32];
+    int n;
+    const char *inner;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '(') {
+        return 0;
+    }
+    
+    /*
+     * The current token for an explicitly-cast argument can be the grouping
+     * parenthesis rather than the cast parenthesis itself, for example:
+     *
+     *     fp (((long long) i));
+     *
+     * The previous check only accepted text whose first '(' directly opened
+     * the cast type, so extra harmless grouping caused the indirect-call
+     * argument classifier to miss the 64-bit cast and replay only the low
+     * scalar value.  Peel grouping parentheses while the next non-space
+     * character is another '(', but leave the normal cast parser below to
+     * validate that the inner construct is actually "long long".
+     */
+    inner = p + 1;
+    
+    while (*inner == ' ' || *inner == '\t' || *inner == '\r' || *inner == '\n') {
+        inner++;
+    }
+    
+    if (*inner == '(' && argument_text_starts_64bit_cast_now (inner)) {
+        return 1;
+    }
+    
+    p++;
+    
+    for (;;) {
+    
+        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+            p++;
+        }
+        
+        if (*p == ')') {
+            return saw_long >= 2;
+        }
+        
+        if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+            return 0;
+        }
+        
+        n = 0;
+        
+        while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') ||
+               (*p >= '0' && *p <= '9') || *p == '_') {
+        
+            if (n + 1 < (int) sizeof (word)) {
+                word[n++] = *p;
+            }
+            
+            p++;
+        
+        }
+        
+        word[n] = 0;
+        
+        if (strcmp (word, "unsigned") == 0) {
+            /* accepted as part of a cast prefix */
+        } else if (strcmp (word, "signed") == 0) {
+            /* accepted as part of a cast prefix */
+        } else if (strcmp (word, "const") == 0 || strcmp (word, "volatile") == 0) {
+            /* qualifiers before the long long are harmless here */
+        } else if (strcmp (word, "long") == 0) {
+            saw_long++;
+        } else {
+            return 0;
+        }
+    
+    }
+
+}
+
+static int current_argument_starts_64bit_cast_now (void) {
+
+    if (argument_text_starts_64bit_cast_now (tok.start)) {
+        return 1;
+    }
+    
+    if (argument_text_starts_64bit_cast_now (tok.caret)) {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static int argument_text_starts_narrow_integer_cast_now (const char *p) {
+
+    int saw_long = 0;
+    int saw_narrow = 0;
+    char word[32];
+    int n;
+    const char *inner;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '(') {
+        return 0;
+    }
+    
+    inner = p + 1;
+    
+    while (*inner == ' ' || *inner == '\t' || *inner == '\r' || *inner == '\n') {
+        inner++;
+    }
+    
+    if (*inner == '(' && argument_text_starts_narrow_integer_cast_now (inner)) {
+        return 1;
+    }
+    
+    p++;
+    
+    for (;;) {
+    
+        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+            p++;
+        }
+        
+        if (*p == ')') {
+            return saw_narrow || saw_long == 1;
+        }
+        
+        if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+            return 0;
+        }
+        
+        n = 0;
+        
+        while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') ||
+               (*p >= '0' && *p <= '9') || *p == '_') {
+        
+            if (n + 1 < (int) sizeof (word)) {
+                word[n++] = *p;
+            }
+            
+            p++;
+        
+        }
+        
+        word[n] = 0;
+        
+        if (strcmp (word, "unsigned") == 0) {
+            /* accepted as part of a cast prefix */
+        } else if (strcmp (word, "signed") == 0) {
+            /* accepted as part of a cast prefix */
+        } else if (strcmp (word, "const") == 0 || strcmp (word, "volatile") == 0) {
+            /* qualifiers before the integer type are harmless here */
+        } else if (strcmp (word, "char") == 0 || strcmp (word, "short") == 0 || strcmp (word, "int") == 0) {
+            saw_narrow = 1;
+        } else if (strcmp (word, "long") == 0) {
+        
+            saw_long++;
+            
+            if (saw_long >= 2) {
+                return 0;
+            }
+        
+        } else {
+            return 0;
+        }
+    
+    }
+
+}
+
+static int current_argument_starts_narrow_integer_cast_now (void) {
+
+    if (argument_text_starts_narrow_integer_cast_now (tok.start)) {
+        return 1;
+    }
+    
+    if (argument_text_starts_narrow_integer_cast_now (tok.caret)) {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static int current_argument_starts_64bit_integer_now (void) {
+
+    if (tok.kind == TOK_CLLONG || tok.kind == TOK_CULLONG) {
+        return 1;
+    }
+    
+    if (current_argument_is_bare_64bit_identifier_now ()) {
+        return 1;
+    }
+    
+    if (current_argument_starts_64bit_cast_now ()) {
+        return 1;
+    }
+    
+    /*
+     * A visible cast to a narrower integer type overrides any long-long
+     * operand inside the cast expression.  For example:
+     *
+     *     fp ((int) ll);
+     *     fp (((unsigned long) ll));
+     *
+     * are passed as normal scalar integer arguments, not as 64-bit long-long
+     * arguments, even though the source text mentions a long-long object.
+     */
+    if (current_argument_starts_narrow_integer_cast_now ()) {
+        return 0;
+    }
+    
+    {
+    
+        int seen_conditional = 0;
+        
+        if (current_argument_conditional_result_is_64bit_now (&seen_conditional)) {
+            return 1;
+        }
+        
+        if (seen_conditional) {
+            return 0;
+        }
+    
+    }
+    
+    /*
+     * A long-long operand inside a comparison or logical expression does not
+     * make the argument itself a long long.  Expressions such as
+     *
+     *     fp (ll == 0);
+     *     fp ((ll < 0));
+     *     fp (!ll);
+     *
+     * produce int results, so do not let the later symbol scan upgrade them
+     * to 64-bit arguments for unprototyped/function-pointer calls.
+     *
+     * Check this after the conditional-operator special case.  A conditional
+     * expression such as
+     *
+     *     fp (c ? ll : 0);
+     *
+     * is still a 64-bit argument even though one branch may contain an
+     * int-producing subexpression in more complicated cases.
+     */
+    if (current_argument_has_int_result_operator_now ()) {
+        return 0;
+    }
+    
+    /*
+     * Function-pointer calls do not have a prototype table entry to tell the
+     * argument parser that an expression such as "a + b" must be evaluated as
+     * a 64-bit integer when either side is long long.  The previous check only
+     * caught bare identifiers and long-long constants, so indirect calls could
+     * still replay only the low 32 bits for non-trivial long-long arguments.
+     * Limit the source scan to the current comma-separated argument so a later
+     * long-long argument does not accidentally upgrade an earlier int argument.
+     */
+    return current_argument_mentions_64bit_symbol_now ();
+
+}
+
+static const char *amd64_integer_arg_reg (int index) {
+
+    static const char *regs[] = { "rcx", "rdx", "r8", "r9" };
+    
+    if (index < 0 || index >= 4) {
+        return 0;
+    }
+    
+    return regs[index];
+
+}
+
+static void amd64_emit_push_reg_now (const char *reg) {
+    emit_push_reg_now (reg);
+}
+
+static void amd64_emit_pop_reg_now (const char *reg) {
+    emit_pop_reg_now (reg);
+}
+
+static int amd64_align_call_stack_bytes (int bytes) {
+
+    if (bytes < 0) {
+        bytes = 0;
+    }
+    
+    while (((bytes + amd64_temp_stack_mod16) & 15) != 0) {
+        bytes += 8;
+    }
+    
+    return bytes;
+
+}
+
+static void amd64_emit_sub_rsp_bytes (int bytes) {
+
+    if (!state->ofp || bytes <= 0) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    sub rsp, %d\n", bytes);
+    } else {
+        fprintf (state->ofp, "    subq $%d, %%rsp\n", bytes);
+    }
+    
+    amd64_note_stack_sub (bytes);
+
+}
+
+static void amd64_emit_add_rsp_bytes (int bytes) {
+
+    if (!state->ofp || bytes <= 0) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    add rsp, %d\n", bytes);
+    } else {
+        fprintf (state->ofp, "    addq $%d, %%rsp\n", bytes);
+    }
+    
+    amd64_note_stack_add (bytes);
+
+}
+
+static void amd64_emit_store_rax_to_stack_arg (int slot) {
+
+    int offset = 32 + slot * 8;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov qword [rsp + %d], rax\n" : "    mov qword ptr [rsp + %d], rax\n"), offset);
+    } else {
+        fprintf (state->ofp, "    movq %%rax, %d(%%rsp)\n", offset);
+    }
+
+}
+
+static void amd64_emit_store_rax_to_home_arg (int index) {
+
+    int offset = index * 8;
+    
+    if (!state->ofp || index < 0 || index >= 4) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov qword [rsp + %d], rax\n" : "    mov qword ptr [rsp + %d], rax\n"), offset);
+    } else {
+        fprintf (state->ofp, "    movq %%rax, %d(%%rsp)\n", offset);
+    }
+
+}
+
+static void amd64_emit_load_home_arg_to_reg (int index) {
+
+    const char *dst = amd64_integer_arg_reg (index);
+    int offset = index * 8;
+    
+    if (!state->ofp || !dst || index < 0 || index >= 4) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, qword [rsp + %d]\n" : "    mov %s, qword ptr [rsp + %d]\n"), dst, offset);
+    } else {
+        fprintf (state->ofp, "    movq %d(%%rsp), %%%s\n", offset, dst);
+    }
+
+}
+
+static void amd64_emit_mov_imm64_to_rax (int64_s v) {
+    amd64_emit_mov_i64_to_qword_reg_now ("rax", v);
+}
+
+static int amd64_emit_bare_64bit_identifier_to_rax_now (void) {
+
+    struct local_symbol *sym;
+    char *name;
+    
+    if (tok.kind != TOK_IDENT || !tok.ident || !current_argument_is_bare_identifier_now ()) {
+        return 0;
+    }
+    
+    name = xstrdup (tok.ident);
+    sym = find_local_symbol (name);
+    
+    if (sym && sym->size == (DATA_LLONG & 0x1f) && !sym->is_floating) {
+    
+        if (sym->is_static && sym->static_label) {
+            emit_load_global64_to_rax (sym->static_label);
+        } else {
+            emit_load_local64_to_rax (sym->offset);
+        }
+        
+        get_token ();
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (!sym && find_global_symbol (name) >= 0 && get_global_symbol_size (name) == (DATA_LLONG & 0x1f) && !get_global_symbol_floating (name)) {
+    
+        emit_load_global64_to_rax (name);
+        
+        get_token ();
+        free (name);
+        
+        return 1;
+    
+    }
+    
+    free (name);
+    return 0;
+
+}
+
+static void amd64_emit_load_assignment_rhs_expression_to_rax64 (int is_unsigned) {
+
+    if (token_kind_is_integer_constant_now (tok.kind)) {
+    
+        struct token *saved_tok = clone_current_token_now ();
+        enum token_kind next_kind;
+        
+        get_token ();
+        
+        next_kind = tok.kind;
+        unget_token (saved_tok);
+        
+        if (!token_kind_is_binary_expression_operator_now (next_kind)) {
+        
+            int64_s v = const64_from_current_operand ();
+            amd64_emit_mov_imm64_to_rax (v);
+            
+            return;
+        
+        }
+    
+    }
+    
+    if (current_integer_expr_is_foldable_now ()) {
+    
+        int64_s v = const64_from_current_foldable_expr ();
+        amd64_emit_mov_imm64_to_rax (v);
+        
+        return;
+    
+    }
+    
+    if (amd64_emit_bare_64bit_identifier_to_rax_now ()) {
+        return;
+    }
+    
+    /*
+     * Do not fall back to the old i386-style high/low pair path here.
+     * The AMD64 scalar RHS loader is responsible for producing the final
+     * value in RAX using the real source type: qword for pointers/DATA_LLONG,
+     * dword-with-extension for int/long, and byte/word extension for smaller
+     * objects.
+     */
+    emit_load_assignment_rhs_expression_to_reg ("rax");
+    (void) is_unsigned;
+
+}
+
+static void amd64_emit_move_rax_to_arg_reg (int index) {
+
+    const char *dst = amd64_integer_arg_reg (index);
+    
+    if (!state->ofp || !dst) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    mov %s, rax\n", dst);
+    } else {
+        fprintf (state->ofp, "    movq %%rax, %%%s\n", dst);
+    }
+
+}
+
+static const char *amd64_xmm_arg_reg (int index) {
+
+    static const char *regs[] = { "xmm0", "xmm1", "xmm2", "xmm3" };
+    
+    if (index < 0 || index >= 4) {
+        return 0;
+    }
+    
+    return regs[index];
+
+}
+
+static void amd64_emit_move_st0_to_arg (int index, int size, int duplicate_gp) {
+
+    const char *xmm = amd64_xmm_arg_reg (index);
+    const char *ireg = amd64_integer_arg_reg (index);
+    int offset;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (size != (DATA_FLOAT & 0x1f)) {
+        size = DATA_DOUBLE & 0x1f;
+    }
+    
+    if (index < 4 && xmm) {
+    
+        /*
+         * Microsoft x64 / EFI boundary rule: floating arguments are passed in
+         * XMM0-XMM3.  The backend may still use x87 internally, but the call
+         * boundary must spill ST(0) to memory and reload the ABI register.
+         *
+         * A prototyped float parameter is a real 32-bit float in XMMn, not a
+         * double.  The previous boundary shim always used fstp qword/movsd,
+         * which silently widened fixed float parameters and put the wrong ABI
+         * value in XMMn.  Keep doubles on movsd, but use fstp dword/movss for
+         * fixed float slots.
+         * 
+         * For varargs/unprototyped calls the same value must also be duplicated
+         * into the matching integer register so va_arg can recover it from the
+         * register home area.  In normal C those arguments have already been
+         * default-promoted to double, so the duplicate path remains qword-sized
+         * for the ABI-visible vararg case.
+         *
+         * Always reserve an 8-byte temporary spill slot, even for float.  Using
+         * a 4-byte sub/add pair temporarily misaligns RSP inside the already
+         * aligned call frame and makes this ABI shim harder to reason about.
+         */
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, "    sub rsp, 8\n");
+            
+            if (size == (DATA_FLOAT & 0x1f)) {
+            
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fstp dword [rsp]\n" : "    fstp dword ptr [rsp]\n"));
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movss %s, dword [rsp]\n" : "    movss %s, dword ptr [rsp]\n"), xmm);
+                
+                if (duplicate_gp && ireg) {
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [rsp]\n" : "    mov %s, dword ptr [rsp]\n"), amd64_dword_reg_name_from_any (ireg));
+                }
+            
+            } else {
+            
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fstp qword [rsp]\n" : "    fstp qword ptr [rsp]\n"));
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movsd %s, qword [rsp]\n" : "    movsd %s, qword ptr [rsp]\n"), xmm);
+                
+                if (duplicate_gp && ireg) {
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, qword [rsp]\n" : "    mov %s, qword ptr [rsp]\n"), ireg);
+                }
+            
+            }
+            
+            fprintf (state->ofp, "    add rsp, 8\n");
+        
+        } else {
+        
+            fprintf (state->ofp, "    subq $8, %%rsp\n");
+            
+            if (size == (DATA_FLOAT & 0x1f)) {
+            
+                fprintf (state->ofp, "    fstps (%%rsp)\n");
+                fprintf (state->ofp, "    movss (%%rsp), %%%s\n", xmm);
+                
+                if (duplicate_gp && ireg) {
+                    fprintf (state->ofp, "    movl (%%rsp), %%%s\n", amd64_dword_reg_name_from_any (ireg));
+                }
+            
+            } else {
+            
+                fprintf (state->ofp, "    fstpl (%%rsp)\n");
+                fprintf (state->ofp, "    movsd (%%rsp), %%%s\n", xmm);
+                
+                if (duplicate_gp && ireg) {
+                    fprintf (state->ofp, "    movq (%%rsp), %%%s\n", ireg);
+                }
+            
+            }
+            
+            fprintf (state->ofp, "    addq $8, %%rsp\n");
+        
+        }
+    
+    } else {
+    
+        offset = 32 + (index - 4) * 8;
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            if (size == (DATA_FLOAT & 0x1f)) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fstp dword [rsp + %d]\n" : "    fstp dword ptr [rsp + %d]\n"), offset);
+            } else {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fstp qword [rsp + %d]\n" : "    fstp qword ptr [rsp + %d]\n"), offset);
+            }
+        
+        } else {
+        
+            if (size == (DATA_FLOAT & 0x1f)) {
+                fprintf (state->ofp, "    fstps %d(%%rsp)\n", offset);
+            } else {
+                fprintf (state->ofp, "    fstpl %d(%%rsp)\n", offset);
+            }
+        
+        }
+    
+    }
+
+}
+
+static void emit_call_identifier_to_reg_now (const char *name, const char *reg, const char *name_start, const char *name_caret, unsigned long name_line) {
+
+    int argc = 0;
+    int inline_index;
+    int use_inline = 0;
+    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 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;
+    
+    const char *saved_pending_struct_return_global_name = pending_struct_return_global_name;
+    const char *asm_name;
+    
+    int saved_pending_struct_return_stack_address = pending_struct_return_stack_address;
+    int saved_pending_struct_return_stack_offset = pending_struct_return_stack_offset;
+    int saved_pending_struct_return_stack_top = pending_struct_return_stack_top;
+    
+    FILE *inline_saved_ofp = 0;
+    FILE *inline_tmp_ofp = 0;
+    FILE *arg_saved_ofp = 0;
+    FILE *arg_tmp_ofp = 0;
+    FILE **arg_tmp_ofps = 0;
+    FILE **new_arg_tmp_ofps = 0;
+    
+    int *arg_tmp_floating = 0;
+    int *new_arg_tmp_floating = 0;
+    int *arg_tmp_float_sizes = 0;
+    int *new_arg_tmp_float_sizes = 0;
+    
+    int arg_saved_stack_mod16 = 0;
+    int amd64_call_stack_bytes = 0;
+    int hidden_struct_return_arg = 0;
+    int effective_argc = 0;
+    
+    if (tok.kind != TOK_LPAREN) {
+        return;
+    }
+    
+    inline_index = find_inline_function (name);
+    
+    if (inline_index >= 0 &&
+        inline_functions[inline_index].usable &&
+        !inline_functions[inline_index].is_floating &&
+        !inline_functions[inline_index].expanding &&
+        (inline_functions[inline_index].body || inline_functions[inline_index].returns_void) &&
+        (!inline_functions[inline_index].body || inline_body_stack_delta (inline_functions[inline_index].body) == 0)) {
+    
+        use_inline = 1;
+        expected_inline_args = inline_functions[inline_index].param_count;
+        inline_arg_bytes = expected_inline_args * 8;
+        
+        if (state->ofp) {
+        
+            inline_tmp_ofp = scc_tmpfile ();
+            
+            if (inline_tmp_ofp) {
+            
+                inline_saved_ofp = state->ofp;
+                state->ofp = inline_tmp_ofp;
+            
+            }
+            
+            if (inline_arg_bytes > 0) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    sub rsp, %d\n", inline_arg_bytes);
+                } else {
+                    fprintf (state->ofp, "    subq $%d, %%rsp\n", inline_arg_bytes);
+                }
+            
+            }
+        
+        }
+    
+    }
+    
+    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) {
+    
+        for (;;) {
+        
+            arg_saved_ofp = 0;
+            arg_tmp_ofp = 0;
+            
+            /*
+             * cdecl wants the right-most argument nearest the call site and
+             * the left-most argument at [rbp + 8] in the callee.  The old
+             * code emitted each push immediately while parsing left-to-right,
+             * which reversed the parameter slots for normal calls.  Capture
+             * each non-inline argument's evaluation/push code and replay the
+             * completed argument blocks right-to-left just before CALL.
+             *
+             * Inline calls keep using the temporary argument frame below: that
+             * frame intentionally stores argument 0 at [rsp], argument 1 at
+             * [rsp + 4], etc., so do not reverse inline argument copies here.
+             */
+            if (!use_inline && state->ofp) {
+            
+                arg_tmp_ofp = scc_tmpfile ();
+                
+                if (arg_tmp_ofp) {
+                
+                    arg_saved_stack_mod16 = amd64_temp_stack_mod16;
+                    arg_saved_ofp = state->ofp;
+                    
+                    amd64_temp_stack_mod16 = 0;
+                    state->ofp = arg_tmp_ofp;
+                
+                }
+            
+            }
+            
+            postfix_member_seen = 0;
+            postfix_member_size = 0;
+            postfix_member_pointer_depth = 0;
+            postfix_member_pointed_size = 0;
+            
+            if (!use_inline && tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && find_local_symbol (tok.ident) && emit_push_aggregate_argument_now (tok.ident, find_local_symbol (tok.ident))) {
+            
+                struct local_symbol *arg_sym = find_local_symbol (tok.ident);
+                
+                arg_bytes = arg_sym ? arg_sym->size : DATA_PTR;
+                arg_is_floating = 0;
+                
+                get_token ();
+            
+            } else if (!use_inline && tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && !find_local_symbol (tok.ident) && emit_push_global_aggregate_argument_now (tok.ident)) {
+            
+                arg_bytes = get_global_symbol_size (tok.ident);
+                arg_is_floating = 0;
+                
+                get_token ();
+            
+            } else if (!use_inline && tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now () &&
+                       get_global_symbol_kind (tok.ident) == GLOBAL_SYMBOL_FUNCTION &&
+                       get_global_symbol_size (tok.ident) > (DATA_LLONG & 0x1f)) {
+            
+                char *arg_call_name = xstrdup (tok.ident);
+                
+                const char *arg_call_start = tok.start;
+                const char *arg_call_caret = tok.caret;
+                
+                unsigned long arg_call_line = get_line_number ();
+                
+                arg_bytes = get_global_symbol_size (arg_call_name);
+                arg_is_floating = 0;
+                
+                emit_sub_rsp_now (arg_bytes);
+                
+                pending_struct_return_lhs = 0;
+                pending_struct_return_global_name = 0;
+                pending_struct_return_stack_address = 0;
+                pending_struct_return_stack_offset = 0;
+                pending_struct_return_stack_top = 1;
+                
+                get_token ();
+                emit_call_identifier_to_reg_now (arg_call_name, "rax", arg_call_start, arg_call_caret, arg_call_line);
+                
+                pending_struct_return_stack_top = 0;
+                free (arg_call_name);
+            
+            } else {
+            
+                arg_is_floating = rhs_current_operand_is_floating_now ();
+                arg_bytes = arg_is_floating ? (DATA_DOUBLE & 0x1f) : DATA_PTR;
+                
+                if (!use_inline && arg_is_floating &&
+                    get_global_symbol_has_prototype (name) &&
+                    argc < get_global_symbol_param_count (name) &&
+                    get_global_symbol_param_floating (name, argc) &&
+                    get_global_symbol_param_size (name, argc) == (DATA_FLOAT & 0x1f)) {
+                    arg_bytes = DATA_FLOAT & 0x1f;
+                }
+                
+                if (!use_inline && get_global_symbol_has_prototype (name) &&
+                    argc < get_global_symbol_param_count (name) &&
+                    get_global_symbol_param_size (name, argc) == (DATA_LLONG & 0x1f) &&
+                    get_global_symbol_param_pointer_depth (name, argc) == 0 &&
+                    !get_global_symbol_param_floating (name, argc)) {
+                
+                    arg_is_floating = 0;
+                    arg_bytes = DATA_LLONG & 0x1f;
+                    
+                    amd64_emit_load_assignment_rhs_expression_to_rax64 (get_global_symbol_param_unsigned (name, argc));
+
+                } else if (!use_inline && get_global_symbol_has_prototype (name) && get_global_symbol_is_variadic (name) && argc >= get_global_symbol_param_count (name) && current_argument_starts_64bit_integer_now ()) {
+                
+                    arg_is_floating = 0;
+                    arg_bytes = DATA_LLONG & 0x1f;
+                        
+                    amd64_emit_load_assignment_rhs_expression_to_rax64 (rhs_current_operand_is_unsigned_now ());
+                
+                } else if (arg_is_floating) {
+                    emit_load_floating_rhs_expression_now (arg_bytes);
+                } else {
+                    emit_load_assignment_rhs_expression_to_reg ("rax");
+                }
+                
+                if (state->ofp) {
+                
+                    if (!use_inline && !arg_is_floating && arg_bytes == (DATA_LLONG & 0x1f)) {
+                    
+                        /**
+                         * AMD64 passes scalar arguments in 64-bit slots.  Do
+                         * not emit the old i386 EDX:EAX stack-push sequence
+                         * here; the completed argument evaluation is replayed
+                         * below and assigned to RCX/RDX/R8/R9 or a qword stack
+                         * slot according to the AMD64 calling convention.
+                         */
+                    
+                    } else if (!use_inline && !arg_is_floating && postfix_member_seen && postfix_member_pointer_depth == 0 && postfix_member_size > (DATA_PTR & 0x1f)) {
+                    
+                        arg_bytes = postfix_member_size;
+                        emit_push_aggregate_from_addr_reg_now ("rax", arg_bytes);
+                    
+                    } else if (!use_inline && !arg_is_floating && postfix_member_size > (DATA_PTR & 0x1f)) {
+                    
+                        arg_bytes = postfix_member_size;
+                        emit_push_aggregate_from_addr_reg_now ("rax", arg_bytes);
+                    
+                    } else if (use_inline) {
+                    
+                        if (argc < expected_inline_args) {
+                        
+                            if (state->syntax & ASM_SYNTAX_INTEL) {
+                                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov qword [rsp + %d], rax\n" : "    mov qword ptr [rsp + %d], rax\n"), argc * 8);
+                            } else {
+                                fprintf (state->ofp, "    movq %%rax, %d(%%rsp)\n", argc * 8);
+                            }
+                        
+                        }
+                    
+                    } else if (arg_is_floating) {
+                        /* Keep ST(0) live; amd64_emit_move_st0_to_arg() places it. */
+                    } else {
+                        /* Keep RAX live; the AMD64 call replay moves it to the proper slot. */
+                    }
+                
+                }
+            
+            }
+            
+            if (!use_inline) {
+                total_arg_bytes += arg_bytes;
+            }
+            
+            if (arg_saved_ofp) {
+            
+                fflush (arg_tmp_ofp);
+                
+                amd64_temp_stack_mod16 = arg_saved_stack_mod16;
+                state->ofp = arg_saved_ofp;
+                
+                new_arg_tmp_ofps = (FILE **) xrealloc (arg_tmp_ofps, sizeof (*arg_tmp_ofps) * (argc + 1));
+                
+                if (new_arg_tmp_ofps) {
+                
+                    arg_tmp_ofps = new_arg_tmp_ofps;
+                    
+                    arg_tmp_ofps[argc] = arg_tmp_ofp;
+                    arg_tmp_ofp = 0;
+                
+                }
+                
+                new_arg_tmp_floating = (int *) xrealloc (arg_tmp_floating, sizeof (*arg_tmp_floating) * (argc + 1));
+                
+                if (new_arg_tmp_floating) {
+                
+                    arg_tmp_floating = new_arg_tmp_floating;
+                    arg_tmp_floating[argc] = arg_is_floating;
+                
+                }
+                
+                new_arg_tmp_float_sizes = (int *) xrealloc (arg_tmp_float_sizes, sizeof (*arg_tmp_float_sizes) * (argc + 1));
+                
+                if (new_arg_tmp_float_sizes) {
+                
+                    arg_tmp_float_sizes = new_arg_tmp_float_sizes;
+                    arg_tmp_float_sizes[argc] = arg_is_floating ? arg_bytes : 0;
+                
+                }
+
+            }
+            
+            if (arg_tmp_ofp) {
+            
+                scc_close (arg_tmp_ofp);
+                arg_tmp_ofp = 0;
+            
+            }
+            
+            argc++;
+            
+            if (!_accept (TOK_COMMA)) {
+                break;
+            }
+        
+        }
+    
+    }
+    
+    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);
+    }
+    
+    if (use_inline) {
+    
+        if (argc == expected_inline_args && emit_inline_call_if_possible (name, argc, reg)) {
+        
+            if (state->ofp && inline_arg_bytes > 0) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    add rsp, %d\n", inline_arg_bytes);
+                } else {
+                    fprintf (state->ofp, "    addq $%d, %%rsp\n", inline_arg_bytes);
+                }
+            
+            }
+            
+            /*
+             * The peephole inline optimiser currently understands the
+             * single-argument case well, but its stack-slot liveness pass is
+             * too aggressive for multi-argument inline calls.  It can fold
+             * constants correctly in simple examples, but it may also remove
+             * the temporary argument frame and leave confusing label-only
+             * fragments.  Keep multi-argument inline expansion conservative:
+             * emit the substituted inline body exactly as generated, with the
+             * argument copies still present.
+             */
+            finish_inline_buffer (&inline_tmp_ofp, &inline_saved_ofp, expected_inline_args <= 1);
+            return;
+        
+        }
+        
+        if (state->ofp && inline_arg_bytes > 0) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    add rsp, %d\n", inline_arg_bytes);
+            } else {
+                fprintf (state->ofp, "    addq $%d, %%rsp\n", inline_arg_bytes);
+            }
+        
+        }
+        
+        finish_inline_buffer (&inline_tmp_ofp, &inline_saved_ofp, 0);
+        return;
+    
+    }
+    
+    if (emit_inline_call_if_possible (name, argc, reg)) {
+    
+        if (arg_tmp_ofps) {
+        
+            for (i = 0; i < argc; i++) {
+            
+                if (arg_tmp_ofps[i]) {
+                    scc_close (arg_tmp_ofps[i]);
+                }
+            
+            }
+            
+            for (i = hidden_struct_return_arg; i < effective_argc && i < 4; i++) {
+            
+                int user_index = i - hidden_struct_return_arg;
+                
+                if (user_index >= 0 && user_index < argc && !(arg_tmp_floating && arg_tmp_floating[user_index])) {
+                    amd64_emit_load_home_arg_to_reg (i);
+                }
+            
+            }
+            
+            free (arg_tmp_ofps);
+            arg_tmp_ofps = 0;
+        
+        }
+        
+        if (arg_tmp_floating) {
+        
+            free (arg_tmp_floating);
+            arg_tmp_floating = 0;
+        
+        }
+        
+        if (arg_tmp_float_sizes) {
+        
+            free (arg_tmp_float_sizes);
+            arg_tmp_float_sizes = 0;
+        
+        }
+        
+        return;
+    
+    }
+    
+    call_sym = find_local_symbol (name);
+    
+    if (!call_sym) {
+    
+        if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_OBJECT) {
+            emit_extern_reference_symbol (name, DATA_PTR);
+        } else {
+            emit_extern_symbol (name, DATA_PTR, 1);
+        }
+        
+        asm_name = asm_global_symbol_name (name);
+    
+    } else {
+        asm_name = 0;
+    }
+    
+    if (state->ofp) {
+    
+        /*
+         * Microsoft x64 requires the caller to reserve the 32-byte home area
+         * for every call, even when the call has no arguments.  The old code
+         * only reserved it when arg_tmp_ofps was non-null, so zero-argument
+         * calls emitted no shadow space at all.
+         */
+        hidden_struct_return_arg = (saved_pending_struct_return_lhs || saved_pending_struct_return_global_name || saved_pending_struct_return_stack_address || saved_pending_struct_return_stack_top) ? 1 : 0;
+        effective_argc = argc + hidden_struct_return_arg;
+            
+        amd64_call_stack_bytes = 32;
+        
+        if (effective_argc > 4) {
+            amd64_call_stack_bytes += (effective_argc - 4) * 8;
+        }
+        
+        amd64_call_stack_bytes = amd64_align_call_stack_bytes (amd64_call_stack_bytes);
+        amd64_emit_sub_rsp_bytes (amd64_call_stack_bytes);
+        
+        if (arg_tmp_ofps) {
+        
+            /*
+             * Replay argument evaluations from right to left.  Each captured
+             * argument fragment may contain calls, and a nested call is free
+             * to clobber RCX/RDX/R8/R9.  Replaying left-to-right can therefore
+             * load an early argument register, evaluate a later argument that
+             * calls out, and lose the earlier register value before the final
+             * call.  Assign the low-numbered register arguments last.
+             */
+            for (i = argc - 1; i >= 0; i--) {
+            
+                if (arg_tmp_ofps[i]) {
+                
+                    int arg_index = i + hidden_struct_return_arg;
+                    fseek (arg_tmp_ofps[i], 0, SEEK_SET);
+                    
+                    while ((ch = fgetc (arg_tmp_ofps[i])) != EOF) {
+                        fputc (ch, state->ofp);
+                    }
+                    
+                    if (arg_tmp_floating && arg_tmp_floating[i]) {
+                    
+                        amd64_emit_move_st0_to_arg (arg_index,
+                            (arg_tmp_float_sizes && arg_tmp_float_sizes[i]) ? arg_tmp_float_sizes[i] :
+                                ((get_global_symbol_has_prototype (name) &&
+                                    i < get_global_symbol_param_count (name) &&
+                                        get_global_symbol_param_floating (name, i) &&
+                                            get_global_symbol_param_size (name, i) == (DATA_FLOAT & 0x1f)) ? (DATA_FLOAT & 0x1f) : (DATA_DOUBLE & 0x1f)),
+                                                (!get_global_symbol_has_prototype (name) ||
+                                                    (get_global_symbol_is_variadic (name) &&
+                                                        i >= get_global_symbol_param_count (name))));
+                    
+                    } else if (arg_index < 4) {
+                        amd64_emit_store_rax_to_home_arg (arg_index);
+                    } else {
+                        amd64_emit_store_rax_to_stack_arg (arg_index - 4);
+                    }
+                    
+                    scc_close (arg_tmp_ofps[i]);
+                    arg_tmp_ofps[i] = 0;
+                
+                }
+            
+            }
+            
+            /*
+             * Non-floating AMD64 register arguments were staged into the
+             * caller's home area while replaying captured argument code.
+             * Load RCX/RDX/R8/R9 only after all argument evaluations have
+             * finished, otherwise a nested call in a later argument can
+             * clobber an earlier register argument before the final call.
+             */
+            for (i = 0; i < argc; i++) {
+            
+                int arg_index = i + hidden_struct_return_arg;
+                
+                if (arg_index >= 4) {
+                    continue;
+                }
+                
+                if (arg_tmp_floating && arg_tmp_floating[i]) {
+                    continue;
+                }
+                
+                amd64_emit_load_home_arg_to_reg (arg_index);
+            
+            }
+            
+            free (arg_tmp_ofps);
+            arg_tmp_ofps = 0;
+            
+            if (arg_tmp_floating) {
+            
+                free (arg_tmp_floating);
+                arg_tmp_floating = 0;
+            
+            }
+            
+            if (arg_tmp_float_sizes) {
+            
+                free (arg_tmp_float_sizes);
+                arg_tmp_float_sizes = 0;
+            
+            }
+        
+        }
+        
+        if (hidden_struct_return_arg) {
+        
+            pending_struct_return_lhs = saved_pending_struct_return_lhs;
+            pending_struct_return_global_name = saved_pending_struct_return_global_name;
+            pending_struct_return_stack_address = saved_pending_struct_return_stack_address;
+            pending_struct_return_stack_offset = saved_pending_struct_return_stack_offset;
+            pending_struct_return_stack_top = saved_pending_struct_return_stack_top;
+            
+            /*
+             * The hidden return-buffer pointer occupies argument register 0.
+             * Emit it after replaying user arguments so nested argument
+             * evaluation cannot clobber RCX.
+             */
+            emit_load_pending_struct_return_address_to_rax_now (amd64_call_stack_bytes);
+            amd64_emit_move_rax_to_arg_reg (0);
+        
+        }
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            if (call_sym) {
+            
+                emit_load_local_to_reg ("r11", call_sym->offset, DATA_PTR);
+                fprintf (state->ofp, "    call r11\n");
+            
+            } else if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_OBJECT) {
+            
+                emit_load_global_to_reg ("r11", name, DATA_PTR);
+                fprintf (state->ofp, "    call r11\n");
+            
+            } else if (get_global_symbol_dllimport (name)) {
+            
+                remember_global_symbol_import_call_stack_bytes (name, total_arg_bytes);
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    call qword [%s]\n" : "    call qword ptr [%s]\n"), asm_global_import_symbol_name (name));
+            
+            } else {
+                fprintf (state->ofp, "    call %s\n", asm_name);
+            }
+            
+            if (amd64_call_stack_bytes > 0) {
+                amd64_emit_add_rsp_bytes (amd64_call_stack_bytes);
+            }
+            
+            if (strcmp (reg, "rax") != 0) {
+                fprintf (state->ofp, "    mov %s, rax\n", reg);
+            }
+        
+        } else {
+        
+            if (call_sym) {
+            
+                emit_load_local_to_reg ("r11", call_sym->offset, DATA_PTR);
+                fprintf (state->ofp, "    call *%%r11\n");
+            
+            } else if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_OBJECT) {
+            
+                emit_load_global_to_reg ("r11", name, DATA_PTR);
+                fprintf (state->ofp, "    call *%%r11\n");
+            
+            } else if (get_global_symbol_dllimport (name)) {
+            
+                remember_global_symbol_import_call_stack_bytes (name, total_arg_bytes);
+                fprintf (state->ofp, "    call *%s\n", asm_global_import_symbol_name (name));
+            
+            } else {
+                fprintf (state->ofp, "    call %s\n", asm_name);
+            }
+            
+            if (amd64_call_stack_bytes > 0) {
+                amd64_emit_add_rsp_bytes (amd64_call_stack_bytes);
+            }
+            
+            if (strcmp (reg, "rax") != 0) {
+                fprintf (state->ofp, "    movq %%rax, %%%s\n", reg);
+            }
+        
+        }
+    
+    }
+    
+    set_rhs_last_pointer_info (get_global_symbol_pointer_depth (name), get_global_symbol_pointed_size (name));
+    
+    pending_struct_return_lhs = 0;
+    pending_struct_return_global_name = 0;
+    pending_struct_return_stack_address = 0;
+    pending_struct_return_stack_offset = 0;
+    pending_struct_return_stack_top = 0;
+    
+    if (arg_tmp_ofps) {
+    
+        for (i = 0; i < argc; i++) {
+        
+            if (arg_tmp_ofps[i]) {
+                scc_close (arg_tmp_ofps[i]);
+            }
+        
+        }
+        
+        free (arg_tmp_ofps);
+        arg_tmp_ofps = 0;
+    
+    }
+
+}
+
+static void emit_statement_label (int label);
+static void emit_statement_jump (int label);
+
+#define     MAX_GOTO_LABELS        256
+#define     MAX_GOTO_REFS          512
+
+struct goto_label_entry {
+
+    char *name;
+    
+    int label;
+    int defined;
+    int referenced;
+
+    long defined_stack_size;
+    unsigned long line;
+    
+    const char *start;
+    const char *caret;
+
+};
+
+static struct goto_label_entry goto_labels[MAX_GOTO_LABELS];
+static int goto_label_count = 0;
+
+struct goto_ref_entry {
+
+    int label_index;
+    int ref_label;
+    
+    long stack_size;
+
+};
+
+static struct goto_ref_entry goto_refs[MAX_GOTO_REFS];
+static int goto_ref_count = 0;
+
+static int current_break_label = -1;
+static int current_continue_label = -1;
+
+static long current_break_cleanup_base = 0;
+static long current_continue_cleanup_base = 0;
+
+#define     MAX_SWITCH_CASES        256
+
+struct switch_case_entry {
+
+    long value;
+    int label;
+
+};
+
+struct switch_context {
+
+    struct switch_case_entry cases[MAX_SWITCH_CASES];
+    int case_count;
+    int default_label;
+    int break_label;
+
+};
+
+static struct switch_context *current_switch_context = 0;
+static int statement_ends_control_flow = 0;
+
+static void reset_goto_labels (void) {
+
+    int i;
+    
+    for (i = 0; i < goto_label_count; i++) {
+    
+        if (goto_labels[i].name) {
+            free (goto_labels[i].name);
+        }
+        
+        goto_labels[i].name = 0;
+        goto_labels[i].label = 0;
+        goto_labels[i].defined = 0;
+        goto_labels[i].referenced = 0;
+        goto_labels[i].defined_stack_size = 0;
+        goto_labels[i].line = 0;
+        goto_labels[i].start = 0;
+        goto_labels[i].caret = 0;
+    
+    }
+    
+    goto_label_count = 0;
+    goto_ref_count = 0;
+
+}
+
+static int find_goto_label (const char *name) {
+
+    int i;
+    
+    for (i = 0; i < goto_label_count; i++) {
+    
+        if (goto_labels[i].name && strcmp (goto_labels[i].name, name) == 0) {
+            return i;
+        }
+    
+    }
+    
+    return -1;
+
+}
+
+static int get_goto_label (const char *name, unsigned long line, const char *start, const char *caret) {
+
+    int i = find_goto_label (name);
+    
+    if (i >= 0) {
+        return i;
+    }
+    
+    if (goto_label_count >= MAX_GOTO_LABELS) {
+    
+        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "too many goto labels");
+        return -1;
+    
+    }
+    
+    i = goto_label_count++;
+    
+    goto_labels[i].name = xstrdup (name);
+    goto_labels[i].label = anon_label++;
+    goto_labels[i].defined = 0;
+    goto_labels[i].referenced = 0;
+    goto_labels[i].defined_stack_size = 0;
+    goto_labels[i].line = line;
+    goto_labels[i].start = start;
+    goto_labels[i].caret = caret;
+    
+    return i;
+
+}
+
+static void define_goto_label (const char *name, unsigned long line, const char *start, const char *caret) {
+
+    int i = get_goto_label (name, line, start, caret);
+    
+    if (i < 0) {
+        return;
+    }
+    
+    if (goto_labels[i].defined) {
+    
+        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "duplicate label '%s'", name);
+        return;
+    
+    }
+    
+    goto_labels[i].defined = 1;
+    goto_labels[i].defined_stack_size = current_local_stack_size;
+    
+    /**
+     * A C label marks the next statement.  If the previous statement was a
+     * return, the compiler may have deferred the jump to the common return
+     * label so it can avoid redundant jumps.  Flush it before emitting the
+     * user label, otherwise the user label will point at the deferred return
+     * jump instead of the labelled statement.
+     */
+    if (pending_return_jump) {
+        emit_pending_return_jump ();
+    }
+    
+    emit_statement_label (goto_labels[i].label);
+
+}
+
+static void reference_goto_label (const char *name, unsigned long line, const char *start, const char *caret) {
+
+    int i = get_goto_label (name, line, start, caret);
+    
+    if (i < 0) {
+        return;
+    }
+    
+    goto_labels[i].referenced = 1;
+    
+    /*
+     * If this is a forward goto, do not jump directly to the final C
+     * label.  The target may be after automatic declarations in an inner
+     * block.  Because SCC emits stack allocation when those declarations are
+     * parsed, a direct branch can bypass the allocation and then use invalid
+     * EBP-relative locals.  Emit a per-reference trampoline after the function
+     * epilogue once the target stack depth is known.
+     */
+    if (!goto_labels[i].defined) {
+    
+        if (goto_ref_count < MAX_GOTO_REFS) {
+        
+            int ref_label = anon_label++;
+            
+            goto_refs[goto_ref_count].label_index = i;
+            goto_refs[goto_ref_count].ref_label = ref_label;
+            goto_refs[goto_ref_count].stack_size = current_local_stack_size;
+            goto_ref_count++;
+            
+            emit_statement_jump (ref_label);
+            return;
+        
+        }
+    
+    }
+    
+    emit_statement_jump (goto_labels[i].label);
+
+}
+
+static void check_goto_labels (void) {
+
+    int i;
+    
+    for (i = 0; i < goto_label_count; i++) {
+    
+        if (goto_labels[i].referenced && !goto_labels[i].defined) {
+            report_line_at (get_filename (), goto_labels[i].line, REPORT_ERROR, goto_labels[i].start, goto_labels[i].caret, "undefined label '%s'", goto_labels[i].name);
+        }
+    
+    }
+
+}
+
+static void emit_goto_trampolines (void) {
+
+    int i;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    for (i = 0; i < goto_ref_count; i++) {
+    
+        int label_index = goto_refs[i].label_index;
+        long delta;
+        
+        if (label_index < 0 || label_index >= goto_label_count) {
+            continue;
+        }
+        
+        if (!goto_labels[label_index].defined) {
+            continue;
+        }
+        
+        emit_statement_label_raw (goto_refs[i].ref_label);
+        delta = goto_labels[label_index].defined_stack_size - goto_refs[i].stack_size;
+        
+        /*
+         * 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);
+    
+    }
+
+}
+
+static void queue_pending_statement_label (int label) {
+
+    if (label < 0) {
+        return;
+    }
+    
+    if (pending_statement_label_count >= MAX_PENDING_STATEMENT_LABELS) {
+        flush_pending_statement_labels ();
+    }
+    
+    if (pending_statement_label_count < MAX_PENDING_STATEMENT_LABELS) {
+        pending_statement_labels[pending_statement_label_count++] = label;
+    } else {
+        emit_statement_label (label);
+    }
+
+}
+
+static void add_switch_case_label (long value, unsigned long line, const char *start, const char *caret) {
+
+    int i;
+    
+    if (!current_switch_context) {
+    
+        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "case label not within a switch statement");
+        return;
+    
+    }
+    
+    for (i = 0; i < current_switch_context->case_count; i++) {
+    
+        if (current_switch_context->cases[i].value == value) {
+        
+            report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "duplicate case value");
+            return;
+        
+        }
+    
+    }
+    
+    if (current_switch_context->case_count >= MAX_SWITCH_CASES) {
+    
+        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "too many case labels in switch statement");
+        return;
+    
+    }
+    
+    current_switch_context->cases[current_switch_context->case_count].value = value;
+    current_switch_context->cases[current_switch_context->case_count].label = anon_label++;
+    
+    queue_pending_statement_label (current_switch_context->cases[current_switch_context->case_count].label);
+    current_switch_context->case_count++;
+
+}
+
+static void set_switch_default_label (unsigned long line, const char *start, const char *caret) {
+
+    if (!current_switch_context) {
+    
+        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "default label not within a switch statement");
+        return;
+    
+    }
+    
+    if (current_switch_context->default_label >= 0) {
+    
+        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "duplicate default label");
+        return;
+    
+    }
+    
+    current_switch_context->default_label = anon_label++;
+    queue_pending_statement_label (current_switch_context->default_label);
+
+}
+
+static void emit_switch_dispatch (struct switch_context *sw) {
+
+    int i;
+    int target;
+    
+    if (!state->ofp || !sw) {
+        return;
+    }
+    
+    for (i = 0; i < sw->case_count; i++) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, "    cmp rax, %ld\n", sw->cases[i].value);
+            
+            if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+                fprintf (state->ofp, "    je L%d\n", sw->cases[i].label);
+            } else {
+                fprintf (state->ofp, "    je .L%d\n", sw->cases[i].label);
+            }
+        
+        } else {
+        
+            fprintf (state->ofp, "    cmpq $%ld, %%rax\n", sw->cases[i].value);
+            fprintf (state->ofp, "    je .L%d\n", sw->cases[i].label);
+        
+        }
+    
+    }
+    
+    target = (sw->default_label >= 0) ? sw->default_label : sw->break_label;
+    emit_statement_jump (target);
+
+}
+
+static void parse_switch_statement (void) {
+
+    struct switch_context sw;
+    struct switch_context *old_switch_context;
+    
+    int old_break_label;
+    int old_continue_label;
+    
+    long old_break_cleanup_base;
+    long old_continue_cleanup_base;
+    
+    int saved_ends_control_flow;
+    
+    FILE *saved_ofp;
+    FILE *body_tmp = 0;
+    
+    char *body_text = 0;
+    int body_pending_return_jump = 0;
+    
+    sw.case_count = 0;
+    sw.default_label = -1;
+    sw.break_label = anon_label++;
+    
+    get_token ();
+    expect (TOK_LPAREN, "(");
+    
+    emit_load_assignment_rhs_expression_to_reg ("rax");
+    
+    if (tok.kind != TOK_RPAREN) {
+        skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+    }
+    
+    expect (TOK_RPAREN, ")");
+    
+    old_switch_context = current_switch_context;
+    old_break_label = current_break_label;
+    old_continue_label = current_continue_label;
+    old_break_cleanup_base = current_break_cleanup_base;
+    old_continue_cleanup_base = current_continue_cleanup_base;
+    
+    current_switch_context = &sw;
+    current_break_label = sw.break_label;
+    current_break_cleanup_base = current_block_cleanup_bytes;
+    
+    saved_ofp = state->ofp;
+    
+    if (saved_ofp) {
+    
+        body_tmp = scc_tmpfile ();
+        
+        if (body_tmp) {
+            state->ofp = body_tmp;
+        }
+    
+    }
+    
+    parse_statement ();
+    saved_ends_control_flow = statement_ends_control_flow;
+    
+    if (body_tmp) {
+    
+        body_text = read_tmp_file_text (body_tmp);
+        
+        scc_close (body_tmp);
+        body_tmp = 0;
+        
+        state->ofp = saved_ofp;
+        
+        body_pending_return_jump = pending_return_jump;
+        pending_return_jump = 0;
+        
+        emit_switch_dispatch (&sw);
+        
+        if (body_text) {
+        
+            fputs (body_text, state->ofp);
+            free (body_text);
+        
+        }
+        
+        pending_return_jump = body_pending_return_jump;
+    
+    } else {
+        state->ofp = saved_ofp;
+    }
+    
+    emit_statement_label (sw.break_label);
+    
+    current_switch_context = old_switch_context;
+    current_break_label = old_break_label;
+    current_continue_label = old_continue_label;
+    current_break_cleanup_base = old_break_cleanup_base;
+    current_continue_cleanup_base = old_continue_cleanup_base;
+    
+    /*
+     * A break inside the switch only leaves the switch.  Do not propagate the
+     * break statement's statement_ends_control_flow flag to the enclosing
+     * statement, otherwise code like:
+     *
+     *     if (x) { switch (y) { case 1: break; } } else { ... }
+     *
+     * is compiled without the jump over the else block and the true branch
+     * falls through into the else body.
+     */
+    (void)saved_ends_control_flow;
+    statement_ends_control_flow = 0;
+
+}
+
+static int is_value_compare_operator (enum token_kind k) {
+
+    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 const char *value_compare_set_mnemonic (enum token_kind op, int is_unsigned) {
+
+    switch (op) {
+    
+        case TOK_LESS:
+        
+            return is_unsigned ? "setb"  : "setl";
+        
+        case TOK_LTEQ:
+        
+            return is_unsigned ? "setbe" : "setle";
+        
+        case TOK_GREATER:
+        
+            return is_unsigned ? "seta"  : "setg";
+        
+        case TOK_GTEQ:
+        
+            return is_unsigned ? "setae" : "setge";
+        
+        case TOK_EQEQ:
+        
+            return "sete";
+        
+        case TOK_NOTEQ:
+        
+            return "setne";
+        
+        default:
+        
+            return "setne";
+    
+    }
+
+}
+
+static void emit_compare_rax_rdx_to_reg (enum token_kind op, const char *reg, int is_unsigned) {
+
+    const char *setcc;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    setcc = value_compare_set_mnemonic (op, is_unsigned);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    cmp rax, rdx\n");
+        fprintf (state->ofp, "    %s al\n", setcc);
+        fprintf (state->ofp, "    movzx eax, al\n");
+        
+        if (strcmp (reg, "rax") != 0) {
+            fprintf (state->ofp, "    mov %s, rax\n", reg);
+        }
+    
+    } else {
+    
+        fprintf (state->ofp, "    cmpq %%rdx, %%rax\n");
+        fprintf (state->ofp, "    %s %%al\n", setcc);
+        fprintf (state->ofp, "    movzbl %%al, %%eax\n");
+        
+        if (strcmp (reg, "rax") != 0) {
+            fprintf (state->ofp, "    movq %%rax, %%%s\n", reg);
+        }
+    
+    }
+
+}
+
+static int rhs_current_operand_is_unsigned_now (void);
+
+static int source_lhs_has_char_pointer_cast_before_now (const char *p) {
+
+    const char *q;
+    int limit = 160;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    q = p;
+    
+    while (limit-- > 0 && q > tok.start) {
+    
+        q--;
+        
+        if (*q != '(') {
+            continue;
+        }
+        
+        if ((strncmp (q, "(char", 5) == 0 || strncmp (q, "(unsigned char", 14) == 0 || strncmp (q, "(signed char", 12) == 0)
+            && strchr (q, '*') && strchr (q, ')') && strchr (q, '*') < p && strchr (q, ')') < p) {
+            return 1;
+        }
+        
+        if (*q == ';' || *q == ',' || *q == '\n') {
+            break;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int arithmetic_operator_precedence_now (enum token_kind op) {
+
+    if (op == TOK_PIPE) {
+        return 1;
+    }
+    
+    if (op == TOK_CARET) {
+        return 2;
+    }
+    
+    if (op == TOK_AMPER) {
+        return 3;
+    }
+    
+    if (op == TOK_LSH || op == TOK_RSH) {
+        return 4;
+    }
+    
+    if (op == TOK_PLUS || op == TOK_MINUS) {
+        return 5;
+    }
+    
+    if (op == TOK_STAR || op == TOK_BSLASH || op == TOK_MOD) {
+        return 6;
+    }
+    
+    return 0;
+
+}
+
+static int emit_load_assignment_binary_expression_prec_to_reg (const char *reg, int min_prec) {
+
+    int is_unsigned;
+    int expr_pointer_depth;
+    int expr_pointed_size;
+    
+    is_unsigned = rhs_current_operand_is_unsigned_now ();
+    emit_load_assignment_rhs_to_reg (reg);
+    
+    /*
+     * Some statement-condition paths can leave a postfix member chain after
+     * the primary operand, e.g. inside parenthesized logical RHS terms such as
+     *     && (reg->type.dword || reg->type.debug)
+     * Consume that postfix here before the binary/logical expression parser
+     * decides whether the operand is complete.  Otherwise the enclosing
+     * parenthesized-expression code sees the still-pending "->"/"." token and
+     * reports a false "expected )".
+     */
+    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+        emit_apply_postfix_member_access_to_reg_now (reg);
+    }
+    
+    /*
+     * The postfix member helper deliberately leaves aggregates and 64-bit
+     * scalar members as an address because the pair/aggregate paths may need
+     * the full object.  This single-register expression path, however, only
+     * has EAX/EDX-style 32-bit arithmetic available.  When such a member is
+     * used inside ordinary arithmetic/comparison code (for example the
+     * CHECK_READ macro in pdld with address_type fields), load the low word
+     * from the member address instead of adding the member address itself.
+     */
+    if (postfix_member_seen
+        && postfix_member_pointer_depth == 0
+        && postfix_member_size == (DATA_LLONG & 0x1f)
+        && !postfix_member_is_floating) {
+    
+        emit_load_deref_reg_now (reg, DATA_INT & 0x1f);
+        postfix_member_size = DATA_INT & 0x1f;
+    
+    }
+    
+    if (postfix_member_seen && postfix_member_is_unsigned) {
+        is_unsigned = 1;
+    }
+    
+    expr_pointer_depth = rhs_last_pointer_depth;
+    expr_pointed_size = rhs_last_pointed_size;
+    
+    while (is_arithmetic_binary_operator (tok.kind) && arithmetic_operator_precedence_now (tok.kind) >= min_prec) {
+        
+        enum token_kind op;
+        
+        int prec;
+        int rhs_is_unsigned;
+        int lhs_pointer_depth;
+        int lhs_pointed_size;
+        int rhs_pointer_depth;
+        int rhs_pointed_size;
+        int scale_rhs = 0;
+        int scale_lhs = 0;
+        
+        op = tok.kind;
+        prec = arithmetic_operator_precedence_now (op);
+        
+        lhs_pointer_depth = expr_pointer_depth;
+        lhs_pointed_size = expr_pointed_size;
+        
+        if ((op == TOK_PLUS || op == TOK_MINUS) && lhs_pointer_depth > 0 &&
+            source_lhs_has_char_pointer_cast_before_now (tok.caret)) {
+            lhs_pointed_size = DATA_CHAR & 0x1f;
+        }
+        
+        get_token ();
+        rhs_is_unsigned = rhs_current_operand_is_unsigned_now ();
+        
+        if (rhs_is_unsigned) {
+            is_unsigned = 1;
+        }
+        
+        if (strcmp (reg, "rax") != 0 && state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    mov rax, %s\n", reg);
+            } else {
+                fprintf (state->ofp, "    movq %%%s, %%rax\n", reg);
+            }
+        
+        }
+        
+        emit_push_reg_now ("rax");
+        rhs_is_unsigned = emit_load_assignment_binary_expression_prec_to_reg ("rdx", prec + 1);
+        
+        if (rhs_is_unsigned) {
+            is_unsigned = 1;
+        }
+        
+        rhs_pointer_depth = rhs_last_pointer_depth;
+        rhs_pointed_size = rhs_last_pointed_size;
+        
+        if ((op == TOK_PLUS || op == TOK_MINUS) && lhs_pointer_depth > 0 && rhs_pointer_depth == 0) {
+            scale_rhs = index_step_size (lhs_pointed_size);
+        } else if (op == TOK_PLUS && lhs_pointer_depth == 0 && rhs_pointer_depth > 0) {
+            scale_lhs = index_step_size (rhs_pointed_size);
+        }
+        
+        if (scale_rhs > 1) {
+            emit_scale_reg_by_const_now ("rdx", scale_rhs);
+        }
+        
+        emit_pop_reg_now ("rax");
+        
+        if (scale_lhs > 1) {
+            emit_scale_reg_by_const_now ("rax", scale_lhs);
+        }
+        
+        emit_assignment_binary_op (op, is_unsigned);
+        
+        if (op == TOK_MINUS && lhs_pointer_depth > 0 && rhs_pointer_depth > 0 && index_step_size (lhs_pointed_size) > 1) {
+            emit_divide_rax_by_const_now (index_step_size (lhs_pointed_size));
+        }
+        
+        if (op == TOK_PLUS && lhs_pointer_depth == 0 && rhs_pointer_depth > 0) {
+        
+            expr_pointer_depth = rhs_pointer_depth;
+            expr_pointed_size = rhs_pointed_size;
+        
+        } else if (op == TOK_MINUS && lhs_pointer_depth > 0 && rhs_pointer_depth > 0) {
+        
+            expr_pointer_depth = 0;
+            expr_pointed_size = 0;
+        
+        } else if (op != TOK_PLUS && op != TOK_MINUS) {
+        
+            expr_pointer_depth = 0;
+            expr_pointed_size = 0;
+        
+        }
+        
+        if (strcmp (reg, "rax") != 0 && state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    mov %s, rax\n", reg);
+            } else {
+                fprintf (state->ofp, "    movq %%rax, %%%s\n", reg);
+            }
+        
+        }
+    
+    }
+    
+    set_rhs_last_pointer_info (expr_pointer_depth, expr_pointed_size);
+    return is_unsigned;
+
+}
+
+static void emit_load_assignment_binary_expression_to_reg (const char *reg) {
+
+    if (current_integer_expr_is_foldable_now ()) {
+    
+        int64_s v = const64_from_current_foldable_expr ();
+        emit_load_const32_to_reg_now (reg, v);
+        
+        return;
+    
+    }
+    
+    emit_load_assignment_binary_expression_prec_to_reg (reg, 1);
+
+}
+
+static void emit_statement_const32_to_rdx (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 rax, <rhs-constant>
+     *     test rax, rax
+     */
+    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 ();
+    
+    if (emit_load_assignment_binary_expression_prec_to_reg (reg, 1)) {
+        is_unsigned = 1;
+    }
+    
+    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, "rax") != 0 && state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    mov rax, %s\n", reg);
+            } else {
+                fprintf (state->ofp, "    movq %%%s, %%rax\n", 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 rax, 45
+         *     test rax, rax
+         *
+         * 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_rdx (rhs_enum_value);
+            
+            if (lhs_pointer_depth > 0) {
+                is_unsigned = 1;
+            }
+            
+            emit_compare_rax_rdx_to_reg (op, reg, is_unsigned);
+            return;
+        
+        }
+        
+        emit_push_reg_now ("rax");
+        
+        if (rhs_current_operand_is_unsigned_now ()) {
+            is_unsigned = 1;
+        }
+        
+        if (!emit_statement_rhs_const32_to_rdx_if_possible ()) {
+            emit_load_assignment_binary_expression_to_reg ("rdx");
+        }
+        
+        if (lhs_pointer_depth > 0 || rhs_last_pointer_depth > 0) {
+            is_unsigned = 1;
+        }
+        
+        emit_pop_reg_now ("rax");
+        emit_compare_rax_rdx_to_reg (op, reg, is_unsigned);
+    
+    }
+
+}
+
+static void emit_test_reg_jump_zero_now (const char *reg, int label) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    test %s, %s\n", reg, reg);
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jz L%d\n" : "    jz .L%d\n"), label);
+    
+    } else {
+    
+        fprintf (state->ofp, "    testq %%%s, %%%s\n", reg, reg);
+        fprintf (state->ofp, "    jz .L%d\n", label);
+    
+    }
+
+}
+
+static void emit_test_reg_jump_nonzero_now (const char *reg, int label) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    test %s, %s\n", reg, reg);
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), label);
+    
+    } else {
+    
+        fprintf (state->ofp, "    testq %%%s, %%%s\n", reg, reg);
+        fprintf (state->ofp, "    jnz .L%d\n", label);
+    
+    }
+
+}
+
+static void emit_mov_imm_to_reg_now (const char *reg, long value) {
+
+    const char *dreg = amd64_dword_reg_name_from_any (reg);
+    
+    if (!state->ofp || !dreg) {
+        return;
+    }
+    
+    /*
+     * This helper is used by boolean/integer-result paths.  Load through the
+     * dword register so AMD64 clears the upper half instead of relying on a
+     * qword immediate move with sign-extension-sensitive encodings.
+     */
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    mov %s, %ld\n", dreg, value);
+    } else {
+        fprintf (state->ofp, "    movl $%ld, %%%s\n", value, dreg);
+    }
+
+}
+
+static void emit_floating_stack_to_int_reg_now (const char *reg) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    /*
+     * C requires floating-to-integer conversion to discard the fractional
+     * part.  x87 fistp uses the current FPU rounding mode, which is normally
+     * round-to-nearest, so values such as 0.5000000001 become 1 instead of 0.
+     * Temporarily switch the x87 control word to truncate for this conversion.
+     */
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    sub rsp, 8\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fnstcw word [rsp + 4]\n" : "    fnstcw word ptr [rsp + 4]\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov ax, word [rsp + 4]\n" : "    mov ax, word ptr [rsp + 4]\n");
+        fprintf (state->ofp, "    or ah, 12\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov word [rsp + 6], ax\n" : "    mov word ptr [rsp + 6], ax\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fldcw word [rsp + 6]\n" : "    fldcw word ptr [rsp + 6]\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fistp dword [rsp]\n" : "    fistp dword ptr [rsp]\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fldcw word [rsp + 4]\n" : "    fldcw word ptr [rsp + 4]\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [rsp]\n" : "    mov %s, dword ptr [rsp]\n", amd64_dword_reg_name_from_any (reg));
+        fprintf (state->ofp, "    add rsp, 8\n");
+    
+    } else {
+    
+        fprintf (state->ofp, "    subq $8, %%rsp\n");
+        fprintf (state->ofp, "    fnstcw 4(%%rsp)\n");
+        fprintf (state->ofp, "    movw 4(%%rsp), %%ax\n");
+        fprintf (state->ofp, "    orb $12, %%ah\n");
+        fprintf (state->ofp, "    movw %%ax, 6(%%rsp)\n");
+        fprintf (state->ofp, "    fldcw 6(%%rsp)\n");
+        fprintf (state->ofp, "    fistpl (%%rsp)\n");
+        fprintf (state->ofp, "    fldcw 4(%%rsp)\n");
+        fprintf (state->ofp, "    movl (%%rsp), %%%s\n", amd64_dword_reg_name_from_any (reg));
+        fprintf (state->ofp, "    addq $8, %%rsp\n");
+    
+    }
+
+}
+
+static void emit_floating_stack_to_int_pair_now (const char *lo, const char *hi) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    sub rsp, 12\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fnstcw word [rsp + 8]\n" : "    fnstcw word ptr [rsp + 8]\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov ax, word [rsp + 8]\n" : "    mov ax, word ptr [rsp + 8]\n");
+        fprintf (state->ofp, "    or ah, 12\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov word [rsp + 10], ax\n" : "    mov word ptr [rsp + 10], ax\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fldcw word [rsp + 10]\n" : "    fldcw word ptr [rsp + 10]\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fistp qword [rsp]\n" : "    fistp qword ptr [rsp]\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fldcw word [rsp + 8]\n" : "    fldcw word ptr [rsp + 8]\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [rsp]\n" : "    mov %s, dword ptr [rsp]\n", amd64_dword_reg_name_from_any (lo));
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [rsp + 4]\n" : "    mov %s, dword ptr [rsp + 4]\n", amd64_dword_reg_name_from_any (hi));
+        fprintf (state->ofp, "    add rsp, 12\n");
+    
+    } else {
+    
+        fprintf (state->ofp, "    subq $12, %%rsp\n");
+        fprintf (state->ofp, "    fnstcw 8(%%rsp)\n");
+        fprintf (state->ofp, "    movw 8(%%rsp), %%ax\n");
+        fprintf (state->ofp, "    orb $12, %%ah\n");
+        fprintf (state->ofp, "    movw %%ax, 10(%%rsp)\n");
+        fprintf (state->ofp, "    fldcw 10(%%rsp)\n");
+        fprintf (state->ofp, "    fistpll (%%rsp)\n");
+        fprintf (state->ofp, "    fldcw 8(%%rsp)\n");
+        fprintf (state->ofp, "    movl (%%rsp), %%%s\n", amd64_dword_reg_name_from_any (lo));
+        fprintf (state->ofp, "    movl 4(%%rsp), %%%s\n", amd64_dword_reg_name_from_any (hi));
+        fprintf (state->ofp, "    addq $12, %%rsp\n");
+    
+    }
+
+}
+
+static void emit_integer_pair_to_floating_stack_now (const char *lo, const char *hi, int size) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if ((size & 0x1f) == (DATA_LLONG & 0x1f)) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, "    sub rsp, 8\n");
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov dword [rsp], %s\n" : "    mov dword ptr [rsp], %s\n", amd64_dword_reg_name_from_any (lo));
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov dword [rsp + 4], %s\n" : "    mov dword ptr [rsp + 4], %s\n", amd64_dword_reg_name_from_any (hi));
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fild qword [rsp]\n" : "    fild qword ptr [rsp]\n");
+            fprintf (state->ofp, "    add rsp, 8\n");
+        
+        } else {
+        
+            fprintf (state->ofp, "    subq $8, %%rsp\n");
+            fprintf (state->ofp, "    movl %%%s, (%%rsp)\n", amd64_dword_reg_name_from_any (lo));
+            fprintf (state->ofp, "    movl %%%s, 4(%%rsp)\n", amd64_dword_reg_name_from_any (hi));
+            fprintf (state->ofp, "    fildll (%%rsp)\n");
+            fprintf (state->ofp, "    addq $8, %%rsp\n");
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    sub rsp, 8\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov dword [rsp], %s\n" : "    mov dword ptr [rsp], %s\n", amd64_dword_reg_name_from_any (lo));
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fild dword [rsp]\n" : "    fild dword ptr [rsp]\n");
+        fprintf (state->ofp, "    add rsp, 8\n");
+    
+    } else {
+    
+        fprintf (state->ofp, "    subq $8, %%rsp\n");
+        fprintf (state->ofp, "    movl %%%s, (%%rsp)\n", amd64_dword_reg_name_from_any (lo));
+        fprintf (state->ofp, "    fildl (%%rsp)\n");
+        fprintf (state->ofp, "    addq $8, %%rsp\n");
+    
+    }
+
+}
+
+static void emit_load_assignment_rhs_expression_to_reg (const char *reg) {
+
+    int false_label;
+    int true_label;
+    int end_label;
+    
+    if (rhs_current_operand_is_floating_now ()) {
+    
+        emit_load_floating_rhs_expression_now (DATA_DOUBLE & 0x1f);
+        
+        /*
+         * Floating comparisons leave their boolean result in rax.
+         * Do not run that through fistp: emit_floating_compare_to_rax_now()
+         * has already consumed both x87 operands with fcompp, so the x87
+         * stack no longer contains a value to convert.
+         */
+        if (floating_rhs_result_in_eax_bool) {
+        
+            if (state->ofp && strcmp (reg, "rax") != 0) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    mov %s, rax\n", reg);
+                } else {
+                    fprintf (state->ofp, "    movq %%rax, %%%s\n", reg);
+                }
+            
+            }
+            
+            floating_rhs_result_in_eax_bool = 0;
+            return;
+        
+        }
+        
+        emit_floating_stack_to_int_reg_now (reg);
+        return;
+    
+    }
+    
+    emit_load_assignment_compare_expression_to_reg (reg);
+    
+    for (;;) {
+    
+        if (assignment32_stop_before_condition_operator && is_assignment32_condition_stop_operator (tok.kind)) {
+            break;
+        }
+        
+        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);
+            emit_mov_imm_to_reg_now (reg, 1);
+            emit_statement_jump (end_label);
+            emit_statement_label (false_label);
+            emit_mov_imm_to_reg_now (reg, 0);
+            emit_statement_label (end_label);
+            
+            continue;
+        
+        }
+        
+        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);
+            emit_mov_imm_to_reg_now (reg, 0);
+            emit_statement_jump (end_label);
+            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) {
+    
+        false_label = anon_label++;
+        end_label = anon_label++;
+        
+        get_token ();
+        
+        if (state->ofp) {
+        
+            if (strcmp (reg, "rax") != 0) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    mov rax, %s\n", reg);
+                } else {
+                    fprintf (state->ofp, "    movq %%%s, %%rax\n", reg);
+                }
+            
+            }
+            
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                fprintf (state->ofp, "    test rax, rax\n");
+                
+                if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+                    fprintf (state->ofp, "    jz L%d\n", false_label);
+                } else {
+                    fprintf (state->ofp, "    jz .L%d\n", false_label);
+                }
+            
+            } else {
+            
+                fprintf (state->ofp, "    testq %%rax, %%rax\n");
+                fprintf (state->ofp, "    jz .L%d\n", false_label);
+            
+            }
+        
+        }
+        
+        emit_load_assignment_rhs_expression_to_reg (reg);
+        expect (TOK_COLON, ":");
+        emit_statement_jump (end_label);
+        emit_statement_label (false_label);
+        emit_load_assignment_rhs_expression_to_reg (reg);
+        emit_statement_label (end_label);
+    
+    }
+
+}
+
+static void emit_statement_cmp64_to_rax (enum token_kind op, int is_unsigned);
+
+static int is_assignment64_condition_stop_operator (enum token_kind k) {
+
+    return  k == TOK_LESS || k == TOK_LTEQ || k == TOK_GREATER ||
+                k == TOK_GTEQ || k == TOK_EQEQ || k == TOK_NOTEQ ||
+                    k == TOK_LOGAND || k == TOK_LOGOR;
+
+}
+
+static int is_assignment64_binary_operator (enum token_kind k) {
+
+    return  is_arithmetic_binary_operator (k) ||
+                k == TOK_LESS || k == TOK_LTEQ || k == TOK_GREATER ||
+                    k == TOK_GTEQ || k == TOK_EQEQ || k == TOK_NOTEQ ||
+                        k == TOK_LOGAND || k == TOK_LOGOR;
+
+}
+
+static void emit_assignment64_bool_result_to_pair_now (const char *lo, const char *hi) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (strcmp (lo, "rax") != 0) {
+            fprintf (state->ofp, "    mov %s, rax\n", lo);
+        }
+        
+        fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
+    
+    } else {
+    
+        if (strcmp (lo, "rax") != 0) {
+            fprintf (state->ofp, "    movq %%rax, %%%s\n", lo);
+        }
+        
+        fprintf (state->ofp, "    xorq %%%s, %%%s\n", hi, hi);
+    
+    }
+
+}
+
+static void emit_assignment64_logical_op_to_pair_now (enum token_kind op, const char *lo, const char *hi) {
+
+    int true_label;
+    int false_label;
+    int end_label;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    true_label = anon_label++;
+    false_label = anon_label++;
+    end_label = anon_label++;
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    test rdx, rdx\n");
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), op == TOK_LOGOR ? true_label : end_label);
+        fprintf (state->ofp, "    test rax, rax\n");
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), op == TOK_LOGOR ? true_label : end_label);
+        
+        if (op == TOK_LOGAND) {
+        
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jmp L%d\n" : "    jmp .L%d\n"), false_label);
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), end_label);
+            fprintf (state->ofp, "    test rcx, rcx\n");
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), true_label);
+            fprintf (state->ofp, "    test rbx, rbx\n");
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), true_label);
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), false_label);
+            fprintf (state->ofp, "    xor rax, rax\n");
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jmp L%d\n" : "    jmp .L%d\n"), end_label + 1);
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), true_label);
+            fprintf (state->ofp, "    mov eax, 1\n");
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), end_label + 1);
+        
+        } else {
+        
+            fprintf (state->ofp, "    test rcx, rcx\n");
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), true_label);
+            fprintf (state->ofp, "    test rbx, rbx\n");
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), true_label);
+            fprintf (state->ofp, "    xor rax, rax\n");
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jmp L%d\n" : "    jmp .L%d\n"), end_label);
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), true_label);
+            fprintf (state->ofp, "    mov eax, 1\n");
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), end_label);
+        
+        }
+    
+    } else {
+    
+        fprintf (state->ofp, "    testq %%rdx, %%rdx\n");
+        fprintf (state->ofp, op == TOK_LOGOR ? "    jnz .L%d\n" : "    jnz .L%d\n", op == TOK_LOGOR ? true_label : end_label);
+        fprintf (state->ofp, "    testq %%rax, %%rax\n");
+        fprintf (state->ofp, op == TOK_LOGOR ? "    jnz .L%d\n" : "    jnz .L%d\n", op == TOK_LOGOR ? true_label : end_label);
+        
+        if (op == TOK_LOGAND) {
+        
+            fprintf (state->ofp, "    jmp .L%d\n", false_label);
+            fprintf (state->ofp, ".L%d:\n", end_label);
+            fprintf (state->ofp, "    testq %%rcx, %%rcx\n");
+            fprintf (state->ofp, "    jnz .L%d\n", true_label);
+            fprintf (state->ofp, "    testq %%rbx, %%rbx\n");
+            fprintf (state->ofp, "    jnz .L%d\n", true_label);
+            fprintf (state->ofp, ".L%d:\n", false_label);
+            fprintf (state->ofp, "    xorq %%rax, %%rax\n");
+            fprintf (state->ofp, "    jmp .L%d\n", end_label + 1);
+            fprintf (state->ofp, ".L%d:\n", true_label);
+            fprintf (state->ofp, "    movl $1, %%eax\n");
+            fprintf (state->ofp, ".L%d:\n", end_label + 1);
+        
+        } else {
+        
+            fprintf (state->ofp, "    testq %%rcx, %%rcx\n");
+            fprintf (state->ofp, "    jnz .L%d\n", true_label);
+            fprintf (state->ofp, "    testq %%rbx, %%rbx\n");
+            fprintf (state->ofp, "    jnz .L%d\n", true_label);
+            fprintf (state->ofp, "    xorq %%rax, %%rax\n");
+            fprintf (state->ofp, "    jmp .L%d\n", end_label);
+            fprintf (state->ofp, ".L%d:\n", true_label);
+            fprintf (state->ofp, "    movl $1, %%eax\n");
+            fprintf (state->ofp, ".L%d:\n", end_label);
+        
+        }
+    
+    }
+    
+    anon_label++;
+    emit_assignment64_bool_result_to_pair_now (lo, hi);
+
+}
+
+static void emit_assignment64_compare_op_to_pair_now (enum token_kind op, const char *lo, const char *hi, int is_unsigned) {
+
+    emit_statement_cmp64_to_rax (op, is_unsigned);
+    emit_assignment64_bool_result_to_pair_now (lo, hi);
+
+}
+
+static void emit_load_assignment_rhs_expression_to_pair (const char *lo, const char *hi, int is_unsigned) {
+
+    enum token_kind op;
+    
+    int result_pair_is_rax_rdx = (strcmp (lo, "rax") == 0 && strcmp (hi, "rdx") == 0);
+    int current_pair_is_rax_rdx = result_pair_is_rax_rdx;
+    
+    if (current_integer_expr_is_foldable_now ()) {
+    
+        int64_s v = const64_from_current_foldable_expr ();
+        emit_load_const64_to_pair_now (lo, hi, v);
+        
+        return;
+    
+    }
+    
+    emit_load_assignment_rhs_to_pair (lo, hi);
+    
+    while (is_assignment64_binary_operator (tok.kind) && !(assignment64_stop_before_condition_operator && is_assignment64_condition_stop_operator (tok.kind))) {
+    
+        op = tok.kind;
+        get_token ();
+        
+        if (!current_pair_is_rax_rdx) {
+        
+            emit_mov_reg_to_reg_now ("rax", lo);
+            emit_mov_reg_to_reg_now ("rdx", hi);
+            
+            current_pair_is_rax_rdx = 1;
+        
+        }
+        
+        emit_preserve_assignment64_regs (op);
+        
+        /*
+         * The right operand of a 64-bit shift is a plain integer shift
+         * count, not a 64-bit value.  Loading it through the 64-bit primary
+         * path loses precedence for cases such as:
+         *
+         *     ((address_type)1) << (CHAR_BIT * rel->howto->size)
+         *
+         * Worse, the RHS loader uses EAX internally for nested expressions;
+         * preserve the 64-bit LHS in EDX:EAX while the count is evaluated
+         * into EBX.
+         */
+        if (op == TOK_LSH || op == TOK_RSH || op == TOK_LSHEQ || op == TOK_RSHEQ) {
+        
+            emit_push_reg_now ("rax");
+            emit_push_reg_now ("rdx");
+            
+            emit_load_assignment_binary_expression_to_reg ("rbx");
+            
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    xor rcx, rcx\n");
+            } else {
+                fprintf (state->ofp, "    xorq %%rcx, %%rcx\n");
+            }
+            
+            emit_pop_reg_now ("rdx");
+            emit_pop_reg_now ("rax");
+        
+        } else {
+        
+            /*
+             * The generic 64-bit RHS loader uses EAX:EDX as scratch even
+             * when asked to leave the final value in EBX:ECX.  Preserve the
+             * left operand around RHS evaluation; otherwise expressions such
+             * as:
+             *
+             *     result &= (((address_type)1) << n) - 1
+             *
+             * end up applying the operator to the RHS twice, because the
+             * computed mask clobbers the original result in EAX:EDX.
+             */
+            emit_push_reg_now ("rax");
+            emit_push_reg_now ("rdx");
+            
+            emit_load_assignment_rhs_to_pair ("rbx", "rcx");
+            
+            emit_pop_reg_now ("rdx");
+            emit_pop_reg_now ("rax");
+        
+        }
+        
+        if (op == TOK_LOGAND || op == TOK_LOGOR) {
+        
+            emit_assignment64_logical_op_to_pair_now (op, lo, hi);
+            current_pair_is_rax_rdx = result_pair_is_rax_rdx;
+        
+        } else if (is_value_compare_operator (op)) {
+        
+            emit_assignment64_compare_op_to_pair_now (op, lo, hi, is_unsigned);
+            current_pair_is_rax_rdx = result_pair_is_rax_rdx;
+        
+        } else {
+        
+            emit_assignment_binary_op64 (op, is_unsigned);
+            current_pair_is_rax_rdx = 1;
+        
+        }
+        
+        emit_restore_assignment64_regs (op);
+    
+    }
+    
+    if (current_pair_is_rax_rdx && !result_pair_is_rax_rdx) {
+    
+        emit_mov_reg_to_reg_now (lo, "rax");
+        emit_mov_reg_to_reg_now (hi, "rdx");
+        
+        current_pair_is_rax_rdx = 0;
+    
+    }
+    
+    if (tok.kind == TOK_QMARK) {
+    
+        int false_label = anon_label++;
+        int end_label = anon_label++;
+        
+        get_token ();
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                fprintf (state->ofp, "    test %s, %s\n", hi, hi);
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), false_label + 2);
+                fprintf (state->ofp, "    test %s, %s\n", lo, lo);
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jz L%d\n" : "    jz .L%d\n"), false_label);
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), false_label + 2);
+            
+            } else {
+            
+                fprintf (state->ofp, "    testq %%%s, %%%s\n", hi, hi);
+                fprintf (state->ofp, "    jnz .L%d\n", false_label + 2);
+                fprintf (state->ofp, "    testq %%%s, %%%s\n", lo, lo);
+                fprintf (state->ofp, "    jz .L%d\n", false_label);
+                fprintf (state->ofp, ".L%d:\n", false_label + 2);
+            
+            }
+        
+        }
+        
+        anon_label++;
+        
+        emit_load_assignment_rhs_expression_to_pair (lo, hi, is_unsigned);
+        expect (TOK_COLON, ":");
+        
+        emit_statement_jump (end_label);
+        emit_statement_label (false_label);
+        emit_load_assignment_rhs_expression_to_pair (lo, hi, is_unsigned);
+        emit_statement_label (end_label);
+    
+    }
+
+}
+
+static void emit_incdec_integral_symbol_now (struct local_symbol *sym, const char *name, int size, enum token_kind op) {
+
+    char memref[64];
+    char nasm_memref[256];
+    
+    const char *symbol;
+    const char *mnemonic;
+    
+    int qword;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    size &= 0x1f;
+    qword = (size == (DATA_LLONG & 0x1f) || size == (DATA_PTR & 0x1f));
+    
+    if (size != (DATA_CHAR & 0x1f) &&
+        size != (DATA_SHORT & 0x1f) &&
+        size != (DATA_INT & 0x1f) &&
+        size != (DATA_LONG & 0x1f) &&
+        size != (DATA_LLONG & 0x1f) &&
+        size != (DATA_PTR & 0x1f)) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        mnemonic = op == TOK_INCR ? "add" : "sub";
+        
+        if (sym && !sym->is_static) {
+        
+            format_intel_rbp_offset (memref, sizeof (memref), sym->offset);
+            symbol = memref;
+        
+        } else if (sym && sym->static_label) {
+            symbol = asm_global_symbol_name (sym->static_label);
+        } else {
+            symbol = asm_global_symbol_name (name);
+        }
+        
+        if (state->syntax & ASM_SYNTAX_NASM) {
+            symbol = format_nasm_memory_operand (nasm_memref, sizeof (nasm_memref), symbol);
+        }
+        
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s byte %s, 1\n" : "    %s byte ptr %s, 1\n"), mnemonic, symbol);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s word %s, 1\n" : "    %s word ptr %s, 1\n"), mnemonic, symbol);
+        } else if (qword) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s qword %s, 1\n" : "    %s qword ptr %s, 1\n"), mnemonic, symbol);
+        } else {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s dword %s, 1\n" : "    %s dword ptr %s, 1\n"), mnemonic, symbol);
+        }
+    
+    } else {
+    
+        if (sym && !sym->is_static) {
+        
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, op == TOK_INCR ? "    incb %ld(%%rbp)\n" : "    decb %ld(%%rbp)\n", sym->offset);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, op == TOK_INCR ? "    incw %ld(%%rbp)\n" : "    decw %ld(%%rbp)\n", sym->offset);
+            } else if (qword) {
+                fprintf (state->ofp, op == TOK_INCR ? "    incq %ld(%%rbp)\n" : "    decq %ld(%%rbp)\n", sym->offset);
+            } else {
+                fprintf (state->ofp, op == TOK_INCR ? "    incl %ld(%%rbp)\n" : "    decl %ld(%%rbp)\n", sym->offset);
+            }
+        
+        } else {
+        
+            symbol = asm_global_symbol_name ((sym && sym->static_label) ? sym->static_label : name);
+            
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, op == TOK_INCR ? "    incb %s\n" : "    decb %s\n", symbol);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, op == TOK_INCR ? "    incw %s\n" : "    decw %s\n", symbol);
+            } else if (qword) {
+                fprintf (state->ofp, op == TOK_INCR ? "    incq %s\n" : "    decq %s\n", symbol);
+            } else {
+                fprintf (state->ofp, op == TOK_INCR ? "    incl %s\n" : "    decl %s\n", symbol);
+            }
+        
+        }
+    
+    }
+
+}
+
+static void emit_incdec_pointer_symbol_now (struct local_symbol *sym, const char *name, enum token_kind op, int step) {
+
+    const char *mnemonic = op == TOK_INCR ? "add" : "sub";
+    const char *symbol;
+    
+    char memref[64];
+    char nasm_memref[128];
+    
+    if (step <= 0) {
+        step = 1;
+    }
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (step == 1) {
+    
+        emit_incdec_integral_symbol_now (sym, name, DATA_PTR, op);
+        return;
+    
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (sym && !sym->is_static) {
+        
+            format_intel_rbp_offset (memref, sizeof (memref), sym->offset);
+            symbol = memref;
+        
+        } else if (sym && sym->static_label) {
+            symbol = asm_global_symbol_name (sym->static_label);
+        } else {
+            symbol = asm_global_symbol_name (name);
+        }
+        
+        if (state->syntax & ASM_SYNTAX_NASM) {
+        
+            symbol = format_nasm_memory_operand (nasm_memref, sizeof (nasm_memref), symbol);
+            fprintf (state->ofp, "    %s qword %s, %d\n", mnemonic, symbol, step);
+        
+        } else {
+            fprintf (state->ofp, "    %s qword ptr %s, %d\n", mnemonic, symbol, step);
+        }
+    
+    } else {
+    
+        if (sym && !sym->is_static) {
+            fprintf (state->ofp, "    %sq $%d, %ld(%%rbp)\n", mnemonic, step, sym->offset);
+        } else {
+        
+            symbol = asm_global_symbol_name ((sym && sym->static_label) ? sym->static_label : name);
+            fprintf (state->ofp, "    %sq $%d, %s(%%rip)\n", mnemonic, step, symbol);
+        
+        }
+    
+    }
+
+}
+
+static void emit_incdec_symbol_now (struct local_symbol *sym, const char *name, enum token_kind op, int line, const char *start, const char *caret) {
+
+    int global_index;
+    int is_floating;
+    int pointer_depth;
+    int pointed_size;
+    
+    int size;
+    
+    if (!sym) {
+    
+        global_index = find_global_symbol (name);
+        
+        if (global_index < 0) {
+        
+            report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "unknown symbol '%s'", name);
+            return;
+        
+        }
+        
+        if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION) {
+        
+            report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "function '%s' cannot be incremented or decremented", name);
+            return;
+        
+        }
+    
+    }
+    
+    size = sym ? sym->size : get_global_symbol_size (name);
+    is_floating = sym ? sym->is_floating : get_global_symbol_floating (name);
+    
+    pointer_depth = sym ? sym->pointer_depth : get_global_symbol_pointer_depth (name);
+    pointed_size = sym ? sym->pointed_size : get_global_symbol_pointed_size (name);
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (is_floating) {
+    
+        emit_load_floating_symbol_now (sym, name, size);
+        fprintf (state->ofp, "    fld1\n");
+        
+        if (op == TOK_INCR) {
+            emit_floating_binary_now (TOK_PLUS);
+        } else {
+            emit_floating_binary_now (TOK_MINUS);
+        }
+        
+        emit_store_floating_symbol_now (sym, name, size);
+        return;
+    
+    }
+    
+    if (pointer_depth > 0) {
+    
+        emit_incdec_pointer_symbol_now (sym, name, op, pointed_size);
+        return;
+    
+    }
+    
+    emit_incdec_integral_symbol_now (sym, name, size, op);
+
+}
+
+static int parse_prefix_incdec_statement (void) {
+
+    enum token_kind op;
+    char *name;
+    
+    const char *name_start, *name_caret;
+    unsigned long name_line;
+    
+    struct local_symbol *sym;
+    
+    int deref_size = DATA_INT & 0x1f;
+    int indirect = 0;
+    
+    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+    
+        if (emit_load_prefix_incdec_member_to_reg_now ("rax")) {
+        
+            expect_semi_or_recover ();
+            return 1;
+        
+        }
+    
+    }
+    
+    if (emit_load_prefix_incdec_parenthesized_deref_to_reg_now ("rax")) {
+    
+        expect_semi_or_recover ();
+        return 1;
+    
+    }
+    
+    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
+        return 0;
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    if (tok.kind == TOK_STAR) {
+    
+        indirect = 1;
+        get_token ();
+    
+    }
+    
+    if (tok.kind != TOK_IDENT) {
+    
+        if (indirect) {
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after *");
+        } else {
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after %s", op == TOK_INCR ? "++" : "--");
+        }
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    get_token ();
+
+    sym = find_local_symbol (name);
+    
+    if (indirect) {
+    
+        if (sym) {
+        
+            if (sym->pointer_depth > 1) {
+                deref_size = DATA_PTR & 0x1f;
+            } else if (sym->pointer_depth == 1 && sym->pointed_size > 0) {
+                deref_size = sym->pointed_size & 0x1f;
+            }
+            
+            if (sym->is_static && sym->static_label) {
+                emit_load_global_to_reg ("rdx", sym->static_label, DATA_PTR);
+            } else {
+                emit_load_local_to_reg ("rdx", sym->offset, DATA_PTR);
+            }
+        
+        } else if (find_global_symbol (name) >= 0) {
+        
+            if (get_global_symbol_pointer_depth (name) > 1) {
+                deref_size = DATA_PTR & 0x1f;
+            } else if (get_global_symbol_pointer_depth (name) == 1 && get_global_symbol_pointed_size (name) > 0) {
+                deref_size = get_global_symbol_pointed_size (name) & 0x1f;
+            }
+            
+            emit_load_global_to_reg ("rdx", name, DATA_PTR);
+        
+        } else {
+        
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        emit_push_reg_now ("rdx");
+        emit_load_member_from_addr_reg_now ("rax", "rdx", 0, deref_size);
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, op == TOK_INCR ? "    add rax, 1\n" : "    sub rax, 1\n");
+            } else {
+                fprintf (state->ofp, op == TOK_INCR ? "    addq $1, %%rax\n" : "    subq $1, %%rax\n");
+            }
+        
+        }
+        
+        emit_pop_reg_now ("rdx");
+        emit_store_reg_to_deref_reg_now ("rdx", "rax", deref_size);
+        
+        expect_semi_or_recover ();
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    emit_incdec_symbol_now (sym, name, op, name_line, name_start, name_caret);
+    
+    expect_semi_or_recover ();
+    free (name);
+    
+    return 1;
+
+}
+
+static int parse_parenthesized_pointer_member_indirect_assignment_statement (void) {
+
+    char *name = 0;
+    char *member = 0;
+    
+    struct local_symbol *sym;
+    
+    int global_index;
+    int parens = 0;
+    int offset = 0;
+    int member_size = DATA_PTR & 0x1f;
+    int member_elem_size = DATA_INT & 0x1f;
+    int member_pointer_depth = 0;
+    int deref_size = DATA_INT & 0x1f;
+    int step = 1;
+    
+    enum token_kind postfix_op = TOK_EOF;
+    enum token_kind op;
+    
+    const char *name_start;
+    const char *name_caret;
+    const char *member_start;
+    const char *member_caret;
+    
+    unsigned long name_line;
+    unsigned long member_line;
+    
+    if (tok.kind != TOK_LPAREN) {
+        return 0;
+    }
+    
+    while (tok.kind == TOK_LPAREN) {
+        ++parens;
+        get_token ();
+    }
+    
+    if (tok.kind != TOK_STAR) {
+    
+        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+        
+            enum token_kind prefix_op = tok.kind;
+            char *prefix_name;
+            
+            const char *prefix_start;
+            const char *prefix_caret;
+            
+            unsigned long prefix_line;
+            
+            struct local_symbol *prefix_sym;
+            
+            int prefix_global_index;
+            int prefix_deref_size = DATA_INT & 0x1f;
+            
+            enum token_kind prefix_assign_op;
+            get_token ();
+            
+            if (tok.kind != TOK_IDENT) {
+            
+                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                
+                expect_semi_or_recover ();
+                return 1;
+            
+            }
+            
+            prefix_name = xstrdup (tok.ident);
+            prefix_start = tok.start;
+            prefix_caret = tok.caret;
+            prefix_line = get_line_number ();
+            
+            get_token ();
+            
+            while (tok.kind == TOK_RPAREN && parens > 0) {
+            
+                --parens;
+                get_token ();
+            
+            }
+            
+            if (parens != 0 || !is_assignment_operator (tok.kind)) {
+            
+                free (prefix_name);
+                
+                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                expect_semi_or_recover ();
+                
+                return 1;
+            
+            }
+            
+            prefix_assign_op = tok.kind;
+            get_token ();
+            
+            prefix_sym = find_local_symbol (prefix_name);
+            prefix_global_index = find_global_symbol (prefix_name);
+            
+            if (!prefix_sym && prefix_global_index < 0) {
+            
+                report_line_at (get_filename (), prefix_line, REPORT_ERROR, prefix_start, prefix_caret, "unknown symbol '%s'", prefix_name);
+                
+                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                expect_semi_or_recover ();
+                
+                free (prefix_name);
+                return 1;
+            
+            }
+            
+            if (prefix_sym) {
+            
+                if (prefix_sym->pointer_depth > 1) {
+                    prefix_deref_size = DATA_PTR & 0x1f;
+                } else if (prefix_sym->pointer_depth == 1 && prefix_sym->pointed_size > 0) {
+                    prefix_deref_size = prefix_sym->pointed_size & 0x1f;
+                }
+            
+            } else {
+            
+                if (get_global_symbol_pointer_depth (prefix_name) > 1) {
+                    prefix_deref_size = DATA_PTR & 0x1f;
+                } else if (get_global_symbol_pointer_depth (prefix_name) == 1 && get_global_symbol_pointed_size (prefix_name) > 0) {
+                    prefix_deref_size = get_global_symbol_pointed_size (prefix_name) & 0x1f;
+                }
+            
+            }
+            
+            if (prefix_deref_size == 0) {
+                prefix_deref_size = DATA_INT & 0x1f;
+            }
+            
+            emit_incdec_symbol_now (prefix_sym, prefix_name, prefix_op, prefix_line, prefix_start, prefix_caret);
+            
+            if (state->ofp) {
+            
+                if (prefix_sym) {
+                
+                    if (prefix_sym->is_static && prefix_sym->static_label) {
+                        emit_load_global_to_reg ("rcx", prefix_sym->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg ("rcx", prefix_sym->offset, DATA_PTR);
+                    }
+                
+                } else {
+                    emit_load_global_to_reg ("rcx", prefix_name, DATA_PTR);
+                }
+                
+                emit_push_reg_now ("rcx");
+                
+                if (prefix_assign_op == TOK_ASSIGN) {
+                    emit_load_assignment_rhs_expression_to_reg ("rax");
+                } else {
+                
+                    emit_pop_reg_now ("rdx");
+                    emit_push_reg_now ("rdx");
+                    
+                    emit_load_member_from_addr_reg_now ("rax", "rdx", 0, prefix_deref_size);
+                    emit_push_reg_now ("rax");
+                    
+                    emit_load_assignment_rhs_expression_to_reg ("rdx");
+                    emit_pop_reg_now ("rax");
+                    
+                    emit_assignment_binary_op (prefix_assign_op, 0);
+                
+                }
+                
+                emit_pop_reg_now ("rdx");
+                emit_store_reg_to_deref_reg_now ("rdx", "rax", prefix_deref_size);
+            
+            } else {
+                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            }
+            
+            expect_semi_or_recover ();
+            
+            free (prefix_name);
+            return 1;
+        
+        }
+        
+        if (tok.kind == TOK_IDENT) {
+        
+            name = xstrdup (tok.ident);
+            name_start = tok.start;
+            name_caret = tok.caret;
+            name_line = get_line_number ();
+            
+            get_token ();
+            
+            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+            
+                postfix_op = tok.kind;
+                get_token ();
+            
+            }
+            
+            while (tok.kind == TOK_RPAREN && parens > 0) {
+            
+                --parens;
+                get_token ();
+            
+            }
+            
+            if (parens != 0 || !is_assignment_operator (tok.kind)) {
+            
+                free (name);
+                
+                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                expect_semi_or_recover ();
+                
+                return 1;
+            
+            }
+            
+            op = tok.kind;
+            get_token ();
+            
+            sym = find_local_symbol (name);
+            global_index = find_global_symbol (name);
+            
+            if (!sym && global_index < 0) {
+            
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+                
+                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                expect_semi_or_recover ();
+                
+                free (name);
+                return 1;
+            
+            }
+            
+            if (sym) {
+            
+                if (sym->pointer_depth > 1) {
+                
+                    deref_size = DATA_PTR & 0x1f;
+                    step = DATA_PTR & 0x1f;
+                
+                } else if (sym->pointer_depth == 1) {
+                
+                    deref_size = sym->pointed_size & 0x1f;
+                    step = sym->pointed_size > 0 ? sym->pointed_size : 1;
+                
+                }
+            
+            } else {
+            
+                if (get_global_symbol_pointer_depth (name) > 1) {
+                
+                    deref_size = DATA_PTR & 0x1f;
+                    step = DATA_PTR & 0x1f;
+                
+                } else if (get_global_symbol_pointer_depth (name) == 1) {
+                
+                    deref_size = get_global_symbol_pointed_size (name) & 0x1f;
+                    step = get_global_symbol_pointed_size (name) > 0 ? get_global_symbol_pointed_size (name) : 1;
+                
+                }
+            
+            }
+            
+            if (deref_size == 0) {
+                deref_size = DATA_INT & 0x1f;
+            }
+            
+            if (state->ofp) {
+            
+                if (sym) {
+                
+                    if (sym->is_static && sym->static_label) {
+                        emit_load_global_to_reg ("rcx", sym->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg ("rcx", sym->offset, DATA_PTR);
+                    }
+                
+                } else {
+                    emit_load_global_to_reg ("rcx", name, DATA_PTR);
+                }
+                
+                emit_push_reg_now ("rcx");
+                
+                if (postfix_op == TOK_INCR || postfix_op == TOK_DECR) {
+                
+                    if (sym) {
+                    
+                        if (sym->is_static && sym->static_label) {
+                        
+                            if (state->syntax & ASM_SYNTAX_INTEL) {
+                                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s qword [%s], %d\n" : "    %s qword ptr [%s], %d\n"), postfix_op == TOK_INCR ? "add" : "sub", asm_global_symbol_name (sym->static_label), step);
+                            } else {
+                                fprintf (state->ofp, "    %sq $%d, %s(%%rip)\n", postfix_op == TOK_INCR ? "add" : "sub", step, asm_global_symbol_name (sym->static_label));
+                            }
+                        
+                        } else {
+                        
+                            if (state->syntax & ASM_SYNTAX_INTEL) {
+                            
+                                char memref[64];
+                                char nasm_memref[128];
+                                const char *out_memref;
+                                
+                                format_intel_rbp_offset (memref, sizeof (memref), sym->offset);
+                                out_memref = memref;
+                                
+                                if (state->syntax & ASM_SYNTAX_NASM) {
+                                    out_memref = format_nasm_memory_operand (nasm_memref, sizeof (nasm_memref), memref);
+                                }
+                                
+                                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s qword %s, %d\n" : "    %s qword ptr %s, %d\n"), postfix_op == TOK_INCR ? "add" : "sub", out_memref, step);
+                                
+                            } else {
+                                fprintf (state->ofp, "    %sq $%d, %ld(%%rbp)\n", postfix_op == TOK_INCR ? "add" : "sub", step, sym->offset);
+                            }
+                        
+                        }
+                    
+                    } else {
+                    
+                        if (state->syntax & ASM_SYNTAX_INTEL) {
+                            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s qword [%s], %d\n" : "    %s qword ptr [%s], %d\n"), postfix_op == TOK_INCR ? "add" : "sub", asm_global_symbol_name (name), step);
+                        } else {
+                            fprintf (state->ofp, "    %sq $%d, %s(%%rip)\n", postfix_op == TOK_INCR ? "add" : "sub", step, asm_global_symbol_name (name));
+                        }
+                    
+                    }
+                
+                }
+                
+                if (op == TOK_ASSIGN) {
+                    emit_load_assignment_rhs_expression_to_reg ("rax");
+                } else {
+                
+                    emit_pop_reg_now ("rdx");
+                    emit_push_reg_now ("rdx");
+                    emit_load_member_from_addr_reg_now ("rax", "rdx", 0, deref_size);
+                    emit_push_reg_now ("rax");
+                    emit_load_assignment_rhs_expression_to_reg ("rdx");
+                    emit_pop_reg_now ("rax");
+                    emit_assignment_binary_op (op, 0);
+                
+                }
+                
+                emit_pop_reg_now ("rdx");
+                emit_store_reg_to_deref_reg_now ("rdx", "rax", deref_size);
+            
+            } else {
+                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            }
+            
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        
+        expect_semi_or_recover ();
+        return 1;
+    
+    }
+    
+    get_token ();
+    
+    while (tok.kind == TOK_LPAREN) {
+    
+        ++parens;
+        get_token ();
+    
+    }
+    
+    if (tok.kind != TOK_IDENT) {
+    
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        
+        expect_semi_or_recover ();
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    get_token ();
+    
+    if (state->ofp) {
+    
+        if (tok.kind == TOK_LPAREN) {
+            emit_call_identifier_to_reg_now (name, "rax", name_start, name_caret, name_line);
+        } else {
+        
+            sym = find_local_symbol (name);
+            global_index = find_global_symbol (name);
+            
+            if (sym) {
+            
+                if (sym->is_static && sym->static_label) {
+                    emit_load_global_to_reg ("rax", sym->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg ("rax", sym->offset, DATA_PTR);
+                }
+            
+            } else if (global_index >= 0) {
+                emit_load_global_to_reg ("rax", name, DATA_PTR);
+            } else {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            }
+        
+        }
+        
+        emit_load_deref_reg_now ("rax", DATA_PTR);
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    mov rdx, rax\n");
+        } else {
+            fprintf (state->ofp, "    movq %%rax, %%rdx\n");
+        }
+    
+    } else if (tok.kind == TOK_LPAREN) {
+        emit_call_identifier_to_reg_now (name, "rax", name_start, name_caret, name_line);
+    }
+    
+    while (tok.kind == TOK_RPAREN && parens > 0) {
+    
+        --parens;
+        get_token ();
+    
+    }
+    
+    if (tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
+    
+        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+        
+            postfix_op = tok.kind;
+            get_token ();
+            
+            sym = find_local_symbol (name);
+            global_index = find_global_symbol (name);
+            
+            if (sym) {
+            
+                if (sym->pointer_depth > 1) {
+                
+                    deref_size = DATA_PTR & 0x1f;
+                    step = DATA_PTR & 0x1f;
+                
+                } else if (sym->pointer_depth == 1) {
+                
+                    deref_size = sym->pointed_size & 0x1f;
+                    step = 1;
+                
+                }
+                
+                if (deref_size == 0) {
+                    deref_size = DATA_INT & 0x1f;
+                }
+                
+                if (sym->is_static && sym->static_label) {
+                    emit_load_global_to_reg ("rdx", sym->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg ("rdx", sym->offset, DATA_PTR);
+                }
+            
+            } else if (global_index >= 0) {
+            
+                if (get_global_symbol_pointer_depth (name) > 1) {
+                
+                    deref_size = DATA_PTR & 0x1f;
+                    step = DATA_PTR & 0x1f;
+                
+                } else if (get_global_symbol_pointer_depth (name) == 1) {
+                
+                    deref_size = get_global_symbol_pointed_size (name) & 0x1f;
+                    step = 1;
+                
+                }
+                
+                if (deref_size == 0) {
+                    deref_size = DATA_INT & 0x1f;
+                }
+                
+                emit_load_global_to_reg ("rdx", name, DATA_PTR);
+            
+            } else {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            }
+            
+            if (state->ofp) {
+            
+                emit_load_deref_reg_now ("rdx", deref_size);
+
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    %s rdx, %d\n", postfix_op == TOK_INCR ? "add" : "sub", step);
+                } else {
+                    fprintf (state->ofp, "    %sq $%d, %%rdx\n", postfix_op == TOK_INCR ? "add" : "sub", step);
+                }
+                
+                if (sym) {
+                
+                    if (sym->is_static && sym->static_label) {
+                        emit_load_global_to_reg ("rax", sym->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg ("rax", sym->offset, DATA_PTR);
+                    }
+                
+                } else if (global_index >= 0) {
+                    emit_load_global_to_reg ("rax", name, DATA_PTR);
+                }
+                
+                emit_store_reg_to_deref_reg_now ("rax", "rdx", deref_size);
+            
+            }
+            
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        free (name);
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        return 1;
+    
+    }
+    
+    get_token ();
+    
+    member_start = tok.start;
+    member_caret = tok.caret;
+    member_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT) {
+    
+        report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name");
+        free (name);
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        
+        expect_semi_or_recover ();
+        return 1;
+    
+    }
+    
+    member = xstrdup (tok.ident);
+    get_token ();
+    
+    if (!find_member_info_ex (member, &offset, &member_size, &member_elem_size, &member_pointer_depth, 0, 0)) {
+    
+        report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+        
+        free (member);
+        free (name);
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        return 1;
+    
+    }
+    
+    free (member);
+    
+    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+    
+        postfix_op = tok.kind;
+        get_token ();
+    
+    }
+    
+    if (!is_assignment_operator (tok.kind)) {
+    
+        free (name);
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        return 1;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    if (member_pointer_depth > 1) {
+        deref_size = DATA_PTR & 0x1f;
+    } else if (member_pointer_depth == 1 && member_elem_size > 0) {
+        deref_size = member_elem_size & 0x1f;
+    } else if (member_size > 0) {
+        deref_size = member_size & 0x1f;
+    }
+    
+    if (deref_size == 0) {
+        deref_size = DATA_INT & 0x1f;
+    }
+    
+    step = member_elem_size > 0 ? member_elem_size : 1;
+    
+    if (state->ofp) {
+    
+        emit_load_member_from_addr_reg_now ("rcx", "rdx", offset, DATA_PTR & 0x1f);
+        
+        if (postfix_op == TOK_INCR || postfix_op == TOK_DECR) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                if (state->syntax & ASM_SYNTAX_NASM) {
+                    fprintf (state->ofp, "    %s qword [rdx + %d], %d\n", postfix_op == TOK_INCR ? "add" : "sub", offset, step);
+                } else {
+                    fprintf (state->ofp, "    %s qword ptr [rdx + %d], %d\n", postfix_op == TOK_INCR ? "add" : "sub", offset, step);
+                }
+            
+            } else {
+                fprintf (state->ofp, "    %sq $%d, %d(%%rdx)\n", postfix_op == TOK_INCR ? "add" : "sub", step, offset);
+            }
+        
+        }
+        
+        emit_push_reg_now ("rcx");
+        
+        if (op == TOK_ASSIGN) {
+            emit_load_assignment_rhs_expression_to_reg ("rax");
+        } else {
+        
+            emit_load_member_from_addr_reg_now ("rax", "rdx", 0, deref_size);
+            emit_push_reg_now ("rax");
+            emit_load_assignment_rhs_expression_to_reg ("rdx");
+            emit_pop_reg_now ("rax");
+            emit_assignment_binary_op (op, 0);
+        
+        }
+        
+        emit_pop_reg_now ("rdx");
+        emit_store_reg_to_deref_reg_now ("rdx", "rax", deref_size);
+    
+    } else {
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+    }
+    
+    expect_semi_or_recover ();
+    
+    free (name);
+    return 1;
+
+}
+
+static int paren_text_starts_type_name_now (void) {
+
+    const char *p;
+    
+    char name[128];
+    int n = 0;
+    
+    if (tok.caret) {
+        p = tok.caret;
+    } else if (tok.start) {
+        p = tok.start;
+    } else {
+        return 0;
+    }
+    
+    if (*p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p == '(') {
+    
+        p++;
+        
+        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 == '_') && n < (int) sizeof (name) - 1) {
+        name[n++] = *p++;
+    }
+    
+    name[n] = '\0';
+    
+    if (strcmp (name, "char") == 0 || strcmp (name, "short") == 0 ||
+        strcmp (name, "int") == 0 || strcmp (name, "long") == 0 ||
+        strcmp (name, "signed") == 0 || strcmp (name, "unsigned") == 0 ||
+        strcmp (name, "void") == 0 || strcmp (name, "struct") == 0 ||
+        strcmp (name, "union") == 0 || strcmp (name, "enum") == 0) {
+        return 1;
+    }
+    
+    return find_typedef_name (name) != 0;
+
+}
+
+static int parse_cast_indirect_assignment_statement (void) {
+
+    int saved_type_size = parsed_type_size;
+    int saved_storage_class = parsed_storage_class;
+    int saved_is_aggregate = parsed_type_is_aggregate;
+    int saved_is_void = parsed_type_is_void;
+    int saved_is_unsigned = parsed_type_is_unsigned;
+    int saved_is_floating = parsed_type_is_floating;
+    int saved_has_tag = parsed_type_has_tag;
+    int saved_is_inline = parsed_type_is_inline;
+    int saved_field_count = parsed_field_count;
+    int saved_fields[MAX_AGG_FIELDS];
+    int saved_declarator_is_pointer = declarator_is_pointer;
+    int saved_declarator_pointer_depth = declarator_pointer_depth;
+    int saved_declarator_has_array = declarator_has_array;
+    int saved_declarator_has_function = declarator_has_function;
+    int saved_declarator_array_unsized = declarator_array_unsized;
+    int saved_declarator_array_dimensions = declarator_array_dimensions;
+    
+    long saved_declarator_first_array_count = declarator_first_array_count;
+    long saved_declarator_array_count = declarator_array_count;
+    
+    char *cast_name = 0;
+    int base_size;
+    int deref_size;
+    int pointer_depth;
+    int i;
+    
+    enum token_kind op;
+    int has_outer_paren = 0;
+    
+    if (tok.kind != TOK_LPAREN) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    /*
+     * Accept the common casted-dereference lvalue spelling:
+     *
+     *     *((char *)ptr + n) = v;
+     *
+     * parse_indirect_assignment_statement() enters here at the outer '(';
+     * the actual cast type begins after the inner '('.
+     */
+    if (tok.kind == TOK_LPAREN) {
+    
+        has_outer_paren = 1;
+        get_token ();
+    
+    }
+    
+    if (!is_type_start (tok.kind)) {
+        return 0;
+    }
+    
+    for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
+        saved_fields[i] = parsed_field_sizes[i];
+    }
+    
+    parse_type_spec ();
+    base_size = parsed_type_size & 0x1f;
+    
+    if (tok.kind != TOK_RPAREN) {
+        parse_declarator (&cast_name);
+    }
+    
+    pointer_depth = declarator_is_pointer ? (declarator_pointer_depth > 0 ? declarator_pointer_depth : 1) : 0;
+    deref_size = pointer_depth > 1 ? (DATA_PTR & 0x1f) : base_size;
+    
+    if (deref_size <= 0) {
+        deref_size = DATA_INT & 0x1f;
+    }
+    
+    if (cast_name) {
+        free (cast_name);
+    }
+    
+    expect (TOK_RPAREN, ")");
+    
+    parsed_type_size = saved_type_size;
+    parsed_storage_class = saved_storage_class;
+    parsed_type_is_aggregate = saved_is_aggregate;
+    parsed_type_is_void = saved_is_void;
+    parsed_type_is_unsigned = saved_is_unsigned;
+    parsed_type_is_floating = saved_is_floating;
+    parsed_type_has_tag = saved_has_tag;
+    parsed_type_is_inline = saved_is_inline;
+    
+    clear_parsed_fields ();
+    
+    for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
+        parsed_field_sizes[i] = saved_fields[i];
+    }
+    
+    parsed_field_count = saved_field_count;
+    
+    declarator_is_pointer = saved_declarator_is_pointer;
+    declarator_pointer_depth = saved_declarator_pointer_depth;
+    declarator_has_array = saved_declarator_has_array;
+    declarator_has_function = saved_declarator_has_function;
+    declarator_array_unsized = saved_declarator_array_unsized;
+    declarator_array_count = saved_declarator_array_count;
+    declarator_first_array_count = saved_declarator_first_array_count;
+    declarator_array_dimensions = saved_declarator_array_dimensions;
+    
+    if (state->ofp) {
+    
+        /*
+         * Parse the address expression inside the outer dereference without
+         * allowing the first operand parser to consume the assignment operator.
+         *
+         * For:
+         *
+         *     *(size_t *)ptr = size;
+         *
+         * emit_load_assignment_rhs_to_reg() sees the identifier "ptr" followed
+         * by '=' and treats it as an assignment expression, generating
+         * "ptr = size" instead of using ptr as the destination address.  Load a
+         * plain identifier operand directly, then let the explicit '+'/'-' loop
+         * below handle the casted pointer arithmetic case:
+         *
+         *     *((char *)ptr + *actualRead) = '\n';
+         */
+        if (tok.kind == TOK_IDENT) {
+        
+            char *addr_name = xstrdup (tok.ident);
+            
+            const char *addr_start = tok.start;
+            const char *addr_caret = tok.caret;
+            
+            unsigned long addr_line = get_line_number ();
+            
+            struct local_symbol *addr_sym;
+            int addr_global_index;
+            
+            get_token ();
+            
+            addr_sym = find_local_symbol (addr_name);
+            addr_global_index = find_global_symbol (addr_name);
+            
+            if (addr_sym) {
+            
+                if (addr_sym->is_static && addr_sym->static_label) {
+                    emit_load_global_to_reg ("rdx", addr_sym->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg ("rdx", addr_sym->offset, DATA_PTR);
+                }
+            
+            } else if (addr_global_index >= 0) {
+                emit_load_global_to_reg ("rdx", addr_name, DATA_PTR);
+            } else {
+                report_line_at (get_filename (), addr_line, REPORT_ERROR, addr_start, addr_caret, "unknown symbol '%s'", addr_name);
+            }
+            
+            free (addr_name);
+        
+        } else {
+            emit_load_assignment_rhs_to_reg ("rdx");
+        }
+        
+        while (tok.kind == TOK_PLUS || tok.kind == TOK_MINUS) {
+        
+            enum token_kind addr_op = tok.kind;
+            get_token ();
+            
+            emit_push_reg_now ("rdx");
+            emit_load_assignment_rhs_to_reg ("rax");
+            
+            if (deref_size > 1) {
+                emit_scale_reg_by_const_now ("rax", deref_size);
+            }
+            
+            emit_pop_reg_now ("rdx");
+            
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    %s rdx, rax\n", addr_op == TOK_PLUS ? "add" : "sub");
+            } else {
+                fprintf (state->ofp, "    %sq %%rax, %%rdx\n", addr_op == TOK_PLUS ? "add" : "sub");
+            }
+        
+        }
+    
+    } else {
+        skip_balanced_until (TOK_RPAREN, TOK_SEMI, TOK_EOF);
+    }
+    
+    if (has_outer_paren) {
+        expect (TOK_RPAREN, ")");
+    }
+    
+    if (!is_assignment_operator (tok.kind)) {
+    
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        
+        expect_semi_or_recover ();
+        return 1;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    if (op == TOK_ASSIGN) {
+    
+        emit_push_reg_now ("rdx");
+        emit_load_assignment_rhs_expression_to_reg ("rax");
+        emit_pop_reg_now ("rdx");
+    
+    } else {
+    
+        emit_push_reg_now ("rdx");
+        emit_load_deref_reg_now ("rax", deref_size);
+        emit_push_reg_now ("rax");
+        emit_load_assignment_rhs_expression_to_reg ("rdx");
+        emit_pop_reg_now ("rax");
+        emit_assignment_binary_op (op, 0);
+        emit_pop_reg_now ("rdx");
+    
+    }
+    
+    emit_store_reg_to_deref_reg_now ("rdx", "rax", deref_size);
+    expect_semi_or_recover ();
+    
+    return 1;
+
+}
+
+static int lparen_expression_starts_with_star_now (void) {
+
+    const char *p;
+    
+    if (tok.kind != TOK_LPAREN || !tok.caret) {
+        return 0;
+    }
+    
+    p = tok.caret + 1;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '*';
+
+}
+
+static int parse_parenthesized_indirect_assignment_statement (void) {
+
+    enum token_kind op;
+    
+    int pointer_depth;
+    int pointed_size;
+    int deref_size = DATA_INT & 0x1f;
+    
+    if (tok.kind != TOK_LPAREN) {
+        return 0;
+    }
+    
+    get_token ();
+    emit_load_assignment_rhs_expression_to_reg ("rdx");
+    
+    pointer_depth = rhs_last_pointer_depth;
+    pointed_size = rhs_last_pointed_size;
+    
+    if (pointer_depth > 1) {
+        deref_size = DATA_PTR & 0x1f;
+    } else if (pointer_depth == 1 && pointed_size > 0) {
+        deref_size = pointed_size & 0x1f;
+    }
+    
+    if (deref_size <= 0) {
+        deref_size = DATA_INT & 0x1f;
+    }
+    
+    expect (TOK_RPAREN, ")");
+    
+    if (!is_assignment_operator (tok.kind)) {
+    
+        expect_semi_or_recover ();
+        return 1;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    if (op == TOK_ASSIGN) {
+    
+        emit_push_reg_now ("rdx");
+        
+        emit_load_assignment_rhs_expression_to_reg ("rax");
+        emit_pop_reg_now ("rdx");
+    
+    } else {
+    
+        emit_push_reg_now ("rdx");
+        
+        emit_load_deref_reg_now ("rax", deref_size);
+        emit_push_reg_now ("rax");
+        
+        emit_load_assignment_rhs_expression_to_reg ("rdx");
+        emit_pop_reg_now ("rax");
+        
+        emit_assignment_binary_op (op, 0);
+        emit_pop_reg_now ("rdx");
+    
+    }
+    
+    emit_store_reg_to_deref_reg_now ("rdx", "rax", deref_size);
+    expect_semi_or_recover ();
+    
+    return 1;
+
+}
+
+static int parse_indirect_assignment_statement (void) {
+
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    struct local_symbol *lhs;
+    
+    int deref_size = DATA_INT & 0x1f;
+    int deref_is_floating = 0;
+    
+    enum token_kind op;
+    int global_index;
+    
+    if (tok.kind != TOK_STAR) {
+        return 0;
+    }
+    
+    if (emit_store_to_deref_parenthesized_deref_postfix_incdec_now ("rax")) {
+    
+        expect_semi_or_recover ();
+        return 1;
+    
+    }
+    
+    get_token ();
+    
+    if (tok.kind == TOK_STAR) {
+    
+        get_token ();
+        
+        if (tok.kind == TOK_IDENT) {
+        
+            name = xstrdup (tok.ident);
+            
+            name_start = tok.start;
+            name_caret = tok.caret;
+            
+            name_line = get_line_number ();
+            get_token ();
+            
+            if (is_assignment_operator (tok.kind)) {
+            
+                op = tok.kind;
+                get_token ();
+                
+                lhs = find_local_symbol (name);
+                global_index = find_global_symbol (name);
+                
+                if (!lhs && global_index < 0) {
+                
+                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+                    
+                    skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                    expect_semi_or_recover ();
+                    
+                    free (name);
+                    return 1;
+                
+                }
+                
+                if (lhs) {
+                
+                    if (lhs->pointer_depth > 2) {
+                        deref_size = DATA_PTR & 0x1f;
+                    } else if (lhs->pointer_depth == 2) {
+                        deref_size = lhs->pointed_size & 0x1f;
+                    }
+                
+                } else {
+                
+                    if (get_global_symbol_pointer_depth (name) > 2) {
+                        deref_size = DATA_PTR & 0x1f;
+                    } else if (get_global_symbol_pointer_depth (name) == 2) {
+                        deref_size = get_global_symbol_pointed_size (name) & 0x1f;
+                    }
+                
+                }
+                
+                if (deref_size <= 0) {
+                    deref_size = DATA_INT & 0x1f;
+                }
+                
+                if (state->ofp) {
+                
+                    if (lhs) {
+                    
+                        if (lhs->is_static && lhs->static_label) {
+                            emit_load_global_to_reg ("rcx", lhs->static_label, DATA_PTR);
+                        } else {
+                            emit_load_local_to_reg ("rcx", lhs->offset, DATA_PTR);
+                        }
+                    
+                    } else {
+                        emit_load_global_to_reg ("rcx", name, DATA_PTR);
+                    }
+                    
+                    emit_load_deref_reg_now ("rcx", DATA_PTR & 0x1f);
+                    
+                    if (op == TOK_ASSIGN) {
+                    
+                        emit_push_reg_now ("rcx");
+                        
+                        emit_load_assignment_rhs_expression_to_reg ("rax");
+                        emit_pop_reg_now ("rcx");
+                    
+                    } else {
+                    
+                        emit_push_reg_now ("rcx");
+                        
+                        emit_load_member_from_addr_reg_now ("rax", "rcx", 0, deref_size);
+                        emit_push_reg_now ("rax");
+                        
+                        emit_load_assignment_rhs_expression_to_reg ("rdx");
+                        emit_pop_reg_now ("rax");
+                        
+                        emit_assignment_binary_op (op, 0);
+                        emit_pop_reg_now ("rcx");
+                    
+                    }
+                    
+                    emit_store_reg_to_deref_reg_now ("rcx", "rax", deref_size);
+                
+                } else {
+                    skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                }
+                
+                expect_semi_or_recover ();
+                
+                free (name);
+                return 1;
+            
+            }
+            
+            free (name);
+        
+        }
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        
+        expect_semi_or_recover ();
+        return 1;
+    
+    }
+    
+    if (tok.kind != TOK_IDENT) {
+    
+        if (tok.kind == TOK_LPAREN) {
+        
+            if (paren_text_starts_type_name_now () ||
+                (tok.start && tok.start[0] == '(' && tok.start[1] == '(')) {
+                return parse_cast_indirect_assignment_statement ();
+            }
+            
+            if (lparen_expression_starts_with_star_now ()) {
+                return parse_parenthesized_pointer_member_indirect_assignment_statement ();
+            }
+            
+            return parse_parenthesized_indirect_assignment_statement ();
+        
+        }
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    get_token ();
+    
+    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+    
+        enum token_kind postfix_op = tok.kind;
+        int step = 1;
+        
+        get_token ();
+        
+        if (!is_assignment_operator (tok.kind)) {
+        
+            free (name);
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect_semi_or_recover ();
+            
+            return 1;
+        
+        }
+        
+        op = tok.kind;
+        get_token ();
+        
+        lhs = find_local_symbol (name);
+        global_index = find_global_symbol (name);
+        
+        if (!lhs && global_index < 0) {
+        
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        if (lhs) {
+        
+            if (lhs->pointer_depth > 1) {
+            
+                deref_size = DATA_PTR & 0x1f;
+                step = DATA_PTR & 0x1f;
+            
+            } else if (lhs->pointer_depth == 1) {
+            
+                deref_size = lhs->pointed_size & 0x1f;
+                step = lhs->pointed_size > 0 ? lhs->pointed_size : 1;
+            
+            }
+        
+        } else {
+            
+            if (get_global_symbol_pointer_depth (name) > 1) {
+            
+                deref_size = DATA_PTR & 0x1f;
+                step = DATA_PTR & 0x1f;
+            
+            } else if (get_global_symbol_pointer_depth (name) == 1) {
+            
+                deref_size = get_global_symbol_pointed_size (name) & 0x1f;
+                step = get_global_symbol_pointed_size (name) > 0 ? get_global_symbol_pointed_size (name) : 1;
+            
+            }
+        
+        }
+        
+        if (deref_size == 0) {
+            deref_size = DATA_INT & 0x1f;
+        }
+        
+        if (state->ofp) {
+        
+            if (lhs) {
+            
+                if (lhs->is_static && lhs->static_label) {
+                    emit_load_global_to_reg ("rcx", lhs->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg ("rcx", lhs->offset, DATA_PTR);
+                }
+            
+            } else {
+                emit_load_global_to_reg ("rcx", name, DATA_PTR);
+            }
+            
+            emit_push_reg_now ("rcx");
+            
+            if (lhs) {
+            
+                if (lhs->is_static && lhs->static_label) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s qword [%s], %d\n" : "    %s qword ptr [%s], %d\n"), postfix_op == TOK_INCR ? "add" : "sub", asm_global_symbol_name (lhs->static_label), step);
+                    } else {
+                        fprintf (state->ofp, "    %sq $%d, %s(%%rip)\n", postfix_op == TOK_INCR ? "add" : "sub", step, asm_global_symbol_name (lhs->static_label));
+                    }
+                
+                } else {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                    
+                        char memref[64];
+                        char nasm_memref[128];
+                        const char *out_memref;
+                        
+                        format_intel_rbp_offset (memref, sizeof (memref), lhs->offset);
+                        out_memref = memref;
+                        
+                        if (state->syntax & ASM_SYNTAX_NASM) {
+                            out_memref = format_nasm_memory_operand (nasm_memref, sizeof (nasm_memref), memref);
+                        }
+                        
+                        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s qword %s, %d\n" : "    %s qword ptr %s, %d\n"), postfix_op == TOK_INCR ? "add" : "sub", out_memref, step);
+                    
+                    } else {
+                        fprintf (state->ofp, "    %sq $%d, %ld(%%rbp)\n", postfix_op == TOK_INCR ? "add" : "sub", step, lhs->offset);
+                    }
+                
+                }
+            
+            } else {
+                
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s qword [%s], %d\n" : "    %s qword ptr [%s], %d\n"), postfix_op == TOK_INCR ? "add" : "sub", asm_global_symbol_name (name), step);
+                } else {
+                    fprintf (state->ofp, "    %sq $%d, %s(%%rip)\n", postfix_op == TOK_INCR ? "add" : "sub", step, asm_global_symbol_name (name));
+                }
+            
+            }
+            
+            if (op == TOK_ASSIGN) {
+                emit_load_assignment_rhs_expression_to_reg ("rax");
+            } else {
+            
+                emit_pop_reg_now ("rdx");
+                emit_push_reg_now ("rdx");
+                emit_load_member_from_addr_reg_now ("rax", "rdx", 0, deref_size);
+                emit_push_reg_now ("rax");
+                emit_load_assignment_rhs_expression_to_reg ("rdx");
+                emit_pop_reg_now ("rax");
+                emit_assignment_binary_op (op, 0);
+            
+            }
+            
+            emit_pop_reg_now ("rdx");
+            emit_store_reg_to_deref_reg_now ("rdx", "rax", deref_size);
+        
+        } else {
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        }
+        
+        expect_semi_or_recover ();
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+    
+        enum token_kind member_op = tok.kind;
+        enum token_kind postfix_op = TOK_EOF;
+        
+        char *member;
+        
+        const char *member_start;
+        const char *member_caret;
+        
+        unsigned long member_line;
+        
+        int offset = 0;
+        int member_size = DATA_PTR & 0x1f;
+        int member_elem_size = DATA_INT & 0x1f;
+        int member_pointer_depth = 0;
+        int step;
+        
+        get_token ();
+        
+        member_start = tok.start;
+        member_caret = tok.caret;
+        member_line = get_line_number ();
+        
+        if (tok.kind != TOK_IDENT) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        member = xstrdup (tok.ident);
+        get_token ();
+        
+        if (!find_member_info_ex (member, &offset, &member_size, &member_elem_size, &member_pointer_depth, 0, 0)) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect_semi_or_recover ();
+            
+            free (member);
+            free (name);
+            
+            return 1;
+        
+        }
+        
+        free (member);
+        
+        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+        
+            postfix_op = tok.kind;
+            get_token ();
+        
+        }
+        
+        if (!is_assignment_operator (tok.kind)) {
+        
+            free (name);
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect_semi_or_recover ();
+            
+            return 1;
+        
+        }
+        
+        op = tok.kind;
+        get_token ();
+        
+        lhs = find_local_symbol (name);
+        global_index = find_global_symbol (name);
+        
+        if (!lhs && global_index < 0) {
+        
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        if (member_pointer_depth > 1) {
+            deref_size = DATA_PTR & 0x1f;
+        } else if (member_pointer_depth == 1 && member_elem_size > 0) {
+            deref_size = member_elem_size & 0x1f;
+        }
+        
+        if (deref_size == 0) {
+            deref_size = DATA_INT & 0x1f;
+        }
+        
+        step = member_elem_size > 0 ? member_elem_size : 1;
+        
+        if (state->ofp) {
+        
+            if (lhs) {
+            
+                if (member_op == TOK_ARROW) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_global_to_reg ("rdx", lhs->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg ("rdx", lhs->offset, DATA_PTR);
+                    }
+                
+                } else {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_address_to_reg_now ("rdx", lhs->static_label);
+                    } else {
+                        emit_load_local_address_to_reg_now ("rdx", lhs->offset);
+                    }
+                
+                }
+            
+            } else {
+            
+                if (member_op == TOK_ARROW) {
+                    emit_load_global_to_reg ("rdx", name, DATA_PTR);
+                } else {
+                    emit_load_address_to_reg_now ("rdx", name);
+                }
+            
+            }
+            
+            emit_load_member_from_addr_reg_now ("rcx", "rdx", offset, DATA_PTR & 0x1f);
+            
+            if (postfix_op == TOK_INCR || postfix_op == TOK_DECR) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    if (state->syntax & ASM_SYNTAX_NASM) {
+                        fprintf (state->ofp, "    %s qword [rdx + %d], %d\n", postfix_op == TOK_INCR ? "add" : "sub", offset, step);
+                    } else {
+                        fprintf (state->ofp, "    %s qword ptr [rdx + %d], %d\n", postfix_op == TOK_INCR ? "add" : "sub", offset, step);
+                    }
+                
+                } else {
+                    fprintf (state->ofp, "    %sq $%d, %d(%%rdx)\n", postfix_op == TOK_INCR ? "add" : "sub", step, offset);
+                }
+            
+            }
+            
+            emit_push_reg_now ("rcx");
+            
+            if (op == TOK_ASSIGN) {
+                emit_load_assignment_rhs_expression_to_reg ("rax");
+            } else {
+            
+                emit_load_member_from_addr_reg_now ("rax", "rdx", 0, deref_size);
+                emit_push_reg_now ("rax");
+                emit_load_assignment_rhs_expression_to_reg ("rdx");
+                emit_pop_reg_now ("rax");
+                emit_assignment_binary_op (op, 0);
+            
+            }
+            
+            emit_pop_reg_now ("rdx");
+            emit_store_reg_to_deref_reg_now ("rdx", "rax", deref_size);
+        
+        } else {
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        }
+        
+        expect_semi_or_recover ();
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (!is_assignment_operator (tok.kind)) {
+    
+        free (name);
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        return 1;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    lhs = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (!lhs && global_index < 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (lhs) {
+    
+        if (lhs->pointer_depth > 1) {
+        
+            deref_size = DATA_PTR & 0x1f;
+            deref_is_floating = 0;
+        
+        } else if (lhs->pointer_depth == 1) {
+        
+            /**
+             * Keep aggregate pointed-to sizes intact for assignments like
+             * *hashtab = old_hashtab;  Masking with 0x1f corrupts struct
+             * copies whose size is greater than 31 bytes.
+             */
+            deref_size = lhs->pointed_size;
+            deref_is_floating = lhs->pointed_is_floating;
+        
+        }
+    
+    } else {
+    
+        if (get_global_symbol_pointer_depth (name) > 1) {
+        
+            deref_size = DATA_PTR & 0x1f;
+            deref_is_floating = 0;
+        
+        } else if (get_global_symbol_pointer_depth (name) == 1) {
+        
+            deref_size = get_global_symbol_pointed_size (name);
+            deref_is_floating = get_global_symbol_pointed_is_floating (name);
+        
+        }
+    
+    }
+    
+    if (deref_size == 0) {
+        deref_size = DATA_INT & 0x1f;
+    }
+    
+    if (state->ofp) {
+    
+        if (lhs) {
+        
+            if (lhs->is_static && lhs->static_label) {
+                emit_load_global_to_reg ("rdx", lhs->static_label, DATA_PTR);
+            } else {
+                emit_load_local_to_reg ("rdx", lhs->offset, DATA_PTR);
+            }
+        
+        } else {
+            emit_load_global_to_reg ("rdx", name, DATA_PTR);
+        }
+        
+        if (op == TOK_ASSIGN) {
+        
+            if (deref_is_floating) {
+            
+                emit_push_reg_now ("rdx");
+                
+                emit_load_floating_rhs_expression_now (deref_size);
+                emit_pop_reg_now ("rdx");
+                
+                emit_store_floating_member_to_addr_reg_now ("rdx", 0, deref_size);
+                expect_semi_or_recover ();
+                
+                free (name);
+                return 1;
+            
+            }
+            
+            if (deref_size != (DATA_LLONG & 0x1f) && emit_aggregate_copy_from_current_rhs_to_addr_reg_now ("rdx", 0, deref_size)) {
+            
+                expect_semi_or_recover ();
+                
+                free (name);
+                return 1;
+            
+            }
+            
+            emit_push_reg_now ("rdx");
+            
+            if (deref_size == (DATA_LLONG & 0x1f)) {
+            
+                emit_load_assignment_rhs_expression_to_pair ("rax", "rdx", 1);
+                emit_pop_reg_now ("rcx");
+            
+            } else {
+            
+                emit_load_assignment_rhs_expression_to_reg ("rax");
+                emit_pop_reg_now ("rdx");
+            
+            }
+        
+        } else {
+        
+            emit_load_member_from_addr_reg_now ("rax", "rdx", 0, deref_size);
+            
+            emit_push_reg_now ("rdx");
+            emit_push_reg_now ("rax");
+            
+            emit_load_assignment_rhs_expression_to_reg ("rdx");
+            emit_pop_reg_now ("rax");
+            
+            emit_assignment_binary_op (op, 0);
+            emit_pop_reg_now ("rdx");
+        
+        }
+        
+        if (deref_size == (DATA_LLONG & 0x1f) && !deref_is_floating) {
+            emit_store_pair_to_deref_reg_now ("rcx", "rax", "rdx");
+        } else {
+            emit_store_reg_to_deref_reg_now ("rdx", "rax", deref_size);
+        }
+    
+    } else {
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+    }
+    
+    expect_semi_or_recover ();
+    
+    free (name);
+    return 1;
+
+}
+
+static int source_starts_parenthesized_star_now (void) {
+
+    const char *p = tok.caret ? tok.caret : tok.start;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (*p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    return *p == '*';
+
+}
+
+static int parse_parenthesized_indirect_member_assignment_statement (void) {
+
+    enum token_kind member_op;
+    enum token_kind op;
+    
+    char *member;
+    
+    const char *member_start;
+    const char *member_caret;
+    
+    unsigned long member_line;
+    
+    int member_offset = 0;
+    int member_size = DATA_INT & 0x1f;
+    int saw_close = 0;
+    
+    if (tok.kind != TOK_LPAREN || !source_starts_parenthesized_star_now ()) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    if (tok.kind != TOK_STAR) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    /*
+     * Parse only the object expression inside the parenthesized dereference.
+     * For macro-expanded lvalues such as
+     *
+     *     (*(__gtin()))->field = value;
+     *
+     * the normal assignment-expression loader can consume the complete
+     * "->field = value" tail as a value expression.  That emits only
+     * member loads and drops the store.
+     */
+    if (tok.kind == TOK_LPAREN) {
+    
+        int parens = 0;
+        char *inner_name = 0;
+        
+        const char *inner_start = 0;
+        const char *inner_caret = 0;
+        
+        unsigned long inner_line = 0;
+        struct local_symbol *inner_lhs;
+        
+        while (tok.kind == TOK_LPAREN) {
+        
+            parens++;
+            get_token ();
+        
+        }
+        
+        if (tok.kind == TOK_IDENT) {
+        
+            inner_name = xstrdup (tok.ident);
+            inner_start = tok.start;
+            inner_caret = tok.caret;
+            inner_line = get_line_number ();
+            
+            get_token ();
+            
+            if (tok.kind == TOK_LPAREN) {
+                emit_call_identifier_to_reg_now (inner_name, "rdx", inner_start, inner_caret, inner_line);
+            } else {
+            
+                inner_lhs = find_local_symbol (inner_name);
+                
+                if (inner_lhs) {
+                
+                    if (inner_lhs->is_static && inner_lhs->static_label) {
+                        emit_load_global_to_reg ("rdx", inner_lhs->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg ("rdx", inner_lhs->offset, DATA_PTR);
+                    }
+                
+                } else {
+                    emit_load_global_to_reg ("rdx", inner_name, DATA_PTR);
+                }
+            
+            }
+            
+            free (inner_name);
+            
+            while (parens > 0 && tok.kind == TOK_RPAREN) {
+            
+                saw_close = 1;
+                parens--;
+                
+                get_token ();
+            
+            }
+        
+        } else {
+            emit_load_assignment_rhs_expression_to_reg ("rdx");
+        }
+    
+    } else {
+        emit_load_assignment_rhs_expression_to_reg ("rdx");
+    }
+    
+    while (tok.kind == TOK_RPAREN) {
+    
+        saw_close = 1;
+        get_token ();
+    
+    }
+    
+    if (!saw_close) {
+    
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        return 1;
+    
+    }
+    
+    if (tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
+    
+        int deref_size = DATA_INT & 0x1f;
+        int step = 1;
+        
+        if (rhs_last_pointer_depth > 1) {
+        
+            deref_size = DATA_PTR & 0x1f;
+            step = DATA_PTR & 0x1f;
+        
+        } else if (rhs_last_pointer_depth == 1 && rhs_last_pointed_size > 0) {
+            deref_size = rhs_last_pointed_size & 0x1f;
+        }
+        
+        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+        
+            op = tok.kind;
+            get_token ();
+            
+            if (state->ofp) {
+            
+                emit_load_member_from_addr_reg_now ("rax", "rdx", 0, deref_size);
+                
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    %s rax, %d\n", op == TOK_INCR ? "add" : "sub", step);
+                } else {
+                    fprintf (state->ofp, "    %sq $%d, %%rax\n", op == TOK_INCR ? "add" : "sub", step);
+                }
+                
+                emit_store_reg_to_deref_reg_now ("rdx", "rax", deref_size);
+            
+            }
+            
+            expect_semi_or_recover ();
+            return 1;
+        
+        }
+        
+        if (!is_assignment_operator (tok.kind)) {
+        
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect_semi_or_recover ();
+            
+            return 1;
+        
+        }
+        
+        op = tok.kind;
+        get_token ();
+        
+        if (state->ofp) {
+        
+            if (op == TOK_ASSIGN) {
+            
+                emit_push_reg_now ("rdx");
+                emit_load_assignment_rhs_expression_to_reg ("rax");
+                emit_pop_reg_now ("rdx");
+            
+            } else {
+            
+                emit_load_member_from_addr_reg_now ("rax", "rdx", 0, deref_size);
+                emit_push_reg_now ("rdx");
+                emit_push_reg_now ("rax");
+                emit_load_assignment_rhs_expression_to_reg ("rdx");
+                emit_pop_reg_now ("rax");
+                emit_assignment_binary_op (op, 0);
+                emit_pop_reg_now ("rdx");
+            
+            }
+            
+            emit_store_reg_to_deref_reg_now ("rdx", "rax", deref_size);
+        
+        } else {
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        }
+        
+        expect_semi_or_recover ();
+        return 1;
+    
+    }
+    
+    if (state->ofp) {
+        emit_load_deref_reg_now ("rdx", DATA_PTR);
+    }
+    
+    member_op = tok.kind;
+    get_token ();
+    
+    member_start = tok.start;
+    member_caret = tok.caret;
+    member_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT) {
+    
+        report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        return 1;
+    
+    }
+    
+    member = xstrdup (tok.ident);
+    get_token ();
+    
+    if (!find_member_info (member, &member_offset, &member_size)) {
+    
+        report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+        free (member);
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        return 1;
+    
+    }
+    
+    free (member);
+    
+    if (!is_assignment_operator (tok.kind)) {
+    
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        return 1;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    if (state->ofp) {
+    
+        if (op == TOK_ASSIGN) {
+        
+            emit_push_reg_now ("rdx");
+            emit_load_assignment_rhs_expression_to_reg ("rax");
+            emit_pop_reg_now ("rdx");
+        
+        } else {
+        
+            emit_load_member_from_addr_reg_now ("rax", "rdx", member_offset, member_size);
+            emit_push_reg_now ("rdx");
+            emit_push_reg_now ("rax");
+            emit_load_assignment_rhs_expression_to_reg ("rdx");
+            emit_pop_reg_now ("rax");
+            emit_assignment_binary_op (op, 0);
+            emit_pop_reg_now ("rdx");
+        
+        }
+        
+        emit_store_member_to_addr_reg_now ("rdx", member_offset, "rax", member_size);
+    
+    } else {
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+    }
+    
+    expect_semi_or_recover ();
+    return 1;
+
+}
+
+static int token_text_looks_like_postfix_call_now (void) {
+
+    const char *p;
+    
+    int saw_postfix;
+    int paren_depth;
+    int bracket_depth;
+    
+    if (tok.caret) {
+        p = tok.caret;
+    } else if (tok.start) {
+        p = tok.start;
+    } else {
+        return 0;
+    }
+    
+    saw_postfix = 0;
+    paren_depth = 0;
+    bracket_depth = 0;
+    
+    while (*p && *p != ';' && *p != '\n') {
+    
+        if (*p == '(') {
+        
+            if (saw_postfix && paren_depth == 0 && bracket_depth == 0) {
+                return 1;
+            }
+            
+            paren_depth++;
+        
+        } else if (*p == ')') {
+        
+            if (paren_depth > 0) {
+                paren_depth--;
+            }
+        
+        } else if (*p == '[') {
+            bracket_depth++;
+        } else if (*p == ']') {
+        
+            if (bracket_depth > 0) {
+                bracket_depth--;
+            }
+        
+        } else if (paren_depth == 0 && bracket_depth == 0 && *p == '.') {
+            saw_postfix = 1;
+        } else if (paren_depth == 0 && bracket_depth == 0 && *p == '-' && p[1] == '>') {
+        
+            saw_postfix = 1;
+            p++;
+        
+        } else if (paren_depth == 0 && bracket_depth == 0 && *p == '=') {
+            return 0;
+        }
+        
+        p++;
+    
+    }
+    
+    return 0;
+
+}
+
+static int parse_parenthesized_deref_subscript_statement (void) {
+
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    struct local_symbol *src;
+    
+    int global_index;
+    int pointer_depth;
+    int pointed_size;
+    
+    if (tok.kind != TOK_LPAREN || !source_starts_lparen_deref_subscript_at (tok.caret)) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    if (tok.kind != TOK_STAR) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    get_token ();
+    
+    expect (TOK_RPAREN, ")");
+    
+    src = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    pointer_depth = 0;
+    pointed_size = DATA_INT & 0x1f;
+    
+    if (src) {
+    
+        pointer_depth = src->pointer_depth;
+        pointed_size = src->pointed_size;
+        
+        if (src->is_static && src->static_label) {
+            emit_load_global_to_reg ("rax", src->static_label, DATA_PTR);
+        } else {
+            emit_load_local_to_reg ("rax", src->offset, DATA_PTR);
+        }
+    
+    } else if (global_index >= 0) {
+    
+        pointer_depth = get_global_symbol_pointer_depth (name);
+        pointed_size = get_global_symbol_pointed_size (name);
+        
+        emit_load_global_to_reg ("rax", name, DATA_PTR);
+    
+    } else {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (pointer_depth <= 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid indirection of non-pointer '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    emit_load_deref_reg_now ("rax", DATA_PTR & 0x1f);
+    emit_handle_subscript_after_loaded_pointer_to_reg_now ("rax", pointer_depth - 1, pointed_size, src ? src->pointed_is_unsigned : get_global_symbol_pointed_is_unsigned (name));
+    
+    free (name);
+    return 1;
+
+}
+
+static int parse_identifier_assignment_statement (void) {
+
+    char *name;
+    int global_index;
+    
+    const char *name_start, *name_caret;
+    unsigned long name_line;
+    
+    enum token_kind op;
+    struct local_symbol *lhs;
+    
+    int is_simple_assign;
+    int lhs_size;
+    int lhs_is_floating;
+    int lhs_pointer_depth;
+    
+    if (tok.kind != TOK_IDENT) {
+        return 0;
+    }
+    
+    if (token_text_looks_like_postfix_call_now ()) {
+        return 0;
+    }
+    
+    name = xstrdup (tok.ident);
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    get_token ();
+    
+    if (tok.kind == TOK_COLON) {
+    
+        define_goto_label (name, name_line, name_start, name_caret);
+        
+        get_token ();
+        free (name);
+        
+        parse_statement ();
+        return 1;
+    
+    }
+    
+    if (tok.kind == TOK_DOT || tok.kind == TOK_ARROW) {
+    
+        enum token_kind member_op = tok.kind;
+        char *member;
+        
+        const char *member_start;
+        const char *member_caret;
+        
+        unsigned long member_line;
+        
+        int member_offset = 0;
+        int member_size = DATA_INT & 0x1f;
+        int member_elem_size = DATA_INT & 0x1f;
+        int member_pointer_depth = 0;
+        int member_is_floating = 0;
+        int member_assignment_is_floating = 0;
+        
+        get_token ();
+        
+        member_start = tok.start;
+        member_caret = tok.caret;
+        member_line = get_line_number ();
+        
+        if (tok.kind != TOK_IDENT) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        member = xstrdup (tok.ident);
+        get_token ();
+        
+        lhs = find_local_symbol (name);
+        global_index = find_global_symbol (name);
+        
+        if (!find_member_info_ex_bounded (member,
+                member_op == TOK_DOT
+                    ? (lhs ? lhs->size : (global_index >= 0 ? get_global_symbol_size (name) : 0))
+                    : (lhs ? lhs->pointed_size : (global_index >= 0 ? get_global_symbol_pointed_size (name) : 0)),
+                member_op == TOK_DOT
+                    ? (lhs ? lhs->tag_name : (global_index >= 0 ? get_global_symbol_tag_name (name) : 0))
+                    : (lhs ? lhs->pointed_tag_name : 0),
+                &member_offset, &member_size, &member_elem_size, &member_pointer_depth, 0, &member_is_floating)) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+            
+            free (member);
+            free (name);
+            
+            return 1;
+        
+        }
+        
+        free (member);
+        
+        if (!is_assignment_operator (tok.kind)) {
+        
+            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+            
+                enum token_kind postfix_op = tok.kind;
+                int step = member_pointer_depth > 0 && member_elem_size > 0 ? member_elem_size : 1;
+                
+                get_token ();
+                
+                lhs = find_local_symbol (name);
+                global_index = find_global_symbol (name);
+                
+                if (!lhs && global_index < 0) {
+                
+                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+                    
+                    skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                    expect (TOK_SEMI, ";");
+                    
+                    free (name);
+                    return 1;
+                
+                }
+                
+                if (state->ofp) {
+                
+                    if (member_op == TOK_ARROW) {
+                    
+                        if (lhs) {
+                        
+                            if (lhs->is_static && lhs->static_label) {
+                                emit_load_global_to_reg ("rdx", lhs->static_label, DATA_PTR);
+                            } else {
+                                emit_load_local_to_reg ("rdx", lhs->offset, DATA_PTR);
+                            }
+                        
+                        } else {
+                            emit_load_global_to_reg ("rdx", name, DATA_PTR);
+                        }
+                    
+                    } else {
+                    
+                        if (lhs) {
+                        
+                            if (lhs->is_static && lhs->static_label) {
+                                emit_load_address_to_reg_now ("rdx", lhs->static_label);
+                            } else {
+                                emit_load_local_address_to_reg_now ("rdx", lhs->offset);
+                            }
+                        
+                        } else {
+                            emit_load_address_to_reg_now ("rdx", name);
+                        }
+                    
+                    }
+                    
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                    
+                        const char *opname = postfix_op == TOK_INCR ? "add" : "sub";
+                        const char *opsize = member_size == 1 ? "byte" : (member_size == 2 ? "word" : "dword");
+                        
+                        if (state->syntax & ASM_SYNTAX_NASM) {
+                            fprintf (state->ofp, "    %s %s [rdx + %d], %d\n", opname, opsize, member_offset, step);
+                        } else {
+                            fprintf (state->ofp, "    %s %s ptr [rdx + %d], %d\n", opname, opsize, member_offset, step);
+                        }
+                    
+                    } else {
+                    
+                        const char *suffix = member_size == 1 ? "b" : (member_size == 2 ? "w" : "l");
+                        fprintf (state->ofp, "    %s%s $%d, %d(%%rdx)\n", postfix_op == TOK_INCR ? "add" : "sub", suffix, step, member_offset);
+                    
+                    }
+                
+                }
+                
+                expect_semi_or_recover ();
+                
+                free (name);
+                return 1;
+            
+            }
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect (TOK_SEMI, ";");
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        op = tok.kind;
+        
+        is_simple_assign = (tok.kind == TOK_ASSIGN);
+        get_token ();
+        
+        if (!lhs && global_index < 0) {
+        
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect (TOK_SEMI, ";");
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        if (state->ofp) {
+        
+            if (member_op == TOK_ARROW) {
+            
+                if (lhs) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_global_to_reg ("rdx", lhs->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg ("rdx", lhs->offset, DATA_PTR);
+                    }
+                
+                } else {
+                    emit_load_global_to_reg ("rdx", name, DATA_PTR);
+                }
+            
+            } else {
+            
+                if (lhs) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_address_to_reg_now ("rdx", lhs->static_label);
+                    } else {
+                        emit_load_local_address_to_reg_now ("rdx", lhs->offset);
+                    }
+                
+                } else {
+                    emit_load_address_to_reg_now ("rdx", name);
+                }
+            
+            }
+            
+            if (is_simple_assign) {
+            
+                member_assignment_is_floating = member_is_floating || rhs_current_operand_is_floating_now ();
+                emit_push_reg_now ("rdx");
+                
+                if (member_assignment_is_floating) {
+                    emit_load_floating_rhs_expression_now (member_size);
+                } else {
+                    emit_load_assignment_rhs_expression_to_reg ("rax");
+                }
+                
+                emit_pop_reg_now ("rdx");
+            
+            } else {
+            
+                emit_load_member_from_addr_reg_now ("rax", "rdx", member_offset, member_size);
+                
+                emit_push_reg_now ("rdx");
+                emit_push_reg_now ("rax");
+                
+                if (tok.kind == TOK_TILDE) {
+                
+                    int64_s rhs_const;
+                    get_token ();
+                    
+                    if (tok.kind == TOK_LPAREN) {
+                    
+                        get_token ();
+                        
+                        rhs_const = const64_from_current_foldable_expr ();
+                        expect (TOK_RPAREN, ")");
+                    
+                    } else {
+                        rhs_const = const64_from_current_foldable_expr ();
+                    }
+                    
+                    rhs_const.low = (~rhs_const.low) & U32_MASK;
+                    rhs_const.high = (~rhs_const.high) & U32_MASK;
+                    
+                    emit_load_const32_to_reg_now ("rdx", rhs_const);
+                
+                } else if (current_integer_expr_is_foldable_now ()) {
+                
+                    int64_s rhs_const = const64_from_current_foldable_expr ();
+                    emit_load_const32_to_reg_now ("rdx", rhs_const);
+                
+                } else {
+                    emit_load_assignment_rhs_expression_to_reg ("rdx");
+                }
+                
+                emit_pop_reg_now ("rax");
+                emit_assignment_binary_op (op, 0);
+                emit_pop_reg_now ("rdx");
+            
+            }
+            
+            if (member_assignment_is_floating && is_simple_assign) {
+                emit_store_floating_member_to_addr_reg_now ("rdx", member_offset, member_size);
+            } else {
+                emit_store_member_to_addr_reg_now ("rdx", member_offset, "rax", member_size);
+            }
+        
+        } else {
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        }
+        
+        expect_semi_or_recover ();
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (tok.kind == TOK_LBRACK) {
+    
+        int elem_size = DATA_INT & 0x1f;
+        int elem_pointer_depth = 0;
+        int elem_pointed_size = DATA_INT & 0x1f;
+        
+        lhs = find_local_symbol (name);
+        global_index = find_global_symbol (name);
+        
+        if (!lhs && global_index < 0) {
+        
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        if (lhs) {
+        
+            elem_size = lhs->is_array ? (lhs->pointer_depth ? DATA_PTR : lhs->pointed_size) :
+                (lhs->pointer_depth > 1 ? DATA_PTR : lhs->pointed_size);
+            
+            elem_pointer_depth = lhs->pointer_depth > 0 ? lhs->pointer_depth - 1 : 0;
+            elem_pointed_size = lhs->pointed_size;
+        
+        } else {
+        
+            elem_size = get_global_symbol_array (name) ?
+                (get_global_symbol_pointer_depth (name) ? DATA_PTR : (get_global_symbol_array_element_size (name) > 0 ? get_global_symbol_array_element_size (name) : get_global_symbol_pointed_size (name))) :
+                    (get_global_symbol_pointer_depth (name) > 1 ? DATA_PTR : get_global_symbol_pointed_size (name));
+            
+            elem_pointer_depth = get_global_symbol_pointer_depth (name) > 0 ? get_global_symbol_pointer_depth (name) - 1 : 0;
+            elem_pointed_size = get_global_symbol_pointed_size (name);
+        
+        }
+        
+        if ((elem_size & 0x1f) == 0) {
+            elem_size = DATA_INT & 0x1f;
+        }
+        
+        if (state->ofp) {
+        
+            if (lhs) {
+            
+                if (lhs->is_array) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_symbol_address_to_reg_now ("rdx", lhs->static_label, 0, 0);
+                    } else {
+                        emit_load_symbol_address_to_reg_now ("rdx", 0, lhs->offset, 1);
+                    }
+                
+                } else if (lhs->is_static && lhs->static_label) {
+                    emit_load_global_to_reg ("rdx", lhs->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg ("rdx", lhs->offset, DATA_PTR);
+                }
+            
+            } else if (get_global_symbol_array (name)) {
+                emit_load_symbol_address_to_reg_now ("rdx", name, 0, 0);
+            } else {
+                emit_load_global_to_reg ("rdx", name, DATA_PTR);
+            }
+            
+            emit_parse_postfix_subscript_scaled_address_to_reg_now ("rdx", elem_size);
+        
+        } else {
+            emit_parse_postfix_subscript_scaled_address_to_reg_now ("rdx", elem_size);
+        }
+        
+        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+        
+            op = tok.kind;
+            
+            is_simple_assign = (tok.kind == TOK_ASSIGN);
+            get_token ();
+            
+            if (state->ofp) {
+            
+                int inc_amount = (elem_pointer_depth > 0 && (elem_pointed_size & 0x1f) > 0) ?
+                    (elem_pointed_size & 0x1f) : 1;
+                
+                emit_load_member_from_addr_reg_now ("rax", "rdx", 0, elem_size);
+                
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    %s rax, %d\n", op == TOK_INCR ? "add" : "sub", inc_amount);
+                } else {
+                    fprintf (state->ofp, "    %sq $%d, %%rax\n", op == TOK_INCR ? "add" : "sub", inc_amount);
+                }
+                
+                emit_store_reg_to_deref_reg_now ("rdx", "rax", elem_size);
+            
+            }
+            
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        if (!is_assignment_operator (tok.kind)) {
+        
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        op = tok.kind;
+        
+        is_simple_assign = (tok.kind == TOK_ASSIGN);
+        get_token ();
+        
+        if (state->ofp) {
+        
+            if (is_simple_assign) {
+            
+                emit_push_reg_now ("rdx");
+                emit_load_assignment_rhs_expression_to_reg ("rax");
+                emit_pop_reg_now ("rdx");
+            
+            } else {
+            
+                emit_load_member_from_addr_reg_now ("rax", "rdx", 0, elem_size);
+                emit_push_reg_now ("rdx");
+                emit_push_reg_now ("rax");
+                emit_load_assignment_rhs_expression_to_reg ("rdx");
+                emit_pop_reg_now ("rax");
+                emit_assignment_binary_op (op, 0);
+                emit_pop_reg_now ("rdx");
+            
+            }
+            
+            emit_store_reg_to_deref_reg_now ("rdx", "rax", elem_size);
+        
+        } else {
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        }
+        
+        expect_semi_or_recover ();
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (!is_assignment_operator (tok.kind)) {
+    
+        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);
+            emit_incdec_symbol_now (lhs, name, op, name_line, name_start, name_caret);
+            
+            expect_semi_or_recover ();
+            free (name);
+            
+            return 1;
+        
+        }
+        
+        if (tok.kind == TOK_LPAREN) {
+        
+            if (!find_local_symbol (name)) {
+                ensure_global_function_symbol (name, name_start, name_caret, name_line);
+            }
+            
+            emit_call_identifier_to_reg_now (name, "rax", name_start, name_caret, name_line);
+            
+            if (tok.kind == TOK_LBRACK) {
+            
+                int elem_size = get_global_symbol_pointed_size (name);
+                
+                if ((elem_size & 0x1f) == 0) {
+                    elem_size = DATA_INT & 0x1f;
+                }
+                
+                if (state->ofp) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    mov rdx, rax\n");
+                    } else {
+                        fprintf (state->ofp, "    movq %%rax, %%rdx\n");
+                    }
+                
+                }
+                
+                emit_parse_postfix_subscript_scaled_address_to_reg_now ("rdx", elem_size);
+                
+                if (is_assignment_operator (tok.kind)) {
+                
+                    op = tok.kind;
+                    
+                    is_simple_assign = (tok.kind == TOK_ASSIGN);
+                    get_token ();
+                    
+                    if (state->ofp) {
+                    
+                        if (is_simple_assign) {
+                        
+                            emit_push_reg_now ("rdx");
+                            emit_load_assignment_rhs_expression_to_reg ("rax");
+                            emit_pop_reg_now ("rdx");
+                        
+                        } else {
+                        
+                            emit_load_member_from_addr_reg_now ("rax", "rdx", 0, elem_size);
+                            emit_push_reg_now ("rdx");
+                            emit_push_reg_now ("rax");
+                            emit_load_assignment_rhs_expression_to_reg ("rdx");
+                            emit_pop_reg_now ("rax");
+                            emit_assignment_binary_op (op, 0);
+                            emit_pop_reg_now ("rdx");
+                        
+                        }
+                        
+                        emit_store_reg_to_deref_reg_now ("rdx", "rax", elem_size);
+                    
+                    } else {
+                        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                    }
+                    
+                    expect_semi_or_recover ();
+                    
+                    free (name);
+                    return 1;
+                
+                }
+            
+            }
+            
+            if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+            
+                enum token_kind member_op = tok.kind;
+                char *member;
+                
+                const char *member_start;
+                const char *member_caret;
+                
+                unsigned long member_line;
+                
+                int member_offset = 0;
+                int member_size = DATA_PTR & 0x1f;
+                
+                get_token ();
+                
+                member_start = tok.start;
+                member_caret = tok.caret;
+                member_line = get_line_number ();
+                
+                if (tok.kind != TOK_IDENT) {
+                
+                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+                    
+                    skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                    expect_semi_or_recover ();
+                    
+                    free (name);
+                    return 1;
+                
+                }
+                
+                member = xstrdup (tok.ident);
+                get_token ();
+                
+                if (!find_member_info (member, &member_offset, &member_size)) {
+                
+                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+                    free (member);
+                    
+                    skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                    expect_semi_or_recover ();
+                    
+                    free (name);
+                    return 1;
+                
+                }
+                
+                free (member);
+                
+                if (member_op == TOK_DOT && state->ofp) {
+                    emit_load_deref_reg_now ("rax", DATA_PTR);
+                }
+                
+                if (is_assignment_operator (tok.kind)) {
+                
+                    op = tok.kind;
+                    
+                    is_simple_assign = (tok.kind == TOK_ASSIGN);
+                    get_token ();
+                    
+                    if (state->ofp) {
+                    
+                        if (state->syntax & ASM_SYNTAX_INTEL) {
+                            fprintf (state->ofp, "    mov rdx, rax\n");
+                        } else {
+                            fprintf (state->ofp, "    movq %%rax, %%rdx\n");
+                        }
+                        
+                        if (is_simple_assign) {
+                        
+                            emit_push_reg_now ("rdx");
+                            emit_load_assignment_rhs_expression_to_reg ("rax");
+                            emit_pop_reg_now ("rdx");
+                        
+                        } else {
+                        
+                            emit_load_member_from_addr_reg_now ("rax", "rdx", member_offset, member_size);
+                            emit_push_reg_now ("rdx");
+                            emit_push_reg_now ("rax");
+                            emit_load_assignment_rhs_expression_to_reg ("rdx");
+                            emit_pop_reg_now ("rax");
+                            emit_assignment_binary_op (op, 0);
+                            emit_pop_reg_now ("rdx");
+                        
+                        }
+                        
+                        emit_store_member_to_addr_reg_now ("rdx", member_offset, "rax", member_size);
+                    
+                    } else {
+                        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                    }
+                    
+                    expect_semi_or_recover ();
+                    free (name);
+                    
+                    return 1;
+                
+                }
+                
+                if (tok.kind == TOK_LPAREN) {
+                
+                    FILE **arg_tmp_ofps = 0;
+                    FILE **new_arg_tmp_ofps;
+                    FILE *arg_tmp_ofp;
+                    FILE *arg_saved_ofp;
+                    
+                    int argc = 0;
+                    int i;
+                    int ch;
+                    int total_arg_bytes = 0;
+                    
+                    if (state->ofp) {
+                    
+                        emit_load_member_from_addr_reg_now ("rcx", "rax", member_offset, DATA_PTR & 0x1f);
+                        emit_push_reg_now ("rcx");
+                    
+                    }
+                    
+                    get_token ();
+                    
+                    if (tok.kind != TOK_RPAREN) {
+                    
+                        for (;;) {
+                        
+                            arg_tmp_ofp = 0;
+                            arg_saved_ofp = 0;
+                            
+                            if (state->ofp) {
+                            
+                                arg_tmp_ofp = scc_tmpfile ();
+                                
+                                if (arg_tmp_ofp) {
+                                    arg_saved_ofp = state->ofp;
+                                    state->ofp = arg_tmp_ofp;
+                                }
+                            
+                            }
+                            
+                            emit_load_assignment_rhs_expression_to_reg ("rax");
+                            
+                            if (state->ofp) {
+                                emit_push_reg_now ("rax");
+                            }
+                            
+                            if (arg_saved_ofp) {
+                            
+                                fflush (arg_tmp_ofp);
+                                state->ofp = arg_saved_ofp;
+                                
+                                new_arg_tmp_ofps = (FILE **) xrealloc (arg_tmp_ofps, sizeof (*arg_tmp_ofps) * (argc + 1));
+                                
+                                if (new_arg_tmp_ofps) {
+                                
+                                    arg_tmp_ofps = new_arg_tmp_ofps;
+                                    arg_tmp_ofps[argc] = arg_tmp_ofp;
+                                    arg_tmp_ofp = 0;
+                                
+                                }
+                            
+                            }
+                            
+                            if (arg_tmp_ofp) {
+                                scc_close (arg_tmp_ofp);
+                            }
+                            
+                            argc++;
+                            total_arg_bytes += DATA_PTR & 0x1f;
+                            
+                            if (!_accept (TOK_COMMA)) {
+                                break;
+                            }
+                        
+                        }
+                    
+                    }
+                    
+                    expect (TOK_RPAREN, ")");
+                    
+                    if (state->ofp) {
+                    
+                        for (i = argc - 1; i >= 0; i--) {
+                        
+                            if (arg_tmp_ofps && arg_tmp_ofps[i]) {
+                            
+                                fseek (arg_tmp_ofps[i], 0, SEEK_SET);
+                                
+                                while ((ch = fgetc (arg_tmp_ofps[i])) != EOF) {
+                                    fputc (ch, state->ofp);
+                                }
+                                
+                                scc_close (arg_tmp_ofps[i]);
+                                arg_tmp_ofps[i] = 0;
+                            
+                            }
+                        
+                        }
+                        
+                        if (arg_tmp_ofps) {
+                        
+                            free (arg_tmp_ofps);
+                            arg_tmp_ofps = 0;
+                        
+                        }
+                        
+                        if (state->syntax & ASM_SYNTAX_INTEL) {
+                        
+                            if (state->syntax & ASM_SYNTAX_NASM) {
+                                fprintf (state->ofp, "    mov r11, qword [rsp + %d]\n", total_arg_bytes);
+                            } else {
+                                fprintf (state->ofp, "    mov r11, qword ptr [rsp + %d]\n", total_arg_bytes);
+                            }
+                            
+                            fprintf (state->ofp, "    call r11\n");
+                            fprintf (state->ofp, "    add rsp, %d\n", total_arg_bytes + (DATA_PTR & 0x1f));
+                        
+                        } else {
+                        
+                            fprintf (state->ofp, "    movq %d(%%rsp), %%r11\n", total_arg_bytes);
+                            fprintf (state->ofp, "    call *%%r11\n");
+                            
+                            fprintf (state->ofp, "    addq $%d, %%rsp\n", total_arg_bytes + (DATA_PTR & 0x1f));
+                        
+                        }
+                    
+                    }
+                    
+                    expect_semi_or_recover ();
+                    free (name);
+                    
+                    return 1;
+                
+                }
+                
+                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                
+                expect_semi_or_recover ();
+                free (name);
+                
+                return 1;
+            
+            }
+            
+            expect_semi_or_recover ();
+            free (name);
+            
+            return 1;
+        
+        }
+        
+        if (!find_local_symbol (name) && find_global_symbol (name) < 0) {
+        
+            int64_s ignored;
+            
+            if (!resolve_enum_constant (name, &ignored)) {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            }
+        
+        }
+        
+        free (name);
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect (TOK_SEMI, ";");
+        
+        return 1;
+    
+    }
+    
+    op = tok.kind;
+    
+    is_simple_assign = (tok.kind == TOK_ASSIGN);
+    get_token ();
+    
+    lhs = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (!lhs && global_index < 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect (TOK_SEMI, ";");
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (state->ofp) {
+    
+        lhs_size = lhs ? lhs->size : get_global_symbol_size (name);
+        lhs_is_floating = lhs ? lhs->is_floating : get_global_symbol_floating (name);
+        lhs_pointer_depth = lhs ? lhs->pointer_depth : get_global_symbol_pointer_depth (name);
+        
+        if (is_simple_assign && lhs_size > (DATA_LLONG & 0x1f) && tok.kind == TOK_IDENT) {
+            
+            char *rhs_name = xstrdup (tok.ident);
+            
+            struct local_symbol *rhs_sym;
+            int rhs_global_index;
+            
+            get_token ();
+            
+            rhs_sym = find_local_symbol (rhs_name);
+            rhs_global_index = find_global_symbol (rhs_name);
+            
+            if (rhs_sym || rhs_global_index >= 0) {
+            
+                if (tok.kind == TOK_LPAREN && rhs_global_index >= 0 && get_global_symbol_kind (rhs_name) == GLOBAL_SYMBOL_FUNCTION) {
+                
+                    pending_struct_return_lhs = lhs;
+                    pending_struct_return_global_name = lhs ? 0 : name;
+                    
+                    emit_call_identifier_to_reg_now (rhs_name, "rax", name_start, name_caret, name_line);
+                
+                } else if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT || tok.kind == TOK_LBRACK) {
+                
+                    if (emit_parse_postfix_copy_source_address_now ("rax", rhs_sym, rhs_name, name_start, name_caret, name_line)) {
+                    
+                        emit_load_symbol_address_for_copy_now ("rdx", lhs, name);
+                        emit_copy_fixed_size_now (lhs_size);
+                    
+                    }
+                
+                } else {
+                    emit_memcpy_symbol_to_symbol_now (lhs, name, rhs_sym, rhs_name, lhs_size);
+                }
+            
+            } else {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", rhs_name);
+            }
+            
+            free (rhs_name);
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        if (lhs_is_floating) {
+        
+            if (!floating_assignment_operator_supported_now (op)) {
+            
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid operands to floating assignment operator");
+                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            
+            } else {
+            
+                if (is_simple_assign) {
+                    emit_load_floating_rhs_expression_now (lhs_size);
+                } else {
+                
+                    emit_load_floating_symbol_now (lhs, name, lhs_size);
+                    emit_load_floating_rhs_expression_now (lhs_size);
+                    emit_floating_binary_now (op);
+                
+                }
+                
+                emit_store_floating_symbol_now (lhs, name, lhs_size);
+            
+            }
+        
+        } else if (lhs_size == (DATA_LLONG & 0x1f) && lhs_pointer_depth <= 0) {
+        
+            if (is_simple_assign) {
+                emit_load_assignment_rhs_expression_to_pair ("rax", "rdx", lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
+            } else {
+            
+                if (lhs) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_global64_to_pair ("rax", "rdx", lhs->static_label);
+                    } else {
+                        emit_load_local64_to_pair (lhs->offset, "rax", "rdx");
+                    }
+                
+                } else {
+                    emit_load_global64_to_pair ("rax", "rdx", name);
+                }
+                
+                /*
+                 * Compound assignments need the complete RHS expression.
+                 * Using emit_load_assignment_rhs_to_pair() only consumes one
+                 * primary operand, so e.g.
+                 *
+                 *     final_value += symbol->frag->address + left_value;
+                 *
+                 * leaves the second + operand for the statement parser and
+                 * reports "expected ;".  Evaluate the full RHS in rax:rdx,
+                 * copy it to the RHS pair rbx:rcx, then restore the original
+                 * LHS value before applying the compound operator.
+                 */
+                emit_push_reg_now ("rax");
+                emit_push_reg_now ("rdx");
+                
+                emit_load_assignment_rhs_expression_to_pair ("rax", "rdx", lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
+                
+                emit_mov_reg_to_reg_now ("rbx", "rax");
+                emit_mov_reg_to_reg_now ("rcx", "rdx");
+                
+                emit_pop_reg_now ("rdx");
+                emit_pop_reg_now ("rax");
+                
+                emit_preserve_assignment64_regs (op);
+                emit_assignment_binary_op64 (op, lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
+                emit_restore_assignment64_regs (op);
+            
+            }
+            
+            if (lhs) {
+            
+                if (lhs->is_static && lhs->static_label) {
+                    emit_store_pair_to_global64 (lhs->static_label, "rax", "rdx");
+                } else {
+                    emit_store_pair_to_local64 (lhs->offset, "rax", "rdx");
+                }
+            
+            } else {
+                emit_store_pair_to_global64 (name, "rax", "rdx");
+            }
+        
+        } else {
+        
+            if (is_simple_assign) {
+                emit_load_assignment_rhs_expression_to_reg ("rax");
+            } else {
+            
+                if (lhs) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_global_to_reg_ex ("rax", lhs->static_label, lhs->size, lhs->is_unsigned);
+                    } else {
+                        emit_load_local_to_reg_ex ("rax", lhs->offset, lhs->size, lhs->is_unsigned);
+                    }
+                
+                } else {
+                    emit_load_global_to_reg ("rax", name, lhs_size);
+                }
+                
+                /*
+                 * Compound assignments still need the full RHS expression,
+                 * not just a single operand.  Otherwise cases such as:
+                 *
+                 *     processed += (int)(t - stream->upto) - 1;
+                 *
+                 * leave the trailing "- 1" unconsumed and the statement
+                 * parser reports "expected ;".  Preserve the current LHS
+                 * value in rax while the RHS expression is parsed, because
+                 * RHS binary-expression code may use rax internally even
+                 * when the requested result register is rdx.
+                 */
+                emit_push_reg_now ("rax");
+                emit_load_assignment_rhs_expression_to_reg ("rdx");
+                
+                emit_scale_reg_for_pointer_compound_assignment_now ("rdx", lhs, name, op);
+                emit_pop_reg_now ("rax");
+                
+                emit_assignment_binary_op (op, lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
+            
+            }
+            
+            if (lhs) {
+            
+                if (lhs->is_static && lhs->static_label) {
+                    emit_store_reg_to_global (lhs->static_label, lhs->size, "rax");
+                } else {
+                    emit_store_reg_to_local (lhs->offset, lhs->size, "rax");
+                }
+            
+            } else {
+                emit_store_reg_to_global (name, lhs_size, "rax");
+            }
+        
+        }
+    
+    } else {
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+    }
+    
+    expect_semi_or_recover ();
+    
+    free (name);
+    return 1;
+
+}
+
+static void emit_statement_label_raw (int label) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+        fprintf (state->ofp, "L%d:\n", label);
+    } else {
+        fprintf (state->ofp, ".L%d:\n", label);
+    }
+
+}
+
+static void flush_pending_statement_labels (void) {
+
+    int i;
+    int count = pending_statement_label_count;
+    
+    /**
+     * A queued case/default/C label marks the next statement.  If the
+     * previous statement was a return, its jump to the common epilogue may
+     * still be pending.  Emit that jump before placing the next label,
+     * otherwise the label lands between the return value setup and the
+     * deferred jump.
+     *
+     * Also flush the deferred return before any other emitted control-flow
+     * boundary even when there are no queued labels.  A switch body is emitted
+     * into a temporary stream and then replayed before the switch break label;
+     * if the last case returns, there may be no following case/default label to
+     * force this flush.
+     */
+    if (pending_return_jump) {
+        emit_pending_return_jump ();
+    }
+    
+    if (count <= 0) {
+        return;
+    }
+    
+    pending_statement_label_count = 0;
+    
+    for (i = 0; i < count; i++) {
+        emit_statement_label_raw (pending_statement_labels[i]);
+    }
+
+}
+
+static void emit_statement_label (int label) {
+
+    flush_pending_statement_labels ();
+    emit_statement_label_raw (label);
+
+}
+
+static void emit_statement_jump (int label) {
+
+    flush_pending_statement_labels ();
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+        fprintf (state->ofp, "    jmp L%d\n", label);
+    } else {
+        fprintf (state->ofp, "    jmp .L%d\n", label);
+    }
+
+}
+
+static int token_is_integer_constant_now (enum token_kind k) {
+    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 == TOK_CUINT || k == TOK_CULONG || k == TOK_CULLONG;
+}
+
+#define     MAX_INLINE_ASM_INPUTS        16
+
+struct inline_asm_input_operand {
+
+    char constraint[16];
+    char subst[64];
+    int restore_reg;
+    const char *restore_name;
+
+};
+
+static void inline_asm_copy_trimmed_text (char *dst, size_t dst_size, const char *start, const char *end) {
+
+    size_t len;
+    
+    if (!dst || dst_size == 0) {
+        return;
+    }
+    
+    dst[0] = 0;
+    
+    if (!start || !end || end < start) {
+        return;
+    }
+    
+    while (start < end && (*start == ' ' || *start == '\t' || *start == '\r' || *start == '\n')) {
+        start++;
+    }
+    
+    while (end > start && (end[-1] == ' ' || end[-1] == '\t' || end[-1] == '\r' || end[-1] == '\n')) {
+        end--;
+    }
+    
+    len = (size_t) (end - start);
+    
+    if (len >= dst_size) {
+        len = dst_size - 1;
+    }
+    
+    memcpy (dst, start, len);
+    dst[len] = 0;
+
+}
+
+static void inline_asm_unquote_string_token (char *dst, size_t dst_size) {
+
+    const char *s;
+    char quote;
+    size_t n = 0;
+    
+    if (!dst || dst_size == 0) {
+        return;
+    }
+    
+    dst[0] = 0;
+    
+    if (!is_string_token ()) {
+        return;
+    }
+    
+    s = tok.ident;
+    
+    if (tok.kind == TOK_LSTR && *s == 'L') {
+        s++;
+    }
+    
+    quote = *s;
+    
+    if (quote != '"') {
+        return;
+    }
+    
+    s++;
+    
+    while (*s && *s != quote && n + 1 < dst_size) {
+    
+        if (*s == '\\' && s[1]) {
+        
+            s++;
+            
+            switch (*s) {
+            
+                case 'n':
+                
+                    dst[n++] = '\n'; s++;
+                    break;
+                
+                case 'r':
+                
+                    dst[n++] = '\r'; s++;
+                    break;
+                
+                case 't':
+                
+                    dst[n++] = '\t'; s++;
+                    break;
+                
+                case '\\':
+                
+                    dst[n++] = '\\'; s++;
+                    break;
+                
+                case '"':
+                
+                    dst[n++] = '"'; s++;
+                    break;
+                
+                default:
+                
+                    dst[n++] = *s++;
+                    break;
+            
+            }
+        
+        } else {
+            dst[n++] = *s++;
+        }
+    
+    }
+    
+    dst[n] = 0;
+
+}
+
+static const char *inline_asm_constraint_reg32 (const char *constraint) {
+
+    if (!constraint) {
+        return 0;
+    }
+    
+    if (strchr (constraint, 'a')) {
+        return "rax";
+    }
+    
+    if (strchr (constraint, 'b')) {
+        return "rbx";
+    }
+    
+    if (strchr (constraint, 'c')) {
+        return "rcx";
+    }
+    
+    if (strchr (constraint, 'd')) {
+        return "rdx";
+    }
+    
+    if (strchr (constraint, 'S')) {
+        return "rsi";
+    }
+    
+    if (strchr (constraint, 'D')) {
+        return "rdi";
+    }
+    
+    return 0;
+
+}
+
+static const char *inline_asm_reg_for_template (const char *reg32) {
+
+    if (!reg32) {
+        return "";
+    }
+    
+    if (strcmp (reg32, "rax") == 0) {
+        return "al";
+    }
+    
+    if (strcmp (reg32, "rbx") == 0) {
+        return "bl";
+    }
+    
+    if (strcmp (reg32, "rcx") == 0) {
+        return "cl";
+    }
+    
+    if (strcmp (reg32, "rdx") == 0) {
+        return "dx";
+    }
+    
+    if (strcmp (reg32, "rsi") == 0) {
+        return "rsi";
+    }
+    
+    if (strcmp (reg32, "rdi") == 0) {
+        return "rdi";
+    }
+    
+    return reg32;
+
+}
+
+static int inline_asm_reg_needs_restore (const char *reg32) {
+    return reg32 && (strcmp (reg32, "rbx") == 0 || strcmp (reg32, "rsi") == 0 || strcmp (reg32, "rdi") == 0);
+}
+
+static int inline_asm_template_is_out (const char *templ) {
+
+    if (!templ) {
+        return 0;
+    }
+    
+    while (*templ == ' ' || *templ == '\t') {
+        templ++;
+    }
+    
+    return  strncmp (templ, "outb ", 5) == 0 || strncmp (templ, "outw ", 5) == 0 ||
+                strncmp (templ, "outl ", 5) == 0 || strncmp (templ, "out ", 4) == 0;
+
+}
+
+static int inline_asm_is_reg32_name (const char *s, size_t len) {
+
+    return  (len == 3 && strncmp (s, "rax", 3) == 0) ||
+                (len == 3 && strncmp (s, "rbx", 3) == 0) ||
+                    (len == 3 && strncmp (s, "rcx", 3) == 0) ||
+                        (len == 3 && strncmp (s, "rdx", 3) == 0) ||
+                            (len == 3 && strncmp (s, "rsi", 3) == 0) ||
+                                (len == 3 && strncmp (s, "rdi", 3) == 0);
+
+}
+
+static int inline_asm_rewrite_narrow_movzx (char *line, size_t line_size) {
+
+    char rewritten[512];
+    
+    const char *p;
+    const char *reg_start;
+    const char *reg_end;
+    const char *src;
+    
+    size_t reg_len;
+    size_t indent_len;
+    
+    if (!line || line_size == 0 || !(state->syntax & ASM_SYNTAX_INTEL)) {
+        return 0;
+    }
+    
+    p = line;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    indent_len = (size_t) (p - line);
+    
+    if (strncmp (p, "mov", 3) != 0 || (p[3] != ' ' && p[3] != '\t')) {
+        return 0;
+    }
+    
+    p += 3;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    reg_start = p;
+    
+    while ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9')) {
+        p++;
+    }
+    
+    reg_end = p;
+    reg_len = (size_t) (reg_end - reg_start);
+    
+    if (!inline_asm_is_reg32_name (reg_start, reg_len)) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (*p != ',') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    src = p;
+    
+    /**
+     * Only change true narrow memory loads.  This deliberately does not
+     * touch register/register moves, immediates, or lines that have already
+     * been rewritten.
+     */
+    if (strncmp (src, "byte ptr ", 9) != 0 && strncmp (src, "word ptr ", 9) != 0) {
+        return 0;
+    }
+    
+    if (indent_len + 6 + reg_len + 2 + strlen (src) + 1 >= sizeof (rewritten)) {
+        return 0;
+    }
+    
+    memcpy (rewritten, line, indent_len);
+    rewritten[indent_len] = 0;
+    
+    strcat (rewritten, "movzx ");
+    strncat (rewritten, reg_start, reg_len);
+    strcat (rewritten, ", ");
+    strcat (rewritten, src);
+    
+    inline_copy_string (line, rewritten, line_size);
+    return 1;
+
+}
+
+static const char *inline_asm_intel_ptr_name (int size) {
+
+    if (size <= 1) {
+        return "byte";
+    }
+    
+    if (size == 2) {
+        return "word";
+    }
+    
+    if (size == 8) {
+        return "qword";
+    }
+    
+    return "dword";
+
+}
+
+static int inline_asm_format_identifier_operand (char *dst, size_t dst_size, const char *name) {
+
+    struct local_symbol *sym;
+    char memref[64];
+    const char *asm_name;
+    
+    if (!dst || dst_size == 0 || !name || !*name) {
+        return 0;
+    }
+    
+    dst[0] = 0;
+    sym = find_local_symbol (name);
+    
+    if (sym) {
+    
+        if (sym->is_static && sym->static_label) {
+        
+            asm_name = asm_global_symbol_name (sym->static_label);
+            
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                sprintf (dst, (state->syntax & ASM_SYNTAX_NASM ? "%s %s" : "%s ptr %s"), inline_asm_intel_ptr_name (sym->size), asm_name);
+            } else {
+                sprintf (dst, "%s", asm_name);
+            }
+            
+            return 1;
+        
+        }
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            format_intel_rbp_offset (memref, sizeof (memref), sym->offset);
+            sprintf (dst, (state->syntax & ASM_SYNTAX_NASM ? "%s %s" : "%s ptr %s"), inline_asm_intel_ptr_name (sym->size), memref);
+        
+        } else {
+            sprintf (dst, "%ld(%%rbp)", sym->offset);
+        }
+        
+        return 1;
+    
+    }
+    
+    if (find_global_symbol (name) >= 0) {
+    
+        asm_name = asm_global_symbol_name (name);
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            sprintf (dst, (state->syntax & ASM_SYNTAX_NASM ? "%s %s" : "%s ptr %s"), inline_asm_intel_ptr_name (get_global_symbol_size (name)), asm_name);
+        } else {
+            sprintf (dst, "%s", asm_name);
+        }
+        
+        return 1;
+    
+    }
+    
+    return 0;
+
+}
+
+static void inline_asm_emit_input_load (const char *constraint, int input_index, struct inline_asm_input_operand *inputs, const char *templ) {
+
+    char expr_text[64];
+    
+    const char *expr_start;
+    const char *expr_end;
+    const char *reg32;
+    const char *subst;
+    
+    expr_text[0] = 0;
+    expr_start = tok.caret;
+    
+    inputs[input_index].restore_reg = 0;
+    inputs[input_index].restore_name = 0;
+    
+    if (strchr (constraint, 'N')) {
+    
+        if (token_is_integer_constant_now (tok.kind)) {
+        
+            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+            expr_end = tok.caret;
+            
+            inline_asm_copy_trimmed_text (expr_text, sizeof (expr_text), expr_start, expr_end);
+            inline_copy_string (inputs[input_index].subst, expr_text, sizeof (inputs[input_index].subst));
+            
+            return;
+        
+        }
+        
+        if (inline_asm_template_is_out (templ)) {
+        
+            /**
+             * GCC's "N" constraint is really an 8-bit immediate port.
+             * For the OUT templates, allow a non-constant here as a
+             * convenience and lower it through DX, because x86 OUT cannot
+             * encode a variable port as an immediate.
+             */
+            emit_load_assignment_rhs_expression_to_reg ("rdx");
+            inline_copy_string (inputs[input_index].subst, "dx", sizeof (inputs[input_index].subst));
+            
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_IDENT && tok.ident && inline_asm_format_identifier_operand (expr_text, sizeof (expr_text), tok.ident)) {
+        
+            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+            inline_copy_string (inputs[input_index].subst, expr_text, sizeof (inputs[input_index].subst));
+            
+            return;
+        
+        }
+        
+        skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+        expr_end = tok.caret;
+        
+        inline_asm_copy_trimmed_text (expr_text, sizeof (expr_text), expr_start, expr_end);
+        inline_copy_string (inputs[input_index].subst, expr_text, sizeof (inputs[input_index].subst));
+        
+        return;
+    
+    }
+    
+    reg32 = inline_asm_constraint_reg32 (constraint);
+    
+    if (reg32) {
+    
+        subst = inline_asm_reg_for_template (reg32);
+        
+        if (inline_asm_reg_needs_restore (reg32) && state->ofp) {
+        
+            fprintf (state->ofp, "    push %s\n", reg32);
+            
+            inputs[input_index].restore_reg = 1;
+            inputs[input_index].restore_name = reg32;
+        
+        }
+        
+        if (token_is_integer_constant_now (tok.kind)) {
+        
+            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+            expr_end = tok.caret;
+            
+            inline_asm_copy_trimmed_text (expr_text, sizeof (expr_text), expr_start, expr_end);
+            
+            if (state->ofp) {
+                fprintf (state->ofp, "    mov %s, %s\n", subst, expr_text[0] ? expr_text : "0");
+            }
+        
+        } else {
+            emit_load_assignment_rhs_expression_to_reg (reg32);
+        }
+        
+        inline_copy_string (inputs[input_index].subst, subst, sizeof (inputs[input_index].subst));
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_IDENT && tok.ident && inline_asm_format_identifier_operand (expr_text, sizeof (expr_text), tok.ident)) {
+    
+        skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+        inline_copy_string (inputs[input_index].subst, expr_text, sizeof (inputs[input_index].subst));
+        
+        return;
+    
+    }
+    
+    skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+    expr_end = tok.caret;
+    
+    inline_asm_copy_trimmed_text (expr_text, sizeof (expr_text), expr_start, expr_end);
+    inline_copy_string (inputs[input_index].subst, expr_text, sizeof (inputs[input_index].subst));
+
+}
+
+static void inline_asm_emit_template (const char *templ, struct inline_asm_input_operand *inputs, int input_count) {
+
+    char line[512];
+    size_t n = 0;
+    
+    const char *p;
+    
+    if (!state->ofp || !templ) {
+        return;
+    }
+    
+    for (p = templ; *p && n + 1 < sizeof (line); p++) {
+    
+        if (*p == '%' && p[1] == '%') {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                p++;
+            } else {
+            
+                line[n++] = '%';
+                p++;
+            
+            }
+        
+        } else if (*p == '%' && p[1] >= '0' && p[1] <= '9') {
+        
+            int index = p[1] - '0';
+            const char *subst = "";
+            
+            if (index >= 0 && index < input_count) {
+                subst = inputs[index].subst;
+            }
+            
+            while (*subst && n + 1 < sizeof (line)) {
+                line[n++] = *subst++;
+            }
+            
+            p++;
+        
+        } else {
+            line[n++] = *p;
+        }
+    
+    }
+    
+    line[n] = 0;
+    
+    if ((strncmp (line, "outb ", 5) == 0 || strncmp (line, "outw ", 5) == 0 || strncmp (line, "outl ", 5) == 0 || strncmp (line, "out ", 4) == 0)) {
+    
+        char *args;
+        char *comma;
+        char *lhs;
+        char *rhs;
+        
+        args = strchr (line, ' ');
+        
+        if (args) {
+        
+            args++;
+            comma = strchr (args, ',');
+            
+            if (comma) {
+            
+                *comma = 0;
+                
+                lhs = args;
+                rhs = comma + 1;
+                
+                while (*lhs == ' ' || *lhs == '\t') {
+                    lhs++;
+                }
+                
+                while (*rhs == ' ' || *rhs == '\t') {
+                    rhs++;
+                }
+                
+                fprintf (state->ofp, "    out %s, %s\n", rhs, lhs);
+                
+                while (input_count-- > 0) {
+                
+                    if (inputs[input_count].restore_reg && inputs[input_count].restore_name) {
+                        fprintf (state->ofp, "    pop %s\n", inputs[input_count].restore_name);
+                    }
+                
+                }
+                
+                return;
+            
+            }
+        
+        }
+    
+    }
+    
+    if (line[0]) {
+    
+        inline_asm_rewrite_narrow_movzx (line, sizeof (line));
+        fprintf (state->ofp, "    %s\n", line);
+    
+    }
+    
+    while (input_count-- > 0) {
+    
+        if (inputs[input_count].restore_reg && inputs[input_count].restore_name) {
+            fprintf (state->ofp, "    pop %s\n", inputs[input_count].restore_name);
+        }
+    
+    }
+
+}
+
+static int parse_inline_asm_statement (void) {
+
+    char templ[256];
+    
+    struct inline_asm_input_operand inputs[MAX_INLINE_ASM_INPUTS];
+    int input_count = 0;
+    
+    if (tok.kind != TOK_ASM) {
+        return 0;
+    }
+    
+    memset (inputs, 0, sizeof (inputs));
+    
+    get_token ();
+    expect (TOK_LPAREN, "(");
+    
+    if (!is_string_token ()) {
+    
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected asm template string");
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect (TOK_SEMI, ";");
+        
+        return 1;
+    
+    }
+    
+    inline_asm_unquote_string_token (templ, sizeof (templ));
+    get_token ();
+    
+    if (_accept (TOK_COLON)) {
+    
+        if (tok.kind != TOK_COLON) {
+            skip_balanced_until (TOK_COLON, TOK_RPAREN, TOK_EOF);
+        }
+        
+        if (_accept (TOK_COLON)) {
+        
+            while (tok.kind != TOK_RPAREN && tok.kind != TOK_EOF) {
+            
+                char constraint[16];
+                
+                if (!is_string_token ()) {
+                
+                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected asm input constraint string");
+                    
+                    skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+                    break;
+                
+                }
+                
+                inline_asm_unquote_string_token (constraint, sizeof (constraint));
+                get_token ();
+                
+                expect (TOK_LPAREN, "(");
+                
+                if (input_count < MAX_INLINE_ASM_INPUTS) {
+                
+                    inline_copy_string (inputs[input_count].constraint, constraint, sizeof (inputs[input_count].constraint));
+                    inline_asm_emit_input_load (constraint, input_count, inputs, templ);
+                    
+                    input_count++;
+                
+                } else {
+                    skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+                }
+                
+                expect (TOK_RPAREN, ")");
+                
+                if (!_accept (TOK_COMMA)) {
+                    break;
+                }
+            
+            }
+        
+        }
+    
+    }
+    
+    expect (TOK_RPAREN, ")");
+    expect (TOK_SEMI, ";");
+    
+    inline_asm_emit_template (templ, inputs, input_count);
+    return 1;
+
+}
+
+static int token_is_const_condition_operand_now (void) {
+    return token_is_sizeof_keyword () || token_is_integer_constant_now (tok.kind);
+}
+
+static int token_is_const_floating_condition_operand_now (void) {
+    return token_is_floating_constant_now ();
+}
+
+static void emit_statement_const32_to_rdx (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_rdx_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_rdx (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_rdx (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 == '_';
+}
+
+static int ident_start_now (int ch) {
+    return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '_';
+}
+
+static int prefix_incdec_target_is_floating_now (void) {
+
+    const char *p;
+    const char *q;
+    
+    char *name;
+    int len;
+    
+    struct local_symbol *src;
+    int ret = 0;
+    
+    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
+        return 0;
+    }
+    
+    p = tok.caret;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!ident_start_now ((unsigned char) *p)) {
+        return 0;
+    }
+    
+    q = p + 1;
+    
+    while (ident_char_now ((unsigned char) *q)) {
+        q++;
+    }
+    
+    len = (int) (q - p);
+    name = xmalloc ((unsigned long) len + 1);
+    
+    memcpy (name, p, (unsigned long) len);
+    name[len] = 0;
+    
+    src = find_local_symbol (name);
+    
+    if (src) {
+        ret = src->is_floating ? 1 : 0;
+    } else if (find_global_symbol (name) >= 0) {
+        ret = get_global_symbol_floating (name) ? 1 : 0;
+    }
+    
+    free (name);
+    return ret;
+
+}
+
+static int source_parenthesized_floating_condition_now (const char *p) {
+
+    char name[128];
+    int i;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (*p != '(') {
+        return 0;
+    }
+    
+    while (*p == '(' || *p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    i = 0;
+    
+    while (((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') && i < (int) sizeof (name) - 1) {
+        name[i++] = *p++;
+    }
+    
+    name[i] = 0;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (*p == '.') {
+        return 0;
+    }
+    
+    if (*p == '(' && find_global_symbol (name) >= 0 && get_global_symbol_floating (name)) {
+        return 1;
+    }
+    
+    /*
+     * Parenthrsized floating conditions such as:
+     *
+     *     if (num < 0)
+     *     while (b >= 10.0)
+     *
+     * arrive here while TOK_LPAREN is still current.  If we don't recognise
+     * the name inside the parens as floating, the generic parenthesized
+     * integer path consumes the expression and compares only the low dword.
+     */
+    if (find_local_symbol (name)) {
+    
+        struct local_symbol *src = find_local_symbol (name);
+        return src && src->is_floating ? 1 : 0;
+    
+    }
+    
+    if (find_global_symbol (name) >= 0) {
+        return get_global_symbol_floating (name) ? 1 : 0;
+    }
+    
+    return 0;
+
+}
+
+static int source_va_arg_type_is_double_now (const char *p) {
+
+    int paren;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '(') {
+        return 0;
+    }
+    
+    paren = 0;
+    
+    while (*p) {
+    
+        if (*p == '(') {
+            paren++;
+        } else if (*p == ')') {
+        
+            paren--;
+            
+            if (paren == 0) {
+                return 0;
+            }
+        
+        } else if (paren == 1 && *p == ',') {
+        
+            p++;
+            
+            while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+                p++;
+            }
+            
+            if (strncmp (p, "double", 6) == 0 &&
+                !(p[6] == '_' || (p[6] >= '0' && p[6] <= '9') ||
+                  (p[6] >= 'A' && p[6] <= 'Z') ||
+                  (p[6] >= 'a' && p[6] <= 'z'))) {
+                return 1;
+            }
+        
+        }
+        
+        p++;
+    
+    }
+    
+    return 0;
+
+}
+
+static int rhs_current_operand_is_floating_now (void) {
+
+    if (token_is_floating_constant_now ()) {
+        return 1;
+    }
+    
+    if (tok.kind == TOK_SCC_BUILTIN_VA_ARG) {
+    
+        const char *p = tok.caret ? tok.caret + tok.len : 0;
+        
+        if (source_va_arg_type_is_double_now (p)) {
+            return 1;
+        }
+    
+    }
+    
+    if (tok.kind == TOK_LPAREN && (source_parenthesized_floating_condition_now (tok.caret) || source_parenthesized_floating_condition_now (tok.start))) {
+        return 1;
+    }
+    
+    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+        return prefix_incdec_target_is_floating_now ();
+    }
+    
+    if (tok.kind == TOK_IDENT && tok.ident) {
+    
+        struct local_symbol *src = find_local_symbol (tok.ident);
+        const char *p = tok.caret ? tok.caret + tok.len : 0;
+        
+        while (p && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')) {
+            p++;
+        }
+        
+        if (strcmp (tok.ident, "__scc_builtin_va_arg") == 0 && source_va_arg_type_is_double_now (p)) {
+            return 1;
+        }
+        
+        if (p && *p == '(' && find_global_symbol (tok.ident) >= 0) {
+            return get_global_function_returns_floating (tok.ident) ? 1 : 0;
+        }
+        
+        if (p && ((p[0] == '-' && p[1] == '>') || p[0] == '.')) {
+        
+            const char *q = p + (p[0] == '-' ? 2 : 1);
+            char member[128];
+            
+            int n = 0;
+            int offset = 0;
+            int size = 0;
+            int elem_size = 0;
+            int pointer_depth = 0;
+            int is_array = 0;
+            int is_floating = 0;
+            int base_size = 0;
+            
+            const char *base_tag_name = 0;
+            
+            while (*q == ' ' || *q == '\t' || *q == '\r' || *q == '\n') {
+                q++;
+            }
+            
+            while (((*q >= 'A' && *q <= 'Z') || (*q >= 'a' && *q <= 'z') || (*q >= '0' && *q <= '9') || *q == '_') && n < (int) sizeof (member) - 1) {
+                member[n++] = *q++;
+            }
+            
+            member[n] = '\0';
+            
+            if (n > 0) {
+            
+                if (p[0] == '-') {
+                
+                    if (src) {
+                    
+                        base_size = src->pointed_size;
+                        base_tag_name = src->pointed_tag_name;
+                    
+                    } else if (find_global_symbol (tok.ident) >= 0) {
+                    
+                        base_size = get_global_symbol_pointed_size (tok.ident);
+                        base_tag_name = get_global_symbol_tag_name (tok.ident);
+                    
+                    }
+                
+                } else {
+                
+                    if (src) {
+                    
+                        base_size = src->size;
+                        base_tag_name = src->tag_name;
+                    
+                    } else if (find_global_symbol (tok.ident) >= 0) {
+                    
+                        base_size = get_global_symbol_size (tok.ident);
+                        base_tag_name = get_global_symbol_tag_name (tok.ident);
+                    
+                    }
+                
+                }
+                
+                if (find_member_info_ex_bounded (member, base_size, base_tag_name, &offset, &size, &elem_size, &pointer_depth, &is_array, &is_floating)) {
+                    return is_floating ? 1 : 0;
+                }
+            
+            }
+        
+        }
+        
+        if (src) {
+            return src->is_floating ? 1 : 0;
+        }
+        
+        if (find_global_symbol (tok.ident) >= 0) {
+            return get_global_function_returns_floating (tok.ident) ? 1 : 0;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int64_s floating_ld_to_bits_now (int size, double value) {
+
+    int64_s r;
+    
+    unsigned long bits32;
+    unsigned char bytes[8];
+    
+    int i;
+    
+    r.low = 0;
+    r.high = 0;
+    
+    if (size == (DATA_FLOAT & 0x1f)) {
+    
+        float f = (float) value;
+        
+        bits32 = 0;
+        
+        memcpy (&bits32, &f, sizeof (f));
+        r.low = bits32;
+        
+        return r;
+    
+    }
+    
+    {
+    
+        double d = (double) value;
+        
+        memset (bytes, 0, sizeof (bytes));
+        memcpy (bytes, &d, sizeof (d));
+        
+        for (i = 0; i < 4; i++) {
+            r.low |= ((unsigned long) bytes[i]) << (i * 8);
+        }
+        
+        for (i = 0; i < 4; i++) {
+            r.high |= ((unsigned long) bytes[i + 4]) << (i * 8);
+        }
+        
+        return r;
+    
+    }
+
+}
+
+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));
+}
+
+static int int64_statement_truth_value (int64_s v) {
+    return v.low != 0 || v.high != 0;
+}
+
+static long statement_int64_signed_high (int64_s v) {
+
+    unsigned long h = v.high & U32_MASK;
+    
+    if (h & 0x80000000UL) {
+        return -((long) ((~h + 1UL) & U32_MASK));
+    }
+    
+    return (long) h;
+
+}
+
+static int statement_cmp_const64_unsigned (int64_s left, int64_s right) {
+
+    unsigned long lh = left.high & U32_MASK;
+    unsigned long rh = right.high & U32_MASK;
+    unsigned long ll = left.low & U32_MASK;
+    unsigned long rl = right.low & U32_MASK;
+    
+    if (lh < rh) return -1;
+    if (lh > rh) return 1;
+    if (ll < rl) return -1;
+    if (ll > rl) return 1;
+    
+    return 0;
+
+}
+
+static int statement_cmp_const64_signed (int64_s left, int64_s right) {
+
+    long lh = statement_int64_signed_high (left);
+    long rh = statement_int64_signed_high (right);
+    
+    unsigned long ll = left.low & U32_MASK;
+    unsigned long rl = right.low & U32_MASK;
+
+    if (lh < rh) return -1;
+    if (lh > rh) return 1;
+    if (ll < rl) return -1;
+    if (ll > rl) return 1;
+    
+    return 0;
+
+}
+
+static int statement_compare_const64_true (int64_s left, enum token_kind op, int64_s right, int is_unsigned) {
+
+    int c = is_unsigned ? statement_cmp_const64_unsigned (left, right) : statement_cmp_const64_signed (left, right);
+    
+    switch (op) {
+    
+        case TOK_LESS:
+        
+            return c < 0;
+        
+        case TOK_LTEQ:
+        
+            return c <= 0;
+        
+        case TOK_GREATER:
+        
+            return c > 0;
+        
+        case TOK_GTEQ:
+        
+            return c >= 0;
+        
+        case TOK_EQEQ:
+        
+            return c == 0;
+        
+        case TOK_NOTEQ:
+        
+            return c != 0;
+        
+        default:
+        
+            return int64_statement_truth_value (left);
+    
+    }
+
+}
+
+static int rhs_current_operand_is_unsigned_now (void) {
+
+    if (token_is_sizeof_keyword ()) {
+        return 1;
+    }
+    
+    if (token_is_integer_unsigned_constant_now (tok.kind)) {
+        return 1;
+    }
+    
+    if (tok.kind == TOK_IDENT && tok.ident) {
+    
+        struct local_symbol *src = find_local_symbol (tok.ident);
+        
+        if (src) {
+            return src->is_unsigned ? 1 : 0;
+        }
+        
+        if (find_global_symbol (tok.ident) >= 0) {
+            return get_global_symbol_unsigned (tok.ident) ? 1 : 0;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int token_is_statement_compare_operator (enum token_kind k) {
+
+    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_rax_rdx_jump_if_false (enum token_kind op, int is_unsigned, int label);
+static int statement_condition_emit_logical_tail (int label);
+
+static void emit_statement_jump_if_false (int label);
+static int emit_statement_cmp_rax_rdx_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];
+    
+    const char *p;
+    int i;
+    
+    int64_s ignored;
+    
+    if (!pp || !*pp) {
+        return 0;
+    }
+    
+    p = *pp;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    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_rdx_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_rdx (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_rdx (v);
+        return 1;
+    
+    }
+    
+    return 0;
+
+}
+
+static int source_condition_logical_rhs_is_enum_compare_now (const char *p) {
+
+    if (!p) {
+        return 0;
+    }
+    
+    for (;;) {
+    
+        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;
+        }
+        
+        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+            p++;
+        }
+        
+        if (source_condition_tail_end_now (p)) {
+            return 1;
+        }
+        
+        if (!((p[0] == '&' && p[1] == '&') || (p[0] == '|' && p[1] == '|'))) {
+            return 0;
+        }
+    
+    }
+
+}
+
+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 rax, TOK_ASSIGN; test rax, rax".  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;
+    }
+    
+    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;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    /*
+     * 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 rax, <enum>; test rax,rax".
+     */
+    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;
+    }
+    
+    name_len = (int) strlen (tok.ident);
+    p = source_find_current_ident_on_line (p);
+    
+    if (!p) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        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;
+    }
+    
+    is_unsigned = rhs_current_operand_is_unsigned_now ();
+    emit_load_assignment_rhs_to_reg ("rax");
+    
+    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+        emit_apply_postfix_member_access_to_reg_now ("rax");
+    }
+    
+    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_rdx_if_possible ()) {
+    
+        emit_push_reg_now ("rax");
+        emit_load_assignment_compare_expression_to_reg ("rdx");
+        emit_pop_reg_now ("rax");
+    
+    }
+    
+    emit_statement_cmp_rax_rdx_jump_if_false_and_tail (op, is_unsigned, label);
+    return 1;
+
+}
+
+static int emit_statement_ident_enum_compare_jump_if_false_now (int label) {
+
+    enum token_kind op;
+    int is_unsigned;
+    
+    if (!source_condition_ident_enum_compare_now (tok.caret) && !source_condition_ident_enum_compare_now (tok.start)) {
+        return 0;
+    }
+    
+    is_unsigned = rhs_current_operand_is_unsigned_now ();
+    emit_load_assignment_rhs_to_reg ("rax");
+    
+    if (!token_is_statement_compare_operator (tok.kind)) {
+        return 0;
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    /*
+     * 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 rax, TOK_MINUS
+     *     test rax, rax
+     *
+     * 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_rdx_if_possible ()) {
+        return 0;
+    }
+    
+    emit_statement_cmp_rax_rdx_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 ("rax");
+    
+    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+        emit_apply_postfix_member_access_to_reg_now ("rax");
+    }
+    
+    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_or_enum_to_rdx_if_possible ()) {
+        return 0;
+    }
+    
+    emit_statement_cmp_rax_rdx_jump_if_false_and_tail (op, is_unsigned, label);
+    return 1;
+
+}
+
+static int statement_condition_ident_call_at (const char *p) {
+
+    int len;
+    
+    if (tok.kind != TOK_IDENT || !tok.ident || !p) {
+        return 0;
+    }
+    
+    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) len) == 0 && !ident_char_now ((unsigned char) p[len])) {
+        
+            p += len;
+            
+            while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+                p++;
+            }
+            
+            return *p == '(';
+        
+        }
+        
+        p++;
+    
+    }
+    
+    return 0;
+
+}
+
+static int statement_condition_starts_with_ident_call_now (void) {
+
+    if (statement_condition_ident_call_at (tok.caret)) {
+        return 1;
+    }
+    
+    if (statement_condition_ident_call_at (tok.start)) {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static const char *statement_false_jump_mnemonic (enum token_kind op, int is_unsigned) {
+
+    switch (op) {
+    
+        case TOK_LESS:
+        
+            return is_unsigned ? "jae" : "jge";
+        
+        case TOK_LTEQ:
+        
+            return is_unsigned ? "ja"  : "jg";
+        
+        case TOK_GREATER:
+        
+            return is_unsigned ? "jbe" : "jle";
+        
+        case TOK_GTEQ:
+        
+            return is_unsigned ? "jb"  : "jl";
+        
+        case TOK_EQEQ:
+        
+            return "jne";
+        
+        case TOK_NOTEQ:
+        
+            return "je";
+        
+        default:
+        
+            return "jz";
+    
+    }
+
+}
+
+static void emit_statement_const32_to_rax (int64_s v) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    mov eax, %lu\n", v.low & U32_MASK);
+    } else {
+        fprintf (state->ofp, "    movl $%lu, %%eax\n", v.low & U32_MASK);
+    }
+
+}
+
+static void emit_statement_cmp_rax_rdx_jump_if_false (enum token_kind op, int is_unsigned, int label) {
+
+    const char *jmp;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    jmp = statement_false_jump_mnemonic (op, is_unsigned);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    cmp rax, rdx\n");
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    %s L%d\n" : "    %s .L%d\n"), jmp, label);
+    
+    } else {
+    
+        fprintf (state->ofp, "    cmpq %%rdx, %%rax\n");
+        fprintf (state->ofp, "    %s .L%d\n", jmp, label);
+    
+    }
+
+}
+
+static void emit_statement_cmp64_to_rax (enum token_kind op, int is_unsigned) {
+
+    int true_label;
+    int false_label;
+    int end_label;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    true_label = anon_label++;
+    false_label = anon_label++;
+    end_label = anon_label++;
+    
+    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+    
+        switch (op) {
+        
+            case TOK_LESS:
+            
+                fprintf (state->ofp, "    cmp rdx, rcx\n");
+                fprintf (state->ofp, is_unsigned ? "    jb L%d\n" : "    jl L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    ja L%d\n" : "    jg L%d\n", false_label);
+                fprintf (state->ofp, "    cmp rax, rbx\n");
+                fprintf (state->ofp, "    jb L%d\n", true_label);
+                break;
+            
+            case TOK_LTEQ:
+            
+                fprintf (state->ofp, "    cmp rdx, rcx\n");
+                fprintf (state->ofp, is_unsigned ? "    jb L%d\n" : "    jl L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    ja L%d\n" : "    jg L%d\n", false_label);
+                fprintf (state->ofp, "    cmp rax, rbx\n");
+                fprintf (state->ofp, "    jbe L%d\n", true_label);
+                break;
+            
+            case TOK_GREATER:
+            
+                fprintf (state->ofp, "    cmp rdx, rcx\n");
+                fprintf (state->ofp, is_unsigned ? "    ja L%d\n" : "    jg L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    jb L%d\n" : "    jl L%d\n", false_label);
+                fprintf (state->ofp, "    cmp rax, rbx\n");
+                fprintf (state->ofp, "    ja L%d\n", true_label);
+                break;
+            
+            case TOK_GTEQ:
+            
+                fprintf (state->ofp, "    cmp rdx, rcx\n");
+                fprintf (state->ofp, is_unsigned ? "    ja L%d\n" : "    jg L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    jb L%d\n" : "    jl L%d\n", false_label);
+                fprintf (state->ofp, "    cmp rax, rbx\n");
+                fprintf (state->ofp, "    jae L%d\n", true_label);
+                break;
+            
+            case TOK_EQEQ:
+            
+                fprintf (state->ofp, "    cmp rdx, rcx\n");
+                fprintf (state->ofp, "    jne L%d\n", false_label);
+                fprintf (state->ofp, "    cmp rax, rbx\n");
+                fprintf (state->ofp, "    je L%d\n", true_label);
+                break;
+            
+            case TOK_NOTEQ:
+            
+                fprintf (state->ofp, "    cmp rdx, rcx\n");
+                fprintf (state->ofp, "    jne L%d\n", true_label);
+                fprintf (state->ofp, "    cmp rax, rbx\n");
+                fprintf (state->ofp, "    jne L%d\n", true_label);
+                break;
+            
+            default:
+            
+                fprintf (state->ofp, "    test rdx, rdx\n");
+                fprintf (state->ofp, "    jnz L%d\n", true_label);
+                fprintf (state->ofp, "    test rax, rax\n");
+                fprintf (state->ofp, "    jnz L%d\n", true_label);
+                break;
+        
+        }
+        
+        fprintf (state->ofp, "L%d:\n", false_label);
+        fprintf (state->ofp, "    xor rax, rax\n");
+        fprintf (state->ofp, "    jmp L%d\n", end_label);
+        fprintf (state->ofp, "L%d:\n", true_label);
+        fprintf (state->ofp, "    mov eax, 1\n");
+        fprintf (state->ofp, "L%d:\n", end_label);
+    
+    } else if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        switch (op) {
+        
+            case TOK_LESS:
+            
+                fprintf (state->ofp, "    cmp rdx, rcx\n");
+                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", false_label);
+                fprintf (state->ofp, "    cmp rax, rbx\n");
+                fprintf (state->ofp, "    jb .L%d\n", true_label);
+                break;
+            
+            case TOK_LTEQ:
+            
+                fprintf (state->ofp, "    cmp rdx, rcx\n");
+                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", false_label);
+                fprintf (state->ofp, "    cmp rax, rbx\n");
+                fprintf (state->ofp, "    jbe .L%d\n", true_label);
+                break;
+            
+            case TOK_GREATER:
+            
+                fprintf (state->ofp, "    cmp rdx, rcx\n");
+                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", false_label);
+                fprintf (state->ofp, "    cmp rax, rbx\n");
+                fprintf (state->ofp, "    ja .L%d\n", true_label);
+                break;
+            
+            case TOK_GTEQ:
+            
+                fprintf (state->ofp, "    cmp rdx, rcx\n");
+                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", false_label);
+                fprintf (state->ofp, "    cmp rax, rbx\n");
+                fprintf (state->ofp, "    jae .L%d\n", true_label);
+                break;
+            
+            case TOK_EQEQ:
+            
+                fprintf (state->ofp, "    cmp rdx, rcx\n");
+                fprintf (state->ofp, "    jne .L%d\n", false_label);
+                fprintf (state->ofp, "    cmp rax, rbx\n");
+                fprintf (state->ofp, "    je .L%d\n", true_label);
+                break;
+            
+            case TOK_NOTEQ:
+            
+                fprintf (state->ofp, "    cmp rdx, rcx\n");
+                fprintf (state->ofp, "    jne .L%d\n", true_label);
+                fprintf (state->ofp, "    cmp rax, rbx\n");
+                fprintf (state->ofp, "    jne .L%d\n", true_label);
+                break;
+            
+            default:
+            
+                fprintf (state->ofp, "    test rdx, rdx\n");
+                fprintf (state->ofp, "    jnz .L%d\n", true_label);
+                fprintf (state->ofp, "    test rax, rax\n");
+                fprintf (state->ofp, "    jnz .L%d\n", true_label);
+                break;
+        
+        }
+        
+        fprintf (state->ofp, ".L%d:\n", false_label);
+        fprintf (state->ofp, "    xor rax, rax\n");
+        fprintf (state->ofp, "    jmp .L%d\n", end_label);
+        fprintf (state->ofp, ".L%d:\n", true_label);
+        fprintf (state->ofp, "    mov eax, 1\n");
+        fprintf (state->ofp, ".L%d:\n", end_label);
+    
+    } else {
+    
+        switch (op) {
+        
+            case TOK_LESS:
+            
+                fprintf (state->ofp, "    cmpq %%rcx, %%rdx\n");
+                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", false_label);
+                fprintf (state->ofp, "    cmpq %%rbx, %%rax\n");
+                fprintf (state->ofp, "    jb .L%d\n", true_label);
+                break;
+            
+            case TOK_LTEQ:
+            
+                fprintf (state->ofp, "    cmpq %%rcx, %%rdx\n");
+                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", false_label);
+                fprintf (state->ofp, "    cmpq %%rbx, %%rax\n");
+                fprintf (state->ofp, "    jbe .L%d\n", true_label);
+                break;
+            
+            case TOK_GREATER:
+            
+                fprintf (state->ofp, "    cmpq %%rcx, %%rdx\n");
+                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", false_label);
+                fprintf (state->ofp, "    cmpq %%rbx, %%rax\n");
+                fprintf (state->ofp, "    ja .L%d\n", true_label);
+                break;
+            
+            case TOK_GTEQ:
+            
+                fprintf (state->ofp, "    cmpq %%rcx, %%rdx\n");
+                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", false_label);
+                fprintf (state->ofp, "    cmpq %%rbx, %%rax\n");
+                fprintf (state->ofp, "    jae .L%d\n", true_label);
+                break;
+            
+            case TOK_EQEQ:
+            
+                fprintf (state->ofp, "    cmpq %%rcx, %%rdx\n");
+                fprintf (state->ofp, "    jne .L%d\n", false_label);
+                fprintf (state->ofp, "    cmpq %%rbx, %%rax\n");
+                fprintf (state->ofp, "    je .L%d\n", true_label);
+                break;
+            
+            case TOK_NOTEQ:
+            
+                fprintf (state->ofp, "    cmpq %%rcx, %%rdx\n");
+                fprintf (state->ofp, "    jne .L%d\n", true_label);
+                fprintf (state->ofp, "    cmpq %%rbx, %%rax\n");
+                fprintf (state->ofp, "    jne .L%d\n", true_label);
+                break;
+            
+            default:
+            
+                fprintf (state->ofp, "    testq %%rdx, %%rdx\n");
+                fprintf (state->ofp, "    jnz .L%d\n", true_label);
+                fprintf (state->ofp, "    testq %%rax, %%rax\n");
+                fprintf (state->ofp, "    jnz .L%d\n", true_label);
+                break;
+        
+        }
+        
+        fprintf (state->ofp, ".L%d:\n", false_label);
+        fprintf (state->ofp, "    xorq %%rax, %%rax\n");
+        fprintf (state->ofp, "    jmp .L%d\n", end_label);
+        fprintf (state->ofp, ".L%d:\n", true_label);
+        fprintf (state->ofp, "    movl $1, %%eax\n");
+        fprintf (state->ofp, ".L%d:\n", end_label);
+    
+    }
+
+}
+
+static const char *statement_float_false_jump_mnemonic (enum token_kind op) {
+
+    switch (op) {
+    
+        case TOK_LESS:
+        
+            return "jae";
+        
+        case TOK_LTEQ:
+        
+            return "ja";
+        
+        case TOK_GREATER:
+        
+            return "jbe";
+        
+        case TOK_GTEQ:
+        
+            return "jb";
+        
+        case TOK_EQEQ:
+        
+            return "jne";
+        
+        case TOK_NOTEQ:
+        
+            return "je";
+        
+        default:
+        
+            return "jz";
+    
+    }
+
+}
+
+static void emit_statement_floating_compare_jump_if_false (enum token_kind op, int label) {
+
+    const char *jmp;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    jmp = statement_float_false_jump_mnemonic (op);
+    
+    if (state->syntax & ASM_SYNTAX_NASM) {
+    
+        fprintf (state->ofp, "    fxch st1\n");
+        fprintf (state->ofp, "    fcompp\n");
+        fprintf (state->ofp, "    fnstsw ax\n");
+        fprintf (state->ofp, "    sahf\n");
+        fprintf (state->ofp, "    %s L%d\n", jmp, label);
+    
+    } else if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    fxch st(1)\n");
+        fprintf (state->ofp, "    fcompp\n");
+        fprintf (state->ofp, "    fnstsw ax\n");
+        fprintf (state->ofp, "    sahf\n");
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    %s L%d\n" : "    %s .L%d\n"), jmp, label);
+    
+    } else {
+    
+        fprintf (state->ofp, "    fxch %%st(1)\n");
+        fprintf (state->ofp, "    fcompp\n");
+        fprintf (state->ofp, "    fnstsw %%ax\n");
+        fprintf (state->ofp, "    sahf\n");
+        fprintf (state->ofp, "    %s .L%d\n", jmp, label);
+    
+    }
+
+}
+
+static int statement_compare_floating_const_true (double left, enum token_kind op, double right) {
+
+    switch (op) {
+    
+        case TOK_LESS:
+        
+            return left < right;
+        
+        case TOK_LTEQ:
+        
+            return left <= right;
+        
+        case TOK_GREATER:
+        
+            return left > right;
+        
+        case TOK_GTEQ:
+        
+            return left >= right;
+        
+        case TOK_EQEQ:
+        
+            return left == right;
+        
+        case TOK_NOTEQ:
+        
+            return left != right;
+        
+        default:
+        
+            return left != 0.0;
+    
+    }
+
+}
+
+static void emit_statement_test_rax_jump_if_false (int label) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    test rax, rax\n");
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jz L%d\n" : "    jz .L%d\n"), label);
+    
+    } else {
+    
+        fprintf (state->ofp, "    testq %%rax, %%rax\n");
+        fprintf (state->ofp, "    jz .L%d\n", label);
+    
+    }
+
+}
+
+static void emit_statement_test_pair_jump_if_false (const char *lo, const char *hi, int label) {
+
+    int nonzero_label;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    nonzero_label = anon_label++;
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    test %s, %s\n", hi, hi);
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), nonzero_label);
+        fprintf (state->ofp, "    test %s, %s\n", lo, lo);
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jz L%d\n" : "    jz .L%d\n"), label);
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), nonzero_label);
+    
+    } else {
+    
+        fprintf (state->ofp, "    testq %%%s, %%%s\n", hi, hi);
+        fprintf (state->ofp, "    jnz .L%d\n", nonzero_label);
+        fprintf (state->ofp, "    testq %%%s, %%%s\n", lo, lo);
+        fprintf (state->ofp, "    jz .L%d\n", label);
+        fprintf (state->ofp, ".L%d:\n", nonzero_label);
+    
+    }
+
+}
+
+static void emit_statement_test_pair_jump_if_true (const char *lo, const char *hi, int label) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    test %s, %s\n", hi, hi);
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), label);
+        fprintf (state->ofp, "    test %s, %s\n", lo, lo);
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), label);
+    
+    } else {
+    
+        fprintf (state->ofp, "    testq %%%s, %%%s\n", hi, hi);
+        fprintf (state->ofp, "    jnz .L%d\n", label);
+        fprintf (state->ofp, "    testq %%%s, %%%s\n", lo, lo);
+        fprintf (state->ofp, "    jnz .L%d\n", label);
+    
+    }
+
+}
+
+static int statement_condition_constant_known = 0;
+static int statement_condition_constant_value = 0;
+
+static void parse_statement (void);
+static void parse_statement_suppressed (void);
+static void emit_statement_jump_if_false (int label);
+
+static void replay_tmp_file_to_output (FILE *tmp, FILE *out) {
+
+    int ch;
+    
+    if (!tmp || !out) {
+        return;
+    }
+    
+    fflush (tmp);
+    fseek (tmp, 0, SEEK_SET);
+    
+    while ((ch = fgetc (tmp)) != EOF) {
+        fputc (ch, out);
+    }
+
+}
+
+static void parse_for_header_expression_until (enum token_kind end_token) {
+
+    char *name;
+    int global_index;
+    
+    const char *name_start, *name_caret;
+    unsigned long name_line;
+    
+    enum token_kind op;
+    struct local_symbol *lhs;
+    
+    int lhs_size;
+    int lhs_is_floating;
+    
+#define     FINISH_FOR_HEADER_EXPR(free_name)                                   \
+    do {                                                                        \
+        if (tok.kind == TOK_COMMA) {                                            \
+            get_token ();                                                       \
+            if (free_name) {                                                    \
+                free (name);                                                    \
+            }                                                                   \
+            parse_for_header_expression_until (end_token);                      \
+            return;                                                             \
+        }                                                                       \
+        if (tok.kind != end_token) {                                            \
+            skip_balanced_until (end_token, TOK_EOF, TOK_EOF);                  \
+        }                                                                       \
+        expect (end_token, end_token == TOK_SEMI ? ";" : ")");                  \
+        if (free_name) {                                                        \
+            free (name);                                                        \
+        }                                                                       \
+        return;                                                                 \
+    } while (0)
+    
+    if (tok.kind == end_token) {
+        return;
+    }
+    
+    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+    
+        op = tok.kind;
+        get_token ();
+        
+        if (tok.kind == TOK_IDENT) {
+        
+            name = xstrdup (tok.ident);
+            name_start = tok.start;
+            name_caret = tok.caret;
+            name_line = get_line_number ();
+            get_token ();
+            
+            lhs = find_local_symbol (name);
+            emit_incdec_symbol_now (lhs, name, op, name_line, name_start, name_caret);
+            free (name);
+        
+        } else {
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after %s", op == TOK_INCR ? "++" : "--");
+        }
+        
+        FINISH_FOR_HEADER_EXPR (0);
+    
+    }
+    
+    if (tok.kind != TOK_IDENT) {
+    
+        if (state->ofp) {
+            emit_load_assignment_rhs_expression_to_reg ("rax");
+        } else {
+            skip_balanced_until (end_token, TOK_EOF, TOK_EOF);
+        }
+        
+        FINISH_FOR_HEADER_EXPR (0);
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    get_token ();
+    
+    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+    
+        op = tok.kind;
+        get_token ();
+        
+        lhs = find_local_symbol (name);
+        emit_incdec_symbol_now (lhs, name, op, name_line, name_start, name_caret);
+        
+        FINISH_FOR_HEADER_EXPR (1);
+    
+    }
+    
+    if (tok.kind == TOK_LPAREN) {
+    
+        if (!find_local_symbol (name)) {
+            ensure_global_function_symbol (name, name_start, name_caret, name_line);
+        }
+        
+        emit_call_identifier_to_reg_now (name, "rax", name_start, name_caret, name_line);
+        FINISH_FOR_HEADER_EXPR (1);
+    
+    }
+    
+    if (!is_assignment_operator (tok.kind)) {
+    
+        if (!find_local_symbol (name) && find_global_symbol (name) < 0) {
+        
+            int64_s ignored;
+            
+            if (!resolve_enum_constant (name, &ignored)) {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            }
+        
+        }
+        
+        if (tok.kind == TOK_COMMA) {
+        
+            get_token ();
+            free (name);
+            
+            parse_for_header_expression_until (end_token);
+            return;
+        
+        }
+        
+        skip_balanced_until (end_token, TOK_EOF, TOK_EOF);
+        expect (end_token, end_token == TOK_SEMI ? ";" : ")");
+        
+        free (name);
+        return;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    lhs = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (!lhs && global_index < 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        FINISH_FOR_HEADER_EXPR (1);
+    
+    }
+    
+    if (state->ofp) {
+    
+        lhs_size = lhs ? lhs->size : get_global_symbol_size (name);
+        lhs_is_floating = lhs ? lhs->is_floating : get_global_symbol_floating (name);
+        
+        if (lhs_is_floating) {
+        
+            if (!floating_assignment_operator_supported_now (op)) {
+            
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid operands to floating assignment operator");
+                skip_balanced_until (end_token, TOK_EOF, TOK_EOF);
+            
+            } else {
+            
+                if (op == TOK_ASSIGN) {
+                    emit_load_floating_rhs_expression_now (lhs_size);
+                } else {
+                
+                    emit_load_floating_symbol_now (lhs, name, lhs_size);
+                    emit_load_floating_rhs_expression_now (lhs_size);
+                    emit_floating_binary_now (op);
+                
+                }
+                
+                emit_store_floating_symbol_now (lhs, name, lhs_size);
+            
+            }
+        
+        } else if (lhs_size == (DATA_LLONG & 0x1f)) {
+        
+            if (op == TOK_ASSIGN) {
+                emit_load_assignment_rhs_expression_to_pair ("rax", "rdx", lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
+            } else {
+            
+                if (lhs) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_global64_to_pair ("rax", "rdx", lhs->static_label);
+                    } else {
+                        emit_load_local64_to_pair (lhs->offset, "rax", "rdx");
+                    }
+                
+                } else {
+                    emit_load_global64_to_pair ("rax", "rdx", name);
+                }
+                
+                /*
+                 * Compound assignments need the complete RHS expression.
+                 * Using emit_load_assignment_rhs_to_pair() only consumes one
+                 * primary operand, so e.g.
+                 *
+                 *     final_value += symbol->frag->address + left_value;
+                 *
+                 * leaves the second + operand for the statement parser and
+                 * reports "expected ;".  Evaluate the full RHS in rax:rdx,
+                 * copy it to the RHS pair rbx:rcx, then restore the original
+                 * LHS value before applying the compound operator.
+                 */
+                emit_push_reg_now ("rax");
+                emit_push_reg_now ("rdx");
+                
+                emit_load_assignment_rhs_expression_to_pair ("rax", "rdx", lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
+                
+                emit_mov_reg_to_reg_now ("rbx", "rax");
+                emit_mov_reg_to_reg_now ("rcx", "rdx");
+                
+                emit_pop_reg_now ("rdx");
+                emit_pop_reg_now ("rax");
+                
+                emit_preserve_assignment64_regs (op);
+                emit_assignment_binary_op64 (op, lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
+                emit_restore_assignment64_regs (op);
+            
+            }
+            
+            if (lhs) {
+            
+                if (lhs->is_static && lhs->static_label) {
+                    emit_store_pair_to_global64 (lhs->static_label, "rax", "rdx");
+                } else {
+                    emit_store_pair_to_local64 (lhs->offset, "rax", "rdx");
+                }
+            
+            } else {
+                emit_store_pair_to_global64 (name, "rax", "rdx");
+            }
+        
+        } else {
+        
+            if (op == TOK_ASSIGN) {
+                emit_load_assignment_rhs_expression_to_reg ("rax");
+            } else {
+            
+                if (lhs) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_global_to_reg_ex ("rax", lhs->static_label, lhs->size, lhs->is_unsigned);
+                    } else {
+                        emit_load_local_to_reg_ex ("rax", lhs->offset, lhs->size, lhs->is_unsigned);
+                    }
+                
+                } else {
+                    emit_load_global_to_reg ("rax", name, lhs_size);
+                }
+                
+                emit_load_assignment_rhs_to_reg ("rdx");
+                emit_assignment_binary_op (op, lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
+            
+            }
+            
+            if (lhs) {
+            
+                if (lhs->is_static && lhs->static_label) {
+                    emit_store_reg_to_global (lhs->static_label, lhs->size, "rax");
+                } else {
+                    emit_store_reg_to_local (lhs->offset, lhs->size, "rax");
+                }
+            
+            } else {
+                emit_store_reg_to_global (name, lhs_size, "rax");
+            }
+        
+        }
+    
+    } else {
+        skip_balanced_until (end_token, TOK_EOF, TOK_EOF);
+    }
+    
+    FINISH_FOR_HEADER_EXPR (1);
+
+#undef      FINISH_FOR_HEADER_EXPR
+
+}
+
+static void parse_for_statement (void) {
+
+    int loop_label = anon_label++;
+    int body_label = anon_label++;
+    int continue_label = anon_label++;
+    int break_label = anon_label++;
+    int old_break_label = current_break_label;
+    int old_continue_label = current_continue_label;
+    
+    long old_break_cleanup_base = current_break_cleanup_base;
+    long old_continue_cleanup_base = current_continue_cleanup_base;
+    
+    int cond_known = 0;
+    int cond_value = 1;
+    
+    FILE *saved_ofp;
+    FILE *step_tmp = 0;
+    
+    get_token ();
+    expect (TOK_LPAREN, "(");
+    
+    if (tok.kind == TOK_SEMI) {
+        get_token ();
+    } else {
+        parse_for_header_expression_until (TOK_SEMI);
+    }
+    
+    emit_statement_label (loop_label);
+    
+    if (tok.kind == TOK_SEMI) {
+        get_token ();
+    } else {
+    
+        emit_statement_jump_if_false (break_label);
+        
+        cond_known = statement_condition_constant_known;
+        cond_value = statement_condition_constant_value;
+        
+        if (tok.kind != TOK_SEMI) {
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        }
+        
+        expect (TOK_SEMI, ";");
+    
+    }
+    
+    if (tok.kind == TOK_RPAREN) {
+        get_token ();
+    } else {
+    
+        if (state->ofp) {
+            step_tmp = scc_tmpfile ();
+        }
+        
+        if (step_tmp) {
+        
+            saved_ofp = state->ofp;
+            
+            state->ofp = step_tmp;
+            parse_for_header_expression_until (TOK_RPAREN);
+            
+            state->ofp = saved_ofp;
+        
+        } else {
+            parse_for_header_expression_until (TOK_RPAREN);
+        }
+    
+    }
+    
+    current_break_label = break_label;
+    current_continue_label = continue_label;
+    current_break_cleanup_base = current_block_cleanup_bytes;
+    current_continue_cleanup_base = current_block_cleanup_bytes;
+    
+    if (cond_known && !cond_value) {
+        parse_statement_suppressed ();
+    } else {
+    
+        emit_statement_jump (body_label);
+        emit_statement_label (body_label);
+        
+        parse_statement ();
+        emit_statement_label (continue_label);
+        
+        if (step_tmp) {
+        
+            replay_tmp_file_to_output (step_tmp, state->ofp);
+            scc_close (step_tmp);
+            
+            step_tmp = 0;
+        
+        }
+        
+        emit_statement_jump (loop_label);
+    
+    }
+    
+    if (step_tmp) {
+        scc_close (step_tmp);
+    }
+    
+    emit_statement_label (break_label);
+    
+    current_break_label = old_break_label;
+    current_continue_label = old_continue_label;
+    current_break_cleanup_base = old_break_cleanup_base;
+    current_continue_cleanup_base = old_continue_cleanup_base;
+    
+    statement_ends_control_flow = 0;
+
+}
+
+static void parse_while_statement (void) {
+
+    int loop_label = anon_label++;
+    int body_label = anon_label++;
+    int break_label = anon_label++;
+    int old_break_label = current_break_label;
+    int old_continue_label = current_continue_label;
+    
+    long old_break_cleanup_base = current_break_cleanup_base;
+    long old_continue_cleanup_base = current_continue_cleanup_base;
+    
+    int cond_known;
+    int cond_value;
+    
+    get_token ();
+    expect (TOK_LPAREN, "(");
+    
+    emit_statement_label (loop_label);
+    emit_statement_jump_if_false (break_label);
+    
+    cond_known = statement_condition_constant_known;
+    cond_value = statement_condition_constant_value;
+    
+    if (tok.kind != TOK_RPAREN) {
+        skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+    }
+    
+    expect (TOK_RPAREN, ")");
+    
+    current_break_label = break_label;
+    current_continue_label = loop_label;
+    current_break_cleanup_base = current_block_cleanup_bytes;
+    current_continue_cleanup_base = current_block_cleanup_bytes;
+    
+    if (cond_known && !cond_value) {
+        parse_statement_suppressed ();
+    } else {
+    
+        emit_statement_jump (body_label);
+        emit_statement_label (body_label);
+        
+        parse_statement ();
+        
+        if (!statement_ends_control_flow) {
+            emit_statement_jump (loop_label);
+        }
+    
+    }
+    
+    emit_statement_label (break_label);
+    
+    current_break_label = old_break_label;
+    current_continue_label = old_continue_label;
+    current_break_cleanup_base = old_break_cleanup_base;
+    current_continue_cleanup_base = old_continue_cleanup_base;
+    
+    statement_ends_control_flow = 0;
+
+}
+
+static void parse_do_statement (void) {
+
+    int body_label = anon_label++;
+    int cond_label = anon_label++;
+    int break_label = anon_label++;
+    int old_break_label = current_break_label;
+    int old_continue_label = current_continue_label;
+    
+    long old_break_cleanup_base = current_break_cleanup_base;
+    long old_continue_cleanup_base = current_continue_cleanup_base;
+    
+    int cond_known = 0;
+    int cond_value = 0;
+    
+    get_token ();
+    
+    current_break_label = break_label;
+    current_continue_label = cond_label;
+    current_break_cleanup_base = current_block_cleanup_bytes;
+    current_continue_cleanup_base = current_block_cleanup_bytes;
+    
+    emit_statement_jump (body_label);
+    
+    emit_statement_label (body_label);
+    parse_statement ();
+    
+    emit_statement_label (cond_label);
+    
+    if (_accept (TOK_WHILE)) {
+    
+        expect (TOK_LPAREN, "(");
+        emit_statement_jump_if_false (break_label);
+        
+        cond_known = statement_condition_constant_known;
+        cond_value = statement_condition_constant_value;
+        
+        if (tok.kind != TOK_RPAREN) {
+            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+        }
+        
+        expect (TOK_RPAREN, ")");
+        expect (TOK_SEMI, ";");
+        
+        if (!cond_known || cond_value) {
+            emit_statement_jump (body_label);
+        }
+    
+    } else {
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected while after do statement");
+    }
+    
+    emit_statement_label (break_label);
+    
+    current_break_label = old_break_label;
+    current_continue_label = old_continue_label;
+    current_break_cleanup_base = old_break_cleanup_base;
+    current_continue_cleanup_base = old_continue_cleanup_base;
+    
+    statement_ends_control_flow = 0;
+
+}
+
+static int statement_condition_emit_logical_tail (int label) {
+
+    int skip_label;
+    
+    if (tok.kind == TOK_LOGAND) {
+    
+        get_token ();
+        
+        emit_statement_jump_if_false (label);
+        return 1;
+    
+    }
+    
+    if (tok.kind == TOK_LOGOR) {
+    
+        skip_label = anon_label++;
+        get_token ();
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    test rax, rax\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, "    testq %%rax, %%rax\n");
+                fprintf (state->ofp, "    jnz .L%d\n", skip_label);
+            }
+        
+        }
+        
+        emit_statement_jump_if_false (label);
+        emit_statement_label (skip_label);
+        
+        return 1;
+    
+    }
+    
+    return 0;
+
+}
+
+static void emit_statement_rax_truth_jump_if_false_and_tail (int label) {
+
+    int skip_label;
+
+    if (tok.kind == TOK_LOGAND) {
+
+        emit_statement_test_rax_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 ("rax", skip_label);
+        get_token ();
+        emit_statement_jump_if_false (label);
+        emit_statement_label (skip_label);
+        return;
+
+    }
+
+    emit_statement_test_rax_jump_if_false (label);
+
+}
+
+static int emit_statement_cmp_rax_rdx_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_rax_rdx_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 ();
+        
+        emit_statement_cmp_rax_rdx_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);
+        return 1;
+    
+    }
+    
+    emit_statement_cmp_rax_rdx_jump_if_false (op, is_unsigned, label);
+    return 1;
+
+}
+
+static int statement_condition_fold_logical_tail (int label) {
+
+    enum token_kind logop;
+    
+    while (tok.kind == TOK_LOGOR || tok.kind == TOK_LOGAND) {
+    
+        logop = tok.kind;
+        
+        /*
+         * Constant short-circuit cases can discard the rest of the condition.
+         *
+         *     true  || anything  -> true
+         *     false && anything  -> false
+         *
+         * Leave tok on ')' so the caller's expect(TOK_RPAREN) still works.
+         */
+        if ((logop == TOK_LOGOR && statement_condition_constant_value) || (logop == TOK_LOGAND && !statement_condition_constant_value)) {
+        
+            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+            return 1;
+        
+        }
+        
+        /*
+         * The left side is non-decisive:
+         *
+         *     false || rhs  -> rhs
+         *     true  && rhs  -> rhs
+         *
+         * So consume the logical operator and emit/fold the RHS normally.
+         */
+        get_token ();
+        
+        statement_condition_constant_known = 0;
+        statement_condition_constant_value = 0;
+        
+        emit_statement_jump_if_false (label);
+        return 1;
+    
+    }
+    
+    return 0;
+
+}
+
+static int source_starts_with_parenthesized_assignment_at (const char *p) {
+
+    int parens = 0;
+    
+    if (!p || *p != '(') {
+        return 0;
+    }
+    
+    /*
+     * 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++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p == '(') {
+        return 0;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    p++;
+    
+    while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+        p++;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    while (parens > 0 && *p == ')') {
+    
+        parens--;
+        p++;
+        
+        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+            p++;
+        }
+    
+    }
+    
+    /*
+     * A condition assignment normally looks like:
+     *
+     *     if ((x = y))
+     *
+     * At this point the scanner has consumed the opening paren(s) and the
+     * identifier.  For the common form above, the assignment operator appears
+     * before the closing paren, so `parens' is still non-zero.  The previous
+     * guard returned 0 before checking for '=', which made the statement
+     * condition parser treat the expression as just `(x' and then report a
+     * false "expected )" at the assignment operator.  Check for assignment
+     * operators first, while still rejecting comparison operators.
+     */
+    if (*p == '=') {
+        return p[1] != '=';
+    }
+    
+    if (parens != 0) {
+        return 0;
+    }
+    
+    if ((*p == '+' || *p == '-' || *p == '*' || *p == '/' || *p == '%' ||
+         *p == '&' || *p == '|' || *p == '^') && p[1] == '=') {
+        return 1;
+    }
+    
+    if ((*p == '<' && p[1] == '<' && p[2] == '=') ||
+        (*p == '>' && p[1] == '>' && p[2] == '=')) {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static int source_starts_with_parenthesized_assignment_now (void) {
+
+    /**
+     * Only test the current token text.  tok.start can point at the start of
+     * the whole source line, so scanning the whole line misclassifies a for
+     * condition such as:
+     *
+     *     for (len = 0; (len < max_len) && str[len]; len++);
+     *
+     * as a parenthesized assignment because of the earlier ``(len = 0`` in the
+     * same line.  This helper is a look-ahead guard; it must not match any
+     * parenthesized assignment except the one beginning at the current token.
+     */
+    if (source_starts_with_parenthesized_assignment_at (tok.caret)) {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static int parenthesized_assignment_open_parens = 0;
+static int parenthesized_assignment_closed_parens = 0;
+
+static void consume_parenthesized_assignment_remaining_closes (void) {
+
+    while (parenthesized_assignment_closed_parens < parenthesized_assignment_open_parens && tok.kind == TOK_RPAREN) {
+    
+        get_token ();
+        parenthesized_assignment_closed_parens++;
+    
+    }
+
+}
+
+static int emit_load_parenthesized_assignment_expression_to_reg_now (const char *reg, int *out_is_unsigned) {
+
+    char *name;
+    int global_index;
+    
+    const char *name_start, *name_caret;
+    unsigned long name_line;
+    
+    enum token_kind op;
+    struct local_symbol *lhs;
+    
+    int lhs_size;
+    int lhs_is_floating;
+    int lhs_is_unsigned;
+    int paren_count = 0;
+    
+    parenthesized_assignment_open_parens = 0;
+    parenthesized_assignment_closed_parens = 0;
+    
+    if (out_is_unsigned) {
+        *out_is_unsigned = 0;
+    }
+    
+    if (tok.kind != TOK_LPAREN || !source_starts_with_parenthesized_assignment_now ()) {
+        return 0;
+    }
+    
+    while (tok.kind == TOK_LPAREN) {
+    
+        paren_count++;
+        get_token ();
+    
+    }
+    
+    if (tok.kind != TOK_IDENT) {
+        return 0;
+    }
+    
+    parenthesized_assignment_open_parens = paren_count;
+    
+    name = xstrdup (tok.ident);
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    get_token ();
+    
+    while (parenthesized_assignment_closed_parens < parenthesized_assignment_open_parens && tok.kind == TOK_RPAREN) {
+    
+        get_token ();
+        parenthesized_assignment_closed_parens++;
+    
+    }
+    
+    if (tok.kind == TOK_DOT || tok.kind == TOK_ARROW) {
+    
+        enum token_kind member_op = tok.kind;
+        char *member;
+        
+        const char *member_start;
+        const char *member_caret;
+        
+        unsigned long member_line;
+        
+        int member_offset = 0;
+        int member_size = DATA_INT & 0x1f;
+        
+        get_token ();
+        
+        member_start = tok.start;
+        member_caret = tok.caret;
+        member_line = get_line_number ();
+        
+        if (tok.kind != TOK_IDENT) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        member = xstrdup (tok.ident);
+        get_token ();
+        
+        if (!find_member_info (member, &member_offset, &member_size)) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+            
+            free (member);
+            free (name);
+            
+            return 1;
+        
+        }
+        
+        free (member);
+        
+        if (!is_assignment_operator (tok.kind)) {
+        
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect (TOK_SEMI, ";");
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        op = tok.kind;
+        get_token ();
+        
+        lhs = find_local_symbol (name);
+        global_index = find_global_symbol (name);
+        
+        if (!lhs && global_index < 0) {
+        
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect (TOK_SEMI, ";");
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        if (state->ofp) {
+        
+            if (member_op == TOK_ARROW) {
+            
+                if (lhs) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_global_to_reg ("rdx", lhs->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg ("rdx", lhs->offset, DATA_PTR);
+                    }
+                
+                } else {
+                    emit_load_global_to_reg ("rdx", name, DATA_PTR);
+                }
+            
+            } else {
+            
+                if (lhs) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_address_to_reg_now ("rdx", lhs->static_label);
+                    } else {
+                        emit_load_local_address_to_reg_now ("rdx", lhs->offset);
+                    }
+                
+                } else {
+                    emit_load_address_to_reg_now ("rdx", name);
+                }
+            
+            }
+            
+            if (op == TOK_ASSIGN) {
+            
+                emit_push_reg_now ("rdx");
+                emit_load_assignment_rhs_expression_to_reg ("rax");
+                emit_pop_reg_now ("rdx");
+            
+            } else {
+            
+                emit_load_member_from_addr_reg_now ("rax", "rdx", member_offset, member_size);
+                emit_push_reg_now ("rdx");
+                emit_push_reg_now ("rax");
+                
+                if (tok.kind == TOK_TILDE) {
+                
+                    int64_s rhs_const;
+                    get_token ();
+                    
+                    if (tok.kind == TOK_LPAREN) {
+                    
+                        get_token ();
+                        
+                        rhs_const = const64_from_current_foldable_expr ();
+                        expect (TOK_RPAREN, ")");
+                    
+                    } else {
+                        rhs_const = const64_from_current_foldable_expr ();
+                    }
+                    
+                    rhs_const.low = (~rhs_const.low) & U32_MASK;
+                    rhs_const.high = (~rhs_const.high) & U32_MASK;
+                    
+                    emit_load_const32_to_reg_now ("rdx", rhs_const);
+                
+                } else if (current_integer_expr_is_foldable_now ()) {
+                
+                    int64_s rhs_const = const64_from_current_foldable_expr ();
+                    emit_load_const32_to_reg_now ("rdx", rhs_const);
+                
+                } else {
+                    emit_load_assignment_rhs_expression_to_reg ("rdx");
+                }
+                
+                emit_pop_reg_now ("rax");
+                emit_assignment_binary_op (op, 0);
+                emit_pop_reg_now ("rdx");
+            
+            }
+            
+            emit_store_member_to_addr_reg_now ("rdx", member_offset, "rax", member_size);
+        
+        } else {
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        }
+        
+        expect_semi_or_recover ();
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (!is_assignment_operator (tok.kind)) {
+    
+        free (name);
+        return 0;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    lhs = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (!lhs && global_index < 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+        expect (TOK_RPAREN, ")");
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    lhs_size = lhs ? lhs->size : get_global_symbol_size (name);
+    lhs_is_floating = lhs ? lhs->is_floating : get_global_symbol_floating (name);
+    lhs_is_unsigned = lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name);
+    
+    if (out_is_unsigned) {
+        *out_is_unsigned = lhs_is_unsigned;
+    }
+    
+    if (state->ofp) {
+    
+        if (lhs_is_floating) {
+        
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "floating assignment expression in condition not implemented");
+            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+        
+        } else if (lhs_size == (DATA_LLONG & 0x1f)) {
+        
+            if (op == TOK_ASSIGN) {
+                emit_load_assignment_rhs_expression_to_pair ("rax", "rdx", lhs_is_unsigned);
+            } else {
+            
+                if (lhs) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_global64_to_pair ("rax", "rdx", lhs->static_label);
+                    } else {
+                        emit_load_local64_to_pair (lhs->offset, "rax", "rdx");
+                    }
+                
+                } else {
+                    emit_load_global64_to_pair ("rax", "rdx", name);
+                }
+                
+                /*
+                 * Compound assignments need the complete RHS expression.
+                 * Using emit_load_assignment_rhs_to_pair() only consumes one
+                 * primary operand, so e.g.
+                 *
+                 *     final_value += symbol->frag->address + left_value;
+                 *
+                 * leaves the second + operand for the statement parser and
+                 * reports "expected ;".  Evaluate the full RHS in rax:rdx,
+                 * copy it to the RHS pair rbx:rcx, then restore the original
+                 * LHS value before applying the compound operator.
+                 */
+                emit_push_reg_now ("rax");
+                emit_push_reg_now ("rdx");
+                
+                emit_load_assignment_rhs_expression_to_pair ("rax", "rdx", lhs_is_unsigned);
+                
+                emit_mov_reg_to_reg_now ("rbx", "rax");
+                emit_mov_reg_to_reg_now ("rcx", "rdx");
+                
+                emit_pop_reg_now ("rdx");
+                emit_pop_reg_now ("rax");
+                
+                emit_preserve_assignment64_regs (op);
+                emit_assignment_binary_op64 (op, lhs_is_unsigned);
+                emit_restore_assignment64_regs (op);
+            
+            }
+            
+            if (lhs) {
+            
+                if (lhs->is_static && lhs->static_label) {
+                    emit_store_pair_to_global64 (lhs->static_label, "rax", "rdx");
+                } else {
+                    emit_store_pair_to_local64 (lhs->offset, "rax", "rdx");
+                }
+            
+            } else {
+                emit_store_pair_to_global64 (name, "rax", "rdx");
+            }
+        
+        } else {
+        
+            if (op == TOK_ASSIGN) {
+                emit_load_assignment_rhs_expression_to_reg (reg);
+            } else {
+            
+                if (lhs) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_global_to_reg_ex (reg, lhs->static_label, lhs->size, lhs->is_unsigned);
+                    } else {
+                        emit_load_local_to_reg_ex (reg, lhs->offset, lhs->size, lhs->is_unsigned);
+                    }
+                
+                } else {
+                    emit_load_global_to_reg (reg, name, lhs_size);
+                }
+                
+                emit_load_assignment_rhs_to_reg ("rdx");
+                
+                if (strcmp (reg, "rax") != 0 && state->ofp) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    mov rax, %s\n", reg);
+                    } else {
+                        fprintf (state->ofp, "    movq %%%s, %%rax\n", reg);
+                    }
+                
+                }
+                
+                emit_assignment_binary_op (op, lhs_is_unsigned);
+                
+                if (strcmp (reg, "rax") != 0 && state->ofp) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    mov %s, rax\n", reg);
+                    } else {
+                        fprintf (state->ofp, "    movq %%rax, %%%s\n", reg);
+                    }
+                
+                }
+            
+            }
+            
+            if (lhs) {
+            
+                if (lhs->is_static && lhs->static_label) {
+                    emit_store_reg_to_global (lhs->static_label, lhs->size, reg);
+                } else {
+                    emit_store_reg_to_local (lhs->offset, lhs->size, reg);
+                }
+            
+            } else {
+                emit_store_reg_to_global (name, lhs_size, reg);
+            }
+        
+        }
+    
+    } else {
+        skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+    }
+    
+    consume_parenthesized_assignment_remaining_closes ();
+    
+    free (name);
+    return 1;
+
+}
+
+static int source_condition_has_top_level_compare_now (const char *p) {
+
+    int paren_depth = 0;
+    int bracket_depth = 0;
+    int saw_operand = 0;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    while (*p) {
+    
+        if (*p == '\'' || *p == '"') {
+        
+            int quote = *p++;
+            
+            while (*p) {
+            
+                if (*p == '\\' && p[1]) {
+                
+                    p += 2;
+                    continue;
+                
+                }
+                
+                if (*p == quote) {
+                
+                    p++;
+                    break;
+                
+                }
+                
+                p++;
+            
+            }
+            
+            saw_operand = 1;
+            continue;
+        
+        }
+        
+        if (*p == '(') {
+        
+            paren_depth++;
+            
+            saw_operand = 1;
+            p++;
+            
+            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;
+                }
+                
+                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]) {
+                
+                    p += 2;
+                    continue;
+                
+                }
+                
+                if (*p == quote) {
+                
+                    p++;
+                    break;
+                
+                }
+                
+                p++;
+            
+            }
+            
+            continue;
+        
+        }
+        
+        if (*p == '(') {
+        
+            paren_depth++;
+            p++;
+            
+            continue;
+        
+        }
+        
+        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 ("rax");
+    
+    expect (TOK_RPAREN, ")");
+    
+    if (!token_is_statement_compare_operator (tok.kind)) {
+    
+        emit_statement_rax_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_rdx_if_possible ()) {
+    
+        emit_push_reg_now ("rax");
+        emit_load_assignment_compare_expression_to_reg ("rdx");
+        emit_pop_reg_now ("rax");
+    
+    }
+    
+    emit_statement_cmp_rax_rdx_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;
+    }
+    
+    /*
+     * Do not let the generic integer direct-compare fast path consume
+     * floating conditions such as:
+     *
+     *     while (value_fractional_d - ((int64_t)value_fractional_d) != 0)
+     *
+     * That path lowers the LHS through rax and compares integer dwords,
+     * so the example above becomes low_word - low_word and the fractional
+     * loop exits immediately.  Leave floating expressions for the x87
+     * condition path below.
+     */
+    if (token_is_const_floating_condition_operand_now () || rhs_current_operand_is_floating_now ()) {
+        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 ("rax", 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_rax_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_rdx_if_possible ()) {
+    
+        emit_push_reg_now ("rax");
+        emit_load_assignment_compare_expression_to_reg ("rdx");
+        emit_pop_reg_now ("rax");
+    
+    }
+    
+    emit_statement_cmp_rax_rdx_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 ("rax", &is_unsigned)) {
+    
+        while (is_arithmetic_binary_operator (tok.kind)) {
+        
+            op = tok.kind;
+            get_token ();
+            
+            if (rhs_current_operand_is_unsigned_now ()) {
+                is_unsigned = 1;
+            }
+            
+            emit_load_assignment_rhs_to_reg ("rdx");
+            emit_assignment_binary_op (op, is_unsigned);
+        
+        }
+        
+        if (token_is_statement_compare_operator (tok.kind)) {
+        
+            op = tok.kind;
+            get_token ();
+            
+            if (rhs_current_operand_is_unsigned_now ()) {
+                is_unsigned = 1;
+            }
+            
+            emit_load_assignment_compare_expression_to_reg ("rdx");
+            consume_parenthesized_assignment_remaining_closes ();
+            
+            emit_statement_cmp_rax_rdx_jump_if_false_and_tail (op, is_unsigned, label);
+            statement_condition_emit_logical_tail (label);
+            
+            return;
+        
+        }
+        
+        consume_parenthesized_assignment_remaining_closes ();
+        
+        emit_statement_rax_truth_jump_if_false_and_tail (label);
+        return;
+    
+    }
+    
+    if (emit_statement_parenthesized_lhs_compare_jump_if_false_now (label)) {
+        return;
+    }
+    
+    if (emit_statement_direct_compare_jump_if_false_now (label)) {
+        return;
+    }
+    
+    if (tok.kind == TOK_LPAREN && (token_is_const_floating_condition_operand_now () || rhs_current_operand_is_floating_now ())) {
+    
+        double left_float = 0.0;
+        
+        int left_float_constant = 0;
+        int float_size = DATA_DOUBLE & 0x1f;
+        
+        if (token_is_const_floating_condition_operand_now ()) {
+        
+            left_float = parse_floating_const_expr_value_now ();
+            left_float_constant = 1;
+        
+        } else {
+            emit_load_floating_rhs_expression_now (float_size);
+        }
+        
+        if (token_is_statement_compare_operator (tok.kind)) {
+        
+            op = tok.kind;
+            get_token ();
+            
+            if (left_float_constant && (token_is_floating_constant_now () || token_is_const_condition_operand_now ())) {
+            
+                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 = int64_to_double_now (right_int);
+                
+                }
+                
+                statement_condition_constant_known = 1;
+                statement_condition_constant_value = statement_compare_floating_const_true (left_float, op, right_float) ? 1 : 0;
+                
+                if (statement_condition_fold_logical_tail (label)) {
+                    return;
+                }
+                
+                return;
+            
+            }
+            
+            if (left_float_constant) {
+                emit_load_floating_ld_now (float_size, left_float);
+            }
+            
+            emit_load_floating_rhs_expression_now (float_size);
+            emit_statement_floating_compare_jump_if_false (op, label);
+            
+            return;
+        
+        }
+        
+        if (floating_rhs_result_in_eax_bool) {
+        
+            emit_statement_rax_truth_jump_if_false_and_tail (label);
+            
+            floating_rhs_result_in_eax_bool = 0;
+            return;
+        
+        }
+        
+        if (left_float_constant) {
+        
+            statement_condition_constant_known = 1;
+            statement_condition_constant_value = left_float != 0.0 ? 1 : 0;
+            
+            if (statement_condition_fold_logical_tail (label)) {
+                return;
+            }
+            
+            return;
+        
+        }
+        
+        emit_load_floating_ld_now (float_size, 0.0);
+        
+        emit_statement_floating_compare_jump_if_false (TOK_NOTEQ, label);
+        return;
+    
+    }
+    
+    /*
+     * Parenthrsized 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 ("rax");
+        
+        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_rdx_if_possible ()) {
+            
+                emit_push_reg_now ("rax");
+                emit_load_assignment_compare_expression_to_reg ("rdx");
+                emit_pop_reg_now ("rax");
+            
+            }
+            
+            emit_statement_cmp_rax_rdx_jump_if_false_and_tail (op, is_unsigned, label);
+            return;
+        
+        }
+
+        emit_statement_rax_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, ")");
+        
+        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 ("rax");
+        } 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, "rax", 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_rdx_if_possible ()) {
+            
+                emit_push_reg_now ("rax");
+                emit_load_assignment_compare_expression_to_reg ("rdx");
+                emit_pop_reg_now ("rax");
+            
+            }
+            
+            emit_statement_cmp_rax_rdx_jump_if_false_and_tail (op, is_unsigned, label);
+            return;
+        
+        }
+        
+        emit_statement_rax_truth_jump_if_false_and_tail (label);
+        return;
+    
+    }
+    
+    /*
+     * Fold simple constant conditions at parse time.  This avoids emitting:
+     *
+     *     mov rax, 1
+     *     test rax, rax
+     *     jz ...
+     *
+     * for things like if (1), and avoids cmp/jcc for things like
+     * if (1 < 10), if (5 > 2), if (1ULL < 10LL), etc.
+     */
+    if (token_is_const_floating_condition_operand_now () || rhs_current_operand_is_floating_now ()) {
+    
+        double left_float = 0.0;
+        
+        int left_float_constant = 0;
+        int float_size = DATA_DOUBLE & 0x1f;
+        
+        if (token_is_const_floating_condition_operand_now ()) {
+        
+            left_float = parse_floating_const_expr_value_now ();
+            left_float_constant = 1;
+        
+        } else {
+            emit_load_floating_rhs_expression_now (float_size);
+        }
+        
+        if (token_is_statement_compare_operator (tok.kind)) {
+        
+            op = tok.kind;
+            get_token ();
+            
+            if (left_float_constant && (token_is_floating_constant_now () || token_is_const_condition_operand_now ())) {
+            
+                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 = int64_to_double_now (right_int);
+                
+                }
+                
+                statement_condition_constant_known = 1;
+                statement_condition_constant_value = statement_compare_floating_const_true (left_float, op, right_float) ? 1 : 0;
+                
+                if (statement_condition_fold_logical_tail (label)) {
+                    return;
+                }
+                
+                return;
+            
+            }
+            
+            if (left_float_constant) {
+                emit_load_floating_ld_now (float_size, left_float);
+            }
+            
+            emit_load_floating_rhs_expression_now (float_size);
+            emit_statement_floating_compare_jump_if_false (op, label);
+            
+            return;
+        
+        }
+        
+        if (floating_rhs_result_in_eax_bool) {
+        
+            emit_statement_rax_truth_jump_if_false_and_tail (label);
+            
+            floating_rhs_result_in_eax_bool = 0;
+            return;
+        
+        }
+        
+        if (left_float_constant) {
+        
+            statement_condition_constant_known = 1;
+            statement_condition_constant_value = left_float != 0.0 ? 1 : 0;
+            
+            if (statement_condition_fold_logical_tail (label)) {
+                return;
+            }
+            
+            return;
+        
+        }
+        
+        emit_load_floating_ld_now (float_size, 0.0);
+        emit_statement_floating_compare_jump_if_false (TOK_NOTEQ, label);
+        
+        return;
+    
+    }
+    
+    /*
+     * 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 rax, 61; test rax, rax" 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 = current_integer_expr_is_foldable_now ();
+        int left_unsigned = rhs_current_operand_is_unsigned_now ();
+        
+        int64_s left;
+        
+        if (fold_whole_expr) {
+            left = const64_from_current_foldable_expr ();
+        } else {
+            left = const64_from_current_operand ();
+        }
+        
+        if (is_arithmetic_binary_operator (tok.kind)) {
+        
+            emit_statement_const32_to_rax (left);
+            
+            while (is_arithmetic_binary_operator (tok.kind)) {
+            
+                op = tok.kind;
+                get_token ();
+                
+                if (rhs_current_operand_is_unsigned_now ()) {
+                    left_unsigned = 1;
+                }
+                
+                emit_load_assignment_rhs_to_reg ("rdx");
+                emit_assignment_binary_op (op, left_unsigned);
+            
+            }
+            
+            if (token_is_statement_compare_operator (tok.kind)) {
+            
+                op = tok.kind;
+                get_token ();
+                
+                is_unsigned = left_unsigned;
+                
+                if (rhs_current_operand_is_unsigned_now ()) {
+                    is_unsigned = 1;
+                }
+                
+                emit_statement_cmp_rax_rdx_jump_if_false_and_tail (op, is_unsigned, label);
+                return;
+            
+            }
+            
+            emit_statement_test_rax_jump_if_false (label);
+            return;
+        
+        }
+        
+        if (token_is_statement_compare_operator (tok.kind)) {
+        
+            op = tok.kind;
+            get_token ();
+            
+            is_unsigned = left_unsigned;
+            
+            if (rhs_current_operand_is_unsigned_now ()) {
+                is_unsigned = 1;
+            }
+            
+            if (token_is_floating_constant_now ()) {
+            
+                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;
+                statement_condition_constant_value = statement_compare_floating_const_true (left_float, op, right_float) ? 1 : 0;
+                
+                if (statement_condition_fold_logical_tail (label)) {
+                    return;
+                }
+                
+                return;
+            
+            }
+            
+            if (token_is_const_condition_operand_now ()) {
+            
+                int64_s right;
+                
+                if (current_integer_expr_is_foldable_now ()) {
+                    right = const64_from_current_foldable_expr ();
+                } else {
+                    right = const64_from_current_operand ();
+                }
+                
+                statement_condition_constant_known = 1;
+                statement_condition_constant_value = statement_compare_const64_true (left, op, right, is_unsigned) ? 1 : 0;
+                
+                if (statement_condition_fold_logical_tail (label)) {
+                    return;
+                }
+                
+                return;
+            
+            }
+            
+            if (rhs_current_operand_is_floating_now ()) {
+            
+                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);
+                emit_statement_floating_compare_jump_if_false (op, label);
+                
+                return;
+            
+            }
+            
+            emit_statement_const32_to_rax (left);
+            emit_load_assignment_rhs_expression_to_reg ("rdx");
+            
+            emit_statement_cmp_rax_rdx_jump_if_false_and_tail (op, is_unsigned, label);
+            return;
+        
+        }
+        
+        statement_condition_constant_known = 1;
+        statement_condition_constant_value = int64_statement_truth_value (left) ? 1 : 0;
+        
+        if (statement_condition_fold_logical_tail (label)) {
+            return;
+        }
+        
+        return;
+    
+    }
+    
+    /*
+     * A leading unary ! always yields an int truth value.  Do not route it
+     * through the 64-bit condition path just because the operand text happens
+     * to mention a symbol that the coarse scanner thinks is 64-bit; that path
+     * expects an unconverted 64-bit value and will compare EDX:EAX against
+     * uninitialised ECX:EBX for a plain if (!p).
+     */
+    if (tok.kind == TOK_XMARK) {
+    
+        emit_load_assignment_rhs_expression_to_reg ("rax");
+        
+        emit_statement_rax_truth_jump_if_false_and_tail (label);
+        return;
+    
+    }
+    
+    if (current_expression_mentions_64bit_symbol_now ()) {
+    
+        int old_assignment64_stop_before_condition_operator;
+        is_unsigned = rhs_current_operand_is_unsigned_now ();
+        
+        old_assignment64_stop_before_condition_operator = assignment64_stop_before_condition_operator;
+        assignment64_stop_before_condition_operator = 1;
+        
+        emit_load_assignment_rhs_expression_to_pair ("rax", "rdx", is_unsigned);
+        assignment64_stop_before_condition_operator = old_assignment64_stop_before_condition_operator;
+        
+        if (token_is_statement_compare_operator (tok.kind)) {
+        
+            op = tok.kind;
+            get_token ();
+            
+            if (rhs_current_operand_is_unsigned_now ()) {
+                is_unsigned = 1;
+            }
+            
+            if (state->ofp) {
+            
+                /*
+                 * Save the left-hand 64-bit condition value across loading
+                 * the right-hand side without using three PUSHes.  The RHS
+                 * expression may contain a function call, and three pushes
+                 * leave RSP 8 bytes misaligned before the call-frame reserve
+                 * is emitted.  Reserve a 32-byte aligned spill area instead.
+                 */
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    amd64_emit_push_reg_now ("rbx");
+                    amd64_emit_push_reg_now ("rax");
+                    amd64_emit_push_reg_now ("rdx");
+                    amd64_emit_push_reg_now ("rcx");
+                
+                } else {
+                
+                    amd64_emit_push_reg_now ("rbx");
+                    amd64_emit_push_reg_now ("rax");
+                    amd64_emit_push_reg_now ("rdx");
+                    amd64_emit_push_reg_now ("rcx");
+                
+                }
+            
+            }
+            
+            /*
+             * The stop-before-compare guard is only needed while loading the
+             * left hand side of the statement condition.  After the condition
+             * operator has been consumed, the right hand side must be parsed as
+             * a complete expression.  Keeping the guard enabled here makes a
+             * parenthesized conditional expression such as:
+             *
+             *     i < (len_fract == 0 ? 1 : precision - len_fract)
+             *
+             * stop at the nested == and leave the parser expecting the closing
+             * ')'.  That is what produced the false "expected )" diagnostic.
+             */
+            emit_load_assignment_rhs_expression_to_pair ("rax", "rdx", is_unsigned);
+            
+            if (state->ofp) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    fprintf (state->ofp, "    mov rbx, rax\n");
+                    fprintf (state->ofp, "    mov rcx, rdx\n");
+                    
+                    amd64_emit_pop_reg_now ("rcx");
+                    amd64_emit_pop_reg_now ("rdx");
+                    amd64_emit_pop_reg_now ("rax");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    movq %%rax, %%rbx\n");
+                    fprintf (state->ofp, "    movq %%rdx, %%rcx\n");
+                    
+                    amd64_emit_pop_reg_now ("rcx");
+                    amd64_emit_pop_reg_now ("rdx");
+                    amd64_emit_pop_reg_now ("rax");
+                
+                }
+            
+            }
+            
+            emit_statement_cmp64_to_rax (op, is_unsigned);
+            
+            if (state->ofp) {
+                amd64_emit_pop_reg_now ("rbx");
+            }
+            
+            emit_statement_test_rax_jump_if_false (label);
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_LOGAND) {
+        
+            get_token ();
+            
+            emit_statement_test_pair_jump_if_false ("rax", "rdx", label);
+            emit_statement_jump_if_false (label);
+            
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_LOGOR) {
+        
+            int skip_label = anon_label++;
+            get_token ();
+            
+            emit_statement_test_pair_jump_if_true ("rax", "rdx", skip_label);
+            emit_statement_jump_if_false (label);
+            emit_statement_label (skip_label);
+            
+            return;
+        
+        }
+        
+        emit_statement_test_pair_jump_if_false ("rax", "rdx", label);
+        return;
+    
+    }
+    
+    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 ("rax");
+    assignment32_stop_before_condition_operator = old_assignment32_stop_before_condition_operator;
+    
+    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_rdx_if_possible ()) {
+        
+            emit_push_reg_now ("rax");
+            emit_load_assignment_compare_expression_to_reg ("rdx");
+            emit_pop_reg_now ("rax");
+        
+        }
+        
+        emit_statement_cmp_rax_rdx_jump_if_false_and_tail (op, is_unsigned, label);
+        return;
+    
+    }
+    
+    emit_statement_rax_truth_jump_if_false_and_tail (label);
+
+}
+
+static int token_text_starts_void_cast_now (void) {
+
+    const char *p = tok.caret;
+    
+    if (!p || *p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, "void", 4) != 0) {
+        return 0;
+    }
+    
+    p += 4;
+    
+    if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    return *p == ')';
+
+}
+
+static int parse_void_cast_discard_statement (void) {
+
+    if (tok.kind != TOK_LPAREN || !token_text_starts_void_cast_now ()) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    expect (TOK_VOID, "void");
+    expect (TOK_RPAREN, ")");
+    
+    if (tok.kind != TOK_SEMI) {
+    
+        emit_load_assignment_rhs_expression_to_reg ("rax");
+        
+        if (tok.kind != TOK_SEMI) {
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        }
+    
+    }
+    
+    expect (TOK_SEMI, ";");
+    return 1;
+
+}
+
+static int token_text_looks_like_postfix_assignment_now (void) {
+
+    const char *p;
+    int saw_postfix;
+    int paren_depth;
+    int bracket_depth;
+    
+    if (tok.caret) {
+        p = tok.caret;
+    } else if (tok.start) {
+        p = tok.start;
+    } else {
+        return 0;
+    }
+    
+    saw_postfix = 0;
+    paren_depth = 0;
+    bracket_depth = 0;
+    
+    while (*p && *p != ';' && *p != '\n') {
+    
+        if (*p == '(') {
+        
+            /**
+             * A postfix/member expression followed by a top-level '(' is a
+             * function call through that member, not a postfix assignment.
+             * This pre-scan must reject it before the destructive postfix
+             * assignment parser consumes the tokens.
+             */
+            if (saw_postfix && paren_depth == 0 && bracket_depth == 0) {
+                return 0;
+            }
+            
+            paren_depth++;
+        
+        } else if (*p == ')') {
+            if (paren_depth > 0) paren_depth--;
+        } else if (*p == '[') {
+        
+            saw_postfix = 1;
+            bracket_depth++;
+        
+        } else if (*p == ']') {
+            if (bracket_depth > 0) bracket_depth--;
+        } else if (paren_depth == 0 && bracket_depth == 0 && *p == ',') {
+            return 0;
+        } else if (paren_depth == 0 && bracket_depth == 0 && *p == '.') {
+            saw_postfix = 1;
+        } else if (paren_depth == 0 && bracket_depth == 0 && *p == '-' && p[1] == '>') {
+        
+            saw_postfix = 1;
+            p++;
+        
+        } else if (paren_depth == 0 && bracket_depth == 0 && *p == '=') {
+        
+            if (p[1] == '=') {
+                return 0;
+            }
+            
+            return saw_postfix;
+        
+        }
+        
+        p++;
+    
+    }
+    
+    return 0;
+
+}
+
+static int source_starts_with_parenthesized_indirect_call_now (void) {
+
+    const char *p = tok.caret;
+    
+    int member_depth = 1;
+    int saw_member = 0;
+    int depth;
+    
+    if (!p || *p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '*') {
+        return 0;
+    }
+    
+    depth = 1;
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    /*
+     * Accept both
+     *
+     *     (*obj->member)(...)
+     *     (*(obj->member))(...)
+     *
+     * but keep this recognizer deliberately narrow.  It must not claim an
+     * arbitrary parenthesized expression, otherwise normal statement parsing
+     * and C labels can be pulled into this special call path.
+     */
+    if (*p == '(') {
+    
+        depth++;
+        
+        member_depth = 2;
+        p++;
+    
+    }
+    
+    while (*p && depth > 0) {
+    
+        if (*p == '(') {
+            depth++;
+        } else if (*p == ')') {
+        
+            depth--;
+            
+            if (depth == 0) {
+                break;
+            }
+        
+        } else if (depth == member_depth && *p == '-' && p[1] == '>') {
+        
+            saw_member = 1;
+            p++;
+        
+        } else if (depth == member_depth && *p == '.') {
+            saw_member = 1;
+        }
+        
+        p++;
+    
+    }
+    
+    if (depth != 0 || !saw_member) {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '(';
+
+}
+
+static int parse_postfix_assignment_statement_now (void) {
+
+    char *name;
+    
+    struct local_symbol *src;
+    int global_index;
+    
+    enum token_kind assign_op;
+    int lvalue_size;
+    
+    if (tok.kind != TOK_IDENT || !token_text_looks_like_postfix_assignment_now ()) {
+        return 0;
+    }
+    
+    name = xstrdup (tok.ident);
+    
+    {
+    
+        const char *name_start = tok.start;
+        const char *name_caret = tok.caret;
+        
+        unsigned long name_line = get_line_number ();
+        get_token ();
+        
+        src = find_local_symbol (name);
+        global_index = find_global_symbol (name);
+        
+        if (!src && global_index < 0) {
+        
+            free (name);
+            return 0;
+        
+        }
+        
+        if (!emit_parse_postfix_copy_source_address_now ("rdx", src, name, name_start, name_caret, name_line)) {
+        
+            free (name);
+            return 0;
+        
+        }
+    
+    }
+    
+    free (name);
+    
+    if (!is_assignment_operator (tok.kind)) {
+        return 0;
+    }
+    
+    assign_op = tok.kind;
+    lvalue_size = index_step_size (postfix_copy_lvalue_size);
+    
+    if (lvalue_size <= 0) {
+        lvalue_size = DATA_INT & 0x1f;
+    }
+    
+    get_token ();
+    
+    if (assign_op == TOK_ASSIGN) {
+    
+        if (postfix_member_is_floating || token_is_floating_constant_now () || rhs_current_operand_is_floating_now ()) {
+        
+            emit_push_reg_now ("rdx");
+            emit_load_floating_rhs_expression_now (lvalue_size);
+            
+            emit_pop_reg_now ("rdx");
+            emit_store_floating_member_to_addr_reg_now ("rdx", 0, lvalue_size);
+            
+            return 1;
+        
+        }
+        
+        if (lvalue_size == (DATA_LLONG & 0x1f)) {
+        
+            emit_push_reg_now ("rdx");
+            
+            emit_load_assignment_rhs_expression_to_pair ("rax", "rdx", 1);
+            emit_pop_reg_now ("rcx");
+            
+            emit_store_pair_to_deref_reg_now ("rcx", "rax", "rdx");
+            return 1;
+        
+        }
+        
+        if (lvalue_size > (DATA_LLONG & 0x1f)
+            && tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now ()
+            && get_global_symbol_kind (tok.ident) == GLOBAL_SYMBOL_FUNCTION
+            && get_global_symbol_size (tok.ident) > (DATA_LLONG & 0x1f)) {
+        
+            char *rhs_name = xstrdup (tok.ident);
+            const char *rhs_start = tok.start;
+            const char *rhs_caret = tok.caret;
+            unsigned long rhs_line = get_line_number ();
+            
+            emit_push_reg_now ("rdx");
+            
+            pending_struct_return_lhs = 0;
+            pending_struct_return_global_name = 0;
+            pending_struct_return_stack_address = 1;
+            pending_struct_return_stack_offset = 0;
+            
+            get_token ();
+            emit_call_identifier_to_reg_now (rhs_name, "rax", rhs_start, rhs_caret, rhs_line);
+            
+            pending_struct_return_stack_address = 0;
+            pending_struct_return_stack_offset = 0;
+            
+            emit_pop_reg_now ("rdx");
+            
+            free (rhs_name);
+            return 1;
+        
+        }
+        
+        if (emit_aggregate_copy_from_current_rhs_to_addr_reg_now ("rdx", 0, lvalue_size)) {
+            return 1;
+        }
+        
+        /**
+         * Keep the computed lvalue address across the RHS evaluation.
+         * The RHS emitter is free to use rdx for indexing, calls, and
+         * arithmetic, so storing through rdx after it can corrupt memory.
+         */
+        emit_push_reg_now ("rdx");
+        
+        emit_load_assignment_rhs_expression_to_reg ("rax");
+        emit_pop_reg_now ("rdx");
+
+    } else {
+    
+        emit_push_reg_now ("rdx");
+        
+        emit_load_member_from_addr_reg_now ("rax", "rdx", 0, lvalue_size);
+        emit_push_reg_now ("rax");
+        
+        emit_load_assignment_rhs_expression_to_reg ("rdx");
+        emit_pop_reg_now ("rax");
+        
+        emit_assignment_binary_op (assign_op, 0);
+        emit_pop_reg_now ("rdx");
+    
+    }
+    
+    emit_store_reg_to_deref_reg_now ("rdx", "rax", lvalue_size);
+    return 1;
+
+}
+
+static int parse_parenthesized_member_function_pointer_call_statement (void) {
+
+    struct local_symbol *src;
+    char *name;
+    
+    int global_index;
+    int wrapped_member_expr = 0;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    int base_size = DATA_INT & 0x1f;
+    
+    const char *base_tag_name = 0;
+    
+    if (tok.kind != TOK_LPAREN || !source_starts_with_parenthesized_indirect_call_now ()) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    if (tok.kind != TOK_STAR) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    if (tok.kind == TOK_LPAREN) {
+    
+        wrapped_member_expr = 1;
+        get_token ();
+    
+    }
+    
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+        return 0;
+    }
+    
+    name = xstrdup (tok.ident);
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    get_token ();
+    
+    src = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (!src && global_index < 0) {
+    
+        free (name);
+        return 0;
+    
+    }
+    
+    if (tok.kind == TOK_ARROW || tok.kind == TOK_LBRACK) {
+    
+        if (src) {
+        
+            base_size = src->pointer_depth > 0 ? src->pointed_size : src->size;
+            base_tag_name = src->pointer_depth > 0 ? src->pointed_tag_name : 0;
+        
+        } else {
+        
+            base_size = get_global_symbol_pointer_depth (name) > 0 ? get_global_symbol_pointed_size (name) : get_global_symbol_size (name);
+            base_tag_name = get_global_symbol_pointer_depth (name) > 0 ? get_global_symbol_tag_name (name) : 0;
+        
+        }
+    
+    } else if (tok.kind == TOK_DOT) {
+    
+        if (src) {
+        
+            base_size = src->size;
+            base_tag_name = src->tag_name;
+        
+        } else {
+        
+            base_size = get_global_symbol_size (name);
+            base_tag_name = get_global_symbol_tag_name (name);
+        
+        }
+    
+    } else {
+    
+        free (name);
+        return 0;
+    
+    }
+    
+    postfix_copy_lvalue_size = base_size;
+    postfix_copy_lvalue_tag_name = base_tag_name;
+    
+    if (!emit_parse_postfix_copy_source_address_now ("rcx", src, name, name_start, name_caret, name_line)) {
+    
+        free (name);
+        return 0;
+    
+    }
+    
+    free (name);
+    
+    if (wrapped_member_expr) {
+        expect (TOK_RPAREN, ")");
+    }
+    
+    expect (TOK_RPAREN, ")");
+    
+    if (tok.kind != TOK_LPAREN) {
+        return 0;
+    }
+    
+    emit_load_deref_reg_now ("rcx", DATA_PTR & 0x1f);
+    emit_call_pointer_in_reg_now ("rcx", "rax");
+    
+    expect_semi_or_recover ();
+    return 1;
+
+}
+
+static void parse_statement_suppressed (void) {
+
+    FILE *save_ofp = state->ofp;
+    
+    state->ofp = 0;
+    parse_statement ();
+    state->ofp = save_ofp;
+
+}
+
+static void parse_statement (void) {
+
+    statement_ends_control_flow = 0;
+    flush_pending_statement_labels ();
+    
+    if (parse_inline_asm_statement ()) {
+        return;
+    }
+    
+    if (parse_prefix_incdec_statement ()) {
+        return;
+    }
+    
+    if (parse_void_cast_discard_statement ()) {
+        return;
+    }
+    
+    
+    if (tok.kind == TOK_LPAREN && source_starts_lparen_deref_postfix_incdec_at (tok.caret)) {
+    
+        get_token ();
+        
+        if (emit_load_parenthesized_deref_postfix_incdec_subscript_to_reg_now ("rax")) {
+        
+            expect_semi_or_recover ();
+            return;
+        
+        }
+    
+    }
+    
+    if (parse_parenthesized_deref_subscript_statement ()) {
+    
+        expect_semi_or_recover ();
+        return;
+    
+    }
+    
+    if (parse_parenthesized_member_function_pointer_call_statement ()) {
+        return;
+    }
+    
+    if (tok.kind == TOK_LPAREN) {
+    
+        int parenthesized_assignment_is_unsigned;
+        
+        if (emit_load_parenthesized_assignment_expression_to_reg_now ("rax", &parenthesized_assignment_is_unsigned)) {
+        
+            expect_semi_or_recover ();
+            return;
+        
+        }
+    
+    }
+    
+    if (tok.kind == TOK_LPAREN && parse_parenthesized_indirect_member_assignment_statement ()) {
+        return;
+    }
+    
+    if (parse_indirect_assignment_statement ()) {
+        return;
+    }
+    
+    if (parse_postfix_assignment_statement_now ()) {
+    
+        expect_semi_or_recover ();
+        return;
+    
+    }
+    
+    if (parse_identifier_assignment_statement ()) {
+        return;
+    }
+    
+    if (tok.kind == TOK_RETURN) {
+    
+        int has_value = 0;
+        long v = 0;
+        
+        const char *ret_start = tok.start;
+        const char *ret_caret = tok.caret;
+        
+        int ret_line = get_line_number ();
+        
+        current_function_has_return_statement = 1;
+        get_token ();
+        
+        if (tok.kind != TOK_SEMI) {
+        
+            if (current_function_is_void) {
+            
+                FILE *saved_return_ofp = state->ofp;
+                state->ofp = 0;
+                
+                emit_load_assignment_rhs_expression_to_reg ("rax");
+                state->ofp = saved_return_ofp;
+            
+            } else if (current_function_is_floating) {
+            
+                if (state->ofp && pending_return_jump) {
+                    emit_pending_return_jump ();
+                }
+                
+                emit_load_floating_rhs_expression_now (current_function_return_size);
+            
+            } else {
+            
+                if (state->ofp && pending_return_jump) {
+                    emit_pending_return_jump ();
+                }
+                
+                if (state->ofp) {
+                
+                    if (current_function_returns_aggregate) {
+                    
+                        if (state->syntax & ASM_SYNTAX_INTEL) {
+                            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov rdx, qword [rbp + 16]\n" : "    mov rdx, qword ptr [rbp + 16]\n"));
+                        } else {
+                            fprintf (state->ofp, "    movq 16(%%rbp), %%rdx\n");
+                        }
+                        
+                        if (!emit_aggregate_copy_from_current_rhs_to_addr_reg_now ("rdx", 0, current_function_return_size)) {
+                            emit_load_assignment_rhs_expression_to_reg ("rax");
+                        }
+                    
+                    } else if (current_function_return_pointer_depth == 0 && current_function_return_size == (DATA_LLONG & 0x1f)) {
+                        emit_load_assignment_rhs_expression_to_pair ("rax", "rdx", current_function_return_is_unsigned);
+                    } else {
+                        emit_load_assignment_rhs_expression_to_reg ("rax");
+                    }
+                
+                } else {
+                
+                    /*
+                     * Suppressed parsing still has to consume a normal return
+                     * expression.  Do not route it through the integer constant
+                     * evaluator: valid returns such as:
+                     *
+                     *     return ("text");
+                     *
+                     * are ordinary pointer expressions, not integer constant
+                     * expressions.  Using const_from_current_expr() here makes
+                     * dead/suppressed blocks falsely report "integer constant
+                     * expression expected" at the string literal.
+                     */
+                    if (current_function_return_pointer_depth == 0 && current_function_return_size == (DATA_LLONG & 0x1f)) {
+                        emit_load_assignment_rhs_expression_to_pair ("rax", "rdx", current_function_return_is_unsigned);
+                    } else {
+                        emit_load_assignment_rhs_expression_to_reg ("rax");
+                    }
+                
+                }
+            
+            }
+            
+            has_value = 1;
+        
+        }
+        
+        if (current_function_is_void && has_value) {
+            report_line_at (get_filename (), ret_line, REPORT_WARNING, ret_start, ret_caret, "return with a value in void function");
+        } else if (!current_function_is_void && !has_value) {
+            report_line_at (get_filename (), ret_line, REPORT_WARNING, ret_start, ret_caret, "return with no value in non-void function");
+        }
+        
+        if (state->ofp) {
+        
+            if (pending_return_jump) {
+                emit_pending_return_jump ();
+            }
+            
+            if (!current_function_is_floating && !has_value) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    if (current_function_return_size == (DATA_LLONG & 0x1f)) {
+                    
+                        fprintf (state->ofp, "    mov rax, %ld\n", v);
+                        fprintf (state->ofp, "    cqo\n");
+                    
+                    } else {
+                        fprintf (state->ofp, "    mov eax, %ld\n", v);
+                    }
+                
+                } else {
+                
+                    if (current_function_return_size == (DATA_LLONG & 0x1f)) {
+                    
+                        fprintf (state->ofp, "    movq $%ld, %%rax\n", v);
+                        fprintf (state->ofp, "    cqto\n");
+                    
+                    } else {
+                        fprintf (state->ofp, "    movl $%ld, %%eax\n", v);
+                    }
+                
+                }
+            
+            }
+            
+            pending_return_jump = 1;
+            statement_ends_control_flow = 1;
+        
+        }
+        
+        expect (TOK_SEMI, ";");
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_LBRACE) {
+    
+        parse_block ();
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_IF) {
+    
+        int else_label = anon_label++;
+        int end_label = anon_label++;
+        
+        get_token ();
+        expect (TOK_LPAREN, "(");
+        
+        /*
+         * Compile the full if-condition as an expression before testing it.
+         * The older specialised condition emitter jumps to the false label as
+         * soon as the left side of a logical OR is false, which skips the RHS.
+         * That miscompiled expressions such as:
+         *
+         *     if ((base && !base->dword) || (index && ...))
+         *
+         * and made pdas reject valid 32-bit AT&T base/index operands.
+         */
+        emit_statement_jump_if_false (else_label);
+        
+        if (tok.kind != TOK_RPAREN) {
+            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+        }
+        
+        expect (TOK_RPAREN, ")");
+        
+        if (statement_condition_constant_known) {
+        
+            if (statement_condition_constant_value) {
+            
+                parse_statement ();
+                
+                if (_accept (TOK_ELSE)) {
+                    parse_statement_suppressed ();
+                }
+            
+            } else {
+            
+                parse_statement_suppressed ();
+                
+                if (_accept (TOK_ELSE)) {
+                    parse_statement ();
+                }
+            
+            }
+            
+            return;
+        
+        }
+        
+        parse_statement ();
+        
+        {
+        
+            int then_ends_control_flow = statement_ends_control_flow;
+            
+            if (_accept (TOK_ELSE)) {
+            
+                if (pending_return_jump) {
+                
+                    emit_pending_return_jump ();
+                    then_ends_control_flow = 1;
+                
+                } else if (!then_ends_control_flow) {
+                    emit_statement_jump (end_label);
+                }
+                
+                emit_statement_label (else_label);
+                parse_statement ();
+                
+                if (pending_return_jump) {
+                
+                    emit_pending_return_jump ();
+                    statement_ends_control_flow = 1;
+                
+                }
+                
+                emit_statement_label (end_label);
+                statement_ends_control_flow = then_ends_control_flow && statement_ends_control_flow;
+            
+            } else {
+            
+                if (pending_return_jump) {
+                    emit_pending_return_jump ();
+                }
+                
+                emit_statement_label (else_label);
+                statement_ends_control_flow = 0;
+            
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_SWITCH) {
+    
+        parse_switch_statement ();
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_WHILE) {
+    
+        parse_while_statement ();
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_DO) {
+    
+        parse_do_statement ();
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_FOR) {
+    
+        parse_for_statement ();
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_GOTO) {
+    
+        const char *label_start;
+        const char *label_caret;
+        
+        unsigned long label_line;
+        char *label_name = 0;
+        
+        get_token ();
+        
+        label_start = tok.start;
+        label_caret = tok.caret;
+        label_line = get_line_number ();
+        
+        if (tok.kind == TOK_IDENT) {
+        
+            label_name = xstrdup (tok.ident);
+            get_token ();
+            
+            /*
+             * Do not eagerly pop block-local temporary storage for a forward
+             * goto.  A label can legally be later in the same block after
+             * nested statements, and the earlier text scan was too
+             * conservative: it treated the first nested '}' as the end of the
+             * current block.  That produced an extra add to rsp before
+             * `goto skip;` in i386_gen.c's process_bitfield_init(), corrupting
+             * the stack before the local label was reached.
+             */
+            
+            reference_goto_label (label_name, label_line, label_start, label_caret);
+            statement_ends_control_flow = 1;
+            
+            free (label_name);
+        
+        } else {
+            report_line_at (get_filename (), label_line, REPORT_ERROR, label_start, label_caret, "expected label name after goto");
+        }
+        
+        expect (TOK_SEMI, ";");
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_BREAK) {
+    
+        int target_label = current_break_label;
+        
+        long cleanup_base = current_break_cleanup_base;
+        long cleanup_bytes;
+        
+        get_token ();
+        
+        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) {
+        
+            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_CASE) {
+    
+        long value;
+        unsigned long case_line = get_line_number ();
+        
+        const char *case_start = tok.start;
+        const char *case_caret = tok.caret;
+        
+        get_token ();
+        
+        value = const_from_current_case_expr ();
+        add_switch_case_label (value, case_line, case_start, case_caret);
+        
+        if (tok.kind != TOK_COLON) {
+            skip_balanced_until (TOK_COLON, TOK_EOF, TOK_EOF);
+        }
+        
+        expect (TOK_COLON, ":");
+        statement_ends_control_flow = 0;
+        
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_DEFAULT) {
+    
+        unsigned long default_line = get_line_number ();
+        
+        const char *default_start = tok.start;
+        const char *default_caret = tok.caret;
+        
+        get_token ();
+        
+        set_switch_default_label (default_line, default_start, default_caret);
+        expect (TOK_COLON, ":");
+        
+        statement_ends_control_flow = 0;
+        return;
+    
+    }
+    
+    if (tok.kind != TOK_SEMI && tok.kind != TOK_RBRACE && tok.kind != TOK_EOF) {
+    
+        if (parse_postfix_assignment_statement_now ()) {
+        
+            if (tok.kind == TOK_SEMI) {
+            
+                get_token ();
+                return;
+            
+            }
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            
+            expect (TOK_SEMI, ";");
+            return;
+        
+        }
+        
+        emit_load_assignment_rhs_expression_to_reg ("rax");
+        
+        if (tok.kind == TOK_SEMI) {
+        
+            get_token ();
+            return;
+        
+        }
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        
+        expect (TOK_SEMI, ";");
+        return;
+    
+    }
+    
+    expect (TOK_SEMI, ";");
+
+}
+
+static void parse_function_body (const char *name, int storage_class, int is_inline, int return_is_void, int return_is_floating, int return_is_unsigned, int return_size, int return_pointer_depth, unsigned long function_line, const char *function_start, const char *function_caret) {
+
+    int old_return_label = current_return_label;
+    int should_emit = 1;
+    int emit_body = 1;
+    int emit_public = 1;
+    int emit_inline_definition_to_output = 1;
+    
+    FILE *saved_ofp;
+    FILE *function_tmp = 0;
+    
+    char *inline_asm_text = 0;
+    char *function_asm_text = 0;
+    
+    int capture_inline_body = 0;
+    int capture_function_body = 0;
+    
+    int saved_declarator_function_param_count;
+    int saved_declarator_function_has_prototype;
+    int saved_declarator_function_is_variadic;
+    int saved_current_section = current_section;
+    
+    int old_function_is_void;
+    int old_function_is_floating;
+    int old_function_return_size;
+    int old_function_return_is_unsigned;
+    int old_function_return_pointer_depth;
+    int old_function_returns_aggregate;
+    int old_function_has_return_statement;
+    
+    char *function_filename_copy = 0;
+    
+    /**
+     * Inline definitions are compiled into a temporary assembler buffer so
+     * calls in this translation unit can be expanded at the call site.
+     *
+     *   inline int f(...) { ... }
+     *   static inline int f(...) { ... }
+     *       Remember the generated body for inline expansion.  Do not emit an
+     *       out-of-line copy unless a later rule explicitly asks for one.
+     *
+     *   extern inline int f(...) { ... }
+     *       Remember the generated body and also emit the normal public
+     *       definition.
+     *
+     *   int f(...) { ... }
+     *       Normal external definition.  Emit it as public.
+     */
+    if (storage_class == STORAGE_STATIC) {
+        emit_public = 0;
+    } else if (is_inline && storage_class != STORAGE_EXTERN) {
+        emit_public = 0;
+    }
+    
+    if (is_inline && storage_class != STORAGE_EXTERN && !return_is_floating) {
+        emit_inline_definition_to_output = 0;
+    }
+    
+    saved_ofp = state->ofp;
+    
+    saved_declarator_function_param_count = declarator_function_param_count;
+    saved_declarator_function_has_prototype = declarator_function_has_prototype;
+    saved_declarator_function_is_variadic = declarator_function_is_variadic;
+    
+    if (get_filename ()) {
+        function_filename_copy = xstrdup (get_filename ());
+    }
+    
+    capture_inline_body = is_inline && saved_ofp != 0;
+    capture_function_body = saved_ofp != 0;
+    
+    if (capture_function_body) {
+    
+        function_tmp = scc_tmpfile ();
+        
+        if (!function_tmp) {
+            capture_function_body = 0;
+        }
+    
+    }
+    
+    if (emit_body) {
+    
+        if (parsed_dllimport) {
+            report_line_at (get_filename (), last_declarator_name_line, REPORT_ERROR, last_declarator_name_start, last_declarator_name_caret, "function '%s' cannot be defined with '__dllimport'", name);
+        }
+        
+        should_emit = add_global_symbol (name, GLOBAL_SYMBOL_FUNCTION, 0, last_declarator_name_start, last_declarator_name_caret, last_declarator_name_line);
+        
+        set_global_symbol_size (name, return_is_void ? DATA_VOID : return_size);
+        set_global_symbol_unsigned (name, 0);
+        set_global_symbol_floating (name, return_is_floating);
+        set_global_symbol_returns_void (name, return_is_void);
+        set_global_symbol_calling_convention (name, (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention);
+        set_global_symbol_dllimport (name, 0);
+        set_global_symbol_param_count (name, saved_declarator_function_param_count, saved_declarator_function_has_prototype || saved_declarator_function_param_count > 0, saved_declarator_function_is_variadic);
+        
+        if (is_inline) {
+        
+            remember_inline_function_signature (name, saved_declarator_function_param_count, saved_declarator_function_has_prototype || saved_declarator_function_param_count > 0,
+                return_is_void, return_is_floating, return_size);
+        
+        }
+    
+    }
+    
+    old_function_has_return_statement = current_function_has_return_statement;
+    old_function_is_void = current_function_is_void;
+    old_function_is_floating = current_function_is_floating;
+    old_function_return_size = current_function_return_size;
+    old_function_return_is_unsigned = current_function_return_is_unsigned;
+    old_function_return_pointer_depth = current_function_return_pointer_depth;
+    old_function_returns_aggregate = current_function_returns_aggregate;
+    
+    current_function_is_void = return_is_void;
+    current_function_is_floating = return_is_floating;
+    current_function_return_is_unsigned = return_is_unsigned;
+    current_function_return_size = return_size;
+    current_function_return_pointer_depth = return_pointer_depth;
+    current_function_returns_aggregate = (!return_is_void && !return_is_floating && return_pointer_depth == 0 && return_size > (DATA_LLONG & 0x1f));
+    current_function_calling_convention = (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention;
+    current_function_param_stack_bytes = 0;
+    current_function_has_return_statement = 0;
+    
+    parse_old_style_param_decls ();
+    remove_duplicate_pending_params ();
+    
+    /*
+     * Old-style definitions start with an identifier list, so the first
+     * function-symbol install only knows the default int-sized parameter
+     * placeholders.  The declaration list between ')' and '{' is what gives
+     * those parameters their real types.  Refresh the saved call signature
+     * after that list has been parsed, otherwise later calls in the same
+     * translation unit pass 64-bit parameters as single words.
+     */
+    if (emit_body && should_emit) {
+        copy_pending_params_to_global_symbol (name);
+    }
+    
+    current_function_param_stack_bytes = global_symbol_stdcall_stack_bytes (name);
+    
+    reset_local_symbols ();
+    reset_goto_labels ();
+    
+    install_pending_params_as_locals ();
+    clear_pending_params ();
+    
+    if (!emit_body || !should_emit) {
+        state->ofp = 0;
+    } else if (capture_function_body) {
+        state->ofp = function_tmp;
+    }
+    
+    current_return_label = anon_label++;
+    pending_return_jump = 0;
+    
+    current_function_preserve_assignment64_regs = 0;
+    current_function_is_variadic = saved_declarator_function_is_variadic ? 1 : 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 ();
+    check_goto_labels ();
+    
+    if (!current_function_is_void && !current_function_has_return_statement) {
+        report_line_at (function_filename_copy ? function_filename_copy : get_filename (), function_line, REPORT_WARNING, function_start, function_caret, "control reaches end of non-void function");
+    }
+    
+    pending_return_jump = 0;
+    emit_function_end ();
+    
+    current_function_frame_label = -1;
+    current_function_frame_deferred = 0;
+    current_function_frame_enabled = 0;
+    current_function_is_variadic = 0;
+    
+    emit_goto_trampolines ();
+    current_function_uses_single_frame = 0;
+    
+    if (capture_function_body && function_tmp) {
+    
+        function_asm_text = read_tmp_file_text (function_tmp);
+        
+        if (function_asm_text) {
+        
+            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);
+            }
+            
+            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);
+            
+            }
+        
+        }
+        
+        if (function_asm_text) {
+            free (function_asm_text);
+        }
+        
+        if (inline_asm_text) {
+        
+            free (inline_asm_text);
+            inline_asm_text = 0;
+        
+        }
+        
+        scc_close (function_tmp);
+        function_tmp = 0;
+    
+    }
+    
+    reset_local_symbols ();
+    reset_goto_labels ();
+    
+    current_function_has_return_statement = old_function_has_return_statement;
+    current_function_is_void = old_function_is_void;
+    current_function_is_floating = old_function_is_floating;
+    current_function_return_size = old_function_return_size;
+    current_function_return_is_unsigned = old_function_return_is_unsigned;
+    current_function_return_pointer_depth = old_function_return_pointer_depth;
+    current_function_returns_aggregate = old_function_returns_aggregate;
+    
+    current_return_label = old_return_label;
+    state->ofp = saved_ofp;
+    
+    if (capture_inline_body) {
+        current_section = saved_current_section;
+    }
+    
+    if (function_filename_copy) {
+        free (function_filename_copy);
+    }
+    
+    if (inline_asm_text) {
+        free (inline_asm_text);
+    }
+
+}
+
+static int parse_possible_knr_function (void) {
+
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    
+    if (!token_is_ident ()) {
+        return 0;
+    }
+    
+    name_line = get_line_number ();
+    
+    name_start = tok.start;
+    name_caret = tok.caret;
+    
+    name = take_ident ();
+    
+    if (!_accept (TOK_LPAREN)) {
+    
+        free (name);
+        return 0;
+    
+    }
+    
+    clear_pending_params ();
+    
+    declarator_function_param_count = 0;
+    declarator_function_has_prototype = 0;
+    declarator_function_is_variadic = 0;
+    
+    if (tok.kind != TOK_RPAREN) {
+    
+        int old_style_param_start = pending_param_count;
+        
+        for (;;) {
+       
+            if (tok.kind == TOK_ELLIPSIS) {
+            
+                declarator_function_is_variadic = 1;
+                declarator_function_has_prototype = 1;
+                
+                get_token ();
+            
+            } else if (is_type_start (tok.kind)) {
+            
+                int param_base_size;
+                int param_size;
+                int param_pointer_depth;
+                int saved_function_param_count;
+                
+                int count_this_param = 0;
+                int saw_void_param_list = 0;
+                
+                char *param_name = 0;
+                
+                parse_type_spec ();
+                param_base_size = parsed_type_size;
+                
+                preserve_pending_params++;
+                
+                declarator_is_pointer = 0;
+                declarator_pointer_depth = 0;
+                declarator_has_array = 0;
+                declarator_has_function = 0;
+                declarator_function_is_pointer = 0;
+                declarator_array_unsized = 0;
+                declarator_array_count = 1;
+                declarator_last_array_count = 1;
+                
+                if (parsed_type_only_qualifiers && token_is_ident ()) {
+                    get_token ();
+                }
+                
+                saved_function_param_count = declarator_function_param_count;
+                
+                if (tok.kind != TOK_COMMA && tok.kind != TOK_RPAREN) {
+                    parse_declarator (&param_name);
+                }
+                
+                preserve_pending_params--;
+                
+                if (!parsed_type_is_void || declarator_is_pointer || declarator_has_array || declarator_has_function || param_name) {
+                
+                    count_this_param = 1;
+                    
+                    param_size = (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef) ? DATA_PTR : declarator_object_size (param_base_size);
+                    param_pointer_depth = declarator_pointer_depth;
+                    
+                    if ((declarator_has_array || declarator_has_function || parsed_type_is_array_typedef) && param_pointer_depth < 1) {
+                        param_pointer_depth = 1;
+                    }
+                    
+                    if (param_name && find_pending_param_from (param_name, old_style_param_start) >= 0) {
+                        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate parameter '%s'", param_name);
+                    } else {
+                    
+                        add_pending_param (param_name, param_size, type_alignment (param_size),
+                            (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef ? 0 : parsed_type_is_unsigned),
+                                (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef ? 0 : parsed_type_is_floating),
+                                    param_pointer_depth, parsed_type_is_aggregate ? parsed_type_size : (parsed_type_size & 0x1f), parsed_type_is_unsigned);
+                    
+                    }
+                
+                } else {
+                    saw_void_param_list = 1;
+                }
+                
+                if (param_name) {
+                    free (param_name);
+                }
+                
+                declarator_function_param_count = saved_function_param_count + (count_this_param ? 1 : 0);
+                declarator_function_has_prototype = declarator_function_has_prototype || count_this_param || saw_void_param_list;
+            
+            } else if (token_is_ident ()) {
+            
+                if (find_pending_param_from (tok.ident, old_style_param_start) >= 0) {
+                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate parameter '%s'", tok.ident);
+                } else {
+                
+                    add_pending_param (tok.ident, DATA_INT & 0x1f, type_alignment (DATA_INT & 0x1f), 0, 0, 0, 0, 0);
+                    declarator_function_param_count++;
+                
+                }
+                
+                get_token ();
+            
+            } else {
+                skip_balanced_until (TOK_COMMA, TOK_RPAREN, TOK_EOF);
+            }
+            
+            if (!_accept (TOK_COMMA)) {
+                break;
+            }
+        
+        }
+    
+    }
+    
+    expect (TOK_RPAREN, ")");
+    
+    if (is_type_start (tok.kind) || tok.kind == TOK_LBRACE) {
+    
+        parse_function_body (name, STORAGE_NONE, 0, 0, 0, 0, DATA_INT & 0x1f, 0, name_line, name_start, name_caret);
+        
+        if (parsed_dllexport || declarator_dllexport) {
+        
+            vec_push (&vec_dllexports, xstrdup (name));
+            
+            declarator_dllexport = 0;
+            parsed_dllexport = 0;
+        
+        }
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    free (name);
+    return 0;
+
+}
+
+static void append_global_init_byte (int64_s *values, int max_values, int *count, unsigned int value) {
+    append_global_init_value (values, max_values, count, value, DATA_CHAR & 0x1f);
+}
+
+static void parse_char_array_initializer_values (int64_s *values, int max_values, int *count, long row_width) {
+
+    if (tok.kind == TOK_LBRACE) {
+    
+        get_token ();
+        
+        while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
+        
+            parse_char_array_initializer_values (values, max_values, count, row_width);
+            
+            if (!_accept (TOK_COMMA)) {
+                break;
+            }
+        
+        }
+        
+        expect (TOK_RBRACE, "}");
+        return;
+    
+    }
+    
+    if (is_string_token ()) {
+    
+        int64_s tmp[MAX_STRING_INIT_BYTES];
+        int tmp_count = 0;
+        
+        int i;
+        int n;
+        
+        parse_string_initializer_values (tmp, MAX_STRING_INIT_BYTES, &tmp_count);
+        
+        if (row_width <= 0) {
+            n = tmp_count;
+        } else {
+            n = (tmp_count < row_width) ? tmp_count : (int) row_width;
+        }
+        
+        for (i = 0; i < n; i++) {
+            append_global_init_byte (values, max_values, count, (unsigned int) (tmp[i].low & 0xff));
+        }
+        
+        while (row_width > 0 && i < row_width) {
+        
+            append_global_init_byte (values, max_values, count, 0);
+            i++;
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (tok.kind != TOK_COMMA && tok.kind != TOK_SEMI && tok.kind != TOK_RBRACE && tok.kind != TOK_EOF) {
+    
+        if (*count < max_values) {
+            values[*count] = const64_from_current_expr ();
+        } else {
+            const64_from_current_expr ();
+        }
+        
+        (*count)++;
+    
+    }
+
+}
+
+static int global_initializer_parenthesized_string_now (void) {
+
+    const char *p = tok.caret;
+    
+    if (!p || *p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p == '"') {
+        return 1;
+    }
+    
+    if ((*p == 'L' || *p == 'u' || *p == 'U') && p[1] == '"') {
+        return 1;
+    }
+    
+    if (*p == 'u' && p[1] == '8' && p[2] == '"') {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static int global_initializer_cast_before_string_now (void) {
+
+    const char *p = tok.caret;
+    int depth;
+    
+    if (!p || *p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!(ident_start_now ((unsigned char) *p))) {
+        return 0;
+    }
+    
+    depth = 1;
+    
+    while (*p && depth > 0) {
+    
+        if (*p == '(') {
+            depth++;
+        } else if (*p == ')') {
+            depth--;
+        }
+        
+        p++;
+    
+    }
+    
+    if (depth != 0) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p == '"') {
+        return 1;
+    }
+    
+    if ((*p == 'L' || *p == 'u' || *p == 'U') && p[1] == '"') {
+        return 1;
+    }
+    
+    if (*p == 'u' && p[1] == '8' && p[2] == '"') {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static void append_global_zero_initializer_value (int64_s *values, char **symbols, int max_values, int *count) {
+
+    if (*count < max_values) {
+    
+        values[*count].low = 0;
+        values[*count].high = 0;
+        
+        if (symbols) {
+            symbols[*count] = 0;
+        }
+    
+    }
+
+    (*count)++;
+
+}
+
+static int aggregate_initializer_value_field_count (const int *field_sizes, int field_count) {
+
+    int count = 0;
+    int i;
+    
+    for (i = 0; i < field_count; i++) {
+    
+        if (field_sizes[i] > 0) {
+            count++;
+        }
+    
+    }
+    
+    return count;
+
+}
+
+static void parse_global_initializer_values_padded_elements (int64_s *values, char **symbols, int max_values, int *count, int element_field_count) {
+
+    if (element_field_count <= 0 || tok.kind != TOK_LBRACE) {
+    
+        parse_global_initializer_values (values, symbols, max_values, count);
+        return;
+    
+    }
+    
+    get_token ();
+    
+    while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
+    
+        int before = *count;
+        parse_global_initializer_values (values, symbols, max_values, count);
+        
+        if (*count > before) {
+        
+            while ((*count - before) < element_field_count) {
+                append_global_zero_initializer_value (values, symbols, max_values, count);
+            }
+        
+        }
+        
+        if (!_accept (TOK_COMMA)) {
+            break;
+        }
+    
+    }
+    
+    expect (TOK_RBRACE, "}");
+
+}
+
+static void parse_global_initializer_values (int64_s *values, char **symbols, int max_values, int *count) {
+
+    if (tok.kind == TOK_LBRACE) {
+    
+        get_token ();
+        
+        while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
+        
+            parse_global_initializer_values (values, symbols, max_values, count);
+            
+            if (!_accept (TOK_COMMA)) {
+                break;
+            }
+        
+        }
+        
+        expect (TOK_RBRACE, "}");
+        return;
+    
+    }
+    
+    if (tok.kind != TOK_COMMA && tok.kind != TOK_SEMI && tok.kind != TOK_RBRACE && tok.kind != TOK_EOF) {
+    
+        if (is_string_token ()) {
+        
+            if (*count < max_values) {
+            
+                values[*count].low = 0;
+                values[*count].high = 0;
+                
+                if (symbols) {
+                    symbols[*count] = emit_string_literal_global ();
+                }
+            
+            } else {
+                get_token ();
+            }
+            
+            (*count)++;
+        
+        } else if (tok.kind == TOK_LPAREN && global_initializer_parenthesized_string_now ()) {
+        
+            get_token ();
+            
+            if (*count < max_values) {
+            
+                values[*count].low = 0;
+                values[*count].high = 0;
+                
+                if (symbols) {
+                    symbols[*count] = emit_string_literal_global ();
+                } else {
+                
+                    int64_s ignored_values[MAX_AGG_FIELDS];
+                    int ignored_count = 0;
+                    
+                    parse_string_initializer_values (ignored_values, MAX_AGG_FIELDS, &ignored_count);
+                
+                }
+            
+            } else {
+            
+                int64_s ignored_values[MAX_AGG_FIELDS];
+                int ignored_count = 0;
+                
+                parse_string_initializer_values (ignored_values, MAX_AGG_FIELDS, &ignored_count);
+            
+            }
+            
+            expect (TOK_RPAREN, ")");
+            (*count)++;
+        
+        } else if (tok.kind == TOK_LPAREN && global_initializer_cast_before_string_now ()) {
+        
+            int cast_size = 0;
+            int cast_is_unsigned = 0;
+            int cast_is_pointer = 0;
+            
+            get_token ();
+            
+            if (token_starts_type_name () && parse_cast_type_name (&cast_size, &cast_is_unsigned, &cast_is_pointer) && is_string_token ()) {
+            
+                if (*count < max_values) {
+                
+                    values[*count].low = 0;
+                    values[*count].high = 0;
+                    
+                    if (symbols) {
+                        symbols[*count] = emit_string_literal_global ();
+                    }
+                
+                } else {
+                    get_token ();
+                }
+                
+                (*count)++;
+            
+            } else {
+            
+                if (*count < max_values) {
+                
+                    values[*count] = const64_from_current_expr ();
+                    
+                    if (symbols) {
+                        symbols[*count] = 0;
+                    }
+                
+                } else {
+                    const64_from_current_expr ();
+                }
+                
+                (*count)++;
+            
+            }
+        
+        } else if (tok.kind == TOK_AMPER) {
+        
+            get_token ();
+            
+            if (tok.kind != TOK_IDENT) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after '&'");
+            } else {
+            
+                char addr_symbol[256];
+                char *base_name = xstrdup (tok.ident);
+                long addr_offset = 0;
+                int sym_index = find_global_symbol (base_name);
+                long array_count = get_global_symbol_array_count (base_name);
+                long base_size = sym_index >= 0 ? global_symbols[sym_index].size : 0;
+                long elem_size = 0;
+                
+                if (array_count > 0 && base_size > 0) {
+                    elem_size = base_size / array_count;
+                }
+                
+                get_token ();
+                
+                while (tok.kind == TOK_LBRACK) {
+                
+                    int64_s index_value;
+                    long index;
+                    
+                    get_token ();
+                    
+                    index_value.low = 0;
+                    index_value.high = 0;
+                    
+                    if (tok.kind != TOK_RBRACK) {
+                        index_value = const64_from_current_expr ();
+                    }
+                    
+                    index = (long) index_value.low;
+                    
+                    if (elem_size > 0) {
+                        addr_offset += index * elem_size;
+                    }
+                    
+                    expect (TOK_RBRACK, "]");
+                
+                }
+                
+                if (*count < max_values) {
+                
+                    values[*count].low = 0;
+                    values[*count].high = 0;
+                    
+                    if (symbols) {
+                    
+                        if (addr_offset != 0) {
+                        
+                            sprintf (addr_symbol, "%s+%ld", base_name, addr_offset);
+                            symbols[*count] = xstrdup (addr_symbol);
+                        
+                        } else {
+                            symbols[*count] = xstrdup (base_name);
+                        }
+                    
+                    }
+                
+                }
+                
+                (*count)++;
+                free (base_name);
+            
+            }
+        
+        } else if (global_initializer_accept_symbol_addresses && tok.kind == TOK_IDENT && find_global_symbol (tok.ident) >= 0) {
+        
+            if (*count < max_values) {
+            
+                values[*count].low = 0;
+                values[*count].high = 0;
+                
+                if (symbols) {
+                    symbols[*count] = xstrdup (tok.ident);
+                }
+            
+            }
+            
+            (*count)++;
+            get_token ();
+        
+        } else if (*count < max_values) {
+        
+            values[*count] = const64_from_current_expr ();
+                        
+            if (symbols) {
+                symbols[*count] = 0;
+            }
+            
+            (*count)++;
+        
+        } else {
+            const64_from_current_expr ();
+        }
+    
+    }
+
+}
+
+static int int64_is_zero_value (int64_s value) {
+    return value.low == 0 && value.high == 0;
+}
+
+static char masm_pending_data_label[512];
+static char masm_open_data_directive[8];
+
+static int masm_has_pending_data_label = 0;
+static int masm_data_line_open = 0;
+static int masm_data_line_values = 0;
+
+static void masm_set_pending_data_label (const char *name) {
+
+    const char *asm_name = asm_global_symbol_name (name);
+    unsigned long len;
+    
+    if (!asm_name) {
+    
+        masm_has_pending_data_label = 0;
+        masm_pending_data_label[0] = 0;
+        
+        return;
+    
+    }
+    
+    len = strlen (asm_name);
+    
+    if (len >= sizeof (masm_pending_data_label)) {
+        len = sizeof (masm_pending_data_label) - 1;
+    }
+    
+    memcpy (masm_pending_data_label, asm_name, len);
+    
+    masm_pending_data_label[len] = 0;
+    masm_has_pending_data_label = 1;
+
+}
+
+static void masm_flush_data_line (void) {
+
+    if (masm_data_line_open) {
+    
+        fprintf (state->ofp, "\n");
+        
+        masm_data_line_open = 0;
+        masm_data_line_values = 0;
+        
+        masm_open_data_directive[0] = 0;
+    
+    }
+
+}
+
+static void masm_emit_data_prefix (const char *directive) {
+
+    if (masm_has_pending_data_label) {
+    
+        masm_flush_data_line ();
+        fprintf (state->ofp, "%s %s ", masm_pending_data_label, directive);
+        
+        masm_has_pending_data_label = 0;
+        masm_pending_data_label[0] = 0;
+        
+        strncpy (masm_open_data_directive, directive, sizeof (masm_open_data_directive) - 1);
+        
+        masm_open_data_directive[sizeof (masm_open_data_directive) - 1] = 0;
+        masm_data_line_open = 1;
+        masm_data_line_values = 0;
+    
+    } else if (masm_data_line_open && strcmp (masm_open_data_directive, directive) == 0) {
+    
+        if (masm_data_line_values >= 8) {
+        
+            fprintf (state->ofp, "\n    %s ", directive);
+            masm_data_line_values = 0;
+        
+        } else {
+            fprintf (state->ofp, ", ");
+        }
+    
+    } else {
+    
+        masm_flush_data_line ();
+        
+        fprintf (state->ofp, "    %s ", directive);
+        strncpy (masm_open_data_directive, directive, sizeof (masm_open_data_directive) - 1);
+        
+        masm_open_data_directive[sizeof (masm_open_data_directive) - 1] = 0;
+        masm_data_line_open = 1;
+        masm_data_line_values = 0;
+    
+    }
+    
+    masm_data_line_values++;
+
+}
+
+static void emit_global_scalar (int64_s value, int size) {
+
+    unsigned long high = value.high;
+    unsigned long low = value.low;
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+        
+            masm_emit_data_prefix ("db");
+            fprintf (state->ofp, "%ld", low & 0xFFUL);
+        
+        } else if (size == (DATA_SHORT & 0x1f)) {
+        
+            masm_emit_data_prefix ("dw");
+            fprintf (state->ofp, "%ld", low & 0xFFFFUL);
+        
+        } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
+        
+            masm_emit_data_prefix ("dq");
+            fprintf (state->ofp, "0%08lX%08lXh", high & U32_MASK, low & U32_MASK);
+        
+        } else {
+        
+            masm_emit_data_prefix ("dd");
+            fprintf (state->ofp, "%lu", low & U32_MASK);
+        
+        }
+    
+    } else if (state->syntax & ASM_SYNTAX_NASM) {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, "    db %ld\n", low & 0xFFUL);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, "    dw %ld\n", low & 0xFFFFUL);
+        } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
+        
+            fprintf (state->ofp, "    dd %lu\n", low & U32_MASK);
+            fprintf (state->ofp, "    dd %lu\n", high & U32_MASK);
+        
+        } else {
+            fprintf (state->ofp, "    dd %lu\n", low & U32_MASK);
+        }
+    
+    } else {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, "    .byte %ld\n", low & 0xFFUL);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, "    .word %ld\n", low & 0xFFFFUL);
+        } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
+        
+            fprintf (state->ofp, "    .long %lu\n", low & U32_MASK);
+            fprintf (state->ofp, "    .long %lu\n", high & U32_MASK);
+        
+        } else {
+            fprintf (state->ofp, "    .long %lu\n", low & U32_MASK);
+        }
+    
+    }
+
+}
+
+static void emit_global_address (const char *symbol, int size) {
+
+    const char *asm_symbol;
+    int64_s zero;
+    
+    if (!symbol || !*symbol) {
+    
+        zero.low = 0;
+        zero.high = 0;
+        
+        emit_global_scalar (zero, size);
+        return;
+    
+    }
+    
+    if (size != DATA_PTR) {
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "address initializer requires pointer-sized object");
+    }
+    
+    emit_extern_reference_symbol (symbol, DATA_PTR);
+    asm_symbol = asm_global_symbol_name (symbol);
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+    
+        masm_emit_data_prefix ("dq");
+        fprintf (state->ofp, "offset %s", asm_symbol);
+    
+    } else if (state->syntax & ASM_SYNTAX_NASM) {
+        fprintf (state->ofp, "    dq %s\n", asm_symbol);
+    } else {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    .qaud offset %s\n", asm_symbol);
+        } else {
+            fprintf (state->ofp, "    .quad %s\n", asm_symbol);
+        }
+    
+    }
+
+}
+
+static void emit_global_value (const int64_s *value, const char *symbol, int size) {
+
+    int64_s zero;
+    
+    if (symbol) {
+    
+        emit_global_address (symbol, size);
+        return;
+    
+    }
+    
+    if (value) {
+    
+        emit_global_scalar (*value, size);
+        return;
+    
+    }
+    
+    zero.low = 0;
+    zero.high = 0;
+    
+    emit_global_scalar (zero, size);
+
+}
+
+static void emit_global_space (long bytes) {
+
+    if (bytes <= 0) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+    
+        masm_emit_data_prefix ("db");
+        fprintf (state->ofp, "%ld dup (?)", bytes);
+    
+    } else if (state->syntax & ASM_SYNTAX_NASM) {
+        fprintf (state->ofp, "    resb %ld\n", bytes);
+    } else {
+        fprintf (state->ofp, "    .space %ld\n", bytes);
+    }
+
+}
+
+static int field_size_bytes (int field_size) {
+
+    if (field_size < 0) {
+        return -field_size;
+    }
+    
+    return field_size;
+
+}
+
+static int global_initializer_is_all_zero (const int64_s *values, char **symbols, int value_count) {
+
+    int i;
+
+    if (symbols) {
+        for (i = 0; i < value_count; i++) {
+            if (symbols[i]) {
+                return 0;
+            }
+        }
+    }
+
+    if (!values || value_count <= 0) {
+        return 1;
+    }
+
+    for (i = 0; i < value_count; i++) {
+        if (!int64_is_zero_value (values[i])) {
+            return 0;
+        }
+    }
+
+    return 1;
+
+}
+
+static void emit_global_label (const char *name, int is_static) {
+
+    const char *asm_name = asm_global_symbol_name (name);
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+    
+        if (!is_static) {
+            fprintf (state->ofp, "public %s\n", asm_name);
+        }
+        
+        fprintf (state->ofp, "%s:\n", asm_name);
+    
+    } else if (state->syntax & ASM_SYNTAX_NASM) {
+    
+        if (!is_static) {
+            fprintf (state->ofp, "global %s\n", asm_name);
+        }
+        
+        fprintf (state->ofp, "%s:\n", asm_name);
+    
+    } else {
+    
+        if (!is_static) {
+            fprintf (state->ofp, ".globl %s\n", asm_name);
+        }
+        
+        fprintf (state->ofp, "%s:\n", asm_name);
+    
+    }
+
+}
+
+static void emit_global_data_label (const char *name, int is_static) {
+
+    const char *asm_name = asm_global_symbol_name (name);
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+    
+        masm_flush_data_line ();
+        
+        if (!is_static) {
+            fprintf (state->ofp, "public %s\n", asm_name);
+        }
+        
+        masm_set_pending_data_label (name);
+    
+    } else {
+        emit_global_label (name, is_static);
+    }
+
+}
+
+static void emit_global_object (const char *name, int size, int is_array, long array_count, const int *field_sizes, int field_count, const int64_s *values, char **symbols, int value_count, int is_aggregate, int is_static) {
+
+    int64_s zero;
+    
+    int value_index, use_bss, i;
+    long emitted, total;
+
+    zero.low = 0;
+    zero.high = 0;
+    
+    if (!state->ofp || !name || !*name) {
+        return;
+    }
+    
+    if (size <= 0) {
+        size = DATA_INT & 0x1f;
+    }
+    
+    if (array_count <= 0) {
+        array_count = 1;
+    }
+    
+    total = size * array_count;
+    use_bss = global_initializer_is_all_zero (values, symbols, value_count);
+
+    if (use_bss) {
+    
+        switch_section (SECTION_BSS);
+        
+        emit_global_data_label (name, is_static);
+        emit_global_space (total);
+        
+        return;
+    
+    }
+    
+    switch_section (SECTION_DATA);
+    emit_global_data_label (name, is_static);
+    
+    value_index = 0;
+    emitted = 0;
+    
+    if (!is_array && !is_aggregate) {
+    
+        if (value_count > 0) {
+            emit_global_value (&values[0], symbols ? symbols[0] : 0, size);
+        } else {
+            emit_global_value (0, 0, size);
+        }
+        
+        return;
+    
+    }
+    
+    if (is_aggregate && field_count > 0) {
+    
+        while (emitted < total) {
+        
+            for (i = 0; i < field_count && emitted < total; i++) {
+            
+                int fsize = field_sizes[i];
+                
+                if (fsize < 0) {
+                
+                    emit_global_space (-fsize);
+                    
+                    emitted += -fsize;
+                    continue;
+                
+                }
+                
+                if (value_index < value_count) {
+                
+                    emit_global_value (&values[value_index], symbols ? symbols[value_index] : 0, fsize);
+                    value_index++;
+                
+                } else {
+                    emit_global_scalar (zero, fsize);
+                }
+                
+                emitted += field_size_bytes (fsize);
+            
+            }
+        
+        }
+        
+        emit_global_space (total - emitted);
+        return;
+    
+    }
+    
+    if (is_array) {
+    
+        int elem_size = size;
+        
+        if (field_count > 0 && field_sizes[0] > 0) {
+            elem_size = field_sizes[0];
+        }
+        
+        while (emitted + elem_size <= total) {
+        
+            if (value_index < value_count) {
+            
+                emit_global_value (&values[value_index], symbols ? symbols[value_index] : 0, elem_size);
+                value_index++;
+            
+            } else {
+                emit_global_scalar (zero, elem_size);
+            }
+            
+            emitted += elem_size;
+        
+        }
+        
+        emit_global_space (total - emitted);
+        return;
+    
+    }
+    
+    emit_global_space (total);
+
+}
+
+static char *emit_string_literal_global (void) {
+
+    int64_s values[MAX_AGG_FIELDS];
+    
+    char label[64];
+    char skip_label[64];
+    
+    int elem_size = DATA_CHAR & 0x1f;
+    int value_count = 0, i;
+    
+    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+        sprintf (label, "LC%d", anon_label++);
+    } else {
+        sprintf (label, ".LC%d", anon_label++);
+    }
+    
+    parse_string_initializer_values (values, MAX_AGG_FIELDS, &value_count);
+    elem_size = parsed_string_initializer_elem_size;
+    
+    /*
+     * Dead statement parsing suppresses output by temporarily clearing
+     * state->ofp.  Still consume the literal so the token stream remains
+     * correct, but do not try to emit a .data label through a NULL FILE *.
+     * This is needed for optimised-away bodies such as:
+     *
+     *     while (0) { printf ("Hello\n"); }
+     */
+    if (!state->ofp) {
+        return xstrdup (label);
+    }
+    
+    if (current_section == SECTION_TEXT) {
+    
+        if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+            sprintf (skip_label, "L%d", anon_label++);
+        } else {
+            sprintf (skip_label, ".L%d", anon_label++);
+        }
+        
+        fprintf (state->ofp, "    jmp %s\n", skip_label);
+        
+        switch_section (SECTION_DATA);
+        emit_global_data_label (label, 1);
+        
+        for (i = 0; i < value_count; i++) {
+            emit_global_scalar (values[i], elem_size);
+        }
+        
+        switch_section (SECTION_TEXT);
+        emit_global_label (skip_label, 1);
+        
+        return xstrdup (label);
+    
+    }
+    
+    switch_section (SECTION_DATA);
+    emit_global_data_label (label, 1);
+    
+    for (i = 0; i < value_count; i++) {
+        emit_global_scalar (values[i], elem_size);
+    }
+    
+    return xstrdup (label);
+
+}
+
+static const char *masm_extern_type_name (int size, int is_function) {
+
+    if (is_function) {
+        return "PROC";
+    }
+
+    if (size == (DATA_CHAR & 0x1f)) {
+        return "BYTE";
+    }
+
+    if (size == (DATA_SHORT & 0x1f)) {
+        return "WORD";
+    }
+
+    if (size == (DATA_LLONG & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
+        return "QWORD";
+    }
+
+    return "DWORD";
+
+}
+
+static void emit_extern_line (const char *name, int size, int is_function) {
+
+    const char *asm_name = get_global_symbol_dllimport (name) ? asm_global_import_symbol_name (name) : asm_global_symbol_name (name);
+    
+    if (get_global_symbol_dllimport (name)) {
+    
+        size = DATA_PTR & 0x1f;
+        is_function = 0;
+    
+    }
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+        fprintf (state->ofp, "extrn %s:%s\n", asm_name, masm_extern_type_name (size, is_function));
+    } else if (state->syntax & ASM_SYNTAX_NASM) {
+        fprintf (state->ofp, "extern %s\n", asm_name);
+    } else {
+        fprintf (state->ofp, ".extern %s\n", asm_name);
+    }
+
+}
+
+static void emit_extern_symbol (const char *name, int size, int is_function) {
+
+    int i;
+    
+    (void) size;
+    (void) is_function;
+    
+    if (!state->ofp || !name || !*name) {
+        return;
+    }
+    
+    i = find_global_symbol (name);
+    
+    /**
+     * Do not write assembler externs at the point of use.  A symbol can be
+     * declared/called before its real definition appears later in the same
+     * translation unit; NASM then rejects "extern foo" followed by "foo:" as
+     * an inconsistent redefinition.  Just mark that generated code referenced
+     * the external-looking symbol, and emit the actual assembler externs once
+     * the whole file has been parsed and we know which names stayed external.
+     */
+    if (i < 0 || !global_symbols[i].is_extern) {
+        return;
+    }
+    
+    global_symbols[i].extern_emitted = 1;
+
+}
+
+static void emit_pending_extern_symbols (void) {
+
+    int i;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    for (i = 0; i < global_symbol_count; i++) {
+    
+        if (!global_symbols[i].is_extern || !global_symbols[i].extern_emitted) {
+            continue;
+        }
+        
+        emit_extern_line (global_symbols[i].name,
+            global_symbols[i].size > 0 ? global_symbols[i].size : (DATA_INT & 0x1f),
+                global_symbols[i].kind == GLOBAL_SYMBOL_FUNCTION);
+    
+    }
+
+}
+
+static void emit_extern_reference_symbol (const char *name, int size) {
+    emit_extern_symbol (name, size, get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION);
+}
+
+static void parse_external_after_type (void) {
+
+    for (;;) {
+    
+        char **init_symbols = 0;
+        int64_s *init_values = 0;
+        
+        char *name = 0;
+        int init_value_count = 0, i;
+        
+        int object_fields[MAX_AGG_FIELDS];
+        int object_field_count = 0;
+        
+        const char *name_start, *name_caret;
+        unsigned long name_line;
+        
+        int saved_field_count = parsed_field_count;
+        
+        int declaration_is_inline;
+        int declaration_storage;
+        int declaration_dllimport = 0;
+        int declaration_dllexport = 0;
+        
+        int decl_is_pointer;
+        int decl_pointer_depth;
+        int decl_has_array;
+        int decl_has_function;
+        int decl_function_is_pointer;
+        int decl_function_param_count;
+        int decl_function_has_prototype;
+        int decl_function_is_variadic;
+        int decl_array_unsized;
+        
+        long decl_array_count;
+        long decl_first_array_count;
+        long decl_last_array_count;
+        
+        for (i = 0; i < saved_field_count; i++) {
+            object_fields[i] = parsed_field_sizes[i];
+        }
+        
+        object_field_count = saved_field_count;
+        
+        declaration_is_inline = parsed_type_is_inline;
+        declaration_storage = parsed_storage_class;
+        declaration_dllimport = parsed_dllimport;
+        declaration_dllexport = parsed_dllexport;
+        
+        consume_post_type_declaration_modifiers_now (&declaration_dllimport, &declaration_dllexport);
+        parse_declarator (&name);
+        
+        declaration_dllimport = declaration_dllimport || parsed_dllimport || declarator_dllimport;
+        declaration_dllexport = declaration_dllexport || parsed_dllexport || declarator_dllexport;
+        
+        apply_typedef_array_to_declarator ();
+        
+        decl_is_pointer = declarator_is_pointer;
+        decl_pointer_depth = declarator_pointer_depth;
+        decl_has_array = declarator_has_array;
+        decl_has_function = declarator_has_function;
+        decl_function_is_pointer = declarator_function_is_pointer;
+        decl_function_param_count = declarator_function_param_count;
+        decl_function_has_prototype = declarator_function_has_prototype;
+        decl_function_is_variadic = declarator_function_is_variadic;
+        decl_array_unsized = declarator_array_unsized;
+        decl_array_count = declarator_array_count;
+        decl_first_array_count = declarator_first_array_count;
+        decl_last_array_count = declarator_last_array_count;
+        
+        name_start = last_declarator_name_start;
+        name_caret = last_declarator_name_caret;
+        
+        name_line = last_declarator_name_line;
+        
+        if (declaration_storage == STORAGE_TYPEDEF) {
+        
+            if (name) {
+            
+                make_declarator_fields (object_fields, &object_field_count, parsed_field_sizes, parsed_field_count, parsed_type_size, parsed_type_is_aggregate);
+                
+                save_typedef_name (name, declarator_object_size (parsed_type_size),
+                    (declarator_is_pointer ? 0 : parsed_type_is_unsigned),
+                        (declarator_is_pointer ? 0 : parsed_type_is_void),
+                            (!declarator_is_pointer && (parsed_type_is_aggregate || declarator_has_array)),
+                                (!declarator_is_pointer && declarator_has_array),
+                                    declarator_array_count, parsed_type_size,
+                                        (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention,
+                                            object_fields, object_field_count);
+            
+            }
+            
+            if (_accept (TOK_ASSIGN)) {
+            
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "typedef '%s' is initialized", name ? name : "");
+                skip_initializer ();
+            
+            }
+            
+            if (name) {
+                free (name);
+            }
+            
+            if (!_accept (TOK_COMMA)) {
+                break;
+            }
+            
+            continue;
+        
+        }
+        
+        if (name && declarator_has_function && (tok.kind == TOK_LBRACE || is_type_start (tok.kind))) {
+        
+            if (declaration_dllexport || parsed_dllexport || declarator_dllexport) {
+            
+                vec_push (&vec_dllexports, xstrdup (name));
+                
+                declarator_dllexport = 0;
+                parsed_dllexport = 0;
+                declaration_dllexport = 0;
+            
+            }
+            
+            parse_function_body (name, declaration_storage, declaration_is_inline,
+                (parsed_type_is_void && !declarator_is_pointer),
+                    (declarator_is_pointer ? 0 : parsed_type_is_floating),
+                        (declarator_is_pointer ? 0 : parsed_type_is_unsigned),
+                            (declarator_is_pointer ? DATA_PTR : parsed_type_size),
+                                (declarator_is_pointer ? (declarator_pointer_depth > 0 ? declarator_pointer_depth : 1) : 0),
+                                    name_line, name_start, name_caret);
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (parsed_type_is_void && !declarator_is_pointer && !declarator_has_function) {
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "variable '%s' declared void", name ? name : "");
+        }
+        
+        if (declarator_is_pointer) {
+        
+            object_field_count = 1;
+            object_fields[0] = DATA_PTR;
+        
+        }
+        
+        init_values = xmalloc (sizeof (*init_values) * MAX_GLOBAL_INIT_FIELDS);
+        init_symbols = xmalloc (sizeof (*init_symbols) * MAX_GLOBAL_INIT_FIELDS);
+        
+        for (i = 0; i < MAX_GLOBAL_INIT_FIELDS; i++) {
+            init_symbols[i] = 0;
+        }
+        
+        if (_accept (TOK_ASSIGN)) {
+        
+            if (declarator_has_array && !declarator_is_pointer && (parsed_type_size & 0x1f) == (DATA_CHAR & 0x1f) && (is_string_token () || tok.kind == TOK_LBRACE)) {
+            
+                if (is_string_token ()) {
+                    parse_string_initializer_values (init_values, MAX_GLOBAL_INIT_FIELDS, &init_value_count);
+                } else {
+                    parse_char_array_initializer_values (init_values, MAX_GLOBAL_INIT_FIELDS, &init_value_count, declarator_last_array_count);
+                }
+                
+                if (decl_array_unsized) {
+                    decl_array_count = init_value_count;
+                }
+            
+            } else if (declarator_is_pointer && is_string_token ()) {
+            
+                init_values[0].low = 0;
+                init_values[0].high = 0;
+                
+                init_symbols[0] = emit_string_literal_global ();
+                init_value_count = 1;
+            
+            } else if (!declarator_is_pointer && parsed_type_is_floating) {
+            
+                init_values[0] = parse_floating_const_expr_bits_now (parsed_type_size);
+                init_symbols[0] = 0;
+                init_value_count = 1;
+            
+            } else {
+            
+                {
+                
+                    int saved_accept_symbol_addresses = global_initializer_accept_symbol_addresses;
+                    global_initializer_accept_symbol_addresses = declarator_is_pointer || declarator_has_function || parsed_type_is_aggregate || declarator_has_array;
+                    
+                    if (declarator_has_array && !declarator_is_pointer && parsed_type_is_aggregate && parsed_field_count > 0 && tok.kind == TOK_LBRACE) {
+                        parse_global_initializer_values_padded_elements (init_values, init_symbols, MAX_GLOBAL_INIT_FIELDS, &init_value_count, aggregate_initializer_value_field_count (parsed_field_sizes, parsed_field_count));
+                    } else {
+                        parse_global_initializer_values (init_values, init_symbols, MAX_GLOBAL_INIT_FIELDS, &init_value_count);
+                    }
+                    
+                    global_initializer_accept_symbol_addresses = saved_accept_symbol_addresses;
+                
+                }
+                
+                if (decl_has_array && decl_array_unsized) {
+                
+                    if (parsed_type_is_aggregate && object_field_count > 0) {
+                        decl_array_count = (init_value_count + object_field_count - 1) / object_field_count;
+                    } else {
+                        decl_array_count = init_value_count;
+                    }
+                
+                }
+            
+            }
+        
+        }
+        
+        if (init_value_count > MAX_GLOBAL_INIT_FIELDS) {
+        
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "too many initializer values for '%s'", name ? name : "");
+            init_value_count = MAX_GLOBAL_INIT_FIELDS;
+        
+        }
+        
+        declarator_is_pointer = decl_is_pointer;
+        declarator_pointer_depth = decl_pointer_depth;
+        declarator_has_array = decl_has_array;
+        declarator_has_function = decl_has_function;
+        declarator_function_is_pointer = decl_function_is_pointer;
+        declarator_function_param_count = decl_function_param_count;
+        declarator_function_has_prototype = decl_function_has_prototype;
+        declarator_function_is_variadic = decl_function_is_variadic;
+        declarator_array_unsized = decl_array_unsized;
+        declarator_array_count = decl_array_count;
+        declarator_first_array_count = decl_first_array_count;
+        declarator_last_array_count = decl_last_array_count;
+        
+        if (name) {
+        
+            if (declarator_has_function && !declarator_function_is_pointer && !declarator_has_array) {
+            
+                /*
+                 * A file-scope function declaration is a declaration even
+                 * without an explicit extern storage class.  Keep it in the
+                 * global symbol table so a later call does not fall back to
+                 * the implicit-function-declaration path.
+                 *
+                 * Store prototypes as extern-like declarations here.  A real
+                 * function body will later turn the symbol into a definition
+                 * through add_global_symbol(), which already handles replacing
+                 * an extern declaration with the definition.
+                 */
+                add_global_symbol (name, GLOBAL_SYMBOL_FUNCTION, 1, name_start, name_caret, name_line);
+                
+                if (find_global_symbol (name) >= 0) {
+                
+                    set_global_symbol_size (name, declarator_is_pointer ? DATA_PTR : (parsed_type_is_void ? DATA_VOID : parsed_type_size));
+                    set_global_symbol_pointer_info (name, declarator_effective_pointer_depth_now (),
+                        declarator_effective_pointed_size_now (parsed_type_size, object_fields, object_field_count));
+                    set_global_symbol_tag_name (name, parsed_type_tag_name);
+                    set_global_symbol_unsigned (name, 0);
+                    set_global_symbol_floating (name, declarator_is_pointer ? 0 : parsed_type_is_floating);
+                    set_global_symbol_returns_void (name, parsed_type_is_void && !declarator_is_pointer && !declarator_function_is_pointer);
+                    set_global_symbol_param_count (name, declarator_function_param_count, declarator_function_has_prototype || declarator_function_param_count > 0, declarator_function_is_variadic);
+                    
+                    set_global_symbol_calling_convention (name, (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention);
+                    set_global_symbol_dllimport (name, declaration_dllimport);
+                    
+                    copy_pending_params_to_global_symbol (name);
+                
+                }
+            
+            } else if ((declaration_storage == STORAGE_EXTERN || declaration_dllimport) && init_value_count == 0) {
+            
+                add_global_symbol (name, GLOBAL_SYMBOL_OBJECT, 1, name_start, name_caret, name_line);
+                
+                if (find_global_symbol (name) >= 0) {
+                
+                    set_global_symbol_size (name, declarator_is_pointer ? DATA_PTR : declarator_object_size (parsed_type_size));
+                    set_global_symbol_pointer_info (name, declarator_effective_pointer_depth_now (),
+                        declarator_effective_pointed_size_now (parsed_type_size, object_fields, object_field_count));
+                    set_global_symbol_tag_name (name, parsed_type_tag_name);
+                    set_global_symbol_unsigned (name, declarator_is_pointer ? 0 : parsed_type_is_unsigned);
+                    set_global_symbol_array (name, declarator_has_array);
+                    set_global_symbol_array_count (name, declarator_has_array ? declarator_array_count : 0);
+                    set_global_symbol_array_dimensions (name, declarator_has_array ? declarator_array_dimensions : 0);
+                    set_global_symbol_array_element_size (name, declarator_array_element_size_now (parsed_type_size));
+                    set_global_symbol_dllimport (name, declaration_dllimport);
+                
+                }
+            
+            } else {
+            
+                if (add_global_symbol (name, GLOBAL_SYMBOL_OBJECT, 0, name_start, name_caret, name_line)) {
+                
+                    set_global_symbol_size (name, declarator_is_pointer ? DATA_PTR : declarator_object_size (parsed_type_size));
+                    set_global_symbol_pointer_info (name, declarator_effective_pointer_depth_now (),
+                        declarator_effective_pointed_size_now (parsed_type_size, object_fields, object_field_count));
+                    set_global_symbol_tag_name (name, parsed_type_tag_name);
+                    set_global_symbol_unsigned (name, declarator_is_pointer ? 0 : parsed_type_is_unsigned);
+                    set_global_symbol_floating (name, declarator_is_pointer ? 0 : parsed_type_is_floating);
+                    set_global_symbol_array (name, declarator_has_array);
+                    set_global_symbol_array_count (name, declarator_has_array ? declarator_array_count : 0);
+                    set_global_symbol_array_dimensions (name, declarator_has_array ? declarator_array_dimensions : 0);
+                    set_global_symbol_array_element_size (name, declarator_array_element_size_now (parsed_type_size));
+                    
+                    emit_global_object (name, declarator_is_pointer ? DATA_PTR : (declarator_has_array ? parsed_type_size : (parsed_type_is_aggregate ? parsed_type_size : (parsed_type_size & 0x1f))),
+                        declarator_has_array, declarator_array_count, object_fields, object_field_count,
+                            init_values, init_symbols, init_value_count, (!declarator_is_pointer && parsed_type_is_aggregate),
+                                declaration_storage == STORAGE_STATIC);
+                
+                }
+            
+            }
+            
+            free (name);
+        
+        }
+        
+        for (i = 0; i < MAX_GLOBAL_INIT_FIELDS; i++) {
+        
+            if (init_symbols[i]) {
+            
+                free (init_symbols[i]);
+                init_symbols[i] = 0;
+            
+            }
+        
+        }
+        
+        free (init_symbols);
+        free (init_values);
+        
+        if (!_accept (TOK_COMMA)) {
+            break;
+        }
+    
+    }
+    
+    if (tok.kind == TOK_SEMI) {
+        get_token ();
+    } else if (is_type_start (tok.kind)) {
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "missing ';' after declaration");
+    } else {
+        expect (TOK_SEMI, ";");
+    }
+
+}
+
+void compile_translation_unit64 (void) {
+
+    if (state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_MASM) {
+            fprintf (state->ofp, ".model flat\n");
+        } else if (state->syntax & ASM_SYNTAX_NASM) {
+            fprintf (state->ofp, "bits 64\n");
+        } else if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, ".intel_syntax noprefix\n");
+        }
+    
+    }
+    
+    current_section = SECTION_NONE;
+    
+    clear_global_symbols ();
+    clear_inline_functions ();
+    clear_enum_constants ();
+    clear_typedef_names ();
+    
+    get_token ();
+    
+    while (tok.kind != TOK_EOF) {
+    
+        if (is_type_start (tok.kind)) {
+        
+            parse_type_spec ();
+            parse_external_after_type ();
+            
+            continue;
+        
+        }
+        
+        if (parse_possible_knr_function ()) {
+            continue;
+        }
+        
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected external declaration");
+        get_token ();
+    
+    }
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+        masm_flush_data_line ();
+    }
+    
+    emit_pending_extern_symbols ();
+    
+    if (vec_dllexports.length) {
+    
+        char *p, *tmp;
+        
+        const char *name;
+        long i;
+        
+        FILE *fp;
+        
+        if ((p = strrchr (state->ofile, '.'))) {
+        
+            tmp = xmalloc (p - state->ofile + 5);
+            sprintf (tmp, "%.*s.def", (int) (p - state->ofile), state->ofile);
+        
+        } else {
+        
+            tmp = xmalloc (strlen (state->ofile) + 5);
+            sprintf (tmp, "%s.def", state->ofile);
+        
+        }
+        
+        if ((fp = fopen (tmp, "w"))) {
+        
+            fprintf (fp, "EXPORTS\n");
+            
+            for (i = 0; i < vec_dllexports.length; i++) {
+            
+                if ((name = asm_global_symbol_name (vec_dllexports.data[i]))) {
+                    fprintf (fp, "    %s\n", name);
+                }
+            
+            }
+            
+            fclose (fp);
+            
+        }
+    
+    }
+    
+    if (state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_MASM) {
+        
+            masm_flush_data_line ();
+            fprintf (state->ofp, "end\n");
+        
+        }
+    
+    }
+
+}
diff --git a/cc.c b/cc.c
index 74312ad72a53b47ae86f1911a60c5215c53e46eb..48dbbced1a299ad56018e06ea5548c1cea8edb10 100755 (executable)
--- a/cc.c
+++ b/cc.c
@@ -140,7 +140,12 @@ int main (int argc, char **argv) {
         return EXIT_FAILURE;
     }
     
-    compile_translation_unit ();
+    if (state->bits == 32) {
+        compile_translation_unit32 ();
+    } else if (state->bits == 64) {
+        compile_translation_unit64 ();
+    }
+    
     return (get_error_count () > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
 
 }
diff --git a/cc.h b/cc.h
index d971faee0e4610848e6fb5235ceeddf37e124f81..a014e70a9a53f5c0fe8bc7cec8a0ab2c8268de4a 100755 (executable)
--- a/cc.h
+++ b/cc.h
@@ -24,7 +24,8 @@ struct cc_state {
     
     int pedantic;
     int mode;
-    int std;
+    
+    int bits, std;
     int long64;
     int syntax;
     
diff --git a/i386.c b/i386.c
new file mode 100644 (file)
index 0000000..c25401d
--- /dev/null
+++ b/i386.c
@@ -0,0 +1,35596 @@
+/******************************************************************************
+ * @file            i386.c
+ *****************************************************************************/
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+#include    "cc.h"
+#include    "expr.h"
+#include    "lib.h"
+#include    "parse.h"
+#include    "report.h"
+#include    "token.h"
+
+#define     SECTION_NONE                0
+#define     SECTION_TEXT                1
+#define     SECTION_DATA                2
+#define     SECTION_BSS                 3
+
+static int current_section = 0;
+static int anon_label = 1;
+
+static int pending_return_jump = 0;
+static int local_static_id = 1;
+
+#define     MAX_PENDING_STATEMENT_LABELS                    256
+
+static int pending_statement_labels[MAX_PENDING_STATEMENT_LABELS];
+static int pending_statement_label_count = 0;
+
+static void flush_pending_statement_labels (void);
+
+static int current_function_preserve_assignment64_regs = 0;
+static int current_return_label = 0;
+
+static int index_step_size (int size) {
+
+    if (size == DATA_CHAR || size == DATA_SHORT || size == DATA_INT ||
+        size == DATA_LONG || size == DATA_LLONG || size == DATA_FLOAT ||
+        size == DATA_DOUBLE) {
+        return size & 0x1f;
+    }
+    
+    if (size <= 0) {
+        return DATA_INT & 0x1f;
+    }
+    
+    return size;
+
+}
+
+static int rhs_last_pointer_depth = 0;
+static int rhs_last_pointed_size = 0;
+
+static void set_rhs_last_pointer_info (int depth, int size) {
+
+    rhs_last_pointer_depth = depth;
+    rhs_last_pointed_size = depth > 1 ? DATA_PTR : (size > 0 ? size : (DATA_INT & 0x1f));
+
+}
+
+static void clear_rhs_last_pointer_info (void) {
+
+    rhs_last_pointer_depth = 0;
+    rhs_last_pointed_size = 0;
+
+}
+
+static int current_function_has_return_statement = 0;
+static int current_parse_block_depth = 0;
+static int current_function_is_void = 0;
+static int current_function_is_floating = 0;
+static int current_function_return_size = DATA_NONE;
+static int current_function_return_is_unsigned = 0;
+static int current_function_returns_aggregate = 0;
+static int current_function_param_stack_bytes = 0;
+
+static enum token_kind current_function_calling_convention = TOK_EOF;
+
+static struct local_symbol *pending_struct_return_lhs = 0;
+static const char *pending_struct_return_global_name = 0;
+
+static int pending_struct_return_stack_address = 0;
+static int pending_struct_return_stack_offset = 0;
+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 void masm_flush_data_line (void);
+
+static int postfix_member_pointer_depth = 0;
+static int postfix_member_pointed_size = 0;
+static int postfix_member_seen = 0;
+static int postfix_copy_lvalue_size = 0;
+
+static const char *postfix_copy_lvalue_tag_name = 0;
+
+static int postfix_member_offset = 0;
+static int postfix_member_size = 0;
+
+static int postfix_member_is_floating = 0;
+static int postfix_member_is_unsigned = 0;
+
+static int find_member_info (const char *name, int *offset, int *size) {
+    return find_member_info_ex (name, offset, size, 0, 0, 0, 0);
+}
+
+static void clear_typedef_names (void) {
+
+    int i;
+    
+    for (i = 0; i < typedef_name_count; i++) {
+    
+        free (typedef_names[i].name);
+        
+        typedef_names[i].name = 0;
+        typedef_names[i].size = 0;
+        
+        typedef_names[i].tag_name = 0;
+        
+        typedef_names[i].is_aggregate = 0;
+        typedef_names[i].is_unsigned = 0;
+        
+        typedef_names[i].field_count = 0;
+        typedef_names[i].is_array = 0;
+        typedef_names[i].array_count = 1;
+        typedef_names[i].array_element_size = DATA_NONE;
+        
+        typedef_names[i].calling_convention = TOK_EOF;
+    
+    }
+    
+    typedef_name_count = 0;
+
+}
+
+static void save_typedef_name (const char *name, int size, int is_unsigned, int is_void, int is_aggregate, int is_array, long array_count, int array_element_size, enum token_kind calling_convention, const int *field_sizes, int field_count) {
+
+    struct typedef_entry *entry;
+    int i;
+    
+    if (!name || !*name) {
+        return;
+    }
+    
+    entry = find_typedef_name (name);
+    
+    if (!entry) {
+    
+        if (typedef_name_count >= MAX_TYPEDEF_NAMES) {
+        
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "too many typedef names");
+            return;
+        
+        }
+        
+        entry = &typedef_names[typedef_name_count++];
+        entry->name = xstrdup (name);
+        entry->tag_name = 0;
+        entry->calling_convention = TOK_EOF;
+    
+    }
+    
+    if (entry->tag_name) {
+    
+        free (entry->tag_name);
+        entry->tag_name = 0;
+    
+    }
+    
+    if (parsed_type_tag_name[0]) {
+        entry->tag_name = xstrdup (parsed_type_tag_name);
+    } else if (is_aggregate && name && *name) {
+        entry->tag_name = xstrdup (name);
+    }
+    
+    entry->is_void = is_void;
+    entry->size = size;
+    
+    entry->is_unsigned = is_unsigned;
+    entry->is_aggregate = is_aggregate;
+    
+    entry->field_count = 0;
+    entry->is_array = is_array ? 1 : 0;
+    entry->array_count = array_count > 0 ? array_count : 1;
+    entry->array_element_size = array_element_size > 0 ? array_element_size : DATA_INT;
+    entry->calling_convention = calling_convention;
+    
+    for (i = 0; i < field_count && i < MAX_AGG_FIELDS; i++) {
+        entry->field_sizes[entry->field_count++] = field_sizes[i];
+    }
+    
+    if (is_aggregate && !parsed_type_tag_name[0] && name && *name) {
+    
+        int mi;
+        
+        for (mi = 0; mi < member_info_count; mi++) {
+        
+            if (member_infos[mi].owner_size == size
+                && member_infos[mi].owner_tag_name == 0) {
+                member_infos[mi].owner_tag_name = xstrdup (name);
+            }
+        
+        }
+    
+    }
+
+}
+
+static void clear_enum_constants (void) {
+
+    int i;
+    
+    for (i = 0; i < enum_constant_count; i++) {
+    
+        free (enum_constants[i].name);
+        
+        enum_constants[i].name = 0;
+        enum_constants[i].value.low = 0;
+        enum_constants[i].value.high = 0;
+    
+    }
+    
+    enum_constant_count = 0;
+
+}
+
+static void clear_global_symbols (void) {
+
+    int i;
+    
+    for (i = 0; i < global_symbol_count; i++) {
+    
+        free (global_symbols[i].name);
+        
+        global_symbols[i].name = 0;
+        global_symbols[i].kind = 0;
+        global_symbols[i].size = 0;
+        
+        global_symbols[i].array_element_size = 0;
+        global_symbols[i].is_array = 0;
+        global_symbols[i].array_dimensions = 0;
+        
+        global_symbols[i].is_dllimport = 0;
+        global_symbols[i].is_extern = 0;
+        global_symbols[i].is_unsigned = 0;
+        global_symbols[i].is_floating = 0;
+        global_symbols[i].returns_void = 0;
+        
+        global_symbols[i].calling_convention = TOK_EOF;
+        
+        {
+        
+            int pi;
+            
+            for (pi = 0; pi < 128; pi++) {
+            
+                global_symbols[i].param_sizes[pi] = 0;
+                global_symbols[i].param_unsigneds[pi] = 0;
+                global_symbols[i].param_floatings[pi] = 0;
+                global_symbols[i].param_pointer_depths[pi] = 0;
+            
+            }
+        
+        }
+        
+        global_symbols[i].import_call_stack_bytes = 0;
+        global_symbols[i].param_count = 0;
+        global_symbols[i].has_prototype = 0;
+        global_symbols[i].is_variadic = 0;
+        global_symbols[i].is_implicit = 0;
+        global_symbols[i].extern_emitted = 0;
+        
+        if (global_symbols[i].tag_name) {
+        
+            free (global_symbols[i].tag_name);
+            global_symbols[i].tag_name = 0;
+        
+        }
+    
+    }
+    
+    global_symbol_count = 0;
+
+}
+
+static int asm_symbol_is_internal (const char *name) {
+
+    if (!name || !*name) {
+        return 1;
+    }
+    
+    if (name[0] == '.') {
+        return 1;
+    }
+    
+    if (name[0] == 'L') {
+    
+        if (name[1] >= '0' && name[1] <= '9') {
+            return 1;
+        }
+        
+        if (name[1] == 'C' && name[2] >= '0' && name[2] <= '9') {
+            return 1;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int global_symbol_stdcall_stack_bytes (const char *name) {
+
+    int i = find_global_symbol (name);
+    int pi;
+    int bytes = 0;
+    
+    if (i < 0 || global_symbols[i].kind != GLOBAL_SYMBOL_FUNCTION || global_symbols[i].calling_convention != TOK_STDCALL ||
+    
+        global_symbols[i].is_variadic) {
+        return 0;
+    
+    }
+    
+    for (pi = 0; pi < global_symbols[i].param_count && pi < 128; pi++) {
+    
+        int size = global_symbols[i].param_sizes[pi];
+        
+        if (size < 1) {
+            size = DATA_PTR & 0x1f;
+        }
+        
+        bytes += ((size + (DATA_PTR & 0x1f) - 1) / (DATA_PTR & 0x1f)) * (DATA_PTR & 0x1f);
+    
+    }
+    
+    if (bytes <= 0 && global_symbols[i].import_call_stack_bytes > 0) {
+        bytes = global_symbols[i].import_call_stack_bytes;
+    }
+    
+    return bytes;
+
+}
+
+static void remember_global_symbol_import_call_stack_bytes (const char *name, int bytes) {
+
+    int i = find_global_symbol (name);
+    
+    if (i < 0 || bytes <= 0) {
+        return;
+    }
+    
+    if (global_symbols[i].kind != GLOBAL_SYMBOL_FUNCTION || !global_symbols[i].is_dllimport || global_symbols[i].calling_convention != TOK_STDCALL) {
+        return;
+    }
+    
+    if (global_symbol_stdcall_stack_bytes (name) <= 0) {
+        global_symbols[i].import_call_stack_bytes = bytes;
+    }
+
+}
+
+static const char *asm_global_symbol_name (const char *name) {
+
+    static char buffers[8][512];
+    static int index = 0;
+    
+    char *out, suffix[32];
+    int stdcall_bytes, symbol_index;
+    
+    unsigned long avail, len;
+    
+    if (asm_symbol_is_internal (name)) {
+        return name;
+    }
+    
+    index = (index + 1) & 7;
+    
+    out = buffers[index];
+    len = strlen (name);
+    
+    stdcall_bytes = global_symbol_stdcall_stack_bytes (name);
+    suffix[0] = '\0';
+    
+    symbol_index = find_global_symbol (name);
+    
+    if (symbol_index >= 0 && global_symbols[symbol_index].kind == GLOBAL_SYMBOL_FUNCTION  && global_symbols[symbol_index].calling_convention == TOK_STDCALL && !global_symbols[symbol_index].is_variadic) {
+        sprintf (suffix, "@%d", stdcall_bytes);
+    }
+    
+    avail = sizeof (buffers[0]) - 1 - strlen (suffix);
+    
+    if (!state->no_leading_underscore) {
+    
+        if (avail > 0) {
+            avail--;
+        }
+        
+        if (len > avail) {
+            len = avail;
+        }
+        
+        out[0] = '_';
+        
+        memcpy (out + 1, name, len);
+        out[len + 1] = 0;
+    
+    } else {
+    
+        if (len > avail) {
+            len = avail;
+        }
+        
+        memcpy (out, name, len);
+        out[len] = 0;
+    
+    }
+    
+    if (suffix[0]) {
+        strcat (out, suffix);
+    }
+    
+    return out;
+
+}
+
+static const char *asm_global_import_symbol_name (const char *name) {
+
+    static char buffers[8][512];
+    static int index = 0;
+    
+    const char *decorated;
+    char *out;
+    
+    unsigned long len;
+    
+    if (!(decorated = asm_global_symbol_name (name)) || asm_symbol_is_internal (name)) {
+        return decorated;
+    }
+    
+    index = (index + 1) & 7;
+    
+    out = buffers[index];
+    len = strlen (decorated);
+    
+    if (len > sizeof (buffers[0]) - 7) {
+        len = sizeof (buffers[0]) - 7;
+    }
+    
+    sprintf (out, "__imp_");
+    
+    memcpy (out + 6, decorated, len);
+    out[len + 6] = 0;
+    
+    return out;
+
+}
+
+static int get_global_symbol_kind (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].kind;
+    }
+    
+    return 0;
+
+}
+
+static void set_global_symbol_unsigned (const char *name, int is_unsigned) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        global_symbols[i].is_unsigned = is_unsigned ? 1 : 0;
+    }
+
+}
+
+static int get_global_symbol_unsigned (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].is_unsigned;
+    }
+    
+    return 0;
+
+}
+
+static void set_global_symbol_dllimport (const char *name, int is_dllimport) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+    
+        global_symbols[i].is_dllimport = is_dllimport ? 1 : 0;
+        
+        if (is_dllimport) {
+            global_symbols[i].is_extern = 1;
+        }
+    
+    }
+
+}
+
+static int get_global_symbol_dllimport (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].is_dllimport ? 1 : 0;
+    }
+    
+    return 0;
+
+}
+
+static void set_global_symbol_array (const char *name, int is_array) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        global_symbols[i].is_array = is_array ? 1 : 0;
+    }
+
+}
+
+static void set_global_symbol_array_count (const char *name, long array_count) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        global_symbols[i].array_count = array_count;
+    }
+
+}
+
+static long get_global_symbol_array_count (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].array_count;
+    }
+    
+    return 0;
+
+}
+
+static void set_global_symbol_array_dimensions (const char *name, int dims) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        global_symbols[i].array_dimensions = dims > 0 ? dims : 0;
+    }
+
+}
+
+static int get_global_symbol_array_dimensions (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].array_dimensions;
+    }
+    
+    return 0;
+
+}
+
+static void set_global_symbol_array_element_size (const char *name, int elem_size) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        global_symbols[i].array_element_size = elem_size > 0 ? elem_size : 0;
+    }
+
+}
+
+static void set_global_symbol_floating (const char *name, int is_floating) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        global_symbols[i].is_floating = is_floating ? 1 : 0;
+    }
+
+}
+
+static int get_global_symbol_floating (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].is_floating;
+    }
+    
+    return 0;
+
+}
+
+static int get_global_function_returns_floating (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i < 0 || global_symbols[i].kind != GLOBAL_SYMBOL_FUNCTION) {
+        return 0;
+    }
+    
+    if (global_symbols[i].is_floating) {
+        return 1;
+    }
+    
+    /*
+     * Do not infer floating return types from the masked object size.
+     *
+     * DATA_INT and DATA_FLOAT both have a 4-byte payload size, so checking
+     * only (size & 0x1f) makes every int-returning function look like it
+     * returns float.  That breaks expressions such as:
+     *
+     *     printf("%p", main);
+     *
+     * because the function designator gets loaded as a floating object from
+     * memory instead of as a plain code address.  The declaration/definition
+     * paths already record real floating function returns in is_floating.
+     */
+    return global_symbols[i].is_floating ? 1 : 0;
+
+}
+
+static void set_global_symbol_pointer_info (const char *name, int pointer_depth, int pointed_size) {
+
+    int i = find_global_symbol (name);
+    
+    if (pointer_depth > 0 && parsed_type_is_aggregate && parsed_type_size > (DATA_PTR & 0x1f) && pointed_size <= (DATA_PTR & 0x1f)) {
+        pointed_size = parsed_type_size;
+    }
+    
+    if (i >= 0) {
+    
+        global_symbols[i].pointer_depth = pointer_depth;
+        global_symbols[i].pointed_size = pointed_size;
+        
+        global_symbols[i].pointed_is_floating = pointer_depth > 0 ? (parsed_type_is_floating ? 1 : 0) : 0;
+        global_symbols[i].pointed_is_unsigned = pointer_depth > 0 ? (parsed_type_is_unsigned ? 1 : 0) : 0;
+    
+    }
+
+}
+
+static int get_global_symbol_pointed_is_floating (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].pointed_is_floating;
+    }
+    
+    return 0;
+
+}
+
+static int get_global_symbol_pointed_is_unsigned (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].pointed_is_unsigned;
+    }
+    
+    return 0;
+
+}
+
+static void set_global_symbol_tag_name (const char *name, const char *tag_name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+    
+        if (global_symbols[i].tag_name) {
+        
+            free (global_symbols[i].tag_name);
+            global_symbols[i].tag_name = 0;
+        
+        }
+        
+        if (tag_name && tag_name[0]) {
+            global_symbols[i].tag_name = xstrdup (tag_name);
+        }
+    
+    }
+
+}
+
+static const char *get_global_symbol_tag_name (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].tag_name;
+    }
+    
+    return 0;
+
+}
+
+static void set_global_symbol_returns_void (const char *name, int returns_void) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        global_symbols[i].returns_void = returns_void ? 1 : 0;
+    }
+
+}
+
+static void set_global_symbol_calling_convention (const char *name, enum token_kind calling_convention) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        global_symbols[i].calling_convention = calling_convention;
+    }
+
+}
+
+static enum token_kind get_global_symbol_calling_convention (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].calling_convention;
+    }
+    
+    return TOK_EOF;
+
+}
+
+static int get_global_symbol_returns_void (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].returns_void;
+    }
+    
+    return 0;
+
+}
+
+static void set_global_symbol_param_count (const char *name, int param_count, int has_prototype, int is_variadic) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+    
+        global_symbols[i].param_count = param_count < 0 ? 0 : param_count;
+        global_symbols[i].has_prototype = has_prototype ? 1 : 0;
+        global_symbols[i].is_variadic = is_variadic ? 1 : 0;
+    
+    }
+
+}
+
+static int get_global_symbol_has_prototype (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].has_prototype;
+    }
+    
+    return 0;
+
+}
+
+static int get_global_symbol_is_variadic (const char *name) {
+
+    int i = find_global_symbol (name);
+
+    if (i >= 0) {
+        return global_symbols[i].is_variadic;
+    }
+
+    return 0;
+
+}
+
+static int get_global_symbol_param_count (const char *name) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return global_symbols[i].param_count;
+    }
+    
+    return 0;
+
+}
+
+static int get_global_symbol_param_size (const char *name, int param_index) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0 && param_index >= 0 && param_index < 128 && global_symbols[i].param_sizes[param_index] > 0) {
+        return global_symbols[i].param_sizes[param_index];
+    }
+    
+    return DATA_PTR & 0x1f;
+
+}
+
+static int get_global_symbol_param_unsigned (const char *name, int param_index) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0 && param_index >= 0 && param_index < 128) {
+        return global_symbols[i].param_unsigneds[param_index] ? 1 : 0;
+    }
+    
+    return 0;
+
+}
+
+static int get_global_symbol_param_floating (const char *name, int param_index) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0 && param_index >= 0 && param_index < 128) {
+        return global_symbols[i].param_floatings[param_index] ? 1 : 0;
+    }
+    
+    return 0;
+
+}
+
+static void set_global_symbol_size (const char *name, int size) {
+
+    int i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        global_symbols[i].size = size;
+    }
+
+}
+
+static int add_global_symbol (const char *name, int kind, int is_extern, const char *line_start, const char *name_caret, unsigned long lineno) {
+
+    int old;
+    
+    if (!name || !*name) {
+        return 0;
+    }
+    
+    if (!line_start) {
+        line_start = tok.start;
+    }
+
+    if (!name_caret) {
+        name_caret = tok.caret;
+    }
+
+    if (lineno == 0) {
+        lineno = get_line_number ();
+    }
+    
+    old = find_global_symbol (name);
+    
+    if (old >= 0) {
+    
+        if (global_symbols[old].is_implicit) {
+        
+            global_symbols[old].is_extern = is_extern ? 1 : 0;
+            global_symbols[old].is_implicit = 0;
+            
+            global_symbols[old].kind = kind;
+            return 1;
+        
+        }
+        
+        if (is_extern) {
+            return 0;
+        }
+        
+        if (global_symbols[old].is_extern) {
+        
+            global_symbols[old].kind = kind;
+            global_symbols[old].is_extern = 0;
+            
+            return 1;
+        
+        }
+        
+        report_line_at (get_filename (), lineno, REPORT_ERROR, line_start, name_caret, "duplicate symbol '%s'", name);
+        return 0;
+    
+    }
+    
+    if (global_symbol_count >= MAX_GLOBAL_SYMBOLS) {
+    
+        report_line_at (get_filename (), lineno, REPORT_ERROR, line_start, name_caret, "too many global symbols");
+        return 0;
+    
+    }
+    
+    global_symbols[global_symbol_count].name = xstrdup (name);
+    global_symbols[global_symbol_count].kind = kind;
+    global_symbols[global_symbol_count].is_extern = is_extern;
+    global_symbols[global_symbol_count].is_dllimport = 0;
+    global_symbols[global_symbol_count].is_unsigned = 0;
+    global_symbols[global_symbol_count].is_floating = 0;
+    global_symbols[global_symbol_count].is_array = 0;
+    global_symbols[global_symbol_count].pointer_depth = 0;
+    global_symbols[global_symbol_count].pointed_size = 0;
+    global_symbols[global_symbol_count].pointed_is_floating = 0;
+    global_symbols[global_symbol_count].pointed_is_unsigned = 0;
+    global_symbols[global_symbol_count].returns_void = 0;
+    global_symbols[global_symbol_count].calling_convention = TOK_EOF;
+    
+    {
+    
+        int pi;
+        
+        for (pi = 0; pi < 128; pi++) {
+        
+            global_symbols[global_symbol_count].param_sizes[pi] = 0;
+            global_symbols[global_symbol_count].param_unsigneds[pi] = 0;
+            global_symbols[global_symbol_count].param_floatings[pi] = 0;
+        
+        }
+    
+    }
+    
+    global_symbols[global_symbol_count].import_call_stack_bytes = 0;
+    global_symbols[global_symbol_count].param_count = 0;
+    global_symbols[global_symbol_count].has_prototype = 0;
+    global_symbols[global_symbol_count].is_variadic = 0;
+    global_symbols[global_symbol_count].is_implicit = 0;
+    global_symbols[global_symbol_count].extern_emitted = 0;
+    global_symbols[global_symbol_count].tag_name = 0;
+    
+    global_symbol_count++;
+    return 1;
+
+}
+
+static void ensure_global_function_symbol (const char *name, const char *line_start, const char *name_caret, unsigned long lineno) {
+
+    int i;
+    
+    if (!name || !*name) {
+        return;
+    }
+    
+    i = find_global_symbol (name);
+    
+    if (i >= 0) {
+        return;
+    }
+    
+    report_line_at (get_filename (), lineno, REPORT_WARNING, line_start, name_caret, "implicit declaration of function '%s'", name);
+    
+    if (add_global_symbol (name, GLOBAL_SYMBOL_FUNCTION, 1, line_start, name_caret, lineno)) {
+    
+        i = find_global_symbol (name);
+        
+        if (i >= 0) {
+        
+            global_symbols[i].calling_convention = TOK_EOF;
+            global_symbols[i].size = DATA_INT & 0x1f;
+            global_symbols[i].is_unsigned = 0;
+            global_symbols[i].is_floating = 0;
+            global_symbols[i].returns_void = 0;
+            global_symbols[i].param_count = 0;
+            global_symbols[i].has_prototype = 0;
+            global_symbols[i].is_variadic = 0;
+            global_symbols[i].is_implicit = 1;
+        
+        }
+    
+    }
+
+}
+
+#define     MAX_INLINE_FUNCTIONS        256
+
+struct inline_function_entry {
+
+    char *name;
+    char *body;
+    char *data;
+    
+    int param_count;
+    int has_prototype;
+    int returns_void;
+    int is_floating;
+    int return_size;
+    int return_label;
+    int data_emitted;
+    int expanding;
+
+    int usable;
+
+};
+
+static struct inline_function_entry inline_functions[MAX_INLINE_FUNCTIONS];
+static int inline_function_count = 0;
+
+static void clear_inline_functions (void) {
+
+    int i;
+    
+    for (i = 0; i < inline_function_count; i++) {
+    
+        free (inline_functions[i].name);
+        free (inline_functions[i].body);
+        free (inline_functions[i].data);
+        
+        inline_functions[i].name = 0;
+        inline_functions[i].body = 0;
+        inline_functions[i].data = 0;
+        inline_functions[i].param_count = 0;
+        inline_functions[i].has_prototype = 0;
+        inline_functions[i].returns_void = 0;
+        inline_functions[i].is_floating = 0;
+        inline_functions[i].return_size = 0;
+        inline_functions[i].return_label = 0;
+        inline_functions[i].data_emitted = 0;
+        inline_functions[i].expanding = 0;
+        inline_functions[i].usable = 0;
+    
+    }
+    
+    inline_function_count = 0;
+
+}
+
+static int find_inline_function (const char *name) {
+
+    int i;
+    
+    if (!name) {
+        return -1;
+    }
+    
+    for (i = 0; i < inline_function_count; i++) {
+    
+        if (strcmp (inline_functions[i].name, name) == 0) {
+            return i;
+        }
+    
+    }
+    
+    return -1;
+
+}
+
+static void remember_inline_function_signature (const char *name, int param_count, int has_prototype, int returns_void, int is_floating, int return_size) {
+
+    int i;
+    
+    if (!name || !*name) {
+        return;
+    }
+    
+    i = find_inline_function (name);
+    
+    if (i < 0) {
+    
+        if (inline_function_count >= MAX_INLINE_FUNCTIONS) {
+            return;
+        }
+        
+        i = inline_function_count++;
+        inline_functions[i].name = xstrdup (name);
+        inline_functions[i].body = 0;
+        inline_functions[i].data = 0;
+        inline_functions[i].data_emitted = 0;
+        inline_functions[i].expanding = 0;
+    
+    }
+    
+    inline_functions[i].param_count = param_count < 0 ? 0 : param_count;
+    inline_functions[i].has_prototype = has_prototype ? 1 : 0;
+    inline_functions[i].returns_void = returns_void ? 1 : 0;
+    inline_functions[i].is_floating = is_floating ? 1 : 0;
+    inline_functions[i].return_size = return_size;
+    inline_functions[i].return_label = 0;
+    inline_functions[i].data_emitted = 0;
+    inline_functions[i].expanding = 0;
+    inline_functions[i].usable = 0;
+
+}
+
+static int inline_asm_body_is_safe (const char *body) {
+
+    const char *p = body;
+    
+    if (!body) {
+        return 0;
+    }
+    
+    while (*p) {
+    
+        const char *line = p;
+        const char *eol = strchr (p, '\n');
+        
+        size_t len = eol ? (size_t) (eol - line) : strlen (line);
+        
+        while (len > 0 && (line[len - 1] == '\r' || line[len - 1] == '\n')) {
+            len--;
+        }
+        
+        while (len > 0 && (*line == ' ' || *line == '\t')) {
+        
+            line++;
+            len--;
+        
+        }
+        
+        if (len >= 4 && strncmp (line, "ret", 3) == 0) {
+            return 0;
+        }
+        
+        if (len >= 5 && strncmp (line, "leave", 5) == 0) {
+            return 0;
+        }
+        
+        if (len > 0 && line[0] == '.' && !(len >= 3 && line[1] == 'L' && line[2] >= '0' && line[2] <= '9')) {
+        
+            if (!((len == 5 && strncmp (line, ".data", 5) == 0) ||
+                  (len == 6 && strncmp (line, ".data?", 6) == 0) ||
+                  (len == 5 && strncmp (line, ".code", 5) == 0) ||
+                  (len == 5 && strncmp (line, ".text", 5) == 0) ||
+                  (len == 4 && strncmp (line, ".bss", 4) == 0))) {
+            
+                return 0;
+            
+            }
+        
+        }
+        
+        if (len >= 6 && strncmp (line, "public", 6) == 0) {
+            return 0;
+        }
+        
+        if (!eol) {
+            break;
+        }
+        
+        p = eol + 1;
+    
+    }
+    
+    return 1;
+
+}
+
+static char *extract_inline_asm_body (const char *asm_text, int return_label) {
+
+    char marker[64];
+    char *body;
+    
+    const char *start, *end;
+    size_t len;
+    
+    if (!asm_text) {
+        return 0;
+    }
+    
+    start = strstr (asm_text, "    mov ebp, esp\n");
+    
+    if (start) {
+        start += strlen ("    mov ebp, esp\n");
+    } else {
+    
+        start = strstr (asm_text, "    movl %esp, %ebp\n");
+        
+        if (start) {
+            start += strlen ("    movl %esp, %ebp\n");
+        }
+    
+    }
+    
+    if (!start) {
+        return 0;
+    }
+    
+    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+        sprintf (marker, "\nL%d:\n", return_label);
+    } else {
+        sprintf (marker, "\n.L%d:\n", return_label);
+    }
+    
+    end = strstr (start, marker);
+    
+    if (!end) {
+
+        if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+            sprintf (marker, "L%d:\n", return_label);
+        } else {
+            sprintf (marker, ".L%d:\n", return_label);
+        }
+
+        if (strncmp (start, marker, strlen (marker)) == 0) {
+            end = start;
+        } else {
+            return 0;
+        }
+
+    }
+    
+    if (*start == '\n') {
+        start++;
+    }
+    
+    len = (size_t) (end - start);
+    
+    while (len > 0 && (start[len - 1] == '\r' || start[len - 1] == '\n')) {
+        len--;
+    }
+    
+    body = xmalloc (len + 2);
+    memcpy (body, start, len);
+    
+    body[len++] = '\n';
+    body[len] = 0;
+    
+    if (!inline_asm_body_is_safe (body)) {
+    
+        free (body);
+        return 0;
+    
+    }
+    
+    return body;
+
+}
+
+static char *read_tmp_file_text (FILE *fp) {
+
+    long len;
+    char *text;
+    
+    if (!fp) {
+        return 0;
+    }
+    
+    fflush (fp);
+    
+    if (fseek (fp, 0, SEEK_END) != 0) {
+        return 0;
+    }
+    
+    len = ftell (fp);
+    
+    if (len < 0) {
+        return 0;
+    }
+    
+    if (fseek (fp, 0, SEEK_SET) != 0) {
+        return 0;
+    }
+    
+    text = xmalloc ((size_t) len + 1);
+    
+    if (len > 0 && fread (text, 1, (size_t) len, fp) != (size_t) len) {
+        free (text);
+        return 0;
+    }
+    
+    text[len] = 0;
+    return text;
+
+}
+
+static void append_inline_text (char **dst, const char *start, size_t len);
+
+static long function_frame_saved_assignment64_bytes (void) {
+    return current_function_preserve_assignment64_regs ? 12 : 0;
+}
+
+static void emit_function_frame_adjust_text (char **dst, long frame_size) {
+
+    char buf[128];
+    long save_bytes;
+    
+    int n;
+    
+    if (!dst) {
+        return;
+    }
+    
+    frame_size = (frame_size + 3) & ~3L;
+    save_bytes = function_frame_saved_assignment64_bytes ();
+    
+    if (frame_size <= 0 && save_bytes <= 0) {
+        return;
+    }
+    
+    if (frame_size > 2147483647L) {
+        frame_size = 2147483647L;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (frame_size > 0) {
+        
+            n = sprintf (buf, "    sub esp, %ld\n", frame_size);
+            append_inline_text (dst, buf, (size_t) n);
+        
+        }
+        
+        if (save_bytes) {
+        
+            append_inline_text (dst, "    push ebx\n", strlen ("    push ebx\n"));
+            append_inline_text (dst, "    push esi\n", strlen ("    push esi\n"));
+            append_inline_text (dst, "    push edi\n", strlen ("    push edi\n"));
+        
+        }
+    
+    } else {
+    
+        if (frame_size > 0) {
+        
+            n = sprintf (buf, "    subl $%ld, %%esp\n", frame_size);
+            append_inline_text (dst, buf, (size_t) n);
+        
+        }
+        
+        if (save_bytes) {
+        
+            append_inline_text (dst, "    pushl %ebx\n", strlen ("    pushl %ebx\n"));
+            append_inline_text (dst, "    pushl %esi\n", strlen ("    pushl %esi\n"));
+            append_inline_text (dst, "    pushl %edi\n", strlen ("    pushl %edi\n"));
+        
+        }
+    
+    }
+
+}
+
+static void emit_function_frame_restore_text (char **dst, long frame_size) {
+
+    if (!dst || !function_frame_saved_assignment64_bytes ()) {
+        return;
+    }
+    
+    (void) frame_size;
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        append_inline_text (dst, "    pop edi\n", strlen ("    pop edi\n"));
+        append_inline_text (dst, "    pop esi\n", strlen ("    pop esi\n"));
+        append_inline_text (dst, "    pop ebx\n", strlen ("    pop ebx\n"));
+    
+    } else {
+    
+        append_inline_text (dst, "    popl %edi\n", strlen ("    popl %edi\n"));
+        append_inline_text (dst, "    popl %esi\n", strlen ("    popl %esi\n"));
+        append_inline_text (dst, "    popl %ebx\n", strlen ("    popl %ebx\n"));
+    
+    }
+
+}
+
+static char *replace_function_frame_placeholder (const char *text, long frame_size) {
+
+    const char *frame_marker = "__SCC_FRAME_PLACEHOLDER__\n";
+    const char *restore_marker = "__SCC_RESTORE_ASSIGNMENT64_REGS__\n";
+    
+    const char *pr, *pf, *p;
+    const char *marker, *last;
+    
+    char *out = 0;
+    size_t marker_len;
+    
+    if (!text) {
+        return 0;
+    }
+    
+    last = text;
+    
+    for (;;) {
+    
+        pf = strstr (last, frame_marker);
+        pr = strstr (last, restore_marker);
+        
+        if (!pf && !pr) {
+            break;
+        }
+        
+        if (pf && (!pr || pf < pr)) {
+            p = pf;
+            marker = frame_marker;
+        } else {
+            p = pr;
+            marker = restore_marker;
+        }
+        
+        marker_len = strlen (marker);
+        append_inline_text (&out, last, (size_t) (p - last));
+        
+        if (marker == frame_marker) {
+            emit_function_frame_adjust_text (&out, frame_size);
+        } else {
+            emit_function_frame_restore_text (&out, frame_size);
+        }
+        
+        last = p + marker_len;
+    
+    }
+    
+    append_inline_text (&out, last, strlen (last));
+    return out;
+
+}
+
+static void append_inline_text (char **dst, const char *start, size_t len) {
+
+    size_t old_len = 0;
+    char *out;
+    
+    if (!dst || !start || len == 0) {
+        return;
+    }
+    
+    if (*dst) {
+        old_len = strlen (*dst);
+    }
+    
+    out = xmalloc (old_len + len + 1);
+    
+    if (old_len) {
+        memcpy (out, *dst, old_len);
+        free (*dst);
+    }
+    
+    memcpy (out + old_len, start, len);
+    out[old_len + len] = 0;
+    *dst = out;
+
+}
+
+static void split_inline_asm_sections (char **bodyp, char **datap) {
+
+    const char *p;
+    
+    char *body = 0;
+    char *data = 0;
+    
+    int in_data = 0;
+    
+    if (!bodyp || !*bodyp) {
+        return;
+    }
+    
+    p = *bodyp;
+    
+    while (*p) {
+    
+        const char *line = p;
+        const char *eol = strchr (p, '\n');
+        const char *next = eol ? eol + 1 : p + strlen (p);
+        
+        size_t len = (size_t) (next - line);
+        
+        const char *trim = line;
+        size_t tlen = eol ? (size_t) (eol - line) : strlen (line);
+        
+        while (tlen > 0 && (trim[tlen - 1] == '\r' || trim[tlen - 1] == '\n')) {
+            tlen--;
+        }
+        
+        while (tlen > 0 && (*trim == ' ' || *trim == '\t')) {
+        
+            trim++;
+            tlen--;
+        
+        }
+        
+        if ((tlen == 5 && strncmp (trim, ".data", 5) == 0) ||
+            (tlen == 6 && strncmp (trim, ".data?", 6) == 0) ||
+            (tlen == 4 && strncmp (trim, ".bss", 4) == 0)) {
+        
+            in_data = 1;
+            append_inline_text (&data, line, len);
+        
+        } else if ((tlen == 5 && strncmp (trim, ".code", 5) == 0) ||
+                   (tlen == 5 && strncmp (trim, ".text", 5) == 0)) {
+            in_data = 0;
+        } else if (in_data) {
+            append_inline_text (&data, line, len);
+        } else {
+            append_inline_text (&body, line, len);
+        }
+        
+        p = next;
+    
+    }
+    
+    free (*bodyp);
+    
+    *bodyp = body;
+    *datap = data;
+
+}
+
+static void remember_inline_function (const char *name, const char *asm_text, int return_label, int param_count, int has_prototype, int returns_void, int is_floating, int return_size) {
+
+    char *body;
+    char *data = 0;
+    
+    int i;
+    
+    if (!name || !*name || !asm_text) {
+        return;
+    }
+    
+    body = extract_inline_asm_body (asm_text, return_label);
+    
+    if (!body) {
+        return;
+    }
+    
+    split_inline_asm_sections (&body, &data);
+    i = find_inline_function (name);
+    
+    if (i < 0) {
+    
+        if (inline_function_count >= MAX_INLINE_FUNCTIONS) {
+        
+            free (body);
+            free (data);
+            
+            return;
+        
+        }
+        
+        i = inline_function_count++;
+        
+        inline_functions[i].name = xstrdup (name);
+        inline_functions[i].body = 0;
+        inline_functions[i].data = 0;
+        inline_functions[i].data_emitted = 0;
+        inline_functions[i].expanding = 0;
+    
+    }
+    
+    free (inline_functions[i].body);
+    free (inline_functions[i].data);
+    
+    inline_functions[i].body = body;
+    inline_functions[i].data = data;
+    inline_functions[i].data_emitted = 0;
+    inline_functions[i].param_count = param_count;
+    inline_functions[i].has_prototype = has_prototype ? 1 : 0;
+    inline_functions[i].returns_void = returns_void ? 1 : 0;
+    inline_functions[i].is_floating = is_floating ? 1 : 0;
+    inline_functions[i].return_size = return_size;
+    inline_functions[i].return_label = return_label;
+    inline_functions[i].expanding = 0;
+    inline_functions[i].usable = 1;
+
+}
+
+static void emit_inline_label_reference (int label, int return_label, int call_id) {
+
+    if (label == return_label) {
+    
+        if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+            fprintf (state->ofp, "L%d", call_id);
+        } else {
+            fprintf (state->ofp, ".L%d", call_id);
+        }
+    
+    } else {
+    
+        if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+            fprintf (state->ofp, "L%d_%d", label, call_id);
+        } else {
+            fprintf (state->ofp, ".L%d_%d", label, call_id);
+        }
+    
+    }
+
+}
+
+static int emit_inline_parameter_reference_if_any (const char **pp, int argc, int stack_bytes) {
+
+    const char *p = *pp;
+    const char *q;
+    
+    int offset = 0;
+    int param_index;
+    int stack_offset;
+    
+    if (!(state->syntax & ASM_SYNTAX_MASM)) {
+        return 0;
+    }
+    
+    if (*p != '[') {
+        return 0;
+    }
+    
+    q = p + 1;
+    
+    while (*q == ' ' || *q == '\t') {
+        q++;
+    }
+    
+    if (strncmp (q, "ebp", 3) != 0) {
+        return 0;
+    }
+    
+    q += 3;
+    
+    while (*q == ' ' || *q == '\t') {
+        q++;
+    }
+    
+    if (*q != '+') {
+        return 0;
+    }
+    
+    q++;
+    
+    while (*q == ' ' || *q == '\t') {
+        q++;
+    }
+    
+    if (*q < '0' || *q > '9') {
+        return 0;
+    }
+    
+    while (*q >= '0' && *q <= '9') {
+    
+        offset = (offset * 10) + (*q - '0');
+        q++;
+    
+    }
+    
+    while (*q == ' ' || *q == '\t') {
+        q++;
+    }
+    
+    if (*q != ']') {
+        return 0;
+    }
+    
+    if (offset < 8 || ((offset - 8) % 4) != 0) {
+        return 0;
+    }
+    
+    param_index = (offset - 8) / 4;
+    
+    if (param_index < 0 || param_index >= argc) {
+        return 0;
+    }
+    
+    /*
+     * Inline arguments are copied into a compiler-owned temporary stack
+     * area before the inline body is emitted.  Parameter 0 lives at the
+     * lowest address in that area, so [ebp + 8] maps to [esp],
+     * [ebp + 12] maps to [esp + 4], [ebp + 16] maps to [esp + 8], etc.
+     * If the inlined body changes ESP temporarily, stack_bytes keeps all
+     * parameter references pointed at the same argument copies.
+     */
+    stack_offset = stack_bytes + (param_index * 4);
+    
+    if (stack_offset == 0) {
+        fprintf (state->ofp, "[esp]");
+    } else if (stack_offset > 0) {
+        fprintf (state->ofp, "[esp + %d]", stack_offset);
+    } else {
+        fprintf (state->ofp, "[esp - %d]", -stack_offset);
+    }
+    
+    *pp = q + 1;
+    return 1;
+
+}
+
+static void emit_inline_line_substituted (const char *line, size_t len, int return_label, int call_id, int argc, int stack_bytes) {
+
+    const char *p = line;
+    const char *end = line + len;
+    
+    while (p < end) {
+    
+        if ((state->syntax & ASM_SYNTAX_MASM) && *p == 'L' && p + 1 < end && p[1] >= '0' && p[1] <= '9') {
+        
+            const char *q = p + 1;
+            int label = 0;
+            
+            while (q < end && *q >= '0' && *q <= '9') {
+            
+                label = (label * 10) + (*q - '0');
+                q++;
+            
+            }
+            
+            emit_inline_label_reference (label, return_label, call_id);
+            p = q;
+            
+            continue;
+        
+        }
+        
+        if (!(state->syntax & ASM_SYNTAX_MASM) && p + 2 < end && p[0] == '.' && p[1] == 'L' && p[2] >= '0' && p[2] <= '9') {
+        
+            const char *q = p + 2;
+            int label = 0;
+            
+            while (q < end && *q >= '0' && *q <= '9') {
+            
+                label = (label * 10) + (*q - '0');
+                q++;
+            
+            }
+            
+            emit_inline_label_reference (label, return_label, call_id);
+            p = q;
+            
+            continue;
+        
+        }
+        
+        if (emit_inline_parameter_reference_if_any (&p, argc, stack_bytes)) {
+            continue;
+        }
+        
+        fputc (*p++, state->ofp);
+    
+    }
+
+}
+
+static int inline_line_stack_delta (const char *line, size_t len) {
+
+    const char *p = line;
+    long n = 0;
+    int neg = 0;
+    
+    while (len > 0 && (*p == ' ' || *p == '\t')) {
+    
+        p++;
+        len--;
+    
+    }
+    
+    while (len > 0 && (p[len - 1] == '\r' || p[len - 1] == '\n' || p[len - 1] == ' ' || p[len - 1] == '\t')) {
+        len--;
+    }
+    
+    if (len >= 4 && strncmp (p, "push", 4) == 0 && (p[4] == ' ' || p[4] == '\t')) {
+        return 4;
+    }
+    
+    if (len >= 3 && strncmp (p, "pop", 3) == 0 && (p[3] == ' ' || p[3] == '\t')) {
+        return -4;
+    }
+    
+    if (len >= 8 && (strncmp (p, "sub esp,", 8) == 0 || strncmp (p, "add esp,", 8) == 0)) {
+    
+        neg = (p[0] == 'a');
+        
+        p += 8;
+        len -= 8;
+        
+        while (len > 0 && (*p == ' ' || *p == '\t')) {
+        
+            p++;
+            len--;
+        
+        }
+        
+        while (len > 0 && *p >= '0' && *p <= '9') {
+        
+            n = (n * 10) + (*p - '0');
+            
+            p++;
+            len--;
+        
+        }
+        
+        return neg ? -(int) n : (int) n;
+    
+    }
+    
+    if (len >= 10 && (strncmp (p, "subl $", 6) == 0 || strncmp (p, "addl $", 6) == 0)) {
+    
+        neg = (p[0] == 'a');
+        
+        p += 6;
+        len -= 6;
+        
+        while (len > 0 && *p >= '0' && *p <= '9') {
+        
+            n = (n * 10) + (*p - '0');
+            
+            p++;
+            len--;
+        
+        }
+        
+        while (len > 0 && (*p == ' ' || *p == '\t')) {
+        
+            p++;
+            len--;
+        
+        }
+        
+        if (len >= 6 && strncmp (p, ", %esp", 6) == 0) {
+            return neg ? -(int) n : (int) n;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int inline_body_stack_delta (const char *body) {
+
+    const char *p = body;
+    int stack_bytes = 0;
+    
+    if (!body) {
+        return 0;
+    }
+    
+    while (*p) {
+    
+        const char *line = p;
+        const char *eol = strchr (p, '\n');
+        const char *next = eol ? eol + 1 : p + strlen (p);
+        size_t len = (size_t) (next - line);
+        
+        stack_bytes += inline_line_stack_delta (line, len);
+        p = next;
+    
+    }
+    
+    return stack_bytes;
+
+}
+
+static int inline_parse_mov_eax_imm (const char *line, long *value) {
+
+    const char *p = line;
+    
+    int neg = 0;
+    long v = 0;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, "mov eax,", 8) != 0) {
+        return 0;
+    }
+    
+    p += 8;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (*p == '-') {
+    
+        neg = 1;
+        p++;
+    
+    }
+    
+    if (*p < '0' || *p > '9') {
+        return 0;
+    }
+    
+    while (*p >= '0' && *p <= '9') {
+    
+        v = (v * 10) + (*p - '0');
+        p++;
+    
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '\0') {
+        return 0;
+    }
+    
+    *value = neg ? -v : v;
+    return 1;
+
+}
+
+static int inline_parse_mov_edx_imm (const char *line, long *value) {
+
+    const char *p = line;
+    
+    int neg = 0;
+    long v = 0;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, "mov edx,", 8) != 0) {
+        return 0;
+    }
+    
+    p += 8;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (*p == '-') {
+    
+        neg = 1;
+        p++;
+    
+    }
+    
+    if (*p < '0' || *p > '9') {
+        return 0;
+    }
+    
+    while (*p >= '0' && *p <= '9') {
+    
+        v = (v * 10) + (*p - '0');
+        p++;
+    
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '\0') {
+        return 0;
+    }
+    
+    *value = neg ? -v : v;
+    return 1;
+
+}
+
+static int inline_line_is_exact (const char *line, const char *text) {
+
+    const char *p = line;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, text, strlen (text)) != 0) {
+        return 0;
+    }
+    
+    p += strlen (text);
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '\0';
+
+}
+
+
+static int inline_parse_jump_label (const char *line, const char *op, char *label, size_t label_size);
+
+static unsigned long inline_u32 (long v) {
+    return ((unsigned long) v) & 0xffffffffUL;
+}
+
+static long inline_s32 (long v) {
+
+    unsigned long u = inline_u32 (v);
+    
+    if (u & 0x80000000UL) {
+        return -((long) ((~u + 1UL) & 0xffffffffUL));
+    }
+    
+    return (long) u;
+
+}
+
+static int inline_fold_binary_eax_edx (const char *line, long lhs, long rhs, long *out) {
+
+    unsigned long ulhs;
+    unsigned long urhs;
+    unsigned long ures;
+    
+    if (!line || !out) {
+        return 0;
+    }
+    
+    ulhs = inline_u32 (lhs);
+    urhs = inline_u32 (rhs);
+    
+    if (inline_line_is_exact (line, "add eax, edx")) {
+        ures = ulhs + urhs;
+    } else if (inline_line_is_exact (line, "sub eax, edx")) {
+        ures = ulhs - urhs;
+    } else if (inline_line_is_exact (line, "imul eax, edx")) {
+        ures = (unsigned long) (inline_s32 (lhs) * inline_s32 (rhs));
+    } else if (inline_line_is_exact (line, "and eax, edx")) {
+        ures = ulhs & urhs;
+    } else if (inline_line_is_exact (line, "or eax, edx")) {
+        ures = ulhs | urhs;
+    } else if (inline_line_is_exact (line, "xor eax, edx")) {
+        ures = ulhs ^ urhs;
+    } else {
+        return 0;
+    }
+    
+    *out = inline_s32 ((long) ures);
+    return 1;
+
+}
+
+static int inline_fold_shift_eax_edx (const char *line, long lhs, long rhs, long *out) {
+
+    unsigned long ulhs;
+    unsigned long ures;
+    unsigned int count;
+    
+    long slhs;
+    
+    if (!line || !out) {
+        return 0;
+    }
+    
+    count = (unsigned int) (inline_u32 (rhs) & 31UL);
+    ulhs = inline_u32 (lhs);
+    
+    if (inline_line_is_exact (line, "shl eax, cl")) {
+        ures = ulhs << count;
+    } else if (inline_line_is_exact (line, "sal eax, cl")) {
+        ures = ulhs << count;
+    } else if (inline_line_is_exact (line, "sar eax, cl")) {
+    
+        slhs = inline_s32 (lhs);
+        ures = inline_u32 (slhs >> count);
+    
+    } else if (inline_line_is_exact (line, "shr eax, cl")) {
+        ures = ulhs >> count;
+    } else {
+        return 0;
+    }
+    
+    *out = inline_s32 ((long) ures);
+    return 1;
+
+}
+
+static int inline_fold_div_eax_edx (long lhs, long rhs, long *out) {
+
+    long slhs;
+    long srhs;
+    
+    if (!out) {
+        return 0;
+    }
+    
+    srhs = inline_s32 (rhs);
+    
+    if (srhs == 0) {
+        return 0;
+    }
+    
+    slhs = inline_s32 (lhs);
+    
+    *out = inline_s32 (slhs / srhs);
+    return 1;
+
+}
+
+static int inline_fold_mod_eax_edx (long lhs, long rhs, long *out) {
+
+    long slhs;
+    long srhs;
+    
+    if (!out) {
+        return 0;
+    }
+    
+    srhs = inline_s32 (rhs);
+    
+    if (srhs == 0) {
+        return 0;
+    }
+    
+    slhs = inline_s32 (lhs);
+    
+    *out = inline_s32 (slhs % srhs);
+    return 1;
+
+}
+
+static int inline_parse_cond_jump_label (const char *line, char *op, size_t op_size, char *label, size_t label_size) {
+
+    static const char *const ops[] = {
+        "jz", "jnz", "je", "jne", "ja", "jae", "jb", "jbe",
+        "jg", "jge", "jl", "jle", "js", "jns", 0
+    };
+    
+    int i;
+    
+    if (!op || op_size == 0) {
+        return 0;
+    }
+    
+    for (i = 0; ops[i]; i++) {
+    
+        if (inline_parse_jump_label (line, ops[i], label, label_size)) {
+        
+            strncpy (op, ops[i], op_size - 1);
+            op[op_size - 1] = '\0';
+            
+            return 1;
+        
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int inline_eval_test_jump (const char *op, long value) {
+
+    long svalue = inline_s32 (value);
+    
+    if (strcmp (op, "jz") == 0 || strcmp (op, "je") == 0) {
+        return svalue == 0;
+    }
+    
+    if (strcmp (op, "jnz") == 0 || strcmp (op, "jne") == 0) {
+        return svalue != 0;
+    }
+    
+    if (strcmp (op, "js") == 0) {
+        return svalue < 0;
+    }
+    
+    if (strcmp (op, "jns") == 0) {
+        return svalue >= 0;
+    }
+    
+    return 0;
+
+}
+
+static int inline_eval_cmp_jump (const char *op, long lhs, long rhs) {
+
+    long slhs = inline_s32 (lhs);
+    long srhs = inline_s32 (rhs);
+    
+    unsigned long ulhs = inline_u32 (lhs);
+    unsigned long urhs = inline_u32 (rhs);
+    
+    if (strcmp (op, "jz") == 0 || strcmp (op, "je") == 0) {
+        return slhs == srhs;
+    }
+    
+    if (strcmp (op, "jnz") == 0 || strcmp (op, "jne") == 0) {
+        return slhs != srhs;
+    }
+    
+    if (strcmp (op, "jg") == 0) {
+        return slhs > srhs;
+    }
+    
+    if (strcmp (op, "jge") == 0) {
+        return slhs >= srhs;
+    }
+    
+    if (strcmp (op, "jl") == 0) {
+        return slhs < srhs;
+    }
+    
+    if (strcmp (op, "jle") == 0) {
+        return slhs <= srhs;
+    }
+    
+    if (strcmp (op, "ja") == 0) {
+        return ulhs > urhs;
+    }
+    
+    if (strcmp (op, "jae") == 0) {
+        return ulhs >= urhs;
+    }
+    
+    if (strcmp (op, "jb") == 0) {
+        return ulhs < urhs;
+    }
+    
+    if (strcmp (op, "jbe") == 0) {
+        return ulhs <= urhs;
+    }
+    
+    return 0;
+
+}
+
+static int inline_parse_jump_label (const char *line, const char *op, char *label, size_t label_size) {
+
+    const char *p = line;
+    size_t n = 0;
+    
+    if (!label || label_size == 0) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, op, strlen (op)) != 0) {
+        return 0;
+    }
+    
+    p += strlen (op);
+    
+    if (*p != ' ' && *p != '\t') {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_' || *p == '.')) {
+        return 0;
+    }
+    
+    while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') ||
+           (*p >= '0' && *p <= '9') || *p == '_' || *p == '.') {
+    
+        if (n + 1 < label_size) {
+            label[n++] = *p;
+        }
+        
+        p++;
+    }
+    
+    label[n] = '\0';
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '\0';
+
+}
+
+
+
+static int inline_parse_any_jump_label (const char *line, char *label, size_t label_size) {
+
+    static const char *const ops[] = {
+        "jmp", "jz", "jnz", "je", "jne", "jc", "jnc",
+        "ja", "jae", "jb", "jbe", "jg", "jge", "jl", "jle",
+        "js", "jns", "jo", "jno", "jp", "jpe", "jnp", "jpo",
+        0
+    };
+    
+    int i;
+    
+    for (i = 0; ops[i]; i++) {
+    
+        if (inline_parse_jump_label (line, ops[i], label, label_size)) {
+            return 1;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int inline_parse_label_definition (const char *line, char *label, size_t label_size) {
+
+    const char *p = line;
+    size_t n = 0;
+    
+    if (!label || label_size == 0) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_' || *p == '.')) {
+        return 0;
+    }
+    
+    while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') ||
+           (*p >= '0' && *p <= '9') || *p == '_' || *p == '.') {
+    
+        if (n + 1 < label_size) {
+            label[n++] = *p;
+        }
+        
+        p++;
+    }
+    
+    label[n] = '\0';
+    
+    if (*p != ':') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '\0';
+
+}
+
+static const char *inline_find_chain_target (char **from, char **to, int count, const char *label) {
+
+    int i;
+    
+    if (!label) {
+        return 0;
+    }
+    
+    for (i = 0; i < count; i++) {
+    
+        if (from[i] && to[i] && strcmp (from[i], label) == 0) {
+            return to[i];
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static void inline_copy_string (char *dst, const char *src, size_t dst_size) {
+
+    size_t len;
+    
+    if (!dst || dst_size == 0) {
+        return;
+    }
+    
+    if (!src) {
+    
+        dst[0] = '\0';
+        return;
+    
+    }
+    
+    len = strlen (src);
+    
+    if (len >= dst_size) {
+        len = dst_size - 1;
+    }
+    
+    memcpy (dst, src, len);
+    dst[len] = '\0';
+
+}
+
+static int inline_resolve_jump_chain (char **from, char **to, int count, const char *label, char *out, size_t out_size) {
+
+    const char *cur = label;
+    const char *next;
+    
+    int changed = 0;
+    int depth = 0;
+    
+    if (!label || !out || out_size == 0) {
+        return 0;
+    }
+    
+    while (depth++ < count) {
+    
+        next = inline_find_chain_target (from, to, count, cur);
+        
+        if (!next || strcmp (next, cur) == 0) {
+            break;
+        }
+        
+        cur = next;
+        changed = 1;
+    
+    }
+    
+    if (!changed || strcmp (cur, label) == 0) {
+        return 0;
+    }
+    
+    if (out && cur && out_size > 0) {
+        inline_copy_string (out, cur, out_size);
+    }
+    
+    return 1;
+
+}
+
+static int inline_parse_esp_reference (const char *p, int *offset) {
+
+    const char *start = p;
+    
+    int off = 0;
+    int neg = 0;
+    
+    if (strncmp (p, "[esp]", 5) == 0) {
+    
+        *offset = 0;
+        return 5;
+    
+    }
+    
+    if (strncmp (p, "[esp + ", 7) == 0) {
+        p += 7;
+    } else if (strncmp (p, "[esp+", 5) == 0) {
+        p += 5;
+    } else if (strncmp (p, "[esp - ", 7) == 0) {
+        neg = 1;
+        p += 7;
+    } else if (strncmp (p, "[esp-", 5) == 0) {
+        neg = 1;
+        p += 5;
+    } else {
+        return 0;
+    }
+    
+    if (*p < '0' || *p > '9') {
+        return 0;
+    }
+    
+    while (*p >= '0' && *p <= '9') {
+    
+        off = (off * 10) + (*p - '0');
+        p++;
+    
+    }
+    
+    if (*p != ']') {
+        return 0;
+    }
+    
+    *offset = neg ? -off : off;
+    return (int) ((p + 1) - start);
+
+}
+
+static int inline_parse_store_eax_to_esp (const char *line, int *offset) {
+
+    const char *p = line;
+    int n;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, "mov dword ptr ", 14) != 0) {
+        return 0;
+    }
+    
+    p += 14;
+    n = inline_parse_esp_reference (p, offset);
+    
+    if (!n) {
+        return 0;
+    }
+    
+    p += n;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, ", eax", 5) != 0) {
+        return 0;
+    }
+    
+    p += 5;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '\0';
+
+}
+
+static int inline_parse_load_eax_from_esp (const char *line, int *offset) {
+
+    const char *p = line;
+    int n;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, "mov eax, dword ptr ", 19) != 0) {
+        return 0;
+    }
+    
+    p += 19;
+    n = inline_parse_esp_reference (p, offset);
+    
+    if (!n) {
+        return 0;
+    }
+    
+    p += n;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '\0';
+
+}
+
+static int inline_parse_load_edx_from_esp (const char *line, int *offset) {
+
+    const char *p = line;
+    int n;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, "mov edx, dword ptr ", 19) != 0) {
+        return 0;
+    }
+    
+    p += 19;
+    n = inline_parse_esp_reference (p, offset);
+    
+    if (!n) {
+        return 0;
+    }
+    
+    p += n;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '\0';
+
+}
+
+static int inline_parse_addsub_esp_imm1 (const char *line, int *offset, long *delta) {
+
+    const char *p = line;
+    int n;
+    int is_sub = 0;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, "add dword ptr ", 14) == 0) {
+        p += 14;
+    } else if (strncmp (p, "sub dword ptr ", 14) == 0) {
+    
+        is_sub = 1;
+        p += 14;
+    
+    } else {
+        return 0;
+    }
+    
+    n = inline_parse_esp_reference (p, offset);
+    
+    if (!n) {
+        return 0;
+    }
+    
+    p += n;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, ", 1", 3) != 0) {
+        return 0;
+    }
+    
+    p += 3;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '\0') {
+        return 0;
+    }
+    
+    *delta = is_sub ? -1 : 1;
+    return 1;
+
+}
+
+static char *inline_dup_text_slice (const char *start, size_t len) {
+
+    char *out = (char *) malloc (len + 1);
+    
+    if (!out) {
+        return 0;
+    }
+    
+    memcpy (out, start, len);
+    out[len] = '\0';
+    
+    return out;
+
+}
+
+static void inline_clear_slots (int *slot_valid, long *slot_value) {
+
+    int i;
+    
+    for (i = 0; i < 64; i++) {
+    
+        slot_valid[i] = 0;
+        slot_value[i] = 0;
+    
+    }
+
+}
+
+static void emit_inline_optimized_text (const char *text, FILE *ofp) {
+
+    const char *p = text;
+    
+    char **lines;
+    char **repl;
+    
+    int *skip;
+    int *store_slot;
+    int count = 0;
+    int i;
+    
+    long slot_value[64];
+    
+    int slot_valid[64];
+    int slot_real_read[64];
+    
+    long eax_value = 0;
+    
+    int eax_valid = 0;
+    int alloc_line = -1;
+    int free_line = -1;
+    int alloc_bytes = 0;
+    int can_remove_area = 0;
+    
+    char **chain_from = 0;
+    char **chain_to = 0;
+    
+    int *label_refs = 0;
+    
+    if (!text || !ofp) {
+        return;
+    }
+    
+    for (p = text; *p; p++) {
+    
+        if (*p == '\n') {
+            count++;
+        }
+    
+    }
+    
+    if (p != text && p[-1] != '\n') {
+        count++;
+    }
+    
+    if (count <= 0) {
+        return;
+    }
+    
+    lines = (char **) calloc ((size_t) count, sizeof (*lines));
+    repl = (char **) calloc ((size_t) count, sizeof (*repl));
+    skip = (int *) calloc ((size_t) count, sizeof (*skip));
+    store_slot = (int *) malloc ((size_t) count * sizeof (*store_slot));
+    chain_from = (char **) calloc ((size_t) count, sizeof (*chain_from));
+    chain_to = (char **) calloc ((size_t) count, sizeof (*chain_to));
+    label_refs = (int *) calloc ((size_t) count, sizeof (*label_refs));
+    
+    if (!lines || !repl || !skip || !store_slot || !chain_from || !chain_to || !label_refs) {
+    
+        free (lines);
+        free (repl);
+        free (skip);
+        free (store_slot);
+        free (chain_from);
+        free (chain_to);
+        free (label_refs);
+        
+        fputs (text, ofp);
+        return;
+    
+    }
+    
+    for (i = 0; i < count; i++) {
+        store_slot[i] = -1;
+    }
+    
+    p = text;
+    i = 0;
+    
+    while (*p && i < count) {
+    
+        const char *line = p;
+        const char *eol = strchr (p, '\n');
+        const char *next = eol ? eol + 1 : p + strlen (p);
+        size_t len = (size_t) (next - line);
+        
+        lines[i++] = inline_dup_text_slice (line, len);
+        p = next;
+    
+    }
+    
+    count = i;
+    inline_clear_slots (slot_valid, slot_value);
+    
+    for (i = 0; i < 64; i++) {
+        slot_real_read[i] = 0;
+    }
+    
+    for (i = 0; i < count; i++) {
+    
+        char *buf = lines[i];
+        int offset;
+        int slot;
+        long value;
+        long mem_delta;
+        int delta;
+        
+        if (!buf) {
+            continue;
+        }
+        
+        delta = inline_line_stack_delta (buf, strlen (buf));
+        
+        if (delta > 0 && alloc_line < 0) {
+        
+            alloc_line = i;
+            alloc_bytes = delta;
+            
+            eax_valid = 0;
+            continue;
+        
+        }
+        
+        if (delta < 0 && alloc_line >= 0 && -delta == alloc_bytes) {
+        
+            free_line = i;
+            eax_valid = 0;
+            
+            continue;
+        
+        }
+        
+        if (inline_parse_mov_eax_imm (buf, &value)) {
+        
+            eax_value = value;
+            eax_valid = 1;
+            
+            continue;
+        
+        }
+        
+        if (inline_parse_store_eax_to_esp (buf, &offset)) {
+        
+            if (offset >= 0 && (offset % 4) == 0) {
+            
+                slot = offset / 4;
+                
+                if (slot >= 0 && slot < 64) {
+                
+                    store_slot[i] = slot;
+                    
+                    if (eax_valid) {
+                    
+                        slot_valid[slot] = 1;
+                        slot_value[slot] = eax_value;
+                    
+                    } else {
+                        slot_valid[slot] = 0;
+                    }
+                
+                }
+            
+            }
+            
+            continue;
+        
+        }
+        
+        if (inline_parse_load_eax_from_esp (buf, &offset)) {
+        
+            if (offset >= 0 && (offset % 4) == 0) {
+            
+                slot = offset / 4;
+                
+                if (slot >= 0 && slot < 64 && slot_valid[slot]) {
+                
+                    char tmp[128];
+                    sprintf (tmp, "    mov eax, %ld\n", slot_value[slot]);
+                    
+                    repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+                    
+                    eax_value = slot_value[slot];
+                    eax_valid = 1;
+                    
+                    continue;
+                
+                }
+                
+                if (slot >= 0 && slot < 64) {
+                    slot_real_read[slot] = 1;
+                }
+            
+            }
+            
+            eax_valid = 0;
+            continue;
+        }
+        
+        if (inline_parse_load_edx_from_esp (buf, &offset)) {
+        
+            if (offset >= 0 && (offset % 4) == 0) {
+            
+                slot = offset / 4;
+                
+                if (slot >= 0 && slot < 64 && slot_valid[slot]) {
+                
+                    char tmp[128];
+                    sprintf (tmp, "    mov edx, %ld\n", slot_value[slot]);
+                    
+                    repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+                    continue;
+                
+                }
+                
+                if (slot >= 0 && slot < 64) {
+                    slot_real_read[slot] = 1;
+                }
+            
+            }
+            
+            continue;
+        
+        }
+        
+        if (inline_parse_addsub_esp_imm1 (buf, &offset, &mem_delta)) {
+        
+            if (offset >= 0 && (offset % 4) == 0) {
+            
+                slot = offset / 4;
+                
+                if (slot >= 0 && slot < 64) {
+                
+                    if (slot_valid[slot]) {
+                        slot_value[slot] = inline_s32 (slot_value[slot] + mem_delta);
+                        skip[i] = 1;
+                    }
+                    
+                    continue;
+                }
+            }
+            
+            eax_valid = 0;
+            continue;
+        
+        }
+        
+        if (strstr (buf, "esp")) {
+        
+            inline_clear_slots (slot_valid, slot_value);
+            eax_valid = 0;
+        
+        } else if (strstr (buf, "eax")) {
+            eax_valid = 0;
+        }
+    
+    }
+    
+    if (alloc_line >= 0 && free_line > alloc_line && alloc_bytes > 0) {
+    
+        int any_remaining_esp = 0;
+        int slots = alloc_bytes / 4;
+        
+        for (i = 0; i < count; i++) {
+        
+            if (i == alloc_line || i == free_line) {
+                continue;
+            }
+            
+            if (store_slot[i] >= 0 && store_slot[i] < slots && !slot_real_read[store_slot[i]]) {
+                continue;
+            }
+            
+            if (repl[i]) {
+            
+                if (strstr (repl[i], "esp")) {
+                    any_remaining_esp = 1;
+                    break;
+                }
+            
+            } else if (lines[i] && strstr (lines[i], "esp")) {
+            
+                any_remaining_esp = 1;
+                break;
+            
+            }
+        
+        }
+        
+        if (!any_remaining_esp) {
+        
+            can_remove_area = 1;
+            skip[alloc_line] = 1;
+            skip[free_line] = 1;
+            
+            for (i = 0; i < count; i++) {
+            
+                if (store_slot[i] >= 0 && store_slot[i] < slots && !slot_real_read[store_slot[i]]) {
+                    skip[i] = 1;
+                }
+            
+            }
+            
+            /*
+             * If an argument copy was folded away, the immediately preceding
+             * constant load was only there to feed that copy.  Drop it too;
+             * otherwise multi-argument inline calls leave noise like:
+             *
+             *     mov eax, 1
+             *     mov eax, 2
+             *
+             * after both temporary argument stores have been removed.
+             */
+            for (i = 0; i < count; i++) {
+            
+                long ignored_value;
+                int j;
+                
+                if (!skip[i] || store_slot[i] < 0) {
+                    continue;
+                }
+                
+                for (j = i - 1; j >= 0; j--) {
+                
+                    if (skip[j]) {
+                        continue;
+                    }
+                    
+                    if (inline_parse_mov_eax_imm (lines[j], &ignored_value)) {
+                        skip[j] = 1;
+                    }
+                    
+                    break;
+                
+                }
+            
+            }
+        
+        }
+    
+    }
+    
+    (void) can_remove_area;
+    
+    for (i = 0; i < count; i++) {
+    
+        long first_value;
+        int j;
+        
+        if (skip[i] || !lines[i] || !inline_parse_mov_eax_imm (lines[i], &first_value)) {
+            continue;
+        }
+        
+        for (j = i + 1; j < count; j++) {
+        
+            long next_value;
+            const char *check;
+            
+            if (skip[j]) {
+                continue;
+            }
+            
+            check = repl[j] ? repl[j] : lines[j];
+            
+            if (!check) {
+                continue;
+            }
+            
+            if (!strstr (check, "eax")) {
+                continue;
+            }
+            
+            if (inline_parse_mov_eax_imm (check, &next_value) && next_value == first_value) {
+                skip[i] = 1;
+            }
+            
+            break;
+        
+        }
+    
+    }
+    
+    for (i = 0; i + 3 < count; i++) {
+    
+        long lhs;
+        long rhs;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        
+        int taken;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        
+        if (!l0 || !l1 || !l2 || !l3) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "cmp eax, edx")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l3, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_cmp_jump (opbuf, lhs, rhs);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[i]);
+            
+            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+        
+        } else {
+        
+            skip[i] = 1;
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+        
+        }
+    
+    }
+    
+    for (i = 0; i + 4 < count; i++) {
+    
+        long lhs;
+        long rhs;
+        
+        char false_label[128];
+        char true_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "cmp eax, edx")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l3, opbuf, sizeof (opbuf), false_label, sizeof (false_label))) {
+            continue;
+        }
+        
+        if (!inline_parse_jump_label (l4, "jmp", true_label, sizeof (true_label))) {
+            continue;
+        }
+        
+        sprintf (tmp, "    jmp %s\n", inline_eval_cmp_jump (opbuf, lhs, rhs) ? false_label : true_label);
+        free (repl[i]);
+        
+        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+        
+        skip[i + 1] = 1;
+        skip[i + 2] = 1;
+        skip[i + 3] = 1;
+        skip[i + 4] = 1;
+    
+    }
+    
+    for (i = 0; i + 4 < count; i++) {
+
+        long lhs;
+        long rhs;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        
+        int taken;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_fold_binary_eax_edx (l2, lhs, rhs, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l3, "test eax, eax")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l4, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_test_jump (opbuf, lhs);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[i]);
+            
+            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+        
+        } else {
+        
+            skip[i] = 1;
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+        
+        }
+    
+    }
+    
+    for (i = 0; i + 5 < count; i++) {
+    
+        long lhs;
+        long rhs;
+        long cmp_rhs;
+        long folded;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        
+        int taken;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_fold_binary_eax_edx (l2, lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l3, &cmp_rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l4, "cmp eax, edx")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l5, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_cmp_jump (opbuf, folded, cmp_rhs);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[i]);
+            
+            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+        
+        } else {
+        
+            skip[i] = 1;
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+        
+        }
+    
+    }
+    
+    for (i = 0; i + 5 < count; i++) {
+    
+        long lhs;
+        long rhs;
+        
+        char false_label[128];
+        char true_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_fold_binary_eax_edx (l2, lhs, rhs, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l3, "test eax, eax")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l4, opbuf, sizeof (opbuf), false_label, sizeof (false_label))) {
+            continue;
+        }
+        
+        if (!inline_parse_jump_label (l5, "jmp", true_label, sizeof (true_label))) {
+            continue;
+        }
+        
+        sprintf (tmp, "    jmp %s\n", inline_eval_test_jump (opbuf, lhs) ? false_label : true_label);
+        free (repl[i]);
+        
+        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+        
+        skip[i + 1] = 1;
+        skip[i + 2] = 1;
+        skip[i + 3] = 1;
+        skip[i + 4] = 1;
+        skip[i + 5] = 1;
+    
+    }
+    
+    for (i = 0; i + 6 < count; i++) {
+    
+        long lhs;
+        long rhs;
+        long cmp_rhs;
+        long folded;
+        
+        int jump_taken = 0;
+        
+        char cond_label[128];
+        char fall_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        const char *l6;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_fold_binary_eax_edx (l2, lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l3, &cmp_rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l4, "cmp eax, edx")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l5, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        jump_taken = inline_eval_cmp_jump (opbuf, folded, cmp_rhs);
+        
+        if (!inline_parse_jump_label (l6, "jmp", fall_label, sizeof (fall_label))) {
+            continue;
+        }
+        
+        sprintf (tmp, "    jmp %s\n", jump_taken ? cond_label : fall_label);
+        free (repl[i]);
+        
+        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+        
+        skip[i + 1] = 1;
+        skip[i + 2] = 1;
+        skip[i + 3] = 1;
+        skip[i + 4] = 1;
+        skip[i + 5] = 1;
+        skip[i + 6] = 1;
+    
+    }
+    
+    for (i = 0; i + 5 < count; i++) {
+
+        long lhs;
+        long rhs;
+        long folded;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        
+        int taken;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov ecx, edx")) {
+            continue;
+        }
+        
+        if (!inline_fold_shift_eax_edx (l3, lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l4, "test eax, eax")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l5, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_test_jump (opbuf, folded);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[i]);
+            
+            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+        
+        } else {
+        
+            skip[i] = 1;
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+        
+        }
+    
+    }
+    
+    for (i = 0; i + 6 < count; i++) {
+    
+        long lhs;
+        long rhs;
+        long cmp_rhs;
+        long folded;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        const char *l6;
+        
+        int taken;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov ecx, edx")) {
+            continue;
+        }
+        
+        if (!inline_fold_shift_eax_edx (l3, lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l4, &cmp_rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l5, "cmp eax, edx")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l6, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_cmp_jump (opbuf, folded, cmp_rhs);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[i]);
+            
+            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+            skip[i + 6] = 1;
+        
+        } else {
+        
+            skip[i] = 1;
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+            skip[i + 6] = 1;
+        
+        }
+    
+    }
+    
+    for (i = 0; i + 6 < count; i++) {
+    
+        long lhs;
+        long rhs;
+        long folded;
+        
+        char false_label[128];
+        char true_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        const char *l6;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov ecx, edx")) {
+            continue;
+        }
+        
+        if (!inline_fold_shift_eax_edx (l3, lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l4, "test eax, eax")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l5, opbuf, sizeof (opbuf), false_label, sizeof (false_label))) {
+            continue;
+        }
+        
+        if (!inline_parse_jump_label (l6, "jmp", true_label, sizeof (true_label))) {
+            continue;
+        }
+        
+        sprintf (tmp, "    jmp %s\n", inline_eval_test_jump (opbuf, folded) ? false_label : true_label);
+        free (repl[i]);
+        
+        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+        
+        skip[i + 1] = 1;
+        skip[i + 2] = 1;
+        skip[i + 3] = 1;
+        skip[i + 4] = 1;
+        skip[i + 5] = 1;
+        skip[i + 6] = 1;
+    
+    }
+    
+    for (i = 0; i + 7 < count; i++) {
+    
+        long lhs;
+        long rhs;
+        long cmp_rhs;
+        long folded;
+        
+        int jump_taken = 0;
+        
+        char cond_label[128];
+        char fall_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        const char *l6;
+        const char *l7;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
+        l7 = repl[i + 7] ? repl[i + 7] : lines[i + 7];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6 || !l7) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov ecx, edx")) {
+            continue;
+        }
+        
+        if (!inline_fold_shift_eax_edx (l3, lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l4, &cmp_rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l5, "cmp eax, edx")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l6, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        jump_taken = inline_eval_cmp_jump (opbuf, folded, cmp_rhs);
+        
+        if (!inline_parse_jump_label (l7, "jmp", fall_label, sizeof (fall_label))) {
+            continue;
+        }
+        
+        sprintf (tmp, "    jmp %s\n", jump_taken ? cond_label : fall_label);
+        free (repl[i]);
+        
+        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+        
+        skip[i + 1] = 1;
+        skip[i + 2] = 1;
+        skip[i + 3] = 1;
+        skip[i + 4] = 1;
+        skip[i + 5] = 1;
+        skip[i + 6] = 1;
+        skip[i + 7] = 1;
+    
+    }
+    
+    for (i = 0; i + 6 < count; i++) {
+    
+        long lhs;
+        long rhs;
+        long folded;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        const char *l6;
+        
+        int taken;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov ecx, edx") || !inline_line_is_exact (l3, "cdq") ||
+            !inline_line_is_exact (l4, "idiv ecx")) {
+            continue;
+        }
+        
+        if (!inline_fold_div_eax_edx (lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l5, "test eax, eax")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l6, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_test_jump (opbuf, folded);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[i]);
+            
+            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+            skip[i + 6] = 1;
+        
+        } else {
+        
+            skip[i] = 1;
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+            skip[i + 6] = 1;
+        
+        }
+    
+    }
+    
+    for (i = 0; i + 7 < count; i++) {
+    
+        long lhs;
+        long rhs;
+        long cmp_rhs;
+        long folded;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        const char *l6;
+        const char *l7;
+        
+        int taken;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
+        l7 = repl[i + 7] ? repl[i + 7] : lines[i + 7];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6 || !l7) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov ecx, edx") || !inline_line_is_exact (l3, "cdq") ||
+            !inline_line_is_exact (l4, "idiv ecx")) {
+            continue;
+        }
+        
+        if (!inline_fold_div_eax_edx (lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l5, &cmp_rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l6, "cmp eax, edx")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l7, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_cmp_jump (opbuf, folded, cmp_rhs);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[i]);
+            
+            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+            skip[i + 6] = 1;
+            skip[i + 7] = 1;
+        
+        } else {
+        
+            skip[i] = 1;
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+            skip[i + 6] = 1;
+            skip[i + 7] = 1;
+        
+        }
+    
+    }
+    
+    for (i = 0; i + 7 < count; i++) {
+    
+        long lhs;
+        long rhs;
+        long folded;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        const char *l6;
+        const char *l7;
+        
+        int taken;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
+        l7 = repl[i + 7] ? repl[i + 7] : lines[i + 7];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6 || !l7) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov ecx, edx") || !inline_line_is_exact (l3, "cdq") ||
+            !inline_line_is_exact (l4, "idiv ecx") || !inline_line_is_exact (l5, "mov eax, edx")) {
+            continue;
+        }
+        
+        if (!inline_fold_mod_eax_edx (lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l6, "test eax, eax")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l7, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_test_jump (opbuf, folded);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[i]);
+            
+            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+            skip[i + 6] = 1;
+            skip[i + 7] = 1;
+        
+        } else {
+        
+            skip[i] = 1;
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+            skip[i + 6] = 1;
+            skip[i + 7] = 1;
+        
+        }
+    
+    }
+    
+    for (i = 0; i + 8 < count; i++) {
+    
+        long lhs;
+        long rhs;
+        long cmp_rhs;
+        long folded;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        const char *l6;
+        const char *l7;
+        const char *l8;
+        
+        int taken;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
+        l7 = repl[i + 7] ? repl[i + 7] : lines[i + 7];
+        l8 = repl[i + 8] ? repl[i + 8] : lines[i + 8];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6 || !l7 || !l8) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov ecx, edx") || !inline_line_is_exact (l3, "cdq") ||
+            !inline_line_is_exact (l4, "idiv ecx") || !inline_line_is_exact (l5, "mov eax, edx")) {
+            continue;
+        }
+        
+        if (!inline_fold_mod_eax_edx (lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l6, &cmp_rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l7, "cmp eax, edx")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l8, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_cmp_jump (opbuf, folded, cmp_rhs);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[i]);
+            
+            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+            skip[i + 6] = 1;
+            skip[i + 7] = 1;
+            skip[i + 8] = 1;
+        
+        } else {
+        
+            skip[i] = 1;
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+            skip[i + 4] = 1;
+            skip[i + 5] = 1;
+            skip[i + 6] = 1;
+            skip[i + 7] = 1;
+            skip[i + 8] = 1;
+        
+        }
+    
+    }
+    
+    for (i = 0; i + 2 < count; i++) {
+    
+        long lhs;
+        long rhs;
+        long folded;
+        
+        char tmp[128];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        
+        if (skip[i] || skip[i + 1] || skip[i + 2]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        
+        if (!l0 || !l1 || !l2) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_fold_binary_eax_edx (l2, lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        sprintf (tmp, "    mov eax, %ld\n", folded);
+        free (repl[i]);
+        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+        
+        skip[i + 1] = 1;
+        skip[i + 2] = 1;
+    
+    }
+    
+    for (i = 0; i + 3 < count; i++) {
+    
+        long lhs;
+        long rhs;
+        long folded;
+        
+        char tmp[128];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        
+        if (skip[i] || skip[i + 1] || skip[i + 2] || skip[i + 3]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        
+        if (!l0 || !l1 || !l2 || !l3) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov ecx, edx")) {
+            continue;
+        }
+        
+        if (!inline_fold_shift_eax_edx (l3, lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        sprintf (tmp, "    mov eax, %ld\n", folded);
+        free (repl[i]);
+        
+        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+        
+        skip[i + 1] = 1;
+        skip[i + 2] = 1;
+        skip[i + 3] = 1;
+    
+    }
+    
+    for (i = 0; i + 4 < count; i++) {
+    
+        long lhs;
+        long rhs;
+        long folded;
+        
+        char tmp[128];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        
+        if (skip[i] || skip[i + 1] || skip[i + 2] || skip[i + 3] || skip[i + 4]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov ecx, edx") || !inline_line_is_exact (l3, "cdq") ||
+            !inline_line_is_exact (l4, "idiv ecx")) {
+            continue;
+        }
+        
+        if (!inline_fold_div_eax_edx (lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        sprintf (tmp, "    mov eax, %ld\n", folded);
+        free (repl[i]);
+        
+        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+        
+        skip[i + 1] = 1;
+        skip[i + 2] = 1;
+        skip[i + 3] = 1;
+        skip[i + 4] = 1;
+    
+    }
+    
+    for (i = 0; i + 5 < count; i++) {
+    
+        long lhs;
+        long rhs;
+        long folded;
+        
+        char tmp[128];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        const char *l4;
+        const char *l5;
+        
+        if (skip[i] || skip[i + 1] || skip[i + 2] || skip[i + 3] || skip[i + 4] || skip[i + 5]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
+        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
+        
+        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "mov ecx, edx") || !inline_line_is_exact (l3, "cdq") ||
+            !inline_line_is_exact (l4, "idiv ecx") || !inline_line_is_exact (l5, "mov eax, edx")) {
+            continue;
+        }
+        
+        if (!inline_fold_mod_eax_edx (lhs, rhs, &folded)) {
+            continue;
+        }
+        
+        sprintf (tmp, "    mov eax, %ld\n", folded);
+        free (repl[i]);
+        
+        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+        
+        skip[i + 1] = 1;
+        skip[i + 2] = 1;
+        skip[i + 3] = 1;
+        skip[i + 4] = 1;
+        skip[i + 5] = 1;
+    
+    }
+    
+    /*
+     * Some compound-expression folds, such as x += 1, are reduced only by
+     * the late arithmetic pass above.  Run the constant compare/branch fold
+     * again here so newly-created sequences like:
+     *
+     *     mov eax, 9
+     *     mov edx, 9
+     *     cmp eax, edx
+     *     jne Lx
+     *
+     * are folded after the arithmetic result becomes visible.
+     */
+    for (i = 0; i + 3 < count; i++) {
+    
+        long lhs;
+        long rhs;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        
+        int taken;
+        
+        if (skip[i] || skip[i + 1] || skip[i + 2] || skip[i + 3]) {
+            continue;
+        }
+        
+        l0 = repl[i] ? repl[i] : lines[i];
+        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
+        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
+        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
+        
+        if (!l0 || !l1 || !l2 || !l3) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "cmp eax, edx")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l3, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_cmp_jump (opbuf, lhs, rhs);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[i]);
+            
+            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+        
+        } else {
+        
+            skip[i] = 1;
+            skip[i + 1] = 1;
+            skip[i + 2] = 1;
+            skip[i + 3] = 1;
+        
+        }
+    
+    }
+    
+    /*
+     * A late fold can leave useful instructions separated by skipped source
+     * lines.  For example x += 1 followed by == may become:
+     *
+     *     mov eax, 9
+     *     ; skipped old rhs/op lines
+     *     mov edx, 9
+     *     cmp eax, edx
+     *     jne Lx
+     *
+     * The normal adjacent compare fold cannot see through the skipped lines,
+     * so do one compacting pass over the remaining live instructions.
+     */
+    for (i = 0; i < count; i++) {
+    
+        int j0;
+        int j1;
+        int j2;
+        int j3;
+        
+        long lhs;
+        long rhs;
+        
+        char cond_label[128];
+        char opbuf[16];
+        char tmp[192];
+        
+        const char *l0;
+        const char *l1;
+        const char *l2;
+        const char *l3;
+        
+        int taken;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        j0 = i;
+        j1 = j0 + 1;
+        
+        while (j1 < count && skip[j1]) {
+            j1++;
+        }
+        
+        j2 = j1 + 1;
+        
+        while (j2 < count && skip[j2]) {
+            j2++;
+        }
+        
+        j3 = j2 + 1;
+        
+        while (j3 < count && skip[j3]) {
+            j3++;
+        }
+        
+        if (j1 >= count || j2 >= count || j3 >= count) {
+            continue;
+        }
+        
+        l0 = repl[j0] ? repl[j0] : lines[j0];
+        l1 = repl[j1] ? repl[j1] : lines[j1];
+        l2 = repl[j2] ? repl[j2] : lines[j2];
+        l3 = repl[j3] ? repl[j3] : lines[j3];
+        
+        if (!l0 || !l1 || !l2 || !l3) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
+            continue;
+        }
+        
+        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
+            continue;
+        }
+        
+        if (!inline_line_is_exact (l2, "cmp eax, edx")) {
+            continue;
+        }
+        
+        if (!inline_parse_cond_jump_label (l3, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
+            continue;
+        }
+        
+        taken = inline_eval_cmp_jump (opbuf, lhs, rhs);
+        
+        if (taken) {
+        
+            sprintf (tmp, "    jmp %s\n", cond_label);
+            free (repl[j0]);
+            
+            repl[j0] = inline_dup_text_slice (tmp, strlen (tmp));
+            
+            skip[j1] = 1;
+            skip[j2] = 1;
+            skip[j3] = 1;
+        
+        } else {
+        
+            skip[j0] = 1;
+            skip[j1] = 1;
+            skip[j2] = 1;
+            skip[j3] = 1;
+        
+        }
+    
+    }
+    
+    for (i = 0; i < count; i++) {
+    
+        char label[128];
+        char target[128];
+        const char *line;
+        int j;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        line = repl[i] ? repl[i] : lines[i];
+        
+        if (!line || !inline_parse_label_definition (line, label, sizeof (label))) {
+            continue;
+        }
+        
+        for (j = i + 1; j < count; j++) {
+        
+            const char *next_line;
+            
+            if (skip[j]) {
+                continue;
+            }
+            
+            next_line = repl[j] ? repl[j] : lines[j];
+            
+            if (!next_line) {
+                continue;
+            }
+            
+            if (inline_parse_jump_label (next_line, "jmp", target, sizeof (target))) {
+            
+                if (strcmp (label, target) != 0) {
+                
+                    chain_from[i] = inline_dup_text_slice (label, strlen (label));
+                    chain_to[i] = inline_dup_text_slice (target, strlen (target));
+                
+                }
+            
+            }
+            
+            break;
+        
+        }
+    
+    }
+    
+    for (i = 0; i < count; i++) {
+    
+        char target[128];
+        char resolved[128];
+        char tmp[192];
+        const char *line;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        line = repl[i] ? repl[i] : lines[i];
+        
+        if (!line || !inline_parse_jump_label (line, "jmp", target, sizeof (target))) {
+            continue;
+        }
+        
+        if (!inline_resolve_jump_chain (chain_from, chain_to, count, target, resolved, sizeof (resolved))) {
+            continue;
+        }
+        
+        sprintf (tmp, "    jmp %s\n", resolved);
+        free (repl[i]);
+        
+        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
+    
+    }
+    
+    for (i = 0; i < count; i++) {
+    
+        char target[128];
+        const char *line;
+        int j;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        line = repl[i] ? repl[i] : lines[i];
+        
+        if (!line || !inline_parse_any_jump_label (line, target, sizeof (target))) {
+            continue;
+        }
+        
+        for (j = 0; j < count; j++) {
+        
+            char label[128];
+            const char *def;
+            
+            if (skip[j]) {
+                continue;
+            }
+            
+            def = repl[j] ? repl[j] : lines[j];
+            
+            if (def && inline_parse_label_definition (def, label, sizeof (label)) && strcmp (label, target) == 0) {
+            
+                label_refs[j]++;
+                break;
+            
+            }
+        
+        }
+    
+    }
+    
+    for (i = 0; i < count; i++) {
+    
+        char target[128];
+        const char *line;
+        int j;
+        int target_line = -1;
+        int can_delete = 1;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        line = repl[i] ? repl[i] : lines[i];
+        
+        if (!line || !inline_parse_jump_label (line, "jmp", target, sizeof (target))) {
+            continue;
+        }
+        
+        for (j = i + 1; j < count; j++) {
+        
+            char label[128];
+            const char *check;
+            
+            if (skip[j]) {
+                continue;
+            }
+            
+            check = repl[j] ? repl[j] : lines[j];
+            
+            if (check && inline_parse_label_definition (check, label, sizeof (label)) && strcmp (label, target) == 0) {
+            
+                target_line = j;
+                break;
+            
+            }
+        
+        }
+        
+        if (target_line < 0) {
+            continue;
+        }
+        
+        for (j = i + 1; j < target_line; j++) {
+        
+            char label[128];
+            const char *check;
+            
+            if (skip[j]) {
+                continue;
+            }
+            
+            check = repl[j] ? repl[j] : lines[j];
+            
+            if (check && inline_parse_label_definition (check, label, sizeof (label)) && label_refs[j] > 0) {
+            
+                can_delete = 0;
+                break;
+            
+            }
+        
+        }
+        
+        if (!can_delete) {
+            continue;
+        }
+        
+        for (j = i + 1; j < target_line; j++) {
+            skip[j] = 1;
+        }
+    
+    }
+    
+    for (i = 0; i < count; i++) {
+    
+        char target[128];
+        const char *line;
+        int j;
+        int target_line = -1;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        line = repl[i] ? repl[i] : lines[i];
+        
+        if (!line || !inline_parse_jump_label (line, "jmp", target, sizeof (target))) {
+            continue;
+        }
+        
+        for (j = i + 1; j < count; j++) {
+        
+            char label[128];
+            const char *check;
+            
+            if (skip[j]) {
+                continue;
+            }
+            
+            check = repl[j] ? repl[j] : lines[j];
+            
+            if (!check) {
+                continue;
+            }
+            
+            if (inline_parse_label_definition (check, label, sizeof (label))) {
+            
+                if (strcmp (label, target) == 0) {
+                    target_line = j;
+                }
+                
+                break;
+            
+            }
+            
+            break;
+        
+        }
+        
+        if (target_line >= 0) {
+            skip[i] = 1;
+        }
+    
+    }
+    
+    /*
+     * Branch folding can create new unreachable ranges after the earlier
+     * jump cleanup has already run.  Recompute label references from the
+     * current non-skipped text and remove dead fall-through ranges between
+     * an unconditional jump and its later target.  This deliberately keeps
+     * referenced labels, so externally reachable or still-jumped-to blocks
+     * are not discarded.
+     */
+    {
+    
+        int changed;
+        int pass;
+        
+        for (pass = 0; pass < count; pass++) {
+        
+            changed = 0;
+            
+            for (i = 0; i < count; i++) {
+                label_refs[i] = 0;
+            }
+            
+            for (i = 0; i < count; i++) {
+            
+                char target[128];
+                const char *line;
+                int j;
+                
+                if (skip[i]) {
+                    continue;
+                }
+                
+                line = repl[i] ? repl[i] : lines[i];
+                
+                if (!line || !inline_parse_any_jump_label (line, target, sizeof (target))) {
+                    continue;
+                }
+                
+                for (j = 0; j < count; j++) {
+                
+                    char label[128];
+                    const char *def;
+                    
+                    if (skip[j]) {
+                        continue;
+                    }
+                    
+                    def = repl[j] ? repl[j] : lines[j];
+                    
+                    if (def && inline_parse_label_definition (def, label, sizeof (label)) && strcmp (label, target) == 0) {
+                    
+                        label_refs[j]++;
+                        break;
+                    
+                    }
+                
+                }
+            
+            }
+            
+            for (i = 0; i < count; i++) {
+            
+                char target[128];
+                const char *line;
+                int j;
+                int target_line = -1;
+                int can_delete = 1;
+                
+                if (skip[i]) {
+                    continue;
+                }
+                
+                line = repl[i] ? repl[i] : lines[i];
+                
+                if (!line || !inline_parse_jump_label (line, "jmp", target, sizeof (target))) {
+                    continue;
+                }
+                
+                for (j = i + 1; j < count; j++) {
+                
+                    char label[128];
+                    const char *check;
+                    
+                    if (skip[j]) {
+                        continue;
+                    }
+                    
+                    check = repl[j] ? repl[j] : lines[j];
+                    
+                    if (check && inline_parse_label_definition (check, label, sizeof (label)) && strcmp (label, target) == 0) {
+                    
+                        target_line = j;
+                        break;
+                    
+                    }
+                
+                }
+                
+                if (target_line < 0) {
+                    continue;
+                }
+                
+                for (j = i + 1; j < target_line; j++) {
+                
+                    char label[128];
+                    const char *check;
+                    
+                    if (skip[j]) {
+                        continue;
+                    }
+                    
+                    check = repl[j] ? repl[j] : lines[j];
+                    
+                    if (check && inline_parse_label_definition (check, label, sizeof (label)) && label_refs[j] > 0) {
+                    
+                        can_delete = 0;
+                        break;
+                    
+                    }
+                
+                }
+                
+                if (!can_delete) {
+                    continue;
+                }
+                
+                for (j = i + 1; j < target_line; j++) {
+                
+                    if (!skip[j]) {
+                    
+                        skip[j] = 1;
+                        changed = 1;
+                    
+                    }
+                
+                }
+            
+            }
+            
+            if (!changed) {
+                break;
+            }
+        
+        }
+    
+    }
+    
+    /*
+     * The second unreachable-code pass can expose a new fall-through jump,
+     * for example "jmp L9" immediately followed by "L9:".  Run this small
+     * cleanup again at the end so later branch/unreachable optimisations do
+     * not leave the already-handled form behind.
+     */
+    for (i = 0; i < count; i++) {
+    
+        char target[128];
+        const char *line;
+        int j;
+        int target_line = -1;
+        
+        if (skip[i]) {
+            continue;
+        }
+        
+        line = repl[i] ? repl[i] : lines[i];
+        
+        if (!line || !inline_parse_jump_label (line, "jmp", target, sizeof (target))) {
+            continue;
+        }
+        
+        for (j = i + 1; j < count; j++) {
+        
+            char label[128];
+            const char *check;
+            
+            if (skip[j]) {
+                continue;
+            }
+            
+            check = repl[j] ? repl[j] : lines[j];
+            
+            if (!check) {
+                continue;
+            }
+            
+            if (inline_parse_label_definition (check, label, sizeof (label))) {
+            
+                if (strcmp (label, target) == 0) {
+                    target_line = j;
+                }
+                
+                break;
+            
+            }
+            
+            break;
+        
+        }
+        
+        if (target_line >= 0) {
+            skip[i] = 1;
+        }
+    
+    }
+    
+    for (i = 0; i < count; i++) {
+    
+        if (!skip[i]) {
+            fputs (repl[i] ? repl[i] : (lines[i] ? lines[i] : ""), ofp);
+        }
+        
+        free (lines[i]);
+        free (repl[i]);
+    
+    }
+    
+    for (i = 0; i < count; i++) {
+    
+        free (chain_from[i]);
+        free (chain_to[i]);
+    
+    }
+    
+    free (lines);
+    free (repl);
+    free (skip);
+    free (store_slot);
+    free (chain_from);
+    free (chain_to);
+    free (label_refs);
+
+}
+
+static void finish_inline_buffer (FILE **tmp, FILE **saved, int optimize) {
+
+    FILE *out;
+    long size;
+    char *buf;
+    
+    if (!tmp || !saved || !*tmp || !*saved) {
+        return;
+    }
+    
+    out = *saved;
+    
+    fflush (*tmp);
+    fseek (*tmp, 0, SEEK_END);
+    
+    size = ftell (*tmp);
+    fseek (*tmp, 0, SEEK_SET);
+    
+    if (size > 0) {
+    
+        buf = (char *) malloc ((size_t) size + 1);
+        
+        if (buf) {
+        
+            if (fread (buf, 1, (size_t) size, *tmp) == (size_t) size) {
+            
+                buf[size] = '\0';
+                
+                if (optimize) {
+                    emit_inline_optimized_text (buf, out);
+                } else {
+                    fwrite (buf, 1, (size_t) size, out);
+                }
+            
+            }
+            
+            free (buf);
+        
+        }
+    
+    }
+    
+    scc_close (*tmp);
+    
+    *tmp = 0;
+    *saved = 0;
+    
+    state->ofp = out;
+
+}
+
+static void emit_inline_body_substituted (const char *body, int return_label, int argc) {
+
+    const char *p = body;
+    
+    int call_id = anon_label++;
+    int stack_bytes = 0;
+    
+    if (!body || !state->ofp) {
+        return;
+    }
+    
+    while (*p) {
+    
+        const char *line = p;
+        const char *eol = strchr (p, '\n');
+        const char *next = eol ? eol + 1 : p + strlen (p);
+        size_t len = (size_t) (next - line);
+        
+        emit_inline_line_substituted (line, len, return_label, call_id, argc, stack_bytes);
+        stack_bytes += inline_line_stack_delta (line, len);
+        p = next;
+    
+    }
+    
+    if (body[0] && body[strlen (body) - 1] != '\n') {
+        fputc ('\n', state->ofp);
+    }
+    
+    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+        fprintf (state->ofp, "L%d:\n", call_id);
+    } else {
+        fprintf (state->ofp, ".L%d:\n", call_id);
+    }
+
+}
+
+static int emit_inline_call_if_possible (const char *name, int argc, const char *reg) {
+
+    int i = find_inline_function (name);
+    
+    if (i < 0 || !inline_functions[i].usable) {
+        return 0;
+    }
+    
+    if (argc != inline_functions[i].param_count) {
+        return 0;
+    }
+    
+    if (inline_functions[i].is_floating) {
+        return 0;
+    }
+    
+    if (inline_functions[i].expanding) {
+        return 0;
+    }
+    
+    if (!state->ofp) {
+        return 1;
+    }
+    
+    if (!inline_functions[i].body && !inline_functions[i].returns_void) {
+        return 0;
+    }
+    
+    if (inline_functions[i].body && inline_body_stack_delta (inline_functions[i].body) != 0) {
+        return 0;
+    }
+    
+    if (inline_functions[i].data && !inline_functions[i].data_emitted) {
+    
+        fputs (inline_functions[i].data, state->ofp);
+        
+        if (inline_functions[i].data[0] && inline_functions[i].data[strlen (inline_functions[i].data) - 1] != '\n') {
+            fputc ('\n', state->ofp);
+        }
+        
+        if (state->syntax & ASM_SYNTAX_MASM) {
+            fprintf (state->ofp, ".code\n");
+        } else if (state->syntax & ASM_SYNTAX_NASM) {
+            fprintf (state->ofp, "section .text\n");
+        } else {
+            fprintf (state->ofp, ".text\n");
+        }
+        
+        inline_functions[i].data_emitted = 1;
+    
+    }
+    
+    if (inline_functions[i].body) {
+    
+        inline_functions[i].expanding = 1;
+        emit_inline_body_substituted (inline_functions[i].body, inline_functions[i].return_label, argc);
+        inline_functions[i].expanding = 0;
+    
+    }
+    
+    if (!inline_functions[i].returns_void && strcmp (reg, "eax") != 0) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    mov %s, eax\n", reg);
+        } else {
+            fprintf (state->ofp, "    movl %%eax, %%%s\n", reg);
+        }
+    
+    }
+    
+    return 1;
+
+}
+
+static int local_array_pointer_step_size (const struct local_symbol *sym);
+static int global_array_pointer_step_size (const char *name);
+
+static int aggregate_tag_size_or_zero (const char *tag_name) {
+
+    struct aggregate_tag_entry *entry;
+    
+    if (!tag_name || !tag_name[0]) {
+        return 0;
+    }
+    
+    entry = find_aggregate_tag (tag_name, 0);
+    
+    if (entry && entry->size > 0) {
+        return entry->size;
+    }
+    
+    return 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 void reset_local_symbols (void) {
+
+    int i;
+    
+    for (i = 0; i < local_symbol_count; i++) {
+    
+        if (local_symbols[i].name) {
+        
+            free (local_symbols[i].name);
+            local_symbols[i].name = 0;
+        
+        }
+        
+        if (local_symbols[i].static_label) {
+        
+            free (local_symbols[i].static_label);
+            local_symbols[i].static_label = 0;
+        
+        }
+        
+        if (local_symbols[i].pointed_tag_name) {
+        
+            free (local_symbols[i].pointed_tag_name);
+            local_symbols[i].pointed_tag_name = 0;
+        
+        }
+        
+        if (local_symbols[i].tag_name) {
+        
+            free (local_symbols[i].tag_name);
+            local_symbols[i].tag_name = 0;
+        
+        }
+    
+    }
+    
+    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;
+    current_function_preserve_assignment64_regs = 0;
+
+}
+
+static void truncate_local_symbols (int count, long stack_size) {
+
+    int i;
+    
+    if (count < 0) {
+        count = 0;
+    }
+    
+    for (i = count; i < local_symbol_count; i++) {
+    
+        if (local_symbols[i].name) {
+        
+            free (local_symbols[i].name);
+            local_symbols[i].name = 0;
+        
+        }
+        
+        if (local_symbols[i].static_label) {
+        
+            free (local_symbols[i].static_label);
+            local_symbols[i].static_label = 0;
+        
+        }
+        
+        if (local_symbols[i].pointed_tag_name) {
+        
+            free (local_symbols[i].pointed_tag_name);
+            local_symbols[i].pointed_tag_name = 0;
+        
+        }
+        
+        if (local_symbols[i].tag_name) {
+        
+            free (local_symbols[i].tag_name);
+            local_symbols[i].tag_name = 0;
+        
+        }
+    
+    }
+    
+    local_symbol_count = count;
+    current_local_stack_size = stack_size;
+
+}
+
+static int local_symbol_exists_in_current_scope (const char *name, int start_count) {
+
+    int i;
+    
+    if (!name) {
+        return 0;
+    }
+    
+    for (i = start_count; i < local_symbol_count; i++) {
+    
+        if (local_symbols[i].name && strcmp (local_symbols[i].name, name) == 0) {
+            return 1;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static long add_local_symbol (const char *name, int size, int align, int is_unsigned, int scope_start_count, int line, const char *start, const char *caret) {
+
+    long new_size;
+    
+    if (!name) {
+        return 0;
+    }
+    
+    if (size < 1) {
+        size = 1;
+    }
+    
+    if (align < 1) {
+        align = 1;
+    }
+    
+    if (local_symbol_exists_in_current_scope (name, scope_start_count)) {
+    
+        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "duplicate local symbol '%s'", name);
+        return 0;
+    
+    }
+    
+    if (local_symbol_count >= MAX_LOCAL_SYMBOLS) {
+    
+        report_line_at (get_filename (), line, REPORT_ERROR, start, caret,  "too many local symbols");
+        return 0;
+    
+    }
+    
+    new_size = align_up_long (current_local_stack_size + size, align);
+    
+    /*
+     * EBP-relative locals must be backed by whole stack slots.  Without this,
+     * a byte-sized local following two pointer locals can be assigned offset
+     * -9(%ebp), while the emitted stack adjustment has only reserved 8 bytes.
+     * That is exactly what happened in cpplib/lex.c's _cpp_skip_block_comment:
+     *
+     *     cpp_mffc *mffc;   -> -4
+     *     const char *pos;  -> -8
+     *     char c;           -> -9, outside the reserved frame
+     *
+     * Keep the object's real size for loads/stores, but round the frame growth
+     * so subsequent stack allocation reserves enough bytes before the local is
+     * used.
+     */
+    new_size = align_up_long (new_size, 4);
+    
+    local_symbols[local_symbol_count].name = xstrdup (name);
+    local_symbols[local_symbol_count].size = size;
+    local_symbols[local_symbol_count].align = align;
+    local_symbols[local_symbol_count].offset = -(int) new_size;
+    local_symbols[local_symbol_count].is_static = 0;
+    local_symbols[local_symbol_count].static_label = 0;
+    local_symbols[local_symbol_count].is_unsigned = is_unsigned ? 1 : 0;
+    local_symbols[local_symbol_count].is_floating = 0;
+    local_symbols[local_symbol_count].is_array = 0;
+    local_symbols[local_symbol_count].array_element_size = 0;
+    local_symbols[local_symbol_count].array_dimensions = 0;
+    local_symbols[local_symbol_count].pointer_depth = 0;
+    local_symbols[local_symbol_count].pointed_size = 0;
+    local_symbols[local_symbol_count].pointed_is_floating = 0;
+    local_symbols[local_symbol_count].pointed_is_unsigned = 0;
+    local_symbols[local_symbol_count].pointed_tag_name = 0;
+    local_symbols[local_symbol_count].tag_name = 0;
+    
+    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;
+
+}
+
+static void add_static_local_symbol (const char *name, const char *label, int size, int align, int is_unsigned, int scope_start_count, int line, const char *start, const char *caret) {
+
+    if (!name || !label) {
+        return;
+    }
+    
+    if (size < 1) {
+        size = 1;
+    }
+    
+    if (align < 1) {
+        align = 1;
+    }
+    
+    if (local_symbol_exists_in_current_scope (name, scope_start_count)) {
+    
+        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "duplicate local symbol '%s'", name);
+        return;
+    
+    }
+    
+    if (local_symbol_count >= MAX_LOCAL_SYMBOLS) {
+    
+        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "too many local symbols");
+        return;
+    
+    }
+    
+    local_symbols[local_symbol_count].name = xstrdup (name);
+    local_symbols[local_symbol_count].static_label = xstrdup (label);
+    local_symbols[local_symbol_count].size = size;
+    local_symbols[local_symbol_count].align = align;
+    local_symbols[local_symbol_count].offset = 0;
+    local_symbols[local_symbol_count].is_static = 1;
+    local_symbols[local_symbol_count].is_unsigned = is_unsigned ? 1 : 0;
+    local_symbols[local_symbol_count].is_floating = 0;
+    local_symbols[local_symbol_count].is_array = 0;
+    local_symbols[local_symbol_count].array_element_size = 0;
+    local_symbols[local_symbol_count].array_dimensions = 0;
+    local_symbols[local_symbol_count].pointer_depth = 0;
+    local_symbols[local_symbol_count].pointed_size = 0;
+    local_symbols[local_symbol_count].pointed_is_floating = 0;
+    local_symbols[local_symbol_count].pointed_is_unsigned = 0;
+    local_symbols[local_symbol_count].pointed_tag_name = 0;
+    local_symbols[local_symbol_count].tag_name = 0;
+       
+    local_symbol_count++;
+
+}
+
+static void set_local_symbol_array (const char *name, int is_array) {
+
+    struct local_symbol *sym = find_local_symbol (name);
+    
+    if (sym) {
+        sym->is_array = is_array ? 1 : 0;
+    }
+
+}
+
+static void set_local_symbol_array_element_size (const char *name, int elem_size) {
+
+    struct local_symbol *sym = find_local_symbol (name);
+    
+    if (sym) {
+        sym->array_element_size = elem_size > 0 ? elem_size : 0;
+    }
+
+}
+
+static void set_local_symbol_array_dimensions (const char *name, int dims) {
+
+    struct local_symbol *sym = find_local_symbol (name);
+    
+    if (sym) {
+        sym->array_dimensions = dims > 0 ? dims : 0;
+    }
+
+}
+
+static void set_local_symbol_floating (const char *name, int is_floating) {
+
+    int i;
+    
+    if (!name) {
+        return;
+    }
+    
+    for (i = local_symbol_count - 1; i >= 0; i--) {
+    
+        if (local_symbols[i].name && strcmp (local_symbols[i].name, name) == 0) {
+        
+            local_symbols[i].is_floating = is_floating ? 1 : 0;
+            return;
+        
+        }
+    
+    }
+
+}
+
+static int local_symbol_exists_in_current_scope (const char *name, int start_count);
+
+static int find_pending_param (const char *name) {
+    return find_pending_param_from (name, 0);
+}
+
+static void update_pending_param (const char *name, int size, int align, int is_unsigned, int is_floating, int pointer_depth, int pointed_size, int pointed_is_unsigned) {
+
+    int i = find_pending_param (name);
+    
+    if (i < 0) {
+        return;
+    }
+    
+    if (pointer_depth > 0 && parsed_type_is_aggregate && parsed_type_size > (DATA_PTR & 0x1f) && pointed_size <= (DATA_PTR & 0x1f)) {
+        pointed_size = parsed_type_size;
+    }
+    
+    if (size < 1) {
+        size = DATA_INT & 0x1f;
+    }
+    
+    if (align < 1) {
+        align = type_alignment (size);
+    }
+    
+    pending_params[i].size = size;
+    pending_params[i].align = align;
+    pending_params[i].is_unsigned = is_unsigned ? 1 : 0;
+    pending_params[i].is_floating = is_floating ? 1 : 0;
+    pending_params[i].pointer_depth = pointer_depth;
+    pending_params[i].pointed_size = pointed_size > 0 ? pointed_size : 0;
+    pending_params[i].pointed_is_floating = pointer_depth > 0 ? (parsed_type_is_floating ? 1 : 0) : 0;
+    pending_params[i].pointed_is_unsigned = pointer_depth > 0 ? (pointed_is_unsigned ? 1 : 0) : 0;
+    
+    if (pending_params[i].pointed_tag_name) {
+    
+        free (pending_params[i].pointed_tag_name);
+        pending_params[i].pointed_tag_name = 0;
+    
+    }
+    
+    if (pointer_depth > 0 && parsed_type_tag_name[0]) {
+        pending_params[i].pointed_tag_name = xstrdup (parsed_type_tag_name);
+    }
+
+}
+
+static int mark_pending_param_knr_declared (const char *name, const char *name_start, const char *name_caret, unsigned long name_line) {
+
+    int i = find_pending_param (name);
+    
+    if (i < 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "K&R parameter '%s' is not in function parameter list", name);
+        return 0;
+    
+    }
+    
+    if (pending_params[i].knr_declared) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "duplicate K&R parameter declaration for '%s'", name);
+        return 0;
+    
+    }
+    
+    pending_params[i].knr_declared = 1;
+    return 1;
+
+}
+
+static void remove_duplicate_pending_params (void) {
+
+    int i;
+    
+    for (i = 0; i < pending_param_count; i++) {
+    
+        int j;
+        
+        if (!pending_params[i].name) {
+            continue;
+        }
+        
+        j = i + 1;
+        
+        while (j < pending_param_count) {
+        
+            if (pending_params[j].name && strcmp (pending_params[i].name, pending_params[j].name) == 0) {
+            
+                int k;
+                
+                if (pending_params[j].name) {
+                    free (pending_params[j].name);
+                }
+                
+                if (pending_params[j].pointed_tag_name) {
+                    free (pending_params[j].pointed_tag_name);
+                }
+                
+                for (k = j; k + 1 < pending_param_count; k++) {
+                    pending_params[k] = pending_params[k + 1];
+                }
+                
+                pending_param_count--;
+                
+                pending_params[pending_param_count].name = 0;
+                pending_params[pending_param_count].size = 0;
+                pending_params[pending_param_count].align = 0;
+                pending_params[pending_param_count].is_unsigned = 0;
+                pending_params[pending_param_count].is_floating = 0;
+                pending_params[pending_param_count].pointer_depth = 0;
+                pending_params[pending_param_count].pointed_size = 0;
+                pending_params[pending_param_count].pointed_tag_name = 0;
+                
+                continue;
+            
+            }
+            
+            j++;
+        
+        }
+    
+    }
+
+}
+
+static void copy_pending_params_to_global_symbol (const char *name) {
+
+    int i = find_global_symbol (name);
+    int pi;
+    
+    if (i < 0) {
+        return;
+    }
+    
+    for (pi = 0; pi < 128; pi++) {
+    
+        global_symbols[i].param_sizes[pi] = 0;
+        global_symbols[i].param_unsigneds[pi] = 0;
+        global_symbols[i].param_floatings[pi] = 0;
+        global_symbols[i].param_pointer_depths[pi] = 0;
+    
+    }
+    
+    for (pi = 0; pi < pending_param_count && pi < 128; pi++) {
+    
+        global_symbols[i].param_sizes[pi] = pending_params[pi].size;
+        global_symbols[i].param_unsigneds[pi] = pending_params[pi].is_unsigned;
+        global_symbols[i].param_floatings[pi] = pending_params[pi].is_floating;
+        global_symbols[i].param_pointer_depths[pi] = pending_params[pi].pointer_depth;
+    
+    }
+
+}
+
+static void set_local_symbol_pointer_info (const char *name, int pointer_depth, int pointed_size) {
+
+    struct local_symbol *sym = find_local_symbol (name);
+    
+    if (pointer_depth > 0 && parsed_type_is_aggregate && parsed_type_size > (DATA_PTR & 0x1f) && pointed_size <= (DATA_PTR & 0x1f)) {
+        pointed_size = parsed_type_size;
+    }
+    
+    if (sym) {
+    
+        sym->pointer_depth = pointer_depth;
+        sym->pointed_size = pointed_size;
+        
+        sym->pointed_is_floating = pointer_depth > 0 ? (parsed_type_is_floating ? 1 : 0) : 0;
+        sym->pointed_is_unsigned = pointer_depth > 0 ? (parsed_type_is_unsigned ? 1 : 0) : 0;
+        
+        if (sym->pointed_tag_name) {
+        
+            free (sym->pointed_tag_name);
+            sym->pointed_tag_name = 0;
+        
+        }
+        
+        if ((pointer_depth > 0 || sym->is_array) && parsed_type_tag_name[0]) {
+            sym->pointed_tag_name = xstrdup (parsed_type_tag_name);
+        }
+    
+    }
+
+}
+
+static void install_pending_params_as_locals (void) {
+
+    long offset = current_function_returns_aggregate ? 12 : 8;
+    int i;
+    
+    for (i = 0; i < pending_param_count; i++) {
+    
+        int slot_size;
+        
+        if (!pending_params[i].name) {
+            continue;
+        }
+        
+        if (local_symbol_count >= MAX_LOCAL_SYMBOLS) {
+        
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "too many local symbols");
+            break;
+        
+        }
+        
+        if (local_symbol_exists_in_current_scope (pending_params[i].name, 0)) {
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate parameter '%s'", pending_params[i].name);
+        }
+        
+        local_symbols[local_symbol_count].name = xstrdup (pending_params[i].name);
+        local_symbols[local_symbol_count].size = pending_params[i].size;
+        local_symbols[local_symbol_count].align = pending_params[i].align;
+        local_symbols[local_symbol_count].offset = (int) offset;
+        local_symbols[local_symbol_count].is_static = 0;
+        local_symbols[local_symbol_count].static_label = 0;
+        local_symbols[local_symbol_count].is_unsigned = pending_params[i].is_unsigned;
+        local_symbols[local_symbol_count].is_floating = pending_params[i].is_floating;
+        local_symbols[local_symbol_count].pointer_depth = pending_params[i].pointer_depth;
+        local_symbols[local_symbol_count].pointed_is_floating = pending_params[i].pointed_is_floating;
+        local_symbols[local_symbol_count].pointed_is_unsigned = pending_params[i].pointed_is_unsigned;
+        local_symbols[local_symbol_count].is_array = 0;
+        local_symbols[local_symbol_count].array_element_size = 0;
+        local_symbols[local_symbol_count].array_dimensions = 0;
+        local_symbols[local_symbol_count].pointed_size = pending_params[i].pointed_size;
+        local_symbols[local_symbol_count].pointed_tag_name = pending_params[i].pointed_tag_name ? xstrdup (pending_params[i].pointed_tag_name) : 0;
+        local_symbols[local_symbol_count].tag_name = 0;
+        
+        local_symbol_count++;
+        slot_size = pending_params[i].size;
+        
+        if (slot_size < DATA_PTR) {
+            slot_size = DATA_PTR;
+        }
+        
+        slot_size = (int) align_up_long (slot_size, DATA_PTR);
+        offset += slot_size;
+    
+    }
+
+}
+
+#define     MAX_LOCAL_INITS             1024
+
+#define     LOCAL_INIT_CONST            0
+#define     LOCAL_INIT_ADDRESS          1
+#define     LOCAL_INIT_STACK            2
+#define     LOCAL_INIT_GLOBAL           3
+
+struct local_init {
+
+    long offset;
+    
+    int size;
+    int kind;
+    
+    char *symbol;
+    int64_s value;
+    
+    long source_offset;
+    int source_size;
+
+};
+
+static void switch_section (int sec) {
+
+    if (!state->ofp || current_section == sec) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+        masm_flush_data_line ();
+    }
+    
+    if (sec == SECTION_TEXT) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+            fprintf (state->ofp, "section .text\n");
+        } else {
+            fprintf (state->ofp, "%s\n", (state->syntax & ASM_SYNTAX_MASM ? ".code" : ".text"));
+        }
+    
+    } else if (sec == SECTION_DATA) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+            fprintf (state->ofp, "section .data\n");
+        } else {
+            fprintf (state->ofp, ".data\n");
+        }
+    
+    } else if (sec == SECTION_BSS) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+            fprintf (state->ofp, "section .bss\n");
+        } else {
+            fprintf (state->ofp, "%s\n", (state->syntax & ASM_SYNTAX_MASM ? ".data?" : ".bss"));
+        }
+    
+    }
+    
+    current_section = sec;
+
+}
+
+/*static void next (void) {
+    get_token ();
+}*/
+
+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;
+    int saved_storage_class = parsed_storage_class;
+    int saved_is_aggregate = parsed_type_is_aggregate;
+    int saved_is_void = parsed_type_is_void;
+    int saved_is_unsigned = parsed_type_is_unsigned;
+    int saved_is_floating = parsed_type_is_floating;
+    int saved_has_tag = parsed_type_has_tag;
+    int saved_is_inline = parsed_type_is_inline;
+    int saved_field_count = parsed_field_count;
+    int saved_fields[MAX_AGG_FIELDS];
+    int saved_declarator_is_pointer = declarator_is_pointer;
+    int saved_declarator_pointer_depth = declarator_pointer_depth;
+    int saved_declarator_has_array = declarator_has_array;
+    int saved_declarator_has_function = declarator_has_function;
+    int saved_declarator_array_unsized = declarator_array_unsized;
+    int saved_declarator_array_dimensions = declarator_array_dimensions;
+    
+    long saved_declarator_array_count = declarator_array_count;
+    long saved_declarator_first_array_count = declarator_first_array_count;
+    
+    char *name = 0;
+    
+    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];
+    }
+    
+    if (is_type_start (tok.kind)) {
+    
+        declarator_is_pointer = 0;
+        declarator_pointer_depth = 0;
+        declarator_has_array = 0;
+        declarator_has_function = 0;
+        declarator_array_unsized = 0;
+        declarator_array_count = 0;
+        
+        parse_type_spec ();
+        
+        size = parsed_type_size & 0x1f;
+        cast_is_floating = parsed_type_is_floating;
+        
+        if (tok.kind != TOK_RPAREN) {
+        
+            parse_declarator (&name);
+            
+            /*
+             * This parser is called after a leading unary '*', for forms such
+             * as *(long long *)p.  The '*' outside the cast performs the
+             * dereference, so the size needed by the caller is the pointed-at
+             * object size, not DATA_PTR.  However, forms produced by va_arg()
+             * for pointer types are one level deeper, e.g. char * becomes
+             * *(char **).  In that case the dereferenced object is itself a
+             * pointer and must be loaded with pointer width.
+             */
+            if (declarator_is_pointer && declarator_pointer_depth > 1) {
+                size = DATA_PTR;
+            }
+        
+        }
+        
+        if (tok.kind == TOK_RPAREN) {
+        
+            get_token ();
+            ok = 1;
+            
+            last_deref_cast_type_is_floating = cast_is_floating;
+        
+        } else {
+            expect (TOK_RPAREN, ")");
+        }
+        
+        if (name) {
+            free (name);
+        }
+    
+    }
+    
+    parsed_type_size = saved_type_size;
+    parsed_storage_class = saved_storage_class;
+    parsed_type_is_aggregate = saved_is_aggregate;
+    parsed_type_is_void = saved_is_void;
+    parsed_type_is_unsigned = saved_is_unsigned;
+    parsed_type_is_floating = saved_is_floating;
+    parsed_type_has_tag = saved_has_tag;
+    parsed_type_is_inline = saved_is_inline;
+    
+    clear_parsed_fields ();
+    
+    for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
+        parsed_field_sizes[i] = saved_fields[i];
+    }
+    
+    parsed_field_count = saved_field_count;
+    
+    declarator_is_pointer = saved_declarator_is_pointer;
+    declarator_pointer_depth = saved_declarator_pointer_depth;
+    declarator_has_array = saved_declarator_has_array;
+    declarator_has_function = saved_declarator_has_function;
+    declarator_array_unsized = saved_declarator_array_unsized;
+    declarator_array_count = saved_declarator_array_count;
+    declarator_first_array_count = saved_declarator_first_array_count;
+    declarator_array_dimensions = saved_declarator_array_dimensions;
+    
+    if (out_size) {
+        *out_size = size;
+    }
+    
+    return ok;
+
+}
+
+static void emit_load_assignment_rhs_expression_to_reg (const char *reg);
+static void emit_load_floating_rhs_expression_now (int result_size);
+static void emit_store_floating_to_local_now (long offset, int size);
+
+static void consume_comma_expression_tail_before_semi (void) {
+
+    while (tok.kind == TOK_COMMA) {
+    
+        get_token ();
+        emit_load_assignment_rhs_expression_to_reg ("eax");
+    
+    }
+
+}
+
+static void expect_semi_or_recover (void) {
+
+    consume_comma_expression_tail_before_semi ();
+    
+    if (expect (TOK_SEMI, ";")) {
+        return;
+    }
+    
+    skip_balanced_until (TOK_SEMI, TOK_RBRACE, TOK_EOF);
+    
+    if (tok.kind == TOK_SEMI) {
+        get_token ();
+    }
+
+}
+
+static int current_ident_is_known_value (void) {
+
+    int64_s ignored;
+    
+    if (tok.kind != TOK_IDENT) {
+        return 0;
+    }
+    
+    if (find_local_symbol (tok.ident)) {
+        return 1;
+    }
+    
+    if (find_global_symbol (tok.ident) >= 0) {
+        return 1;
+    }
+    
+    if (resolve_enum_constant (tok.ident, &ignored)) {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static int recover_unknown_rhs_identifier (void) {
+
+    const char *name;
+    const char *start;
+    const char *caret;
+    
+    unsigned long line;
+    
+    if (tok.kind != TOK_IDENT || current_ident_is_known_value ()) {
+        return 0;
+    }
+    
+    name = tok.ident ? tok.ident : "";
+    start = tok.start;
+    caret = tok.caret;
+    line = get_line_number ();
+    
+    report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "unknown symbol '%s'", name);
+    get_token ();
+    
+    if (tok.kind == TOK_LPAREN) {
+    
+        get_token ();
+        skip_balanced_until (TOK_RPAREN, TOK_SEMI, TOK_EOF);
+        
+        if (tok.kind == TOK_RPAREN) {
+            get_token ();
+        }
+    
+    }
+    
+    return 1;
+
+}
+
+/*static void consume_redundant_rparens_before_statement (void) {
+
+    while (tok.kind == TOK_RPAREN) {
+        get_token ();
+    }
+
+}*/
+
+static void skip_initializer (void) {
+
+    if (tok.kind == TOK_LBRACE) {
+        skip_balanced_until (TOK_COMMA, TOK_SEMI, TOK_EOF);
+    } else {
+        skip_balanced_until (TOK_COMMA, TOK_SEMI, TOK_EOF);
+    }
+
+}
+
+static void apply_typedef_array_to_declarator (void) {
+
+    if (parsed_type_is_array_typedef && !declarator_is_pointer && !declarator_has_array && !declarator_has_function) {
+    
+        declarator_has_array = 1;
+        
+        declarator_array_count = parsed_type_array_count > 0 ? parsed_type_array_count : 1;
+        declarator_first_array_count = declarator_array_count;
+        declarator_last_array_count = declarator_array_count;
+        declarator_array_dimensions = 1;
+        
+        if (parsed_type_array_element_size > 0) {
+            parsed_type_size = parsed_type_array_element_size;
+        }
+    
+    }
+
+}
+
+static void parse_old_style_param_decls (void) {
+
+    while (is_type_start (tok.kind)) {
+    
+        int param_base_size;
+        
+        parse_type_spec ();
+        param_base_size = parsed_type_size;
+        
+        for (;;) {
+        
+            char *name = 0;
+            
+            int param_size;
+            int param_pointer_depth;
+            
+            preserve_pending_params++;
+            parse_declarator (&name);
+            preserve_pending_params--;
+            
+            if (name) {
+            
+                param_size = (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef) ? DATA_PTR : declarator_object_size (param_base_size);
+                param_pointer_depth = declarator_pointer_depth;
+                
+                if ((declarator_has_array || declarator_has_function || parsed_type_is_array_typedef) && param_pointer_depth < 1) {
+                    param_pointer_depth = 1;
+                }
+                
+                if (mark_pending_param_knr_declared (name, last_declarator_name_start, last_declarator_name_caret, last_declarator_name_line)) {
+                
+                    update_pending_param (name, param_size, type_alignment (param_size),
+                        (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef ? 0 : parsed_type_is_unsigned),
+                            (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef ? 0 : parsed_type_is_floating),
+                                param_pointer_depth, parsed_type_is_aggregate ? parsed_type_size : (parsed_type_size & 0x1f), parsed_type_is_unsigned);
+                
+                }
+                
+                free (name);
+            
+            }
+            
+            if (_accept (TOK_ASSIGN)) {
+                skip_initializer ();
+            }
+            
+            if (!_accept (TOK_COMMA)) {
+                break;
+            }
+        
+        }
+        
+        expect (TOK_SEMI, ";");
+    
+    }
+
+}
+
+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;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    asm_name = asm_global_symbol_name (name);
+    switch_section (SECTION_TEXT);
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+    
+        masm_flush_data_line ();
+        
+        if (!is_static) {
+            fprintf (state->ofp, "public %s\n", asm_name);
+        }
+    
+    } else if (state->syntax & ASM_SYNTAX_NASM) {
+    
+        if (!is_static) {
+            fprintf (state->ofp, "global %s\n", asm_name);
+        }
+    
+    } else {
+    
+        if (!is_static) {
+            fprintf (state->ofp, ".globl %s\n", asm_name);
+        }
+    
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        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 ();
+    
+    }
+
+}
+
+static void emit_pending_return_jump (void) {
+
+    if (!pending_return_jump) {
+        return;
+    }
+    
+    if (!state->ofp) {
+    
+        pending_return_jump = 0;
+        return;
+    
+    }
+    
+    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+        fprintf (state->ofp, "    jmp L%d\n", current_return_label);
+    } else {
+        fprintf (state->ofp, "    jmp .L%d\n", current_return_label);
+    }
+    
+    pending_return_jump = 0;
+
+}
+
+static void emit_stack_adjust (long bytes, int allocate) {
+
+    if (!state->ofp || bytes <= 0) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    %s esp, %ld\n", allocate ? "sub" : "add", bytes);
+    } else {
+        fprintf (state->ofp, "    %s $%ld, %%esp\n", allocate ? "subl" : "addl", bytes);
+    }
+
+}
+
+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) {
+        return;
+    }
+    
+    if (offset < 0) {
+        sprintf (buf, "[ebp - %ld]", -offset);
+    } else if (offset > 0) {
+        sprintf (buf, "[ebp + %ld]", offset);
+    } else {
+        sprintf (buf, "[ebp]");
+    }
+
+}
+
+static const char *format_nasm_memory_operand (char *buf, size_t bufsz, const char *operand) {
+
+    if (!operand) {
+        return operand;
+    }
+    
+    if (!(state->syntax & ASM_SYNTAX_NASM)) {
+        return operand;
+    }
+    
+    if (operand[0] == '[') {
+        return operand;
+    }
+    
+    if (buf && bufsz > 0) {
+    
+        sprintf (buf, "[%s]", operand);
+        return buf;
+    
+    }
+    
+    return operand;
+
+}
+
+static void emit_local_store_const (long offset, int size, int64_s value) {
+
+    char memref_hi[64], memref[64];
+    unsigned long high, low;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    low = value.low;
+    high = value.high;
+    
+    if (size > 8 && low == 0 && high == 0) {
+    
+        long pos;
+        
+        for (pos = 0; pos < size; pos += 4) {
+            emit_local_store_const (offset + pos, DATA_INT, value);
+        }
+        
+        return;
+    
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_ebp_offset (memref, sizeof (memref), offset);
+        
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov byte %s, %lu\n" : "    mov byte ptr %s, %lu\n"), memref, low & ((1 << 8) - 1));
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov word %s, %lu\n" : "    mov word ptr %s, %lu\n"), memref, low & ((1 << 16) - 1));
+        } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
+        
+            format_intel_ebp_offset (memref_hi, sizeof (memref_hi), offset + 4);
+            
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword %s, %lu\n" : "    mov dword ptr %s, %lu\n"), memref, low & U32_MASK);
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword %s, %lu\n" : "    mov dword ptr %s, %lu\n"), memref_hi, high & U32_MASK);
+        
+        } else {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword %s, %lu\n" : "    mov dword ptr %s, %lu\n"), memref, low & U32_MASK);
+        }
+    
+    } else {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, "    movb $%lu, %ld(%%ebp)\n", low & 0xffUL, offset);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, "    movw $%lu, %ld(%%ebp)\n", low & 0xffffUL, offset);
+        } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
+        
+            fprintf (state->ofp, "    movl $%lu, %ld(%%ebp)\n", low & U32_MASK, offset);
+            fprintf (state->ofp, "    movl $%lu, %ld(%%ebp)\n", high & U32_MASK, offset + 4);
+        
+        } else {
+            fprintf (state->ofp, "    movl $%lu, %ld(%%ebp)\n", low & U32_MASK, offset);
+        }
+    
+    }
+
+}
+
+static void emit_store_floating_to_local_now (long offset, int size) {
+
+    char memref[64];
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_ebp_offset (memref, sizeof (memref), offset);
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fstp %s %s\n" : "    fstp %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", memref);
+    
+    } else {
+        fprintf (state->ofp, "    fstp%s %ld(%%ebp)\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", offset);
+    }
+
+}
+
+static void emit_local_store_address (long offset, const char *symbol) {
+
+    const char *asm_symbol;
+    char memref[64];
+    
+    if (!state->ofp || !symbol) {
+        return;
+    }
+    
+    emit_extern_reference_symbol (symbol, DATA_PTR);
+    asm_symbol = asm_global_symbol_name (symbol);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_ebp_offset (memref, sizeof (memref), offset);
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword %s, %s\n" : "    mov dword ptr %s, offset %s\n"), memref, asm_symbol);
+    
+    } else {
+        fprintf (state->ofp, "    movl $%s, %ld(%%ebp)\n", asm_symbol, offset);
+    }
+
+}
+
+static void emit_local_store_stack (long dst_offset, int dst_size, long src_offset, int src_size) {
+
+    char dst[64];
+    char src[64];
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_ebp_offset (dst, sizeof (dst), dst_offset);
+        format_intel_ebp_offset (src, sizeof (src), src_offset);
+
+        if (dst_size == (DATA_CHAR & 0x1f)) {
+        
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov al, byte %s\n" : "    mov al, byte ptr %s\n"), src);
+            fprintf (state->ofp, "    mov byte ptr %s, al\n", dst);
+        
+        } else if (dst_size == (DATA_SHORT & 0x1f)) {
+        
+            if (src_size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov ax, byte %s\n" : "    movzx ax, byte ptr %s\n"), src);
+            } else {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov ax, word %s\n" : "    mov ax, word ptr %s\n"), src);
+            }
+            
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov word %s, ax\n" : "    mov word ptr %s, ax\n"), dst);
+        
+        } else {
+        
+            if (src_size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movzx eax, byte %s\n" : "    movzx eax, byte ptr %s\n"), src);
+            } else if (src_size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movzx eax, word %s\n" : "    movzx eax, word ptr %s\n"), src);
+            } else {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov eax, dword %s\n" : "    mov eax, dword ptr %s\n"), src);
+            }
+            
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword %s, eax\n" : "    mov dword ptr %s, eax\n"), dst);
+        
+        }
+    
+    } else {
+    
+        if (dst_size == (DATA_CHAR & 0x1f)) {
+        
+            fprintf (state->ofp, "    movb %ld(%%ebp), %%al\n", src_offset);
+            fprintf (state->ofp, "    movb %%al, %ld(%%ebp)\n", dst_offset);
+        
+        } else if (dst_size == (DATA_SHORT & 0x1f)) {
+        
+            fprintf (state->ofp, "    movw %ld(%%ebp), %%ax\n", src_offset);
+            fprintf (state->ofp, "    movw %%ax, %ld(%%ebp)\n", dst_offset);
+        
+        } else {
+        
+            fprintf (state->ofp, "    movl %ld(%%ebp), %%eax\n", src_offset);
+            fprintf (state->ofp, "    movl %%eax, %ld(%%ebp)\n", dst_offset);
+        
+        }
+    
+    }
+
+}
+
+static void emit_local_store_global (long dst_offset, int dst_size, const char *symbol) {
+
+    const char *asm_symbol;
+    char dst[64];
+    
+    if (!state->ofp || !symbol) {
+        return;
+    }
+    
+    emit_extern_reference_symbol (symbol, get_global_symbol_size (symbol));
+    asm_symbol = asm_global_symbol_name (symbol);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_ebp_offset (dst, sizeof (dst), dst_offset);
+        
+        if (dst_size == (DATA_CHAR & 0x1f)) {
+        
+            if (state->syntax & ASM_SYNTAX_NASM) {
+            
+                fprintf (state->ofp, "    mov al, byte [%s]\n", asm_symbol);
+                fprintf (state->ofp, "    mov byte %s, al\n", dst);
+            
+            } else {
+            
+                fprintf (state->ofp, "    mov al, byte ptr %s\n", asm_symbol);
+                fprintf (state->ofp, "    mov byte ptr %s, al\n", dst);
+            
+            }
+        
+        } else if (dst_size == (DATA_SHORT & 0x1f)) {
+        
+            if (state->syntax & ASM_SYNTAX_NASM) {
+            
+                fprintf (state->ofp, "    mov ax, word [%s]\n", asm_symbol);
+                fprintf (state->ofp, "    mov word %s, ax\n", dst);
+            
+            } else {
+            
+                fprintf (state->ofp, "    mov ax, word ptr %s\n", asm_symbol);
+                fprintf (state->ofp, "    mov word ptr %s, ax\n", dst);
+            
+            }
+        
+        } else {
+        
+            if (state->syntax & ASM_SYNTAX_NASM) {
+            
+                fprintf (state->ofp, "    mov eax, dword [%s]\n", asm_symbol);
+                fprintf (state->ofp, "    mov dword %s, eax\n", dst);
+            
+            } else {
+            
+                fprintf (state->ofp, "    mov eax, dword ptr %s\n", asm_symbol);
+                fprintf (state->ofp, "    mov dword ptr %s, eax\n", dst);
+            
+            }
+        
+        }
+    
+    } else {
+    
+        if (dst_size == (DATA_CHAR & 0x1f)) {
+        
+            fprintf (state->ofp, "    movb %s, %%al\n", asm_symbol);
+            fprintf (state->ofp, "    movb %%al, %ld(%%ebp)\n", dst_offset);
+        
+        } else if (dst_size == (DATA_SHORT & 0x1f)) {
+        
+            fprintf (state->ofp, "    movw %s, %%ax\n", asm_symbol);
+            fprintf (state->ofp, "    movw %%ax, %ld(%%ebp)\n", dst_offset);
+        
+        } else {
+        
+            fprintf (state->ofp, "    movl %s, %%eax\n", asm_symbol);
+            fprintf (state->ofp, "    movl %%eax, %ld(%%ebp)\n", dst_offset);
+        
+        }
+    
+    }
+
+}
+
+static void emit_local_initializers (struct local_init *inits, int init_count) {
+
+    int i;
+    
+    for (i = 0; i < init_count; i++) {
+    
+        if (inits[i].kind == LOCAL_INIT_ADDRESS) {
+            emit_local_store_address (inits[i].offset, inits[i].symbol);
+        } else if (inits[i].kind == LOCAL_INIT_STACK) {
+            emit_local_store_stack (inits[i].offset, inits[i].size, inits[i].source_offset, inits[i].source_size);
+        } else if (inits[i].kind == LOCAL_INIT_GLOBAL) {
+            emit_local_store_global (inits[i].offset, inits[i].size, inits[i].symbol);
+        } else {
+            emit_local_store_const (inits[i].offset, inits[i].size, inits[i].value);
+        }
+        
+        if (inits[i].symbol) {
+        
+            free (inits[i].symbol);
+            inits[i].symbol = 0;
+        
+        }
+    
+    }
+
+}
+
+static void emit_function_end (void) {
+
+    patch_deferred_function_frame ();
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+    
+        fprintf (state->ofp, "L%d:\n", current_return_label);
+        
+        if (current_function_returns_aggregate) {
+        
+            if (state->syntax & ASM_SYNTAX_NASM) {
+                fprintf (state->ofp, "    mov eax, dword [ebp + 8]\n");
+            } else {
+                fprintf (state->ofp, "    mov eax, dword ptr [ebp + 8]\n");
+            }
+        
+        }
+        
+        if (current_function_preserve_assignment64_regs) {
+            fprintf (state->ofp, "__SCC_RESTORE_ASSIGNMENT64_REGS__\n");
+        }
+        
+        fprintf (state->ofp, "    leave\n");
+        
+        if (current_function_calling_convention == TOK_STDCALL && current_function_param_stack_bytes > 0) {
+            fprintf (state->ofp, "    ret %d\n", current_function_param_stack_bytes);
+        } else {
+            fprintf (state->ofp, "    ret\n");
+        }
+    
+    } else {
+    
+        fprintf (state->ofp, ".L%d:\n", current_return_label);
+        
+        if (current_function_returns_aggregate) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    mov eax, dword ptr [ebp + 8]\n");
+            } else {
+                fprintf (state->ofp, "    movl 8(%%ebp), %%eax\n");
+            }
+        
+        }
+        
+        if (current_function_preserve_assignment64_regs) {
+            fprintf (state->ofp, "__SCC_RESTORE_ASSIGNMENT64_REGS__\n");
+        }
+        
+        fprintf (state->ofp, "    leave\n");
+        
+        if (current_function_calling_convention == TOK_STDCALL && current_function_param_stack_bytes > 0) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    ret %d\n", current_function_param_stack_bytes);
+            } else {
+                fprintf (state->ofp, "    ret $%d\n", current_function_param_stack_bytes);
+            }
+        
+        } else {
+            fprintf (state->ofp, "    ret\n");
+        }
+    
+    }
+
+}
+
+static void emit_preserve_assignment64_regs (enum token_kind op) {
+
+    if (current_function_frame_deferred) {
+    
+        current_function_preserve_assignment64_regs = 1;
+        return;
+    
+    }
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    push ebx\n");
+        
+        if (op == TOK_STAREQ || op == TOK_STAR || op == TOK_SLASHEQ || op == TOK_BSLASH || op == TOK_MODEQ || op == TOK_MOD) {
+        
+            fprintf (state->ofp, "    push esi\n");
+            fprintf (state->ofp, "    push edi\n");
+        
+        }
+    
+    } else {
+    
+        fprintf (state->ofp, "    pushl %%ebx\n");
+        
+        if (op == TOK_STAREQ || op == TOK_STAR || op == TOK_SLASHEQ || op == TOK_BSLASH || op == TOK_MODEQ || op == TOK_MOD) {
+        
+            fprintf (state->ofp, "    pushl %%esi\n");
+            fprintf (state->ofp, "    pushl %%edi\n");
+        
+        }
+    
+    }
+
+}
+
+static void emit_restore_assignment64_regs (enum token_kind op) {
+
+    if (current_function_frame_deferred) {
+        return;
+    }
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (op == TOK_STAREQ || op == TOK_STAR || op == TOK_SLASHEQ || op == TOK_BSLASH || op == TOK_MODEQ || op == TOK_MOD) {
+        
+            fprintf (state->ofp, "    pop edi\n");
+            fprintf (state->ofp, "    pop esi\n");
+        
+        }
+        
+        fprintf (state->ofp, "    pop ebx\n");
+    
+    } else {
+    
+        if (op == TOK_STAREQ || op == TOK_STAR || op == TOK_SLASHEQ || op == TOK_BSLASH || op == TOK_MODEQ || op == TOK_MOD) {
+        
+            fprintf (state->ofp, "    popl %%edi\n");
+            fprintf (state->ofp, "    popl %%esi\n");
+        
+        }
+        
+        fprintf (state->ofp, "    popl %%ebx\n");
+    
+    }
+
+}
+
+static int64_s sizeof_from_current_token (void) {
+
+    int64_s v;
+    int size;
+    
+    zext64 (&v, 0);
+    get_token ();
+    
+    size = parse_sizeof_value ();
+    zext64 (&v, (unsigned long) size);
+    
+    return v;
+
+}
+
+static int64_s const64_from_current_expr (void) {
+
+    enum token_kind kill[6];
+    int64_s v;
+    
+    kill[0] = TOK_SEMI;
+    kill[1] = TOK_COMMA;
+    kill[2] = TOK_RPAREN;
+    kill[3] = TOK_RBRACK;
+    kill[4] = TOK_RBRACE;
+    kill[5] = 0;
+    
+    v = expr_const64 (kill);
+    return v;
+
+}
+
+static int64_s const64_from_current_operand (void) {
+
+    enum token_kind kill[26];
+    
+    if (token_is_sizeof_keyword ()) {
+        return sizeof_from_current_token ();
+    }
+    
+    kill[0] = TOK_PLUS;
+    kill[1] = TOK_MINUS;
+    kill[2] = TOK_STAR;
+    kill[3] = TOK_BSLASH;
+    kill[4] = TOK_MOD;
+    kill[5] = TOK_LSH;
+    kill[6] = TOK_RSH;
+    kill[7] = TOK_AMPER;
+    kill[8] = TOK_PIPE;
+    kill[9] = TOK_CARET;
+    kill[10] = TOK_LESS;
+    kill[11] = TOK_LTEQ;
+    kill[12] = TOK_GREATER;
+    kill[13] = TOK_GTEQ;
+    kill[14] = TOK_EQEQ;
+    kill[15] = TOK_NOTEQ;
+    kill[16] = TOK_LOGAND;
+    kill[17] = TOK_LOGOR;
+    kill[18] = TOK_QMARK;
+    kill[19] = TOK_COLON;
+    kill[20] = TOK_SEMI;
+    kill[21] = TOK_COMMA;
+    kill[22] = TOK_RPAREN;
+    kill[23] = TOK_RBRACK;
+    kill[24] = TOK_RBRACE;
+    kill[25] = 0;
+    
+    return expr_const64 (kill);
+
+}
+
+static int64_s const64_from_current_foldable_expr (void) {
+
+    enum token_kind kill[17];
+    
+    if (token_is_sizeof_keyword ()) {
+        return sizeof_from_current_token ();
+    }
+    
+    kill[0] = TOK_LESS;
+    kill[1] = TOK_LTEQ;
+    kill[2] = TOK_GREATER;
+    kill[3] = TOK_GTEQ;
+    kill[4] = TOK_EQEQ;
+    kill[5] = TOK_NOTEQ;
+    kill[6] = TOK_LOGAND;
+    kill[7] = TOK_LOGOR;
+    kill[8] = TOK_QMARK;
+    kill[9] = TOK_COLON;
+    kill[10] = TOK_SEMI;
+    kill[11] = TOK_COMMA;
+    kill[12] = TOK_RPAREN;
+    kill[13] = TOK_RBRACK;
+    kill[14] = TOK_RBRACE;
+    kill[15] = 0;
+    kill[16] = 0;
+    
+    return expr_const64 (kill);
+
+}
+
+static long const_from_current_expr (void) {
+
+    int64_s v = const64_from_current_expr ();
+    return (long) v.low;
+
+}
+
+static long const_from_current_case_expr (void) {
+
+    enum token_kind kill[7];
+    int64_s v;
+    
+    if (token_is_sizeof_keyword ()) {
+    
+        v = sizeof_from_current_token ();
+        return (long) v.low;
+    
+    }
+    
+    kill[0] = TOK_COLON;
+    kill[1] = TOK_SEMI;
+    kill[2] = TOK_COMMA;
+    kill[3] = TOK_RPAREN;
+    kill[4] = TOK_RBRACK;
+    kill[5] = TOK_RBRACE;
+    kill[6] = 0;
+    
+    v = expr_const64 (kill);
+    return (long) v.low;
+
+}
+
+static int declarator_element_size_from_fields (int base_size, const int *field_sizes, int field_count);
+
+static int declarator_pointed_size_now (void) {
+
+    if (declarator_pointer_depth > 1) {
+        return DATA_PTR;
+    }
+    
+    if (parsed_type_is_aggregate) {
+        return parsed_type_size;
+    }
+    
+    return parsed_type_size & 0x1f;
+
+}
+
+static struct aggregate_tag_entry *hidden_typedef_pointer_entry_now (void) {
+
+    if (declarator_pointer_depth != 0 || declarator_is_pointer ||
+        declarator_has_array || declarator_has_function) {
+        return 0;
+    }
+    
+    if ((parsed_type_size & 0x1f) != (DATA_PTR & 0x1f) ||
+        !parsed_type_tag_name[0]) {
+        return 0;
+    }
+    
+    return find_aggregate_tag (parsed_type_tag_name, 0);
+
+}
+
+static int declarator_effective_pointer_depth_now (void) {
+
+    if (declarator_pointer_depth > 0) {
+        return declarator_pointer_depth;
+    }
+    
+    return hidden_typedef_pointer_entry_now () ? 1 : 0;
+
+}
+
+static int declarator_effective_pointed_size_now (int base_size, const int *field_sizes, int field_count) {
+
+    struct aggregate_tag_entry *entry;
+    
+    if (declarator_pointer_depth > 0 || declarator_is_pointer) {
+        return declarator_pointed_size_now ();
+    }
+    
+    entry = hidden_typedef_pointer_entry_now ();
+    
+    if (entry) {
+        return entry->size;
+    }
+    
+    return declarator_element_size_from_fields (base_size, field_sizes, field_count);
+
+}
+
+static int declarator_element_size_from_fields (int base_size, const int *field_sizes, int field_count) {
+
+    int total = 0;
+    int i;
+    
+    if (field_sizes && field_count > 0) {
+    
+        for (i = 0; i < field_count; i++) {
+            total += field_sizes[i] & 0x1f;
+        }
+        
+        if (total > 0) {
+            return total;
+        }
+    
+    }
+    
+    if (parsed_type_is_aggregate) {
+        return base_size;
+    }
+    
+    return base_size & 0x1f;
+
+}
+
+static int declarator_array_element_size_now (int base_size) {
+
+    int object_size;
+    
+    if (!declarator_has_array) {
+        return 0;
+    }
+    
+    if (declarator_is_pointer) {
+        return DATA_PTR;
+    }
+    
+    /*
+     * For an array object, the element reached by one subscript is the
+     * complete row after the first dimension, not always the scalar base
+     * type.  For example, with:
+     *
+     *     static const char wday_name[7][3];
+     *
+     * wday_name[i] has type char [3] and decays to the address of that
+     * three-byte row when passed to %.3s.  Recording element size as char
+     * made expression code emit a byte load from wday_name + i instead of
+     * the row address wday_name + i * 3.
+     */
+    if (declarator_array_dimensions > 1 && declarator_first_array_count > 0) {
+    
+        object_size = declarator_object_size (base_size);
+        
+        if (object_size > 0) {
+            return object_size / declarator_first_array_count;
+        }
+    
+    }
+    
+    /*
+     * For a one-dimensional array, the size of the element reached by one
+     * subscript is the declared base object size, not the total flattened
+     * initializer field size.  make_declarator_fields() expands objects like
+     *
+     *     char parmbuf[410];
+     *
+     * into 410 byte fields for initialization/copying purposes.  Feeding that
+     * field total back here made parmbuf[i] scale by 410 and store a dword far
+     * beyond the stack object.
+     */
+    if (parsed_type_is_aggregate) {
+        return base_size;
+    }
+    
+    return base_size & 0x1f;
+
+}
+
+static int count_brace_initializer_elements_from_assign_now (void) {
+
+    const char *p;
+    
+    int brace_depth = 0;
+    int paren_depth = 0;
+    int bracket_depth = 0;
+    int count = 0;
+    int saw_element = 0;
+    
+    if (tok.kind != TOK_ASSIGN || !tok.start) {
+        return 0;
+    }
+    
+    p = tok.start;
+    
+    while (*p && *p != '=') {
+        p++;
+    }
+    
+    if (*p != '=') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '{') {
+        return 0;
+    }
+    
+    p++;
+    brace_depth = 1;
+    
+    while (*p && brace_depth > 0) {
+    
+        if (*p == '\'' || *p == '"') {
+        
+            int quote = *p++;
+            saw_element = 1;
+            
+            while (*p && *p != quote) {
+            
+                if (*p == '\\' && p[1]) {
+                    p += 2;
+                } else {
+                    p++;
+                }
+            
+            }
+            
+            if (*p == quote) {
+                p++;
+            }
+            
+            continue;
+        
+        }
+        
+        if (*p == '{') {
+        
+            brace_depth++;
+            saw_element = 1;
+        
+        } else if (*p == '}') {
+        
+            if (brace_depth == 1 && paren_depth == 0 && bracket_depth == 0) {
+                break;
+            }
+            
+            brace_depth--;
+        
+        } else if (*p == '(') {
+        
+            paren_depth++;
+            saw_element = 1;
+        
+        } else if (*p == ')') {
+        
+            if (paren_depth > 0) {
+                paren_depth--;
+            }
+        
+        } else if (*p == '[') {
+        
+            bracket_depth++;
+            saw_element = 1;
+        
+        } else if (*p == ']') {
+        
+            if (bracket_depth > 0) {
+                bracket_depth--;
+            }
+        
+        } else if (*p == ',' && brace_depth == 1 && paren_depth == 0 && bracket_depth == 0) {
+        
+            if (saw_element) {
+            
+                count++;
+                saw_element = 0;
+            
+            }
+        
+        } else if (!(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')) {
+            saw_element = 1;
+        }
+        
+        p++;
+    
+    }
+    
+    if (saw_element) {
+        count++;
+    }
+    
+    return count;
+
+}
+
+static void make_declarator_fields (int *out_fields, int *out_count, const int *base_fields, int base_count, int base_size, int base_is_aggregate) {
+
+    int i;
+    long r;
+    
+    *out_count = 0;
+    
+    if (declarator_is_pointer) {
+    
+        out_fields[(*out_count)++] = DATA_PTR;
+        return;
+    
+    }
+    
+    if (declarator_has_array) {
+    
+        if (base_is_aggregate && base_count > 0) {
+        
+            for (r = 0; r < declarator_array_count && *out_count < MAX_AGG_FIELDS; r++) {
+            
+                for (i = 0; i < base_count && *out_count < MAX_AGG_FIELDS; i++) {
+                    out_fields[(*out_count)++] = base_fields[i];
+                }
+            
+            }
+        
+        } else {
+        
+            for (r = 0; r < declarator_array_count && *out_count < MAX_AGG_FIELDS; r++) {
+                out_fields[(*out_count)++] = (base_size & 0x1f);
+            }
+        
+        }
+        
+        return;
+
+    }
+    
+    for (i = 0; i < base_count && *out_count < MAX_AGG_FIELDS; i++) {
+        out_fields[(*out_count)++] = base_fields[i];
+    }
+    
+    if (*out_count == 0) {
+        out_fields[(*out_count)++] = (base_size & 0x1f);
+    }
+
+}
+
+static void parse_statement (void);
+
+static void emit_load_assignment_rhs_expression_to_pair (const char *lo, const char *hi, int is_unsigned);
+static void emit_load_assignment_rhs_expression_to_reg (const char *reg);
+
+static void emit_incdec_symbol_now (struct local_symbol *sym, const char *name, enum token_kind op, int line, const char *start, const char *caret);
+
+static int current_expression_mentions_64bit_symbol_now (void);
+static int rhs_current_operand_is_unsigned_now (void);
+
+static int64_s parse_floating_const_expr_bits_now (int size);
+
+static int initializer_contains_runtime_call_now (void) {
+
+    const char *p = tok.start;
+    
+    int paren_depth = 0;
+    int bracket_depth = 0;
+    int brace_depth = 0;
+    
+    while (*p) {
+    
+        if (paren_depth == 0 && bracket_depth == 0 && brace_depth == 0 && (*p == ';' || *p == ',' || *p == '}')) {
+            break;
+        }
+        
+        if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_') {
+        
+            const char *q = p + 1;
+            
+            while ((*q >= 'A' && *q <= 'Z') || (*q >= 'a' && *q <= 'z') || (*q >= '0' && *q <= '9') || *q == '_') {
+                q++;
+            }
+            
+            while (*q == ' ' || *q == '\t' || *q == '\r' || *q == '\n') {
+                q++;
+            }
+            
+            if (*q == '(') {
+                return 1;
+            }
+            
+            p = q;
+            continue;
+        
+        }
+        
+        if (*p == '\'' || *p == '"') {
+        
+            int quote = *p++;
+            
+            while (*p && *p != quote) {
+            
+                if (*p == '\\' && p[1]) {
+                    p += 2;
+                } else {
+                    p++;
+                }
+            
+            }
+            
+            if (*p == quote) {
+                p++;
+            }
+            
+            continue;
+        
+        }
+        
+        if (*p == '(') {
+            paren_depth++;
+        } else if (*p == ')') {
+        
+            if (paren_depth > 0) {
+                paren_depth--;
+            }
+        
+        } else if (*p == '[') {
+            bracket_depth++;
+        } else if (*p == ']') {
+        
+            if (bracket_depth > 0) {
+                bracket_depth--;
+            }
+        
+        } else if (*p == '{') {
+            brace_depth++;
+        } else if (*p == '}') {
+        
+            if (brace_depth > 0) {
+                brace_depth--;
+            }
+        
+        }
+        
+        p++;
+    
+    }
+    
+    return 0;
+
+}
+
+static int auto_init_ident_char_now (int ch) {
+    return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '_';
+}
+
+static int auto_init_expr_continues_after_ident_now (void) {
+
+    const char *p;
+    const char *q;
+    
+    if (tok.kind != TOK_IDENT) {
+        return 1;
+    }
+    
+    p = tok.start;
+    q = p;
+    
+    while (auto_init_ident_char_now ((unsigned char) *q)) {
+        q++;
+    }
+    
+    while (*q == ' ' || *q == '\t' || *q == '\r' || *q == '\n') {
+        q++;
+    }
+    
+    return !(*q == ';' || *q == ',' || *q == '}');
+
+}
+
+static int auto_initializer_needs_runtime_now (void) {
+
+    const char *p = tok.start;
+    int paren_depth = 0;
+    int bracket_depth = 0;
+    int brace_depth = 0;
+    
+    if (initializer_contains_runtime_call_now () || tok.kind == TOK_LPAREN) {
+        return 1;
+    }
+    
+    if (tok.kind == TOK_IDENT) {
+        return auto_init_expr_continues_after_ident_now ();
+    }
+    
+    if (tok.kind == TOK_AMPER) {
+    
+        p++;
+        
+        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+            p++;
+        }
+        
+        if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+            return 1;
+        }
+        
+        while (auto_init_ident_char_now ((unsigned char) *p)) {
+            p++;
+        }
+        
+        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+            p++;
+        }
+        
+        return !(*p == ';' || *p == ',' || *p == '}');
+    
+    }
+    
+    p = tok.start;
+    
+    while (*p) {
+    
+        if (paren_depth == 0 && bracket_depth == 0 && brace_depth == 0 && (*p == ';' || *p == ',' || *p == '}')) {
+            break;
+        }
+        
+        if (*p == '[' || *p == ']' || *p == '*') {
+            return 1;
+        }
+        
+        if (*p == '(') {
+            paren_depth++;
+        } else if (*p == ')') {
+            if (paren_depth > 0) paren_depth--;
+        } else if (*p == '[') {
+            bracket_depth++;
+        } else if (*p == ']') {
+            if (bracket_depth > 0) bracket_depth--;
+        } else if (*p == '{') {
+            brace_depth++;
+        } else if (*p == '}') {
+            if (brace_depth > 0) brace_depth--;
+        }
+        
+        if (((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_') && p[0] != 'L') {
+            return 1;
+        }
+        
+        p++;
+    
+    }
+    
+    return 0;
+
+}
+
+static void parse_local_initializer_value (struct local_init *init, int object_size, int object_is_floating) {
+
+    init->kind = LOCAL_INIT_CONST;
+    init->symbol = 0;
+    init->value.low = 0;
+    init->value.high = 0;
+    init->source_offset = 0;
+    init->source_size = 0;
+    
+    if (tok.kind == TOK_LBRACE) {
+    
+        get_token ();
+        parse_local_initializer_value (init, object_size, object_is_floating);
+        
+        while (_accept (TOK_COMMA)) {
+            skip_initializer ();
+        }
+        
+        expect (TOK_RBRACE, "}");
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_AMPER) {
+    
+        get_token ();
+        
+        if (tok.kind != TOK_IDENT) {
+        
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after '&'");
+            return;
+        
+        }
+        
+        init->kind = LOCAL_INIT_ADDRESS;
+        init->symbol = xstrdup (tok.ident);
+        
+        get_token ();
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_IDENT) {
+    
+        struct local_symbol *src = find_local_symbol (tok.ident);
+        
+        if (src) {
+        
+            if (src->is_static && src->static_label) {
+            
+                init->kind = LOCAL_INIT_GLOBAL;
+                init->symbol = xstrdup (src->static_label);
+            
+            } else {
+            
+                init->kind = LOCAL_INIT_STACK;
+                
+                init->source_offset = src->offset;
+                init->source_size = src->size;
+            
+            }
+            
+            get_token ();
+            return;
+        
+        }
+        
+        if (find_global_symbol (tok.ident) >= 0) {
+        
+            init->kind = LOCAL_INIT_GLOBAL;
+            init->symbol = xstrdup (tok.ident);
+            
+            get_token ();
+            return;
+        
+        }
+    
+    }
+    
+    if (object_is_floating) {
+        init->value = parse_floating_const_expr_bits_now (object_size);
+    } else {
+        init->value = const64_from_current_expr ();
+    }
+
+}
+
+static void parse_local_string_field_initializer (struct local_init *inits, int *init_count, int max_inits, long base_offset, int field_size) {
+
+    int64_s values[MAX_STRING_INIT_BYTES];
+    int value_count = 0, i;
+    
+    parse_string_initializer_values (values, MAX_STRING_INIT_BYTES, &value_count);
+    
+    for (i = 0; i < field_size; i++) {
+    
+        if (*init_count >= max_inits) {
+            continue;
+        }
+        
+        inits[*init_count].offset = base_offset + i;
+        inits[*init_count].size = 1;
+        inits[*init_count].kind = LOCAL_INIT_CONST;
+        inits[*init_count].symbol = 0;
+        inits[*init_count].value.low = (i < value_count) ? (values[i].low & 0xffUL) : 0;
+        inits[*init_count].value.high = 0;
+        inits[*init_count].source_offset = 0;
+        inits[*init_count].source_size = 0;
+        
+        (*init_count)++;
+    
+    }
+
+}
+
+static void parse_local_aggregate_initializer_values (struct local_init *inits, int *init_count, int max_inits, long base_offset, const int *fields, int field_count) {
+
+    int field_index = 0;
+    long field_offset = 0;
+    int braced = 0;
+    
+    if (tok.kind == TOK_LBRACE) {
+        braced = 1;
+        get_token ();
+    }
+    
+    while (field_index < field_count) {
+    
+        int field_size = fields[field_index];
+        
+        if (field_size < 0) {
+        
+            field_offset += -field_size;
+            
+            field_index++;
+            continue;
+        
+        }
+        
+        if (braced && tok.kind == TOK_RBRACE) {
+        
+            if (*init_count < max_inits) {
+            
+                inits[*init_count].offset = base_offset + field_offset;
+                inits[*init_count].size = field_size;
+                inits[*init_count].kind = LOCAL_INIT_CONST;
+                inits[*init_count].symbol = 0;
+                inits[*init_count].value.low = 0;
+                inits[*init_count].value.high = 0;
+                inits[*init_count].source_offset = 0;
+                inits[*init_count].source_size = 0;
+                
+                (*init_count)++;
+            
+            }
+            
+            field_offset += field_size;
+            field_index++;
+            
+            continue;
+        
+        }
+        
+        if (*init_count < max_inits) {
+        
+            if (is_string_token ()) {
+                parse_local_string_field_initializer (inits, init_count, max_inits, base_offset + field_offset, field_size);
+            } else {
+            
+                inits[*init_count].offset = base_offset + field_offset;
+                inits[*init_count].size = field_size;
+                
+                parse_local_initializer_value (&inits[*init_count], 0, 0);
+                (*init_count)++;
+            
+            }
+        
+        } else {
+            skip_initializer ();
+        }
+        
+        field_offset += field_size;
+        field_index++;
+        
+        if (braced) {
+        
+            if (!_accept (TOK_COMMA)) {
+                break;
+            }
+            
+            if (tok.kind == TOK_RBRACE) {
+                break;
+            }
+        
+        } else {
+            break;
+        }
+    
+    }
+    
+    if (braced) {
+    
+        while (field_index < field_count) {
+        
+            int field_size = fields[field_index];
+            
+            if (field_size < 0) {
+            
+                field_offset += -field_size;
+                
+                field_index++;
+                continue;
+            
+            }
+            
+            if (*init_count < max_inits) {
+            
+                inits[*init_count].offset = base_offset + field_offset;
+                inits[*init_count].size = field_size;
+                inits[*init_count].kind = LOCAL_INIT_CONST;
+                inits[*init_count].symbol = 0;
+                inits[*init_count].value.low = 0;
+                inits[*init_count].value.high = 0;
+                inits[*init_count].source_offset = 0;
+                inits[*init_count].source_size = 0;
+                
+                (*init_count)++;
+            
+            }
+            
+            field_offset += field_size;
+            field_index++;
+        
+        }
+        
+        while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
+        
+            skip_initializer ();
+            
+            if (!_accept (TOK_COMMA)) {
+                break;
+            }
+        }
+        
+        expect (TOK_RBRACE, "}");
+    
+    }
+
+}
+
+static void make_local_static_label (char *buf, size_t bufsz, const char *name) {
+
+    if (!buf || bufsz == 0) {
+        return;
+    }
+    
+    if (!name) {
+        name = "anon";
+    }
+    
+    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+        sprintf (buf, "LC%d_%s", local_static_id++, name);
+    } else {
+        sprintf (buf, ".LC%d_%s", local_static_id++, name);
+    }
+
+}
+
+static void emit_global_object (const char *name, int size, int is_array, long array_count, const int *field_sizes, int field_count, const int64_s *values, char **symbols, int value_count, int is_aggregate, int is_static);
+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_block_static_object (const char *label, int size, int is_array, long array_count, const int *field_sizes, int field_count, const int64_s *values, char **symbols, int value_count, int is_aggregate) {
+    
+    emit_global_object (label, size, is_array, array_count, field_sizes, field_count, values, symbols, value_count, is_aggregate, 1);
+    
+    /**
+     * We may have switched to .data/.data? to emit the static object while
+     * parsing a function body.  The following statements still belong in
+     * .code/.text.
+     */
+    switch_section (SECTION_TEXT);
+
+}
+
+static char *emit_string_literal_global (void);
+
+static void ensure_block_stack_allocated (long block_stack_start, long *block_stack_bytes, int *block_stack_emitted) {
+
+    long needed_stack_bytes = align_up_long (current_local_stack_size - block_stack_start, 4);
+    
+    /*
+     * The parser can emit code while it is still inside a declaration list
+     * containing comma-separated declarators and runtime initializers.  Keep
+     * one word of conservative headroom once a block frame exists, so a
+     * subsequently-discovered automatic slot in the same declaration phase is
+     * not allowed to overlap the caller frame before the next adjustment is
+     * emitted.  This fixes cases like:
+     *
+     *     cpp_mffc *old = reader->mffc;
+     *     struct if_stack *ifs, *next_ifs;
+     *     ... next_ifs = ifs->next;
+     *
+     * where generated code used -12(%ebp) after reserving only 8 bytes.
+     */
+    if (needed_stack_bytes > 0) {
+        needed_stack_bytes = align_up_long (needed_stack_bytes + 4, 4);
+    }
+    
+    if (!block_stack_bytes || !block_stack_emitted) {
+        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;
+        emit_stack_adjust (*block_stack_bytes, 1);
+        
+        if (current_parse_block_depth > 1) {
+            current_block_cleanup_bytes += *block_stack_bytes;
+        }
+        
+        *block_stack_emitted = (*block_stack_bytes > 0);
+    
+    } 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 (current_parse_block_depth > 1) {
+            current_block_cleanup_bytes += extra_stack_bytes;
+        }
+        
+        *block_stack_bytes = needed_stack_bytes;
+    
+    }
+
+}
+
+static void parse_global_initializer_values (int64_s *values, char **symbols, int max_values, int *count);
+
+static int aggregate_initializer_value_field_count (const int *field_sizes, int field_count);
+static void parse_global_initializer_values_padded_elements (int64_s *values, char **symbols, int max_values, int *count, int element_field_count);
+
+static void parse_char_array_initializer_values (int64_s *values, int max_values, int *count, long row_width);
+static int64_s parse_floating_const_expr_bits_now (int size);
+
+static void emit_store_pair_to_local64 (long offset, const char *lo, const char *hi);
+static void emit_store_reg_to_local (long offset, int size, const char *reg);
+
+static void emit_load_local_address_to_reg_now (const char *reg, long offset);
+static int emit_aggregate_copy_from_current_rhs_to_addr_reg_now (const char *addr_reg, int offset, int size);
+
+static void parse_block (void) {
+
+    int declaration_phase = 1, is_function_body = (current_parse_block_depth == 0);
+    
+    int block_local_start = local_symbol_count;
+    int block_stack_emitted = 0;
+    
+    long block_stack_start = current_local_stack_size;
+    long block_stack_bytes = 0;
+    
+    struct local_init inits[MAX_LOCAL_INITS];
+    int block_scope_start, init_count = 0;
+    
+    block_scope_start = is_function_body ? 0 : block_local_start;
+    current_parse_block_depth++;;
+    
+    expect (TOK_LBRACE, "{");
+    
+    while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
+    
+        if (is_type_start (tok.kind)) {
+        
+            if (!declaration_phase) {
+            
+                if (state->std == 90) {
+                    report_line_at (get_filename (), get_line_number (), (state->pedantic ? REPORT_ERROR : REPORT_WARNING), tok.start, tok.caret, "ISO C90 forbids mixed declarations and code");
+                }
+            
+            }
+            
+            parse_type_spec ();
+            
+            for (;;) {
+            
+                long object_offset = 0;
+                
+                int object_init_size = 0;
+                int object_is_auto = 0;
+                
+                char *name = 0;
+                unsigned long name_line;
+                
+                const char *name_start, *name_caret;
+                int object_align, object_size = 0;
+                
+                int object_fields[MAX_AGG_FIELDS];
+                int object_field_count = 0;
+                int init_value_count = 0;
+                
+                int64_s init_values[MAX_AGG_FIELDS];
+                int i;
+                
+                char *init_symbols[MAX_AGG_FIELDS];
+                char static_label[128];
+                
+                int declaration_dllimport = parsed_dllimport;
+                
+                for (i = 0; i < MAX_AGG_FIELDS; i++) {
+                    init_symbols[i] = 0;
+                }
+                
+                parse_declarator (&name);
+                
+                declaration_dllimport = declaration_dllimport || parsed_dllimport || declarator_dllimport;
+                apply_typedef_array_to_declarator ();
+                
+                if (declarator_has_array && declarator_array_unsized && tok.kind == TOK_ASSIGN) {
+                
+                    int inferred_count = count_brace_initializer_elements_from_assign_now ();
+                    
+                    if (inferred_count > 0) {
+                        declarator_array_count = inferred_count;
+                    }
+                
+                }
+                
+                name_line = last_declarator_name_line;
+                name_start = last_declarator_name_start;
+                name_caret = last_declarator_name_caret;
+                
+                make_declarator_fields (object_fields, &object_field_count, parsed_field_sizes, parsed_field_count, parsed_type_size, parsed_type_is_aggregate);
+                
+                if (parsed_type_is_void && !declarator_is_pointer && !declarator_has_function) {
+                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "variable '%s' declared void", name ? name : "");
+                }
+                
+                if (declarator_is_pointer) {
+                
+                    object_field_count = 1;
+                    object_fields[0] = DATA_PTR;
+                
+                }
+                
+                if (parsed_storage_class == STORAGE_TYPEDEF && name) {
+                
+                    save_typedef_name (name, declarator_object_size (parsed_type_size),
+                        (declarator_is_pointer ? 0 : parsed_type_is_unsigned),
+                            (declarator_is_pointer ? 0 : parsed_type_is_void),
+                                (!declarator_is_pointer && (parsed_type_is_aggregate || declarator_has_array)),
+                                    (!declarator_is_pointer && declarator_has_array),
+                                        declarator_array_count, parsed_type_size,
+                                            (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention,
+                                                object_fields, object_field_count);
+                
+                } else if (name && (parsed_storage_class == STORAGE_EXTERN || declaration_dllimport)) {
+                
+                    add_global_symbol (name, (declarator_has_function && !declarator_function_is_pointer) ? GLOBAL_SYMBOL_FUNCTION : GLOBAL_SYMBOL_OBJECT, 1, name_start, name_caret, name_line);
+                    
+                    if (find_global_symbol (name) >= 0) {
+                    
+                        set_global_symbol_size (name, (declarator_has_function && !declarator_is_pointer && !declarator_function_is_pointer) ? parsed_type_size : ((declarator_has_function || declarator_is_pointer) ? DATA_PTR : declarator_object_size (parsed_type_size)));
+                        set_global_symbol_pointer_info (name, declarator_effective_pointer_depth_now (),
+                            declarator_effective_pointed_size_now (parsed_type_size, object_fields, object_field_count));
+                        set_global_symbol_tag_name (name, parsed_type_tag_name);
+                        set_global_symbol_unsigned (name, (declarator_is_pointer || declarator_has_function) ? 0 : parsed_type_is_unsigned);
+                        set_global_symbol_floating (name, (declarator_is_pointer || (declarator_has_function && declarator_function_is_pointer)) ? 0 : parsed_type_is_floating);
+                        set_global_symbol_returns_void (name, declarator_has_function && parsed_type_is_void && !declarator_is_pointer && !declarator_function_is_pointer);
+                        
+                        if (declarator_has_function) {
+                        
+                            set_global_symbol_param_count (name, declarator_function_param_count, declarator_function_has_prototype || declarator_function_param_count > 0, declarator_function_is_variadic);
+                            
+                            set_global_symbol_calling_convention (name, (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention);
+                            set_global_symbol_dllimport (name, declaration_dllimport);
+                            
+                            copy_pending_params_to_global_symbol (name);
+                        
+                        }
+                        
+                        set_global_symbol_dllimport (name, declaration_dllimport);
+                        switch_section (SECTION_TEXT);
+                    
+                    }
+                
+                } else if (name && parsed_storage_class != STORAGE_STATIC) {
+                
+                    object_size = declarator_object_size (parsed_type_size);
+                    object_align = declarator_is_pointer ? type_alignment (DATA_PTR) : type_alignment (parsed_type_is_aggregate ? DATA_PTR : parsed_type_size);
+                    
+                    object_offset = add_local_symbol (name, object_size, object_align,
+                        (declarator_is_pointer ? 0 : parsed_type_is_unsigned),
+                            block_scope_start, name_line, name_start, name_caret);
+                    
+                    /*
+                     * Reserve stack space as soon as an automatic local receives
+                     * an EBP-relative slot.  Some blocks start with declarations
+                     * and then immediately execute statements that write those
+                     * locals, for example:
+                     *
+                     *     if (...) { location_t loc; unsigned int i; loc.file = ...; }
+                     *
+                     * Waiting until the declaration phase is exited proved too
+                     * fragile after runtime initializer handling was added: code
+                     * could use -4/-8/-12(%ebp) before any sub esp had been
+                     * emitted.  Keep block_stack_bytes in sync here so the later
+                     * declaration-phase transition is a no-op unless a later
+                     * unsized aggregate expands the frame.
+                     */
+                    ensure_block_stack_allocated (block_stack_start, &block_stack_bytes, &block_stack_emitted);
+                    
+                    set_local_symbol_floating (name, declarator_is_pointer ? 0 : parsed_type_is_floating);
+                    set_local_symbol_array (name, declarator_has_array);
+                    set_local_symbol_array_dimensions (name, declarator_has_array ? declarator_array_dimensions : 0);
+                    set_local_symbol_array_element_size (name, declarator_array_element_size_now (parsed_type_size));
+                    set_local_symbol_pointer_info (name, declarator_effective_pointer_depth_now (),
+                        declarator_effective_pointed_size_now (parsed_type_size, object_fields, object_field_count));
+                    
+                    if (!declarator_is_pointer && parsed_type_tag_name[0]) {
+                    
+                        struct local_symbol *lsym = find_local_symbol (name);
+                        
+                        if (lsym) {
+                            lsym->tag_name = xstrdup (parsed_type_tag_name);
+                        }
+                    
+                    }
+                    
+                    object_init_size = declarator_is_pointer ? DATA_PTR : (parsed_type_size & 0x1f);
+                    object_is_auto = 1;
+                    
+                    /*
+                     * If an earlier automatic declaration in this block had a
+                     * runtime initializer, stack space has already been emitted.
+                     * Any later automatic declaration extends current_local_stack_size,
+                     * and its initializer may immediately store to the new slot.
+                     * Reserve the extra bytes before parsing/emitting that initializer;
+                     * otherwise code can write to -8(%ebp), -12(%ebp), etc. after
+                     * only the first 4 bytes were allocated.
+                     */
+                    if (block_stack_emitted) {
+                        ensure_block_stack_allocated (block_stack_start, &block_stack_bytes, &block_stack_emitted);
+                    }
+                
+                }
+                
+                if (_accept (TOK_ASSIGN)) {
+                
+                    /*
+                     * Reserve the stack slot before parsing an automatic initializer.
+                     *
+                     * Some initializer forms which are not compile-time constants
+                     * can still reach code emission through parse_local_initializer_value().
+                     * If the stack adjustment is delayed until the first following
+                     * statement, those stores use offsets that have not yet been
+                     * reserved.  In create_definition(), this affected:
+                     *
+                     *     cpp_token *saved_cur_token = reader->cur_token;
+                     *
+                     * The generated code stored to -64(%ebp) while only -60 bytes
+                     * had been allocated, so the following call overwrote the saved
+                     * value and reader->cur_token was restored with garbage.
+                     */
+                    if (object_is_auto) {
+                        ensure_block_stack_allocated (block_stack_start, &block_stack_bytes, &block_stack_emitted);
+                    }
+                    
+                    if ((parsed_storage_class == STORAGE_EXTERN || parsed_dllimport)) {
+                    
+                        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "extern declaration '%s' is initialized", name ? name : "");
+                        skip_initializer ();
+                    
+                    } else if (parsed_storage_class == STORAGE_STATIC && name) {
+                    
+                        if (declarator_has_array && !declarator_is_pointer && (parsed_type_size & 0x1f) == (DATA_CHAR & 0x1f) && (is_string_token () || tok.kind == TOK_LBRACE)) {
+                        
+                            if (is_string_token ()) {
+                                parse_string_initializer_values (init_values, MAX_AGG_FIELDS, &init_value_count);
+                            } else {
+                                parse_char_array_initializer_values (init_values, MAX_AGG_FIELDS, &init_value_count, declarator_last_array_count);
+                            }
+                            
+                            if (declarator_array_unsized) {
+                                declarator_array_count = init_value_count;
+                            }
+                        
+                        } else if (declarator_is_pointer && is_string_token ()) {
+                        
+                            init_values[0].low = 0;
+                            init_values[0].high = 0;
+                            
+                            init_symbols[0] = emit_string_literal_global ();
+                            init_value_count = 1;
+                        
+                        } else if (!declarator_is_pointer && parsed_type_is_floating) {
+                        
+                            init_values[0] = parse_floating_const_expr_bits_now (parsed_type_size);
+                            init_symbols[0] = 0;
+                            init_value_count = 1;
+                        
+                        } else {
+                        
+                            {
+                            
+                                int saved_accept_symbol_addresses = global_initializer_accept_symbol_addresses;
+                                global_initializer_accept_symbol_addresses = declarator_is_pointer || parsed_type_is_aggregate || declarator_has_array;
+                                
+                                if (declarator_has_array && !declarator_is_pointer && parsed_type_is_aggregate && parsed_field_count > 0 && tok.kind == TOK_LBRACE) {
+                                    parse_global_initializer_values_padded_elements (init_values, init_symbols, MAX_AGG_FIELDS, &init_value_count, aggregate_initializer_value_field_count (parsed_field_sizes, parsed_field_count));
+                                } else {
+                                    parse_global_initializer_values (init_values, init_symbols, MAX_AGG_FIELDS, &init_value_count);
+                                }
+                                
+                                global_initializer_accept_symbol_addresses = saved_accept_symbol_addresses;
+                            
+                            }
+                            
+                            if (declarator_has_array && declarator_array_unsized) {
+                            
+                                if (parsed_type_is_aggregate && object_field_count > 0) {
+                                    declarator_array_count = (init_value_count + object_field_count - 1) / object_field_count;
+                                } else {
+                                    declarator_array_count = init_value_count;
+                                }
+                            
+                            }
+                        
+                        }
+                    
+                    } else if (object_is_auto && declarator_has_array && declarator_is_pointer && tok.kind == TOK_LBRACE) {
+                    
+                        int elem_index = 0;
+                        int elem_size = DATA_PTR;
+                        int first_init_index = init_count;
+                        
+                        get_token ();
+                        
+                        while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
+                        
+                            if (init_count < MAX_LOCAL_INITS) {
+                            
+                                inits[init_count].offset = object_offset + (elem_index * elem_size);
+                                inits[init_count].size = elem_size;
+                                
+                                if (is_string_token ()) {
+                                
+                                    inits[init_count].kind = LOCAL_INIT_ADDRESS;
+                                    inits[init_count].symbol = emit_string_literal_global ();
+                                    inits[init_count].value.low = 0;
+                                    inits[init_count].value.high = 0;
+                                    inits[init_count].source_offset = 0;
+                                    inits[init_count].source_size = 0;
+                                    
+                                    switch_section (SECTION_TEXT);
+                                
+                                } else {
+                                    parse_local_initializer_value (&inits[init_count], elem_size, 0);
+                                }
+                                
+                                init_count++;
+                            
+                            } else {
+                                skip_initializer ();
+                            }
+                            
+                            elem_index++;
+                            
+                            if (!_accept (TOK_COMMA)) {
+                                break;
+                            }
+                            
+                            if (tok.kind == TOK_RBRACE) {
+                                break;
+                            }
+                        
+                        }
+                        
+                        if (declarator_array_unsized && elem_index > 0 && (elem_index * elem_size) > object_size) {
+                        
+                            long old_offset = object_offset;
+                            long new_offset;
+                            long delta;
+                            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;
+                            object_size = elem_index * elem_size;
+                            
+                            if (local_symbol_count > 0 && name && local_symbols[local_symbol_count - 1].name
+                                && strcmp (local_symbols[local_symbol_count - 1].name, name) == 0) {
+                            
+                                local_symbols[local_symbol_count - 1].offset = object_offset;
+                                local_symbols[local_symbol_count - 1].size = object_size;
+                            
+                            }
+                            
+                            for (adj_i = first_init_index; adj_i < init_count; adj_i++) {
+                                inits[adj_i].offset += delta;
+                            }
+                        
+                        }
+                        
+                        expect (TOK_RBRACE, "}");
+                    
+                    } else if (object_is_auto && declarator_has_array && !declarator_is_pointer && (parsed_type_size & 0x1f) == (DATA_CHAR & 0x1f) && is_string_token ()) {
+                    
+                        int first_init_index = init_count;
+                        int value_count = 0;
+                        
+                        int64_s values[MAX_STRING_INIT_BYTES];
+                        int i;
+                        
+                        parse_string_initializer_values (values, MAX_STRING_INIT_BYTES, &value_count);
+                        
+                        if (declarator_array_unsized && value_count > 0 && value_count > object_size) {
+                        
+                            long old_offset = object_offset;
+                            long new_offset;
+                            long delta;
+                            
+                            int adj_i;
+                            current_local_stack_size += value_count - 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;
+                            declarator_array_count = value_count;
+                            
+                            if (local_symbol_count > 0 && name && local_symbols[local_symbol_count - 1].name && strcmp (local_symbols[local_symbol_count - 1].name, name) == 0) {
+                            
+                                local_symbols[local_symbol_count - 1].offset = object_offset;
+                                local_symbols[local_symbol_count - 1].size = object_size;
+                            
+                            }
+                            
+                            for (adj_i = first_init_index; adj_i < init_count; adj_i++) {
+                                inits[adj_i].offset += delta;
+                            }
+                        
+                        }
+                        
+                        for (i = 0; i < object_size; i++) {
+                        
+                            if (init_count >= MAX_LOCAL_INITS) {
+                                continue;
+                            }
+                            
+                            inits[init_count].offset = object_offset + i;
+                            inits[init_count].size = 1;
+                            inits[init_count].kind = LOCAL_INIT_CONST;
+                            inits[init_count].symbol = 0;
+                            inits[init_count].value.low = (i < value_count) ? (values[i].low & 0xffUL) : 0;
+                            inits[init_count].value.high = 0;
+                            inits[init_count].source_offset = 0;
+                            inits[init_count].source_size = 0;
+                            
+                            init_count++;
+                        
+                        }
+                    
+                    } else if (object_is_auto && !declarator_is_pointer && (parsed_type_is_aggregate || declarator_has_array) && tok.kind == TOK_LBRACE) {
+                        parse_local_aggregate_initializer_values (inits, &init_count, MAX_LOCAL_INITS, object_offset, object_fields, object_field_count);
+                    } else if (object_is_auto && auto_initializer_needs_runtime_now ()) {
+                    
+                        long needed_stack_bytes = align_up_long (current_local_stack_size - block_stack_start, 4);
+                        
+                        if (!block_stack_emitted) {
+                        
+                            block_stack_bytes = needed_stack_bytes;
+                            emit_stack_adjust (block_stack_bytes, 1);
+                            
+                            if (!is_function_body) {
+                                current_block_cleanup_bytes += block_stack_bytes;
+                            }
+                            
+                            block_stack_emitted = (block_stack_bytes > 0);
+                        
+                        } 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) {
+                                current_block_cleanup_bytes += extra_stack_bytes;
+                            }
+                            
+                            block_stack_bytes = needed_stack_bytes;
+                        
+                        }
+                        
+                        emit_local_initializers (inits, init_count);
+                        init_count = 0;
+                        
+                        if (!declarator_is_pointer && (parsed_type_is_aggregate || declarator_has_array)) {
+                        
+                            emit_load_local_address_to_reg_now ("edx", object_offset);
+                            
+                            if (!emit_aggregate_copy_from_current_rhs_to_addr_reg_now ("edx", 0, object_size)) {
+                            
+                                if (tok.kind == TOK_IDENT && token_identifier_is_function_call_rhs_now () &&
+                                    get_global_symbol_kind (tok.ident) == GLOBAL_SYMBOL_FUNCTION &&
+                                    get_global_symbol_size (tok.ident) > (DATA_LLONG & 0x1f)) {
+                                
+                                    pending_struct_return_lhs = find_local_symbol (name);
+                                    pending_struct_return_global_name = 0;
+                                    
+                                    emit_load_assignment_rhs_expression_to_reg ("eax");
+                                
+                                } else if (object_init_size == (DATA_LLONG & 0x1f) && !parsed_type_is_floating && !declarator_has_array) {
+                                
+                                    emit_load_assignment_rhs_expression_to_pair ("eax", "edx", parsed_type_is_unsigned);
+                                    emit_store_pair_to_local64 (object_offset, "eax", "edx");
+                                
+                                } else {
+                                
+                                    emit_load_assignment_rhs_expression_to_reg ("eax");
+                                    emit_store_reg_to_local (object_offset, object_init_size, "eax");
+                                
+                                }
+                            
+                            }
+                        
+                        } else if (!declarator_is_pointer && parsed_type_is_floating) {
+                        
+                            emit_load_floating_rhs_expression_now (object_init_size);
+                            emit_store_floating_to_local_now (object_offset, object_init_size);
+                        
+                        } else if (object_init_size == (DATA_LLONG & 0x1f) && !parsed_type_is_floating && !declarator_is_pointer) {
+                        
+                            emit_load_assignment_rhs_expression_to_pair ("eax", "edx", parsed_type_is_unsigned);
+                            emit_store_pair_to_local64 (object_offset, "eax", "edx");
+                        
+                        } else {
+                        
+                            emit_load_assignment_rhs_expression_to_reg ("eax");
+                            emit_store_reg_to_local (object_offset, object_init_size, "eax");
+                        
+                        }
+                    
+                    } else if (object_is_auto && init_count < MAX_LOCAL_INITS) {
+                    
+                        inits[init_count].offset = object_offset;
+                        inits[init_count].size = object_init_size;
+                        
+                        if (declarator_is_pointer && is_string_token ()) {
+                        
+                            inits[init_count].kind = LOCAL_INIT_ADDRESS;
+                            inits[init_count].symbol = emit_string_literal_global ();
+                            inits[init_count].value.low = 0;
+                            inits[init_count].value.high = 0;
+                            inits[init_count].source_offset = 0;
+                            inits[init_count].source_size = 0;
+                            
+                            switch_section (SECTION_TEXT);
+                        
+                        } else {
+                            parse_local_initializer_value (&inits[init_count], object_init_size, (!declarator_is_pointer && parsed_type_is_floating));
+                        }
+                        
+                        init_count++;
+                    
+                    } else {
+                        skip_initializer ();
+                    }
+                
+                }
+                
+                if (name && parsed_storage_class == STORAGE_STATIC) {
+                
+                    make_local_static_label (static_label, sizeof (static_label), name);
+                    
+                    if (add_global_symbol (static_label, GLOBAL_SYMBOL_OBJECT, 0, name_start, name_caret, name_line)) {
+                    
+                        set_global_symbol_size (static_label, declarator_is_pointer ? DATA_PTR : declarator_object_size (parsed_type_size));
+                        set_global_symbol_pointer_info (static_label, declarator_pointer_depth,
+                            declarator_is_pointer ? declarator_pointed_size_now () :
+                                declarator_element_size_from_fields (parsed_type_size, object_fields, object_field_count));
+                        set_global_symbol_unsigned (static_label, (declarator_is_pointer || declarator_has_function) ? 0 : parsed_type_is_unsigned);
+                        set_global_symbol_floating (static_label, (declarator_is_pointer || declarator_has_function) ? 0 : parsed_type_is_floating);
+                        set_global_symbol_array (static_label, declarator_has_array);
+                        set_global_symbol_array_count (static_label, declarator_has_array ? declarator_array_count : 0);
+                        set_global_symbol_array_dimensions (static_label, declarator_has_array ? declarator_array_dimensions : 0);
+                        set_global_symbol_array_element_size (static_label, declarator_array_element_size_now (parsed_type_size));
+                        
+                        emit_block_static_object (static_label,
+                            declarator_is_pointer ? DATA_PTR : (parsed_type_is_aggregate ? parsed_type_size : (parsed_type_size & 0x1f)),
+                                declarator_has_array, declarator_array_count,
+                                    object_fields, object_field_count,
+                                        init_values, init_symbols, init_value_count,
+                                            (!declarator_is_pointer && parsed_type_is_aggregate));
+                    
+                    }
+                    
+                    add_static_local_symbol (name, static_label,
+                        declarator_object_size (parsed_type_size),
+                            type_alignment (declarator_is_pointer ? DATA_PTR : parsed_type_size),
+                                (declarator_is_pointer ? 0 : parsed_type_is_unsigned),
+                                    block_scope_start, name_line, name_start, name_caret);
+                    
+                    set_local_symbol_floating (name, declarator_is_pointer ? 0 : parsed_type_is_floating);
+                    set_local_symbol_array (name, declarator_has_array);
+                    set_local_symbol_array_dimensions (name, declarator_has_array ? declarator_array_dimensions : 0);
+                    set_local_symbol_array_element_size (name, declarator_array_element_size_now (parsed_type_size));
+                    set_local_symbol_pointer_info (name, declarator_effective_pointer_depth_now (),
+                        declarator_effective_pointed_size_now (parsed_type_size, object_fields, object_field_count));
+                    
+                    if (!declarator_is_pointer && parsed_type_tag_name[0]) {
+                    
+                        struct local_symbol *lsym = find_local_symbol (name);
+                        
+                        if (lsym) {
+                            lsym->tag_name = xstrdup (parsed_type_tag_name);
+                        }
+                    
+                    }
+                
+                }
+                
+                for (i = 0; i < MAX_AGG_FIELDS; i++) {
+                
+                    if (init_symbols[i]) {
+                    
+                        free (init_symbols[i]);
+                        init_symbols[i] = 0;
+                    
+                    }
+                
+                }
+                
+                if (name) {
+                    free (name);
+                }
+                
+                if (!_accept (TOK_COMMA)) {
+                    break;
+                }
+            
+            }
+            
+            expect (TOK_SEMI, ";");
+            
+            if (block_stack_emitted) {
+                ensure_block_stack_allocated (block_stack_start, &block_stack_bytes, &block_stack_emitted);
+            }
+            
+            continue;
+        
+        }
+        
+        if (declaration_phase) {
+        
+            declaration_phase = 0;
+            
+            {
+            
+                long needed_stack_bytes = align_up_long (current_local_stack_size - block_stack_start, 4);
+                
+                if (!block_stack_emitted) {
+                
+                    block_stack_bytes = needed_stack_bytes;
+                    
+                    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;
+                    }
+                    
+                    block_stack_emitted = (block_stack_bytes > 0);
+                
+                } else if (needed_stack_bytes > block_stack_bytes) {
+                
+                    long extra_stack_bytes = needed_stack_bytes - block_stack_bytes;
+                    
+                    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;
+                    }
+                    
+                    block_stack_bytes = needed_stack_bytes;
+                
+                }
+            
+            }
+            
+            emit_local_initializers (inits, init_count);
+            init_count = 0;
+        
+        }
+        
+        parse_statement ();
+    
+    }
+    
+    if (declaration_phase) {
+    
+        /**
+         * The block contained declarations only.  We still need to reserve
+         * stack space for those automatic objects, otherwise a function like
+         *
+         *     void f(void) { int a; }
+         *
+         * would produce no `sub esp, ...` at all.
+         */
+        declaration_phase = 0;
+        
+        {
+        
+            long needed_stack_bytes = align_up_long (current_local_stack_size - block_stack_start, 4);
+            
+            if (!block_stack_emitted) {
+            
+                block_stack_bytes = needed_stack_bytes;
+                
+                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) {
+            
+                if (!current_function_frame_deferred) {
+                    emit_stack_adjust (needed_stack_bytes - block_stack_bytes, 1);
+                }
+                
+                block_stack_bytes = needed_stack_bytes;
+            
+            }
+        
+        }
+        
+        emit_local_initializers (inits, init_count);
+        init_count = 0;
+    
+    }
+    
+    expect (TOK_RBRACE, "}");
+    
+    if (!is_function_body && !current_function_frame_deferred && block_stack_emitted && block_stack_bytes > 0) {
+    
+        emit_stack_adjust (block_stack_bytes, 0);
+        
+        if (current_block_cleanup_bytes >= block_stack_bytes) {
+            current_block_cleanup_bytes -= block_stack_bytes;
+        } else {
+            current_block_cleanup_bytes = 0;
+        }
+    
+    }
+    
+    current_parse_block_depth--;
+    truncate_local_symbols (block_local_start, block_stack_start);
+
+}
+
+static int is_assignment_operator (enum token_kind k) {
+
+    switch (k) {
+    
+        case TOK_ASSIGN:
+        case TOK_PLUSEQ:
+        case TOK_MINUSEQ:
+        case TOK_STAREQ:
+        case TOK_SLASHEQ:
+        case TOK_MODEQ:
+        case TOK_ANDEQ:
+        case TOK_OREQ:
+        case TOK_XOREQ:
+        case TOK_LSHEQ:
+        case TOK_RSHEQ:
+        
+            return 1;
+        
+        default:
+        
+            return 0;
+    
+    }
+
+}
+
+static void emit_load_local_to_reg_ex (const char *reg, long offset, int size, int is_unsigned) {
+
+    char memref[64];
+    size &= 0x1f;
+    
+    if (!state->ofp || !reg) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_ebp_offset (memref, sizeof (memref), offset);
+        
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s %s, byte %s\n" : "    %s %s, byte ptr %s\n"), is_unsigned ? "movzx" : "movsx", reg, memref);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s %s, word %s\n" : "    %s %s, word ptr %s\n"), is_unsigned ? "movzx" : "movsx", reg, memref);
+        } else {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword %s\n" : "    mov %s, dword ptr %s\n"), reg, memref);
+        }
+    
+    } else {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, "    %s %ld(%%ebp), %%%s\n", is_unsigned ? "movzbl" : "movsbl", offset, reg);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, "    %s %ld(%%ebp), %%%s\n", is_unsigned ? "movzwl" : "movswl", offset, reg);
+        } else {
+            fprintf (state->ofp, "    movl %ld(%%ebp), %%%s\n", offset, reg);
+        }
+    
+    }
+
+}
+
+static void emit_load_local_to_reg (const char *reg, long offset, int size) {
+    emit_load_local_to_reg_ex (reg, offset, size, 0);
+}
+
+static void emit_load_global_to_reg_ex (const char *reg, const char *symbol, int size, int is_unsigned) {
+
+    const char *asm_symbol;
+    size &= 0x1f;
+    
+    if (!state->ofp || !reg || !symbol) {
+        return;
+    }
+    
+    emit_extern_reference_symbol (symbol, size);
+    
+    if (get_global_symbol_dllimport (symbol) && get_global_symbol_kind (symbol) == GLOBAL_SYMBOL_OBJECT) {
+    
+        asm_symbol = asm_global_import_symbol_name (symbol);
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [%s]\n" : "    mov %s, dword ptr %s\n"), reg, asm_symbol);
+            
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s %s, byte [%s]\n" : "    %s %s, byte ptr [%s]\n"), is_unsigned ? "movzx" : "movsx", reg, reg);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s %s, word [%s]\n" : "    %s %s, word ptr [%s]\n"), is_unsigned ? "movzx" : "movsx", reg, reg);
+            } else {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [%s]\n" : "    mov %s, dword ptr [%s]\n"), reg, reg);
+            }
+        
+        } else {
+        
+            fprintf (state->ofp, "    movl %s, %%%s\n", asm_symbol, reg);
+            
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    %s (%%%s), %%%s\n", is_unsigned ? "movzbl" : "movsbl", reg, reg);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    %s (%%%s), %%%s\n", is_unsigned ? "movzwl" : "movswl", reg, reg);
+            } else {
+                fprintf (state->ofp, "    movl (%%%s), %%%s\n", reg, reg);
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    asm_symbol = asm_global_symbol_name (symbol);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s %s, byte [%s]\n" : "    %s %s, byte ptr %s\n"), is_unsigned ? "movzx" : "movsx", reg, asm_symbol);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s %s, word [%s]\n" : "    %s %s, word ptr %s\n"), is_unsigned ? "movzx" : "movsx", reg, asm_symbol);
+        } else {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [%s]\n" : "    mov %s, dword ptr %s\n"), reg, asm_symbol);
+        }
+    
+    } else {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, "    %s %s, %%%s\n", is_unsigned ? "movzbl" : "movsbl", asm_symbol, reg);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, "    %s %s, %%%s\n", is_unsigned ? "movzwl" : "movswl", asm_symbol, reg);
+        } else {
+            fprintf (state->ofp, "    movl %s, %%%s\n", asm_symbol, reg);
+        }
+    
+    }
+
+}
+
+static void emit_load_global_to_reg (const char *reg, const char *symbol, int size) {
+    emit_load_global_to_reg_ex (reg, symbol, size, 0);
+}
+
+static void emit_store_reg_to_local (long offset, int size, const char *reg) {
+
+    char memref[64];
+    
+    if (!state->ofp || !reg) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_ebp_offset (memref, sizeof (memref), offset);
+
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov byte %s, %cl\n" : "    mov byte ptr %s, %cl\n"), memref, reg[1]);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov word %s, %cx\n" : "    mov word ptr %s, %cx\n"), memref, reg[1]);
+        } else {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword %s, %s\n" : "    mov dword ptr %s, %s\n"), memref, reg);
+        }
+    
+    } else {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, "    movb %%%cl, %ld(%%ebp)\n", reg[1], offset);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, "    movw %%%cx, %ld(%%ebp)\n", reg[1], offset);
+        } else {
+            fprintf (state->ofp, "    movl %%%s, %ld(%%ebp)\n", reg, offset);
+        }
+    
+    }
+
+}
+
+static void emit_store_reg_to_global (const char *symbol, int size, const char *reg) {
+
+    const char *asm_symbol;
+    
+    if (!state->ofp || !symbol || !reg) {
+        return;
+    }
+    
+    if (get_global_symbol_dllimport (symbol) && get_global_symbol_kind (symbol) == GLOBAL_SYMBOL_OBJECT) {
+    
+        const char *addr_reg = (strcmp (reg, "ecx") == 0) ? "edx" : "ecx";
+        
+        asm_symbol = asm_global_import_symbol_name (symbol);
+        emit_extern_reference_symbol (symbol, size);
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [%s]\n" : "    mov %s, dword ptr %s\n"), addr_reg, asm_symbol);
+            
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov byte [%s], %cl\n" : "    mov byte ptr [%s], %cl\n"), addr_reg, reg[1]);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov word [%s], %cx\n" : "    mov word ptr [%s], %cx\n"), addr_reg, reg[1]);
+            } else {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword [%s], %s\n" : "    mov dword ptr [%s], %s\n"), addr_reg, reg);
+            }
+        
+        } else {
+        
+            fprintf (state->ofp, "    movl %s, %%%s\n", asm_symbol, addr_reg);
+            
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    movb %%%cl, (%%%s)\n", reg[1], addr_reg);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    movw %%%cx, (%%%s)\n", reg[1], addr_reg);
+            } else {
+                fprintf (state->ofp, "    movl %%%s, (%%%s)\n", reg, addr_reg);
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    asm_symbol = asm_global_symbol_name (symbol);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov byte [%s], %cl\n" : "    mov byte ptr %s, %cl\n"), asm_symbol, reg[1]);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov word [%s], %cx\n" : "    mov word ptr %s, %cx\n"), asm_symbol, reg[1]);
+        } else {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword [%s], %s\n" : "    mov dword ptr %s, %s\n"), asm_symbol, reg);
+        }
+    
+    } else {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, "    movb %%%cl, %s\n", reg[1], asm_symbol);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, "    movw %%%cx, %s\n", reg[1], asm_symbol);
+        } else {
+            fprintf (state->ofp, "    movl %%%s, %s\n", reg, asm_symbol);
+        }
+    
+    }
+
+}
+
+static void emit_load_local64_to_pair (long offset, const char *lo, const char *hi) {
+
+    char memref_lo[64], memref_hi[64];
+    
+    if (!state->ofp || !lo || !hi) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_ebp_offset (memref_lo, sizeof (memref_lo), offset);
+        format_intel_ebp_offset (memref_hi, sizeof (memref_hi), offset + 4);
+        
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword %s\n" : "    mov %s, dword ptr %s\n"), lo, memref_lo);
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword %s\n" : "    mov %s, dword ptr %s\n"), hi, memref_hi);
+    
+    } else {
+    
+        fprintf (state->ofp, "    movl %ld(%%ebp), %%%s\n", offset, lo);
+        fprintf (state->ofp, "    movl %ld(%%ebp), %%%s\n", offset + 4, hi);
+    
+    }
+
+}
+
+static void emit_store_pair_to_local64 (long offset, const char *lo, const char *hi) {
+
+    char memref_lo[64], memref_hi[64];
+    
+    if (!state->ofp || !lo || !hi) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_ebp_offset (memref_lo, sizeof (memref_lo), offset);
+        format_intel_ebp_offset (memref_hi, sizeof (memref_hi), offset + 4);
+        
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword %s, %s\n" : "    mov dword ptr %s, %s\n"), memref_lo, lo);
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword %s, %s\n" : "    mov dword ptr %s, %s\n"), memref_hi, hi);
+    
+    } else {
+    
+        fprintf (state->ofp, "    movl %%%s, %ld(%%ebp)\n", lo, offset);
+        fprintf (state->ofp, "    movl %%%s, %ld(%%ebp)\n", hi, offset + 4);
+    
+    }
+
+}
+
+static void emit_load_global64_to_pair (const char *lo, const char *hi, const char *symbol) {
+
+    const char *asm_symbol;
+    
+    if (!state->ofp || !lo || !hi || !symbol) {
+        return;
+    }
+    
+    emit_extern_reference_symbol (symbol, DATA_LLONG & 0x1f);
+    asm_symbol = asm_global_symbol_name (symbol);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [%s]\n" : "    mov %s, dword ptr %s\n"), lo, asm_symbol);
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [%s + 4]\n" : "    mov %s, dword ptr %s + 4\n"), hi, asm_symbol);
+    
+    } else {
+    
+        fprintf (state->ofp, "    movl %s, %%%s\n", asm_symbol, lo);
+        fprintf (state->ofp, "    movl %s+4, %%%s\n", asm_symbol, hi);
+    
+    }
+
+}
+
+static void emit_store_pair_to_global64 (const char *symbol, const char *lo, const char *hi) {
+
+    const char *asm_symbol;
+    
+    if (!state->ofp || !symbol || !lo || !hi) {
+        return;
+    }
+    
+    emit_extern_reference_symbol (symbol, DATA_LLONG & 0x1f);
+    asm_symbol = asm_global_symbol_name (symbol);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword [%s], %s\n" : "    mov dword ptr %s, %s\n"), asm_symbol, lo);
+        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword [%s + 4], %s\n" : "    mov dword ptr %s + 4, %s\n"), asm_symbol, hi);
+    
+    } else {
+    
+        fprintf (state->ofp, "    movl %%%s, %s\n", lo, asm_symbol);
+        fprintf (state->ofp, "    movl %%%s, %s+4\n", hi, asm_symbol);
+    
+    }
+
+}
+
+static void emit_call_identifier_to_reg_now (const char *name, const char *reg, const char *name_start, const char *name_caret, unsigned long name_line);
+static void emit_push_pending_struct_return_address_now (int stack_arg_bytes);
+
+static int emit_push_aggregate_from_addr_reg_now (const char *reg, int size) {
+
+    int offset;
+    int chunk;
+    
+    if (!reg || size <= (DATA_PTR & 0x1f)) {
+        return 0;
+    }
+    
+    if (!state->ofp) {
+        return 1;
+    }
+    
+    for (offset = size; offset > 0; ) {
+    
+        if (offset >= 4) {
+        
+            chunk = 4;
+            offset -= 4;
+        
+        } else if (offset >= 2) {
+        
+            chunk = 2;
+            offset -= 2;
+        
+        } else {
+        
+            chunk = 1;
+            offset -= 1;
+        
+        }
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            if (state->syntax & ASM_SYNTAX_NASM) {
+            
+                if (chunk == 4) {
+                    fprintf (state->ofp, "    push dword [%s + %d]\n", reg, offset);
+                } else if (chunk == 2) {
+                
+                    fprintf (state->ofp, "    movzx edx, word [%s + %d]\n", reg, offset);
+                    fprintf (state->ofp, "    push edx\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    movzx edx, byte [%s + %d]\n", reg, offset);
+                    fprintf (state->ofp, "    push edx\n");
+                
+                }
+            
+            } else {
+            
+                if (chunk == 4) {
+                    fprintf (state->ofp, "    push dword ptr [%s + %d]\n", reg, offset);
+                } else if (chunk == 2) {
+                
+                    fprintf (state->ofp, "    movzx edx, word ptr [%s + %d]\n", reg, offset);
+                    fprintf (state->ofp, "    push edx\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    movzx edx, byte ptr [%s + %d]\n", reg, offset);
+                    fprintf (state->ofp, "    push edx\n");
+                
+                }
+            
+            }
+        
+        } else {
+        
+            if (chunk == 4) {
+                fprintf (state->ofp, "    pushl %d(%%%s)\n", offset, reg);
+            } else if (chunk == 2) {
+            
+                fprintf (state->ofp, "    movzwl %d(%%%s), %%edx\n", offset, reg);
+                fprintf (state->ofp, "    pushl %%edx\n");
+            
+            } else {
+            
+                fprintf (state->ofp, "    movzbl %d(%%%s), %%edx\n", offset, reg);
+                fprintf (state->ofp, "    pushl %%edx\n");
+            
+            }
+        
+        }
+    
+    }
+    
+    return 1;
+
+}
+
+static void emit_call_pointer_in_reg_now (const char *fn_reg, const char *result_reg);
+
+static int is_arithmetic_binary_operator (enum token_kind k) {
+
+    return  k == TOK_PLUS || k == TOK_MINUS || k == TOK_STAR || k == TOK_BSLASH ||
+                k == TOK_MOD || k == TOK_AMPER || k == TOK_PIPE || k == TOK_CARET ||
+                    k == TOK_LSH || k == TOK_RSH;
+
+}
+
+static void emit_push_reg_now (const char *reg) {
+
+    if (!state->ofp || !reg) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    push %s\n", reg);
+    } else {
+        fprintf (state->ofp, "    pushl %%%s\n", reg);
+    }
+
+}
+
+static void emit_pop_reg_now (const char *reg) {
+
+    if (!state->ofp || !reg) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    pop %s\n", reg);
+    } else {
+        fprintf (state->ofp, "    popl %%%s\n", reg);
+    }
+
+}
+
+static void emit_mov_reg_to_reg_now (const char *dst, const char *src) {
+
+    if (!state->ofp || !dst || !src || strcmp (dst, src) == 0) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    mov %s, %s\n", dst, src);
+    } else {
+        fprintf (state->ofp, "    movl %%%s, %%%s\n", src, dst);
+    }
+
+}
+
+static void emit_load_indexed_pointer_to_reg_now (const char *base_reg, const char *index_reg) {
+
+    if (!state->ofp || !base_reg || !index_reg) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+            fprintf (state->ofp, "    mov %s, dword [%s + %s * 4]\n", base_reg, base_reg, index_reg);
+        } else {
+            fprintf (state->ofp, "    mov %s, dword ptr [%s + %s * 4]\n", base_reg, base_reg, index_reg);
+        }
+    
+    } else {
+        fprintf (state->ofp, "    movl (%%%s,%%%s,4), %%%s\n", base_reg, index_reg, base_reg);
+    }
+
+}
+
+static void emit_load_indexed_char_to_reg_now (const char *base_reg, const char *index_reg, const char *dst_reg, int is_unsigned) {
+
+    if (!state->ofp || !base_reg || !index_reg || !dst_reg) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+            fprintf (state->ofp, "    %s %s, byte [%s + %s]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg);
+        } else {
+            fprintf (state->ofp, "    %s %s, byte ptr [%s + %s]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg);
+        }
+    
+    } else {
+        fprintf (state->ofp, "    %s (%%%s,%%%s), %%%s\n", is_unsigned ? "movzbl" : "movsbl", base_reg, index_reg, dst_reg);
+    }
+
+}
+
+static void emit_load_indexed_sized_to_reg_ex_now (const char *base_reg, const char *index_reg, const char *dst_reg, int elem_size, int is_unsigned) {
+
+    int scale = 1;
+    
+    const char *gasop = is_unsigned ? "movzbl" : "movsbl";
+    const char *atype = "byte";
+    
+    if (!state->ofp || !base_reg || !index_reg || !dst_reg) {
+        return;
+    }
+    
+    elem_size &= 0x1f;
+    
+    if (elem_size == (DATA_SHORT & 0x1f)) {
+    
+        scale = 2;
+        
+        atype = "word";
+        gasop = "movswl";
+    
+    } else if (elem_size == (DATA_INT & 0x1f) || elem_size == (DATA_LONG & 0x1f) || elem_size == DATA_PTR) {
+    
+        scale = 4;
+        
+        atype = "dword";
+        gasop = "movl";
+    
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (elem_size == (DATA_CHAR & 0x1f)) {
+            emit_load_indexed_char_to_reg_now (base_reg, index_reg, dst_reg, is_unsigned);
+        } else if (scale == 1) {
+        
+            if (strcmp (atype, "byte") == 0) {
+            
+                if (state->syntax & ASM_SYNTAX_NASM) {
+                    fprintf (state->ofp, "    %s %s, byte [%s + %s]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg);
+                } else {
+                    fprintf (state->ofp, "    %s %s, byte ptr [%s + %s]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg);
+                }
+            
+            } else if (elem_size == (DATA_SHORT & 0x1f)) {
+            
+                if (state->syntax & ASM_SYNTAX_NASM) {
+                    fprintf (state->ofp, "    %s %s, word [%s + %s]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg);
+                } else {
+                    fprintf (state->ofp, "    %s %s, word ptr [%s + %s]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg);
+                }
+            
+            } else if (state->syntax & ASM_SYNTAX_NASM) {
+                fprintf (state->ofp, "    mov %s, %s [%s + %s]\n", dst_reg, atype, base_reg, index_reg);
+            } else {
+                fprintf (state->ofp, "    mov %s, %s ptr [%s + %s]\n", dst_reg, atype, base_reg, index_reg);
+            }
+        
+        } else {
+        
+            if (strcmp (atype, "byte") == 0) {
+            
+                if (state->syntax & ASM_SYNTAX_NASM) {
+                    fprintf (state->ofp, "    %s %s, byte [%s + %s * %d]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg, scale);
+                } else {
+                    fprintf (state->ofp, "    %s %s, byte ptr [%s + %s * %d]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg, scale);
+                }
+            
+            } else if (elem_size == (DATA_SHORT & 0x1f)) {
+
+                if (state->syntax & ASM_SYNTAX_NASM) {
+                    fprintf (state->ofp, "    %s %s, word [%s + %s * %d]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg, scale);
+                } else {
+                    fprintf (state->ofp, "    %s %s, word ptr [%s + %s * %d]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg, scale);
+                }
+
+            } else if (state->syntax & ASM_SYNTAX_NASM) {
+                fprintf (state->ofp, "    mov %s, %s [%s + %s * %d]\n", dst_reg, atype, base_reg, index_reg, scale);
+            } else {
+                fprintf (state->ofp, "    mov %s, %s ptr [%s + %s * %d]\n", dst_reg, atype, base_reg, index_reg, scale);
+            }
+        
+        }
+    
+    } else {
+    
+        if (scale == 1) {
+            fprintf (state->ofp, "    %s (%%%s,%%%s), %%%s\n", gasop, base_reg, index_reg, dst_reg);
+        } else {
+            fprintf (state->ofp, "    %s (%%%s,%%%s,%d), %%%s\n", gasop, base_reg, index_reg, scale, dst_reg);
+        }
+    
+    }
+
+}
+
+static void emit_load_indexed_sized_to_reg_now (const char *base_reg, const char *index_reg, const char *dst_reg, int elem_size) {
+    emit_load_indexed_sized_to_reg_ex_now (base_reg, index_reg, dst_reg, elem_size, 0);
+}
+
+static void emit_load_indexed_unsigned_sized_to_reg_now (const char *base_reg, const char *index_reg, const char *dst_reg, int elem_size) {
+    emit_load_indexed_sized_to_reg_ex_now (base_reg, index_reg, dst_reg, elem_size, 1);
+}
+
+static void emit_load_symbol_address_to_reg_now (const char *reg, const char *symbol, long offset, int is_local) {
+
+    const char *asm_symbol;
+    
+    if (!state->ofp || !reg) {
+        return;
+    }
+    
+    if (is_local) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    lea %s, [ebp%+ld]\n", reg, offset);
+        } else {
+            fprintf (state->ofp, "    leal %ld(%%ebp), %%%s\n", offset, reg);
+        }
+        
+        return;
+    
+    }
+    
+    if (!symbol) {
+        return;
+    }
+    
+    emit_extern_reference_symbol (symbol, DATA_PTR);
+    asm_symbol = asm_global_symbol_name (symbol);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+            fprintf (state->ofp, "    mov %s, %s\n", reg, asm_symbol);
+        } else {
+            fprintf (state->ofp, "    mov %s, offset %s\n", reg, asm_symbol);
+        }
+    
+    } else {
+        fprintf (state->ofp, "    movl $%s, %%%s\n", asm_symbol, reg);
+    }
+
+}
+
+static void emit_add_indexed_scaled_address_to_reg_now (const char *base_reg, const char *index_reg, int elem_size) {
+
+    int raw_elem_size = elem_size;
+    int scale = 1;
+    
+    if (!state->ofp || !base_reg || !index_reg) {
+        return;
+    }
+    
+    if (raw_elem_size == DATA_SHORT || raw_elem_size == (DATA_SHORT & 0x1f)) {
+    
+        elem_size = DATA_SHORT & 0x1f;
+        scale = 2;
+    
+    } else if (raw_elem_size == DATA_INT || raw_elem_size == DATA_LONG || raw_elem_size == DATA_PTR || raw_elem_size == (DATA_INT & 0x1f)) {
+    
+        elem_size = DATA_INT & 0x1f;
+        scale = 4;
+    
+    } else if (elem_size > 1) {
+        scale = 0;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (scale == 0) {
+        
+            fprintf (state->ofp, "    imul %s, %d\n", index_reg, elem_size);
+            fprintf (state->ofp, "    lea %s, [%s + %s]\n", base_reg, base_reg, index_reg);
+        
+        } else if (scale == 1) {
+            fprintf (state->ofp, "    lea %s, [%s + %s]\n", base_reg, base_reg, index_reg);
+        } else {
+            fprintf (state->ofp, "    lea %s, [%s + %s * %d]\n", base_reg, base_reg, index_reg, scale);
+        }
+    
+    } else {
+    
+        if (scale == 0) {
+        
+            fprintf (state->ofp, "    imull $%d, %%%s, %%%s\n", elem_size, index_reg, index_reg);
+            fprintf (state->ofp, "    leal (%%%s,%%%s), %%%s\n", base_reg, index_reg, base_reg);
+        
+        } else if (scale == 1) {
+            fprintf (state->ofp, "    leal (%%%s,%%%s), %%%s\n", base_reg, index_reg, base_reg);
+        } else {
+            fprintf (state->ofp, "    leal (%%%s,%%%s,%d), %%%s\n", base_reg, index_reg, scale, base_reg);
+        }
+    
+    }
+
+}
+
+static void emit_load_subscript_index_to_reg_now (const char *index_reg) {
+
+    if (current_expression_mentions_64bit_symbol_now ()) {
+    
+        int is_unsigned = rhs_current_operand_is_unsigned_now ();
+        emit_load_assignment_rhs_expression_to_pair ("eax", "edx", is_unsigned);
+        
+        if (index_reg && strcmp (index_reg, "eax") != 0) {
+            emit_mov_reg_to_reg_now (index_reg, "eax");
+        }
+        
+        return;
+    
+    }
+    
+    emit_load_assignment_rhs_expression_to_reg (index_reg);
+
+}
+
+static int emit_parse_postfix_subscript_scaled_address_to_reg_now (const char *reg, int elem_size) {
+
+    const char *index_reg;
+    int saw_subscript = 0;
+    
+    if (!reg) {
+        reg = "eax";
+    }
+    
+    index_reg = (strcmp (reg, "ecx") == 0) ? "edx" : "ecx";
+    
+    while (tok.kind == TOK_LBRACK) {
+    
+        saw_subscript = 1;
+        get_token ();
+        
+        emit_push_reg_now (reg);
+        emit_load_subscript_index_to_reg_now (index_reg);
+        expect (TOK_RBRACK, "]");
+        emit_pop_reg_now (reg);
+        
+        if (tok.kind == TOK_LBRACK) {
+            emit_load_indexed_pointer_to_reg_now (reg, index_reg);
+        } else {
+            emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
+        }
+    
+    }
+    
+    return saw_subscript;
+
+}
+
+static int emit_parse_postfix_subscripts_to_reg_now (const char *reg, int elem_size, int pointer_depth, int pointed_size) {
+
+    const char *index_reg;
+    int saw_subscript = 0;
+    
+    if (!reg) {
+        reg = "eax";
+    }
+    
+    index_reg = (strcmp (reg, "ecx") == 0) ? "edx" : "ecx";
+    
+    while (tok.kind == TOK_LBRACK) {
+    
+        saw_subscript = 1;
+        get_token ();
+        
+        emit_push_reg_now (reg);
+        emit_load_subscript_index_to_reg_now (index_reg);
+        
+        expect (TOK_RBRACK, "]");
+        emit_pop_reg_now (reg);
+        
+        if (tok.kind == TOK_LBRACK) {
+        
+            if (pointer_depth == 0 && pointed_size > 0 && elem_size > pointed_size) {
+            
+                /*
+                 * This is a real multidimensional array row, not an array of
+                 * pointers.  For char a[7][3], a[i] is the address of the
+                 * three-byte row.  The old code treated every further subscript
+                 * as pointer traversal and loaded *(a + i), which turns the
+                 * first bytes of the row into a bogus pointer.
+                 */
+                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
+                elem_size = index_step_size (pointed_size);
+            
+            } else {
+            
+                emit_load_indexed_pointer_to_reg_now (reg, index_reg);
+                
+                if (pointer_depth > 0) {
+                    pointer_depth--;
+                }
+                
+                if (pointed_size > 0) {
+                    elem_size = (pointer_depth > 1) ? (DATA_PTR & 0x1f) : index_step_size (pointed_size);
+                }
+            
+            }
+        
+        } else {
+        
+            if (pointer_depth == 0 && pointed_size > 0 && elem_size > pointed_size) {
+                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
+            } else if (index_step_size (elem_size) > (DATA_PTR & 0x1f)) {
+                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
+            } else {
+                emit_load_indexed_sized_to_reg_now (reg, index_reg, reg, elem_size);
+            }
+        
+        }
+    
+    }
+
+    return saw_subscript;
+
+}
+
+static int emit_parse_postfix_subscripts_to_reg_dims_now (const char *reg, int elem_size, int pointer_depth, int pointed_size, int array_dimensions, int is_unsigned) {
+
+    const char *index_reg;
+    int saw_subscript = 0;
+    
+    if (!reg) {
+        reg = "eax";
+    }
+    
+    index_reg = (strcmp (reg, "ecx") == 0) ? "edx" : "ecx";
+    
+    while (tok.kind == TOK_LBRACK) {
+    
+        int dims_before = array_dimensions;
+        
+        saw_subscript = 1;
+        get_token ();
+        
+        emit_push_reg_now (reg);
+        emit_load_subscript_index_to_reg_now (index_reg);
+        
+        expect (TOK_RBRACK, "]");
+        emit_pop_reg_now (reg);
+        
+        if (array_dimensions > 0) {
+            array_dimensions--;
+        }
+        
+        if (tok.kind == TOK_LBRACK) {
+        
+            if (pointer_depth == 0 && pointed_size > 0 && elem_size > pointed_size) {
+            
+                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
+                elem_size = index_step_size (pointed_size);
+            
+            } else {
+            
+                emit_load_indexed_pointer_to_reg_now (reg, index_reg);
+                
+                if (pointer_depth > 0) {
+                    pointer_depth--;
+                }
+                
+                if (pointed_size > 0) {
+                    elem_size = (pointer_depth > 1) ? (DATA_PTR & 0x1f) : index_step_size (pointed_size);
+                }
+            
+            }
+        
+        } else {
+        
+            if (pointer_depth == 0 && dims_before > 1) {
+                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
+            } else if (pointer_depth == 0 && pointed_size > 0 && elem_size > pointed_size) {
+                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
+            } else if (index_step_size (elem_size) > (DATA_PTR & 0x1f)) {
+                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
+            } else {
+            
+                if (is_unsigned) {
+                    emit_load_indexed_unsigned_sized_to_reg_now (reg, index_reg, reg, elem_size);
+                } else {
+                    emit_load_indexed_sized_to_reg_now (reg, index_reg, reg, elem_size);
+                }
+            
+            }
+        
+        }
+    
+    }
+
+    return saw_subscript;
+
+}
+
+static int parse_incdec_identifier_now (enum token_kind *op, char **name, const char **name_start, const char **name_caret, unsigned long *name_line) {
+
+    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
+        return 0;
+    }
+    
+    *op = tok.kind;
+    get_token ();
+    
+    if (tok.kind != TOK_IDENT) {
+    
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after %s", *op == TOK_INCR ? "++" : "--");
+        
+        *name = 0;
+        return 1;
+    }
+    
+    *name = xstrdup (tok.ident);
+    *name_start = tok.start;
+    *name_caret = tok.caret;
+    *name_line = get_line_number ();
+    
+    get_token ();
+    return 1;
+
+}
+
+static void emit_apply_postfix_member_access_to_reg_now (const char *reg);
+static void emit_apply_postfix_member_incdec_now (const char *reg, enum token_kind op);
+static void emit_load_member_from_addr_reg_now (const char *dst_reg, const char *addr_reg, int offset, int size);
+
+static struct token *clone_current_token_now (void);
+static void emit_store_reg_to_deref_reg_now (const char *addr_reg, const char *value_reg, int size);
+
+static int source_starts_prefix_incdec_parenthesized_deref_at (const char *p) {
+
+    if (!p) {
+        return 0;
+    }
+    
+    if (!((p[0] == '+' && p[1] == '+') || (p[0] == '-' && p[1] == '-'))) {
+        return 0;
+    }
+    
+    p += 2;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '*') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    p++;
+    
+    while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+        p++;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == ')';
+
+}
+
+static int emit_load_prefix_incdec_parenthesized_deref_to_reg_now (const char *reg) {
+
+    enum token_kind op;
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    struct local_symbol *sym;
+    
+    int global_index;
+    int pointer_depth = 0;
+    int pointed_size = DATA_INT & 0x1f;
+    int lvalue_size = DATA_INT & 0x1f;
+    int step = 1;
+    
+    const char *addr_reg;
+    
+    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
+        return 0;
+    }
+    
+    if (!source_starts_prefix_incdec_parenthesized_deref_at (tok.caret)) {
+        return 0;
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    expect (TOK_LPAREN, "(");
+    expect (TOK_STAR, "*");
+    
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    get_token ();
+    
+    expect (TOK_RPAREN, ")");
+    
+    sym = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (sym) {
+    
+        pointer_depth = sym->pointer_depth;
+        pointed_size = sym->pointed_size;
+    
+    } else if (global_index >= 0) {
+    
+        pointer_depth = get_global_symbol_pointer_depth (name);
+        pointed_size = get_global_symbol_pointed_size (name);
+    
+    } else {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (pointer_depth <= 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid indirection of non-pointer '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (pointed_size <= 0) {
+        pointed_size = DATA_INT & 0x1f;
+    }
+    
+    if (pointer_depth > 1) {
+    
+        lvalue_size = DATA_PTR & 0x1f;
+        step = pointer_depth > 2 ? (DATA_PTR & 0x1f) : index_step_size (pointed_size);
+    
+    } else {
+    
+        lvalue_size = pointed_size & 0x1f;
+        step = 1;
+    
+    }
+    
+    if (!reg) {
+        reg = "eax";
+    }
+    
+    addr_reg = (strcmp (reg, "edx") == 0) ? "ecx" : "edx";
+    
+    if (sym) {
+    
+        if (sym->is_static && sym->static_label) {
+            emit_load_global_to_reg (addr_reg, sym->static_label, DATA_PTR);
+        } else {
+            emit_load_local_to_reg (addr_reg, sym->offset, DATA_PTR);
+        }
+    
+    } else {
+        emit_load_global_to_reg (addr_reg, name, DATA_PTR);
+    }
+    
+    emit_load_member_from_addr_reg_now (reg, addr_reg, 0, lvalue_size);
+    
+    if (state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, op == TOK_INCR ? "    add %s, %d\n" : "    sub %s, %d\n", reg, step);
+        } else {
+            fprintf (state->ofp, op == TOK_INCR ? "    addl $%d, %%%s\n" : "    subl $%d, %%%s\n", step, reg);
+        }
+    
+    }
+    
+    emit_store_reg_to_deref_reg_now (addr_reg, reg, lvalue_size);
+    
+    if (pointer_depth > 1) {
+        set_rhs_last_pointer_info (pointer_depth - 1, pointed_size);
+    } else {
+        clear_rhs_last_pointer_info ();
+    }
+    
+    free (name);
+    return 1;
+
+}
+
+static int emit_load_prefix_incdec_deref_to_reg_now (const char *reg) {
+
+    enum token_kind op;
+    
+    struct token *saved_tok;
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    
+    struct local_symbol *sym;
+    
+    int global_index;
+    int deref_size = DATA_INT & 0x1f;
+    
+    const char *addr_reg;
+    
+    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
+        return 0;
+    }
+    
+    saved_tok = clone_current_token_now ();
+    op = tok.kind;
+    
+    get_token ();
+    
+    if (tok.kind != TOK_STAR) {
+    
+        unget_token (saved_tok);
+        return 0;
+    
+    }
+    
+    get_token ();
+    
+    if (tok.kind != TOK_IDENT) {
+    
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after *");
+        
+        free (saved_tok->ident);
+        free ((char *) saved_tok->start);
+        free (saved_tok);
+        
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    get_token ();
+    
+    sym = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (sym) {
+    
+        if (sym->pointer_depth > 1) {
+            deref_size = DATA_PTR & 0x1f;
+        } else if (sym->pointer_depth == 1 && sym->pointed_size > 0) {
+            deref_size = sym->pointed_size & 0x1f;
+        }
+    
+    } else if (global_index >= 0) {
+    
+        if (get_global_symbol_pointer_depth (name) > 1) {
+            deref_size = DATA_PTR & 0x1f;
+        } else if (get_global_symbol_pointer_depth (name) == 1 && get_global_symbol_pointed_size (name) > 0) {
+            deref_size = get_global_symbol_pointed_size (name) & 0x1f;
+        }
+    
+    } else {
+
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        free (name);
+        free (saved_tok->ident);
+        
+        free ((char *) saved_tok->start);
+        free (saved_tok);
+        
+        return 1;
+    
+    }
+    
+    if (!reg) {
+        reg = "eax";
+    }
+    
+    addr_reg = (strcmp (reg, "edx") == 0) ? "ecx" : "edx";
+    
+    if (sym) {
+    
+        if (sym->is_static && sym->static_label) {
+            emit_load_global_to_reg (addr_reg, sym->static_label, DATA_PTR);
+        } else {
+            emit_load_local_to_reg (addr_reg, sym->offset, DATA_PTR);
+        }
+    
+    } else {
+        emit_load_global_to_reg (addr_reg, name, DATA_PTR);
+    }
+    
+    emit_load_member_from_addr_reg_now (reg, addr_reg, 0, deref_size);
+    
+    if (state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, op == TOK_INCR ? "    add %s, 1\n" : "    sub %s, 1\n", reg);
+        } else {
+            fprintf (state->ofp, op == TOK_INCR ? "    addl $1, %%%s\n" : "    subl $1, %%%s\n", reg);
+        }
+    
+    }
+    
+    emit_store_reg_to_deref_reg_now (addr_reg, reg, deref_size);
+    
+    free (name);
+    
+    free (saved_tok->ident);
+    free ((char *) saved_tok->start);
+    
+    free (saved_tok);
+    return 1;
+
+}
+
+static int emit_load_prefix_incdec_to_reg_now (const char *reg) {
+
+    enum token_kind op;
+    char *name;
+    
+    const char *name_start, *name_caret;
+    unsigned long name_line;
+    
+    struct local_symbol *sym;
+    
+    if (emit_load_prefix_incdec_parenthesized_deref_to_reg_now (reg)) {
+        return 1;
+    }
+    
+    if (emit_load_prefix_incdec_deref_to_reg_now (reg)) {
+        return 1;
+    }
+    
+    if (!parse_incdec_identifier_now (&op, &name, &name_start, &name_caret, &name_line)) {
+        return 0;
+    }
+    
+    if (!name) {
+        return 1;
+    }
+    
+    sym = find_local_symbol (name);
+    emit_incdec_symbol_now (sym, name, op, name_line, name_start, name_caret);
+    
+    if (sym) {
+    
+        if (sym->is_static && sym->static_label) {
+            emit_load_global_to_reg_ex (reg, sym->static_label, sym->size, sym->is_unsigned);
+        } else {
+            emit_load_local_to_reg_ex (reg, sym->offset, sym->size, sym->is_unsigned);
+        }
+    
+    } else if (find_global_symbol (name) >= 0) {
+        emit_load_global_to_reg_ex (reg, name, get_global_symbol_size (name), get_global_symbol_unsigned (name));
+    }
+    
+    free (name);
+    return 1;
+
+}
+
+static int emit_load_prefix_incdec_member_to_reg_now (const char *reg) {
+
+    struct token *saved_tok;
+    
+    enum token_kind op;
+    enum token_kind member_op = TOK_EOF;
+    
+    char *member;
+    
+    const char *member_start;
+    const char *member_caret;
+    
+    unsigned long member_line;
+    
+    int offset = 0;
+    int size = DATA_INT & 0x1f;
+    
+    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
+        return 0;
+    }
+    
+    saved_tok = clone_current_token_now ();
+    get_token ();
+    
+    if (tok.kind == TOK_STAR) {
+    
+        unget_token (saved_tok);
+        return 0;
+    
+    }
+    
+    unget_token (saved_tok);
+    
+    if (emit_load_prefix_incdec_parenthesized_deref_to_reg_now (reg)) {
+        return 1;
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    if (tok.kind != TOK_LPAREN) {
+    
+        char *name;
+        
+        const char *name_start;
+        const char *name_caret;
+        
+        unsigned long name_line;
+        struct local_symbol *sym;
+        
+        int global_index;
+        
+        if (tok.kind != TOK_IDENT) {
+        
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after %s", op == TOK_INCR ? "++" : "--");
+            return 1;
+        
+        }
+        
+        name = xstrdup (tok.ident);
+        name_start = tok.start;
+        name_caret = tok.caret;
+        name_line = get_line_number ();
+        
+        get_token ();
+        
+        sym = find_local_symbol (name);
+        global_index = find_global_symbol (name);
+        
+        if (tok.kind == TOK_ARROW) {
+        
+            member_op = tok.kind;
+            get_token ();
+            
+            member_start = tok.start;
+            member_caret = tok.caret;
+            member_line = get_line_number ();
+            
+            if (tok.kind != TOK_IDENT) {
+            
+                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+                
+                free (name);
+                return 1;
+            
+            }
+            
+            member = xstrdup (tok.ident);
+            get_token ();
+            
+            if (!find_member_info (member, &offset, &size)) {
+            
+                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+                
+                free (member);
+                free (name);
+                
+                return 1;
+            
+            }
+            
+            free (member);
+            
+            if (sym) {
+            
+                if (sym->is_static && sym->static_label) {
+                    emit_load_global_to_reg (reg, sym->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg (reg, sym->offset, DATA_PTR);
+                }
+            
+            } else if (global_index >= 0) {
+                emit_load_global_to_reg (reg, name, DATA_PTR);
+            } else {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            }
+            
+            free (name);
+            goto emit_member_incdec;
+        
+        }
+        
+        emit_incdec_symbol_now (sym, name, op, name_line, name_start, name_caret);
+        
+        if (sym) {
+        
+            if (sym->is_static && sym->static_label) {
+                emit_load_global_to_reg_ex (reg, sym->static_label, sym->size, sym->is_unsigned);
+            } else {
+                emit_load_local_to_reg_ex (reg, sym->offset, sym->size, sym->is_unsigned);
+            }
+        
+        } else if (find_global_symbol (name) >= 0) {
+            emit_load_global_to_reg_ex (reg, name, get_global_symbol_size (name), get_global_symbol_unsigned (name));
+        }
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    get_token ();
+    
+    emit_load_assignment_rhs_expression_to_reg (reg);
+    expect (TOK_RPAREN, ")");
+    
+    if (postfix_member_seen && tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
+    
+        emit_apply_postfix_member_incdec_now (reg, op);
+        emit_load_member_from_addr_reg_now (reg, "edx", postfix_member_offset, postfix_member_size);
+        
+        return 1;
+    
+    }
+    
+    if (tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
+    
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected member after %s", op == TOK_INCR ? "++" : "--");
+        return 1;
+    
+    }
+    
+    member_op = tok.kind;
+    get_token ();
+    
+    member_start = tok.start;
+    member_caret = tok.caret;
+    member_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT) {
+    
+        report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+        return 1;
+    
+    }
+    
+    member = xstrdup (tok.ident);
+    get_token ();
+    
+    if (!find_member_info (member, &offset, &size)) {
+    
+        report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+        
+        free (member);
+        return 1;
+    
+    }
+    
+    free (member);
+    
+emit_member_incdec:
+    
+    if (!state->ofp) {
+        return 1;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        const char *insn = op == TOK_INCR ? "inc" : "dec";
+        const char *opsize = "dword";
+        
+        if (size == (DATA_CHAR & 0x1f)) {
+            opsize = "byte";
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            opsize = "word";
+        }
+        
+        if (state->syntax & ASM_SYNTAX_NASM) {
+        
+            fprintf (state->ofp, "    %s %s [%s + %d]\n", insn, opsize, reg, offset);
+            
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    movzx %s, byte [%s + %d]\n", reg, reg, offset);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    movzx %s, word [%s + %d]\n", reg, reg, offset);
+            } else {
+                fprintf (state->ofp, "    mov %s, dword [%s + %d]\n", reg, reg, offset);
+            }
+        
+        } else {
+        
+            fprintf (state->ofp, "    %s %s ptr [%s + %d]\n", insn, opsize, reg, offset);
+            
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    movzx %s, byte ptr [%s + %d]\n", reg, reg, offset);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    movzx %s, word ptr [%s + %d]\n", reg, reg, offset);
+            } else {
+                fprintf (state->ofp, "    mov %s, dword ptr [%s + %d]\n", reg, reg, offset);
+            }
+        
+        }
+    
+    } else {
+    
+        const char *suffix = "l";
+        
+        if (size == (DATA_CHAR & 0x1f)) {
+            suffix = "b";
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            suffix = "w";
+        }
+        
+        fprintf (state->ofp, "    %s%s %d(%%%s)\n", op == TOK_INCR ? "inc" : "dec", suffix, offset, reg);
+        
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, "    movzbl %d(%%%s), %%%s\n", offset, reg, reg);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, "    movzwl %d(%%%s), %%%s\n", offset, reg, reg);
+        } else {
+            fprintf (state->ofp, "    movl %d(%%%s), %%%s\n", offset, reg, reg);
+        }
+    
+    }
+    
+    return 1;
+
+}
+
+static int emit_load_prefix_incdec_to_pair_now (const char *lo, const char *hi) {
+
+    enum token_kind op;
+    char *name;
+    
+    const char *name_start, *name_caret;
+    unsigned long name_line;
+    
+    struct local_symbol *sym;
+    
+    if (!parse_incdec_identifier_now (&op, &name, &name_start, &name_caret, &name_line)) {
+        return 0;
+    }
+    
+    if (!name) {
+        return 1;
+    }
+    
+    sym = find_local_symbol (name);
+    emit_incdec_symbol_now (sym, name, op, name_line, name_start, name_caret);
+    
+    if (sym) {
+    
+        if (sym->size == (DATA_LLONG & 0x1f) && !sym->is_floating) {
+        
+            if (sym->is_static && sym->static_label) {
+                emit_load_global64_to_pair (lo, hi, sym->static_label);
+            } else {
+                emit_load_local64_to_pair (sym->offset, lo, hi);
+            }
+        
+        } else {
+        
+            if (sym->is_static && sym->static_label) {
+                emit_load_global_to_reg_ex (lo, sym->static_label, sym->size, sym->is_unsigned);
+            } else {
+                emit_load_local_to_reg_ex (lo, sym->offset, sym->size, sym->is_unsigned);
+            }
+            
+            if (state->ofp) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
+                } else {
+                    fprintf (state->ofp, "    xorl %%%s, %%%s\n", hi, hi);
+                }
+            
+            }
+        
+        }
+    
+    } else if (find_global_symbol (name) >= 0) {
+    
+        if (get_global_symbol_size (name) == (DATA_LLONG & 0x1f) && !get_global_symbol_floating (name)) {
+            emit_load_global64_to_pair (lo, hi, name);
+        } else {
+        
+            emit_load_global_to_reg_ex (lo, name, get_global_symbol_size (name), get_global_symbol_unsigned (name));
+            
+            if (state->ofp) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
+                } else {
+                    fprintf (state->ofp, "    xorl %%%s, %%%s\n", hi, hi);
+                }
+            
+            }
+        
+        }
+    
+    }
+    
+    free (name);
+    return 1;
+
+}
+
+static int expression_text_mentions_64bit_symbol (const char *p) {
+
+    char name[256];
+    int depth = 0;
+    int i;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    while (*p) {
+    
+        if (*p == '(') {
+        
+            depth++;
+            p++;
+            
+            continue;
+        
+        }
+        
+        if (*p == ')') {
+        
+            if (depth <= 0) {
+                return 0;
+            }
+            
+            depth--;
+            p++;
+            
+            continue;
+        
+        }
+        
+        if (*p == ';' || *p == '{' || *p == '}') {
+            return 0;
+        }
+        
+        if ((unsigned char) *p == '_' || ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z'))) {
+        
+            i = 0;
+            
+            while ((unsigned char) *p == '_' || ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z')) || (*p >= '0' && *p <= '9')) {
+            
+                if (i + 1 < (int) sizeof (name)) {
+                    name[i++] = *p;
+                }
+                
+                p++;
+            
+            }
+            
+            name[i] = 0;
+            
+            while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+                p++;
+            }
+            
+            if (*p == '.' || (p[0] == '-' && p[1] == '>')) {
+                continue;
+            }
+            
+            {
+            
+                struct local_symbol *sym = find_local_symbol (name);
+                
+                if (sym && sym->size == (DATA_LLONG & 0x1f) && !sym->is_floating) {
+                    return 1;
+                }
+            
+            }
+            
+            if (find_global_symbol (name) >= 0 && get_global_symbol_size (name) == (DATA_LLONG & 0x1f) && !get_global_symbol_floating (name)) {
+                return 1;
+            }
+            
+            continue;
+        
+        }
+        
+        p++;
+    
+    }
+    
+    return 0;
+
+}
+
+static int current_expression_mentions_64bit_symbol_now (void) {
+
+    if (expression_text_mentions_64bit_symbol (tok.start)) {
+        return 1;
+    }
+    
+    if (expression_text_mentions_64bit_symbol (tok.caret)) {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static const char *reg8_name_for_32 (const char *reg) {
+
+    if (strcmp (reg, "eax") == 0) {
+        return "al";
+    }
+    
+    if (strcmp (reg, "ebx") == 0) {
+        return "bl";
+    }
+    
+    if (strcmp (reg, "ecx") == 0) {
+        return "cl";
+    }
+    
+    if (strcmp (reg, "edx") == 0) {
+        return "dl";
+    }
+    
+    return "al";
+
+}
+
+static const char *reg16_name_for_32 (const char *reg) {
+
+    if (strcmp (reg, "eax") == 0) {
+        return "ax";
+    }
+    
+    if (strcmp (reg, "ebx") == 0) {
+        return "bx";
+    }
+    
+    if (strcmp (reg, "ecx") == 0) {
+        return "cx";
+    }
+    
+    if (strcmp (reg, "edx") == 0) {
+        return "dx";
+    }
+    
+    return "ax";
+
+}
+
+static void emit_extend_pair_high_from_low (const char *lo, const char *hi, int size, int is_unsigned) {
+
+    if (!state->ofp) {
+        return;
+    }
+
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+
+        if (is_unsigned) {
+        
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    movzx %s, %s\n", lo, reg8_name_for_32 (lo));
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    movzx %s, %s\n", lo, reg16_name_for_32 (lo));
+            }
+            
+            fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
+        
+        } else {
+
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    movsx %s, %s\n", lo, reg8_name_for_32 (lo));
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    movsx %s, %s\n", lo, reg16_name_for_32 (lo));
+            }
+
+            fprintf (state->ofp, "    mov %s, %s\n", hi, lo);
+            fprintf (state->ofp, "    sar %s, 31\n", hi);
+
+        }
+
+    } else {
+
+        if (is_unsigned) {
+        
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    movzbl %%%s, %%%s\n", reg8_name_for_32 (lo), lo);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    movzwl %%%s, %%%s\n", reg16_name_for_32 (lo), lo);
+            }
+            
+            fprintf (state->ofp, "    xorl %%%s, %%%s\n", hi, hi);
+        
+        } else {
+
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    movsbl %%%s, %%%s\n", reg8_name_for_32 (lo), lo);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    movswl %%%s, %%%s\n", reg16_name_for_32 (lo), lo);
+            }
+
+            fprintf (state->ofp, "    movl %%%s, %%%s\n", lo, hi);
+            fprintf (state->ofp, "    sarl $31, %%%s\n", hi);
+
+        }
+
+    }
+
+}
+
+static void emit_apply_integer_cast_to_reg_now (const char *reg, int size, int is_unsigned) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (size != (DATA_CHAR & 0x1f) && size != (DATA_SHORT & 0x1f)) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, is_unsigned ? "    movzx %s, %s\n" : "    movsx %s, %s\n", reg, reg8_name_for_32 (reg));
+        } else {
+            fprintf (state->ofp, is_unsigned ? "    movzx %s, %s\n" : "    movsx %s, %s\n", reg, reg16_name_for_32 (reg));
+        }
+    
+    } else {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, is_unsigned ? "    movzbl %%%s, %%%s\n" : "    movsbl %%%s, %%%s\n", reg8_name_for_32 (reg), reg);
+        } else {
+            fprintf (state->ofp, is_unsigned ? "    movzwl %%%s, %%%s\n" : "    movswl %%%s, %%%s\n", reg16_name_for_32 (reg), reg);
+        }
+    
+    }
+
+}
+
+static int fold_text_starts_with_type_name_only_before_rparen (const char *p) {
+
+    int saw_type = 0;
+    char word[64];
+    int i;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    for (;;) {
+    
+        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+            p++;
+        }
+        
+        if (*p == '*') {
+        
+            saw_type = 1;
+            
+            p++;
+            continue;
+        
+        }
+        
+        if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+            break;
+        }
+        
+        i = 0;
+        
+        while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+        
+            if (i + 1 < (int) sizeof (word)) {
+                word[i++] = *p;
+            }
+            
+            p++;
+        
+        }
+        
+        word[i] = 0;
+        
+        if (strcmp (word, "char") != 0 &&
+            strcmp (word, "short") != 0 &&
+            strcmp (word, "int") != 0 &&
+            strcmp (word, "long") != 0 &&
+            strcmp (word, "signed") != 0 &&
+            strcmp (word, "unsigned") != 0 &&
+            strcmp (word, "void") != 0) {
+            return 0;
+        }
+        
+        saw_type = 1;
+    
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return saw_type && *p == ')';
+
+}
+
+static int const_integer_expr_text_is_foldable_now (const char *p) {
+
+    int saw_value_token = 0;
+    int saw_token = 0;
+    
+    char word[64];
+    int depth = 0, ch, i;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    {
+    
+        const char *q = p;
+        int parens = 0;
+        
+        while (*q == ' ' || *q == '\t' || *q == '\r' || *q == '\n') {
+            q++;
+        }
+        
+        while (*q == '(') {
+        
+            parens = 1;
+            q++;
+            
+            while (*q == ' ' || *q == '\t' || *q == '\r' || *q == '\n') {
+                q++;
+            }
+        
+        }
+        
+        if (fold_text_starts_with_type_name_only_before_rparen (p) || (parens && fold_text_starts_with_type_name_only_before_rparen (q))) {
+            return 0;
+        }
+    
+    }
+    
+    while (*p) {
+    
+        ch = (unsigned char) *p;
+        
+        if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') {
+        
+            p++;
+            continue;
+        
+        }
+        
+        if (depth == 0) {
+        
+            if (*p == ';' || *p == ',' || *p == '}' || *p == ']') {
+                break;
+            }
+            
+            /*
+             * This helper is only for folding a complete integer expression
+             * operand.  Do not claim that a leading parenthesized constant is
+             * foldable when it is followed by a lower-precedence operator such
+             * as the '<' in:
+             *
+             *     ((3) < (1 + n)) ? ...
+             *
+             * Returning true there makes the caller consume only '(3)' and then
+             * expect a closing parenthesis while the current token is '<'.
+             */
+            if (*p == ':' || *p == '?') {
+                return 0;
+            }
+            
+            if (*p == '<' || *p == '>' || *p == '=' || (*p == '!' && p[1] == '=')) {
+            
+                if ((p[0] == '<' && p[1] == '<') || (p[0] == '>' && p[1] == '>')) {
+                
+                    saw_token = 1;
+                    
+                    p += 2;
+                    continue;
+                
+                } else {
+                    return 0;
+                }
+            }
+            
+            if ((p[0] == '&' && p[1] == '&') || (p[0] == '|' && p[1] == '|')) {
+                return 0;
+            }
+        
+        }
+        
+        if (*p == '(') {
+        
+            depth++;
+            
+            saw_token = 1;
+            p++;
+            
+            continue;
+        
+        }
+        
+        if (*p == ')') {
+        
+            if (depth == 0) {
+            
+                /*
+                 * If the caller asks about text that starts inside a cast, the
+                 * scanner can see only the type-name prefix, for example:
+                 *
+                 *     unsigned char) ch
+                 *
+                 * That is not an integer constant expression.  Returning true
+                 * here sends the parser down expr_const64(), which then reports
+                 * "integer constant expression expected" at the cast.
+                 */
+                if (!saw_value_token) {
+                    return 0;
+                }
+                
+                break;
+            
+            }
+            
+            depth--;
+            p++;
+            
+            continue;
+        
+        }
+        
+        if (*p >= '0' && *p <= '9') {
+        
+            saw_value_token = 1;
+            saw_token = 1;
+            
+            p++;
+            
+            while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+                p++;
+            }
+            
+            continue;
+        
+        }
+        
+        if (*p == '\'') {
+        
+            saw_value_token = 1;
+            saw_token = 1;
+            
+            p++;
+            
+            while (*p && *p != '\'') {
+            
+                if (*p == '\\' && p[1]) {
+                    p += 2;
+                } else {
+                    p++;
+                }
+            
+            }
+            
+            if (*p == '\'') {
+                p++;
+            }
+            
+            continue;
+        
+        }
+        
+        if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_') {
+        
+            i = 0;
+            
+            while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+            
+                if (i + 1 < (int) sizeof (word)) {
+                    word[i++] = *p;
+                }
+                
+                p++;
+            
+            }
+            
+            word[i] = 0;
+            
+            if (strcmp (word, "sizeof") == 0) {
+                saw_value_token = 1;
+            }
+            
+            if (strcmp (word, "sizeof") != 0 &&
+                strcmp (word, "char") != 0 &&
+                strcmp (word, "short") != 0 &&
+                strcmp (word, "int") != 0 &&
+                strcmp (word, "long") != 0 &&
+                strcmp (word, "signed") != 0 &&
+                strcmp (word, "unsigned") != 0 &&
+                strcmp (word, "void") != 0) {
+                return 0;
+            }
+            
+            saw_token = 1;
+            continue;
+        
+        }
+        
+        if (*p == '+' || *p == '-' || *p == '*' || *p == '/' || *p == '%' || *p == '&' || *p == '|' || *p == '^' || *p == '~' || *p == '!' || *p == '<' || *p == '>') {
+        
+            saw_token = 1;
+            p++;
+            
+            continue;
+        
+        }
+        
+        return 0;
+    
+    }
+    
+    return saw_token;
+
+}
+
+static int token_kind_is_integer_constant_now (enum token_kind kind) {
+
+    return kind == TOK_CCHAR || kind == TOK_LCHAR ||
+           kind == TOK_CINT || kind == TOK_CUINT ||
+           kind == TOK_CLONG || kind == TOK_CULONG ||
+           kind == TOK_CLLONG || kind == TOK_CULLONG;
+
+}
+
+static int token_kind_is_binary_expression_operator_now (enum token_kind kind) {
+
+    return kind == TOK_PLUS || kind == TOK_MINUS || kind == TOK_STAR ||
+           kind == TOK_FSLASH || kind == TOK_MOD ||
+           kind == TOK_AMPER || kind == TOK_PIPE || kind == TOK_CARET ||
+           kind == TOK_LSH || kind == TOK_RSH ||
+           kind == TOK_LESS || kind == TOK_LTEQ ||
+           kind == TOK_GREATER || kind == TOK_GTEQ ||
+           kind == TOK_EQEQ || kind == TOK_NOTEQ ||
+           kind == TOK_LOGAND || kind == TOK_LOGOR;
+
+}
+
+static int current_integer_expr_is_foldable_now (void) {
+
+    struct token *saved_tok;
+    
+    enum token_kind first_kind;
+    enum token_kind next_kind;
+    
+    if (!const_integer_expr_text_is_foldable_now (tok.start)) {
+        return 0;
+    }
+    
+    /*
+     * Macro-expanded integer tokens can have tok.start/tok.caret pointing at
+     * only the replacement text (for example "16") rather than the complete
+     * source expression that follows it.  Do not hand such a prefix to
+     * expr_const64() as though it described the whole expression when the real
+     * token stream continues with a binary operator:
+     *
+     *     MEMMGR_ALIGN - (size_t)buffer % MEMMGR_ALIGN
+     *
+     * The normal expression parser can still handle this; this guard only
+     * disables the whole-expression constant-folder for that unsafe prefix.
+     */
+    if (!token_kind_is_integer_constant_now (tok.kind)) {
+        return 1;
+    }
+    
+    first_kind = tok.kind;
+    
+    saved_tok = clone_current_token_now ();
+    get_token ();
+    
+    next_kind = tok.kind;
+    unget_token (saved_tok);
+    
+    if (token_kind_is_integer_constant_now (first_kind) && token_kind_is_binary_expression_operator_now (next_kind)) {
+        return 0;
+    }
+    
+    return 1;
+
+}
+
+static void emit_load_const64_to_pair_now (const char *lo, const char *hi, int64_s v) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    mov %s, %lu\n", lo, v.low & U32_MASK);
+        fprintf (state->ofp, "    mov %s, %lu\n", hi, v.high & U32_MASK);
+    
+    } else {
+    
+        fprintf (state->ofp, "    movl $%lu, %%%s\n", v.low & U32_MASK, lo);
+        fprintf (state->ofp, "    movl $%lu, %%%s\n", v.high & U32_MASK, hi);
+    
+    }
+
+}
+
+static void emit_load_const32_to_reg_now (const char *reg, int64_s v) {
+
+    flush_pending_statement_labels ();
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    mov %s, %lu\n", reg, v.low & U32_MASK);
+    } else {
+        fprintf (state->ofp, "    movl $%lu, %%%s\n", v.low & U32_MASK, reg);
+    }
+
+}
+
+static void emit_load_address_to_reg_now (const char *reg, const char *symbol) {
+
+    const char *asm_symbol;
+    flush_pending_statement_labels ();
+    
+    if (!state->ofp || !symbol || !*symbol) {
+        return;
+    }
+    
+    emit_extern_reference_symbol (symbol, DATA_PTR);
+    asm_symbol = asm_global_symbol_name (symbol);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+            fprintf (state->ofp, "    mov %s, %s\n", reg, asm_symbol);
+        } else {
+            fprintf (state->ofp, "    mov %s, offset %s\n", reg, asm_symbol);
+        }
+    
+    } else {
+        fprintf (state->ofp, "    movl $%s, %%%s\n", asm_symbol, reg);
+    }
+
+}
+
+static void emit_load_deref_reg_ex_now (const char *reg, int size, int is_unsigned);
+static void emit_load_deref_reg_now (const char *reg, int size);
+
+static int emit_load_parenthesized_indirect_member_to_reg_now (const char *reg);
+static int emit_parse_postfix_copy_source_address_now (const char *reg, struct local_symbol *src, const char *src_name, const char *name_start, const char *name_caret, unsigned long name_line);
+
+static void emit_load_postfix_lvalue_address_to_pair_ex_now (const char *lo, const char *hi, int size, int is_unsigned) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (size > (DATA_PTR & 0x1f)) {
+    
+        emit_push_reg_now (lo);
+        
+        emit_load_deref_reg_now (lo, DATA_PTR & 0x1f);
+        emit_pop_reg_now (hi);
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            if (state->syntax & ASM_SYNTAX_NASM) {
+                fprintf (state->ofp, "    mov %s, dword [%s + 4]\n", hi, hi);
+            } else {
+                fprintf (state->ofp, "    mov %s, dword ptr [%s + 4]\n", hi, hi);
+            }
+        
+        } else {
+            fprintf (state->ofp, "    movl 4(%%%s), %%%s\n", hi, hi);
+        }
+    
+    } else {
+    
+        emit_load_deref_reg_ex_now (lo, size, is_unsigned);
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
+        } else {
+            fprintf (state->ofp, "    xorl %%%s, %%%s\n", hi, hi);
+        }
+    
+    }
+
+}
+
+static void emit_store_pair_to_deref_reg_now (const char *addr_reg, const char *lo, const char *hi) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+        
+            fprintf (state->ofp, "    mov dword [%s], %s\n", addr_reg, lo);
+            fprintf (state->ofp, "    mov dword [%s + 4], %s\n", addr_reg, hi);
+        
+        } else {
+        
+            fprintf (state->ofp, "    mov dword ptr [%s], %s\n", addr_reg, lo);
+            fprintf (state->ofp, "    mov dword ptr [%s + 4], %s\n", addr_reg, hi);
+        
+        }
+    
+    } else {
+    
+        fprintf (state->ofp, "    movl %%%s, (%%%s)\n", lo, addr_reg);
+        fprintf (state->ofp, "    movl %%%s, 4(%%%s)\n", hi, addr_reg);
+    
+    }
+
+}
+
+static void emit_load_pair_from_deref_reg_now (const char *lo, const char *hi, const char *addr_reg) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+        
+            fprintf (state->ofp, "    mov %s, dword [%s]\n", lo, addr_reg);
+            fprintf (state->ofp, "    mov %s, dword [%s + 4]\n", hi, addr_reg);
+        
+        } else {
+        
+            fprintf (state->ofp, "    mov %s, dword ptr [%s]\n", lo, addr_reg);
+            fprintf (state->ofp, "    mov %s, dword ptr [%s + 4]\n", hi, addr_reg);
+        
+        }
+    
+    } else {
+    
+        fprintf (state->ofp, "    movl (%%%s), %%%s\n", addr_reg, lo);
+        fprintf (state->ofp, "    movl 4(%%%s), %%%s\n", addr_reg, hi);
+    
+    }
+
+}
+
+static void emit_copy_reg_now (const char *dst, const char *src) {
+
+    if (!state->ofp || !dst || !src || strcmp (dst, src) == 0) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    mov %s, %s\n", dst, src);
+    } else {
+        fprintf (state->ofp, "    movl %%%s, %%%s\n", src, dst);
+    }
+
+}
+
+static int emit_parse_builtin_va_arg_address_to_reg_now (const char *reg, int *out_size, int *out_unsigned, int *out_pointer, int *out_floating);
+static int rhs_current_operand_is_floating_now (void);
+static int token_is_floating_constant_now (void);
+
+static void emit_store_floating_member_to_addr_reg_now (const char *addr_reg, int offset, int size);
+static void emit_load_floating_rhs_expression_now (int result_size);
+static void emit_load_assignment_rhs_to_reg (const char *reg);
+static void emit_floating_stack_to_int_pair_now (const char *lo, const char *hi);
+static void emit_integer_pair_to_floating_stack_now (const char *lo, const char *hi, int size);
+
+static void emit_load_assignment_rhs_to_pair (const char *lo, const char *hi) {
+
+    if (_accept (TOK_LPAREN)) {
+    
+        if (token_starts_type_name ()) {
+        
+            int cast_size = 0;
+            int cast_is_unsigned = 0;
+            int cast_is_pointer = 0;
+            
+            if (parse_cast_type_name (&cast_size, &cast_is_unsigned, &cast_is_pointer)) {
+            
+                if (!cast_is_pointer && !last_cast_type_is_floating && rhs_current_operand_is_floating_now ()) {
+                
+                    emit_load_floating_rhs_expression_now (DATA_DOUBLE & 0x1f);
+                    
+                    if (floating_rhs_result_in_eax_bool) {
+                    
+                        if (strcmp (lo, "eax") != 0 && state->ofp) {
+                        
+                            if (state->syntax & ASM_SYNTAX_INTEL) {
+                                fprintf (state->ofp, "    mov %s, eax\n", lo);
+                            } else {
+                                fprintf (state->ofp, "    movl %%eax, %%%s\n", lo);
+                            }
+                        
+                        }
+                        
+                        emit_extend_pair_high_from_low (lo, hi, cast_size, cast_is_unsigned);
+                        floating_rhs_result_in_eax_bool = 0;
+                    
+                    } else {
+                    
+                        emit_floating_stack_to_int_pair_now (lo, hi);
+                        
+                        if ((cast_size & 0x1f) != (DATA_LLONG & 0x1f)) {
+                            emit_extend_pair_high_from_low (lo, hi, cast_size, cast_is_unsigned);
+                        }
+                    
+                    }
+                    
+                    return;
+                
+                }
+                
+                emit_load_assignment_rhs_to_pair (lo, hi);
+                
+                {
+                
+                    int applied_postfix = 0;
+                    
+                    if (cast_is_pointer) {
+                        set_rhs_last_pointer_info (1, cast_size > 0 ? cast_size : (DATA_INT & 0x1f));
+                    } else {
+                        emit_extend_pair_high_from_low (lo, hi, cast_size, cast_is_unsigned);
+                    }
+                    
+                    postfix_member_seen = 0;
+                    
+                    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+                    
+                        applied_postfix = 1;
+                        emit_apply_postfix_member_access_to_reg_now (lo);
+                    
+                    }
+                    
+                    if (applied_postfix && postfix_member_seen) {
+                    
+                        if (postfix_member_size == (DATA_LLONG & 0x1f) && !postfix_member_is_floating) {
+                        
+                            const char *addr_reg = (strcmp (lo, "ecx") != 0 && strcmp (hi, "ecx") != 0) ? "ecx" : "esi";
+                            
+                            emit_copy_reg_now (addr_reg, lo);
+                            emit_load_pair_from_deref_reg_now (lo, hi, addr_reg);
+                        
+                        } else {
+                            emit_extend_pair_high_from_low (lo, hi, postfix_member_size, postfix_member_is_unsigned);
+                        }
+                    
+                    }
+                
+                }
+                
+                return;
+            
+            }
+        
+        }
+        
+        if (tok.kind != TOK_LPAREN && current_integer_expr_is_foldable_now ()) {
+        
+            int64_s v = const64_from_current_foldable_expr ();
+            expect (TOK_RPAREN, ")");
+            
+            emit_load_const64_to_pair_now (lo, hi, v);
+            return;
+        
+        }
+        
+        if (emit_load_parenthesized_indirect_member_to_reg_now (lo)) {
+        
+            emit_extend_pair_high_from_low (lo, hi, DATA_INT & 0x1f, 1);
+            return;
+        
+        }
+        
+        emit_load_assignment_rhs_expression_to_pair (lo, hi, 1);
+        expect (TOK_RPAREN, ")");
+        
+        {
+        
+            int applied_postfix = 0;
+            postfix_member_seen = 0;
+            
+            while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+            
+                applied_postfix = 1;
+                emit_apply_postfix_member_access_to_reg_now (lo);
+            
+            }
+            
+            if (applied_postfix && postfix_member_seen) {
+            
+                if (postfix_member_size == (DATA_LLONG & 0x1f) && !postfix_member_is_floating) {
+                
+                    const char *addr_reg = (strcmp (lo, "ecx") != 0 && strcmp (hi, "ecx") != 0) ? "ecx" : "esi";
+                    
+                    emit_copy_reg_now (addr_reg, lo);
+                    emit_load_pair_from_deref_reg_now (lo, hi, addr_reg);
+                
+                } else {
+                    emit_extend_pair_high_from_low (lo, hi, postfix_member_size, postfix_member_is_unsigned);
+                }
+            
+            }
+        
+        }
+            
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_PLUS || tok.kind == TOK_MINUS || tok.kind == TOK_TILDE || tok.kind == TOK_XMARK) {
+    
+        enum token_kind unary_op = tok.kind;
+        get_token ();
+        
+        emit_load_assignment_rhs_to_pair (lo, hi);
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                if (unary_op == TOK_MINUS) {
+                
+                    fprintf (state->ofp, "    not %s\n", lo);
+                    fprintf (state->ofp, "    not %s\n", hi);
+                    
+                    fprintf (state->ofp, "    add %s, 1\n", lo);
+                    fprintf (state->ofp, "    adc %s, 0\n", hi);
+                
+                } else if (unary_op == TOK_TILDE) {
+                
+                    fprintf (state->ofp, "    not %s\n", lo);
+                    fprintf (state->ofp, "    not %s\n", hi);
+                
+                } else if (unary_op == TOK_XMARK) {
+                
+                    fprintf (state->ofp, "    or %s, %s\n", lo, hi);
+                    fprintf (state->ofp, "    setz al\n");
+                    fprintf (state->ofp, "    movzx eax, al\n");
+                    
+                    if (strcmp (lo, "eax") != 0) {
+                        fprintf (state->ofp, "    mov %s, eax\n", lo);
+                    }
+                    
+                    fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
+                
+                }
+            
+            } else {
+            
+                if (unary_op == TOK_MINUS) {
+                
+                    fprintf (state->ofp, "    notl %%%s\n", lo);
+                    fprintf (state->ofp, "    notl %%%s\n", hi);
+                    
+                    fprintf (state->ofp, "    addl $1, %%%s\n", lo);
+                    fprintf (state->ofp, "    adcl $0, %%%s\n", hi);
+                
+                } else if (unary_op == TOK_TILDE) {
+                
+                    fprintf (state->ofp, "    notl %%%s\n", lo);
+                    fprintf (state->ofp, "    notl %%%s\n", hi);
+                
+                } else if (unary_op == TOK_XMARK) {
+                
+                    fprintf (state->ofp, "    orl %%%s, %%%s\n", hi, lo);
+                    fprintf (state->ofp, "    setz %%al\n");
+                    fprintf (state->ofp, "    movzbl %%al, %%eax\n");
+                    
+                    if (strcmp (lo, "eax") != 0) {
+                        fprintf (state->ofp, "    movl %%eax, %%%s\n", lo);
+                    }
+                    
+                    fprintf (state->ofp, "    xorl %%%s, %%%s\n", hi, hi);
+                
+                }
+            
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (emit_load_prefix_incdec_to_pair_now (lo, hi)) {
+        return;
+    }
+    
+    if (tok.kind == TOK_STAR) {
+    
+        char *name;
+        
+        const char *name_start;
+        const char *name_caret;
+        
+        unsigned long name_line;
+        struct local_symbol *src;
+        
+        int global_index;
+        
+        int deref_size = DATA_INT & 0x1f;
+        int deref_unsigned = 1;
+        
+        int postfix_incdec = 0;
+        
+        enum token_kind postfix_op = TOK_EOF;
+        get_token ();
+        
+        name_start = tok.start;
+        name_caret = tok.caret;
+        name_line = get_line_number ();
+        
+        if (tok.kind == TOK_LPAREN) {
+        
+            const char *addr_reg = (strcmp (lo, "ecx") != 0 && strcmp (hi, "ecx") != 0) ? "ecx" : "esi";
+            int cast_deref_size = DATA_INT & 0x1f;
+            
+            get_token ();
+            
+            if (is_type_start (tok.kind) && parse_deref_cast_type_name (&cast_deref_size)) {
+            
+                emit_load_assignment_rhs_to_reg (lo);
+                
+                if ((cast_deref_size & 0x1f) == (DATA_LLONG & 0x1f)) {
+                
+                    emit_copy_reg_now (addr_reg, lo);
+                    emit_load_pair_from_deref_reg_now (lo, hi, addr_reg);
+                
+                } else {
+                
+                    emit_load_deref_reg_now (lo, cast_deref_size);
+                    emit_extend_pair_high_from_low (lo, hi, cast_deref_size, 1);
+                
+                }
+                
+                return;
+            
+            }
+            
+            emit_load_assignment_rhs_expression_to_reg (lo);
+            expect (TOK_RPAREN, ")");
+            
+            emit_load_deref_reg_now (lo, DATA_INT & 0x1f);
+            emit_extend_pair_high_from_low (lo, hi, DATA_INT & 0x1f, 1);
+            
+            return;
+        
+        }
+        
+        if (tok.kind != TOK_IDENT || !tok.ident) {
+        
+            int64_s zero;
+            
+            zero.low = 0;
+            zero.high = 0;
+            
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
+            
+            emit_load_const64_to_pair_now (lo, hi, zero);
+            return;
+        
+        }
+        
+        name = xstrdup (tok.ident);
+        get_token ();
+        
+        src = find_local_symbol (name);
+        global_index = find_global_symbol (name);
+        
+        if (!src && global_index >= 0 && tok.kind == TOK_LPAREN &&
+            get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION) {
+        
+            const char *addr_reg = (strcmp (lo, "ecx") != 0 && strcmp (hi, "ecx") != 0) ? "ecx" : "esi";
+            int fptr_depth = get_global_symbol_pointer_depth (name);
+            int fpointed_size = get_global_symbol_pointed_size (name);
+            
+            if (get_global_symbol_returns_void (name)) {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "void function '%s' used as a value", name);
+            }
+            
+            emit_call_identifier_to_reg_now (name, lo, name_start, name_caret, name_line);
+            
+            if (fptr_depth > 1) {
+                deref_size = DATA_PTR & 0x1f;
+            } else if (fptr_depth == 1 && fpointed_size > 0) {
+                deref_size = fpointed_size & 0x1f;
+            }
+            
+            if (deref_size == (DATA_LLONG & 0x1f)) {
+            
+                emit_copy_reg_now (addr_reg, lo);
+                emit_load_pair_from_deref_reg_now (lo, hi, addr_reg);
+            
+            } else {
+            
+                emit_load_deref_reg_now (lo, deref_size);
+                emit_extend_pair_high_from_low (lo, hi, deref_size, 1);
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+        
+            postfix_incdec = 1;
+            postfix_op = tok.kind;
+            
+            get_token ();
+        
+        }
+        
+        if (src) {
+        
+            if (src->pointer_depth > 1) {
+                deref_size = DATA_PTR & 0x1f;
+            } else if (src->pointer_depth == 1 && src->pointed_size > 0) {
+                deref_size = src->pointed_size & 0x1f;
+            }
+            
+            if (src->is_static && src->static_label) {
+                emit_load_global_to_reg (lo, src->static_label, DATA_PTR);
+            } else {
+                emit_load_local_to_reg (lo, src->offset, DATA_PTR);
+            }
+        
+        } else if (global_index >= 0) {
+        
+            if (get_global_symbol_pointer_depth (name) > 1) {
+                deref_size = DATA_PTR & 0x1f;
+            } else if (get_global_symbol_pointer_depth (name) == 1 && get_global_symbol_pointed_size (name) > 0) {
+                deref_size = get_global_symbol_pointed_size (name) & 0x1f;
+            }
+            
+            emit_load_global_to_reg (lo, name, DATA_PTR);
+        
+        } else {
+        
+            int64_s zero;
+            
+            zero.low = 0;
+            zero.high = 0;
+            
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            
+            emit_load_const64_to_pair_now (lo, hi, zero);
+            free (name);
+            
+            return;
+        
+        }
+        
+        if (deref_size == (DATA_LLONG & 0x1f)) {
+        
+            emit_push_reg_now (lo);
+            
+            emit_load_deref_reg_now (lo, DATA_INT & 0x1f);
+            emit_pop_reg_now (hi);
+            
+            if (state->ofp) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    if (state->syntax & ASM_SYNTAX_NASM) {
+                        fprintf (state->ofp, "    mov %s, dword [%s + 4]\n", hi, hi);
+                    } else {
+                        fprintf (state->ofp, "    mov %s, dword ptr [%s + 4]\n", hi, hi);
+                    }
+                
+                } else {
+                    fprintf (state->ofp, "    movl 4(%%%s), %%%s\n", hi, hi);
+                }
+            
+            }
+        
+        } else {
+        
+            emit_load_deref_reg_now (lo, deref_size);
+            emit_extend_pair_high_from_low (lo, hi, deref_size, deref_unsigned);
+        
+        }
+        
+        if (postfix_incdec) {
+        
+            emit_push_reg_now (lo);
+            emit_push_reg_now (hi);
+            
+            emit_incdec_symbol_now (src, name, postfix_op, name_line, name_start, name_caret);
+            
+            emit_pop_reg_now (hi);
+            emit_pop_reg_now (lo);
+        
+        }
+        
+        free (name);
+        return;
+    
+    }
+    
+    if (token_is_sizeof_keyword ()) {
+    
+        int64_s v = sizeof_from_current_token ();
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                fprintf (state->ofp, "    mov %s, %lu\n", lo, v.low & U32_MASK);
+                fprintf (state->ofp, "    mov %s, %lu\n", hi, v.high & U32_MASK);
+            
+            } else {
+            
+                fprintf (state->ofp, "    movl $%lu, %%%s\n", v.low & U32_MASK, lo);
+                fprintf (state->ofp, "    movl $%lu, %%%s\n", v.high & U32_MASK, hi);
+            
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_SCC_BUILTIN_VA_ARG) {
+    
+        int va_size = DATA_INT & 0x1f;
+        int va_unsigned = 1;
+        int va_pointer = 0;
+        int va_floating = 0;
+        
+        const char *addr_reg = (strcmp (lo, "ecx") != 0 && strcmp (hi, "ecx") != 0) ? "ecx" : "esi";
+        
+        get_token ();
+        emit_parse_builtin_va_arg_address_to_reg_now (addr_reg, &va_size, &va_unsigned, &va_pointer, &va_floating);
+        
+        if (va_size == (DATA_LLONG & 0x1f) && va_pointer == 0) {
+            emit_load_pair_from_deref_reg_now (lo, hi, addr_reg);
+        } else {
+        
+            emit_copy_reg_now (lo, addr_reg);
+            emit_load_deref_reg_now (lo, va_size);
+            
+            emit_extend_pair_high_from_low (lo, hi, va_size, va_unsigned);
+        
+        }
+        
+        return;
+    
+    }
+
+    if (tok.kind == TOK_IDENT) {
+    
+        enum token_kind postfix_op = TOK_EOF;
+        char *name = xstrdup (tok.ident);
+        
+        const char *name_start = tok.start, *name_caret = tok.caret;
+        unsigned long name_line = get_line_number ();
+        
+        int postfix_incdec = 0;
+        
+        struct local_symbol *src;
+        int64_s enum_value;
+        
+        get_token ();
+        
+        if (strcmp (name, "__scc_builtin_va_arg") == 0 && tok.kind == TOK_LPAREN) {
+        
+            int va_size = DATA_INT & 0x1f;
+            int va_unsigned = 1;
+            int va_pointer = 0;
+            int va_floating = 0;
+            
+            const char *addr_reg = (strcmp (lo, "ecx") != 0 && strcmp (hi, "ecx") != 0) ? "ecx" : "esi";
+            emit_parse_builtin_va_arg_address_to_reg_now (addr_reg, &va_size, &va_unsigned, &va_pointer, &va_floating);
+            
+            if (va_size == (DATA_LLONG & 0x1f) && !va_floating && va_pointer == 0) {
+                emit_load_pair_from_deref_reg_now (lo, hi, addr_reg);
+            } else {
+            
+                emit_copy_reg_now (lo, addr_reg);
+                emit_load_deref_reg_now (lo, va_size);
+                emit_extend_pair_high_from_low (lo, hi, va_size, va_unsigned);
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (!find_local_symbol (name) && find_global_symbol (name) < 0 && resolve_enum_constant (name, &enum_value)) {
+        
+            emit_load_const64_to_pair_now (lo, hi, enum_value);
+            
+            free (name);
+            return;
+        
+        }
+
+        if (tok.kind == TOK_LPAREN) {
+        
+            if (!find_local_symbol (name)) {
+                ensure_global_function_symbol (name, name_start, name_caret, name_line);
+            }
+            
+            if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION && get_global_symbol_returns_void (name)) {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "void function '%s' used as a value", name);
+            }
+            
+            emit_call_identifier_to_reg_now (name, "eax", name_start, name_caret, name_line);
+            
+            if (get_global_function_returns_floating (name)) {
+            
+                if (state->ofp) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                    
+                        fprintf (state->ofp, "    sub esp, 8\n");
+                        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fstp qword [esp]\n" : "    fstp qword ptr [esp]\n");
+                        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [esp]\n" : "    mov %s, dword ptr [esp]\n", lo);
+                        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [esp + 4]\n" : "    mov %s, dword ptr [esp + 4]\n", hi);
+                        fprintf (state->ofp, "    add esp, 8\n");
+                    
+                    } else {
+                    
+                        fprintf (state->ofp, "    subl $8, %%esp\n");
+                        fprintf (state->ofp, "    fstpl (%%esp)\n");
+                        fprintf (state->ofp, "    movl (%%esp), %%%s\n", lo);
+                        fprintf (state->ofp, "    movl 4(%%esp), %%%s\n", hi);
+                        fprintf (state->ofp, "    addl $8, %%esp\n");
+                    
+                    }
+                
+                }
+                
+                free (name);
+                return;
+            }
+            
+            if (state->ofp) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    if (strcmp (lo, "eax") != 0) {
+                        fprintf (state->ofp, "    mov %s, eax\n", lo);
+                    }
+                    
+                    if (strcmp (hi, "edx") != 0) {
+                        fprintf (state->ofp, "    mov %s, edx\n", hi);
+                    }
+                
+                } else {
+                
+                    if (strcmp (lo, "eax") != 0) {
+                        fprintf (state->ofp, "    movl %%eax, %%%s\n", lo);
+                    }
+                    
+                    if (strcmp (hi, "edx") != 0) {
+                        fprintf (state->ofp, "    movl %%edx, %%%s\n", hi);
+                    }
+                
+                }
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+        
+            postfix_incdec = 1;
+            postfix_op = tok.kind;
+            
+            get_token ();
+        
+        }
+
+        src = find_local_symbol (name);
+        
+        if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT || tok.kind == TOK_LBRACK) {
+        
+            int source_size;
+            
+            if (src || find_global_symbol (name) >= 0) {
+            
+                if (tok.kind == TOK_ARROW || tok.kind == TOK_LBRACK) {
+                
+                    if (src) {
+                    
+                        postfix_copy_lvalue_size = src->pointer_depth > 0 ? src->pointed_size : src->size;
+                        postfix_copy_lvalue_tag_name = src->pointer_depth > 0 ? src->pointed_tag_name : src->tag_name;
+                    
+                    } else {
+                    
+                        postfix_copy_lvalue_size = get_global_symbol_pointer_depth (name) > 0 ? get_global_symbol_pointed_size (name) : get_global_symbol_size (name);
+                        postfix_copy_lvalue_tag_name = 0;
+                    
+                    }
+                
+                } else if (src) {
+                
+                    postfix_copy_lvalue_size = src->size;
+                    postfix_copy_lvalue_tag_name = src->tag_name;
+                
+                } else {
+                
+                    postfix_copy_lvalue_size = get_global_symbol_size (name);
+                    postfix_copy_lvalue_tag_name = get_global_symbol_tag_name (name);
+                
+                }
+                
+                if (!emit_parse_postfix_copy_source_address_now (lo, src, name, name_start, name_caret, name_line)) {
+                
+                    free (name);
+                    return;
+                
+                }
+                
+                source_size = postfix_copy_lvalue_size;
+                
+                if (source_size <= 0) {
+                    source_size = DATA_INT & 0x1f;
+                }
+                
+                if (is_assignment_operator (tok.kind)) {
+                
+                    enum token_kind assign_op = tok.kind;
+                    
+                    const char *addr_reg = (strcmp (lo, "ecx") != 0 && strcmp (hi, "ecx") != 0) ? "ecx" : "edx";
+                    int lvalue_size = index_step_size (source_size);
+                    
+                    get_token ();
+                    
+                    if (assign_op == TOK_ASSIGN && (postfix_member_is_floating || token_is_floating_constant_now () || rhs_current_operand_is_floating_now ())) {
+                    
+                        emit_push_reg_now (lo);
+                        emit_load_floating_rhs_expression_now (lvalue_size);
+                        
+                        emit_pop_reg_now (addr_reg);
+                        emit_store_floating_member_to_addr_reg_now (addr_reg, 0, lvalue_size);
+                        
+                        free (name);
+                        return;
+                    }
+                    
+                    if (assign_op == TOK_ASSIGN && lvalue_size == (DATA_LLONG & 0x1f)) {
+                    
+                        emit_push_reg_now (lo);
+                        
+                        emit_load_assignment_rhs_expression_to_pair (lo, hi, 1);
+                        emit_pop_reg_now (addr_reg);
+                        
+                        emit_store_pair_to_deref_reg_now (addr_reg, lo, hi);
+                        
+                        free (name);
+                        return;
+                    
+                    }
+                    
+                    if (assign_op == TOK_ASSIGN) {
+                    
+                        emit_push_reg_now (lo);
+                        
+                        emit_load_assignment_rhs_expression_to_reg (lo);
+                        emit_extend_pair_high_from_low (lo, hi, lvalue_size, 1);
+                        
+                        emit_pop_reg_now (addr_reg);
+                        emit_store_reg_to_deref_reg_now (addr_reg, lo, lvalue_size);
+                        
+                        free (name);
+                        return;
+                    
+                    }
+                    
+                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "compound member assignment expression not implemented in 64-bit context");
+                    
+                    free (name);
+                    return;
+                
+                }
+                
+                emit_load_postfix_lvalue_address_to_pair_ex_now (lo, hi, source_size, src ? (src->pointer_depth > 0 ? src->pointed_is_unsigned : src->is_unsigned) : (get_global_symbol_pointer_depth (name) > 0 ? get_global_symbol_pointed_is_unsigned (name) : get_global_symbol_unsigned (name)));
+                
+                free (name);
+                return;
+            
+            }
+        
+        }
+        
+        if (src) {
+        
+            if (src->size == (DATA_LLONG & 0x1f) && !src->is_floating) {
+            
+                if (src->is_static && src->static_label) {
+                    emit_load_global64_to_pair (lo, hi, src->static_label);
+                } else {
+                    emit_load_local64_to_pair (src->offset, lo, hi);
+                }
+            
+            } else {
+            
+                if (src->is_static && src->static_label) {
+                    emit_load_global_to_reg_ex (lo, src->static_label, src->size, src->is_unsigned);
+                } else {
+                    emit_load_local_to_reg_ex (lo, src->offset, src->size, src->is_unsigned);
+                }
+                
+                emit_extend_pair_high_from_low (lo, hi, src->size, src->is_unsigned);
+            
+            }
+            
+            if (postfix_incdec) {
+            
+                emit_push_reg_now (lo);
+                emit_push_reg_now (hi);
+                
+                emit_incdec_symbol_now (src, name, postfix_op, name_line, name_start, name_caret);
+                
+                emit_pop_reg_now (hi);
+                emit_pop_reg_now (lo);
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (find_global_symbol (name) >= 0) {
+        
+            if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION ||
+                get_global_symbol_array (name) ||
+                (!get_global_symbol_pointer_depth (name) &&
+                    get_global_symbol_size (name) > (DATA_PTR & 0x1f))) {
+            
+                /*
+                 * In a 64-bit/pair context, an array/function/aggregate
+                 * expression still decays to its address.  The 32-bit RHS
+                 * path already handled this, but this path was used when
+                 * the caller requested eax:edx (for example a mis-sized
+                 * pointer return).  Loading the first word of the global
+                 * table produced bogus pseudo-op table pointers such as the
+                 * first string pointer instead of &table.
+                 */
+                emit_load_address_to_reg_now (lo, name);
+                if (state->ofp) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
+                    } else {
+                        fprintf (state->ofp, "    xorl %%%s, %%%s\n", hi, hi);
+                    }
+                
+                }
+            
+            } else if (get_global_symbol_size (name) == (DATA_LLONG & 0x1f) && !get_global_symbol_floating (name)) {
+                emit_load_global64_to_pair (lo, hi, name);
+            } else {
+            
+                emit_load_global_to_reg_ex (lo, name, get_global_symbol_size (name), get_global_symbol_unsigned (name));
+                emit_extend_pair_high_from_low (lo, hi, get_global_symbol_size (name), get_global_symbol_unsigned (name));
+            
+            }
+            
+            if (postfix_incdec) {
+            
+                emit_push_reg_now (lo);
+                emit_push_reg_now (hi);
+                
+                emit_incdec_symbol_now (0, name, postfix_op, name_line, name_start, name_caret);
+                
+                emit_pop_reg_now (hi);
+                emit_pop_reg_now (lo);
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        free (name);
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                fprintf (state->ofp, "    xor %s, %s\n", lo, lo);
+                fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
+            
+            } else {
+            
+                fprintf (state->ofp, "    xorl %%%s, %%%s\n", lo, lo);
+                fprintf (state->ofp, "    xorl %%%s, %%%s\n", hi, hi);
+            
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (recover_unknown_rhs_identifier ()) {
+    
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                fprintf (state->ofp, "    xor %s, %s\n", lo, lo);
+                fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
+            
+            } else {
+            
+                fprintf (state->ofp, "    xorl %%%s, %%%s\n", lo, lo);
+                fprintf (state->ofp, "    xorl %%%s, %%%s\n", hi, hi);
+            
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    {
+    
+        int64_s v = const64_from_current_operand ();
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                fprintf (state->ofp, "    mov %s, %lu\n", lo, v.low & U32_MASK);
+                fprintf (state->ofp, "    mov %s, %lu\n", hi, v.high & U32_MASK);
+            
+            } else {
+            
+                fprintf (state->ofp, "    movl $%lu, %%%s\n", v.low & U32_MASK, lo);
+                fprintf (state->ofp, "    movl $%lu, %%%s\n", v.high & U32_MASK, hi);
+            
+            }
+        
+        }
+    
+    }
+
+}
+
+static void emit_assignment_divmod64_intel (int is_unsigned, int want_mod) {
+
+    int loop_label, sub_label, nosub_label;
+    int lhs_pos_label, rhs_pos_label;
+    int qpos_label, rpos_label;
+    
+    loop_label = anon_label++;
+    sub_label = anon_label++;
+    nosub_label = anon_label++;
+    lhs_pos_label = anon_label++;
+    rhs_pos_label = anon_label++;
+    qpos_label = anon_label++;
+    rpos_label = anon_label++;
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+    
+        fprintf (state->ofp, "    sub esp, 40\n");
+        fprintf (state->ofp, "    mov dword ptr [esp], eax\n");
+        fprintf (state->ofp, "    mov dword ptr [esp + 4], edx\n");
+        fprintf (state->ofp, "    mov dword ptr [esp + 8], ebx\n");
+        fprintf (state->ofp, "    mov dword ptr [esp + 12], ecx\n");
+        fprintf (state->ofp, "    xor eax, eax\n");
+        fprintf (state->ofp, "    mov dword ptr [esp + 16], eax\n");
+        fprintf (state->ofp, "    mov dword ptr [esp + 20], eax\n");
+        fprintf (state->ofp, "    mov dword ptr [esp + 24], eax\n");
+        fprintf (state->ofp, "    mov dword ptr [esp + 28], eax\n");
+        fprintf (state->ofp, "    mov dword ptr [esp + 32], eax\n");
+        fprintf (state->ofp, "    mov dword ptr [esp + 36], eax\n");
+        
+        if (!is_unsigned) {
+        
+            fprintf (state->ofp, "    test dword ptr [esp + 4], 80000000h\n");
+            fprintf (state->ofp, "    jz L%d\n", lhs_pos_label);
+            fprintf (state->ofp, "    not dword ptr [esp]\n");
+            fprintf (state->ofp, "    not dword ptr [esp + 4]\n");
+            fprintf (state->ofp, "    add dword ptr [esp], 1\n");
+            fprintf (state->ofp, "    adc dword ptr [esp + 4], 0\n");
+            fprintf (state->ofp, "    mov dword ptr [esp + 32], 1\n");
+            fprintf (state->ofp, "    xor dword ptr [esp + 36], 1\n");
+            fprintf (state->ofp, "L%d:\n", lhs_pos_label);
+            fprintf (state->ofp, "    test dword ptr [esp + 12], 80000000h\n");
+            fprintf (state->ofp, "    jz L%d\n", rhs_pos_label);
+            fprintf (state->ofp, "    not dword ptr [esp + 8]\n");
+            fprintf (state->ofp, "    not dword ptr [esp + 12]\n");
+            fprintf (state->ofp, "    add dword ptr [esp + 8], 1\n");
+            fprintf (state->ofp, "    adc dword ptr [esp + 12], 0\n");
+            fprintf (state->ofp, "    xor dword ptr [esp + 36], 1\n");
+            fprintf (state->ofp, "L%d:\n", rhs_pos_label);
+        
+        }
+        
+        fprintf (state->ofp, "    mov esi, 64\n");
+        fprintf (state->ofp, "L%d:\n", loop_label);
+        fprintf (state->ofp, "    shl dword ptr [esp], 1\n");
+        fprintf (state->ofp, "    rcl dword ptr [esp + 4], 1\n");
+        fprintf (state->ofp, "    rcl dword ptr [esp + 24], 1\n");
+        fprintf (state->ofp, "    rcl dword ptr [esp + 28], 1\n");
+        fprintf (state->ofp, "    shl dword ptr [esp + 16], 1\n");
+        fprintf (state->ofp, "    rcl dword ptr [esp + 20], 1\n");
+        fprintf (state->ofp, "    mov eax, dword ptr [esp + 28]\n");
+        fprintf (state->ofp, "    cmp eax, dword ptr [esp + 12]\n");
+        fprintf (state->ofp, "    ja L%d\n", sub_label);
+        fprintf (state->ofp, "    jb L%d\n", nosub_label);
+        fprintf (state->ofp, "    mov eax, dword ptr [esp + 24]\n");
+        fprintf (state->ofp, "    cmp eax, dword ptr [esp + 8]\n");
+        fprintf (state->ofp, "    jb L%d\n", nosub_label);
+        fprintf (state->ofp, "L%d:\n", sub_label);
+        fprintf (state->ofp, "    mov eax, dword ptr [esp + 8]\n");
+        fprintf (state->ofp, "    sub dword ptr [esp + 24], eax\n");
+        fprintf (state->ofp, "    mov eax, dword ptr [esp + 12]\n");
+        fprintf (state->ofp, "    sbb dword ptr [esp + 28], eax\n");
+        fprintf (state->ofp, "    or dword ptr [esp + 16], 1\n");
+        fprintf (state->ofp, "L%d:\n", nosub_label);
+        fprintf (state->ofp, "    dec esi\n");
+        fprintf (state->ofp, "    jnz L%d\n", loop_label);
+        
+        if (!is_unsigned) {
+        
+            fprintf (state->ofp, "    cmp dword ptr [esp + 36], 0\n");
+            fprintf (state->ofp, "    je L%d\n", qpos_label);
+            fprintf (state->ofp, "    not dword ptr [esp + 16]\n");
+            fprintf (state->ofp, "    not dword ptr [esp + 20]\n");
+            fprintf (state->ofp, "    add dword ptr [esp + 16], 1\n");
+            fprintf (state->ofp, "    adc dword ptr [esp + 20], 0\n");
+            fprintf (state->ofp, "L%d:\n", qpos_label);
+            fprintf (state->ofp, "    cmp dword ptr [esp + 32], 0\n");
+            fprintf (state->ofp, "    je L%d\n", rpos_label);
+            fprintf (state->ofp, "    not dword ptr [esp + 24]\n");
+            fprintf (state->ofp, "    not dword ptr [esp + 28]\n");
+            fprintf (state->ofp, "    add dword ptr [esp + 24], 1\n");
+            fprintf (state->ofp, "    adc dword ptr [esp + 28], 0\n");
+            fprintf (state->ofp, "L%d:\n", rpos_label);
+        
+        }
+        
+        if (want_mod) {
+        
+            fprintf (state->ofp, "    mov eax, dword ptr [esp + 24]\n");
+            fprintf (state->ofp, "    mov edx, dword ptr [esp + 28]\n");
+        
+        } else {
+        
+            fprintf (state->ofp, "    mov eax, dword ptr [esp + 16]\n");
+            fprintf (state->ofp, "    mov edx, dword ptr [esp + 20]\n");
+        
+        }
+    
+    } else if (state->syntax & ASM_SYNTAX_NASM) {
+    
+        fprintf (state->ofp, "    sub esp, 40\n");
+        fprintf (state->ofp, "    mov dword [esp], eax\n");
+        fprintf (state->ofp, "    mov dword [esp + 4], edx\n");
+        fprintf (state->ofp, "    mov dword [esp + 8], ebx\n");
+        fprintf (state->ofp, "    mov dword [esp + 12], ecx\n");
+        fprintf (state->ofp, "    xor eax, eax\n");
+        fprintf (state->ofp, "    mov dword [esp + 16], eax\n");
+        fprintf (state->ofp, "    mov dword [esp + 20], eax\n");
+        fprintf (state->ofp, "    mov dword [esp + 24], eax\n");
+        fprintf (state->ofp, "    mov dword [esp + 28], eax\n");
+        fprintf (state->ofp, "    mov dword [esp + 32], eax\n");
+        fprintf (state->ofp, "    mov dword [esp + 36], eax\n");
+        
+        if (!is_unsigned) {
+        
+            fprintf (state->ofp, "    test dword [esp + 4], 80000000h\n");
+            fprintf (state->ofp, "    jz L%d\n", lhs_pos_label);
+            fprintf (state->ofp, "    not dword [esp]\n");
+            fprintf (state->ofp, "    not dword [esp + 4]\n");
+            fprintf (state->ofp, "    add dword [esp], 1\n");
+            fprintf (state->ofp, "    adc dword [esp + 4], 0\n");
+            fprintf (state->ofp, "    mov dword [esp + 32], 1\n");
+            fprintf (state->ofp, "    xor dword [esp + 36], 1\n");
+            fprintf (state->ofp, "L%d:\n", lhs_pos_label);
+            fprintf (state->ofp, "    test dword [esp + 12], 80000000h\n");
+            fprintf (state->ofp, "    jz L%d\n", rhs_pos_label);
+            fprintf (state->ofp, "    not dword [esp + 8]\n");
+            fprintf (state->ofp, "    not dword [esp + 12]\n");
+            fprintf (state->ofp, "    add dword [esp + 8], 1\n");
+            fprintf (state->ofp, "    adc dword [esp + 12], 0\n");
+            fprintf (state->ofp, "    xor dword [esp + 36], 1\n");
+            fprintf (state->ofp, "L%d:\n", rhs_pos_label);
+        
+        }
+        
+        fprintf (state->ofp, "    mov esi, 64\n");
+        fprintf (state->ofp, "L%d:\n", loop_label);
+        fprintf (state->ofp, "    shl dword [esp], 1\n");
+        fprintf (state->ofp, "    rcl dword [esp + 4], 1\n");
+        fprintf (state->ofp, "    rcl dword [esp + 24], 1\n");
+        fprintf (state->ofp, "    rcl dword [esp + 28], 1\n");
+        fprintf (state->ofp, "    shl dword [esp + 16], 1\n");
+        fprintf (state->ofp, "    rcl dword [esp + 20], 1\n");
+        fprintf (state->ofp, "    mov eax, dword [esp + 28]\n");
+        fprintf (state->ofp, "    cmp eax, dword [esp + 12]\n");
+        fprintf (state->ofp, "    ja L%d\n", sub_label);
+        fprintf (state->ofp, "    jb L%d\n", nosub_label);
+        fprintf (state->ofp, "    mov eax, dword [esp + 24]\n");
+        fprintf (state->ofp, "    cmp eax, dword [esp + 8]\n");
+        fprintf (state->ofp, "    jb L%d\n", nosub_label);
+        fprintf (state->ofp, "L%d:\n", sub_label);
+        fprintf (state->ofp, "    mov eax, dword [esp + 8]\n");
+        fprintf (state->ofp, "    sub dword [esp + 24], eax\n");
+        fprintf (state->ofp, "    mov eax, dword [esp + 12]\n");
+        fprintf (state->ofp, "    sbb dword [esp + 28], eax\n");
+        fprintf (state->ofp, "    or dword [esp + 16], 1\n");
+        fprintf (state->ofp, "L%d:\n", nosub_label);
+        fprintf (state->ofp, "    dec esi\n");
+        fprintf (state->ofp, "    jnz L%d\n", loop_label);
+        
+        if (!is_unsigned) {
+        
+            fprintf (state->ofp, "    cmp dword [esp + 36], 0\n");
+            fprintf (state->ofp, "    je L%d\n", qpos_label);
+            fprintf (state->ofp, "    not dword [esp + 16]\n");
+            fprintf (state->ofp, "    not dword [esp + 20]\n");
+            fprintf (state->ofp, "    add dword [esp + 16], 1\n");
+            fprintf (state->ofp, "    adc dword [esp + 20], 0\n");
+            fprintf (state->ofp, "L%d:\n", qpos_label);
+            fprintf (state->ofp, "    cmp dword [esp + 32], 0\n");
+            fprintf (state->ofp, "    je L%d\n", rpos_label);
+            fprintf (state->ofp, "    not dword [esp + 24]\n");
+            fprintf (state->ofp, "    not dword [esp + 28]\n");
+            fprintf (state->ofp, "    add dword [esp + 24], 1\n");
+            fprintf (state->ofp, "    adc dword [esp + 28], 0\n");
+            fprintf (state->ofp, "L%d:\n", rpos_label);
+        
+        }
+        
+        if (want_mod) {
+        
+            fprintf (state->ofp, "    mov eax, dword [esp + 24]\n");
+            fprintf (state->ofp, "    mov edx, dword [esp + 28]\n");
+        
+        } else {
+        
+            fprintf (state->ofp, "    mov eax, dword [esp + 16]\n");
+            fprintf (state->ofp, "    mov edx, dword [esp + 20]\n");
+        
+        }
+    
+    } else {
+    
+        fprintf (state->ofp, "    sub esp, 40\n");
+        fprintf (state->ofp, "    mov dword ptr [esp], eax\n");
+        fprintf (state->ofp, "    mov dword ptr [esp + 4], edx\n");
+        fprintf (state->ofp, "    mov dword ptr [esp + 8], ebx\n");
+        fprintf (state->ofp, "    mov dword ptr [esp + 12], ecx\n");
+        fprintf (state->ofp, "    xor eax, eax\n");
+        fprintf (state->ofp, "    mov dword ptr [esp + 16], eax\n");
+        fprintf (state->ofp, "    mov dword ptr [esp + 20], eax\n");
+        fprintf (state->ofp, "    mov dword ptr [esp + 24], eax\n");
+        fprintf (state->ofp, "    mov dword ptr [esp + 28], eax\n");
+        fprintf (state->ofp, "    mov dword ptr [esp + 32], eax\n");
+        fprintf (state->ofp, "    mov dword ptr [esp + 36], eax\n");
+        
+        if (!is_unsigned) {
+        
+            fprintf (state->ofp, "    test dword ptr [esp + 4], 80000000h\n");
+            fprintf (state->ofp, "    jz .L%d\n", lhs_pos_label);
+            fprintf (state->ofp, "    not dword ptr [esp]\n");
+            fprintf (state->ofp, "    not dword ptr [esp + 4]\n");
+            fprintf (state->ofp, "    add dword ptr [esp], 1\n");
+            fprintf (state->ofp, "    adc dword ptr [esp + 4], 0\n");
+            fprintf (state->ofp, "    mov dword ptr [esp + 32], 1\n");
+            fprintf (state->ofp, "    xor dword ptr [esp + 36], 1\n");
+            fprintf (state->ofp, ".L%d:\n", lhs_pos_label);
+            fprintf (state->ofp, "    test dword ptr [esp + 12], 80000000h\n");
+            fprintf (state->ofp, "    jz .L%d\n", rhs_pos_label);
+            fprintf (state->ofp, "    not dword ptr [esp + 8]\n");
+            fprintf (state->ofp, "    not dword ptr [esp + 12]\n");
+            fprintf (state->ofp, "    add dword ptr [esp + 8], 1\n");
+            fprintf (state->ofp, "    adc dword ptr [esp + 12], 0\n");
+            fprintf (state->ofp, "    xor dword ptr [esp + 36], 1\n");
+            fprintf (state->ofp, ".L%d:\n", rhs_pos_label);
+        
+        }
+        
+        fprintf (state->ofp, "    mov esi, 64\n");
+        fprintf (state->ofp, ".L%d:\n", loop_label);
+        fprintf (state->ofp, "    shl dword ptr [esp], 1\n");
+        fprintf (state->ofp, "    rcl dword ptr [esp + 4], 1\n");
+        fprintf (state->ofp, "    rcl dword ptr [esp + 24], 1\n");
+        fprintf (state->ofp, "    rcl dword ptr [esp + 28], 1\n");
+        fprintf (state->ofp, "    shl dword ptr [esp + 16], 1\n");
+        fprintf (state->ofp, "    rcl dword ptr [esp + 20], 1\n");
+        fprintf (state->ofp, "    mov eax, dword ptr [esp + 28]\n");
+        fprintf (state->ofp, "    cmp eax, dword ptr [esp + 12]\n");
+        fprintf (state->ofp, "    ja .L%d\n", sub_label);
+        fprintf (state->ofp, "    jb .L%d\n", nosub_label);
+        fprintf (state->ofp, "    mov eax, dword ptr [esp + 24]\n");
+        fprintf (state->ofp, "    cmp eax, dword ptr [esp + 8]\n");
+        fprintf (state->ofp, "    jb .L%d\n", nosub_label);
+        fprintf (state->ofp, ".L%d:\n", sub_label);
+        fprintf (state->ofp, "    mov eax, dword ptr [esp + 8]\n");
+        fprintf (state->ofp, "    sub dword ptr [esp + 24], eax\n");
+        fprintf (state->ofp, "    mov eax, dword ptr [esp + 12]\n");
+        fprintf (state->ofp, "    sbb dword ptr [esp + 28], eax\n");
+        fprintf (state->ofp, "    or dword ptr [esp + 16], 1\n");
+        fprintf (state->ofp, ".L%d:\n", nosub_label);
+        fprintf (state->ofp, "    dec esi\n");
+        fprintf (state->ofp, "    jnz .L%d\n", loop_label);
+        
+        if (!is_unsigned) {
+        
+            fprintf (state->ofp, "    cmp dword ptr [esp + 36], 0\n");
+            fprintf (state->ofp, "    je .L%d\n", qpos_label);
+            fprintf (state->ofp, "    not dword ptr [esp + 16]\n");
+            fprintf (state->ofp, "    not dword ptr [esp + 20]\n");
+            fprintf (state->ofp, "    add dword ptr [esp + 16], 1\n");
+            fprintf (state->ofp, "    adc dword ptr [esp + 20], 0\n");
+            fprintf (state->ofp, ".L%d:\n", qpos_label);
+            fprintf (state->ofp, "    cmp dword ptr [esp + 32], 0\n");
+            fprintf (state->ofp, "    je .L%d\n", rpos_label);
+            fprintf (state->ofp, "    not dword ptr [esp + 24]\n");
+            fprintf (state->ofp, "    not dword ptr [esp + 28]\n");
+            fprintf (state->ofp, "    add dword ptr [esp + 24], 1\n");
+            fprintf (state->ofp, "    adc dword ptr [esp + 28], 0\n");
+            fprintf (state->ofp, ".L%d:\n", rpos_label);
+        
+        }
+        
+        if (want_mod) {
+        
+            fprintf (state->ofp, "    mov eax, dword ptr [esp + 24]\n");
+            fprintf (state->ofp, "    mov edx, dword ptr [esp + 28]\n");
+        
+        } else {
+        
+            fprintf (state->ofp, "    mov eax, dword ptr [esp + 16]\n");
+            fprintf (state->ofp, "    mov edx, dword ptr [esp + 20]\n");
+        
+        }
+    
+    }
+    
+    fprintf (state->ofp, "    add esp, 40\n");
+
+}
+
+static void emit_assignment_divmod64_att (int is_unsigned, int want_mod) {
+
+    int loop_label, sub_label, nosub_label;
+    int lhs_pos_label, rhs_pos_label;
+    int qpos_label, rpos_label;
+    
+    loop_label = anon_label++;
+    sub_label = anon_label++;
+    nosub_label = anon_label++;
+    lhs_pos_label = anon_label++;
+    rhs_pos_label = anon_label++;
+    qpos_label = anon_label++;
+    rpos_label = anon_label++;
+    
+    fprintf (state->ofp, "    subl $40, %%esp\n");
+    fprintf (state->ofp, "    movl %%eax, (%%esp)\n");
+    fprintf (state->ofp, "    movl %%edx, 4(%%esp)\n");
+    fprintf (state->ofp, "    movl %%ebx, 8(%%esp)\n");
+    fprintf (state->ofp, "    movl %%ecx, 12(%%esp)\n");
+    fprintf (state->ofp, "    xorl %%eax, %%eax\n");
+    fprintf (state->ofp, "    movl %%eax, 16(%%esp)\n");
+    fprintf (state->ofp, "    movl %%eax, 20(%%esp)\n");
+    fprintf (state->ofp, "    movl %%eax, 24(%%esp)\n");
+    fprintf (state->ofp, "    movl %%eax, 28(%%esp)\n");
+    fprintf (state->ofp, "    movl %%eax, 32(%%esp)\n");
+    fprintf (state->ofp, "    movl %%eax, 36(%%esp)\n");
+    
+    if (!is_unsigned) {
+    
+        fprintf (state->ofp, "    testl $0x80000000, 4(%%esp)\n");
+        fprintf (state->ofp, "    jz .L%d\n", lhs_pos_label);
+        fprintf (state->ofp, "    notl (%%esp)\n");
+        fprintf (state->ofp, "    notl 4(%%esp)\n");
+        fprintf (state->ofp, "    addl $1, (%%esp)\n");
+        fprintf (state->ofp, "    adcl $0, 4(%%esp)\n");
+        fprintf (state->ofp, "    movl $1, 32(%%esp)\n");
+        fprintf (state->ofp, "    xorl $1, 36(%%esp)\n");
+        fprintf (state->ofp, ".L%d:\n", lhs_pos_label);
+        fprintf (state->ofp, "    testl $0x80000000, 12(%%esp)\n");
+        fprintf (state->ofp, "    jz .L%d\n", rhs_pos_label);
+        fprintf (state->ofp, "    notl 8(%%esp)\n");
+        fprintf (state->ofp, "    notl 12(%%esp)\n");
+        fprintf (state->ofp, "    addl $1, 8(%%esp)\n");
+        fprintf (state->ofp, "    adcl $0, 12(%%esp)\n");
+        fprintf (state->ofp, "    xorl $1, 36(%%esp)\n");
+        fprintf (state->ofp, ".L%d:\n", rhs_pos_label);
+    
+    }
+    
+    fprintf (state->ofp, "    movl $64, %%esi\n");
+    fprintf (state->ofp, ".L%d:\n", loop_label);
+    fprintf (state->ofp, "    shll $1, (%%esp)\n");
+    fprintf (state->ofp, "    rcll $1, 4(%%esp)\n");
+    fprintf (state->ofp, "    rcll $1, 24(%%esp)\n");
+    fprintf (state->ofp, "    rcll $1, 28(%%esp)\n");
+    fprintf (state->ofp, "    shll $1, 16(%%esp)\n");
+    fprintf (state->ofp, "    rcll $1, 20(%%esp)\n");
+    fprintf (state->ofp, "    movl 28(%%esp), %%eax\n");
+    fprintf (state->ofp, "    cmpl 12(%%esp), %%eax\n");
+    fprintf (state->ofp, "    ja .L%d\n", sub_label);
+    fprintf (state->ofp, "    jb .L%d\n", nosub_label);
+    fprintf (state->ofp, "    movl 24(%%esp), %%eax\n");
+    fprintf (state->ofp, "    cmpl 8(%%esp), %%eax\n");
+    fprintf (state->ofp, "    jb .L%d\n", nosub_label);
+    fprintf (state->ofp, ".L%d:\n", sub_label);
+    fprintf (state->ofp, "    movl 8(%%esp), %%eax\n");
+    fprintf (state->ofp, "    subl %%eax, 24(%%esp)\n");
+    fprintf (state->ofp, "    movl 12(%%esp), %%eax\n");
+    fprintf (state->ofp, "    sbbl %%eax, 28(%%esp)\n");
+    fprintf (state->ofp, "    orl $1, 16(%%esp)\n");
+    fprintf (state->ofp, ".L%d:\n", nosub_label);
+    fprintf (state->ofp, "    decl %%esi\n");
+    fprintf (state->ofp, "    jnz .L%d\n", loop_label);
+    
+    if (!is_unsigned) {
+    
+        fprintf (state->ofp, "    cmpl $0, 36(%%esp)\n");
+        fprintf (state->ofp, "    je .L%d\n", qpos_label);
+        fprintf (state->ofp, "    notl 16(%%esp)\n");
+        fprintf (state->ofp, "    notl 20(%%esp)\n");
+        fprintf (state->ofp, "    addl $1, 16(%%esp)\n");
+        fprintf (state->ofp, "    adcl $0, 20(%%esp)\n");
+        fprintf (state->ofp, ".L%d:\n", qpos_label);
+        fprintf (state->ofp, "    cmpl $0, 32(%%esp)\n");
+        fprintf (state->ofp, "    je .L%d\n", rpos_label);
+        fprintf (state->ofp, "    notl 24(%%esp)\n");
+        fprintf (state->ofp, "    notl 28(%%esp)\n");
+        fprintf (state->ofp, "    addl $1, 24(%%esp)\n");
+        fprintf (state->ofp, "    adcl $0, 28(%%esp)\n");
+        fprintf (state->ofp, ".L%d:\n", rpos_label);
+    
+    }
+    
+    if (want_mod) {
+    
+        fprintf (state->ofp, "    movl 24(%%esp), %%eax\n");
+        fprintf (state->ofp, "    movl 28(%%esp), %%edx\n");
+    
+    } else {
+    
+        fprintf (state->ofp, "    movl 16(%%esp), %%eax\n");
+        fprintf (state->ofp, "    movl 20(%%esp), %%edx\n");
+    
+    }
+    
+    fprintf (state->ofp, "    addl $40, %%esp\n");
+
+}
+
+static void emit_assignment_divmod64 (int is_unsigned, int want_mod) {
+
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        emit_assignment_divmod64_intel (is_unsigned, want_mod);
+    } else {
+        emit_assignment_divmod64_att (is_unsigned, want_mod);
+    }
+
+}
+
+static void emit_assignment_binary_op64 (enum token_kind op, int is_unsigned) {
+
+    int l1, l2;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        switch (op) {
+        
+            case TOK_PLUS:      case TOK_PLUSEQ:
+            
+                fprintf (state->ofp, "    add eax, ebx\n");
+                fprintf (state->ofp, "    adc edx, ecx\n");
+                break;
+            
+            case TOK_MINUS:     case TOK_MINUSEQ:
+            
+                fprintf (state->ofp, "    sub eax, ebx\n");
+                fprintf (state->ofp, "    sbb edx, ecx\n");
+                break;
+            
+            case TOK_STAR:      case TOK_STAREQ:
+            
+                /**
+                 * Low 64 bits of (EDX:EAX * EBX).  The high half of the RHS
+                 * is ignored for now; this is enough for constants/small ints.
+                 */
+                fprintf (state->ofp, "    mov esi, eax\n");
+                fprintf (state->ofp, "    mov edi, edx\n");
+                fprintf (state->ofp, "    mul ebx\n");
+                fprintf (state->ofp, "    mov esi, edx\n");
+                fprintf (state->ofp, "    mov edx, edi\n");
+                fprintf (state->ofp, "    imul edx, ebx\n");
+                fprintf (state->ofp, "    add edx, esi\n");
+                break;
+            
+            case TOK_BSLASH:    case TOK_SLASHEQ:
+            
+                emit_assignment_divmod64 (is_unsigned, 0);
+                break;
+            
+            case TOK_MOD:       case TOK_MODEQ:
+            
+                emit_assignment_divmod64 (is_unsigned, 1);
+                break;
+            
+            case TOK_AMPER:     case TOK_ANDEQ:
+            
+                fprintf (state->ofp, "    and eax, ebx\n");
+                fprintf (state->ofp, "    and edx, ecx\n");
+                break;
+            
+            case TOK_PIPE:      case TOK_OREQ:
+            
+                fprintf (state->ofp, "    or eax, ebx\n");
+                fprintf (state->ofp, "    or edx, ecx\n");
+                break;
+            
+            case TOK_CARET:     case TOK_XOREQ:
+            
+                fprintf (state->ofp, "    xor eax, ebx\n");
+                fprintf (state->ofp, "    xor edx, ecx\n");
+                break;
+            
+            case TOK_LSH:       case TOK_LSHEQ:
+            
+                l1 = anon_label++;
+                l2 = anon_label++;
+                
+                fprintf (state->ofp, "    test ecx, ecx\n");
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), l2);
+                fprintf (state->ofp, "    mov ecx, ebx\n");
+                fprintf (state->ofp, "    cmp ecx, 64\n");
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jae L%d\n" : "    jae .L%d\n"), l2);
+                fprintf (state->ofp, "    cmp ecx, 32\n");
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jb L%d\n" : "    jb .L%d\n"), l1);
+                fprintf (state->ofp, "    mov edx, eax\n");
+                fprintf (state->ofp, "    xor eax, eax\n");
+                fprintf (state->ofp, "    sub ecx, 32\n");
+                fprintf (state->ofp, "    shl edx, cl\n");
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jmp L%d\n" : "    jmp .L%d\n"), l2 + 1);
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), l1);
+                fprintf (state->ofp, "    shld edx, eax, cl\n");
+                fprintf (state->ofp, "    shl eax, cl\n");
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jmp L%d\n" : "    jmp .L%d\n"), l2 + 1);
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), l2);
+                fprintf (state->ofp, "    xor eax, eax\n");
+                fprintf (state->ofp, "    xor edx, edx\n");
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), l2 + 1);
+                
+                anon_label++;
+                break;
+            
+            case TOK_RSH:       case TOK_RSHEQ:
+            
+                l1 = anon_label++;
+                l2 = anon_label++;
+                
+                fprintf (state->ofp, "    test ecx, ecx\n");
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), l2);
+                fprintf (state->ofp, "    mov ecx, ebx\n");
+                fprintf (state->ofp, "    cmp ecx, 64\n");
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jae L%d\n" : "    jae .L%d\n"), l2);
+                fprintf (state->ofp, "    cmp ecx, 32\n");
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jb L%d\n" : "    jb .L%d\n"), l1);
+                fprintf (state->ofp, "    mov eax, edx\n");
+                fprintf (state->ofp, is_unsigned ? "    xor edx, edx\n" : "    sar edx, 31\n");
+                fprintf (state->ofp, "    sub ecx, 32\n");
+                fprintf (state->ofp, is_unsigned ? "    shr eax, cl\n" : "    sar eax, cl\n");
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jmp L%d\n" : "    jmp .L%d\n"), l2 + 1);
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), l1);
+                fprintf (state->ofp, "    shrd eax, edx, cl\n");
+                fprintf (state->ofp, is_unsigned ? "    shr edx, cl\n" : "    sar edx, cl\n");
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jmp L%d\n" : "    jmp .L%d\n"), l2 + 1);
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), l2);
+                fprintf (state->ofp, is_unsigned ? "    xor eax, eax\n" : "    mov eax, edx\n");
+                fprintf (state->ofp, is_unsigned ? "    xor edx, edx\n" : "    sar edx, 31\n");
+                fprintf (state->ofp, is_unsigned ? "" : "    mov eax, edx\n");
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), l2 + 1);
+                
+                anon_label++;
+                break;
+            
+            default:
+            
+                break;
+        
+        }
+    
+    } else {
+    
+        switch (op) {
+        
+            case TOK_PLUS:      case TOK_PLUSEQ:
+            
+                fprintf (state->ofp, "    addl %%ebx, %%eax\n");
+                fprintf (state->ofp, "    adcl %%ecx, %%edx\n");
+                break;
+            
+            case TOK_MINUS:     case TOK_MINUSEQ:
+            
+                fprintf (state->ofp, "    subl %%ebx, %%eax\n");
+                fprintf (state->ofp, "    sbbl %%ecx, %%edx\n");
+                break;
+            
+            case TOK_STAR:      case TOK_STAREQ:
+            
+                fprintf (state->ofp, "    movl %%eax, %%esi\n");
+                fprintf (state->ofp, "    movl %%edx, %%edi\n");
+                fprintf (state->ofp, "    mull %%ebx\n");
+                fprintf (state->ofp, "    movl %%edx, %%esi\n");
+                fprintf (state->ofp, "    movl %%edi, %%edx\n");
+                fprintf (state->ofp, "    imull %%ebx, %%edx\n");
+                fprintf (state->ofp, "    addl %%esi, %%edx\n");
+                break;
+            
+            case TOK_BSLASH:    case TOK_SLASHEQ:
+            
+                emit_assignment_divmod64 (is_unsigned, 0);
+                break;
+            
+            case TOK_MOD:       case TOK_MODEQ:
+            
+                emit_assignment_divmod64 (is_unsigned, 1);
+                break;
+            
+            case TOK_AMPER:     case TOK_ANDEQ:
+            
+                fprintf (state->ofp, "    andl %%ebx, %%eax\n");
+                fprintf (state->ofp, "    andl %%ecx, %%edx\n");
+                break;
+            
+            case TOK_PIPE:      case TOK_OREQ:
+            
+                fprintf (state->ofp, "    orl %%ebx, %%eax\n");
+                fprintf (state->ofp, "    orl %%ecx, %%edx\n");
+                break;
+            
+            case TOK_CARET:     case TOK_XOREQ:
+            
+                fprintf (state->ofp, "    xorl %%ebx, %%eax\n");
+                fprintf (state->ofp, "    xorl %%ecx, %%edx\n");
+                break;
+            
+            case TOK_LSH:       case TOK_LSHEQ:
+            
+                l1 = anon_label++;
+                l2 = anon_label++;
+                
+                fprintf (state->ofp, "    testl %%ecx, %%ecx\n");
+                fprintf (state->ofp, "    jnz .L%d\n", l2);
+                fprintf (state->ofp, "    movl %%ebx, %%ecx\n");
+                fprintf (state->ofp, "    cmpl $64, %%ecx\n");
+                fprintf (state->ofp, "    jae .L%d\n", l2);
+                fprintf (state->ofp, "    cmpl $32, %%ecx\n");
+                fprintf (state->ofp, "    jb .L%d\n", l1);
+                fprintf (state->ofp, "    movl %%eax, %%edx\n");
+                fprintf (state->ofp, "    xorl %%eax, %%eax\n");
+                fprintf (state->ofp, "    subl $32, %%ecx\n");
+                fprintf (state->ofp, "    shll %%cl, %%edx\n");
+                fprintf (state->ofp, "    jmp .L%d\n", l2 + 1);
+                fprintf (state->ofp, ".L%d:\n", l1);
+                fprintf (state->ofp, "    shldl %%cl, %%eax, %%edx\n");
+                fprintf (state->ofp, "    shll %%cl, %%eax\n");
+                fprintf (state->ofp, "    jmp .L%d\n", l2 + 1);
+                fprintf (state->ofp, ".L%d:\n", l2);
+                fprintf (state->ofp, "    xorl %%eax, %%eax\n");
+                fprintf (state->ofp, "    xorl %%edx, %%edx\n");
+                fprintf (state->ofp, ".L%d:\n", l2 + 1);
+                
+                anon_label++;
+                break;
+            
+            case TOK_RSH:       case TOK_RSHEQ:
+            
+                l1 = anon_label++;
+                l2 = anon_label++;
+                
+                fprintf (state->ofp, "    testl %%ecx, %%ecx\n");
+                fprintf (state->ofp, "    jnz .L%d\n", l2);
+                fprintf (state->ofp, "    movl %%ebx, %%ecx\n");
+                fprintf (state->ofp, "    cmpl $64, %%ecx\n");
+                fprintf (state->ofp, "    jae .L%d\n", l2);
+                fprintf (state->ofp, "    cmpl $32, %%ecx\n");
+                fprintf (state->ofp, "    jb .L%d\n", l1);
+                fprintf (state->ofp, "    movl %%edx, %%eax\n");
+                fprintf (state->ofp, is_unsigned ? "    xorl %%edx, %%edx\n" : "    sarl $31, %%edx\n");
+                fprintf (state->ofp, "    subl $32, %%ecx\n");
+                fprintf (state->ofp, is_unsigned ? "    shrl %%cl, %%eax\n" : "    sarl %%cl, %%eax\n");
+                fprintf (state->ofp, "    jmp .L%d\n", l2 + 1);
+                fprintf (state->ofp, ".L%d:\n", l1);
+                fprintf (state->ofp, "    shrdl %%cl, %%edx, %%eax\n");
+                fprintf (state->ofp, is_unsigned ? "    shrl %%cl, %%edx\n" : "    sarl %%cl, %%edx\n");
+                fprintf (state->ofp, "    jmp .L%d\n", l2 + 1);
+                fprintf (state->ofp, ".L%d:\n", l2);
+                fprintf (state->ofp, is_unsigned ? "    xorl %%eax, %%eax\n" : "    movl %%edx, %%eax\n");
+                fprintf (state->ofp, is_unsigned ? "    xorl %%edx, %%edx\n" : "    sarl $31, %%edx\n");
+                fprintf (state->ofp, is_unsigned ? "" : "    movl %%edx, %%eax\n");
+                fprintf (state->ofp, ".L%d:\n", l2 + 1);
+                
+                anon_label++;
+                break;
+            
+            default:
+            
+                break;
+        
+        }
+    
+    }
+
+}
+
+static void emit_call_identifier_to_reg_now (const char *name, const char *reg, const char *name_start, const char *name_caret, unsigned long name_line);
+static void emit_assignment_binary_op (enum token_kind op, int is_unsigned);
+static void emit_store_member_to_addr_reg_now (const char *addr_reg, int offset, const char *value_reg, int size);
+static void emit_store_reg_to_deref_reg_now (const char *addr_reg, const char *value_reg, int size);
+static void emit_load_deref_reg_now (const char *reg, int size);
+
+static void emit_store_floating_member_to_addr_reg_now (const char *addr_reg, int offset, int size);
+static void emit_load_floating_rhs_expression_now (int result_size);
+
+static int emit_load_parenthesized_assignment_expression_to_reg_now (const char *reg, int *out_is_unsigned);
+static int token_is_floating_constant_now (void);
+
+static void emit_load_local_address_to_reg_now (const char *reg, long offset) {
+
+    char memref[64];
+    
+    if (!state->ofp || !reg) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        format_intel_ebp_offset (memref, sizeof (memref), offset);
+        fprintf (state->ofp, "    lea %s, %s\n", reg, memref);
+    
+    } else {
+        fprintf (state->ofp, "    leal %ld(%%ebp), %%%s\n", offset, reg);
+    }
+
+}
+
+static void emit_apply_postfix_member_access_to_reg_now (const char *reg) {
+
+    postfix_member_pointer_depth = 0;
+    postfix_member_pointed_size = 0;
+    postfix_member_seen = 0;
+    postfix_member_offset = 0;
+    postfix_member_size = 0;
+    postfix_member_is_floating = 0;
+    postfix_member_is_unsigned = 0;
+    
+    postfix_member_calling_convention = TOK_EOF;
+
+    {
+    
+        const char *current_object_tag_name = postfix_copy_lvalue_tag_name;
+        int current_object_size = postfix_copy_lvalue_size;
+        
+        if (current_object_size <= 0 && rhs_last_pointed_size > 0) {
+            current_object_size = rhs_last_pointed_size;
+        }
+        
+        while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+        
+            enum token_kind op = tok.kind;
+            char *member;
+            
+            const char *member_start;
+            const char *member_caret;
+            
+            unsigned long member_line;
+            
+            int offset = 0;
+            int size = DATA_INT & 0x1f;
+            int elem_size = DATA_INT & 0x1f;
+            int pointer_depth = 0;
+            int is_array = 0;
+            int is_floating = 0;
+            int is_unsigned = 0;
+            
+            get_token ();
+            
+            member_start = tok.start;
+            member_caret = tok.caret;
+            member_line = get_line_number ();
+            
+            if (tok.kind != TOK_IDENT) {
+            
+                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", op == TOK_ARROW ? "->" : ".");
+                return;
+            
+            }
+            
+            member = xstrdup (tok.ident);
+            get_token ();
+            
+            if (!find_member_info_ex_bounded (member, current_object_size, current_object_tag_name, &offset, &size, &elem_size, &pointer_depth, &is_array, &is_floating)) {
+            
+                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+                
+                free (member);
+                return;
+            
+            }
+            
+            is_unsigned = last_found_member_is_unsigned;
+            
+            {
+            
+                const char *member_tag_name = last_found_member_tag_name;
+                
+                /*
+                 * For an array member whose element type is a pointer, the
+                 * subscript step is always one pointer.  Keep this independent
+                 * of the pointed aggregate size; otherwise expressions like
+                 * ic->heads[i] scale by sizeof(*heads[i]) and are later passed
+                 * as an aggregate instead of one pointer.
+                 */
+                if (is_array && pointer_depth > 0) {
+                    elem_size = DATA_PTR;
+                } else if (pointer_depth > 1) {
+                    elem_size = DATA_PTR;
+                } else if (pointer_depth == 1 && member_tag_name) {
+                
+                    struct aggregate_tag_entry *entry = find_aggregate_tag (member_tag_name, 0);
+                    
+                    if (entry) {
+                        elem_size = entry->size;
+                    }
+                
+                }
+                
+                current_object_tag_name = member_tag_name;
+            
+            }
+            
+            free (member);
+            
+            postfix_member_seen = 1;
+            postfix_member_pointer_depth = is_array ? 1 : pointer_depth;
+            postfix_member_pointed_size = elem_size;
+            postfix_member_offset = offset;
+            postfix_member_size = size;
+            postfix_member_is_floating = is_floating;
+            postfix_member_is_unsigned = is_unsigned;
+            postfix_member_calling_convention = last_found_member_calling_convention;
+            
+            if (pointer_depth > 0 || is_array) {
+                current_object_size = elem_size;
+            } else {
+                current_object_size = size;
+            }
+            
+            if (tok.kind == TOK_LBRACK) {
+            
+                enum token_kind assign_op;
+                int subscript_elem_size;
+                
+                if (!is_array && pointer_depth > 0) {
+                    emit_load_member_from_addr_reg_now (reg, reg, offset, DATA_PTR & 0x1f);
+                } else if (state->ofp && offset != 0) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+                    } else {
+                        fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
+                    }
+                
+                }
+                
+                subscript_elem_size = index_step_size (elem_size);
+                
+                if (subscript_elem_size <= 0) {
+                    subscript_elem_size = DATA_INT & 0x1f;
+                }
+                
+                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, subscript_elem_size);
+                
+                if (tok.kind == TOK_ARROW && subscript_elem_size <= (DATA_PTR & 0x1f)) {
+                
+                    emit_load_deref_reg_now (reg, DATA_PTR & 0x1f);
+                    
+                    postfix_member_pointer_depth = 0;
+                    postfix_member_size = DATA_PTR & 0x1f;
+                    
+                    continue;
+                
+                }
+                
+                if (is_assignment_operator (tok.kind)) {
+                
+                    assign_op = tok.kind;
+                    get_token ();
+                    
+                    if (assign_op == TOK_ASSIGN && subscript_elem_size > (DATA_LLONG & 0x1f)
+                        && tok.kind == TOK_IDENT && tok.ident
+                        && get_global_symbol_kind (tok.ident) == GLOBAL_SYMBOL_FUNCTION) {
+                    
+                        char *rhs_name = xstrdup (tok.ident);
+                        
+                        const char *rhs_start = tok.start;
+                        const char *rhs_caret = tok.caret;
+                        
+                        unsigned long rhs_line = get_line_number ();
+                        emit_push_reg_now (reg);
+                        
+                        pending_struct_return_lhs = 0;
+                        pending_struct_return_global_name = 0;
+                        pending_struct_return_stack_address = 1;
+                        pending_struct_return_stack_offset = 0;
+                        
+                        get_token ();
+                        emit_call_identifier_to_reg_now (rhs_name, reg, rhs_start, rhs_caret, rhs_line);
+                        
+                        pending_struct_return_stack_address = 0;
+                        pending_struct_return_stack_offset = 0;
+                        
+                        emit_pop_reg_now ("edx");
+                        free (rhs_name);
+                        
+                        postfix_member_seen = 0;
+                        return;
+                    
+                    }
+                    
+                    emit_push_reg_now (reg);
+                    
+                    if (assign_op == TOK_ASSIGN) {
+                    
+                        if (subscript_elem_size > (DATA_LLONG & 0x1f)) {
+                        
+                            pending_struct_return_lhs = 0;
+                            pending_struct_return_global_name = 0;
+                            pending_struct_return_stack_address = 1;
+                            pending_struct_return_stack_offset = 0;
+                            
+                            emit_load_assignment_rhs_expression_to_reg (reg);
+                            
+                            pending_struct_return_stack_address = 0;
+                            pending_struct_return_stack_offset = 0;
+                            
+                            emit_pop_reg_now ("edx");
+                            
+                            postfix_member_seen = 0;
+                            return;
+                        
+                        }
+                        
+                        emit_load_assignment_rhs_expression_to_reg (reg);
+                    
+                    } else {
+                    
+                        emit_load_deref_reg_now (reg, subscript_elem_size);
+                        emit_push_reg_now (reg);
+                        emit_load_assignment_rhs_expression_to_reg ("edx");
+                        emit_pop_reg_now (reg);
+                        emit_assignment_binary_op (assign_op, 0);
+                    
+                    }
+                    
+                    emit_pop_reg_now ("edx");
+                    emit_store_reg_to_deref_reg_now ("edx", reg, subscript_elem_size);
+                    
+                    postfix_member_seen = 0;
+                    return;
+                
+                }
+                
+                if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+                
+                    current_object_size = elem_size;
+                    continue;
+                
+                }
+                
+                /**
+                 * The expression now denotes the subscripted element, not the
+                 * whole member array.  Keep the postfix-member metadata in
+                 * step with the value in REG so argument passing does not
+                 * mistake e.g. ic->heads[i] for the entire heads[] aggregate
+                 * and push multiple words.
+                 *
+                 * If the element itself is an aggregate, REG must remain the
+                 * address of that element.  Loading *(REG) would fetch the
+                 * first word of the struct and later aggregate argument
+                 * passing would treat that word as a pointer, as happened for
+                 * instruction.types[instruction.operands].
+                 */
+                postfix_member_size = subscript_elem_size;
+                
+                /*
+                 * Subscript of an array member whose element type is a pointer
+                 * yields the pointer stored in that array slot.  The generic
+                 * aggregate-subscript path deliberately keeps struct elements as
+                 * addresses, but pointer elements must still be loaded before a
+                 * following -> member access.  Otherwise expressions such as
+                 * instruction.regs[operand]->type.reg_rex treat the address of
+                 * the regs[] slot as if it were a struct reg_entry *.
+                 */
+                if (is_array && (pointer_depth > 0 || (tok.kind == TOK_ARROW && subscript_elem_size == (DATA_PTR & 0x1f)))) {
+                
+                    emit_load_deref_reg_now (reg, DATA_PTR & 0x1f);
+                    
+                    postfix_member_pointer_depth = pointer_depth > 0 ? pointer_depth - 1 : 0;
+                    postfix_member_size = DATA_PTR & 0x1f;
+                    
+                    if (postfix_member_pointer_depth == 0 && current_object_tag_name) {
+                    
+                        struct aggregate_tag_entry *entry = find_aggregate_tag (current_object_tag_name, 0);
+                        
+                        if (entry) {
+                            current_object_size = entry->size;
+                        }
+                    
+                    }
+                    
+                    continue;
+                
+                }
+                
+                if (postfix_member_pointer_depth > 0) {
+                    postfix_member_pointer_depth--;
+                }
+                
+                if (postfix_member_pointer_depth != 0
+                    || postfix_member_size <= (DATA_PTR & 0x1f)) {
+                    emit_load_deref_reg_now (reg, subscript_elem_size);
+                }
+                
+                continue;
+            
+            }
+            
+            if (is_array && tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
+            
+                if (state->ofp && offset != 0) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+                    } else {
+                        fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
+                    }
+                
+                }
+                
+                /*
+                 * A bare array member expression decays to a pointer when used
+                 * as an rvalue/function argument.  Keep REG as the element
+                 * address, but do not leave aggregate element metadata behind or
+                 * the call argument path will push the first element by value.
+                 * This broke calls such as _cpp_add_unknown2_direct(...,
+                 * macro->tokens, token_count), where tokens[0] is a struct.
+                 */
+                postfix_member_size = DATA_PTR & 0x1f;
+                postfix_member_pointer_depth = 1;
+                postfix_member_pointed_size = elem_size;
+                
+                continue;
+            
+            }
+            
+            if ((tok.kind == TOK_ARROW || tok.kind == TOK_DOT) && pointer_depth == 0) {
+            
+                if (state->ofp && offset != 0) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+                    } else {
+                        fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
+                    }
+                
+                }
+                
+                continue;
+            
+            }
+            
+            if (size > (DATA_PTR & 0x1f) && tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
+            
+                if (state->ofp && offset != 0) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+                    } else {
+                        fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
+                    }
+                
+                }
+                
+                continue;
+            
+            }
+            
+            if (state->ofp) {
+            
+                if (strcmp (reg, "edx") != 0) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    mov edx, %s\n", reg);
+                    } else {
+                        fprintf (state->ofp, "    movl %%%s, %%edx\n", reg);
+                    }
+                
+                }
+                
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    const char *opsize = "dword";
+                    
+                    if (size == 1) {
+                        opsize = "byte";
+                    } else if (size == 2) {
+                        opsize = "word";
+                    }
+                    
+                    if (state->syntax & ASM_SYNTAX_NASM) {
+                    
+                        if (size == 1) {
+                            fprintf (state->ofp, "    movzx %s, byte [%s + %d]\n", reg, reg, offset);
+                        } else if (size == 2) {
+                            fprintf (state->ofp, "    movzx %s, word [%s + %d]\n", reg, reg, offset);
+                        } else {
+                            fprintf (state->ofp, "    mov %s, %s [%s + %d]\n", reg, opsize, reg, offset);
+                        }
+                    
+                    } else {
+                    
+                        if (size == 1) {
+                            fprintf (state->ofp, "    movzx %s, byte ptr [%s + %d]\n", reg, reg, offset);
+                        } else if (size == 2) {
+                            fprintf (state->ofp, "    movzx %s, word ptr [%s + %d]\n", reg, reg, offset);
+                        } else {
+                            fprintf (state->ofp, "    mov %s, %s ptr [%s + %d]\n", reg, opsize, reg, offset);
+                        }
+                    
+                    }
+                
+                } else {
+                
+                    if (size == 1) {
+                        fprintf (state->ofp, "    movzbl %d(%%%s), %%%s\n", offset, reg, reg);
+                    } else if (size == 2) {
+                        fprintf (state->ofp, "    movzwl %d(%%%s), %%%s\n", offset, reg, reg);
+                    } else {
+                        fprintf (state->ofp, "    movl %d(%%%s), %%%s\n", offset, reg, reg);
+                    }
+                
+                }
+            
+            }
+        
+        }
+    
+    }
+
+}
+
+static void emit_apply_postfix_member_incdec_now (const char *reg, enum token_kind op) {
+
+    if (!postfix_member_seen) {
+        return;
+    }
+    
+    if (state->ofp) {
+    
+        const char *insn = op == TOK_INCR ? "inc" : "dec";
+        (void) reg;
+        
+        if (postfix_member_pointer_depth > 0) {
+        
+            int step = postfix_member_pointed_size;
+            const char *arith = op == TOK_INCR ? "add" : "sub";
+            
+            if (step <= 0) {
+                step = 1;
+            }
+            
+            if (step == 1) {
+                /* Falling through keeps the compact inc/dec form for char *. */
+            } else if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                if (state->syntax & ASM_SYNTAX_NASM) {
+                    fprintf (state->ofp, "    %s dword [edx + %d], %d\n", arith, postfix_member_offset, step);
+                } else {
+                    fprintf (state->ofp, "    %s dword ptr [edx + %d], %d\n", arith, postfix_member_offset, step);
+                }
+                
+                return;
+            
+            } else {
+            
+                fprintf (state->ofp, "    %sl $%d, %d(%%edx)\n", arith, step, postfix_member_offset);
+                return;
+            }
+        
+        }
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            const char *opsize = "dword";
+            
+            if (postfix_member_size == 1) {
+                opsize = "byte";
+            } else if (postfix_member_size == 2) {
+                opsize = "word";
+            }
+            
+            if (state->syntax & ASM_SYNTAX_NASM) {
+                fprintf (state->ofp, "    %s %s [edx + %d]\n", insn, opsize, postfix_member_offset);
+            } else {
+                fprintf (state->ofp, "    %s %s ptr [edx + %d]\n", insn, opsize, postfix_member_offset);
+            }
+        
+        } else {
+        
+            if (postfix_member_size == 1) {
+                fprintf (state->ofp, "    %sb %d(%%edx)\n", insn, postfix_member_offset);
+            } else if (postfix_member_size == 2) {
+                fprintf (state->ofp, "    %sw %d(%%edx)\n", insn, postfix_member_offset);
+            } else {
+                fprintf (state->ofp, "    %sl %d(%%edx)\n", insn, postfix_member_offset);
+            }
+        
+        }
+    
+    }
+
+}
+
+static int rhs_text_is_plain_aggregate_lvalue_now (const char *p) {
+
+    int paren_depth = 0;
+    int bracket_depth = 0;
+    int saw_ident = 0;
+    
+    if (!p) {
+        return 1;
+    }
+    
+    while (*p) {
+    
+        unsigned char ch = (unsigned char) *p;
+        
+        if (ch == '\'' || ch == '"') {
+        
+            int quote = ch;
+            p++;
+            
+            while (*p && *p != quote) {
+            
+                if (*p == '\\' && p[1]) {
+                    p += 2;
+                } else {
+                    p++;
+                }
+            
+            }
+            
+            if (*p == quote) {
+                p++;
+            }
+            
+            continue;
+        
+        }
+        
+        if (ch == '(') {
+        
+            paren_depth++;
+            p++;
+            
+            continue;
+        
+        }
+        
+        if (ch == ')') {
+        
+            if (paren_depth == 0 && bracket_depth == 0) {
+                break;
+            }
+            
+            if (paren_depth > 0) {
+                paren_depth--;
+            }
+            
+            p++;
+            continue;
+        
+        }
+        
+        if (ch == '[') {
+        
+            bracket_depth++;
+            p++;
+            
+            continue;
+        
+        }
+        
+        if (ch == ']') {
+        
+            if (bracket_depth > 0) {
+                bracket_depth--;
+            }
+            
+            p++;
+            continue;
+        
+        }
+        
+        if (paren_depth == 0 && bracket_depth == 0) {
+        
+            if (ch == ';' || ch == ',') {
+                break;
+            }
+            
+            if (ch == '-' && p[1] == '>') {
+            
+                p += 2;
+                continue;
+            
+            }
+            
+            if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%' ||
+                ch == '&' || ch == '|' || ch == '^' || ch == '?' || ch == ':') {
+                return 0;
+            }
+        
+        }
+        
+        if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '_') {
+            saw_ident = 1;
+        }
+        
+        p++;
+    
+    }
+
+    return saw_ident;
+
+}
+
+static int emit_aggregate_copy_from_current_rhs_to_addr_reg_now (const char *addr_reg, int offset, int size);
+static int emit_parse_postfix_copy_source_address_now (const char *reg, struct local_symbol *src, const char *src_name, const char *name_start, const char *name_caret, unsigned long name_line);
+
+static int emit_store_assignment_to_aggregate_address_now (const char *addr_reg, int size, const char *name_start, const char *name_caret, unsigned long name_line) {
+
+    enum token_kind op;
+    
+    if (!is_assignment_operator (tok.kind) || size <= (DATA_LLONG & 0x1f)) {
+        return 0;
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    if (op == TOK_ASSIGN && tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now ()) {
+    
+        char *rhs_name = xstrdup (tok.ident);
+        
+        const char *rhs_start = tok.start ? tok.start : name_start;
+        const char *rhs_caret = tok.caret ? tok.caret : name_caret;
+        
+        unsigned long rhs_line = get_line_number ();
+        emit_push_reg_now (addr_reg);
+        
+        pending_struct_return_lhs = 0;
+        pending_struct_return_global_name = 0;
+        pending_struct_return_stack_address = 1;
+        pending_struct_return_stack_offset = 0;
+        
+        get_token ();
+        emit_call_identifier_to_reg_now (rhs_name, "eax", rhs_start, rhs_caret, rhs_line);
+        
+        pending_struct_return_stack_address = 0;
+        pending_struct_return_stack_offset = 0;
+        
+        emit_pop_reg_now ("edx");
+        free (rhs_name);
+        
+        return 1;
+    
+    }
+    
+    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "aggregate assignment expression not implemented");
+    
+    skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+    return 1;
+
+}
+
+static int rhs_current_operand_is_floating_now (void);
+
+static int emit_store_assignment_to_postfix_member_now (const char *reg) {
+
+    enum token_kind op;
+    int assign_member_offset;
+    int assign_member_size;
+    
+    if (!postfix_member_seen || !is_assignment_operator (tok.kind)) {
+        return 0;
+    }
+    
+    op = tok.kind;
+    assign_member_offset = postfix_member_offset;
+    assign_member_size = postfix_member_size;
+    
+    get_token ();
+    
+    if (state->ofp) {
+    
+        if (op == TOK_ASSIGN) {
+        
+            if (postfix_member_is_floating || token_is_floating_constant_now () || rhs_current_operand_is_floating_now ()) {
+            
+                emit_push_reg_now ("edx");
+                emit_load_floating_rhs_expression_now (assign_member_size);
+                
+                emit_pop_reg_now ("edx");
+                emit_store_floating_member_to_addr_reg_now ("edx", assign_member_offset, assign_member_size);
+                
+                return 1;
+            
+            }
+            
+            if (assign_member_size > (DATA_LLONG & 0x1f) &&
+                tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now ()) {
+            
+                char *rhs_name = xstrdup (tok.ident);
+                
+                const char *rhs_start = tok.start;
+                const char *rhs_caret = tok.caret;
+                
+                unsigned long rhs_line = get_line_number ();
+                emit_push_reg_now ("edx");
+                
+                pending_struct_return_lhs = 0;
+                pending_struct_return_global_name = 0;
+                pending_struct_return_stack_address = 1;
+                pending_struct_return_stack_offset = assign_member_offset;
+                
+                get_token ();
+                emit_call_identifier_to_reg_now (rhs_name, reg, rhs_start, rhs_caret, rhs_line);
+                
+                pending_struct_return_stack_address = 0;
+                pending_struct_return_stack_offset = 0;
+                
+                emit_pop_reg_now ("edx");
+                free (rhs_name);
+                
+                return 1;
+            
+            }
+            
+            if (emit_aggregate_copy_from_current_rhs_to_addr_reg_now ("edx", assign_member_offset, assign_member_size)) {
+                return 1;
+            }
+            
+            emit_push_reg_now ("edx");
+            
+            emit_load_assignment_rhs_expression_to_reg (reg);
+            emit_pop_reg_now ("edx");
+        
+        } else {
+        
+            emit_push_reg_now ("edx");
+            emit_push_reg_now (reg);
+            
+            emit_load_assignment_rhs_expression_to_reg ("edx");
+            emit_pop_reg_now (reg);
+            
+            emit_assignment_binary_op (op, 0);
+            emit_pop_reg_now ("edx");
+        
+        }
+        
+        emit_store_member_to_addr_reg_now ("edx", assign_member_offset, reg, assign_member_size);
+    
+    } else {
+        emit_load_assignment_rhs_expression_to_reg (reg);
+    }
+    
+    return 1;
+
+}
+
+static int parenthesized_function_designator_call_now (void) {
+
+    const char *p;
+    
+    if (tok.kind != TOK_IDENT || !tok.caret || !tok.ident) {
+        return 0;
+    }
+    
+    p = tok.caret + strlen (tok.ident);
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (*p != ')') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    return *p == '(';
+
+}
+
+static void emit_load_deref_reg_ex_now (const char *reg, int size, int is_unsigned) {
+
+    const char *op8;
+    const char *op16;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    op8 = is_unsigned ? "movzx" : "movsx";
+    op16 = is_unsigned ? "movzx" : "movsx";
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+        
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    %s %s, byte [%s]\n", op8, reg, reg);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    %s %s, word [%s]\n", op16, reg, reg);
+            } else {
+                fprintf (state->ofp, "    mov %s, dword [%s]\n", reg, reg);
+            }
+        
+        } else {
+        
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    %s %s, byte ptr [%s]\n", op8, reg, reg);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    %s %s, word ptr [%s]\n", op16, reg, reg);
+            } else {
+                fprintf (state->ofp, "    mov %s, dword ptr [%s]\n", reg, reg);
+            }
+        
+        }
+    
+    } else {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, "    %s (%%%s), %%%s\n", is_unsigned ? "movzbl" : "movsbl", reg, reg);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, "    %s (%%%s), %%%s\n", is_unsigned ? "movzwl" : "movswl", reg, reg);
+        } else {
+            fprintf (state->ofp, "    movl (%%%s), %%%s\n", reg, reg);
+        }
+    
+    }
+
+}
+
+static void emit_load_deref_reg_now (const char *reg, int size) {
+    emit_load_deref_reg_ex_now (reg, size, 0);
+}
+
+static void emit_store_reg_to_deref_reg_now (const char *addr_reg, const char *value_reg, int size) {
+
+    if (suppress_next_struct_return_scalar_store) {
+    
+        suppress_next_struct_return_scalar_store = 0;
+        return;
+    
+    }
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+        
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    mov byte [%s], %cl\n", addr_reg, value_reg[1]);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    mov word [%s], %cx\n", addr_reg, value_reg[1]);
+            } else {
+                fprintf (state->ofp, "    mov dword [%s], %s\n", addr_reg, value_reg);
+            }
+        
+        } else {
+        
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    mov byte ptr [%s], %cl\n", addr_reg, value_reg[1]);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    mov word ptr [%s], %cx\n", addr_reg, value_reg[1]);
+            } else {
+                fprintf (state->ofp, "    mov dword ptr [%s], %s\n", addr_reg, value_reg);
+            }
+        
+        }
+    
+    } else {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, "    movb %%%cl, (%%%s)\n", value_reg[1], addr_reg);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, "    movw %%%cx, (%%%s)\n", value_reg[1], addr_reg);
+        } else {
+            fprintf (state->ofp, "    movl %%%s, (%%%s)\n", value_reg, addr_reg);
+        }
+    
+    }
+
+}
+
+static int emit_handle_subscript_after_loaded_pointer_to_reg_now (const char *reg, int pointer_depth, int pointed_size, int pointed_is_unsigned) {
+
+    int subscript_elem_size;
+    
+    if (tok.kind != TOK_LBRACK) {
+        return 0;
+    }
+    
+    subscript_elem_size = pointer_depth > 1 ? (DATA_PTR & 0x1f) : pointed_size;
+    
+    if (subscript_elem_size <= 0) {
+        subscript_elem_size = DATA_INT & 0x1f;
+    }
+    
+    emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, subscript_elem_size);
+    
+    if (is_assignment_operator (tok.kind)) {
+    
+        enum token_kind assign_op = tok.kind;
+        
+        get_token ();
+        emit_push_reg_now (reg);
+        
+        if (assign_op == TOK_ASSIGN) {
+            emit_load_assignment_rhs_expression_to_reg (reg);
+        } else {
+        
+            emit_load_deref_reg_now (reg, subscript_elem_size);
+            emit_push_reg_now (reg);
+            
+            emit_load_assignment_rhs_expression_to_reg ("edx");
+            emit_pop_reg_now (reg);
+            
+            emit_assignment_binary_op (assign_op, 0);
+        
+        }
+        
+        emit_pop_reg_now ("edx");
+        
+        emit_store_reg_to_deref_reg_now ("edx", reg, subscript_elem_size);
+        clear_rhs_last_pointer_info ();
+        
+        return 1;
+    
+    }
+    
+    emit_load_deref_reg_ex_now (reg, subscript_elem_size, pointer_depth <= 1 ? pointed_is_unsigned : 0);
+    
+    if (pointer_depth > 1) {
+        set_rhs_last_pointer_info (pointer_depth - 1, pointed_size);
+    } else {
+        clear_rhs_last_pointer_info ();
+    }
+    
+    return 1;
+
+}
+
+static void emit_load_member_from_addr_reg_now (const char *dst_reg, const char *addr_reg, int offset, int size) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (state->syntax & ASM_SYNTAX_NASM) {
+        
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    movsx %s, byte [%s + %d]\n", dst_reg, addr_reg, offset);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    movsx %s, word [%s + %d]\n", dst_reg, addr_reg, offset);
+            } else {
+                fprintf (state->ofp, "    mov %s, dword [%s + %d]\n", dst_reg, addr_reg, offset);
+            }
+        
+        } else {
+        
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, "    movsx %s, byte ptr [%s + %d]\n", dst_reg, addr_reg, offset);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, "    movsx %s, word ptr [%s + %d]\n", dst_reg, addr_reg, offset);
+            } else {
+                fprintf (state->ofp, "    mov %s, dword ptr [%s + %d]\n", dst_reg, addr_reg, offset);
+            }
+        
+        }
+    
+    } else {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, "    movsbl %d(%%%s), %%%s\n", offset, addr_reg, dst_reg);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, "    movswl %d(%%%s), %%%s\n", offset, addr_reg, dst_reg);
+        } else {
+            fprintf (state->ofp, "    movl %d(%%%s), %%%s\n", offset, addr_reg, dst_reg);
+        }
+    
+    }
+
+}
+
+static int emit_load_address_of_parenthesized_postfix_to_reg_now (const char *reg) {
+
+    char *name;
+    
+    enum token_kind member_op;
+    struct local_symbol *src;
+    
+    int global_index;
+    
+    const char *current_object_tag_name = 0;
+    int current_object_size = 0;
+    
+    if (tok.kind != TOK_LPAREN) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    if (tok.kind == TOK_LPAREN) {
+    
+        int64_s offset_value;
+        
+        if (parse_constexpr_null_member_address_after_lparen (&offset_value)) {
+        
+            emit_load_const32_to_reg_now (reg, offset_value);
+            return 1;
+        
+        }
+    
+    }
+    
+    if (tok.kind != TOK_IDENT) {
+    
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after '&('");
+        
+        expect (TOK_RPAREN, ")");
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    get_token ();
+    
+    src = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (src) {
+    
+        if (src->is_array) {
+        
+            current_object_size = src->pointed_size > 0 ? src->pointed_size : src->size;
+            current_object_tag_name = src->pointed_tag_name;
+            
+            if (src->is_static && src->static_label) {
+                emit_load_symbol_address_to_reg_now (reg, src->static_label, 0, 0);
+            } else {
+                emit_load_symbol_address_to_reg_now (reg, 0, src->offset, 1);
+            }
+        
+        } else if (src->pointer_depth > 0) {
+        
+            current_object_size = src->pointed_size > 0 ? src->pointed_size : DATA_PTR;
+            current_object_tag_name = src->pointed_tag_name;
+            
+            if (src->is_static && src->static_label) {
+                emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
+            
+            } else {
+                emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+            }
+        
+        } else if (src->is_static && src->static_label) {
+        
+            current_object_size = src->size;
+            emit_load_address_to_reg_now (reg, src->static_label);
+        
+        } else {
+        
+            current_object_size = src->size;
+            
+            /**
+             * A typedef such as section_t can hide the pointer depth from this
+             * older parser.  For &(p->member), the base must be the pointer
+             * value stored in the local, not the address of the local slot.
+             *
+             * Keep the pointed aggregate tag as well.  Without that, address-of
+             * member expressions such as &symbol->next can fall back to an
+             * unqualified member-name lookup and pick another struct's "next"
+             * field.  That emitted symbol + 24 instead of symbol + 36 for
+             * struct symbol::next, corrupting symbol->section in pdas.
+             */
+            if (tok.kind == TOK_ARROW && src->size == (DATA_PTR & 0x1f)) {
+            
+                if (src->pointed_tag_name) {
+                
+                    struct aggregate_tag_entry *entry = find_aggregate_tag (src->pointed_tag_name, 0);
+                    current_object_tag_name = src->pointed_tag_name;
+                    
+                    if (entry) {
+                        current_object_size = entry->size;
+                    }
+                
+                }
+                
+                emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+            
+            } else {
+                emit_load_local_address_to_reg_now (reg, src->offset);
+            }
+        
+        }
+    
+    } else if (global_index >= 0) {
+    
+        if (get_global_symbol_array (name)) {
+        
+            current_object_size = get_global_symbol_pointed_size (name);
+            emit_load_symbol_address_to_reg_now (reg, name, 0, 0);
+        
+        } else if (get_global_symbol_pointer_depth (name) > 0 || (tok.kind == TOK_ARROW && get_global_symbol_size (name) == (DATA_PTR & 0x1f))) {
+        
+            current_object_size = get_global_symbol_pointed_size (name);
+            
+            if (current_object_size <= 0) {
+                current_object_size = DATA_PTR & 0x1f;
+            }
+            
+            emit_load_global_to_reg (reg, name, DATA_PTR);
+        
+        } else {
+        
+            current_object_size = get_global_symbol_size (name);
+            emit_load_address_to_reg_now (reg, name);
+        
+        }
+    
+    } else {
+    
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "unknown symbol '%s'", name);
+        free (name);
+        
+        expect (TOK_RPAREN, ")");
+        return 1;
+    
+    }
+    
+    if (tok.kind == TOK_LBRACK) {
+    
+        int elem_size = DATA_INT & 0x1f;
+        
+        if (src) {
+        
+            elem_size = src->is_array ? (src->pointer_depth ? DATA_PTR : (src->array_element_size > 0 ? src->array_element_size : src->pointed_size)) :
+                (src->pointer_depth > 1 ? DATA_PTR : src->pointed_size);
+        
+        } else if (global_index >= 0) {
+        
+            elem_size = get_global_symbol_array (name) ?
+                (get_global_symbol_pointer_depth (name) ? DATA_PTR : (get_global_symbol_array_element_size (name) > 0 ? get_global_symbol_array_element_size (name) : get_global_symbol_pointed_size (name))) :
+                    (get_global_symbol_pointer_depth (name) > 1 ? DATA_PTR : get_global_symbol_pointed_size (name));
+        
+        }
+        
+        if (elem_size <= 0) {
+            elem_size = DATA_INT & 0x1f;
+        }
+        
+        emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
+    
+    }
+    
+    free (name);
+    
+    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+    
+        char *member;
+        
+        const char *member_start;
+        const char *member_caret;
+        
+        unsigned long member_line;
+        
+        int offset;
+        int size;
+        int elem_size;
+        int pointer_depth;
+        
+        member_op = tok.kind;
+        get_token ();
+        
+        member_start = tok.start;
+        member_caret = tok.caret;
+        member_line = get_line_number ();
+        
+        if (tok.kind != TOK_IDENT) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+            
+            expect (TOK_RPAREN, ")");
+            return 1;
+        
+        }
+        
+        member = xstrdup (tok.ident);
+        get_token ();
+        
+        offset = 0;
+        size = DATA_INT & 0x1f;
+        elem_size = DATA_INT & 0x1f;
+        pointer_depth = 0;
+        
+        if (!find_member_info_ex_bounded (member, current_object_size, current_object_tag_name, &offset, &size, &elem_size, &pointer_depth, 0, 0)) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+            
+            free (member);
+            expect (TOK_RPAREN, ")");
+            
+            return 1;
+        
+        }
+        
+        current_object_tag_name = last_found_member_tag_name;
+        free (member);
+        
+        if (tok.kind == TOK_LBRACK) {
+        
+            if (pointer_depth > 0) {
+            
+                emit_load_member_from_addr_reg_now (reg, reg, offset, DATA_PTR & 0x1f);
+                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
+            
+            } else {
+            
+                if (state->ofp && offset != 0) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+                    } else {
+                        fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
+                    }
+                
+                }
+                
+                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
+            
+            }
+        
+        } else {
+        
+            if (state->ofp && offset != 0) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+                } else {
+                    fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
+                }
+            
+            }
+        
+        }
+        
+        if (pointer_depth > 0) {
+            current_object_size = elem_size > 0 ? elem_size : DATA_PTR;
+        } else {
+            current_object_size = size;
+        }
+    
+    }
+    
+    expect (TOK_RPAREN, ")");
+    return 1;
+
+}
+
+static void emit_store_member_to_addr_reg_now (const char *addr_reg, int offset, const char *value_reg, int size) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (offset != 0) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    add %s, %d\n", addr_reg, offset);
+        } else {
+            fprintf (state->ofp, "    addl $%d, %%%s\n", offset, addr_reg);
+        }
+    
+    }
+    
+    emit_store_reg_to_deref_reg_now (addr_reg, value_reg, size);
+
+}
+
+static void emit_store_floating_member_to_addr_reg_now (const char *addr_reg, int offset, int size) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (offset != 0) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    add %s, %d\n", addr_reg, offset);
+        } else {
+            fprintf (state->ofp, "    addl $%d, %%%s\n", offset, addr_reg);
+        }
+    
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fstp %s [%s]\n" : "    fstp %s ptr [%s]\n", size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", addr_reg);
+    } else {
+        fprintf (state->ofp, "    fstp%s (%%%s)\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", addr_reg);
+    }
+
+}
+
+static void emit_load_symbol_address_for_copy_now (const char *reg, struct local_symbol *sym, const char *name) {
+
+    if (sym) {
+    
+        if (sym->is_static && sym->static_label) {
+            emit_load_address_to_reg_now (reg, sym->static_label);
+        } else {
+            emit_load_local_address_to_reg_now (reg, sym->offset);
+        }
+    
+    } else {
+        emit_load_address_to_reg_now (reg, name);
+    }
+
+}
+
+static void emit_copy_fixed_size_now (int size) {
+
+    int offset = 0;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    while (size - offset >= 4) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov ecx, dword [eax + %d]\n" : "    mov ecx, dword ptr [eax + %d]\n", offset);
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov dword [edx + %d], ecx\n" : "    mov dword ptr [edx + %d], ecx\n", offset);
+        
+        } else {
+        
+            fprintf (state->ofp, "    movl %d(%%eax), %%ecx\n", offset);
+            fprintf (state->ofp, "    movl %%ecx, %d(%%edx)\n", offset);
+        
+        }
+        
+        offset += 4;
+    
+    }
+    
+    while (size - offset >= 2) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov cx, word [eax + %d]\n" : "    mov cx, word ptr [eax + %d]\n", offset);
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov word [edx + %d], cx\n" : "    mov word ptr [edx + %d], cx\n", offset);
+        
+        } else {
+        
+            fprintf (state->ofp, "    movw %d(%%eax), %%cx\n", offset);
+            fprintf (state->ofp, "    movw %%cx, %d(%%edx)\n", offset);
+        
+        }
+        
+        offset += 2;
+    
+    }
+    
+    while (size - offset >= 1) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov cl, byte [eax + %d]\n" : "    mov cl, byte ptr [eax + %d]\n", offset);
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov byte [edx + %d], cl\n" : "    mov byte ptr [edx + %d], cl\n", offset);
+        
+        } else {
+        
+            fprintf (state->ofp, "    movb %d(%%eax), %%cl\n", offset);
+            fprintf (state->ofp, "    movb %%cl, %d(%%edx)\n", offset);
+        
+        }
+        
+        offset++;
+    
+    }
+
+}
+
+static void emit_memcpy_symbol_to_symbol_now (struct local_symbol *dst, const char *dst_name, struct local_symbol *src, const char *src_name, int size) {
+
+    emit_load_symbol_address_for_copy_now ("eax", src, src_name);
+    emit_load_symbol_address_for_copy_now ("edx", dst, dst_name);
+    emit_copy_fixed_size_now (size);
+
+}
+
+static int token_identifier_is_function_call_rhs_now (void) {
+
+    struct token *saved_tok;
+    int is_call;
+    
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+        return 0;
+    }
+    
+    /**
+     * Do not inspect tok.start/tok.caret to decide whether this identifier is
+     * followed by a call.  After macro substitution the spelling in the source
+     * can be a different length from tok.ident, e.g.
+     *
+     *     #define cc_parse_type ccpartype
+     *     member.type = cc_parse_type(reader);
+     *
+     * tok.ident is "ccpartype" but tok.caret still points into the original
+     * text "cc_parse_type(reader)".  The old spelling-based test missed the
+     * '(' and the aggregate-copy fast path treated the function symbol as an
+     * object, leaving the argument list unconsumed and producing "expected ;".
+     */
+    saved_tok = xmalloc (sizeof (*saved_tok));
+    *saved_tok = tok;
+    
+    if (tok.ident) {
+        saved_tok->ident = xstrdup (tok.ident);
+    }
+    
+    if (tok.start) {
+    
+        const char *old_start = tok.start;
+        const char *old_caret = tok.caret;
+        
+        saved_tok->start = xstrdup (old_start);
+        
+        if (old_caret && old_caret >= old_start) {
+            saved_tok->caret = saved_tok->start + (old_caret - old_start);
+        } else {
+            saved_tok->caret = saved_tok->start;
+        }
+    
+    }
+    
+    get_token ();
+    
+    is_call = (tok.kind == TOK_LPAREN);
+    unget_token (saved_tok);
+    
+    return is_call;
+
+}
+
+static struct token *clone_current_token_now (void) {
+
+    struct token *saved_tok = xmalloc (sizeof (*saved_tok));
+    *saved_tok = tok;
+    
+    if (tok.ident) {
+        saved_tok->ident = xstrdup (tok.ident);
+    }
+    
+    if (tok.start) {
+    
+        const char *old_start = tok.start;
+        const char *old_caret = tok.caret;
+        
+        saved_tok->start = xstrdup (old_start);
+        
+        if (old_caret && old_caret >= old_start) {
+            saved_tok->caret = saved_tok->start + (old_caret - old_start);
+        } else {
+            saved_tok->caret = saved_tok->start;
+        }
+    
+    }
+    
+    return saved_tok;
+
+}
+
+static int emit_aggregate_copy_from_current_rhs_to_addr_reg_now (const char *addr_reg, int offset, int size) {
+
+    struct local_symbol *rhs_sym;
+    char *rhs_name;
+    
+    const char *rhs_start;
+    const char *rhs_caret;
+    
+    unsigned long rhs_line;
+    
+    int rhs_global_index;
+    int rhs_size;
+    
+    int source_size;
+    int source_ready;
+    
+    /*
+     * Only use the aggregate-copy fast path when the destination is
+     * itself an aggregate object.  Pointer members can legally be assigned
+     * an array object, e.g. fp->intBuffer = buffer1; in pdpclib.  The RHS
+     * symbol then has a large array size, but the LHS is only a pointer, so
+     * emitting a fixed-size aggregate copy corrupts the FILE object.
+     */
+    if (size < (DATA_LLONG & 0x1f)) {
+        return 0;
+    }
+    
+    if (tok.kind == TOK_STAR) {
+    
+        struct token *saved_tok = clone_current_token_now ();
+        struct local_symbol *ptr_sym;
+        
+        char *ptr_name;
+        
+        int ptr_global_index;
+        int ptr_depth;
+        int ptr_pointed_size;
+        
+        get_token ();
+        
+        if (tok.kind != TOK_IDENT || !tok.ident) {
+        
+            unget_token (saved_tok);
+            return 0;
+        
+        }
+        
+        ptr_name = xstrdup (tok.ident);
+        ptr_sym = find_local_symbol (ptr_name);
+        ptr_global_index = find_global_symbol (ptr_name);
+        
+        if (!ptr_sym && ptr_global_index < 0) {
+        
+            free (ptr_name);
+            
+            unget_token (saved_tok);
+            return 0;
+        
+        }
+        
+        ptr_depth = ptr_sym ? ptr_sym->pointer_depth : get_global_symbol_pointer_depth (ptr_name);
+        ptr_pointed_size = ptr_sym ? ptr_sym->pointed_size : get_global_symbol_pointed_size (ptr_name);
+        
+        if (!ptr_sym && ptr_global_index >= 0
+            && get_global_symbol_kind (ptr_name) == GLOBAL_SYMBOL_FUNCTION) {
+        
+            const char *call_start = tok.start;
+            const char *call_caret = tok.caret;
+            unsigned long call_line = get_line_number ();
+            
+            get_token ();
+            
+            if (tok.kind != TOK_LPAREN || ptr_depth <= 0
+                || (ptr_depth == 1 && ptr_pointed_size > 0 && ptr_pointed_size < size)) {
+            
+                free (ptr_name);
+                
+                unget_token (saved_tok);
+                return 0;
+            
+            }
+            
+            emit_push_reg_now (addr_reg);
+            emit_call_identifier_to_reg_now (ptr_name, "eax", call_start, call_caret, call_line);
+            emit_pop_reg_now ("edx");
+            
+            if (offset != 0 && state->ofp) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    add edx, %d\n", offset);
+                } else {
+                    fprintf (state->ofp, "    addl $%d, %%edx\n", offset);
+                }
+            
+            }
+            
+            emit_copy_fixed_size_now (size);
+            
+            free (ptr_name);
+            return 1;
+        
+        }
+        
+        /*
+         * For aggregate initialization from a dereferenced pointer, keep the
+         * full pointed-to object size.  The old code masked pointed_size with
+         * 0x1f as if it were a DATA_* scalar type.  That turns e.g.
+         *
+         *     struct hashtab old_hashtab = *hashtab;
+         *
+         * from a 44-byte copy into a rejected aggregate fast path because
+         * 44 & 0x1f == 12.  The initializer then falls back to scalar code
+         * and copies only the first word, leaving old_hashtab mostly
+         * uninitialized and crashing in rehash().
+         */
+        source_size = ptr_depth > 1 ? (DATA_PTR & 0x1f) : ptr_pointed_size;
+        
+        if (ptr_depth <= 0 || source_size < size) {
+        
+            free (ptr_name);
+            
+            unget_token (saved_tok);
+            return 0;
+        
+        }
+        
+        emit_push_reg_now (addr_reg);
+        
+        if (ptr_sym) {
+        
+            if (ptr_sym->is_static && ptr_sym->static_label) {
+                emit_load_global_to_reg ("eax", ptr_sym->static_label, DATA_PTR);
+            } else {
+                emit_load_local_to_reg ("eax", ptr_sym->offset, DATA_PTR);
+            }
+        
+        } else {
+            emit_load_global_to_reg ("eax", ptr_name, DATA_PTR);
+        }
+        
+        get_token ();
+        
+        if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+        
+            enum token_kind member_op = tok.kind;
+            char *member;
+            
+            int member_offset = 0;
+            int member_size = DATA_INT & 0x1f;
+            int member_elem_size = DATA_INT & 0x1f;
+            int member_pointer_depth = 0;
+            int member_is_array = 0;
+            int member_incdec = 0;
+            
+            enum token_kind member_incdec_op = TOK_EOF;
+            const char *object_tag_name = ptr_sym ? ptr_sym->pointed_tag_name : 0;
+            
+            int object_size = ptr_sym ? ptr_sym->pointed_size : get_global_symbol_pointed_size (ptr_name);
+            get_token ();
+            
+            if (tok.kind != TOK_IDENT || !tok.ident) {
+            
+                free (ptr_name);
+                
+                unget_token (saved_tok);
+                return 0;
+            
+            }
+            
+            member = xstrdup (tok.ident);
+            get_token ();
+            
+            if (!find_member_info_ex_bounded (member, object_size, object_tag_name,
+                                              &member_offset, &member_size, &member_elem_size,
+                                              &member_pointer_depth, &member_is_array, 0)) {
+            
+                free (member);
+                free (ptr_name);
+                
+                unget_token (saved_tok);
+                return 0;
+            
+            }
+            
+            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+            
+                member_incdec = 1;
+                member_incdec_op = tok.kind;
+                
+                get_token ();
+            
+            }
+            
+            if (member_op != TOK_ARROW || member_pointer_depth <= 0 || member_elem_size < size) {
+            
+                free (member);
+                free (ptr_name);
+                
+                unget_token (saved_tok);
+                return 0;
+            
+            }
+            
+            emit_push_reg_now (addr_reg);
+            
+            if (ptr_sym) {
+            
+                if (ptr_sym->is_static && ptr_sym->static_label) {
+                    emit_load_global_to_reg ("ecx", ptr_sym->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg ("ecx", ptr_sym->offset, DATA_PTR);
+                }
+            
+            } else {
+                emit_load_global_to_reg ("ecx", ptr_name, DATA_PTR);
+            }
+            
+            if (state->ofp) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ?
+                        "    mov eax, dword [ecx + %d]\n" :
+                        "    mov eax, dword ptr [ecx + %d]\n", member_offset);
+                    
+                    if (member_incdec) {
+                    
+                        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ?
+                            "    %s dword [ecx + %d], %d\n" :
+                            "    %s dword ptr [ecx + %d], %d\n",
+                            member_incdec_op == TOK_INCR ? "add" : "sub",
+                            member_offset, member_elem_size);
+                    
+                    }
+                
+                } else {
+                
+                    fprintf (state->ofp, "    movl %d(%%ecx), %%eax\n", member_offset);
+                    
+                    if (member_incdec) {
+                    
+                        fprintf (state->ofp, "    %sl $%d, %d(%%ecx)\n",
+                            member_incdec_op == TOK_INCR ? "add" : "sub",
+                            member_elem_size, member_offset);
+                    
+                    }
+                
+                }
+            
+            }
+            
+            emit_pop_reg_now ("edx");
+            
+            if (offset != 0 && state->ofp) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    add edx, %d\n", offset);
+                } else {
+                    fprintf (state->ofp, "    addl $%d, %%edx\n", offset);
+                }
+            
+            }
+            
+            emit_copy_fixed_size_now (size);
+            
+            free (member);
+            free (ptr_name);
+            
+            return 1;
+        
+        }
+        
+        emit_pop_reg_now ("edx");
+        
+        if (offset != 0 && state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    add edx, %d\n", offset);
+            } else {
+                fprintf (state->ofp, "    addl $%d, %%edx\n", offset);
+            }
+        
+        }
+        
+        emit_copy_fixed_size_now (size);
+        
+        free (ptr_name);
+        return 1;
+    
+    }
+    
+    if (tok.kind == TOK_LPAREN) {
+    
+        struct token *saved_tok = clone_current_token_now ();
+        struct local_symbol *ptr_sym;
+        
+        char *ptr_name;
+        
+        const char *ptr_start;
+        const char *ptr_caret;
+        
+        unsigned long ptr_line;
+        
+        int ptr_global_index;
+        int ptr_depth;
+        
+        const char *ptr_tag_name;
+        
+        int current_object_size;
+        int have_direct_object_pointer;
+        
+        get_token ();
+        
+        if (tok.kind != TOK_STAR) {
+        
+            unget_token (saved_tok);
+            return 0;
+        
+        }
+        
+        get_token ();
+        
+        if (tok.kind != TOK_IDENT || !tok.ident) {
+        
+            unget_token (saved_tok);
+            return 0;
+        
+        }
+        
+        ptr_name = xstrdup (tok.ident);
+        ptr_start = tok.start;
+        ptr_caret = tok.caret;
+        ptr_line = get_line_number ();
+        ptr_sym = find_local_symbol (ptr_name);
+        ptr_global_index = find_global_symbol (ptr_name);
+        
+        if (!ptr_sym && ptr_global_index < 0) {
+        
+            free (ptr_name);
+            
+            unget_token (saved_tok);
+            return 0;
+        
+        }
+        
+        ptr_depth = ptr_sym ? ptr_sym->pointer_depth : get_global_symbol_pointer_depth (ptr_name);
+        ptr_tag_name = ptr_sym ? ptr_sym->pointed_tag_name : 0;
+        
+        current_object_size = ptr_sym ? ptr_sym->pointed_size : get_global_symbol_pointed_size (ptr_name);
+        source_size = current_object_size;
+        
+        if (ptr_tag_name) {
+        
+            struct aggregate_tag_entry *entry = find_aggregate_tag (ptr_tag_name, 0);
+            
+            if (entry) {
+            
+                current_object_size = entry->size;
+                source_size = current_object_size;
+            
+            }
+        
+        }
+        
+        get_token ();
+        
+        if (tok.kind != TOK_RPAREN || ptr_depth <= 0) {
+        
+            free (ptr_name);
+            
+            unget_token (saved_tok);
+            return 0;
+        
+        }
+        
+        get_token ();
+        
+        if (tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
+        
+            free (ptr_name);
+            
+            unget_token (saved_tok);
+            return 0;
+        
+        }
+        
+        emit_push_reg_now (addr_reg);
+        
+        if (ptr_sym) {
+        
+            if (ptr_sym->is_static && ptr_sym->static_label) {
+                emit_load_global_to_reg ("eax", ptr_sym->static_label, DATA_PTR);
+            } else {
+                emit_load_local_to_reg ("eax", ptr_sym->offset, DATA_PTR);
+            }
+        
+        } else {
+            emit_load_global_to_reg ("eax", ptr_name, DATA_PTR);
+        }
+        
+        emit_load_deref_reg_now ("eax", DATA_PTR);
+        have_direct_object_pointer = 1;
+        
+        while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT || tok.kind == TOK_LBRACK) {
+        
+            if (tok.kind == TOK_LBRACK) {
+            
+                emit_parse_postfix_subscript_scaled_address_to_reg_now ("eax", DATA_PTR);
+                
+                current_object_size = DATA_PTR;
+                continue;
+            
+            }
+            
+            {
+            
+                enum token_kind member_op = tok.kind;
+                char *member;
+                
+                int member_offset = 0;
+                int member_size = DATA_INT & 0x1f;
+                int member_elem_size = DATA_INT & 0x1f;
+                int member_pointer_depth = 0;
+                int member_is_array = 0;
+                
+                get_token ();
+                
+                if (tok.kind != TOK_IDENT || !tok.ident) {
+                
+                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret,
+                        "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+                    
+                    free (ptr_name);
+                    return 0;
+                
+                }
+                
+                member = xstrdup (tok.ident);
+                get_token ();
+                
+                if (!find_member_info_ex_bounded (member, current_object_size, ptr_tag_name,
+                                                  &member_offset, &member_size, &member_elem_size,
+                                                  &member_pointer_depth, &member_is_array, 0)) {
+                
+                    report_line_at (get_filename (), ptr_line, REPORT_ERROR, ptr_start, ptr_caret,
+                        "unknown member '%s'", member);
+                    
+                    free (member);
+                    free (ptr_name);
+                    
+                    return 0;
+                
+                }
+                
+                ptr_tag_name = last_found_member_tag_name;
+                
+                if (member_op == TOK_ARROW) {
+                
+                    if (have_direct_object_pointer) {
+                        have_direct_object_pointer = 0;
+                    } else {
+                        emit_load_deref_reg_now ("eax", DATA_PTR);
+                    }
+                
+                } else {
+                    have_direct_object_pointer = 0;
+                }
+                
+                if (member_offset != 0 && state->ofp) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    add eax, %d\n", member_offset);
+                    } else {
+                        fprintf (state->ofp, "    addl $%d, %%eax\n", member_offset);
+                    }
+                
+                }
+                
+                current_object_size = member_size;
+                source_size = member_size;
+                
+                free (member);
+            
+            }
+        
+        }
+        
+        if (source_size < size) {
+        
+            free (ptr_name);
+            return 0;
+        
+        }
+        
+        emit_pop_reg_now ("edx");
+        
+        if (offset != 0 && state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    add edx, %d\n", offset);
+            } else {
+                fprintf (state->ofp, "    addl $%d, %%edx\n", offset);
+            }
+        
+        }
+        
+        emit_copy_fixed_size_now (size);
+        
+        free (ptr_name);
+        return 1;
+    
+    }
+    
+    if (tok.kind != TOK_IDENT) {
+        return 0;
+    }
+    
+    /*
+     * A function-call RHS that returns a struct/union must be parsed by
+     * the normal expression code.  The aggregate-copy fast path is only
+     * for copying an already-existing aggregate object by address.
+     */
+    if (token_identifier_is_function_call_rhs_now ()) {
+        return 0;
+    }
+    
+    if (!rhs_text_is_plain_aggregate_lvalue_now (tok.caret ? tok.caret : tok.start)) {
+        return 0;
+    }
+    
+    rhs_name = xstrdup (tok.ident);
+    rhs_start = tok.start;
+    rhs_caret = tok.caret;
+    rhs_line = get_line_number ();
+
+    rhs_sym = find_local_symbol (rhs_name);
+    rhs_global_index = find_global_symbol (rhs_name);
+    
+    if (!rhs_sym && rhs_global_index < 0) {
+    
+        free (rhs_name);
+        return 0;
+    
+    }
+    
+    rhs_size = rhs_sym ? rhs_sym->size : get_global_symbol_size (rhs_name);
+    
+    {
+    
+        struct token *saved_rhs_tok = clone_current_token_now ();
+        get_token ();
+        
+        if (rhs_size <= (DATA_LLONG & 0x1f) && tok.kind != TOK_DOT && tok.kind != TOK_ARROW && tok.kind != TOK_LBRACK) {
+        
+            free (rhs_name);
+            
+            unget_token (saved_rhs_tok);
+            return 0;
+        
+        }
+        
+        unget_token (saved_rhs_tok);
+    
+    }
+    
+    emit_push_reg_now (addr_reg);
+    get_token ();
+    
+    source_ready = 0;
+    source_size = rhs_size;
+    
+    if (tok.kind == TOK_DOT || tok.kind == TOK_ARROW || tok.kind == TOK_LBRACK) {
+    
+        if (!emit_parse_postfix_copy_source_address_now ("eax", rhs_sym, rhs_name, rhs_start, rhs_caret, rhs_line)) {
+        
+            free (rhs_name);
+            return 0;
+        
+        }
+        
+        source_size = postfix_copy_lvalue_size;
+        source_ready = 1;
+    
+    }
+    
+    if (source_size < size) {
+    
+        free (rhs_name);
+        return 0;
+    
+    }
+    
+    if (!source_ready) {
+        emit_load_symbol_address_for_copy_now ("eax", rhs_sym, rhs_name);
+    }
+    
+    emit_pop_reg_now ("edx");
+    
+    if (offset != 0 && state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    add edx, %d\n", offset);
+        } else {
+            fprintf (state->ofp, "    addl $%d, %%edx\n", offset);
+        }
+    
+    }
+    
+    emit_copy_fixed_size_now (size);
+    
+    free (rhs_name);
+    return 1;
+
+}
+
+static void emit_load_member_address_for_copy_now (const char *reg, struct local_symbol *sym, const char *name, enum token_kind member_op, int offset) {
+
+    if (sym) {
+    
+        if (member_op == TOK_DOT || sym->is_array) {
+        
+            if (sym->is_static && sym->static_label) {
+                emit_load_address_to_reg_now (reg, sym->static_label);
+            } else {
+                emit_load_local_address_to_reg_now (reg, sym->offset);
+            }
+        
+        } else if (sym->is_static && sym->static_label) {
+            emit_load_global_to_reg (reg, sym->static_label, DATA_PTR);
+        } else {
+            emit_load_local_to_reg (reg, sym->offset, DATA_PTR);
+        }
+    
+    } else {
+    
+        if (member_op == TOK_DOT || get_global_symbol_array (name)) {
+            emit_load_address_to_reg_now (reg, name);
+        } else {
+            emit_load_global_to_reg (reg, name, DATA_PTR);
+        }
+    
+    }
+    
+    if (offset != 0 && state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+        } else {
+            fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
+        }
+    
+    }
+
+}
+
+static int emit_parse_postfix_copy_source_address_now (const char *reg, struct local_symbol *src, const char *src_name, const char *name_start, const char *name_caret, unsigned long name_line) {
+
+    int have_address = 0;
+    int have_direct_object_pointer = 0;
+    int last_elem_size = DATA_INT & 0x1f;
+    int last_lvalue_size = DATA_INT & 0x1f;
+    
+    const char *current_object_tag_name = 0;
+    int current_object_size = 0;
+    
+    postfix_copy_lvalue_size = DATA_INT & 0x1f;
+    
+    if (!reg) {
+        reg = "eax";
+    }
+    
+    if (tok.kind == TOK_LPAREN) {
+    
+        if (src) {
+            return 0;
+        }
+        
+        ensure_global_function_symbol (src_name, name_start, name_caret, name_line);
+        emit_call_identifier_to_reg_now (src_name, reg, name_start, name_caret, name_line);
+        
+        have_address = 1;
+        have_direct_object_pointer = 1;
+    
+    }
+    
+    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+    
+        enum token_kind postfix_op = tok.kind;
+        
+        int pointer_depth;
+        int pointed_size;
+        
+        get_token ();
+        
+        if (tok.kind != TOK_LBRACK) {
+            return 0;
+        }
+        
+        if (src) {
+        
+            pointer_depth = src->pointer_depth;
+            pointed_size = src->pointed_size;
+            
+            if (src->is_static && src->static_label) {
+                emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
+            } else {
+                emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+            }
+        
+        } else if (find_global_symbol (src_name) >= 0) {
+        
+            pointer_depth = get_global_symbol_pointer_depth (src_name);
+            pointed_size = get_global_symbol_pointed_size (src_name);
+            
+            emit_load_global_to_reg (reg, src_name, DATA_PTR);
+        
+        } else {
+        
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", src_name);
+            return 0;
+        
+        }
+        
+        if (pointer_depth <= 0) {
+        
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "subscripted value is not a pointer");
+            return 0;
+        }
+        
+        last_elem_size = pointer_depth > 1 ? (DATA_PTR & 0x1f) : (pointed_size > 0 ? (pointed_size & 0x1f) : (DATA_INT & 0x1f));
+        last_lvalue_size = last_elem_size;
+        
+        have_address = 1;
+        have_direct_object_pointer = 0;
+        
+        emit_incdec_symbol_now (src, src_name, postfix_op, name_line, name_start, name_caret);
+    
+    }
+    
+    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT || tok.kind == TOK_LBRACK) {
+    
+        if (tok.kind == TOK_LBRACK) {
+        
+            int elem_size = last_elem_size;
+            
+            if (!have_address) {
+            
+                if (src) {
+                
+                    if (src->is_array) {
+                        emit_load_symbol_address_for_copy_now (reg, src, src_name);
+                    } else if (src->is_static && src->static_label) {
+                        emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+                    }
+                
+                    elem_size = src->is_array ? (src->pointer_depth ? DATA_PTR : (src->array_element_size > 0 ? src->array_element_size : src->pointed_size)) :
+                        (src->pointer_depth > 1 ? DATA_PTR : src->pointed_size);
+                    
+                    if (src->is_array && !src->pointer_depth) {
+                        current_object_tag_name = src->tag_name;
+                    } else if (!src->is_array && src->pointer_depth > 0) {
+                        current_object_tag_name = src->pointed_tag_name;
+                    }
+                
+                } else {
+                
+                    if (get_global_symbol_array (src_name)) {
+                        emit_load_address_to_reg_now (reg, src_name);
+                    } else {
+                        emit_load_global_to_reg (reg, src_name, DATA_PTR);
+                    }
+                    
+                    elem_size = get_global_symbol_array (src_name) ?
+                        (get_global_symbol_pointer_depth (src_name) ? DATA_PTR : (get_global_symbol_array_element_size (src_name) > 0 ? get_global_symbol_array_element_size (src_name) : get_global_symbol_pointed_size (src_name))) :
+                            (get_global_symbol_pointer_depth (src_name) > 1 ? DATA_PTR : get_global_symbol_pointed_size (src_name));
+                    
+                    if (get_global_symbol_array (src_name) && !get_global_symbol_pointer_depth (src_name)) {
+                        current_object_tag_name = get_global_symbol_tag_name (src_name);
+                    } else if (!get_global_symbol_array (src_name) && get_global_symbol_pointer_depth (src_name) > 0) {
+                        current_object_tag_name = get_global_symbol_tag_name (src_name);
+                    }
+                
+                }
+                
+                if (elem_size <= 0) {
+                    elem_size = DATA_INT & 0x1f;
+                }
+                
+                have_address = 1;
+            
+            }
+            
+            emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
+            
+            last_elem_size = elem_size;
+            last_lvalue_size = elem_size;
+            
+            current_object_size = elem_size;
+            continue;
+        
+        }
+        
+        {
+        
+            enum token_kind member_op = tok.kind;
+            char *member;
+            
+            const char *member_start;
+            const char *member_caret;
+            
+            unsigned long member_line;
+            
+            int member_offset = 0;
+            int member_size = DATA_INT & 0x1f;
+            int member_elem_size = DATA_INT & 0x1f;
+            int member_pointer_depth = 0;
+            int member_is_array = 0;
+            
+            get_token ();
+            
+            member_start = tok.start;
+            member_caret = tok.caret;
+            member_line = get_line_number ();
+            
+            if (tok.kind != TOK_IDENT) {
+            
+                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret,
+                    "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+                
+                return 0;
+            
+            }
+            
+            member = xstrdup (tok.ident);
+            get_token ();
+            
+            if (current_object_size <= 0) {
+            
+                if (src) {
+                
+                    if (member_op == TOK_ARROW && src->pointer_depth > 0) {
+                    
+                        current_object_size = src->pointed_size;
+                        current_object_tag_name = src->pointed_tag_name;
+                    
+                    } else {
+                    
+                        current_object_size = src->size;
+                        current_object_tag_name = src->tag_name;
+                    
+                    }
+                
+                } else {
+                
+                    if (member_op == TOK_ARROW && get_global_symbol_pointer_depth (src_name) > 0) {
+                    
+                        current_object_size = get_global_symbol_pointed_size (src_name);
+                        current_object_tag_name = get_global_symbol_tag_name (src_name);
+                    
+                    } else {
+                    
+                        current_object_size = get_global_symbol_size (src_name);
+                        current_object_tag_name = get_global_symbol_tag_name (src_name);
+                    
+                    }
+                
+                }
+            
+            }
+            
+            if (!find_member_info_ex_bounded (member, current_object_size, current_object_tag_name, &member_offset, &member_size, &member_elem_size, &member_pointer_depth, &member_is_array, 0)) {
+            
+                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret,
+                    "unknown member '%s'", member);
+                
+                free (member);
+                return 0;
+            
+            }
+            
+            {
+            
+                const char *member_tag_name = last_found_member_tag_name;
+                
+                if (member_is_array && member_pointer_depth > 0) {
+                
+                    /*
+                     * For an array member whose element type is a pointer,
+                     * the subscript step is one pointer.  Do not replace it
+                     * with the pointed aggregate size from the member tag.
+                     */
+                    member_elem_size = DATA_PTR;
+                
+                } else if (member_pointer_depth > 1) {
+                    member_elem_size = DATA_PTR;
+                } else if (member_pointer_depth == 1 && member_tag_name) {
+                
+                    struct aggregate_tag_entry *entry = find_aggregate_tag (member_tag_name, 0);
+                    
+                    if (entry) {
+                        member_elem_size = entry->size;
+                    }
+                
+                }
+                
+                current_object_tag_name = member_tag_name;
+            
+            }
+            
+            free (member);
+            
+            if (!have_address) {
+            
+                emit_load_member_address_for_copy_now (reg, src, src_name, member_op, 0);
+                have_address = 1;
+            
+            } else if (member_op == TOK_ARROW) {
+            
+                if (have_direct_object_pointer) {
+                    have_direct_object_pointer = 0;
+                } else {
+                    emit_load_deref_reg_now (reg, DATA_PTR);
+                }
+            
+            } else {
+                have_direct_object_pointer = 0;
+            }
+            
+            if (tok.kind == TOK_LBRACK && member_pointer_depth > 0 && !member_is_array) {
+                emit_load_member_from_addr_reg_now (reg, reg, member_offset, DATA_PTR & 0x1f);
+            } else if (state->ofp && member_offset != 0) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    add %s, %d\n", reg, member_offset);
+                } else {
+                    fprintf (state->ofp, "    addl $%d, %%%s\n", member_offset, reg);
+                }
+            
+            }
+            
+            last_elem_size = member_elem_size;
+            last_lvalue_size = member_size;
+            
+            if (member_pointer_depth > 0 || member_is_array) {
+                current_object_size = member_elem_size;
+            } else {
+                current_object_size = member_size;
+            }
+        
+        }
+    
+    }
+    
+    postfix_copy_lvalue_size = last_lvalue_size;
+    return have_address;
+
+}
+
+static void emit_load_floating_deref_reg_now (const char *reg, int size) {
+
+    if (!state->ofp) {
+        return;
+    }
+
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+
+        if (size == (DATA_FLOAT & 0x1f)) {
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fld dword [%s]\n" : "    fld dword ptr [%s]\n", reg);
+        } else {
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fld qword [%s]\n" : "    fld qword ptr [%s]\n", reg);
+        }
+
+    } else {
+
+        if (size == (DATA_FLOAT & 0x1f)) {
+            fprintf (state->ofp, "    flds (%%%s)\n", reg);
+        } else {
+            fprintf (state->ofp, "    fldl (%%%s)\n", reg);
+        }
+
+    }
+
+}
+
+static void emit_add_const_to_reg_now (const char *reg, int offset) {
+
+    if (!state->ofp || !reg || offset == 0) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+    } else {
+        fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
+    }
+
+}
+
+static void emit_load_floating_member_from_addr_reg_now (const char *reg, int offset, int size) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (size == (DATA_FLOAT & 0x1f)) {
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fld dword [%s + %d]\n" : "    fld dword ptr [%s + %d]\n", reg, offset);
+        } else {
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fld qword [%s + %d]\n" : "    fld qword ptr [%s + %d]\n", reg, offset);
+        }
+    
+    } else {
+    
+        if (size == (DATA_FLOAT & 0x1f)) {
+            fprintf (state->ofp, "    flds %d(%%%s)\n", offset, reg);
+        } else {
+            fprintf (state->ofp, "    fldl %d(%%%s)\n", offset, reg);
+        }
+    
+    }
+
+}
+
+static void save_parse_type_state_now (
+
+    int *saved_type_size,
+    int *saved_storage_class,
+    int *saved_is_aggregate,
+    int *saved_is_void,
+    int *saved_is_unsigned,
+    int *saved_is_floating,
+    int *saved_has_tag,
+    int *saved_is_inline,
+    int *saved_field_count,
+    int saved_fields[MAX_AGG_FIELDS],
+    int *saved_declarator_is_pointer,
+    int *saved_declarator_pointer_depth,
+    int *saved_declarator_has_array,
+    int *saved_declarator_has_function,
+    int *saved_declarator_array_unsized,
+    int *saved_declarator_array_dimensions,
+    long *saved_declarator_array_count,
+    long *saved_declarator_first_array_count) {
+
+    int i;
+    
+    *saved_type_size = parsed_type_size;
+    *saved_storage_class = parsed_storage_class;
+    *saved_is_aggregate = parsed_type_is_aggregate;
+    *saved_is_void = parsed_type_is_void;
+    *saved_is_unsigned = parsed_type_is_unsigned;
+    *saved_is_floating = parsed_type_is_floating;
+    *saved_has_tag = parsed_type_has_tag;
+    *saved_is_inline = parsed_type_is_inline;
+    *saved_field_count = parsed_field_count;
+    
+    for (i = 0; i < *saved_field_count && i < MAX_AGG_FIELDS; i++) {
+        saved_fields[i] = parsed_field_sizes[i];
+    }
+    
+    *saved_declarator_is_pointer = declarator_is_pointer;
+    *saved_declarator_pointer_depth = declarator_pointer_depth;
+    *saved_declarator_has_array = declarator_has_array;
+    *saved_declarator_has_function = declarator_has_function;
+    *saved_declarator_array_unsized = declarator_array_unsized;
+    *saved_declarator_array_dimensions = declarator_array_dimensions;
+    *saved_declarator_array_count = declarator_array_count;
+    *saved_declarator_first_array_count = declarator_first_array_count;
+
+}
+
+static void restore_parse_type_state_now (
+    int saved_type_size,
+    int saved_storage_class,
+    int saved_is_aggregate,
+    int saved_is_void,
+    int saved_is_unsigned,
+    int saved_is_floating,
+    int saved_has_tag,
+    int saved_is_inline,
+    int saved_field_count,
+    int saved_fields[MAX_AGG_FIELDS],
+    int saved_declarator_is_pointer,
+    int saved_declarator_pointer_depth,
+    int saved_declarator_has_array,
+    int saved_declarator_has_function,
+    int saved_declarator_array_unsized,
+    int saved_declarator_array_dimensions,
+    long saved_declarator_array_count,
+    long saved_declarator_first_array_count) {
+
+    int i;
+    
+    parsed_type_size = saved_type_size;
+    parsed_storage_class = saved_storage_class;
+    parsed_type_is_aggregate = saved_is_aggregate;
+    parsed_type_is_void = saved_is_void;
+    parsed_type_is_unsigned = saved_is_unsigned;
+    parsed_type_is_floating = saved_is_floating;
+    parsed_type_has_tag = saved_has_tag;
+    parsed_type_is_inline = saved_is_inline;
+    
+    clear_parsed_fields ();
+    
+    for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
+        parsed_field_sizes[i] = saved_fields[i];
+    }
+    
+    parsed_field_count = saved_field_count;
+    declarator_is_pointer = saved_declarator_is_pointer;
+    declarator_pointer_depth = saved_declarator_pointer_depth;
+    declarator_has_array = saved_declarator_has_array;
+    declarator_has_function = saved_declarator_has_function;
+    declarator_array_unsized = saved_declarator_array_unsized;
+    declarator_array_dimensions = saved_declarator_array_dimensions;
+    declarator_array_count = saved_declarator_array_count;
+    declarator_first_array_count = saved_declarator_first_array_count;
+
+}
+
+static int parse_builtin_va_arg_type_now (int *out_size, int *out_unsigned, int *out_pointer, int *out_floating) {
+
+    int saved_type_size;
+    int saved_storage_class;
+    int saved_is_aggregate;
+    int saved_is_void;
+    int saved_is_unsigned;
+    int saved_is_floating;
+    int saved_has_tag;
+    int saved_is_inline;
+    int saved_field_count;
+    int saved_fields[MAX_AGG_FIELDS];
+    int saved_declarator_is_pointer;
+    int saved_declarator_pointer_depth;
+    int saved_declarator_has_array;
+    int saved_declarator_has_function;
+    int saved_declarator_array_unsized;
+    int saved_declarator_array_dimensions;
+    
+    long saved_declarator_array_count;
+    long saved_declarator_first_array_count;
+    
+    char *type_name = 0;
+    
+    int base_size;
+    int pointer_depth;
+    int is_unsigned;
+    int is_floating;
+    
+    save_parse_type_state_now (&saved_type_size, &saved_storage_class,
+        &saved_is_aggregate, &saved_is_void, &saved_is_unsigned,
+        &saved_is_floating, &saved_has_tag, &saved_is_inline,
+        &saved_field_count, saved_fields, &saved_declarator_is_pointer,
+        &saved_declarator_pointer_depth, &saved_declarator_has_array,
+        &saved_declarator_has_function, &saved_declarator_array_unsized,
+        &saved_declarator_array_dimensions, &saved_declarator_array_count,
+        &saved_declarator_first_array_count);
+    
+    declarator_is_pointer = 0;
+    declarator_pointer_depth = 0;
+    declarator_has_array = 0;
+    declarator_has_function = 0;
+    declarator_array_unsized = 0;
+    declarator_array_count = 0;
+    declarator_first_array_count = 1;
+    declarator_array_dimensions = 0;
+    
+    parse_type_spec ();
+    base_size = parsed_type_size & 0x1f;
+    
+    is_unsigned = parsed_type_is_unsigned;
+    is_floating = parsed_type_is_floating;
+    
+    if (tok.kind != TOK_RPAREN) {
+        parse_declarator (&type_name);
+    }
+    
+    pointer_depth = declarator_is_pointer ? (declarator_pointer_depth > 0 ? declarator_pointer_depth : 1) : 0;
+    
+    if (type_name) {
+        free (type_name);
+    }
+    
+    if (out_pointer) {
+        *out_pointer = pointer_depth;
+    }
+    
+    if (out_unsigned) {
+        *out_unsigned = is_unsigned;
+    }
+    
+    if (out_floating) {
+        *out_floating = is_floating;
+    }
+    
+    if (out_size) {
+        *out_size = pointer_depth > 0 ? (DATA_PTR & 0x1f) : base_size;
+    }
+    
+    restore_parse_type_state_now (saved_type_size, saved_storage_class,
+        saved_is_aggregate, saved_is_void, saved_is_unsigned,
+        saved_is_floating, saved_has_tag, saved_is_inline,
+        saved_field_count, saved_fields, saved_declarator_is_pointer,
+        saved_declarator_pointer_depth, saved_declarator_has_array,
+        saved_declarator_has_function, saved_declarator_array_unsized,
+        saved_declarator_array_dimensions, saved_declarator_array_count,
+        saved_declarator_first_array_count);
+    
+    return 1;
+
+}
+
+static int emit_parse_builtin_va_arg_address_to_reg_now (const char *reg, int *out_size, int *out_unsigned, int *out_pointer, int *out_floating) {
+
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    const char *scratch_reg;
+    
+    unsigned long name_line;
+    unsigned long inc;
+    
+    struct local_symbol *src;
+    
+    int global_index;
+    int size = DATA_INT & 0x1f;
+    int is_unsigned = 1;
+    int pointer_depth = 0;
+    int is_floating = 0;
+    int deref_lvalue = 0;
+    int paren_lvalue = 0;
+    
+    if (tok.kind != TOK_LPAREN) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    if (tok.kind == TOK_LPAREN) {
+    
+        paren_lvalue = 1;
+        get_token ();
+    
+    }
+    
+    if (tok.kind == TOK_STAR) {
+    
+        deref_lvalue = 1;
+        get_token ();
+    
+    }
+    
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected va_list object in __scc_builtin_va_arg");
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    get_token ();
+    
+    if (paren_lvalue) {
+        expect (TOK_RPAREN, ")");
+    }
+    
+    expect (TOK_COMMA, ",");
+    
+    if (!is_type_start (tok.kind)) {
+    
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected type name in __scc_builtin_va_arg");
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    parse_builtin_va_arg_type_now (&size, &is_unsigned, &pointer_depth, &is_floating);
+    expect (TOK_RPAREN, ")");
+    
+    if (size <= 0) {
+        size = DATA_INT & 0x1f;
+    }
+    
+    inc = (unsigned long) size;
+    
+    src = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (!src && global_index < 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (deref_lvalue) {
+    
+        scratch_reg = strcmp (reg, "edx") == 0 ? "ecx" : "edx";
+        
+        if (src) {
+        
+            if (src->is_static && src->static_label) {
+                emit_load_global_to_reg (scratch_reg, src->static_label, DATA_PTR);
+            } else {
+                emit_load_local_to_reg (scratch_reg, src->offset, DATA_PTR);
+            }
+        
+        } else {
+            emit_load_global_to_reg (scratch_reg, name, DATA_PTR);
+        }
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [%s]\n" : "    mov %s, dword ptr [%s]\n", reg, scratch_reg);
+                fprintf (state->ofp, "    push %s\n", reg);
+                fprintf (state->ofp, "    add %s, %lu\n", reg, inc);
+                fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov dword [%s], %s\n" : "    mov dword ptr [%s], %s\n", scratch_reg, reg);
+                fprintf (state->ofp, "    pop %s\n", reg);
+            
+            } else {
+            
+                fprintf (state->ofp, "    movl (%%%s), %%%s\n", scratch_reg, reg);
+                fprintf (state->ofp, "    pushl %%%s\n", reg);
+                fprintf (state->ofp, "    addl $%lu, %%%s\n", inc, reg);
+                fprintf (state->ofp, "    movl %%%s, (%%%s)\n", reg, scratch_reg);
+                fprintf (state->ofp, "    subl $%lu, %%%s\n", inc, reg);
+                fprintf (state->ofp, "    popl %%%s\n", reg);
+            
+            }
+        
+        }
+    
+    } else {
+    
+        if (src) {
+        
+            if (src->is_static && src->static_label) {
+                emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
+            } else {
+                emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+            }
+        
+        } else {
+            emit_load_global_to_reg (reg, name, DATA_PTR);
+        }
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                fprintf (state->ofp, "    push %s\n", reg);
+                fprintf (state->ofp, "    add %s, %lu\n", reg, inc);
+            
+            } else {
+            
+                fprintf (state->ofp, "    pushl %%%s\n", reg);
+                fprintf (state->ofp, "    addl $%lu, %%%s\n", inc, reg);
+            
+            }
+        
+        }
+        
+        if (src) {
+        
+            if (src->is_static && src->static_label) {
+                emit_store_reg_to_global (src->static_label, DATA_PTR, reg);
+            } else {
+                emit_store_reg_to_local (src->offset, DATA_PTR, reg);
+            }
+        
+        } else {
+            emit_store_reg_to_global (name, DATA_PTR, reg);
+        }
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    pop %s\n", reg);
+            } else {
+                fprintf (state->ofp, "    popl %%%s\n", reg);
+            }
+        
+        }
+    
+    }
+    
+    if (out_size) {
+        *out_size = size;
+    }
+    
+    if (out_unsigned) {
+        *out_unsigned = is_unsigned;
+    }
+    
+    if (out_pointer) {
+        *out_pointer = pointer_depth;
+    }
+    
+    if (out_floating) {
+        *out_floating = is_floating;
+    }
+    
+    free (name);
+    return 1;
+
+}
+
+static int emit_load_parenthesized_indirect_member_to_reg_now (const char *reg) {
+
+    const char *p;
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    struct local_symbol *src;
+    
+    int global_index;
+    int current_object_size;
+    
+    const char *current_tag_name;
+    
+    int first_member;
+    int last_member_size;
+    int last_member_pointer_depth;
+    int last_member_elem_size;
+    
+    if (tok.kind != TOK_STAR || !tok.caret) {
+        return 0;
+    }
+    
+    p = tok.caret + 1;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    p++;
+    
+    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;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '.' && !(*p == '-' && p[1] == '>')) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    get_token ();
+    
+    expect (TOK_RPAREN, ")");
+    
+    src = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (src) {
+    
+        if (src->is_static && src->static_label) {
+            emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
+        } else {
+            emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+        }
+        
+        current_object_size = src->pointed_size;
+        current_tag_name = src->pointed_tag_name;
+    
+    } else if (global_index >= 0) {
+    
+        emit_load_global_to_reg (reg, name, DATA_PTR);
+        
+        current_object_size = get_global_symbol_pointed_size (name);
+        current_tag_name = 0;
+    
+    } else {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    free (name);
+    
+    emit_load_deref_reg_now (reg, DATA_PTR);
+    first_member = 1;
+    
+    last_member_size = DATA_INT & 0x1f;
+    last_member_pointer_depth = 0;
+    last_member_elem_size = DATA_INT & 0x1f;
+    
+    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+    
+        enum token_kind member_op = tok.kind;
+        char *member;
+        
+        const char *member_start;
+        const char *member_caret;
+        
+        unsigned long member_line;
+        
+        int member_offset = 0;
+        int member_size = DATA_INT & 0x1f;
+        int member_elem_size = DATA_INT & 0x1f;
+        int member_pointer_depth = 0;
+        int member_is_array = 0;
+        
+        get_token ();
+        
+        member_start = tok.start;
+        member_caret = tok.caret;
+        member_line = get_line_number ();
+        
+        if (tok.kind != TOK_IDENT || !tok.ident) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+            return 1;
+        
+        }
+        
+        member = xstrdup (tok.ident);
+        get_token ();
+        
+        if (!find_member_info_ex_bounded (member, current_object_size, current_tag_name, &member_offset, &member_size, &member_elem_size, &member_pointer_depth, &member_is_array, 0)) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+            
+            free (member);
+            return 1;
+        
+        }
+        
+        free (member);
+        
+        if (!first_member && member_op == TOK_ARROW) {
+            emit_load_deref_reg_now (reg, DATA_PTR);
+        }
+        
+        if (member_offset != 0 && state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    add %s, %d\n", reg, member_offset);
+            } else {
+                fprintf (state->ofp, "    addl $%d, %%%s\n", member_offset, reg);
+            }
+        
+        }
+        
+        current_object_size = member_size;
+        current_tag_name = last_found_member_tag_name;
+        
+        last_member_size = member_size;
+        last_member_pointer_depth = member_pointer_depth;
+        last_member_elem_size = member_elem_size;
+        
+        first_member = 0;
+    
+    }
+    
+    emit_load_deref_reg_now (reg, last_member_size);
+    
+    if (last_member_pointer_depth > 0) {
+        set_rhs_last_pointer_info (last_member_pointer_depth, last_member_elem_size);
+    } else {
+        clear_rhs_last_pointer_info ();
+    }
+    
+    return 1;
+
+}
+
+static int source_starts_parenthesized_deref_postfix_incdec_subscript_at (const char *p) {
+
+    if (!p || *p != '*') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    p++;
+    
+    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;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((p[0] == '+' && p[1] == '+') || (p[0] == '-' && p[1] == '-'))) {
+        return 0;
+    }
+    
+    p += 2;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return 1;
+
+}
+
+static int source_starts_lparen_deref_subscript_at (const char *p) {
+
+    if (!p || *p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '*') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    p++;
+    
+    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;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '[';
+
+}
+
+static int source_starts_lparen_deref_postfix_incdec_at (const char *p) {
+
+    if (!p) {
+        return 0;
+    }
+    
+    /*
+     * Most callers pass the caret at the opening parenthesis, but some
+     * token paths leave it just after the '('.  Accept both positions so
+     * a statement such as:
+     *
+     *     (*parameter_count)++;
+     *
+     * is always routed through the dereferenced-object inc/dec emitter, not
+     * the ordinary pointer-variable inc/dec path.  The latter scales by the
+     * pointed-to size and would emit addl $4 for int *, corrupting counts.
+     */
+    if (*p == '(') {
+        p++;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '*') {
+        return 0;
+    }
+    
+    return source_starts_parenthesized_deref_postfix_incdec_subscript_at (p);
+
+}
+
+static int emit_load_parenthesized_deref_postfix_incdec_subscript_to_reg_now (const char *reg) {
+
+    enum token_kind op;
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    struct local_symbol *src;
+    
+    int global_index;
+    int pointer_depth = 0;
+    int pointed_size = DATA_INT & 0x1f;
+    int elem_size = DATA_INT & 0x1f;
+    int lvalue_size = DATA_INT & 0x1f;
+    int step = 1;
+    
+    const char *addr_reg;
+    
+    if (tok.kind != TOK_STAR) {
+        return 0;
+    }
+    
+    if (!source_starts_parenthesized_deref_postfix_incdec_subscript_at (tok.caret)) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    get_token ();
+    
+    if (tok.kind != TOK_RPAREN) {
+    
+        free (name);
+        return 0;
+    
+    }
+    
+    get_token ();
+    
+    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
+    
+        free (name);
+        return 0;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    src = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (src) {
+    
+        pointer_depth = src->pointer_depth;
+        pointed_size = src->pointed_size;
+    
+    } else if (global_index >= 0) {
+    
+        pointer_depth = get_global_symbol_pointer_depth (name);
+        pointed_size = get_global_symbol_pointed_size (name);
+    
+    } else {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (pointer_depth <= 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid indirection of non-pointer '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (pointed_size <= 0) {
+        pointed_size = DATA_INT & 0x1f;
+    }
+    
+    if (pointer_depth > 1) {
+    
+        lvalue_size = DATA_PTR & 0x1f;
+        
+        elem_size = (pointer_depth > 2) ? (DATA_PTR & 0x1f) : index_step_size (pointed_size);
+        step = elem_size;
+    
+    } else {
+    
+        lvalue_size = pointed_size & 0x1f;
+        
+        elem_size = pointed_size & 0x1f;
+        step = 1;
+    
+    }
+    
+    if (!reg) {
+        reg = "eax";
+    }
+    
+    addr_reg = (strcmp (reg, "edx") == 0) ? "ecx" : "edx";
+    
+    if (src) {
+    
+        if (src->is_static && src->static_label) {
+            emit_load_global_to_reg (addr_reg, src->static_label, DATA_PTR);
+        } else {
+            emit_load_local_to_reg (addr_reg, src->offset, DATA_PTR);
+        }
+    
+    } else {
+        emit_load_global_to_reg (addr_reg, name, DATA_PTR);
+    }
+    
+    emit_load_member_from_addr_reg_now (reg, addr_reg, 0, lvalue_size);
+    emit_push_reg_now (reg);
+    
+    if (state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, op == TOK_INCR ? "    add %s, %d\n" : "    sub %s, %d\n", reg, step);
+        } else {
+            fprintf (state->ofp, op == TOK_INCR ? "    addl $%d, %%%s\n" : "    subl $%d, %%%s\n", step, reg);
+        }
+    
+    }
+    
+    emit_store_reg_to_deref_reg_now (addr_reg, reg, lvalue_size);
+    emit_pop_reg_now (reg);
+    
+    if (tok.kind == TOK_LBRACK) {
+        emit_parse_postfix_subscripts_to_reg_now (reg, elem_size, pointer_depth - 1, pointed_size);
+    }
+    
+    if (pointer_depth > 1) {
+        set_rhs_last_pointer_info (pointer_depth - 1, pointed_size);
+    } else {
+        clear_rhs_last_pointer_info ();
+    }
+    
+    free (name);
+    return 1;
+
+}
+
+static int source_starts_deref_parenthesized_deref_postfix_incdec_assignment_at (const char *p) {
+
+    if (!p) {
+        return 0;
+    }
+    
+    if (*p == '*') {
+        p++;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '*') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    p++;
+    
+    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;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((p[0] == '+' && p[1] == '+') || (p[0] == '-' && p[1] == '-'))) {
+        return 0;
+    }
+    
+    p += 2;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '=';
+
+}
+
+static int source_starts_deref_parenthesized_deref_postfix_incdec_value_at (const char *p) {
+
+    if (!p || *p != '*') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '*') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    p++;
+    
+    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;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((p[0] == '+' && p[1] == '+') || (p[0] == '-' && p[1] == '-'))) {
+        return 0;
+    }
+    
+    p += 2;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == ')';
+
+}
+
+static int emit_load_deref_parenthesized_deref_postfix_incdec_to_reg_now (const char *reg) {
+
+    enum token_kind op;
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    struct local_symbol *src;
+    
+    int global_index;
+    int pointer_depth = 0;
+    int pointed_size = DATA_INT & 0x1f;
+    int deref_size = DATA_INT & 0x1f;
+    int step = DATA_PTR & 0x1f;
+    
+    if (tok.kind != TOK_STAR) {
+        return 0;
+    }
+    
+    if (!source_starts_deref_parenthesized_deref_postfix_incdec_value_at (tok.caret)) {
+        return 0;
+    }
+    
+    expect (TOK_STAR, "*");
+    expect (TOK_LPAREN, "(");
+    expect (TOK_LPAREN, "(");
+    expect (TOK_STAR, "*");
+    
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    get_token ();
+    
+    expect (TOK_RPAREN, ")");
+    
+    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
+    
+        free (name);
+        return 0;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    expect (TOK_RPAREN, ")");
+    
+    src = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (src) {
+    
+        pointer_depth = src->pointer_depth;
+        pointed_size = src->pointed_size;
+    
+    } else if (global_index >= 0) {
+    
+        pointer_depth = get_global_symbol_pointer_depth (name);
+        pointed_size = get_global_symbol_pointed_size (name);
+    
+    } else {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (pointer_depth <= 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid indirection of non-pointer '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (pointed_size <= 0) {
+        pointed_size = DATA_INT & 0x1f;
+    }
+    
+    deref_size = pointer_depth > 1 ? (pointed_size & 0x1f) : (DATA_INT & 0x1f);
+    step = pointer_depth > 2 ? (DATA_PTR & 0x1f) : index_step_size (pointed_size);
+    
+    if (deref_size <= 0) {
+        deref_size = DATA_INT & 0x1f;
+    }
+    
+    if (step <= 0) {
+        step = DATA_PTR & 0x1f;
+    }
+    
+    if (!reg) {
+        reg = "eax";
+    }
+    
+    if (src) {
+    
+        if (src->is_static && src->static_label) {
+            emit_load_global_to_reg ("ecx", src->static_label, DATA_PTR);
+        } else {
+            emit_load_local_to_reg ("ecx", src->offset, DATA_PTR);
+        }
+    
+    } else {
+        emit_load_global_to_reg ("ecx", name, DATA_PTR);
+    }
+    
+    emit_load_member_from_addr_reg_now (reg, "ecx", 0, DATA_PTR & 0x1f);
+    emit_push_reg_now (reg);
+    
+    if (state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, op == TOK_INCR ? "    add %s, %d\n" : "    sub %s, %d\n", reg, step);
+        } else {
+            fprintf (state->ofp, op == TOK_INCR ? "    addl $%d, %%%s\n" : "    subl $%d, %%%s\n", step, reg);
+        }
+    
+    }
+    
+    emit_store_reg_to_deref_reg_now ("ecx", reg, DATA_PTR & 0x1f);
+    emit_pop_reg_now (reg);
+    emit_load_deref_reg_now (reg, deref_size);
+    
+    if (pointer_depth > 2) {
+        set_rhs_last_pointer_info (pointer_depth - 2, pointed_size);
+    } else {
+        clear_rhs_last_pointer_info ();
+    }
+    
+    free (name);
+    return 1;
+
+}
+
+static int emit_store_to_deref_parenthesized_deref_postfix_incdec_now (const char *reg) {
+
+    enum token_kind op;
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    struct local_symbol *src;
+    
+    int global_index;
+    int pointer_depth = 0;
+    int pointed_size = DATA_INT & 0x1f;
+    int store_size = DATA_INT & 0x1f;
+    int step = DATA_PTR & 0x1f;
+    
+    if (tok.kind != TOK_STAR) {
+        return 0;
+    }
+    
+    if (!source_starts_deref_parenthesized_deref_postfix_incdec_assignment_at (tok.caret)) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    expect (TOK_LPAREN, "(");
+    expect (TOK_STAR, "*");
+    
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    get_token ();
+    
+    expect (TOK_RPAREN, ")");
+    
+    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
+    
+        free (name);
+        return 0;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    expect (TOK_ASSIGN, "=");
+    
+    src = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (src) {
+    
+        pointer_depth = src->pointer_depth;
+        pointed_size = src->pointed_size;
+    
+    } else if (global_index >= 0) {
+    
+        pointer_depth = get_global_symbol_pointer_depth (name);
+        pointed_size = get_global_symbol_pointed_size (name);
+    
+    } else {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (pointer_depth <= 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid indirection of non-pointer '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (pointed_size <= 0) {
+        pointed_size = DATA_INT & 0x1f;
+    }
+    
+    store_size = pointed_size & 0x1f;
+    step = pointed_size & 0x1f;
+    
+    if (step <= 0) {
+        step = DATA_PTR & 0x1f;
+    }
+    
+    if (!reg) {
+        reg = "eax";
+    }
+    
+    if (src) {
+    
+        if (src->is_static && src->static_label) {
+            emit_load_global_to_reg ("ecx", src->static_label, DATA_PTR);
+        } else {
+            emit_load_local_to_reg ("ecx", src->offset, DATA_PTR);
+        }
+    
+    } else {
+        emit_load_global_to_reg ("ecx", name, DATA_PTR);
+    }
+    
+    emit_load_member_from_addr_reg_now ("edx", "ecx", 0, DATA_PTR & 0x1f);
+    emit_push_reg_now ("edx");
+    
+    if (state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, op == TOK_INCR ? "    add edx, %d\n" : "    sub edx, %d\n", step);
+        } else {
+            fprintf (state->ofp, op == TOK_INCR ? "    addl $%d, %%edx\n" : "    subl $%d, %%edx\n", step);
+        }
+    
+    }
+    
+    emit_store_reg_to_deref_reg_now ("ecx", "edx", DATA_PTR & 0x1f);
+    
+    emit_load_assignment_rhs_expression_to_reg (reg);
+    emit_pop_reg_now ("edx");
+    emit_store_reg_to_deref_reg_now ("edx", reg, store_size);
+    
+    free (name);
+    return 1;
+
+}
+
+static void emit_scale_reg_by_const_now (const char *reg, int scale);
+
+static int source_starts_deref_assignment_at_now (const char *p) {
+
+    if (!p || *p != '*') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    p++;
+    
+    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[1] != '=') {
+        return 1;
+    }
+    
+    if ((p[0] == '+' || p[0] == '-' || p[0] == '*' || p[0] == '/' ||
+         p[0] == '%' || p[0] == '&' || p[0] == '^' || p[0] == '|') &&
+        p[1] == '=') {
+        return 1;
+    }
+    
+    if ((p[0] == '<' && p[1] == '<' && p[2] == '=') ||
+        (p[0] == '>' && p[1] == '>' && p[2] == '=')) {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static int emit_load_deref_assignment_expression_to_reg_now (const char *reg) {
+
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    
+    struct local_symbol *sym;
+    int global_index;
+    
+    enum token_kind op;
+    
+    int pointer_depth = 0;
+    int pointed_size = DATA_INT & 0x1f;
+    int value_pointer_depth = 0;
+    int store_size = DATA_INT & 0x1f;
+    
+    if (tok.kind != TOK_STAR) {
+        return 0;
+    }
+    
+    if (!source_starts_deref_assignment_at_now (tok.caret)) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    get_token ();
+    
+    if (!is_assignment_operator (tok.kind)) {
+    
+        free (name);
+        return 0;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    sym = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (sym) {
+    
+        pointer_depth = sym->pointer_depth;
+        pointed_size = sym->pointed_size;
+        
+        if (sym->is_static && sym->static_label) {
+            emit_load_global_to_reg ("ecx", sym->static_label, DATA_PTR);
+        } else {
+            emit_load_local_to_reg ("ecx", sym->offset, DATA_PTR);
+        }
+    
+    } else if (global_index >= 0) {
+    
+        pointer_depth = get_global_symbol_pointer_depth (name);
+        pointed_size = get_global_symbol_pointed_size (name);
+        
+        emit_load_global_to_reg ("ecx", name, DATA_PTR);
+    
+    } else {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (pointer_depth <= 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid indirection of non-pointer '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    value_pointer_depth = pointer_depth - 1;
+    
+    if (value_pointer_depth > 0) {
+        store_size = DATA_PTR & 0x1f;
+    } else if (pointed_size > 0) {
+        store_size = pointed_size & 0x1f;
+    }
+    
+    if (store_size <= 0) {
+        store_size = DATA_INT & 0x1f;
+    }
+    
+    emit_push_reg_now ("ecx");
+    
+    if (op == TOK_ASSIGN) {
+        emit_load_assignment_rhs_expression_to_reg ("eax");
+    } else {
+    
+        emit_load_deref_reg_now ("ecx", store_size);
+        
+        emit_push_reg_now ("ecx");
+        emit_load_assignment_rhs_expression_to_reg ("edx");
+        
+        emit_pop_reg_now ("eax");
+        
+        if ((op == TOK_PLUSEQ || op == TOK_MINUSEQ) && value_pointer_depth > 0 &&
+            index_step_size (pointed_size) > 1) {
+            emit_scale_reg_by_const_now ("edx", index_step_size (pointed_size));
+        }
+        
+        emit_assignment_binary_op (op, 0);
+    
+    }
+    
+    emit_pop_reg_now ("ecx");
+    emit_store_reg_to_deref_reg_now ("ecx", "eax", store_size);
+    
+    if (reg && strcmp (reg, "eax") != 0 && state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    mov %s, eax\n", reg);
+        } else {
+            fprintf (state->ofp, "    movl %%eax, %%%s\n", reg);
+        }
+    
+    }
+    
+    expect (TOK_RPAREN, ")");
+    
+    if (value_pointer_depth > 0) {
+        set_rhs_last_pointer_info (value_pointer_depth, pointed_size);
+    } else {
+        clear_rhs_last_pointer_info ();
+    }
+    
+    free (name);
+    return 1;
+
+}
+
+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 ();
+        
+        if (emit_load_parenthesized_deref_postfix_incdec_subscript_to_reg_now (reg)) {
+            return;
+        }
+    
+    }
+    
+    /*
+     * Do not special-case parenthesized assignment expressions here.
+     *
+     * The normal parenthesized-expression path below already recurses back
+     * into emit_load_assignment_rhs_expression_to_reg(), and the identifier
+     * operand parser below already _accepts assignment operators.  Using the
+     * old source-text detector here was wrong for nested grouping such as:
+     *
+     *     ((((reta <<= 1)) & 0x10))
+     *
+     * because it greedily treated all leading '(' tokens as belonging to the
+     * assignment expression, including parentheses that actually enclose the
+     * later binary '&' expression.
+     */
+    if (_accept (TOK_LPAREN)) {
+    
+        char *paren_call_name = 0;
+        
+        const char *paren_call_start = 0;
+        const char *paren_call_caret = 0;
+        
+        unsigned long paren_call_line = 0;
+        
+        if (emit_load_deref_assignment_expression_to_reg_now (reg)) {
+            return;
+        }
+        
+        /*
+         * Function pointer call designator: (*fp)(args).
+         *
+         * If this is left to the normal parenthesized-expression path, the
+         * inner unary * path treats *fp as a data dereference and emits:
+         *
+         *     movl off(%ebp), %eax
+         *     movl (%eax), %eax
+         *
+         * That is correct for reading *p as an object, but wrong for a
+         * function designator.  In a call, the value of fp is already the
+         * target address, so load fp and call through it without the extra
+         * data load.  Keep this narrow: only handle the exact token form
+         * (*identifier)(...), and let every other parenthesized expression use
+         * the existing parser.
+         */
+        if (tok.kind == TOK_STAR && tok.caret) {
+        
+            const char *p = tok.caret + 1;
+            const char *name_start;
+            const char *name_caret;
+            
+            unsigned long name_line;
+            char *name;
+            
+            struct local_symbol *src;
+            
+            int global_index;
+            int looks_like_call = 0;
+            
+            if (emit_load_parenthesized_deref_postfix_incdec_subscript_to_reg_now (reg)) {
+                return;
+            }
+            
+            while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+                p++;
+            }
+            
+            if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_') {
+            
+                p++;
+                
+                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++;
+                    
+                    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+                        p++;
+                    }
+                    
+                    looks_like_call = (*p == '(');
+                
+                }
+            
+            }
+            
+            if (looks_like_call) {
+            
+                get_token ();
+                
+                name_start = tok.start;
+                name_caret = tok.caret;
+                name_line = get_line_number ();
+                
+                if (tok.kind != TOK_IDENT || !tok.ident) {
+                
+                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
+                    return;
+                
+                }
+                
+                name = xstrdup (tok.ident);
+                get_token ();
+                
+                expect (TOK_RPAREN, ")");
+                
+                src = find_local_symbol (name);
+                global_index = find_global_symbol (name);
+                
+                if (src) {
+                
+                    if (src->is_static && src->static_label) {
+                        emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+                    }
+                
+                } else if (global_index >= 0) {
+                    emit_load_global_to_reg (reg, name, DATA_PTR);
+                } else {
+                
+                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+                    
+                    free (name);
+                    return;
+                
+                }
+                
+                free (name);
+                
+                emit_call_pointer_in_reg_now (reg, reg);
+                clear_rhs_last_pointer_info ();
+                
+                return;
+            
+            }
+        
+        }
+        
+        if (emit_load_parenthesized_indirect_member_to_reg_now (reg)) {
+            return;
+        }
+        
+        if (tok.kind == TOK_IDENT && tok.ident &&
+        
+            find_global_symbol (tok.ident) >= 0 &&
+            get_global_symbol_kind (tok.ident) == GLOBAL_SYMBOL_FUNCTION) {
+        
+            paren_call_name = xstrdup (tok.ident);
+            paren_call_start = tok.start;
+            paren_call_caret = tok.caret;
+            paren_call_line = get_line_number ();
+        
+        }
+        
+        if (!is_type_start (tok.kind) && parenthesized_function_designator_call_now ()) {
+        
+            char *call_name = xstrdup (tok.ident);
+            
+            const char *call_start = tok.start;
+            const char *call_caret = tok.caret;
+            
+            unsigned long call_line = get_line_number ();
+            get_token ();
+            
+            expect (TOK_RPAREN, ")");
+            
+            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, reg, call_start, call_caret, call_line);
+            free (call_name);
+            
+            return;
+        
+        }
+        
+        if (is_type_start (tok.kind)) {
+        
+            int saved_type_size = parsed_type_size;
+            int saved_storage_class = parsed_storage_class;
+            int saved_is_aggregate = parsed_type_is_aggregate;
+            int saved_is_void = parsed_type_is_void;
+            int saved_is_unsigned = parsed_type_is_unsigned;
+            int saved_is_floating = parsed_type_is_floating;
+            int saved_has_tag = parsed_type_has_tag;
+            int saved_is_inline = parsed_type_is_inline;
+            int saved_field_count = parsed_field_count;
+            int saved_fields[MAX_AGG_FIELDS];
+            int saved_declarator_is_pointer = declarator_is_pointer;
+            int saved_declarator_pointer_depth = declarator_pointer_depth;
+            int saved_declarator_has_array = declarator_has_array;
+            int saved_declarator_has_function = declarator_has_function;
+            int saved_declarator_array_unsized = declarator_array_unsized;
+            int saved_declarator_array_dimensions = declarator_array_dimensions;
+            
+            long saved_declarator_array_count = declarator_array_count;
+            long saved_declarator_first_array_count = declarator_first_array_count;
+            
+            char *cast_name = 0;
+            
+            int cast_base_size;
+            int cast_is_unsigned = 0;
+            int cast_pointer_depth = 0;
+            int cast_pointed_size = 0;
+            
+            int i;
+            
+            for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
+                saved_fields[i] = parsed_field_sizes[i];
+            }
+            
+            declarator_is_pointer = 0;
+            declarator_pointer_depth = 0;
+            declarator_has_array = 0;
+            declarator_has_function = 0;
+            declarator_array_unsized = 0;
+            declarator_array_count = 0;
+            declarator_first_array_count = 1;
+            
+            parse_type_spec ();
+            
+            cast_base_size = parsed_type_size & 0x1f;
+            cast_is_unsigned = parsed_type_is_unsigned;
+            
+            if (tok.kind != TOK_RPAREN) {
+                parse_declarator (&cast_name);
+            }
+            
+            if (declarator_is_pointer) {
+            
+                cast_pointer_depth = declarator_pointer_depth > 0 ? declarator_pointer_depth : 1;
+                cast_pointed_size = cast_pointer_depth > 1 ? (DATA_PTR & 0x1f) : cast_base_size;
+                
+                if (cast_pointed_size <= 0) {
+                    cast_pointed_size = DATA_INT & 0x1f;
+                }
+            
+            }
+            
+            if (cast_name) {
+                free (cast_name);
+            }
+            
+            expect (TOK_RPAREN, ")");
+            
+            parsed_type_size = saved_type_size;
+            parsed_storage_class = saved_storage_class;
+            parsed_type_is_aggregate = saved_is_aggregate;
+            parsed_type_is_void = saved_is_void;
+            parsed_type_is_unsigned = saved_is_unsigned;
+            parsed_type_is_floating = saved_is_floating;
+            parsed_type_has_tag = saved_has_tag;
+            parsed_type_is_inline = saved_is_inline;
+            
+            clear_parsed_fields ();
+            
+            for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
+                parsed_field_sizes[i] = saved_fields[i];
+            }
+            
+            parsed_field_count = saved_field_count;
+            
+            declarator_is_pointer = saved_declarator_is_pointer;
+            declarator_pointer_depth = saved_declarator_pointer_depth;
+            declarator_has_array = saved_declarator_has_array;
+            declarator_has_function = saved_declarator_has_function;
+            declarator_array_unsized = saved_declarator_array_unsized;
+            declarator_array_count = saved_declarator_array_count;
+            declarator_first_array_count = saved_declarator_first_array_count;
+            declarator_array_dimensions = saved_declarator_array_dimensions;
+            
+            emit_load_assignment_rhs_to_reg (reg);
+            
+            while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+                emit_apply_postfix_member_access_to_reg_now (reg);
+            }
+            
+            if (tok.kind == TOK_LBRACK) {
+            
+                int cast_subscript_elem_size = cast_pointer_depth > 1 ? (DATA_PTR & 0x1f) : cast_pointed_size;
+                
+                if (cast_subscript_elem_size <= 0) {
+                    cast_subscript_elem_size = DATA_INT & 0x1f;
+                }
+                
+                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, cast_subscript_elem_size);
+                emit_load_deref_reg_now (reg, cast_subscript_elem_size);
+            
+            }
+            
+            if (cast_pointer_depth > 0) {
+                set_rhs_last_pointer_info (cast_pointer_depth, cast_pointed_size);
+            } else {
+            
+                emit_apply_integer_cast_to_reg_now (reg, cast_base_size, cast_is_unsigned);
+                clear_rhs_last_pointer_info ();
+            
+            }
+            
+            return;
+        
+        }
+        
+        if (tok.kind != TOK_LPAREN && current_integer_expr_is_foldable_now ()) {
+        
+            int64_s v = const64_from_current_foldable_expr ();
+            expect (TOK_RPAREN, ")");
+            
+            emit_load_const32_to_reg_now (reg, v);
+            return;
+        
+        }
+        
+        emit_load_assignment_rhs_expression_to_reg (reg);
+        
+        if (postfix_member_seen && (tok.kind == TOK_INCR || tok.kind == TOK_DECR)) {
+        
+            enum token_kind postfix_op = tok.kind;
+            get_token ();
+            emit_apply_postfix_member_incdec_now (reg, postfix_op);
+        
+        }
+        
+        while (tok.kind == TOK_COMMA) {
+        
+            get_token ();
+            emit_load_assignment_rhs_expression_to_reg (reg);
+        
+        }
+        
+        if (is_assignment_operator (tok.kind)) {
+        
+            get_token ();
+            emit_load_assignment_rhs_expression_to_reg (reg);
+        
+        }
+        
+        if (paren_call_name && tok.kind == TOK_RPAREN) {
+        
+            get_token ();
+            
+            if (tok.kind == TOK_LPAREN) {
+            
+                if (!find_local_symbol (paren_call_name)) {
+                    ensure_global_function_symbol (paren_call_name, paren_call_start, paren_call_caret, paren_call_line);
+                }
+                
+                emit_call_identifier_to_reg_now (paren_call_name, reg, paren_call_start, paren_call_caret, paren_call_line);
+                free (paren_call_name);
+                
+                return;
+            
+            }
+        
+        } else {
+            expect (TOK_RPAREN, ")");
+        }
+        
+        if (paren_call_name) {
+            free (paren_call_name);
+        }
+        
+        if (tok.kind == TOK_LBRACK) {
+        
+            int subscript_pointer_depth = rhs_last_pointer_depth;
+            int subscript_elem_size = rhs_last_pointed_size;
+            
+            if (subscript_elem_size <= 0) {
+                subscript_elem_size = DATA_INT & 0x1f;
+            }
+            
+            emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, subscript_elem_size);
+            
+            if (is_assignment_operator (tok.kind)) {
+            
+                enum token_kind assign_op = tok.kind;
+                
+                get_token ();
+                emit_push_reg_now (reg);
+                
+                if (assign_op == TOK_ASSIGN && subscript_elem_size > (DATA_LLONG & 0x1f) &&
+                    tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now ()) {
+                
+                    char *rhs_name = xstrdup (tok.ident);
+                    
+                    const char *rhs_start = tok.start;
+                    const char *rhs_caret = tok.caret;
+                    
+                    unsigned long rhs_line = get_line_number ();
+                    
+                    pending_struct_return_lhs = 0;
+                    pending_struct_return_global_name = 0;
+                    pending_struct_return_stack_address = 1;
+                    pending_struct_return_stack_offset = 0;
+                    
+                    get_token ();
+                    emit_call_identifier_to_reg_now (rhs_name, reg, rhs_start, rhs_caret, rhs_line);
+                    
+                    pending_struct_return_stack_address = 0;
+                    pending_struct_return_stack_offset = 0;
+                    
+                    emit_pop_reg_now ("edx");
+                    free (rhs_name);
+                    
+                    set_rhs_last_pointer_info (0, 0);
+                    return;
+                
+                } else if (assign_op == TOK_ASSIGN) {
+                
+                    if (subscript_elem_size > (DATA_LLONG & 0x1f)) {
+                    
+                        pending_struct_return_lhs = 0;
+                        pending_struct_return_global_name = 0;
+                        pending_struct_return_stack_address = 1;
+                        pending_struct_return_stack_offset = 0;
+                        
+                        emit_load_assignment_rhs_expression_to_reg (reg);
+                        
+                        pending_struct_return_stack_address = 0;
+                        pending_struct_return_stack_offset = 0;
+                        
+                        emit_pop_reg_now ("edx");
+                        set_rhs_last_pointer_info (0, 0);
+                        
+                        return;
+                    
+                    }
+                    
+                    emit_load_assignment_rhs_expression_to_reg (reg);
+                
+                } else {
+                
+                    emit_load_deref_reg_now (reg, subscript_elem_size);
+                    emit_push_reg_now (reg);
+                    
+                    emit_load_assignment_rhs_expression_to_reg ("edx");
+                    emit_pop_reg_now (reg);
+                    
+                    emit_assignment_binary_op (assign_op, 0);
+                
+                }
+                
+                emit_pop_reg_now ("edx");
+                
+                emit_store_reg_to_deref_reg_now ("edx", reg, subscript_elem_size);
+                set_rhs_last_pointer_info (0, 0);
+                
+                return;
+            
+            }
+            
+            emit_load_deref_reg_now (reg, subscript_elem_size);
+            
+            if (subscript_pointer_depth > 0) {
+                subscript_pointer_depth--;
+            }
+            
+            if (subscript_pointer_depth > 0) {
+                set_rhs_last_pointer_info (subscript_pointer_depth, subscript_elem_size);
+            } else {
+                set_rhs_last_pointer_info (0, 0);
+            }
+        
+        }
+        
+        if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+            emit_apply_postfix_member_access_to_reg_now (reg);
+        }
+        
+        if (postfix_member_seen && tok.kind == TOK_LPAREN) {
+        
+            emit_call_pointer_in_reg_now (reg, reg);
+            
+            set_rhs_last_pointer_info (0, 0);
+            return;
+        
+        }
+        
+        if (postfix_member_seen) {
+        
+            set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
+            
+            if (is_assignment_operator (tok.kind)) {
+            
+                enum token_kind op = tok.kind;
+                
+                int assign_member_offset = postfix_member_offset;
+                int assign_member_size = postfix_member_size;
+                
+                get_token ();
+                
+                if (state->ofp) {
+                
+                    if (op == TOK_ASSIGN) {
+                    
+                        if (postfix_member_is_floating || token_is_floating_constant_now () || rhs_current_operand_is_floating_now ()) {
+                        
+                            emit_push_reg_now ("edx");
+                            emit_load_floating_rhs_expression_now (assign_member_size);
+                            
+                            emit_pop_reg_now ("edx");
+                            emit_store_floating_member_to_addr_reg_now ("edx", assign_member_offset, assign_member_size);
+                            
+                            return;
+                        
+                        }
+                        
+                        if (assign_member_size > (DATA_LLONG & 0x1f) &&
+                            tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now ()) {
+                        
+                            char *rhs_name = xstrdup (tok.ident);
+                            
+                            const char *rhs_start = tok.start;
+                            const char *rhs_caret = tok.caret;
+                            
+                            unsigned long rhs_line = get_line_number ();
+                            emit_push_reg_now ("edx");
+                            
+                            pending_struct_return_lhs = 0;
+                            pending_struct_return_global_name = 0;
+                            pending_struct_return_stack_address = 1;
+                            pending_struct_return_stack_offset = assign_member_offset;
+                            
+                            get_token ();
+                            emit_call_identifier_to_reg_now (rhs_name, reg, rhs_start, rhs_caret, rhs_line);
+                            
+                            pending_struct_return_stack_address = 0;
+                            pending_struct_return_stack_offset = 0;
+                            
+                            emit_pop_reg_now ("edx");
+                            free (rhs_name);
+                            
+                            return;
+                        
+                        }
+                        
+                        if (emit_aggregate_copy_from_current_rhs_to_addr_reg_now ("edx", assign_member_offset, assign_member_size)) {
+                            return;
+                        }
+                        
+                        emit_push_reg_now ("edx");
+                        
+                        emit_load_assignment_rhs_expression_to_reg (reg);
+                        emit_pop_reg_now ("edx");
+                    
+                    } else {
+                    
+                        /*
+                         * emit_apply_postfix_member_access_to_reg_now() has already
+                         * loaded the member value into reg and left the containing
+                         * object address in edx.  Do not load the member again from
+                         * reg: for p->m |= x that treats the old value of m as a
+                         * pointer and dereferences it, which corrupts/segfaults code
+                         * such as section->symbol->flags |= SYMBOL_FLAG_SECTION_SYMBOL.
+                         */
+                        emit_push_reg_now ("edx");
+                        emit_push_reg_now (reg);
+                        
+                        emit_load_assignment_rhs_expression_to_reg ("edx");
+                        emit_pop_reg_now (reg);
+                        
+                        emit_assignment_binary_op (op, 0);
+                        emit_pop_reg_now ("edx");
+                    
+                    }
+                    
+                    emit_store_member_to_addr_reg_now ("edx", assign_member_offset, reg, assign_member_size);
+                
+                } else {
+                    emit_load_assignment_rhs_expression_to_reg (reg);
+                }
+            
+            }
+        
+        }
+        
+        /*
+         * This routine parses one primary operand for the outer binary
+         * expression parser.  After returning, the caller can still consume
+         * any trailing operator, e.g. the / b in:
+         *
+         *     (a + b - 1) / b
+         */
+        return;
+    
+    } else if (tok.kind == TOK_AMPER) {
+    
+        char *name;
+        
+        const char *name_start;
+        const char *name_caret;
+        
+        unsigned long name_line;
+        struct local_symbol *src;
+        
+        get_token ();
+        
+        if (tok.kind == TOK_LPAREN) {
+        
+            if (emit_load_address_of_parenthesized_postfix_to_reg_now (reg)) {
+                return;
+            }
+        
+        }
+        
+        name_start = tok.start;
+        name_caret = tok.caret;
+        name_line = get_line_number ();
+        
+        if (tok.kind != TOK_IDENT) {
+        
+            int64_s zero;
+            
+            zero.low = 0;
+            zero.high = 0;
+            
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after '&'");
+            
+            emit_load_const32_to_reg_now (reg, zero);
+            return;
+        
+        }
+        
+        name = xstrdup (tok.ident);
+        get_token ();
+        
+        src = find_local_symbol (name);
+        
+        if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+        
+            int global_index = find_global_symbol (name);
+            
+            const char *current_object_tag_name = 0;
+            int current_object_size = 0;
+            
+            if (src) {
+            
+                if (tok.kind == TOK_DOT || src->is_array) {
+                
+                    current_object_size = src->is_array && src->pointed_size > 0 ? src->pointed_size : src->size;
+                    current_object_tag_name = src->is_array ? (src->pointed_tag_name ? src->pointed_tag_name : src->tag_name) : 0;
+                    
+                    if (src->is_static && src->static_label) {
+                        emit_load_address_to_reg_now (reg, src->static_label);
+                    } else {
+                        emit_load_local_address_to_reg_now (reg, src->offset);
+                    }
+                
+                } else if (src->is_static && src->static_label) {
+                
+                    current_object_size = src->pointed_size > 0 ? src->pointed_size : DATA_PTR;
+                    current_object_tag_name = src->pointed_tag_name;
+                    
+                    emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
+                
+                } else {
+                
+                    current_object_size = src->pointed_size > 0 ? src->pointed_size : DATA_PTR;
+                    current_object_tag_name = src->pointed_tag_name;
+                    
+                    emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+                
+                }
+            
+            } else if (global_index >= 0) {
+            
+                if (tok.kind == TOK_DOT || get_global_symbol_array (name)) {
+                
+                    current_object_size = get_global_symbol_array (name) && get_global_symbol_pointed_size (name) > 0 ? get_global_symbol_pointed_size (name) : get_global_symbol_size (name);
+                    current_object_tag_name = get_global_symbol_tag_name (name);
+                    
+                    emit_load_address_to_reg_now (reg, name);
+                
+                } else {
+                
+                    current_object_size = get_global_symbol_pointed_size (name) > 0 ? get_global_symbol_pointed_size (name) : DATA_PTR;
+                    current_object_tag_name = get_global_symbol_tag_name (name);
+                    
+                    emit_load_global_to_reg (reg, name, DATA_PTR);
+                
+                }
+            
+            } else {
+            
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+                
+                free (name);
+                return;
+            
+            }
+            
+            while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+            
+                enum token_kind member_op = tok.kind;
+                char *member;
+                
+                const char *member_start;
+                const char *member_caret;
+                
+                unsigned long member_line;
+                
+                int offset = 0;
+                int member_size = DATA_INT & 0x1f;
+                int elem_size = DATA_INT & 0x1f;
+                int pointer_depth = 0;
+                
+                get_token ();
+                
+                member_start = tok.start;
+                member_caret = tok.caret;
+                member_line = get_line_number ();
+                
+                if (tok.kind != TOK_IDENT) {
+                
+                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+                    
+                    free (name);
+                    return;
+                
+                }
+                
+                member = xstrdup (tok.ident);
+                get_token ();
+                
+                if (!find_member_info_ex_bounded (member, current_object_size, current_object_tag_name, &offset, &member_size, &elem_size, &pointer_depth, 0, 0)) {
+                
+                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+                    
+                    free (member);
+                    free (name);
+                    
+                    return;
+                
+                }
+                
+                current_object_tag_name = last_found_member_tag_name;
+                free (member);
+                
+                if (state->ofp && offset != 0) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+                    } else {
+                        fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
+                    }
+                
+                }
+                
+                if (tok.kind == TOK_LBRACK) {
+                
+                    if (pointer_depth > 0) {
+                    
+                        emit_load_member_from_addr_reg_now (reg, reg, 0, DATA_PTR & 0x1f);
+                        emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
+                    
+                    } else {
+                        emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
+                    }
+                
+                } else if (pointer_depth > 0 && (tok.kind == TOK_ARROW || tok.kind == TOK_DOT)) {
+                    emit_load_member_from_addr_reg_now (reg, reg, 0, DATA_PTR & 0x1f);
+                }
+                
+                if (pointer_depth > 0) {
+                    current_object_size = elem_size > 0 ? elem_size : DATA_PTR;
+                } else {
+                    current_object_size = member_size;
+                }
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_LBRACK) {
+        
+            if (src) {
+            
+                int elem_size = src->is_array ? (src->pointer_depth ? DATA_PTR : (src->array_element_size > 0 ? src->array_element_size : src->pointed_size)) :
+                    (src->pointer_depth > 1 ? DATA_PTR : src->pointed_size);
+                
+                if (elem_size <= 0) {
+                    elem_size = DATA_INT & 0x1f;
+                }
+                
+                if (src->is_array) {
+                
+                    if (src->is_static && src->static_label) {
+                        emit_load_address_to_reg_now (reg, src->static_label);
+                    } else {
+                        emit_load_local_address_to_reg_now (reg, src->offset);
+                    }
+                
+                } else if (src->is_static && src->static_label) {
+                    emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+                }
+                
+                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
+                
+                if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+                
+                    const char *current_object_tag_name = src->is_array ? (src->tag_name ? src->tag_name : src->pointed_tag_name) : src->pointed_tag_name;
+                    int current_object_size = elem_size;
+                    
+                    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+                    
+                        enum token_kind member_op = tok.kind;
+                        char *member;
+                        
+                        const char *member_start;
+                        const char *member_caret;
+                        
+                        unsigned long member_line;
+                        
+                        int offset = 0;
+                        int member_size = DATA_INT & 0x1f;
+                        int member_elem_size = DATA_INT & 0x1f;
+                        int member_pointer_depth = 0;
+                        
+                        get_token ();
+                        
+                        member_start = tok.start;
+                        member_caret = tok.caret;
+                        member_line = get_line_number ();
+                        
+                        if (tok.kind != TOK_IDENT) {
+                        
+                            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+                            
+                            free (name);
+                            return;
+                        
+                        }
+                        
+                        member = xstrdup (tok.ident);
+                        get_token ();
+                        
+                        if (!find_member_info_ex_bounded (member, current_object_size, current_object_tag_name, &offset, &member_size, &member_elem_size, &member_pointer_depth, 0, 0)) {
+                        
+                            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+                            
+                            free (member);
+                            free (name);
+                            
+                            return;
+                        
+                        }
+                        
+                        current_object_tag_name = last_found_member_tag_name;
+                        free (member);
+                        
+                        if (state->ofp && offset != 0) {
+                        
+                            if (state->syntax & ASM_SYNTAX_INTEL) {
+                                fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+                            } else {
+                                fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
+                            }
+                        
+                        }
+                        
+                        if (tok.kind == TOK_LBRACK) {
+                        
+                            if (member_pointer_depth > 0) {
+                                emit_load_member_from_addr_reg_now (reg, reg, 0, DATA_PTR & 0x1f);
+                            }
+                            
+                            emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, member_elem_size > 0 ? member_elem_size : DATA_INT & 0x1f);
+                        
+                        } else if (member_pointer_depth > 0 && (tok.kind == TOK_ARROW || tok.kind == TOK_DOT)) {
+                            emit_load_member_from_addr_reg_now (reg, reg, 0, DATA_PTR & 0x1f);
+                        }
+                        
+                        if (member_pointer_depth > 0) {
+                            current_object_size = member_elem_size > 0 ? member_elem_size : DATA_PTR;
+                        } else {
+                            current_object_size = member_size;
+                        }
+                    
+                    }
+                
+                }
+                
+                free (name);
+                return;
+            
+            }
+            
+            if (find_global_symbol (name) >= 0) {
+            
+                int elem_size = get_global_symbol_array (name) ?
+                    (get_global_symbol_pointer_depth (name) ? DATA_PTR : (get_global_symbol_array_element_size (name) > 0 ? get_global_symbol_array_element_size (name) : get_global_symbol_pointed_size (name))) :
+                        (get_global_symbol_pointer_depth (name) > 1 ? DATA_PTR : get_global_symbol_pointed_size (name));
+                
+                if (elem_size <= 0) {
+                    elem_size = DATA_INT & 0x1f;
+                }
+                
+                if (get_global_symbol_array (name)) {
+                    emit_load_address_to_reg_now (reg, name);
+                } else {
+                    emit_load_global_to_reg (reg, name, DATA_PTR);
+                }
+                
+                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
+                
+                free (name);
+                return;
+            
+            }
+        
+        }
+        
+        if (src) {
+        
+            if (src->is_static && src->static_label) {
+                emit_load_address_to_reg_now (reg, src->static_label);
+            } else {
+                emit_load_local_address_to_reg_now (reg, src->offset);
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (find_global_symbol (name) >= 0) {
+        
+            emit_load_address_to_reg_now (reg, name);
+            
+            free (name);
+            return;
+        
+        }
+        
+        {
+        
+            int64_s zero;
+            
+            zero.low = 0;
+            zero.high = 0;
+            
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            
+            free (name);
+            emit_load_const32_to_reg_now (reg, zero);
+        
+        }
+        
+        return;
+    
+    } else if (tok.kind == TOK_STAR) {
+    
+        int deref_had_parens = 0;
+        int deref_size = DATA_CHAR & 0x1f;
+        int deref_pointer_depth = 0;
+        int deref_pointed_size = 0;
+        
+        if (emit_load_deref_parenthesized_deref_postfix_incdec_to_reg_now (reg)) {
+            return;
+        }
+        
+        if (emit_store_to_deref_parenthesized_deref_postfix_incdec_now (reg)) {
+            return;
+        }
+        
+        get_token ();
+        
+        if (tok.kind == TOK_IDENT) {
+        
+            char *lhs_name = xstrdup (tok.ident);
+            
+            const char *lhs_start = tok.start;
+            const char *lhs_caret = tok.caret;
+            
+            unsigned long lhs_line = get_line_number ();
+            struct local_symbol *lhs_sym;
+            
+            enum token_kind lhs_postfix_op = TOK_EOF;
+            enum token_kind member_op = TOK_EOF;
+            
+            char *member;
+            
+            const char *member_start;
+            const char *member_caret;
+            
+            unsigned long member_line;
+            
+            int lhs_has_postfix = 0;
+            int offset = 0;
+            
+            int member_size = DATA_PTR & 0x1f;
+            int member_elem_size = DATA_INT & 0x1f;
+            int member_pointer_depth = 0;
+            int member_load_size = DATA_PTR & 0x1f;
+            
+            get_token ();
+            
+            if (tok.kind == TOK_LPAREN &&
+                find_global_symbol (lhs_name) >= 0 &&
+                get_global_symbol_kind (lhs_name) == GLOBAL_SYMBOL_FUNCTION) {
+            
+                int fptr_depth = get_global_symbol_pointer_depth (lhs_name);
+                int fpointed_size = get_global_symbol_pointed_size (lhs_name);
+                
+                emit_call_identifier_to_reg_now (lhs_name, reg, lhs_start, lhs_caret, lhs_line);
+                
+                if (fptr_depth > 1) {
+                    deref_size = DATA_PTR;
+                } else if (fptr_depth == 1 && fpointed_size > 0) {
+                    deref_size = fpointed_size;
+                }
+                
+                emit_load_deref_reg_now (reg, deref_size);
+                
+                free (lhs_name);
+                return;
+            
+            }
+            
+            if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+            
+                member_op = tok.kind;
+                get_token ();
+                
+                member_start = tok.start;
+                member_caret = tok.caret;
+                member_line = get_line_number ();
+                
+                if (tok.kind != TOK_IDENT) {
+                
+                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+                    
+                    free (lhs_name);
+                    return;
+                
+                }
+                
+                member = xstrdup (tok.ident);
+                get_token ();
+                
+                if (!find_member_info_ex (member, &offset, &member_size, &member_elem_size, &member_pointer_depth, 0, 0)) {
+                
+                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+                    
+                    free (member);
+                    free (lhs_name);
+                    
+                    return;
+                
+                }
+                
+                free (member);
+                
+                if (member_pointer_depth > 0) {
+                    member_load_size = DATA_PTR & 0x1f;
+                } else {
+                    member_load_size = member_size;
+                }
+                
+                if (member_pointer_depth > 1) {
+                    deref_size = DATA_PTR;
+                } else if (member_pointer_depth == 1 && member_elem_size > 0) {
+                    deref_size = member_elem_size;
+                }
+                
+                if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+                
+                    lhs_has_postfix = 1;
+                    lhs_postfix_op = tok.kind;
+                    
+                    get_token ();
+                
+                }
+                
+                if (tok.kind == TOK_ASSIGN) {
+                
+                    lhs_sym = find_local_symbol (lhs_name);
+                    
+                    if (lhs_sym) {
+                    
+                        if (lhs_sym->is_static && lhs_sym->static_label) {
+                            emit_load_global_to_reg ("edx", lhs_sym->static_label, DATA_PTR);
+                        } else {
+                            emit_load_local_to_reg ("edx", lhs_sym->offset, DATA_PTR);
+                        }
+                    
+                    } else if (find_global_symbol (lhs_name) >= 0) {
+                        emit_load_global_to_reg ("edx", lhs_name, DATA_PTR);
+                    } else {
+                        report_line_at (get_filename (), lhs_line, REPORT_ERROR, lhs_start, lhs_caret, "unknown symbol '%s'", lhs_name);
+                    }
+                    
+                    if (state->ofp && offset != 0) {
+                    
+                        if (state->syntax & ASM_SYNTAX_INTEL) {
+                            fprintf (state->ofp, "    add edx, %d\n", offset);
+                        } else {
+                            fprintf (state->ofp, "    addl $%d, %%edx\n", offset);
+                        }
+                    
+                    }
+                    
+                    emit_push_reg_now ("edx");
+                    get_token ();
+                    
+                    emit_load_assignment_rhs_expression_to_reg (reg);
+                    
+                    emit_pop_reg_now ("edx");
+                    emit_store_reg_to_deref_reg_now ("edx", reg, member_load_size);
+                    
+                    free (lhs_name);
+                    return;
+                
+                }
+                
+                lhs_sym = find_local_symbol (lhs_name);
+                
+                if (lhs_sym) {
+                
+                    if (member_op == TOK_DOT) {
+                    
+                        if (lhs_sym->is_static && lhs_sym->static_label) {
+                            emit_load_address_to_reg_now (reg, lhs_sym->static_label);
+                        } else {
+                            emit_load_local_address_to_reg_now (reg, lhs_sym->offset);
+                        }
+                    
+                    } else if (lhs_sym->is_static && lhs_sym->static_label) {
+                        emit_load_global_to_reg (reg, lhs_sym->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg (reg, lhs_sym->offset, DATA_PTR);
+                    }
+                
+                } else if (find_global_symbol (lhs_name) >= 0) {
+                
+                    if (member_op == TOK_DOT) {
+                        emit_load_address_to_reg_now (reg, lhs_name);
+                    } else {
+                        emit_load_global_to_reg (reg, lhs_name, DATA_PTR);
+                    }
+                
+                } else {
+                    report_line_at (get_filename (), lhs_line, REPORT_ERROR, lhs_start, lhs_caret, "unknown symbol '%s'", lhs_name);
+                }
+                
+                if (member_size > (DATA_PTR & 0x1f) && member_pointer_depth == 0) {
+                
+                    if (state->ofp && offset != 0) {
+                    
+                        if (state->syntax & ASM_SYNTAX_INTEL) {
+                            fprintf (state->ofp, "    add %s, %d\n", reg, offset);
+                        } else {
+                            fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
+                        }
+                    
+                    }
+                
+                } else {
+                    emit_load_member_from_addr_reg_now (reg, reg, offset, member_load_size);
+                }
+                
+                if (lhs_has_postfix) {
+                    /* Already applied above only for assignment forms. */
+                }
+                
+                if (member_pointer_depth > 0) {
+                    set_rhs_last_pointer_info (member_pointer_depth, member_elem_size);
+                } else {
+                    clear_rhs_last_pointer_info ();
+                }
+                
+                free (lhs_name);
+                return;
+            
+            }
+            
+            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+            
+                lhs_has_postfix = 1;
+                lhs_postfix_op = tok.kind;
+                
+                get_token ();
+            
+            }
+            
+            if (tok.kind == TOK_ASSIGN) {
+            
+                int lhs_deref_is_unsigned = 1;
+                lhs_sym = find_local_symbol (lhs_name);
+                
+                if (lhs_sym) {
+                
+                    if (lhs_sym->pointer_depth > 1) {
+                        deref_size = DATA_PTR & 0x1f;
+                    } else if (lhs_sym->pointer_depth == 1 && lhs_sym->pointed_size > 0) {
+                    
+                        /**
+                         * Keep the full pointed-to object size here.  This
+                         * assignment path also handles aggregate lvalues such
+                         * as *hashtab = old_hashtab;  Masking with 0x1f turns
+                         * a 44-byte struct hashtab into 12 and emits a partial
+                         * copy, corrupting pdas hashtab state during rehash().
+                         */
+                        deref_size = lhs_sym->pointed_size;
+                    
+                    }
+                    
+                    if (member_op == TOK_DOT) {
+                    
+                        if (lhs_sym->is_static && lhs_sym->static_label) {
+                            emit_load_address_to_reg_now ("edx", lhs_sym->static_label);
+                        } else {
+                            emit_load_local_address_to_reg_now ("edx", lhs_sym->offset);
+                        }
+                    
+                    } else if (lhs_sym->is_static && lhs_sym->static_label) {
+                        emit_load_global_to_reg ("edx", lhs_sym->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg ("edx", lhs_sym->offset, DATA_PTR);
+                    }
+                
+                } else if (find_global_symbol (lhs_name) >= 0) {
+                
+                    if (get_global_symbol_pointer_depth (lhs_name) > 1) {
+                        deref_size = DATA_PTR & 0x1f;
+                    } else if (get_global_symbol_pointer_depth (lhs_name) == 1 && get_global_symbol_pointed_size (lhs_name) > 0) {
+                        deref_size = get_global_symbol_pointed_size (lhs_name);
+                    }
+                    
+                    if (member_op == TOK_DOT) {
+                        emit_load_address_to_reg_now ("edx", lhs_name);
+                    } else {
+                        emit_load_global_to_reg ("edx", lhs_name, DATA_PTR);
+                    }
+                
+                } else {
+                    report_line_at (get_filename (), lhs_line, REPORT_ERROR, lhs_start, lhs_caret, "unknown symbol '%s'", lhs_name);
+                }
+                
+                emit_push_reg_now ("edx");
+                
+                if (lhs_has_postfix) {
+                    emit_incdec_symbol_now (lhs_sym, lhs_name, lhs_postfix_op, lhs_line, lhs_start, lhs_caret);
+                }
+                
+                get_token ();
+                
+                if (deref_size > (DATA_LLONG & 0x1f)) {
+                
+                    emit_pop_reg_now ("edx");
+                    
+                    if (!emit_store_assignment_to_aggregate_address_now ("edx", deref_size, lhs_start, lhs_caret, lhs_line)) {
+                        report_line_at (get_filename (), lhs_line, REPORT_ERROR, lhs_start, lhs_caret, "aggregate assignment expression not implemented");
+                    }
+                
+                } else if (deref_size == (DATA_LLONG & 0x1f)) {
+                
+                    emit_load_assignment_rhs_expression_to_pair ("eax", "edx", lhs_deref_is_unsigned);
+                    emit_pop_reg_now ("ecx");
+                    
+                    emit_store_pair_to_deref_reg_now ("ecx", "eax", "edx");
+                
+                } else {
+                
+                    emit_load_assignment_rhs_expression_to_reg (reg);
+                    emit_pop_reg_now ("edx");
+                    
+                    emit_store_reg_to_deref_reg_now ("edx", reg, deref_size);
+                
+                }
+                
+                free (lhs_name);
+                return;
+            
+            }
+            
+            lhs_sym = find_local_symbol (lhs_name);
+            
+            if (lhs_sym) {
+            
+                if (lhs_sym->is_static && lhs_sym->static_label) {
+                    emit_load_global_to_reg (reg, lhs_sym->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg (reg, lhs_sym->offset, DATA_PTR);
+                }
+                
+                if (lhs_has_postfix) {
+                
+                    emit_push_reg_now (reg);
+                    emit_incdec_symbol_now (lhs_sym, lhs_name, lhs_postfix_op, lhs_line, lhs_start, lhs_caret);
+                    emit_pop_reg_now (reg);
+                
+                }
+                
+                if (lhs_sym->pointer_depth > 1) {
+                    deref_size = DATA_PTR;
+                } else if (lhs_sym->pointer_depth == 1) {
+                    deref_size = lhs_sym->pointed_size;
+                }
+                
+                emit_load_deref_reg_now (reg, deref_size);
+                
+                if (lhs_sym->pointer_depth > 1) {
+                    set_rhs_last_pointer_info (lhs_sym->pointer_depth - 1, lhs_sym->pointed_size);
+                } else {
+                    clear_rhs_last_pointer_info ();
+                }
+                
+                if (emit_handle_subscript_after_loaded_pointer_to_reg_now (reg, lhs_sym->pointer_depth > 0 ? lhs_sym->pointer_depth - 1 : 0, lhs_sym->pointed_size, lhs_sym->pointed_is_unsigned)) {
+                
+                    free (lhs_name);
+                    return;
+                
+                }
+                
+                free (lhs_name);
+                return;
+            
+            }
+            
+            if (find_global_symbol (lhs_name) >= 0) {
+            
+                emit_load_global_to_reg (reg, lhs_name, DATA_PTR);
+                
+                if (lhs_has_postfix) {
+                
+                    emit_push_reg_now (reg);
+                    
+                    emit_incdec_symbol_now (0, lhs_name, lhs_postfix_op, lhs_line, lhs_start, lhs_caret);
+                    emit_pop_reg_now (reg);
+                
+                }
+                
+                if (get_global_symbol_pointer_depth (lhs_name) > 1) {
+                    deref_size = DATA_PTR;
+                } else if (get_global_symbol_pointer_depth (lhs_name) == 1) {
+                    deref_size = get_global_symbol_pointed_size (lhs_name);
+                }
+                
+                emit_load_deref_reg_now (reg, deref_size);
+                
+                if (get_global_symbol_pointer_depth (lhs_name) > 1) {
+                    set_rhs_last_pointer_info (get_global_symbol_pointer_depth (lhs_name) - 1, get_global_symbol_pointed_size (lhs_name));
+                } else {
+                    clear_rhs_last_pointer_info ();
+                }
+                
+                if (emit_handle_subscript_after_loaded_pointer_to_reg_now (reg, get_global_symbol_pointer_depth (lhs_name) > 0 ? get_global_symbol_pointer_depth (lhs_name) - 1 : 0, get_global_symbol_pointed_size (lhs_name), get_global_symbol_pointed_is_unsigned (lhs_name))) {
+                
+                    free (lhs_name);
+                    return;
+                
+                }
+                
+                free (lhs_name);
+                return;
+            
+            }
+            
+            report_line_at (get_filename (), lhs_line, REPORT_ERROR, lhs_start, lhs_caret, "unknown symbol '%s'", lhs_name);
+            free (lhs_name);
+            
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_LPAREN) {
+        
+            deref_had_parens = 1;
+            get_token ();
+            
+            if (is_type_start (tok.kind)) {
+            
+                if (parse_deref_cast_type_name (&deref_size)) {
+                
+                    /*
+                     * parse_deref_cast_type_name() consumes the cast parentheses
+                     * only.  Do not consume a following ')' here: in expressions
+                     * such as:
+                     *
+                     *     __munmap(ptr, *(size_t *)ptr + sizeof(size_t))
+                     *
+                     * that ')' belongs to the surrounding call.  Consuming it
+                     * here makes the caller report a false "expected )".
+                     */
+                    
+                    if (tok.kind == TOK_ASSIGN) {
+                    
+                        get_token ();
+                        
+                        emit_push_reg_now (reg);
+                        emit_load_assignment_rhs_expression_to_reg (reg);
+                        
+                        emit_pop_reg_now ("edx");
+                        emit_store_reg_to_deref_reg_now ("edx", reg, deref_size);
+                        
+                        return;
+                    
+                    }
+                    
+                    /*
+                     * parse_deref_cast_type_name() consumes only the cast type
+                     * parentheses.  The operand being cast is still the current
+                     * token, e.g. the ptr in:
+                     *
+                     *     *(size_t *)ptr + sizeof(size_t)
+                     *
+                     * Load that address expression before applying the outer
+                     * unary '*'.  Otherwise the caller sees the unconsumed
+                     * identifier/operator and reports a false "expected )".
+                     */
+                    emit_load_assignment_rhs_to_reg (reg);
+                    goto dereference_loaded_address;
+                
+                }
+            
+            }
+            
+            if (tok.kind == TOK_AMPER) {
+            
+                char *name;
+                
+                const char *name_start;
+                const char *name_caret;
+                
+                unsigned long name_line;
+                struct local_symbol *dst;
+                
+                int global_index;
+                int dst_size;
+                
+                get_token ();
+                
+                name_start = tok.start;
+                name_caret = tok.caret;
+                name_line = get_line_number ();
+                
+                if (tok.kind == TOK_IDENT) {
+                
+                    name = xstrdup (tok.ident);
+                    
+                    get_token ();
+                    expect (TOK_RPAREN, ")");
+                    
+                    if (is_assignment_operator (tok.kind)) {
+                    
+                        get_token ();
+                        emit_load_assignment_rhs_expression_to_reg (reg);
+                        
+                        dst = find_local_symbol (name);
+                        global_index = find_global_symbol (name);
+                        
+                        if (dst) {
+                        
+                            dst_size = dst->size;
+                            
+                            if (dst->is_static && dst->static_label) {
+                                emit_store_reg_to_global (dst->static_label, dst_size, reg);
+                            } else {
+                                emit_store_reg_to_local (dst->offset, dst_size, reg);
+                            }
+                        
+                        } else if (global_index >= 0) {
+                        
+                            dst_size = get_global_symbol_size (name);
+                            emit_store_reg_to_global (name, dst_size, reg);
+                        
+                        } else {
+                            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+                        }
+                        
+                        free (name);
+                        return;
+                    
+                    }
+                    
+                    if (find_local_symbol (name) || find_global_symbol (name) >= 0) {
+                    
+                        dst = find_local_symbol (name);
+                        
+                        if (dst) {
+                        
+                            if (dst->is_static && dst->static_label) {
+                                emit_load_address_to_reg_now (reg, dst->static_label);
+                            } else {
+                                emit_load_local_address_to_reg_now (reg, dst->offset);
+                            }
+                        
+                        } else {
+                            emit_load_address_to_reg_now (reg, name);
+                        }
+                        
+                        free (name);
+                        goto dereference_loaded_address;
+                    
+                    }
+                    
+                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+                    free (name);
+                    
+                    return;
+                
+                }
+            
+            }
+        
+        }
+        
+        if (deref_had_parens) {
+        
+            emit_load_assignment_rhs_expression_to_reg (reg);
+            
+            if (rhs_last_pointer_depth > 1) {
+                deref_size = DATA_PTR;
+            } else if (rhs_last_pointer_depth == 1) {
+                deref_size = rhs_last_pointed_size;
+            }
+            
+            expect (TOK_RPAREN, ")");
+            
+            /*
+             * A parenthesized dereferenced function pointer is still a function
+             * designator when it is followed by an argument list.  For example:
+             *
+             *     (*generate_func)(outfile, pos)
+             *
+             * The inner expression already loaded the function pointer value into
+             * reg.  Do not dereference that value as data before the call; call
+             * through it directly.
+             */
+            if (tok.kind == TOK_LPAREN) {
+            
+                emit_call_pointer_in_reg_now (reg, reg);
+                
+                clear_rhs_last_pointer_info ();
+                return;
+            
+            }
+            
+            if (is_assignment_operator (tok.kind)) {
+            
+                enum token_kind assign_op = tok.kind;
+                
+                emit_push_reg_now (reg);
+                get_token ();
+                
+                if (assign_op == TOK_ASSIGN) {
+                    emit_load_assignment_rhs_expression_to_reg (reg);
+                } else {
+                
+                    emit_load_deref_reg_now (reg, deref_size);
+                    
+                    emit_push_reg_now (reg);
+                    emit_load_assignment_rhs_expression_to_reg ("edx");
+                    
+                    emit_pop_reg_now (reg);
+                    emit_assignment_binary_op (assign_op, 0);
+                
+                }
+                
+                emit_pop_reg_now ("edx");
+                emit_store_reg_to_deref_reg_now ("edx", reg, deref_size);
+                
+                return;
+            
+            }
+            
+            if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+            
+                enum token_kind member_op = tok.kind;
+                enum token_kind postfix_op = TOK_EOF;
+                
+                char *member;
+                
+                const char *member_start;
+                const char *member_caret;
+                
+                unsigned long member_line;
+                
+                int offset = 0;
+                int member_size = DATA_PTR & 0x1f;
+                int member_elem_size = DATA_INT & 0x1f;
+                int member_pointer_depth = 0;
+                
+                get_token ();
+                
+                member_start = tok.start;
+                member_caret = tok.caret;
+                member_line = get_line_number ();
+                
+                if (tok.kind != TOK_IDENT) {
+                
+                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+                    return;
+                
+                }
+                
+                member = xstrdup (tok.ident);
+                get_token ();
+                
+                if (!find_member_info_ex (member, &offset, &member_size, &member_elem_size, &member_pointer_depth, 0, 0)) {
+                
+                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+                    
+                    free (member);
+                    return;
+                
+                }
+                
+                free (member);
+                
+                if (member_pointer_depth > 1) {
+                    deref_size = DATA_PTR;
+                } else if (member_pointer_depth == 1 && member_elem_size > 0) {
+                    deref_size = member_elem_size;
+                }
+                
+                if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+                
+                    postfix_op = tok.kind;
+                    get_token ();
+                
+                }
+                
+                if (state->ofp) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                    
+                        if (state->syntax & ASM_SYNTAX_NASM) {
+                            fprintf (state->ofp, "    mov edx, dword [%s + %d]\n", reg, offset);
+                        } else {
+                            fprintf (state->ofp, "    mov edx, dword ptr [%s + %d]\n", reg, offset);
+                        }
+                        
+                        if (postfix_op == TOK_INCR || postfix_op == TOK_DECR) {
+                        
+                            if (state->syntax & ASM_SYNTAX_NASM) {
+                                fprintf (state->ofp, "    %s dword [%s + %d]\n", postfix_op == TOK_INCR ? "inc" : "dec", reg, offset);
+                            } else {
+                                fprintf (state->ofp, "    %s dword ptr [%s + %d]\n", postfix_op == TOK_INCR ? "inc" : "dec", reg, offset);
+                            }
+                        
+                        }
+                    
+                    } else {
+                    
+                        fprintf (state->ofp, "    movl %d(%%%s), %%edx\n", offset, reg);
+                        
+                        if (postfix_op == TOK_INCR || postfix_op == TOK_DECR) {
+                            fprintf (state->ofp, "    %sl %d(%%%s)\n", postfix_op == TOK_INCR ? "inc" : "dec", offset, reg);
+                        }
+                    
+                    }
+                
+                }
+                
+                if (tok.kind == TOK_ASSIGN) {
+                
+                    emit_push_reg_now ("edx");
+                    get_token ();
+                    
+                    emit_load_assignment_rhs_expression_to_reg (reg);
+                    emit_pop_reg_now ("edx");
+                    emit_store_reg_to_deref_reg_now ("edx", reg, deref_size);
+                    
+                    return;
+                
+                }
+                
+                if (state->ofp && strcmp (reg, "edx") != 0) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    mov %s, edx\n", reg);
+                    } else {
+                        fprintf (state->ofp, "    movl %%edx, %%%s\n", reg);
+                    }
+                
+                }
+                
+                goto dereference_loaded_address;
+            
+            }
+        
+        } else {
+            emit_load_assignment_rhs_to_reg (reg);
+        }
+        
+    dereference_loaded_address:
+        
+        deref_pointer_depth = rhs_last_pointer_depth;
+        deref_pointed_size = rhs_last_pointed_size;
+        
+        emit_load_deref_reg_now (reg, deref_size);
+        
+        if (deref_pointer_depth > 1) {
+            set_rhs_last_pointer_info (deref_pointer_depth - 1, deref_pointed_size);
+        } else {
+            clear_rhs_last_pointer_info ();
+        }
+        
+        if (tok.kind == TOK_LBRACK) {
+        
+            int subscript_pointer_depth = deref_pointer_depth > 0 ? deref_pointer_depth - 1 : 0;
+            int subscript_elem_size = subscript_pointer_depth > 1 ? (DATA_PTR & 0x1f) : deref_pointed_size;
+            
+            if (subscript_elem_size <= 0) {
+                subscript_elem_size = DATA_INT & 0x1f;
+            }
+            
+            emit_parse_postfix_subscripts_to_reg_now (reg, subscript_elem_size, subscript_pointer_depth, deref_pointed_size);
+            
+            if (is_assignment_operator (tok.kind)) {
+            
+                enum token_kind assign_op = tok.kind;
+                
+                get_token ();
+                emit_push_reg_now (reg);
+                
+                if (assign_op == TOK_ASSIGN && subscript_elem_size > (DATA_LLONG & 0x1f) &&
+                    tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now ()) {
+                
+                    char *rhs_name = xstrdup (tok.ident);
+                    
+                    const char *rhs_start = tok.start;
+                    const char *rhs_caret = tok.caret;
+                    
+                    unsigned long rhs_line = get_line_number ();
+                    
+                    pending_struct_return_lhs = 0;
+                    pending_struct_return_global_name = 0;
+                    pending_struct_return_stack_address = 1;
+                    pending_struct_return_stack_offset = 0;
+                    
+                    get_token ();
+                    emit_call_identifier_to_reg_now (rhs_name, reg, rhs_start, rhs_caret, rhs_line);
+                    
+                    pending_struct_return_stack_address = 0;
+                    pending_struct_return_stack_offset = 0;
+                    
+                    emit_pop_reg_now ("edx");
+                    free (rhs_name);
+                    
+                    set_rhs_last_pointer_info (0, 0);
+                    return;
+                
+                } else if (assign_op == TOK_ASSIGN) {
+                
+                    if (subscript_elem_size > (DATA_LLONG & 0x1f)) {
+                    
+                        pending_struct_return_lhs = 0;
+                        pending_struct_return_global_name = 0;
+                        pending_struct_return_stack_address = 1;
+                        pending_struct_return_stack_offset = 0;
+                        
+                        emit_load_assignment_rhs_expression_to_reg (reg);
+                        
+                        pending_struct_return_stack_address = 0;
+                        pending_struct_return_stack_offset = 0;
+                        
+                        emit_pop_reg_now ("edx");
+                        set_rhs_last_pointer_info (0, 0);
+                        return;
+                    
+                    }
+                    
+                    emit_load_assignment_rhs_expression_to_reg (reg);
+                
+                } else {
+                
+                    emit_load_deref_reg_now (reg, subscript_elem_size);
+                    emit_push_reg_now (reg);
+                    
+                    emit_load_assignment_rhs_expression_to_reg ("edx");
+                    emit_pop_reg_now (reg);
+                    
+                    emit_assignment_binary_op (assign_op, 0);
+                
+                }
+                
+                emit_pop_reg_now ("edx");
+                
+                emit_store_reg_to_deref_reg_now ("edx", reg, subscript_elem_size);
+                clear_rhs_last_pointer_info ();
+                
+                return;
+            
+            }
+            
+            emit_load_deref_reg_now (reg, subscript_elem_size);
+            
+            if (subscript_pointer_depth > 1) {
+                set_rhs_last_pointer_info (subscript_pointer_depth - 1, deref_pointed_size);
+            } else {
+                clear_rhs_last_pointer_info ();
+            }
+        
+        }
+        
+        return;
+    
+    } else if (tok.kind == TOK_TILDE) {
+    
+        get_token ();
+        emit_load_assignment_rhs_to_reg (reg);
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    not %s\n", reg);
+            } else {
+                fprintf (state->ofp, "    notl %%%s\n", reg);
+            }
+        
+        }
+        
+        return;
+    
+    } else if (tok.kind == TOK_XMARK) {
+    
+        get_token ();
+        emit_load_assignment_rhs_to_reg (reg);
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                fprintf (state->ofp, "    test %s, %s\n", reg, reg);
+                
+                if (strcmp (reg, "eax") != 0) {
+                
+                    fprintf (state->ofp, "    setz al\n");
+                    fprintf (state->ofp, "    movzx eax, al\n");
+                    fprintf (state->ofp, "    mov %s, eax\n", reg);
+                
+                } else {
+                
+                    fprintf (state->ofp, "    setz al\n");
+                    fprintf (state->ofp, "    movzx eax, al\n");
+                
+                }
+            
+            } else {
+            
+                fprintf (state->ofp, "    testl %%%s, %%%s\n", reg, reg);
+                fprintf (state->ofp, "    setz %%al\n");
+                fprintf (state->ofp, "    movzbl %%al, %%eax\n");
+                
+                if (strcmp (reg, "eax") != 0) {
+                    fprintf (state->ofp, "    movl %%eax, %%%s\n", reg);
+                }
+            
+            }
+        
+        }
+        
+        return;
+    
+    } else if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+    
+        if (emit_load_prefix_incdec_member_to_reg_now (reg)) {
+            return;
+        }
+        
+        if (emit_load_prefix_incdec_to_reg_now (reg)) {
+            return;
+        }
+    
+    }
+    
+    if (tok.kind == TOK_PLUS || tok.kind == TOK_MINUS) {
+    
+        int negate = 0;
+        
+        while (tok.kind == TOK_PLUS || tok.kind == TOK_MINUS) {
+        
+            if (tok.kind == TOK_MINUS) {
+                negate = !negate;
+            }
+            
+            get_token ();
+        
+        }
+        
+        emit_load_assignment_rhs_to_reg (reg);
+        
+        if (negate && state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    neg %s\n", reg);
+            } else {
+                fprintf (state->ofp, "    negl %%%s\n", reg);
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (token_is_sizeof_keyword ()) {
+    
+        int64_s v = sizeof_from_current_token ();
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    mov %s, %lu\n", reg, v.low & U32_MASK);
+            } else {
+                fprintf (state->ofp, "    movl $%lu, %%%s\n", v.low & U32_MASK, reg);
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (is_string_token ()) {
+    
+        char *label = emit_string_literal_global ();
+        
+        switch_section (SECTION_TEXT);
+        emit_load_address_to_reg_now (reg, label);
+        
+        free (label);
+        
+        /*
+         * A string literal is a primary expression and may still have
+         * postfix operators applied to it.  In particular, macro-expanded
+         * string constants are commonly subscripted in calls, e.g.
+         *
+         *     tebc (LINKAGE_EDITOR_PROGRAM_NAME[i])
+         *
+         * where LINKAGE_EDITOR_PROGRAM_NAME expands to a string literal.
+         * The old path returned immediately after loading the literal
+         * address, leaving the '[' token for the caller and causing a false
+         * "expected )".  Treat the literal as a char array here and consume
+         * any following subscripts.
+         */
+        if (tok.kind == TOK_LBRACK) {
+        
+            emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, DATA_CHAR & 0x1f);
+            emit_load_deref_reg_now (reg, DATA_CHAR & 0x1f);
+            
+            set_rhs_last_pointer_info (0, 0);
+        
+        } else {
+            set_rhs_last_pointer_info (1, DATA_CHAR & 0x1f);
+        }
+        
+        return;
+    
+    }
+    
+    switch (tok.kind) {
+    
+        case TOK_CCHAR:     case TOK_CINT:      case TOK_CUINT:     case TOK_CULONG:
+        case TOK_CLONG:     case TOK_CLLONG:    case TOK_CULLONG:   case TOK_LCHAR:
+        {
+        
+            int64_s v;
+            
+            int trailing_op = 0;
+            size_t len = tok.ident ? strlen (tok.ident) : 0;
+            
+            v.high = tok.val.i.high;
+            v.low = tok.val.i.low;
+            
+            if (len > 1 && tok.ident[len - 1] == '+') {
+                trailing_op = TOK_PLUS;
+            } else if (len > 1 && tok.ident[len - 1] == '-') {
+                trailing_op = TOK_MINUS;
+            }
+            
+            if (trailing_op) {
+            
+                free (tok.ident);
+                
+                tok.ident = xstrdup (trailing_op == TOK_PLUS ? "+" : "-");
+                tok.kind = (enum token_kind) trailing_op;
+                
+                if (tok.caret) {
+                    tok.caret--;
+                }
+            
+            } else {
+                get_token ();
+            }
+            
+            emit_load_const32_to_reg_now (reg, v);
+            return;
+        
+        }
+        
+        case TOK_CFLOAT:    case TOK_CDOUBLE:    case TOK_CLDOUBLE:
+        {
+        
+            int trailing_op = 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;
+            
+            if (len > 1 && tok.ident[len - 1] == '+') {
+                trailing_op = TOK_PLUS;
+            } else if (len > 1 && tok.ident[len - 1] == '-') {
+                trailing_op = TOK_MINUS;
+            }
+            
+            if (trailing_op) {
+            
+                free (tok.ident);
+                
+                tok.ident = xstrdup (trailing_op == TOK_PLUS ? "+" : "-");
+                tok.kind = (enum token_kind) trailing_op;
+                
+                if (tok.caret) {
+                    tok.caret--;
+                }
+            
+            } else {
+                get_token ();
+            }
+            
+            emit_load_const32_to_reg_now (reg, v);
+            return;
+        
+        }
+        
+        default:
+        
+            break;
+    
+    }
+    
+    if (tok.kind == TOK_SCC_BUILTIN_VA_ARG) {
+    
+        int va_size = DATA_INT & 0x1f;
+        int va_unsigned = 1;
+        int va_pointer = 0;
+        int va_floating = 0;
+        
+        get_token ();
+        
+        emit_parse_builtin_va_arg_address_to_reg_now (reg, &va_size, &va_unsigned, &va_pointer, &va_floating);
+        emit_load_deref_reg_now (reg, va_size);
+        
+        if (va_pointer > 0) {
+            set_rhs_last_pointer_info (va_pointer, DATA_INT & 0x1f);
+        } else {
+        
+            emit_apply_integer_cast_to_reg_now (reg, va_size, va_unsigned);
+            clear_rhs_last_pointer_info ();
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_IDENT) {
+    
+        enum token_kind postfix_op = TOK_EOF;
+        char *name = xstrdup (tok.ident);
+        
+        const char *name_start = tok.start, *name_caret = tok.caret;
+        unsigned long name_line = get_line_number ();
+        
+        struct local_symbol *src;
+        int postfix_incdec = 0;
+        
+        get_token ();
+        
+        if (strcmp (name, "__scc_builtin_va_arg") == 0 && tok.kind == TOK_LPAREN) {
+        
+            int va_size = DATA_INT & 0x1f;
+            int va_unsigned = 1;
+            int va_pointer = 0;
+            int va_floating = 0;
+            
+            emit_parse_builtin_va_arg_address_to_reg_now (reg, &va_size, &va_unsigned, &va_pointer, &va_floating);
+            emit_load_deref_reg_now (reg, va_size);
+            
+            if (va_pointer > 0) {
+                set_rhs_last_pointer_info (va_pointer, DATA_INT & 0x1f);
+            } else {
+            
+                emit_apply_integer_cast_to_reg_now (reg, va_size, va_unsigned);
+                clear_rhs_last_pointer_info ();
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        {
+        
+            int64_s enum_value;
+            
+            if (!find_local_symbol (name) && find_global_symbol (name) < 0 && resolve_enum_constant (name, &enum_value)) {
+            
+                emit_load_const32_to_reg_now (reg, enum_value);
+                
+                set_rhs_last_pointer_info (0, DATA_INT & 0x1f);
+                free (name);
+                
+                return;
+            
+            }
+        
+        }
+        
+        if (tok.kind == TOK_LBRACK) {
+        
+            src = find_local_symbol (name);
+            
+            if (src) {
+            
+                int saw_subscript;
+                int elem_size;
+                
+                {
+                
+                    elem_size = src->is_array ? (src->pointer_depth ? DATA_PTR : (src->array_element_size > 0 ? src->array_element_size : src->pointed_size)) :
+                        (src->pointer_depth > 1 ? DATA_PTR : src->pointed_size);
+                    
+                    if (src->is_array && src->pointer_depth == 0 && elem_size <= (DATA_PTR & 0x1f)) {
+                    
+                        int aggregate_elem_size = aggregate_tag_size_or_zero (src->tag_name ? src->tag_name : src->pointed_tag_name);
+                        
+                        if (aggregate_elem_size > (DATA_PTR & 0x1f)) {
+                            elem_size = aggregate_elem_size;
+                        }
+                    
+                    }
+                    
+                    if (src->is_array) {
+                    
+                        if (src->is_static && src->static_label) {
+                            emit_load_symbol_address_to_reg_now (reg, src->static_label, 0, 0);
+                        } else {
+                            emit_load_symbol_address_to_reg_now (reg, 0, src->offset, 1);
+                        }
+                    
+                    } else if (src->is_static && src->static_label) {
+                        emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+                    }
+                    
+                    saw_subscript = emit_parse_postfix_subscripts_to_reg_dims_now (reg, elem_size, src->pointer_depth, src->pointed_size, src->array_dimensions, src->pointer_depth > 0 ? src->pointed_is_unsigned : src->is_unsigned);
+                    
+                    postfix_copy_lvalue_size = index_step_size (elem_size);
+                    postfix_copy_lvalue_tag_name = src->is_array ? (src->tag_name ? src->tag_name : src->pointed_tag_name) : src->pointed_tag_name;
+                
+                }
+                
+                emit_apply_postfix_member_access_to_reg_now (reg);
+                postfix_copy_lvalue_tag_name = 0;
+                
+                if (!postfix_member_seen && emit_store_assignment_to_aggregate_address_now (reg, elem_size, name_start, name_caret, name_line)) {
+                
+                    free (name);
+                    return;
+                
+                }
+                
+                if (!postfix_member_seen && saw_subscript && elem_size > (DATA_PTR & 0x1f)) {
+                
+                    postfix_member_seen = 1;
+                    postfix_member_pointer_depth = 0;
+                    postfix_member_pointed_size = elem_size;
+                    postfix_member_size = elem_size;
+                    postfix_member_is_floating = src->is_floating;
+                    postfix_member_is_unsigned = src->is_unsigned;
+                
+                }
+                
+                if (postfix_member_seen) {
+                    set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
+                } else {
+                    set_rhs_last_pointer_info (src->pointer_depth > 0 ? src->pointer_depth - 1 : 0, src->pointed_size);
+                }
+                
+                free (name);
+                return;
+            
+            }
+            
+            if (find_global_symbol (name) >= 0) {
+            
+                int saw_subscript;
+                int elem_size;
+                
+                {
+                
+                    elem_size = get_global_symbol_array (name) ?
+                        (get_global_symbol_pointer_depth (name) ? DATA_PTR :
+                            (get_global_symbol_array_element_size (name) > 0 ? get_global_symbol_array_element_size (name) : get_global_symbol_pointed_size (name))) :
+                                (get_global_symbol_pointer_depth (name) > 1 ? DATA_PTR : get_global_symbol_pointed_size (name));
+                    
+                    if (get_global_symbol_array (name) && get_global_symbol_pointer_depth (name) == 0 && elem_size <= (DATA_PTR & 0x1f)) {
+                    
+                        int aggregate_elem_size = aggregate_tag_size_or_zero (get_global_symbol_tag_name (name));
+                        
+                        if (aggregate_elem_size > (DATA_PTR & 0x1f)) {
+                            elem_size = aggregate_elem_size;
+                        }
+                    
+                    }
+                    
+                    if (get_global_symbol_array (name)) {
+                        emit_load_symbol_address_to_reg_now (reg, name, 0, 0);
+                    } else {
+                        emit_load_global_to_reg (reg, name, DATA_PTR);
+                    }
+                    
+                    saw_subscript = emit_parse_postfix_subscripts_to_reg_dims_now (reg, elem_size, get_global_symbol_pointer_depth (name), get_global_symbol_pointed_size (name), get_global_symbol_array_dimensions (name), get_global_symbol_pointer_depth (name) > 0 ? get_global_symbol_pointed_is_unsigned (name) : get_global_symbol_unsigned (name));
+                    
+                    postfix_copy_lvalue_size = index_step_size (elem_size);
+                    postfix_copy_lvalue_tag_name = get_global_symbol_array (name) ? get_global_symbol_tag_name (name) : 0;
+                
+                }
+                
+                emit_apply_postfix_member_access_to_reg_now (reg);
+                postfix_copy_lvalue_tag_name = 0;
+                
+                if (!postfix_member_seen && emit_store_assignment_to_aggregate_address_now (reg, elem_size, name_start, name_caret, name_line)) {
+                
+                    free (name);
+                    return;
+                
+                }
+                
+                if (!postfix_member_seen && saw_subscript && elem_size > (DATA_PTR & 0x1f)) {
+                
+                    postfix_member_seen = 1;
+                    postfix_member_pointer_depth = 0;
+                    postfix_member_pointed_size = elem_size;
+                    postfix_member_size = elem_size;
+                    postfix_member_is_floating = get_global_symbol_floating (name);
+                    postfix_member_is_unsigned = get_global_symbol_unsigned (name);
+                
+                }
+                
+                free (name);
+                return;
+            
+            }
+        
+        }
+        
+        if (tok.kind == TOK_LPAREN) {
+        
+            if (!find_local_symbol (name)) {
+                ensure_global_function_symbol (name, name_start, name_caret, name_line);
+            }
+            
+            if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION && get_global_symbol_returns_void (name)) {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "void function '%s' used as a value", name);
+            }
+            
+            emit_call_identifier_to_reg_now (name, reg, name_start, name_caret, name_line);
+            
+            if (tok.kind == TOK_LBRACK) {
+            
+                int subscript_pointer_depth = get_global_symbol_pointer_depth (name);
+                int subscript_elem_size = get_global_symbol_pointed_size (name);
+                
+                if (subscript_elem_size <= 0) {
+                    subscript_elem_size = DATA_INT & 0x1f;
+                }
+                
+                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, subscript_elem_size);
+                
+                if (is_assignment_operator (tok.kind)) {
+                
+                    enum token_kind assign_op = tok.kind;
+                    
+                    get_token ();
+                    emit_push_reg_now (reg);
+                    
+                    if (assign_op == TOK_ASSIGN) {
+                    
+                        if (subscript_elem_size > (DATA_LLONG & 0x1f)) {
+                        
+                            pending_struct_return_lhs = 0;
+                            pending_struct_return_global_name = 0;
+                            pending_struct_return_stack_address = 1;
+                            pending_struct_return_stack_offset = 0;
+                            
+                            emit_load_assignment_rhs_expression_to_reg (reg);
+                            
+                            pending_struct_return_stack_address = 0;
+                            pending_struct_return_stack_offset = 0;
+                            
+                            emit_pop_reg_now ("edx");
+                            postfix_member_seen = 0;
+                            
+                            return;
+                        
+                        }
+                        
+                        emit_load_assignment_rhs_expression_to_reg (reg);
+                    
+                    } else {
+                    
+                        emit_load_deref_reg_now (reg, subscript_elem_size);
+                        emit_push_reg_now (reg);
+                        
+                        emit_load_assignment_rhs_expression_to_reg ("edx");
+                        emit_pop_reg_now (reg);
+                        
+                        emit_assignment_binary_op (assign_op, 0);
+                    
+                    }
+                    
+                    emit_pop_reg_now ("edx");
+                    emit_store_member_to_addr_reg_now ("edx", 0, reg, subscript_elem_size);
+                    set_rhs_last_pointer_info (0, 0);
+                    
+                    free (name);
+                    return;
+                
+                }
+                
+                emit_load_deref_reg_now (reg, subscript_elem_size);
+                
+                if (subscript_pointer_depth > 0) {
+                    subscript_pointer_depth--;
+                }
+                
+                if (subscript_pointer_depth > 0) {
+                    set_rhs_last_pointer_info (subscript_pointer_depth, subscript_elem_size);
+                } else {
+                    set_rhs_last_pointer_info (0, 0);
+                }
+            
+            }
+            
+            emit_apply_postfix_member_access_to_reg_now (reg);
+            
+            if (postfix_member_seen && tok.kind == TOK_LPAREN) {
+            
+                emit_call_pointer_in_reg_now (reg, reg);
+                
+                set_rhs_last_pointer_info (0, 0);
+                free (name);
+                
+                return;
+            
+            }
+            
+            if (postfix_member_seen) {
+                set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (is_assignment_operator (tok.kind)) {
+        
+            enum token_kind assign_op = tok.kind;
+            struct local_symbol *dst;
+            int global_index;
+            int dst_size;
+            int dst_is_floating;
+            
+            get_token ();
+            
+            dst = find_local_symbol (name);
+            global_index = find_global_symbol (name);
+            
+            if (!dst && global_index < 0) {
+            
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+                
+                if (state->ofp) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    xor %s, %s\n", reg, reg);
+                    } else {
+                        fprintf (state->ofp, "    xorl %%%s, %%%s\n", reg, reg);
+                    }
+                
+                }
+                
+                free (name);
+                return;
+            
+            }
+            
+            dst_size = dst ? dst->size : get_global_symbol_size (name);
+            dst_is_floating = dst ? dst->is_floating : get_global_symbol_floating (name);
+            
+            if (dst_is_floating) {
+            
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "floating assignment expression not implemented");
+                skip_balanced_until (TOK_RPAREN, TOK_SEMI, TOK_EOF);
+                
+                free (name);
+                return;
+            
+            }
+            
+            if (dst_size == (DATA_LLONG & 0x1f)) {
+            
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "64-bit assignment expression not implemented");
+                skip_balanced_until (TOK_RPAREN, TOK_SEMI, TOK_EOF);
+                
+                free (name);
+                return;
+            
+            }
+            
+            if (assign_op == TOK_ASSIGN) {
+                emit_load_assignment_rhs_expression_to_reg (reg);
+            } else {
+            
+                if (dst) {
+                
+                    if (dst->is_static && dst->static_label) {
+                        emit_load_global_to_reg_ex (reg, dst->static_label, dst->size, dst->is_unsigned);
+                    } else {
+                        emit_load_local_to_reg_ex (reg, dst->offset, dst->size, dst->is_unsigned);
+                    }
+                
+                } else {
+                    emit_load_global_to_reg_ex (reg, name, dst_size, get_global_symbol_unsigned (name));
+                }
+                
+                emit_load_assignment_rhs_expression_to_reg ("edx");
+                
+                if (strcmp (reg, "eax") != 0 && state->ofp) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    mov eax, %s\n", reg);
+                    } else {
+                        fprintf (state->ofp, "    movl %%%s, %%eax\n", reg);
+                    }
+                
+                }
+                
+                emit_assignment_binary_op (assign_op, dst ? dst->is_unsigned : get_global_symbol_unsigned (name));
+                
+                if (strcmp (reg, "eax") != 0 && state->ofp) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    mov %s, eax\n", reg);
+                    } else {
+                        fprintf (state->ofp, "    movl %%eax, %%%s\n", reg);
+                    }
+                
+                }
+            
+            }
+            
+            if (dst) {
+            
+                if (dst->is_static && dst->static_label) {
+                    emit_store_reg_to_global (dst->static_label, dst->size, reg);
+                } else {
+                    emit_store_reg_to_local (dst->offset, dst->size, reg);
+                }
+                
+                if (dst->is_array || dst->pointer_depth > 0) {
+                    set_rhs_last_pointer_info (dst->is_array ? 1 : dst->pointer_depth, dst->is_array ? local_array_pointer_step_size (dst) : dst->pointed_size);
+                } else {
+                    clear_rhs_last_pointer_info ();
+                }
+            
+            } else {
+            
+                emit_store_reg_to_global (name, dst_size, reg);
+                
+                if (get_global_symbol_array (name) || get_global_symbol_pointer_depth (name) > 0) {
+                    set_rhs_last_pointer_info (get_global_symbol_array (name) ? 1 : get_global_symbol_pointer_depth (name), get_global_symbol_array (name) ? global_array_pointer_step_size (name) : get_global_symbol_pointed_size (name));
+                } else {
+                    clear_rhs_last_pointer_info ();
+                }
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+        
+            postfix_incdec = 1;
+            postfix_op = tok.kind;
+            
+            get_token ();
+        
+        }
+        
+        src = find_local_symbol (name);
+        
+        if (postfix_incdec && tok.kind == TOK_LBRACK) {
+        
+            int pointer_depth = 0;
+            int pointed_size = 0;
+            int elem_size = DATA_INT & 0x1f;
+            int is_unsigned = 1;
+            int known = 0;
+            
+            if (src) {
+            
+                known = 1;
+                
+                pointer_depth = src->pointer_depth;
+                pointed_size = src->pointed_size;
+                
+                is_unsigned = src->is_unsigned;
+                
+                if (src->is_static && src->static_label) {
+                    emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg (reg, src->offset, DATA_PTR);
+                }
+            
+            } else if (find_global_symbol (name) >= 0) {
+            
+                known = 1;
+                
+                pointer_depth = get_global_symbol_pointer_depth (name);
+                pointed_size = get_global_symbol_pointed_size (name);
+                
+                is_unsigned = get_global_symbol_unsigned (name);
+                emit_load_global_to_reg (reg, name, DATA_PTR);
+            
+            }
+            
+            if (!known) {
+            
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+                
+                free (name);
+                return;
+            
+            }
+            
+            if (pointer_depth <= 0) {
+            
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "subscripted value is not a pointer");
+                
+                free (name);
+                return;
+            
+            }
+            
+            if (pointer_depth > 1) {
+                elem_size = DATA_PTR & 0x1f;
+            } else if (pointed_size > 0) {
+                elem_size = pointed_size & 0x1f;
+            }
+            
+            emit_push_reg_now (reg);
+            
+            emit_incdec_symbol_now (src, name, postfix_op, name_line, name_start, name_caret);
+            emit_pop_reg_now (reg);
+            
+            emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
+            
+            if (is_assignment_operator (tok.kind)) {
+            
+                enum token_kind assign_op = tok.kind;
+                get_token ();
+                
+                emit_push_reg_now (reg);
+                
+                if (assign_op == TOK_ASSIGN) {
+                    emit_load_assignment_rhs_expression_to_reg (reg);
+                } else {
+                
+                    emit_load_deref_reg_now (reg, elem_size);
+                    emit_push_reg_now (reg);
+                    
+                    emit_load_assignment_rhs_expression_to_reg ("edx");
+                    emit_pop_reg_now (reg);
+                    
+                    emit_assignment_binary_op (assign_op, is_unsigned);
+                
+                }
+                
+                emit_pop_reg_now ("edx");
+                emit_store_reg_to_deref_reg_now ("edx", reg, elem_size);
+                
+                clear_rhs_last_pointer_info ();
+                free (name);
+                
+                return;
+            
+            }
+            
+            emit_load_deref_reg_now (reg, elem_size);
+            
+            if (pointer_depth > 1) {
+                set_rhs_last_pointer_info (pointer_depth - 1, pointed_size);
+            } else {
+                clear_rhs_last_pointer_info ();
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (src) {
+        
+            if (src->is_array) {
+            
+                if (src->is_static && src->static_label) {
+                    emit_load_address_to_reg_now (reg, src->static_label);
+                } else {
+                    emit_load_local_address_to_reg_now (reg, src->offset);
+                }
+            
+            } else if (tok.kind == TOK_DOT) {
+            
+                if (src->is_static && src->static_label) {
+                    emit_load_address_to_reg_now (reg, src->static_label);
+                } else {
+                    emit_load_local_address_to_reg_now (reg, src->offset);
+                }
+            
+            } else if (src->is_static && src->static_label) {
+                emit_load_global_to_reg_ex (reg, src->static_label, src->size, src->is_unsigned);
+            } else {
+                emit_load_local_to_reg_ex (reg, src->offset, src->size, src->is_unsigned);
+            }
+            
+            if (src->pointer_depth > 0) {
+            
+                /*
+                 * Keep the pointed-to aggregate information even when the
+                 * arrow is not immediately visible.  Macro expansions commonly
+                 * parenthesize pointer operands, e.g. ((unknown)->type).
+                 * The inner expression sees ')' after 'unknown', and the
+                 * outer parenthesized path sees the later '->'.  If we clear
+                 * the tag here, that later member lookup falls back to an
+                 * unrelated member named 'type' and emits offset 0 instead of
+                 * the struct cpp_unknown offset.
+                 */
+                postfix_copy_lvalue_size = src->pointed_size;
+                postfix_copy_lvalue_tag_name = src->pointed_tag_name;
+            
+            } else {
+            
+                postfix_copy_lvalue_size = src->size;
+                postfix_copy_lvalue_tag_name = src->tag_name;
+            
+            }
+            
+            emit_apply_postfix_member_access_to_reg_now (reg);
+            
+            if (postfix_member_seen && tok.kind == TOK_LPAREN) {
+            
+                emit_call_pointer_in_reg_now (reg, reg);
+                
+                set_rhs_last_pointer_info (0, 0);
+                free (name);
+                
+                return;
+            
+            }
+            
+            if (emit_store_assignment_to_postfix_member_now (reg)) {
+            
+                set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
+                
+                free (name);
+                return;
+            
+            }
+            
+            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+            
+                postfix_incdec = 1;
+                postfix_op = tok.kind;
+                
+                get_token ();
+            
+            }
+            
+            if (postfix_incdec) {
+            
+                if (postfix_member_seen) {
+                    emit_apply_postfix_member_incdec_now (reg, postfix_op);
+                } else {
+                
+                    emit_push_reg_now (reg);
+                    emit_incdec_symbol_now (src, name, postfix_op, name_line, name_start, name_caret);
+                    emit_pop_reg_now (reg);
+                
+                }
+            
+            }
+            
+            if (postfix_member_seen) {
+                set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
+            } else {
+                set_rhs_last_pointer_info (src->is_array ? 1 : src->pointer_depth, src->is_array ? local_array_pointer_step_size (src) : src->pointed_size);
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (find_global_symbol (name) >= 0) {
+        
+            if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION ||
+                get_global_symbol_array (name) ||
+                (!get_global_symbol_pointer_depth (name) &&
+                    get_global_symbol_size (name) > (DATA_PTR & 0x1f)) ||
+                tok.kind == TOK_DOT) {
+                emit_load_address_to_reg_now (reg, name);
+            } else {
+                emit_load_global_to_reg_ex (reg, name, get_global_symbol_size (name), get_global_symbol_unsigned (name));
+            }
+            
+            if (tok.kind == TOK_ARROW && get_global_symbol_pointer_depth (name) > 0) {
+            
+                postfix_copy_lvalue_size = get_global_symbol_pointed_size (name);
+                postfix_copy_lvalue_tag_name = get_global_symbol_tag_name (name);
+            
+            } else {
+            
+                postfix_copy_lvalue_size = get_global_symbol_size (name);
+                postfix_copy_lvalue_tag_name = get_global_symbol_tag_name (name);
+            
+            }
+            
+            emit_apply_postfix_member_access_to_reg_now (reg);
+            
+            if (postfix_member_seen && tok.kind == TOK_LPAREN) {
+            
+                emit_call_pointer_in_reg_now (reg, reg);
+                
+                set_rhs_last_pointer_info (0, 0);
+                free (name);
+                
+                return;
+            
+            }
+            
+            if (emit_store_assignment_to_postfix_member_now (reg)) {
+            
+                set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
+                
+                free (name);
+                return;
+            
+            }
+            
+            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+            
+                postfix_incdec = 1;
+                postfix_op = tok.kind;
+                
+                get_token ();
+            
+            }
+            
+            if (postfix_incdec) {
+            
+                if (postfix_member_seen) {
+                    emit_apply_postfix_member_incdec_now (reg, postfix_op);
+                } else {
+                
+                    emit_push_reg_now (reg);
+                    emit_incdec_symbol_now (0, name, postfix_op, name_line, name_start, name_caret);
+                    emit_pop_reg_now (reg);
+                
+                }
+            
+            }
+            
+            if (postfix_member_seen) {
+                set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
+            } else {
+                set_rhs_last_pointer_info (get_global_symbol_array (name) ? 1 : get_global_symbol_pointer_depth (name), get_global_symbol_array (name) ? global_array_pointer_step_size (name) : get_global_symbol_pointed_size (name));
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        free (name);
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    xor %s, %s\n", reg, reg);
+            } else {
+                fprintf (state->ofp, "    xorl %%%s, %%%s\n", reg, reg);
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (recover_unknown_rhs_identifier ()) {
+    
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    xor %s, %s\n", reg, reg);
+            } else {
+                fprintf (state->ofp, "    xorl %%%s, %%%s\n", reg, reg);
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    {
+    
+        int64_s v = const64_from_current_operand ();
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    mov %s, %lu\n", reg, v.low & U32_MASK);
+            } else {
+                fprintf (state->ofp, "    movl $%lu, %%%s\n", v.low & U32_MASK, reg);
+            }
+        
+        }
+    
+    }
+
+}
+
+static int local_array_pointer_step_size (const struct local_symbol *sym) {
+
+    if (!sym || !sym->is_array) {
+        return 0;
+    }
+    
+    if (sym->array_element_size > 0) {
+        return index_step_size (sym->array_element_size);
+    }
+    
+    if (sym->pointed_size > 0 && sym->pointed_size < sym->size) {
+        return index_step_size (sym->pointed_size);
+    }
+    
+    return index_step_size (sym->size);
+
+}
+
+static int global_array_pointer_step_size (const char *name) {
+
+    long count;
+    int pointed_size;
+    
+    if (!name || !get_global_symbol_array (name)) {
+        return 0;
+    }
+    
+    if (get_global_symbol_array_element_size (name) > 0) {
+        return get_global_symbol_array_element_size (name);
+    }
+    
+    count = get_global_symbol_array_count (name);
+    
+    if (count > 0) {
+        return (int) (get_global_symbol_size (name) / count);
+    }
+    
+    pointed_size = get_global_symbol_pointed_size (name);
+    
+    if (pointed_size > 0 && pointed_size < get_global_symbol_size (name)) {
+        return index_step_size (pointed_size);
+    }
+    
+    return index_step_size (get_global_symbol_size (name));
+
+}
+
+static void emit_scale_reg_by_const_now (const char *reg, int scale) {
+
+    if (!state->ofp || scale <= 1) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    imul %s, %d\n", reg, scale);
+    } else {
+        fprintf (state->ofp, "    imull $%d, %%%s, %%%s\n", scale, reg, reg);
+    }
+
+}
+
+static void emit_divide_eax_by_const_now (int divisor) {
+
+    if (!state->ofp || divisor <= 1) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    mov ecx, %d\n", divisor);
+        fprintf (state->ofp, "    cdq\n");
+        fprintf (state->ofp, "    idiv ecx\n");
+    
+    } else {
+    
+        fprintf (state->ofp, "    movl $%d, %%ecx\n", divisor);
+        fprintf (state->ofp, "    cdq\n");
+        fprintf (state->ofp, "    idivl %%ecx\n");
+    
+    }
+
+}
+
+static void emit_assignment_binary_op (enum token_kind op, int is_unsigned) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        switch (op) {
+        
+            case TOK_PLUS:      case TOK_PLUSEQ:
+            
+                fprintf (state->ofp, "    add eax, edx\n");
+                break;
+            
+            case TOK_MINUS:     case TOK_MINUSEQ:
+            
+                fprintf (state->ofp, "    sub eax, edx\n");
+                break;
+            
+            case TOK_STAR:      case TOK_STAREQ:
+            
+                fprintf (state->ofp, "    imul eax, edx\n");
+                break;
+            
+            case TOK_BSLASH:    case TOK_SLASHEQ:
+            
+                fprintf (state->ofp, "    mov ecx, edx\n");
+                
+                if (is_unsigned) {
+                
+                    fprintf (state->ofp, "    xor edx, edx\n");
+                    fprintf (state->ofp, "    div ecx\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    cdq\n");
+                    fprintf (state->ofp, "    idiv ecx\n");
+                
+                }
+                
+                break;
+            
+            case TOK_MOD:
+            
+                fprintf (state->ofp, "    mov ecx, edx\n");
+                
+                if (is_unsigned) {
+                
+                    fprintf (state->ofp, "    xor edx, edx\n");
+                    fprintf (state->ofp, "    div ecx\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    cdq\n");
+                    fprintf (state->ofp, "    idiv ecx\n");
+                
+                }
+                
+                fprintf (state->ofp, "    mov eax, edx\n");
+                break;
+            
+            case TOK_MODEQ:
+            
+                fprintf (state->ofp, "    mov ecx, edx\n");
+                
+                if (is_unsigned) {
+                
+                    fprintf (state->ofp, "    xor edx, edx\n");
+                    fprintf (state->ofp, "    div ecx\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    cdq\n");
+                    fprintf (state->ofp, "    idiv ecx\n");
+                
+                }
+                
+                fprintf (state->ofp, "    mov eax, edx\n");
+                break;
+            
+            case TOK_AMPER:     case TOK_ANDEQ:
+            
+                fprintf (state->ofp, "    and eax, edx\n");
+                break;
+            
+            case TOK_PIPE:      case TOK_OREQ:
+            
+                fprintf (state->ofp, "    or eax, edx\n");
+                break;
+            
+            case TOK_CARET:     case TOK_XOREQ:
+            
+                fprintf (state->ofp, "    xor eax, edx\n");
+                break;
+            
+            case TOK_LSH:       case TOK_LSHEQ:
+            
+                fprintf (state->ofp, "    mov ecx, edx\n");
+                fprintf (state->ofp, "    shl eax, cl\n");
+                
+                break;
+            
+            case TOK_RSH:       case TOK_RSHEQ:
+            
+                fprintf (state->ofp, "    mov ecx, edx\n");
+                fprintf (state->ofp, is_unsigned ? "    shr eax, cl\n" : "    sar eax, cl\n");
+                
+                break;
+            
+            default:
+            
+                break;
+        
+        }
+    
+    } else {
+    
+        switch (op) {
+        
+            case TOK_PLUS:      case TOK_PLUSEQ:
+            
+                fprintf (state->ofp, "    addl %%edx, %%eax\n");
+                break;
+            
+            case TOK_MINUS:     case TOK_MINUSEQ:
+            
+                fprintf (state->ofp, "    subl %%edx, %%eax\n");
+                break;
+            
+            case TOK_STAR:      case TOK_STAREQ:
+            
+                fprintf (state->ofp, "    imull %%edx, %%eax\n");
+                break;
+            
+            case TOK_BSLASH:    case TOK_SLASHEQ:
+            
+                fprintf (state->ofp, "    movl %%edx, %%ecx\n");
+                
+                if (is_unsigned) {
+                
+                    fprintf (state->ofp, "    xorl %%edx, %%edx\n");
+                    fprintf (state->ofp, "    divl %%ecx\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    cdq\n");
+                    fprintf (state->ofp, "    idivl %%ecx\n");
+                
+                }
+                
+                break;
+            
+            case TOK_MOD:
+            
+                fprintf (state->ofp, "    movl %%edx, %%ecx\n");
+                
+                if (is_unsigned) {
+                
+                    fprintf (state->ofp, "    xorl %%edx, %%edx\n");
+                    fprintf (state->ofp, "    divl %%ecx\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    cdq\n");
+                    fprintf (state->ofp, "    idivl %%ecx\n");
+                
+                }
+                
+                fprintf (state->ofp, "    movl %%edx, %%eax\n");
+                break;
+            
+            case TOK_MODEQ:
+            
+                fprintf (state->ofp, "    movl %%edx, %%ecx\n");
+                
+                if (is_unsigned) {
+                
+                    fprintf (state->ofp, "    xorl %%edx, %%edx\n");
+                    fprintf (state->ofp, "    divl %%ecx\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    cdq\n");
+                    fprintf (state->ofp, "    idivl %%ecx\n");
+                
+                }
+                
+                fprintf (state->ofp, "    movl %%edx, %%eax\n");
+                break;
+            
+            case TOK_AMPER:     case TOK_ANDEQ:
+            
+                fprintf (state->ofp, "    andl %%edx, %%eax\n");
+                break;
+            
+            case TOK_PIPE:      case TOK_OREQ:
+            
+                fprintf (state->ofp, "    orl %%edx, %%eax\n");
+                break;
+            
+            case TOK_CARET:     case TOK_XOREQ:
+            
+                fprintf (state->ofp, "    xorl %%edx, %%eax\n");
+                break;
+            
+            case TOK_LSH:       case TOK_LSHEQ:
+            
+                fprintf (state->ofp, "    movl %%edx, %%ecx\n");
+                fprintf (state->ofp, "    sall %%cl, %%eax\n");
+                
+                break;
+            
+            case TOK_RSH:       case TOK_RSHEQ:
+            
+                fprintf (state->ofp, "    movl %%edx, %%ecx\n");
+                fprintf (state->ofp, is_unsigned ? "    shrl %%cl, %%eax\n" : "    sarl %%cl, %%eax\n");
+                
+                break;
+            
+            default:
+            
+                break;
+        
+        }
+    
+    }
+
+}
+
+static int token_is_floating_constant_now (void) {
+    return tok.kind == TOK_CFLOAT || tok.kind == TOK_CDOUBLE || tok.kind == TOK_CLDOUBLE;
+}
+
+static int64_s floating_constant_to_bits_now (int size) {
+
+    int64_s r;
+    
+    unsigned long bits32;
+    unsigned char bytes[8];
+    
+    int i;
+    
+    r.low = 0;
+    r.high = 0;
+    
+    if (size == (DATA_FLOAT & 0x1f)) {
+    
+        float f;
+        
+        if (tok.kind == TOK_CFLOAT) {
+            f = tok.val.f;
+        } else if (tok.kind == TOK_CLDOUBLE) {
+            f = (double) tok.val.ld;
+        } else {
+            f = tok.val.d;
+        }
+        
+        memcpy (&bits32, &f, sizeof (f));
+        
+        r.low = bits32;
+        get_token ();
+        
+        return r;
+    
+    }
+    
+    {
+    
+        double d;
+        
+        if (tok.kind == TOK_CFLOAT) {
+            d = (double) tok.val.f;
+        } else if (tok.kind == TOK_CLDOUBLE) {
+            d = (double) tok.val.ld;
+        } else {
+            d = tok.val.d;
+        }
+        
+        memset (bytes, 0, sizeof (bytes));
+        memcpy (bytes, &d, sizeof (d));
+        
+        for (i = 0; i < 4; i++) {
+            r.low |= ((unsigned long) bytes[i]) << (i * 8);
+        }
+        
+        for (i = 0; i < 4; i++) {
+            r.high |= ((unsigned long) bytes[i + 4]) << (i * 8);
+        }
+        
+        get_token ();
+        return r;
+    
+    }
+
+}
+
+static double floating_constant_to_ld_now (void) {
+
+    double v;
+    
+    if (tok.kind == TOK_CFLOAT) {
+        v = (float) tok.val.f;
+    } else if (tok.kind == TOK_CLDOUBLE) {
+        v = (double) tok.val.ld;
+    } else {
+        v = tok.val.d;
+    }
+    
+    get_token ();
+    return v;
+
+}
+
+static double int64_u32_base_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;
+
+}
+
+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)) {
+        return parse_floating_const_primary_now ();
+    }
+    
+    if (_accept (TOK_MINUS)) {
+        return -parse_floating_const_primary_now ();
+    }
+    
+    if (token_is_floating_constant_now ()) {
+        return floating_constant_to_ld_now ();
+    }
+    
+    iv = const64_from_current_operand ();
+    return int64_to_double_now (iv);
+
+}
+
+static double parse_floating_const_term_now (void) {
+
+    double rhs, v;
+    enum token_kind op;
+    
+    v = parse_floating_const_primary_now ();
+    
+    while (tok.kind == TOK_STAR || tok.kind == TOK_BSLASH) {
+    
+        op = tok.kind;
+        get_token ();
+        
+        rhs = parse_floating_const_primary_now ();
+        
+        if (op == TOK_STAR) {
+            v *= rhs;
+        } else {
+            v /= rhs;
+        }
+    
+    }
+    
+    return v;
+
+}
+
+static double parse_floating_const_expr_value_now (void) {
+
+    double rhs, v;
+    enum token_kind op;
+    
+    v = parse_floating_const_term_now ();
+    
+    while (tok.kind == TOK_PLUS || tok.kind == TOK_MINUS) {
+    
+        op = tok.kind;
+        get_token ();
+        
+        rhs = parse_floating_const_term_now ();
+        
+        if (op == TOK_PLUS) {
+            v += rhs;
+        } else {
+            v -= rhs;
+        }
+    
+    }
+    
+    return v;
+
+}
+
+static int64_s parse_floating_const_expr_bits_now (int size) {
+
+    double acc;
+    int64_s r;
+    
+    acc = parse_floating_const_expr_value_now ();
+    r.low = 0;
+    r.high = 0;
+    
+    if (size == (DATA_FLOAT & 0x1f)) {
+    
+        float f;
+        unsigned long bits32;
+        
+        f = (float) acc;
+        bits32 = 0;
+        memcpy (&bits32, &f, sizeof (f));
+        r.low = bits32;
+        return r;
+    
+    }
+    
+    {
+    
+        unsigned char bytes[8];
+        
+        double d = (double) acc;
+        int i;
+        
+        memset (bytes, 0, sizeof (bytes));
+        memcpy (bytes, &d, sizeof (d));
+        
+        for (i = 0; i < 4; i++) {
+            r.low |= ((unsigned long) bytes[i]) << (i * 8);
+        }
+        
+        for (i = 0; i < 4; i++) {
+            r.high |= ((unsigned long) bytes[i + 4]) << (i * 8);
+        }
+        
+        return r;
+    
+    }
+
+}
+
+static void emit_load_floating_const_bits_now (int size, int64_s v) {
+
+    int lab;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    lab = anon_label++;
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+    
+        switch_section (SECTION_DATA);
+        
+        if (size == (DATA_DOUBLE & 0x1f)) {
+        
+            /*
+             * 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 0%08lXh\n", lab, v.low & U32_MASK);
+        }
+        
+        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) {
+        
+            switch_section (SECTION_DATA);
+            
+            fprintf (state->ofp, "LC%d_flt:\n", lab);
+            fprintf (state->ofp, "    dd %lu\n", v.low & U32_MASK);
+            
+            if (size == (DATA_DOUBLE & 0x1f)) {
+                fprintf (state->ofp, "    dd %lu\n", v.high & U32_MASK);
+            }
+            
+            switch_section (SECTION_TEXT);
+            fprintf (state->ofp, "    fld %s [LC%d_flt]\n", size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", lab);
+        
+        } else {
+        
+            switch_section (SECTION_DATA);
+            
+            fprintf (state->ofp, ".LC%d_flt:\n", lab);
+            fprintf (state->ofp, "    .long %lu\n", v.low & U32_MASK);
+            
+            if (size == (DATA_DOUBLE & 0x1f)) {
+                fprintf (state->ofp, "    .long %lu\n", v.high & U32_MASK);
+            }
+            
+            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);
+            } else {
+                fprintf (state->ofp, "    fld%s .LC%d_flt\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", lab);
+            }
+        
+        }
+    
+    }
+
+}
+
+static void emit_load_floating_symbol_now (struct local_symbol *sym, const char *name, int size) {
+
+    char memref[64];
+    const char *label;
+    const char *asm_name;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    asm_name = asm_global_symbol_name (name);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (sym) {
+        
+            if (sym->is_static && sym->static_label) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fld %s [%s]\n" : "    fld %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", sym->static_label);
+            } else {
+            
+                format_intel_ebp_offset (memref, sizeof (memref), sym->offset);
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fld %s %s\n" : "    fld %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", memref);
+            
+            }
+        
+        } else {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fld %s [%s]\n" : "    fld %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", asm_name);
+        }
+    
+    } else {
+    
+        if (sym) {
+        
+            label = (sym->is_static && sym->static_label) ? sym->static_label : 0;
+            
+            if (label) {
+                fprintf (state->ofp, "    fld%s %s\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", label);
+            } else {
+                fprintf (state->ofp, "    fld%s %ld(%%ebp)\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", sym->offset);
+            }
+        
+        } else {
+            fprintf (state->ofp, "    fld%s %s\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", asm_name);
+        }
+    
+    }
+
+}
+
+static void emit_load_floating_member_symbol_now (struct local_symbol *sym, const char *name, int offset, int size) {
+
+    char memref[64];
+    char labelref[256];
+    
+    const char *label;
+    const char *asm_name;
+    const char *opsize;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    opsize = size == (DATA_FLOAT & 0x1f) ? "dword" : "qword";
+    asm_name = asm_global_symbol_name (name);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (sym) {
+        
+            if (sym->is_static && sym->static_label) {
+            
+                if (offset) {
+                
+                    sprintf (labelref, "%s + %d", sym->static_label, offset);
+                    label = labelref;
+                
+                } else {
+                    label = sym->static_label;
+                }
+                
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fld %s %s\n" : "    fld %s ptr %s\n"), opsize, label);
+            
+            } else {
+            
+                format_intel_ebp_offset (memref, sizeof (memref), sym->offset + offset);
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fld %s %s\n" : "    fld %s ptr %s\n"), opsize, memref);
+            
+            }
+        
+        } else {
+        
+            if (offset) {
+            
+                sprintf (labelref, "%s + %d", asm_name, offset);
+                label = labelref;
+            
+            } else {
+                label = asm_name;
+            }
+            
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fld %s %s\n" : "    fld %s ptr %s\n"), opsize, label);
+        
+        }
+    
+    } else {
+    
+        if (sym) {
+        
+            label = (sym->is_static && sym->static_label) ? sym->static_label : 0;
+            
+            if (label) {
+            
+                if (offset) {
+                
+                    sprintf (labelref, "%s+%d", label, offset);
+                    label = labelref;
+                
+                }
+                
+                fprintf (state->ofp, "    fld%s %s\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", label);
+            
+            } else {
+                fprintf (state->ofp, "    fld%s %ld(%%ebp)\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", sym->offset + offset);
+            }
+        
+        } else {
+        
+            if (offset) {
+            
+                sprintf (labelref, "%s+%d", asm_name, offset);
+                asm_name = labelref;
+            
+            }
+            
+            fprintf (state->ofp, "    fld%s %s\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", asm_name);
+        
+        }
+    
+    }
+
+}
+
+static void emit_duplicate_floating_stack_top_now (void) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_NASM) {
+        fprintf (state->ofp, "    fld st0\n");
+    } else if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    fld st(0)\n");
+    } else {
+        fprintf (state->ofp, "    fld %%st(0)\n");
+    }
+
+}
+
+static void emit_store_floating_symbol_now (struct local_symbol *sym, const char *name, int size) {
+
+    char memref[64];
+    const char *label;
+    const char *asm_name;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    asm_name = asm_global_symbol_name (name);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (sym) {
+        
+            if (sym->is_static && sym->static_label) {
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fstp %s %s\n" : "    fstp %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", sym->static_label);
+            } else {
+            
+                format_intel_ebp_offset (memref, sizeof (memref), sym->offset);
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fstp %s %s\n" : "    fstp %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", memref);
+            
+            }
+        
+        } else {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fstp %s %s\n" : "    fstp %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", asm_name);
+        }
+    
+    } else {
+    
+        if (sym) {
+        
+            label = (sym->is_static && sym->static_label) ? sym->static_label : 0;
+            
+            if (label) {
+                fprintf (state->ofp, "    fstp%s %s\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", label);
+            } else {
+                fprintf (state->ofp, "    fstp%s %ld(%%ebp)\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", sym->offset);
+            }
+        
+        } else {
+            fprintf (state->ofp, "    fstp%s %s\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", asm_name);
+        }
+    
+    }
+
+}
+
+static void emit_load_any_symbol_as_floating_now (struct local_symbol *src, const char *name, int size, int is_floating) {
+
+    if (is_floating) {
+    
+        emit_load_floating_symbol_now (src, name, size);
+        return;
+    
+    }
+    
+    if (src) {
+    
+        if (src->is_static && src->static_label) {
+            emit_load_global_to_reg_ex ("eax", src->static_label, src->size, src->is_unsigned);
+        } else {
+            emit_load_local_to_reg_ex ("eax", src->offset, src->size, src->is_unsigned);
+        }
+    
+    } else {
+        emit_load_global_to_reg_ex ("eax", name, size, get_global_symbol_unsigned (name));
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    sub esp, 4\n");
+        
+        if (state->syntax & ASM_SYNTAX_NASM) {
+        
+            fprintf (state->ofp, "    mov dword [esp], eax\n");
+            fprintf (state->ofp, "    fild dword [esp]\n");
+        
+        } else {
+        
+            fprintf (state->ofp, "    mov dword ptr [esp], eax\n");
+            fprintf (state->ofp, "    fild dword ptr [esp]\n");
+        
+        }
+        
+        fprintf (state->ofp, "    add esp, 4\n");
+    
+    } else {
+    
+        fprintf (state->ofp, "    subl $4, %%esp\n");
+        fprintf (state->ofp, "    movl %%eax, (%%esp)\n");
+        fprintf (state->ofp, "    fildl (%%esp)\n");
+        fprintf (state->ofp, "    addl $4, %%esp\n");
+    
+    }
+
+}
+
+static int emit_load_floating_prefix_incdec_now (void) {
+
+    enum token_kind op;
+    char *name;
+    
+    const char *name_start, *name_caret;
+    unsigned long name_line;
+    
+    struct local_symbol *sym;
+    int size;
+    int is_floating;
+    
+    if (!parse_incdec_identifier_now (&op, &name, &name_start, &name_caret, &name_line)) {
+        return 0;
+    }
+    
+    if (!name) {
+        return 1;
+    }
+    
+    sym = find_local_symbol (name);
+    emit_incdec_symbol_now (sym, name, op, name_line, name_start, name_caret);
+    
+    if (sym) {
+    
+        size = sym->size;
+        is_floating = sym->is_floating;
+        
+        emit_load_any_symbol_as_floating_now (sym, name, size, is_floating);
+    
+    } else if (find_global_symbol (name) >= 0) {
+    
+        size = get_global_symbol_size (name);
+        is_floating = get_global_symbol_floating (name);
+        
+        emit_load_any_symbol_as_floating_now (0, name, size, is_floating);
+    
+    }
+    
+    free (name);
+    return 1;
+
+}
+
+static void emit_load_floating_rhs_expression_now (int result_size);
+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);
+static void emit_statement_jump (int label);
+
+static void emit_eax_bool_to_floating_stack_now (void) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    sub esp, 4\n");
+        
+        if (state->syntax & ASM_SYNTAX_NASM) {
+        
+            fprintf (state->ofp, "    mov dword [esp], eax\n");
+            fprintf (state->ofp, "    fild dword [esp]\n");
+        
+        } else {
+        
+            fprintf (state->ofp, "    mov dword ptr [esp], eax\n");
+            fprintf (state->ofp, "    fild dword ptr [esp]\n");
+        
+        }
+        
+        fprintf (state->ofp, "    add esp, 4\n");
+    
+    } else {
+    
+        fprintf (state->ofp, "    subl $4, %%esp\n");
+        fprintf (state->ofp, "    movl %%eax, (%%esp)\n");
+        fprintf (state->ofp, "    fildl (%%esp)\n");
+        fprintf (state->ofp, "    addl $4, %%esp\n");
+    
+    }
+    
+    floating_rhs_result_in_eax_bool = 0;
+
+}
+
+static const char *floating_compare_true_setcc_now (enum token_kind op) {
+
+    switch (op) {
+    
+        case TOK_LESS:
+        
+            return "setb";
+        
+        case TOK_LTEQ:
+        
+            return "setbe";
+        
+        case TOK_GREATER:
+        
+            return "seta";
+        
+        case TOK_GTEQ:
+        
+            return "setae";
+        
+        case TOK_EQEQ:
+        
+            return "sete";
+        
+        case TOK_NOTEQ:
+        
+            return "setne";
+        
+        default:
+        
+            return "setz";
+    
+    }
+
+}
+
+static void emit_floating_compare_to_eax_now (enum token_kind op) {
+
+    const char *setcc;
+    
+    if (!state->ofp) {
+    
+        floating_rhs_result_in_eax_bool = 1;
+        return;
+    
+    }
+    
+    setcc = floating_compare_true_setcc_now (op);
+    
+    if (state->syntax & ASM_SYNTAX_NASM) {
+    
+        fprintf (state->ofp, "    fxch st1\n");
+        fprintf (state->ofp, "    fcompp\n");
+        fprintf (state->ofp, "    fnstsw ax\n");
+        fprintf (state->ofp, "    sahf\n");
+        fprintf (state->ofp, "    %s al\n", setcc);
+        fprintf (state->ofp, "    movzx eax, al\n");
+    
+    } else if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    fxch st(1)\n");
+        fprintf (state->ofp, "    fcompp\n");
+        fprintf (state->ofp, "    fnstsw ax\n");
+        fprintf (state->ofp, "    sahf\n");
+        fprintf (state->ofp, "    %s al\n", setcc);
+        fprintf (state->ofp, "    movzx eax, al\n");
+    
+    } else {
+    
+        fprintf (state->ofp, "    fxch %%st(1)\n");
+        fprintf (state->ofp, "    fcompp\n");
+        fprintf (state->ofp, "    fnstsw %%ax\n");
+        fprintf (state->ofp, "    sahf\n");
+        fprintf (state->ofp, "    %s %%al\n", setcc);
+        fprintf (state->ofp, "    movzbl %%al, %%eax\n");
+    
+    }
+    
+    floating_rhs_result_in_eax_bool = 1;
+
+}
+
+static void emit_fild_eax_now (void) {
+
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    sub esp, 4\n");
+        
+        if (state->syntax & ASM_SYNTAX_NASM) {
+        
+            fprintf (state->ofp, "    mov dword [esp], eax\n");
+            fprintf (state->ofp, "    fild dword [esp]\n");
+        
+        } else {
+        
+            fprintf (state->ofp, "    mov dword ptr [esp], eax\n");
+            fprintf (state->ofp, "    fild dword ptr [esp]\n");
+        
+        }
+        
+        fprintf (state->ofp, "    add esp, 4\n");
+    
+    } else {
+    
+        fprintf (state->ofp, "    subl $4, %%esp\n");
+        fprintf (state->ofp, "    movl %%eax, (%%esp)\n");
+        fprintf (state->ofp, "    fildl (%%esp)\n");
+        fprintf (state->ofp, "    addl $4, %%esp\n");
+    
+    }
+
+}
+
+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) {
+    
+        enum token_kind unary_op = tok.kind;
+        get_token ();
+        
+        emit_load_floating_rhs_operand_now (result_size);
+        
+        if (unary_op == TOK_MINUS) {
+            fprintf (state->ofp, "    fchs\n");
+        }
+        
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_STAR) {
+    
+        int deref_size = result_size;
+        int deref_is_floating = 1;
+        
+        get_token ();
+        
+        if (tok.kind == TOK_LPAREN) {
+        
+            get_token ();
+            
+            if (is_type_start (tok.kind) && parse_deref_cast_type_name (&deref_size)) {
+            
+                emit_load_any_deref_as_floating_now ("eax", deref_size, last_deref_cast_type_is_floating);
+                return;
+            
+            }
+            
+            emit_load_assignment_rhs_expression_to_reg ("eax");
+            expect (TOK_RPAREN, ")");
+            
+            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");
+        
+        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;
+    
+    }
+    
+    if (_accept (TOK_LPAREN)) {
+    
+        if (token_starts_type_name ()) {
+        
+            int cast_size = 0;
+            int cast_is_unsigned = 0;
+            int cast_is_pointer = 0;
+            
+            if (parse_cast_type_name (&cast_size, &cast_is_unsigned, &cast_is_pointer)) {
+            
+                if (!cast_is_pointer && !last_cast_type_is_floating) {
+                
+                    if (rhs_current_operand_is_floating_now ()) {
+                    
+                        emit_load_floating_rhs_operand_now (result_size);
+                        
+                        if (floating_rhs_result_in_eax_bool) {
+                        
+                            emit_extend_pair_high_from_low ("eax", "edx", cast_size, cast_is_unsigned);
+                            floating_rhs_result_in_eax_bool = 0;
+                        
+                        } else {
+                            emit_floating_stack_to_int_pair_now ("eax", "edx");
+                        }
+                        
+                        if ((cast_size & 0x1f) != (DATA_LLONG & 0x1f)) {
+                            emit_extend_pair_high_from_low ("eax", "edx", cast_size, cast_is_unsigned);
+                        }
+                    
+                    } else {
+                        emit_load_assignment_rhs_to_pair ("eax", "edx");
+                    }
+                    
+                    emit_integer_pair_to_floating_stack_now ("eax", "edx", cast_size);
+                    return;
+                
+                }
+                
+                emit_load_floating_rhs_operand_now (result_size);
+                return;
+            
+            }
+        
+        }
+        
+        emit_load_floating_rhs_expression_now (result_size);
+        expect (TOK_RPAREN, ")");
+        
+        if (floating_rhs_result_in_eax_bool && tok.kind != TOK_QMARK) {
+            emit_eax_bool_to_floating_stack_now ();
+        }
+        
+        return;
+    
+    }
+    
+    if (emit_load_floating_prefix_incdec_now ()) {
+        return;
+    }
+    
+    if (token_is_sizeof_keyword ()) {
+    
+        int64_s v = sizeof_from_current_token ();
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, "    sub esp, 4\n");
+            
+            if (state->syntax & ASM_SYNTAX_NASM) {
+                
+                fprintf (state->ofp, "    mov dword [esp], %lu\n", v.low & U32_MASK);
+                fprintf (state->ofp, "    fild dword [esp]\n");
+            
+            } else {
+            
+                fprintf (state->ofp, "    mov dword ptr [esp], %lu\n", v.low & U32_MASK);
+                fprintf (state->ofp, "    fild dword ptr [esp]\n");
+            
+            }
+            
+            fprintf (state->ofp, "    add esp, 4\n");
+        
+        } else {
+        
+            fprintf (state->ofp, "    subl $4, %%esp\n");
+            fprintf (state->ofp, "    movl $%lu, (%%esp)\n", v.low & U32_MASK);
+            fprintf (state->ofp, "    fildl (%%esp)\n");
+            fprintf (state->ofp, "    addl $4, %%esp\n");
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_SCC_BUILTIN_VA_ARG) {
+    
+        int va_size = DATA_DOUBLE & 0x1f;
+        int va_unsigned = 0;
+        int va_pointer = 0;
+        int va_floating = 0;
+        
+        get_token ();
+        
+        emit_parse_builtin_va_arg_address_to_reg_now ("eax", &va_size, &va_unsigned, &va_pointer, &va_floating);
+        emit_load_floating_deref_reg_now ("eax", va_size);
+        
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_IDENT) {
+    
+        char *name = xstrdup (tok.ident);
+        
+        const char *name_start = tok.start, *name_caret = tok.caret;
+        unsigned long name_line = get_line_number ();
+        
+        struct local_symbol *src = find_local_symbol (name);
+        get_token ();
+        
+        if (strcmp (name, "__scc_builtin_va_arg") == 0 && tok.kind == TOK_LPAREN) {
+        
+            int va_size = DATA_DOUBLE & 0x1f;
+            int va_unsigned = 0;
+            int va_pointer = 0;
+            int va_floating = 0;
+            
+            emit_parse_builtin_va_arg_address_to_reg_now ("eax", &va_size, &va_unsigned, &va_pointer, &va_floating);
+            emit_load_floating_deref_reg_now ("eax", va_size);
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (is_assignment_operator (tok.kind)) {
+        
+            enum token_kind assign_op = tok.kind;
+            
+            int dst_size = 0;
+            int dst_is_floating = 0;
+            int have_dst = 0;
+            
+            if (src) {
+            
+                dst_size = src->size;
+                
+                dst_is_floating = src->is_floating;
+                have_dst = 1;
+            
+            } else if (find_global_symbol (name) >= 0) {
+            
+                dst_size = get_global_symbol_size (name);
+                
+                dst_is_floating = get_global_symbol_floating (name);
+                have_dst = 1;
+            
+            }
+            
+            if (have_dst && dst_is_floating && floating_assignment_operator_supported_now (assign_op)) {
+            
+                get_token ();
+                
+                if (assign_op == TOK_ASSIGN) {
+                    emit_load_floating_rhs_expression_now (dst_size);
+                } else {
+                
+                    emit_load_floating_symbol_now (src, name, dst_size);
+                    emit_load_floating_rhs_expression_now (dst_size);
+                    
+                    emit_floating_binary_now (assign_op);
+                
+                }
+                
+                emit_duplicate_floating_stack_top_now ();
+                emit_store_floating_symbol_now (src, name, dst_size);
+                
+                free (name);
+                return;
+            
+            }
+        
+        }
+        
+        if (tok.kind == TOK_LPAREN) {
+        
+            if (!find_local_symbol (name)) {
+                ensure_global_function_symbol (name, name_start, name_caret, name_line);
+            }
+            
+            if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION && get_global_symbol_returns_void (name)) {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "void function '%s' used as a value", name);
+            }
+            
+            emit_call_identifier_to_reg_now (name, "eax", name_start, name_caret, name_line);
+            
+            if (!get_global_function_returns_floating (name)) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    fprintf (state->ofp, "    sub esp, 4\n");
+                    
+                    if (state->syntax & ASM_SYNTAX_NASM) {
+                    
+                        fprintf (state->ofp, "    mov dword [esp], eax\n");
+                        fprintf (state->ofp, "    fild dword [esp]\n");
+                    
+                    } else {
+                    
+                        fprintf (state->ofp, "    mov dword ptr [esp], eax\n");
+                        fprintf (state->ofp, "    fild dword ptr [esp]\n");
+                    
+                    }
+                    
+                    fprintf (state->ofp, "    add esp, 4\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    subl $4, %%esp\n");
+                    fprintf (state->ofp, "    movl %%eax, (%%esp)\n");
+                    fprintf (state->ofp, "    fildl (%%esp)\n");
+                    fprintf (state->ofp, "    addl $4, %%esp\n");
+                
+                }
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_LBRACK && (src || find_global_symbol (name) >= 0)) {
+        
+            int elem_size;
+            int pointer_depth;
+            int pointed_size;
+            
+            if (src) {
+            
+                elem_size = src->is_array ?
+                    (src->pointer_depth ? DATA_PTR : (src->array_element_size > 0 ? src->array_element_size : src->pointed_size)) :
+                    (src->pointer_depth > 1 ? DATA_PTR : src->pointed_size);
+                
+                pointer_depth = src->pointer_depth;
+                pointed_size = src->pointed_size;
+                
+                if (src->is_array) {
+                
+                    if (src->is_static && src->static_label) {
+                        emit_load_symbol_address_to_reg_now ("eax", src->static_label, 0, 0);
+                    } else {
+                        emit_load_symbol_address_to_reg_now ("eax", 0, src->offset, 1);
+                    }
+                
+                } else if (src->is_static && src->static_label) {
+                    emit_load_global_to_reg ("eax", src->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg ("eax", src->offset, DATA_PTR);
+                }
+            
+            } else {
+            
+                elem_size = get_global_symbol_array (name) ?
+                    (get_global_symbol_pointer_depth (name) ? DATA_PTR :
+                        (get_global_symbol_array_element_size (name) > 0 ? get_global_symbol_array_element_size (name) : get_global_symbol_pointed_size (name))) :
+                    (get_global_symbol_pointer_depth (name) > 1 ? DATA_PTR : get_global_symbol_pointed_size (name));
+                
+                pointer_depth = get_global_symbol_pointer_depth (name);
+                pointed_size = get_global_symbol_pointed_size (name);
+                
+                if (get_global_symbol_array (name)) {
+                    emit_load_symbol_address_to_reg_now ("eax", name, 0, 0);
+                } else {
+                    emit_load_global_to_reg ("eax", name, DATA_PTR);
+                }
+            
+            }
+            
+            if (elem_size <= 0) {
+                elem_size = DATA_INT & 0x1f;
+            }
+            
+            emit_parse_postfix_subscripts_to_reg_now ("eax", elem_size, pointer_depth, pointed_size);
+            
+            if ((elem_size & 0x1f) > DATA_PTR) {
+                emit_load_floating_deref_reg_now ("eax", elem_size);
+            } else {
+                emit_fild_eax_now ();
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_ARROW && (src || find_global_symbol (name) >= 0)) {
+        
+            char *member;
+            
+            const char *member_start;
+            const char *member_caret;
+            
+            unsigned long member_line;
+            
+            int member_offset = 0;
+            int member_size = result_size;
+            int member_elem_size = result_size;
+            int member_pointer_depth = 0;
+            int member_is_array = 0;
+            int member_is_floating = 0;
+            int base_size;
+            
+            const char *base_tag_name;
+            
+            if (src) {
+            
+                base_size = src->pointed_size;
+                base_tag_name = src->pointed_tag_name;
+            
+            } else {
+            
+                base_size = get_global_symbol_pointed_size (name);
+                base_tag_name = get_global_symbol_tag_name (name);
+            
+            }
+            
+            get_token ();
+            
+            member_start = tok.start;
+            member_caret = tok.caret;
+            member_line = get_line_number ();
+            
+            if (tok.kind != TOK_IDENT) {
+            
+                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after ->");
+                
+                free (name);
+                return;
+            
+            }
+            
+            member = xstrdup (tok.ident);
+            get_token ();
+            
+            if (!find_member_info_ex_bounded (member, base_size, base_tag_name, &member_offset, &member_size, &member_elem_size, &member_pointer_depth, &member_is_array, &member_is_floating)) {
+            
+                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+                
+                free (member);
+                free (name);
+                
+                return;
+            
+            }
+            
+            free (member);
+            
+            if (src) {
+            
+                if (src->is_static && src->static_label) {
+                    emit_load_global_to_reg ("eax", src->static_label, DATA_PTR & 0x1f);
+                } else {
+                    emit_load_local_to_reg ("eax", src->offset, DATA_PTR & 0x1f);
+                }
+            
+            } else {
+                emit_load_global_to_reg ("eax", name, DATA_PTR & 0x1f);
+            }
+            
+            if (member_is_floating) {
+                emit_load_floating_member_from_addr_reg_now ("eax", member_offset, member_size);
+            } else {
+            
+                emit_load_member_from_addr_reg_now ("eax", "eax", member_offset, member_size);
+                emit_eax_bool_to_floating_stack_now ();
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_DOT && (src || find_global_symbol (name) >= 0)) {
+        
+            char *member;
+            
+            const char *member_start;
+            const char *member_caret;
+            const char *current_tag_name;
+            
+            unsigned long member_line;
+            
+            int member_offset = 0;
+            int member_size = result_size;
+            int member_elem_size = result_size;
+            int member_pointer_depth = 0;
+            int member_is_array = 0;
+            int member_is_floating = 0;
+            int current_size;
+            
+            if (src) {
+            
+                current_size = src->size;
+                current_tag_name = src->tag_name;
+            
+            } else {
+            
+                current_size = get_global_symbol_size (name);
+                current_tag_name = get_global_symbol_tag_name (name);
+            
+            }
+            
+            get_token ();
+            
+            member_start = tok.start;
+            member_caret = tok.caret;
+            member_line = get_line_number ();
+            
+            if (tok.kind != TOK_IDENT) {
+            
+                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after .");
+                
+                free (name);
+                return;
+            
+            }
+            
+            member = xstrdup (tok.ident);
+            get_token ();
+            
+            if (!find_member_info_ex_bounded (member, current_size, current_tag_name, &member_offset, &member_size, &member_elem_size, &member_pointer_depth, &member_is_array, &member_is_floating)) {
+            
+                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+                
+                free (member);
+                free (name);
+                
+                return;
+            
+            }
+            
+            free (member);
+            
+            if (tok.kind != TOK_DOT && tok.kind != TOK_ARROW && member_is_floating) {
+            
+                emit_load_floating_member_symbol_now (src, name, member_offset, member_size);
+                
+                free (name);
+                return;
+            
+            }
+            
+            emit_load_symbol_address_for_copy_now ("eax", src, name);
+            emit_add_const_to_reg_now ("eax", member_offset);
+            
+            current_tag_name = last_found_member_tag_name;
+            
+            if (member_pointer_depth > 0 || member_is_array) {
+                current_size = member_elem_size;
+            } else {
+                current_size = member_size;
+            }
+            
+            while (tok.kind == TOK_DOT || tok.kind == TOK_ARROW) {
+            
+                enum token_kind member_op = tok.kind;
+                
+                get_token ();
+                
+                member_start = tok.start;
+                member_caret = tok.caret;
+                member_line = get_line_number ();
+                
+                if (tok.kind != TOK_IDENT) {
+                
+                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+                    
+                    free (name);
+                    return;
+                
+                }
+                
+                member = xstrdup (tok.ident);
+                get_token ();
+                
+                if (!find_member_info_ex_bounded (member, current_size, current_tag_name, &member_offset, &member_size, &member_elem_size, &member_pointer_depth, &member_is_array, &member_is_floating)) {
+                
+                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+                    
+                    free (member);
+                    free (name);
+                    
+                    return;
+                
+                }
+                
+                free (member);
+                
+                if (member_op == TOK_ARROW) {
+                    emit_load_deref_reg_now ("eax", DATA_PTR & 0x1f);
+                }
+                
+                emit_add_const_to_reg_now ("eax", member_offset);
+                
+                current_tag_name = last_found_member_tag_name;
+                
+                if (member_pointer_depth > 0 || member_is_array) {
+                    current_size = member_elem_size;
+                } else {
+                    current_size = member_size;
+                }
+            
+            }
+            
+            if (member_is_floating) {
+                emit_load_floating_member_from_addr_reg_now ("eax", 0, member_size);
+            } else {
+            
+                emit_load_deref_reg_now ("eax", member_size);
+                emit_eax_bool_to_floating_stack_now ();
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (src) {
+        
+            if (src->is_floating) {
+                emit_load_floating_symbol_now (src, name, src->size);
+            } else {
+            
+                if (src->is_static && src->static_label) {
+                    emit_load_global_to_reg_ex ("eax", src->static_label, src->size, src->is_unsigned);
+                } else {
+                    emit_load_local_to_reg_ex ("eax", src->offset, src->size, src->is_unsigned);
+                }
+                
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    fprintf (state->ofp, "    sub esp, 4\n");
+                    
+                    if (state->syntax & ASM_SYNTAX_NASM) {
+                    
+                        fprintf (state->ofp, "    mov dword [esp], eax\n");
+                        fprintf (state->ofp, "    fild dword [esp]\n");
+                    
+                    } else {
+                    
+                        fprintf (state->ofp, "    mov dword ptr [esp], eax\n");
+                        fprintf (state->ofp, "    fild dword ptr [esp]\n");
+                    
+                    }
+                    
+                    fprintf (state->ofp, "    add esp, 4\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    subl $4, %%esp\n");
+                    fprintf (state->ofp, "    movl %%eax, (%%esp)\n");
+                    fprintf (state->ofp, "    fildl (%%esp)\n");
+                    fprintf (state->ofp, "    addl $4, %%esp\n");
+                
+                }
+            
+            }
+            
+            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+            
+                enum token_kind postfix_op = tok.kind;
+                get_token ();
+                
+                emit_incdec_symbol_now (src, name, postfix_op, name_line, name_start, name_caret);
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (find_global_symbol (name) >= 0) {
+        
+            if (get_global_symbol_floating (name)) {
+                emit_load_floating_symbol_now (0, name, get_global_symbol_size (name));
+            } else {
+            
+                emit_load_global_to_reg_ex ("eax", name, get_global_symbol_size (name), get_global_symbol_unsigned (name));
+                
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    fprintf (state->ofp, "    sub esp, 4\n");
+                    
+                    if (state->syntax & ASM_SYNTAX_NASM) {
+                    
+                        fprintf (state->ofp, "    mov dword [esp], eax\n");
+                        fprintf (state->ofp, "    fild dword [esp]\n");
+                    
+                    } else {
+                    
+                        fprintf (state->ofp, "    mov dword ptr [esp], eax\n");
+                        fprintf (state->ofp, "    fild dword ptr [esp]\n");
+                    
+                    }
+                    
+                    fprintf (state->ofp, "    add esp, 4\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    subl $4, %%esp\n");
+                    fprintf (state->ofp, "    movl %%eax, (%%esp)\n");
+                    fprintf (state->ofp, "    fildl (%%esp)\n");
+                    fprintf (state->ofp, "    addl $4, %%esp\n");
+                
+                }
+            
+            }
+            
+            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+            
+                enum token_kind postfix_op = tok.kind;
+                get_token ();
+                
+                emit_incdec_symbol_now (0, name, postfix_op, name_line, name_start, name_caret);
+            
+            }
+            
+            free (name);
+            return;
+        
+        }
+        
+        free (name);
+    
+    }
+    
+    if (token_is_floating_constant_now ()) {
+    
+        emit_load_floating_const_bits_now (result_size, floating_constant_to_bits_now (result_size));
+        return;
+    
+    }
+    
+    if (recover_unknown_rhs_identifier ()) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    fldz\n");
+        } else {
+            fprintf (state->ofp, "    fldz\n");
+        }
+        return;
+    
+    }
+    
+    {
+    
+        int64_s v = const64_from_current_operand ();
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, "    sub esp, 4\n");
+            
+            if (state->syntax & ASM_SYNTAX_NASM) {
+            
+                fprintf (state->ofp, "    mov dword [esp], %lu\n", v.low & U32_MASK);
+                fprintf (state->ofp, "    fild dword [esp]\n");
+            
+            } else {
+            
+                fprintf (state->ofp, "    mov dword ptr [esp], %lu\n", v.low & U32_MASK);
+                fprintf (state->ofp, "    fild dword ptr [esp]\n");
+            
+            }
+            
+            fprintf (state->ofp, "    add esp, 4\n");
+        
+        } else {
+        
+            fprintf (state->ofp, "    subl $4, %%esp\n");
+            fprintf (state->ofp, "    movl $%lu, (%%esp)\n", v.low & U32_MASK);
+            fprintf (state->ofp, "    fildl (%%esp)\n");
+            fprintf (state->ofp, "    addl $4, %%esp\n");
+        
+        }
+    
+    }
+
+}
+
+static int token_is_floating_binary_now (enum token_kind k) {
+    return k == TOK_PLUS || k == TOK_MINUS || k == TOK_STAR || k == TOK_BSLASH;
+}
+
+static void emit_floating_binary_now (enum token_kind k) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    switch (k) {
+    
+        case TOK_PLUS:      case TOK_PLUSEQ:
+        
+            fprintf (state->ofp, "    faddp\n");
+            break;
+        
+        case TOK_MINUS:     case TOK_MINUSEQ:
+        
+            fprintf (state->ofp, "    fsubrp\n");
+            break;
+        
+        case TOK_STAR:      case TOK_STAREQ:
+        
+            fprintf (state->ofp, "    fmulp\n");
+            break;
+        
+        case TOK_BSLASH:    case TOK_SLASHEQ:
+        
+            fprintf (state->ofp, "    fdivrp\n");
+            break;
+        
+        default:
+        
+            break;
+    
+    }
+
+}
+
+static void emit_scale_reg_for_pointer_compound_assignment_now (const char *reg, struct local_symbol *lhs, const char *name, enum token_kind op) {
+
+    int pointer_depth;
+    int pointed_size;
+    int elem_size;
+    
+    if (op != TOK_PLUSEQ && op != TOK_MINUSEQ) {
+        return;
+    }
+    
+    pointer_depth = lhs ? lhs->pointer_depth : get_global_symbol_pointer_depth (name);
+    pointed_size = lhs ? lhs->pointed_size : get_global_symbol_pointed_size (name);
+    
+    if (pointer_depth <= 0) {
+        return;
+    }
+    
+    elem_size = pointer_depth > 1 ? DATA_PTR : pointed_size;
+    
+    if (elem_size > 1) {
+        emit_scale_reg_by_const_now (reg, elem_size);
+    }
+
+}
+
+static int floating_assignment_operator_supported_now (enum token_kind op) {
+    return op == TOK_ASSIGN || op == TOK_PLUSEQ || op == TOK_MINUSEQ || op == TOK_STAREQ || op == TOK_SLASHEQ;
+}
+
+static void emit_load_floating_rhs_expression_now (int result_size) {
+
+    enum token_kind op;
+    
+    int false_label;
+    int end_label;
+    
+    floating_rhs_result_in_eax_bool = 0;
+    emit_load_floating_rhs_operand_now (result_size);
+    
+    while (token_is_floating_binary_now (tok.kind)) {
+    
+        if (floating_rhs_result_in_eax_bool) {
+            emit_eax_bool_to_floating_stack_now ();
+        }
+        
+        op = tok.kind;
+        get_token ();
+        
+        emit_load_floating_rhs_operand_now (result_size);
+        
+        if (floating_rhs_result_in_eax_bool) {
+            emit_eax_bool_to_floating_stack_now ();
+        }
+        
+        emit_floating_binary_now (op);
+    
+    }
+    
+    if (is_value_compare_operator (tok.kind)) {
+    
+        op = tok.kind;
+        get_token ();
+        
+        emit_load_floating_rhs_operand_now (result_size);
+        
+        while (token_is_floating_binary_now (tok.kind)) {
+        
+            enum token_kind rhs_op = tok.kind;
+            get_token ();
+            
+            emit_load_floating_rhs_operand_now (result_size);
+            emit_floating_binary_now (rhs_op);
+        
+        }
+        
+        emit_floating_compare_to_eax_now (op);
+    
+    }
+    
+    if (tok.kind == TOK_QMARK) {
+    
+        false_label = anon_label++;
+        end_label = anon_label++;
+        
+        if (!floating_rhs_result_in_eax_bool) {
+        
+            if (state->ofp) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    fprintf (state->ofp, "    sub esp, 4\n");
+                    
+                    if (state->syntax & ASM_SYNTAX_NASM) {
+                    
+                        fprintf (state->ofp, "    fstp dword [esp]\n");
+                        fprintf (state->ofp, "    mov eax, dword [esp]\n");
+                    
+                    } else {
+                    
+                        fprintf (state->ofp, "    fstp dword ptr [esp]\n");
+                        fprintf (state->ofp, "    mov eax, dword ptr [esp]\n");
+                    
+                    }
+                    
+                    fprintf (state->ofp, "    add esp, 4\n");
+                    fprintf (state->ofp, "    test eax, eax\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    subl $4, %%esp\n");
+                    fprintf (state->ofp, "    fstps (%%esp)\n");
+                    fprintf (state->ofp, "    movl (%%esp), %%eax\n");
+                    fprintf (state->ofp, "    addl $4, %%esp\n");
+                    fprintf (state->ofp, "    testl %%eax, %%eax\n");
+                
+                }
+            
+            }
+        
+        } else if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    test eax, eax\n");
+            } else {
+                fprintf (state->ofp, "    testl %%eax, %%eax\n");
+            }
+        
+        }
+        
+        if (state->ofp) {
+        
+            if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+                fprintf (state->ofp, "    jz L%d\n", false_label);
+            } else {
+                fprintf (state->ofp, "    jz .L%d\n", false_label);
+            }
+        
+        }
+        
+        floating_rhs_result_in_eax_bool = 0;
+        get_token ();
+        
+        emit_load_floating_rhs_expression_now (result_size);
+        expect (TOK_COLON, ":");
+        
+        emit_statement_jump (end_label);
+        emit_statement_label (false_label);
+        
+        emit_load_floating_rhs_expression_now (result_size);
+        emit_statement_label (end_label);
+        
+        floating_rhs_result_in_eax_bool = 0;
+    
+    }
+
+}
+
+static void emit_load_assignment_rhs_expression_to_reg (const char *reg);
+
+static int current_argument_is_bare_identifier_now (void) {
+
+    const char *p;
+    
+    if (tok.kind != TOK_IDENT || !tok.caret) {
+        return 0;
+    }
+    
+    p = tok.caret + tok.len;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == ',' || *p == ')';
+
+}
+
+static int emit_push_aggregate_argument_now (const char *name, struct local_symbol *sym) {
+
+    int size;
+    int offset;
+    int chunk;
+    
+    char memref[64];
+    
+    if (!name || !sym || sym->is_array || sym->pointer_depth > 0 || sym->is_floating) {
+        return 0;
+    }
+    
+    /**
+     * Struct/union locals keep their real byte size here.  Masking with
+     * 0x1f is only valid for scalar DATA_* encodings; it turns e.g. a
+     * 72-byte struct cpu_flags argument into an 8-byte argument.
+     */
+    size = sym->size;
+    
+    /*
+     * Do not treat plain 64-bit scalar locals as aggregate arguments.
+     * The old test used only size > 4, so a call such as:
+     *
+     *     bytearray_write_4_bytes (..., result, endianess)
+     *
+     * where result is uint_fast64_t/address_type pushed both halves of
+     * result.  The callee expects an unsigned long here, so the extra high
+     * word shifted the following arguments and pdld wrote broken relocation
+     * bytes.  Real structs/unions either carry an aggregate tag here, or are
+     * larger than the built-in long long scalar size.
+     */
+    if (size <= (DATA_PTR & 0x1f) || (size <= (DATA_LLONG & 0x1f) && !sym->tag_name)) {
+        return 0;
+    }
+    
+    if (!state->ofp) {
+        return 1;
+    }
+    
+    for (offset = size; offset > 0; ) {
+    
+        if (offset >= 4) {
+        
+            chunk = 4;
+            offset -= 4;
+        
+        } else if (offset >= 2) {
+        
+            chunk = 2;
+            offset -= 2;
+        
+        } else {
+        
+            chunk = 1;
+            offset -= 1;
+        
+        }
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            if (sym->is_static && sym->static_label) {
+            
+                if (chunk == 4) {
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    push dword [%s + %d]\n" : "    push dword ptr %s + %d\n"), asm_global_symbol_name (sym->static_label), offset);
+                } else if (chunk == 2) {
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movzx eax, word [%s + %d]\n" : "    movzx eax, word ptr %s + %d\n"), asm_global_symbol_name (sym->static_label), offset); fprintf (state->ofp, "    push eax\n");
+                } else {
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movzx eax, byte [%s + %d]\n" : "    movzx eax, byte ptr %s + %d\n"), asm_global_symbol_name (sym->static_label), offset); fprintf (state->ofp, "    push eax\n");
+                }
+            
+            } else {
+            
+                format_intel_ebp_offset (memref, sizeof (memref), sym->offset + offset);
+                
+                if (chunk == 4) {
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    push dword %s\n" : "    push dword ptr %s\n"), memref);
+                } else if (chunk == 2) {
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movzx eax, word %s\n" : "    movzx eax, word ptr %s\n"), memref); fprintf (state->ofp, "    push eax\n");
+                } else {
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movzx eax, byte %s\n" : "    movzx eax, byte ptr %s\n"), memref); fprintf (state->ofp, "    push eax\n");
+                }
+            
+            }
+        
+        } else {
+        
+            if (sym->is_static && sym->static_label) {
+            
+                if (chunk == 4) {
+                    fprintf (state->ofp, "    pushl %s+%d\n", asm_global_symbol_name (sym->static_label), offset);
+                } else if (chunk == 2) {
+                    fprintf (state->ofp, "    movzwl %s+%d, %%eax\n", asm_global_symbol_name (sym->static_label), offset); fprintf (state->ofp, "    pushl %%eax\n");
+                } else {
+                    fprintf (state->ofp, "    movzbl %s+%d, %%eax\n", asm_global_symbol_name (sym->static_label), offset); fprintf (state->ofp, "    pushl %%eax\n");
+                }
+            
+            } else {
+            
+                if (chunk == 4) {
+                    fprintf (state->ofp, "    pushl %ld(%%ebp)\n", sym->offset + offset);
+                } else if (chunk == 2) {
+                    fprintf (state->ofp, "    movzwl %ld(%%ebp), %%eax\n", sym->offset + offset); fprintf (state->ofp, "    pushl %%eax\n");
+                } else {
+                    fprintf (state->ofp, "    movzbl %ld(%%ebp), %%eax\n", sym->offset + offset); fprintf (state->ofp, "    pushl %%eax\n");
+                }
+            
+            }
+        
+        }
+    
+    }
+    
+    return 1;
+
+}
+
+static int emit_push_global_aggregate_argument_now (const char *name) {
+
+    int size;
+    int offset;
+    int chunk;
+
+    if (!name || get_global_symbol_kind (name) != GLOBAL_SYMBOL_OBJECT ||
+        get_global_symbol_array (name) || get_global_symbol_pointer_depth (name) > 0 ||
+        get_global_symbol_floating (name)) {
+        return 0;
+    }
+    
+    size = get_global_symbol_size (name);
+    
+    if (size <= (DATA_PTR & 0x1f)) {
+        return 0;
+    }
+    
+    if (!state->ofp) {
+        return 1;
+    }
+    
+    for (offset = size; offset > 0; ) {
+    
+        if (offset >= 4) {
+        
+            chunk = 4;
+            offset -= 4;
+        
+        } else if (offset >= 2) {
+        
+            chunk = 2;
+            offset -= 2;
+        
+        } else {
+        
+            chunk = 1;
+            offset -= 1;
+        
+        }
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            if (chunk == 4) {
+            
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ?
+                    "    push dword [%s + %d]\n" :
+                    "    push dword ptr %s + %d\n"), asm_global_symbol_name (name), offset);
+            
+            } else if (chunk == 2) {
+            
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ?
+                    "    movzx eax, word [%s + %d]\n" :
+                    "    movzx eax, word ptr %s + %d\n"), asm_global_symbol_name (name), offset);
+                fprintf (state->ofp, "    push eax\n");
+            
+            } else {
+            
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ?
+                    "    movzx eax, byte [%s + %d]\n" :
+                    "    movzx eax, byte ptr %s + %d\n"), asm_global_symbol_name (name), offset);
+                fprintf (state->ofp, "    push eax\n");
+            
+            }
+        
+        } else {
+        
+            if (chunk == 4) {
+                fprintf (state->ofp, "    pushl %s+%d\n", asm_global_symbol_name (name), offset);
+            } else if (chunk == 2) {
+            
+                fprintf (state->ofp, "    movzwl %s+%d, %%eax\n", asm_global_symbol_name (name), offset);
+                fprintf (state->ofp, "    pushl %%eax\n");
+            
+            } else {
+            
+                fprintf (state->ofp, "    movzbl %s+%d, %%eax\n", asm_global_symbol_name (name), offset);
+                fprintf (state->ofp, "    pushl %%eax\n");
+            
+            }
+        
+        }
+    
+    }
+    
+    return 1;
+
+}
+
+static void emit_call_pointer_in_reg_now (const char *fn_reg, const char *result_reg) {
+
+    enum token_kind saved_calling_convention = postfix_member_calling_convention;
+    
+    int argc = 0;
+    int total_arg_bytes = 0;
+    int arg_bytes;
+    int arg_is_floating;
+    int i;
+    int ch;
+    
+    FILE **arg_tmp_ofps = 0;
+    FILE **new_arg_tmp_ofps = 0;
+    FILE *arg_saved_ofp = 0;
+    FILE *arg_tmp_ofp = 0;
+    
+    if (tok.kind != TOK_LPAREN) {
+        return;
+    }
+    
+    if (state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    push %s\n", fn_reg);
+        } else {
+            fprintf (state->ofp, "    pushl %%%s\n", fn_reg);
+        }
+    
+    }
+    
+    get_token ();
+    
+    if (tok.kind != TOK_RPAREN) {
+    
+        for (;;) {
+        
+            arg_saved_ofp = 0;
+            arg_tmp_ofp = 0;
+            
+            if (state->ofp) {
+            
+                arg_tmp_ofp = scc_tmpfile ();
+                
+                if (arg_tmp_ofp) {
+                
+                    arg_saved_ofp = state->ofp;
+                    state->ofp = arg_tmp_ofp;
+                
+                }
+            
+            }
+            
+            postfix_member_seen = 0;
+            postfix_member_size = 0;
+            postfix_member_pointer_depth = 0;
+            postfix_member_pointed_size = 0;
+            
+            if (tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && find_local_symbol (tok.ident) && emit_push_aggregate_argument_now (tok.ident, find_local_symbol (tok.ident))) {
+            
+                struct local_symbol *arg_sym = find_local_symbol (tok.ident);
+                
+                arg_bytes = arg_sym ? (arg_sym->size & 0x1f) : DATA_PTR;
+                arg_is_floating = 0;
+                
+                get_token ();
+            
+            } else {
+            
+                arg_is_floating = rhs_current_operand_is_floating_now ();
+                arg_bytes = arg_is_floating ? (DATA_DOUBLE & 0x1f) : DATA_PTR;
+                
+                if (arg_is_floating) {
+                    emit_load_floating_rhs_expression_now (DATA_DOUBLE & 0x1f);
+                } else {
+                    emit_load_assignment_rhs_expression_to_reg ("eax");
+                }
+                
+                if (state->ofp) {
+                
+                    if (!arg_is_floating && postfix_member_seen && postfix_member_pointer_depth == 0 && postfix_member_size > (DATA_PTR & 0x1f)) {
+                    
+                        arg_bytes = postfix_member_size;
+                        emit_push_aggregate_from_addr_reg_now ("eax", arg_bytes);
+                    
+                    } else if (!arg_is_floating && postfix_member_size > (DATA_PTR & 0x1f)) {
+                    
+                        arg_bytes = postfix_member_size;
+                        emit_push_aggregate_from_addr_reg_now ("eax", arg_bytes);
+                    
+                    } else if (arg_is_floating) {
+                    
+                        if (state->syntax & ASM_SYNTAX_INTEL) {
+                        
+                            fprintf (state->ofp, "    sub esp, 8\n");
+                            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fstp qword [esp]\n" : "    fstp qword ptr [esp]\n"));
+                        
+                        } else {
+                        
+                            fprintf (state->ofp, "    subl $8, %%esp\n");
+                            fprintf (state->ofp, "    fstpl (%%esp)\n");
+                        
+                        }
+                    
+                    } else {
+                    
+                        if (state->syntax & ASM_SYNTAX_INTEL) {
+                            fprintf (state->ofp, "    push eax\n");
+                        } else {
+                            fprintf (state->ofp, "    pushl %%eax\n");
+                        }
+                    
+                    }
+                
+                }
+            
+            }
+            
+            total_arg_bytes += arg_bytes;
+            
+            if (arg_saved_ofp) {
+            
+                fflush (arg_tmp_ofp);
+                
+                state->ofp = arg_saved_ofp;
+                new_arg_tmp_ofps = (FILE **) xrealloc (arg_tmp_ofps, sizeof (*arg_tmp_ofps) * (argc + 1));
+                
+                if (new_arg_tmp_ofps) {
+                
+                    arg_tmp_ofps = new_arg_tmp_ofps;
+                    arg_tmp_ofps[argc] = arg_tmp_ofp;
+                    arg_tmp_ofp = 0;
+                
+                }
+            
+            }
+            
+            if (arg_tmp_ofp) {
+            
+                scc_close (arg_tmp_ofp);
+                arg_tmp_ofp = 0;
+            
+            }
+            
+            argc++;
+            
+            if (!_accept (TOK_COMMA)) {
+                break;
+            }
+        
+        }
+    
+    }
+    
+    expect (TOK_RPAREN, ")");
+    
+    if (state->ofp) {
+    
+        for (i = argc - 1; i >= 0; i--) {
+        
+            if (arg_tmp_ofps && arg_tmp_ofps[i]) {
+            
+                fseek (arg_tmp_ofps[i], 0, SEEK_SET);
+                
+                while ((ch = fgetc (arg_tmp_ofps[i])) != EOF) {
+                    fputc (ch, state->ofp);
+                }
+                
+                scc_close (arg_tmp_ofps[i]);
+                arg_tmp_ofps[i] = 0;
+            
+            }
+        
+        }
+        
+        if (arg_tmp_ofps) {
+        
+            free (arg_tmp_ofps);
+            arg_tmp_ofps = 0;
+        
+        }
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            if (state->syntax & ASM_SYNTAX_NASM) {
+                fprintf (state->ofp, "    mov ecx, dword [esp + %d]\n", total_arg_bytes);
+            } else {
+                fprintf (state->ofp, "    mov ecx, dword ptr [esp + %d]\n", total_arg_bytes);
+            }
+            
+            fprintf (state->ofp, "    call ecx\n");
+            
+            if (saved_calling_convention == TOK_STDCALL) {
+                fprintf (state->ofp, "    add esp, %d\n", (DATA_PTR & 0x1f));
+            } else {
+                fprintf (state->ofp, "    add esp, %d\n", total_arg_bytes + (DATA_PTR & 0x1f));
+            }
+            
+            if (strcmp (result_reg, "eax") != 0) {
+                fprintf (state->ofp, "    mov %s, eax\n", result_reg);
+            }
+        
+        } else {
+        
+            fprintf (state->ofp, "    movl %d(%%esp), %%ecx\n", total_arg_bytes);
+            fprintf (state->ofp, "    call *%%ecx\n");
+            
+            if (saved_calling_convention == TOK_STDCALL) {
+                fprintf (state->ofp, "    addl $%d, %%esp\n", (DATA_PTR & 0x1f));
+            } else {
+                fprintf (state->ofp, "    addl $%d, %%esp\n", total_arg_bytes + (DATA_PTR & 0x1f));
+            }
+            
+            if (strcmp (result_reg, "eax") != 0) {
+                fprintf (state->ofp, "    movl %%eax, %%%s\n", result_reg);
+            }
+        
+        }
+    
+    }
+    
+    if (arg_tmp_ofps) {
+    
+        for (i = 0; i < argc; i++) {
+        
+            if (arg_tmp_ofps[i]) {
+                scc_close (arg_tmp_ofps[i]);
+            }
+        
+        }
+        
+        free (arg_tmp_ofps);
+    
+    }
+
+}
+
+static void emit_sub_esp_now (int bytes) {
+
+    if (!state->ofp || bytes <= 0) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    sub esp, %d\n", bytes);
+    } else {
+        fprintf (state->ofp, "    subl $%d, %%esp\n", bytes);
+    }
+
+}
+
+static void emit_push_pending_struct_return_address_now (int stack_arg_bytes) {
+
+    if (!state->ofp || (!pending_struct_return_lhs && !pending_struct_return_global_name && !pending_struct_return_stack_address && !pending_struct_return_stack_top)) {
+        return;
+    }
+    
+    if (pending_struct_return_stack_top) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            if (state->syntax & ASM_SYNTAX_NASM) {
+                fprintf (state->ofp, "    lea eax, [esp + %d]\n", stack_arg_bytes);
+            } else {
+                fprintf (state->ofp, "    lea eax, dword ptr [esp + %d]\n", stack_arg_bytes);
+            }
+        
+        } else {
+            fprintf (state->ofp, "    leal %d(%%esp), %%eax\n", stack_arg_bytes);
+        }
+    
+    } else if (pending_struct_return_stack_address) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            if (state->syntax & ASM_SYNTAX_NASM) {
+                fprintf (state->ofp, "    mov eax, dword [esp + %d]\n", stack_arg_bytes);
+            } else {
+                fprintf (state->ofp, "    mov eax, dword ptr [esp + %d]\n", stack_arg_bytes);
+            }
+            
+            if (pending_struct_return_stack_offset) {
+                fprintf (state->ofp, "    add eax, %d\n", pending_struct_return_stack_offset);
+            }
+        
+        } else {
+        
+            fprintf (state->ofp, "    movl %d(%%esp), %%eax\n", stack_arg_bytes);
+            
+            if (pending_struct_return_stack_offset) {
+                fprintf (state->ofp, "    addl $%d, %%eax\n", pending_struct_return_stack_offset);
+            }
+        
+        }
+    
+    } else if (pending_struct_return_lhs) {
+    
+        if (pending_struct_return_lhs->is_static && pending_struct_return_lhs->static_label) {
+            emit_load_address_to_reg_now ("eax", pending_struct_return_lhs->static_label);
+        } else {
+            emit_load_local_address_to_reg_now ("eax", pending_struct_return_lhs->offset);
+        }
+    
+    } else {
+        emit_load_address_to_reg_now ("eax", pending_struct_return_global_name);
+    }
+    
+    emit_push_reg_now ("eax");
+
+}
+
+static int current_argument_is_bare_64bit_identifier_now (void) {
+
+    struct local_symbol *sym;
+    
+    if (tok.kind != TOK_IDENT || !tok.ident || !current_argument_is_bare_identifier_now ()) {
+        return 0;
+    }
+    
+    sym = find_local_symbol (tok.ident);
+    
+    if (sym) {
+        return sym->size == (DATA_LLONG & 0x1f) && !sym->is_floating;
+    }
+    
+    if (find_global_symbol (tok.ident) >= 0) {
+        return get_global_symbol_size (tok.ident) == (DATA_LLONG & 0x1f) && !get_global_symbol_floating (tok.ident);
+    }
+    
+    return 0;
+
+}
+
+static int current_argument_starts_64bit_integer_now (void) {
+
+    if (tok.kind == TOK_CLLONG || tok.kind == TOK_CULLONG) {
+        return 1;
+    }
+    
+    return current_argument_is_bare_64bit_identifier_now ();
+
+}
+
+static void emit_call_identifier_to_reg_now (const char *name, const char *reg, const char *name_start, const char *name_caret, unsigned long name_line) {
+
+    int argc = 0;
+    int inline_index;
+    int use_inline = 0;
+    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 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;
+    
+    const char *saved_pending_struct_return_global_name = pending_struct_return_global_name;
+    const char *asm_name;
+    
+    int saved_pending_struct_return_stack_address = pending_struct_return_stack_address;
+    int saved_pending_struct_return_stack_offset = pending_struct_return_stack_offset;
+    int saved_pending_struct_return_stack_top = pending_struct_return_stack_top;
+    
+    FILE *inline_saved_ofp = 0;
+    FILE *inline_tmp_ofp = 0;
+    FILE *arg_saved_ofp = 0;
+    FILE *arg_tmp_ofp = 0;
+    FILE **arg_tmp_ofps = 0;
+    FILE **new_arg_tmp_ofps = 0;
+    
+    if (tok.kind != TOK_LPAREN) {
+        return;
+    }
+    
+    inline_index = find_inline_function (name);
+    
+    if (inline_index >= 0 &&
+        inline_functions[inline_index].usable &&
+        !inline_functions[inline_index].is_floating &&
+        !inline_functions[inline_index].expanding &&
+        (inline_functions[inline_index].body || inline_functions[inline_index].returns_void) &&
+        (!inline_functions[inline_index].body || inline_body_stack_delta (inline_functions[inline_index].body) == 0)) {
+    
+        use_inline = 1;
+        expected_inline_args = inline_functions[inline_index].param_count;
+        inline_arg_bytes = expected_inline_args * 4;
+        
+        if (state->ofp) {
+        
+            inline_tmp_ofp = scc_tmpfile ();
+            
+            if (inline_tmp_ofp) {
+            
+                inline_saved_ofp = state->ofp;
+                state->ofp = inline_tmp_ofp;
+            
+            }
+            
+            if (inline_arg_bytes > 0) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    sub esp, %d\n", inline_arg_bytes);
+                } else {
+                    fprintf (state->ofp, "    subl $%d, %%esp\n", inline_arg_bytes);
+                }
+            
+            }
+        
+        }
+    
+    }
+    
+    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) {
+    
+        for (;;) {
+        
+            arg_saved_ofp = 0;
+            arg_tmp_ofp = 0;
+            
+            /*
+             * cdecl wants the right-most argument nearest the call site and
+             * the left-most argument at [ebp + 8] in the callee.  The old
+             * code emitted each push immediately while parsing left-to-right,
+             * which reversed the parameter slots for normal calls.  Capture
+             * each non-inline argument's evaluation/push code and replay the
+             * completed argument blocks right-to-left just before CALL.
+             *
+             * Inline calls keep using the temporary argument frame below: that
+             * frame intentionally stores argument 0 at [esp], argument 1 at
+             * [esp + 4], etc., so do not reverse inline argument copies here.
+             */
+            if (!use_inline && state->ofp) {
+            
+                arg_tmp_ofp = scc_tmpfile ();
+                
+                if (arg_tmp_ofp) {
+                
+                    arg_saved_ofp = state->ofp;
+                    state->ofp = arg_tmp_ofp;
+                
+                }
+            
+            }
+            
+            postfix_member_seen = 0;
+            postfix_member_size = 0;
+            postfix_member_pointer_depth = 0;
+            postfix_member_pointed_size = 0;
+            
+            if (!use_inline && tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && find_local_symbol (tok.ident) && emit_push_aggregate_argument_now (tok.ident, find_local_symbol (tok.ident))) {
+            
+                struct local_symbol *arg_sym = find_local_symbol (tok.ident);
+                
+                arg_bytes = arg_sym ? arg_sym->size : DATA_PTR;
+                arg_is_floating = 0;
+                
+                get_token ();
+            
+            } else if (!use_inline && tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && !find_local_symbol (tok.ident) && emit_push_global_aggregate_argument_now (tok.ident)) {
+            
+                arg_bytes = get_global_symbol_size (tok.ident);
+                arg_is_floating = 0;
+                
+                get_token ();
+            
+            } else if (!use_inline && tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now () &&
+                       get_global_symbol_kind (tok.ident) == GLOBAL_SYMBOL_FUNCTION &&
+                       get_global_symbol_size (tok.ident) > (DATA_LLONG & 0x1f)) {
+            
+                char *arg_call_name = xstrdup (tok.ident);
+                
+                const char *arg_call_start = tok.start;
+                const char *arg_call_caret = tok.caret;
+                
+                unsigned long arg_call_line = get_line_number ();
+                
+                arg_bytes = get_global_symbol_size (arg_call_name);
+                arg_is_floating = 0;
+                
+                emit_sub_esp_now (arg_bytes);
+                
+                pending_struct_return_lhs = 0;
+                pending_struct_return_global_name = 0;
+                pending_struct_return_stack_address = 0;
+                pending_struct_return_stack_offset = 0;
+                pending_struct_return_stack_top = 1;
+                
+                get_token ();
+                emit_call_identifier_to_reg_now (arg_call_name, "eax", arg_call_start, arg_call_caret, arg_call_line);
+                
+                pending_struct_return_stack_top = 0;
+                free (arg_call_name);
+            
+            } else {
+            
+                arg_is_floating = rhs_current_operand_is_floating_now ();
+                arg_bytes = arg_is_floating ? (DATA_DOUBLE & 0x1f) : DATA_PTR;
+                
+                if (!use_inline && get_global_symbol_has_prototype (name) &&
+                    argc < get_global_symbol_param_count (name) &&
+                    get_global_symbol_param_size (name, argc) == (DATA_LLONG & 0x1f) &&
+                    get_global_symbol_param_pointer_depth (name, argc) == 0 &&
+                    !get_global_symbol_param_floating (name, argc)) {
+                
+                    arg_is_floating = 0;
+                    arg_bytes = DATA_LLONG & 0x1f;
+                    
+                    emit_load_assignment_rhs_expression_to_pair ("eax", "edx", get_global_symbol_param_unsigned (name, argc));
+
+                } else if (!use_inline && get_global_symbol_has_prototype (name) && get_global_symbol_is_variadic (name) && argc >= get_global_symbol_param_count (name) && current_argument_starts_64bit_integer_now ()) {
+                
+                    arg_is_floating = 0;
+                    arg_bytes = DATA_LLONG & 0x1f;
+                        
+                    emit_load_assignment_rhs_expression_to_pair ("eax", "edx", rhs_current_operand_is_unsigned_now ());
+                
+                } else if (arg_is_floating) {
+                    emit_load_floating_rhs_expression_now (DATA_DOUBLE & 0x1f);
+                } else {
+                    emit_load_assignment_rhs_expression_to_reg ("eax");
+                }
+                
+                if (state->ofp) {
+                
+                    if (!use_inline && !arg_is_floating && arg_bytes == (DATA_LLONG & 0x1f)) {
+                    
+                        emit_push_reg_now ("edx");
+                        emit_push_reg_now ("eax");
+                    
+                    } else if (!use_inline && !arg_is_floating && postfix_member_seen && postfix_member_pointer_depth == 0 && postfix_member_size > (DATA_PTR & 0x1f)) {
+                    
+                        arg_bytes = postfix_member_size;
+                        emit_push_aggregate_from_addr_reg_now ("eax", arg_bytes);
+                    
+                    } else if (!use_inline && !arg_is_floating && postfix_member_size > (DATA_PTR & 0x1f)) {
+                    
+                        arg_bytes = postfix_member_size;
+                        emit_push_aggregate_from_addr_reg_now ("eax", arg_bytes);
+                    
+                    } else if (use_inline) {
+                    
+                        if (argc < expected_inline_args) {
+                        
+                            if (state->syntax & ASM_SYNTAX_INTEL) {
+                                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword [esp + %d], eax\n" : "    mov dword ptr [esp + %d], eax\n"), argc * 4);
+                            } else {
+                                fprintf (state->ofp, "    movl %%eax, %d(%%esp)\n", argc * 4);
+                            }
+                        
+                        }
+                    
+                    } else if (arg_is_floating) {
+                    
+                        if (state->syntax & ASM_SYNTAX_INTEL) {
+                        
+                            fprintf (state->ofp, "    sub esp, 8\n");
+                            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fstp qword [esp]\n" : "    fstp qword ptr [esp]\n"));
+                        
+                        } else {
+                        
+                            fprintf (state->ofp, "    subl $8, %%esp\n");
+                            fprintf (state->ofp, "    fstpl (%%esp)\n");
+                        
+                        }
+                    
+                    } else {
+                    
+                        if (state->syntax & ASM_SYNTAX_INTEL) {
+                            fprintf (state->ofp, "    push eax\n");
+                        } else {
+                            fprintf (state->ofp, "    pushl %%eax\n");
+                        }
+                    
+                    }
+                
+                }
+            
+            }
+            
+            if (!use_inline) {
+                total_arg_bytes += arg_bytes;
+            }
+            
+            if (arg_saved_ofp) {
+            
+                fflush (arg_tmp_ofp);
+                state->ofp = arg_saved_ofp;
+                
+                new_arg_tmp_ofps = (FILE **) xrealloc (arg_tmp_ofps, sizeof (*arg_tmp_ofps) * (argc + 1));
+                
+                if (new_arg_tmp_ofps) {
+                
+                    arg_tmp_ofps = new_arg_tmp_ofps;
+                    
+                    arg_tmp_ofps[argc] = arg_tmp_ofp;
+                    arg_tmp_ofp = 0;
+                
+                }
+
+            }
+            
+            if (arg_tmp_ofp) {
+            
+                scc_close (arg_tmp_ofp);
+                arg_tmp_ofp = 0;
+            
+            }
+            
+            argc++;
+            
+            if (!_accept (TOK_COMMA)) {
+                break;
+            }
+        
+        }
+    
+    }
+    
+    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);
+    }
+    
+    if (use_inline) {
+    
+        if (argc == expected_inline_args && emit_inline_call_if_possible (name, argc, reg)) {
+        
+            if (state->ofp && inline_arg_bytes > 0) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    add esp, %d\n", inline_arg_bytes);
+                } else {
+                    fprintf (state->ofp, "    addl $%d, %%esp\n", inline_arg_bytes);
+                }
+            
+            }
+            
+            /*
+             * The peephole inline optimiser currently understands the
+             * single-argument case well, but its stack-slot liveness pass is
+             * too aggressive for multi-argument inline calls.  It can fold
+             * constants correctly in simple examples, but it may also remove
+             * the temporary argument frame and leave confusing label-only
+             * fragments.  Keep multi-argument inline expansion conservative:
+             * emit the substituted inline body exactly as generated, with the
+             * argument copies still present.
+             */
+            finish_inline_buffer (&inline_tmp_ofp, &inline_saved_ofp, expected_inline_args <= 1);
+            return;
+        
+        }
+        
+        if (state->ofp && inline_arg_bytes > 0) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    add esp, %d\n", inline_arg_bytes);
+            } else {
+                fprintf (state->ofp, "    addl $%d, %%esp\n", inline_arg_bytes);
+            }
+        
+        }
+        
+        finish_inline_buffer (&inline_tmp_ofp, &inline_saved_ofp, 0);
+        return;
+    
+    }
+    
+    if (emit_inline_call_if_possible (name, argc, reg)) {
+    
+        if (arg_tmp_ofps) {
+        
+            for (i = 0; i < argc; i++) {
+            
+                if (arg_tmp_ofps[i]) {
+                    scc_close (arg_tmp_ofps[i]);
+                }
+            
+            }
+            
+            free (arg_tmp_ofps);
+            arg_tmp_ofps = 0;
+        
+        }
+        
+        return;
+    
+    }
+    
+    call_sym = find_local_symbol (name);
+    
+    if (!call_sym) {
+    
+        if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_OBJECT) {
+            emit_extern_reference_symbol (name, DATA_PTR);
+        } else {
+            emit_extern_symbol (name, DATA_PTR, 1);
+        }
+        
+        asm_name = asm_global_symbol_name (name);
+    
+    } else {
+        asm_name = 0;
+    }
+    
+    if (state->ofp) {
+    
+        if (arg_tmp_ofps) {
+        
+            for (i = argc - 1; i >= 0; i--) {
+            
+                if (arg_tmp_ofps[i]) {
+                
+                    fseek (arg_tmp_ofps[i], 0, SEEK_SET);
+                    
+                    while ((ch = fgetc (arg_tmp_ofps[i])) != EOF) {
+                        fputc (ch, state->ofp);
+                    }
+                    
+                    scc_close (arg_tmp_ofps[i]);
+                    arg_tmp_ofps[i] = 0;
+                
+                }
+            
+            }
+            
+            free (arg_tmp_ofps);
+            arg_tmp_ofps = 0;
+        
+        }
+        
+        if (saved_pending_struct_return_lhs || saved_pending_struct_return_global_name ||
+            saved_pending_struct_return_stack_address || saved_pending_struct_return_stack_top) {
+        
+            pending_struct_return_lhs = saved_pending_struct_return_lhs;
+            pending_struct_return_global_name = saved_pending_struct_return_global_name;
+            pending_struct_return_stack_address = saved_pending_struct_return_stack_address;
+            pending_struct_return_stack_offset = saved_pending_struct_return_stack_offset;
+            pending_struct_return_stack_top = saved_pending_struct_return_stack_top;
+            
+            emit_push_pending_struct_return_address_now (total_arg_bytes);
+            total_arg_bytes += DATA_PTR & 0x1f;
+        
+        }
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            if (call_sym) {
+            
+                emit_load_local_to_reg ("ecx", call_sym->offset, DATA_PTR);
+                fprintf (state->ofp, "    call ecx\n");
+            
+            } else if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_OBJECT) {
+            
+                emit_load_global_to_reg ("ecx", name, DATA_PTR);
+                fprintf (state->ofp, "    call ecx\n");
+            
+            } else if (get_global_symbol_dllimport (name)) {
+            
+                remember_global_symbol_import_call_stack_bytes (name, total_arg_bytes);
+                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    call dword [%s]\n" : "    call dword ptr %s\n"), asm_global_import_symbol_name (name));
+            
+            } else {
+                fprintf (state->ofp, "    call %s\n", asm_name);
+            }
+            
+            if (total_arg_bytes > 0 && get_global_symbol_calling_convention (name) != TOK_STDCALL) {
+                fprintf (state->ofp, "    add esp, %d\n", total_arg_bytes);
+            }
+            
+            if (strcmp (reg, "eax") != 0) {
+                fprintf (state->ofp, "    mov %s, eax\n", reg);
+            }
+        
+        } else {
+        
+            if (call_sym) {
+            
+                emit_load_local_to_reg ("ecx", call_sym->offset, DATA_PTR);
+                fprintf (state->ofp, "    call *%%ecx\n");
+            
+            } else if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_OBJECT) {
+            
+                emit_load_global_to_reg ("ecx", name, DATA_PTR);
+                fprintf (state->ofp, "    call *%%ecx\n");
+            
+            } else if (get_global_symbol_dllimport (name)) {
+            
+                remember_global_symbol_import_call_stack_bytes (name, total_arg_bytes);
+                fprintf (state->ofp, "    call *%s\n", asm_global_import_symbol_name (name));
+            
+            } else {
+                fprintf (state->ofp, "    call %s\n", asm_name);
+            }
+            
+            if (total_arg_bytes > 0 && get_global_symbol_calling_convention (name) != TOK_STDCALL) {
+                fprintf (state->ofp, "    addl $%d, %%esp\n", total_arg_bytes);
+            }
+            
+            if (strcmp (reg, "eax") != 0) {
+                fprintf (state->ofp, "    movl %%eax, %%%s\n", reg);
+            }
+        
+        }
+    
+    }
+    
+    set_rhs_last_pointer_info (get_global_symbol_pointer_depth (name), get_global_symbol_pointed_size (name));
+    
+    pending_struct_return_lhs = 0;
+    pending_struct_return_global_name = 0;
+    pending_struct_return_stack_address = 0;
+    pending_struct_return_stack_offset = 0;
+    pending_struct_return_stack_top = 0;
+    
+    if (arg_tmp_ofps) {
+    
+        for (i = 0; i < argc; i++) {
+        
+            if (arg_tmp_ofps[i]) {
+                scc_close (arg_tmp_ofps[i]);
+            }
+        
+        }
+        
+        free (arg_tmp_ofps);
+        arg_tmp_ofps = 0;
+    
+    }
+
+}
+
+static void emit_statement_label (int label);
+static void emit_statement_jump (int label);
+
+#define     MAX_GOTO_LABELS        256
+#define     MAX_GOTO_REFS          512
+
+struct goto_label_entry {
+
+    char *name;
+    
+    int label;
+    int defined;
+    int referenced;
+
+    long defined_stack_size;
+    unsigned long line;
+    
+    const char *start;
+    const char *caret;
+
+};
+
+static struct goto_label_entry goto_labels[MAX_GOTO_LABELS];
+static int goto_label_count = 0;
+
+struct goto_ref_entry {
+
+    int label_index;
+    int ref_label;
+    
+    long stack_size;
+
+};
+
+static struct goto_ref_entry goto_refs[MAX_GOTO_REFS];
+static int goto_ref_count = 0;
+
+static int current_break_label = -1;
+static int current_continue_label = -1;
+
+static long current_break_cleanup_base = 0;
+static long current_continue_cleanup_base = 0;
+
+#define     MAX_SWITCH_CASES        256
+
+struct switch_case_entry {
+
+    long value;
+    int label;
+
+};
+
+struct switch_context {
+
+    struct switch_case_entry cases[MAX_SWITCH_CASES];
+    int case_count;
+    int default_label;
+    int break_label;
+
+};
+
+static struct switch_context *current_switch_context = 0;
+static int statement_ends_control_flow = 0;
+
+static void reset_goto_labels (void) {
+
+    int i;
+    
+    for (i = 0; i < goto_label_count; i++) {
+    
+        if (goto_labels[i].name) {
+            free (goto_labels[i].name);
+        }
+        
+        goto_labels[i].name = 0;
+        goto_labels[i].label = 0;
+        goto_labels[i].defined = 0;
+        goto_labels[i].referenced = 0;
+        goto_labels[i].defined_stack_size = 0;
+        goto_labels[i].line = 0;
+        goto_labels[i].start = 0;
+        goto_labels[i].caret = 0;
+    
+    }
+    
+    goto_label_count = 0;
+    goto_ref_count = 0;
+
+}
+
+static int find_goto_label (const char *name) {
+
+    int i;
+    
+    for (i = 0; i < goto_label_count; i++) {
+    
+        if (goto_labels[i].name && strcmp (goto_labels[i].name, name) == 0) {
+            return i;
+        }
+    
+    }
+    
+    return -1;
+
+}
+
+static int get_goto_label (const char *name, unsigned long line, const char *start, const char *caret) {
+
+    int i = find_goto_label (name);
+    
+    if (i >= 0) {
+        return i;
+    }
+    
+    if (goto_label_count >= MAX_GOTO_LABELS) {
+    
+        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "too many goto labels");
+        return -1;
+    
+    }
+    
+    i = goto_label_count++;
+    
+    goto_labels[i].name = xstrdup (name);
+    goto_labels[i].label = anon_label++;
+    goto_labels[i].defined = 0;
+    goto_labels[i].referenced = 0;
+    goto_labels[i].defined_stack_size = 0;
+    goto_labels[i].line = line;
+    goto_labels[i].start = start;
+    goto_labels[i].caret = caret;
+    
+    return i;
+
+}
+
+static void define_goto_label (const char *name, unsigned long line, const char *start, const char *caret) {
+
+    int i = get_goto_label (name, line, start, caret);
+    
+    if (i < 0) {
+        return;
+    }
+    
+    if (goto_labels[i].defined) {
+    
+        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "duplicate label '%s'", name);
+        return;
+    
+    }
+    
+    goto_labels[i].defined = 1;
+    goto_labels[i].defined_stack_size = current_local_stack_size;
+    
+    /**
+     * A C label marks the next statement.  If the previous statement was a
+     * return, the compiler may have deferred the jump to the common return
+     * label so it can avoid redundant jumps.  Flush it before emitting the
+     * user label, otherwise the user label will point at the deferred return
+     * jump instead of the labelled statement.
+     */
+    if (pending_return_jump) {
+        emit_pending_return_jump ();
+    }
+    
+    emit_statement_label (goto_labels[i].label);
+
+}
+
+static void reference_goto_label (const char *name, unsigned long line, const char *start, const char *caret) {
+
+    int i = get_goto_label (name, line, start, caret);
+    
+    if (i < 0) {
+        return;
+    }
+    
+    goto_labels[i].referenced = 1;
+    
+    /*
+     * If this is a forward goto, do not jump directly to the final C
+     * label.  The target may be after automatic declarations in an inner
+     * block.  Because SCC emits stack allocation when those declarations are
+     * parsed, a direct branch can bypass the allocation and then use invalid
+     * EBP-relative locals.  Emit a per-reference trampoline after the function
+     * epilogue once the target stack depth is known.
+     */
+    if (!goto_labels[i].defined) {
+    
+        if (goto_ref_count < MAX_GOTO_REFS) {
+        
+            int ref_label = anon_label++;
+            
+            goto_refs[goto_ref_count].label_index = i;
+            goto_refs[goto_ref_count].ref_label = ref_label;
+            goto_refs[goto_ref_count].stack_size = current_local_stack_size;
+            goto_ref_count++;
+            
+            emit_statement_jump (ref_label);
+            return;
+        
+        }
+    
+    }
+    
+    emit_statement_jump (goto_labels[i].label);
+
+}
+
+static void check_goto_labels (void) {
+
+    int i;
+    
+    for (i = 0; i < goto_label_count; i++) {
+    
+        if (goto_labels[i].referenced && !goto_labels[i].defined) {
+            report_line_at (get_filename (), goto_labels[i].line, REPORT_ERROR, goto_labels[i].start, goto_labels[i].caret, "undefined label '%s'", goto_labels[i].name);
+        }
+    
+    }
+
+}
+
+static void emit_goto_trampolines (void) {
+
+    int i;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    for (i = 0; i < goto_ref_count; i++) {
+    
+        int label_index = goto_refs[i].label_index;
+        long delta;
+        
+        if (label_index < 0 || label_index >= goto_label_count) {
+            continue;
+        }
+        
+        if (!goto_labels[label_index].defined) {
+            continue;
+        }
+        
+        emit_statement_label_raw (goto_refs[i].ref_label);
+        delta = goto_labels[label_index].defined_stack_size - goto_refs[i].stack_size;
+        
+        /*
+         * 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);
+    
+    }
+
+}
+
+static void queue_pending_statement_label (int label) {
+
+    if (label < 0) {
+        return;
+    }
+    
+    if (pending_statement_label_count >= MAX_PENDING_STATEMENT_LABELS) {
+        flush_pending_statement_labels ();
+    }
+    
+    if (pending_statement_label_count < MAX_PENDING_STATEMENT_LABELS) {
+        pending_statement_labels[pending_statement_label_count++] = label;
+    } else {
+        emit_statement_label (label);
+    }
+
+}
+
+static void add_switch_case_label (long value, unsigned long line, const char *start, const char *caret) {
+
+    int i;
+    
+    if (!current_switch_context) {
+    
+        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "case label not within a switch statement");
+        return;
+    
+    }
+    
+    for (i = 0; i < current_switch_context->case_count; i++) {
+    
+        if (current_switch_context->cases[i].value == value) {
+        
+            report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "duplicate case value");
+            return;
+        
+        }
+    
+    }
+    
+    if (current_switch_context->case_count >= MAX_SWITCH_CASES) {
+    
+        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "too many case labels in switch statement");
+        return;
+    
+    }
+    
+    current_switch_context->cases[current_switch_context->case_count].value = value;
+    current_switch_context->cases[current_switch_context->case_count].label = anon_label++;
+    
+    queue_pending_statement_label (current_switch_context->cases[current_switch_context->case_count].label);
+    current_switch_context->case_count++;
+
+}
+
+static void set_switch_default_label (unsigned long line, const char *start, const char *caret) {
+
+    if (!current_switch_context) {
+    
+        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "default label not within a switch statement");
+        return;
+    
+    }
+    
+    if (current_switch_context->default_label >= 0) {
+    
+        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "duplicate default label");
+        return;
+    
+    }
+    
+    current_switch_context->default_label = anon_label++;
+    queue_pending_statement_label (current_switch_context->default_label);
+
+}
+
+static void emit_switch_dispatch (struct switch_context *sw) {
+
+    int i;
+    int target;
+    
+    if (!state->ofp || !sw) {
+        return;
+    }
+    
+    for (i = 0; i < sw->case_count; i++) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, "    cmp eax, %ld\n", sw->cases[i].value);
+            
+            if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+                fprintf (state->ofp, "    je L%d\n", sw->cases[i].label);
+            } else {
+                fprintf (state->ofp, "    je .L%d\n", sw->cases[i].label);
+            }
+        
+        } else {
+        
+            fprintf (state->ofp, "    cmpl $%ld, %%eax\n", sw->cases[i].value);
+            fprintf (state->ofp, "    je .L%d\n", sw->cases[i].label);
+        
+        }
+    
+    }
+    
+    target = (sw->default_label >= 0) ? sw->default_label : sw->break_label;
+    emit_statement_jump (target);
+
+}
+
+static void parse_switch_statement (void) {
+
+    struct switch_context sw;
+    struct switch_context *old_switch_context;
+    
+    int old_break_label;
+    int old_continue_label;
+    
+    long old_break_cleanup_base;
+    long old_continue_cleanup_base;
+    
+    int saved_ends_control_flow;
+    
+    FILE *saved_ofp;
+    FILE *body_tmp = 0;
+    
+    char *body_text = 0;
+    int body_pending_return_jump = 0;
+    
+    sw.case_count = 0;
+    sw.default_label = -1;
+    sw.break_label = anon_label++;
+    
+    get_token ();
+    expect (TOK_LPAREN, "(");
+    
+    emit_load_assignment_rhs_expression_to_reg ("eax");
+    
+    if (tok.kind != TOK_RPAREN) {
+        skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+    }
+    
+    expect (TOK_RPAREN, ")");
+    
+    old_switch_context = current_switch_context;
+    old_break_label = current_break_label;
+    old_continue_label = current_continue_label;
+    old_break_cleanup_base = current_break_cleanup_base;
+    old_continue_cleanup_base = current_continue_cleanup_base;
+    
+    current_switch_context = &sw;
+    current_break_label = sw.break_label;
+    current_break_cleanup_base = current_block_cleanup_bytes;
+    
+    saved_ofp = state->ofp;
+    
+    if (saved_ofp) {
+    
+        body_tmp = scc_tmpfile ();
+        
+        if (body_tmp) {
+            state->ofp = body_tmp;
+        }
+    
+    }
+    
+    parse_statement ();
+    saved_ends_control_flow = statement_ends_control_flow;
+    
+    if (body_tmp) {
+    
+        body_text = read_tmp_file_text (body_tmp);
+        
+        scc_close (body_tmp);
+        body_tmp = 0;
+        
+        state->ofp = saved_ofp;
+        
+        body_pending_return_jump = pending_return_jump;
+        pending_return_jump = 0;
+        
+        emit_switch_dispatch (&sw);
+        
+        if (body_text) {
+        
+            fputs (body_text, state->ofp);
+            free (body_text);
+        
+        }
+        
+        pending_return_jump = body_pending_return_jump;
+    
+    } else {
+        state->ofp = saved_ofp;
+    }
+    
+    emit_statement_label (sw.break_label);
+    
+    current_switch_context = old_switch_context;
+    current_break_label = old_break_label;
+    current_continue_label = old_continue_label;
+    current_break_cleanup_base = old_break_cleanup_base;
+    current_continue_cleanup_base = old_continue_cleanup_base;
+    
+    /*
+     * A break inside the switch only leaves the switch.  Do not propagate the
+     * break statement's statement_ends_control_flow flag to the enclosing
+     * statement, otherwise code like:
+     *
+     *     if (x) { switch (y) { case 1: break; } } else { ... }
+     *
+     * is compiled without the jump over the else block and the true branch
+     * falls through into the else body.
+     */
+    (void)saved_ends_control_flow;
+    statement_ends_control_flow = 0;
+
+}
+
+static int is_value_compare_operator (enum token_kind k) {
+
+    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 const char *value_compare_set_mnemonic (enum token_kind op, int is_unsigned) {
+
+    switch (op) {
+    
+        case TOK_LESS:
+        
+            return is_unsigned ? "setb"  : "setl";
+        
+        case TOK_LTEQ:
+        
+            return is_unsigned ? "setbe" : "setle";
+        
+        case TOK_GREATER:
+        
+            return is_unsigned ? "seta"  : "setg";
+        
+        case TOK_GTEQ:
+        
+            return is_unsigned ? "setae" : "setge";
+        
+        case TOK_EQEQ:
+        
+            return "sete";
+        
+        case TOK_NOTEQ:
+        
+            return "setne";
+        
+        default:
+        
+            return "setne";
+    
+    }
+
+}
+
+static void emit_compare_eax_edx_to_reg (enum token_kind op, const char *reg, int is_unsigned) {
+
+    const char *setcc;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    setcc = value_compare_set_mnemonic (op, is_unsigned);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    cmp eax, edx\n");
+        fprintf (state->ofp, "    %s al\n", setcc);
+        fprintf (state->ofp, "    movzx eax, al\n");
+        
+        if (strcmp (reg, "eax") != 0) {
+            fprintf (state->ofp, "    mov %s, eax\n", reg);
+        }
+    
+    } else {
+    
+        fprintf (state->ofp, "    cmpl %%edx, %%eax\n");
+        fprintf (state->ofp, "    %s %%al\n", setcc);
+        fprintf (state->ofp, "    movzbl %%al, %%eax\n");
+        
+        if (strcmp (reg, "eax") != 0) {
+            fprintf (state->ofp, "    movl %%eax, %%%s\n", reg);
+        }
+    
+    }
+
+}
+
+static int rhs_current_operand_is_unsigned_now (void);
+
+static int source_lhs_has_char_pointer_cast_before_now (const char *p) {
+
+    const char *q;
+    int limit = 160;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    q = p;
+    
+    while (limit-- > 0 && q > tok.start) {
+    
+        q--;
+        
+        if (*q != '(') {
+            continue;
+        }
+        
+        if ((strncmp (q, "(char", 5) == 0 || strncmp (q, "(unsigned char", 14) == 0 || strncmp (q, "(signed char", 12) == 0)
+            && strchr (q, '*') && strchr (q, ')') && strchr (q, '*') < p && strchr (q, ')') < p) {
+            return 1;
+        }
+        
+        if (*q == ';' || *q == ',' || *q == '\n') {
+            break;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int arithmetic_operator_precedence_now (enum token_kind op) {
+
+    if (op == TOK_PIPE) {
+        return 1;
+    }
+    
+    if (op == TOK_CARET) {
+        return 2;
+    }
+    
+    if (op == TOK_AMPER) {
+        return 3;
+    }
+    
+    if (op == TOK_LSH || op == TOK_RSH) {
+        return 4;
+    }
+    
+    if (op == TOK_PLUS || op == TOK_MINUS) {
+        return 5;
+    }
+    
+    if (op == TOK_STAR || op == TOK_BSLASH || op == TOK_MOD) {
+        return 6;
+    }
+    
+    return 0;
+
+}
+
+static int emit_load_assignment_binary_expression_prec_to_reg (const char *reg, int min_prec) {
+
+    int is_unsigned;
+    int expr_pointer_depth;
+    int expr_pointed_size;
+    
+    is_unsigned = rhs_current_operand_is_unsigned_now ();
+    emit_load_assignment_rhs_to_reg (reg);
+    
+    /*
+     * Some statement-condition paths can leave a postfix member chain after
+     * the primary operand, e.g. inside parenthesized logical RHS terms such as
+     *     && (reg->type.dword || reg->type.debug)
+     * Consume that postfix here before the binary/logical expression parser
+     * decides whether the operand is complete.  Otherwise the enclosing
+     * parenthesized-expression code sees the still-pending "->"/"." token and
+     * reports a false "expected )".
+     */
+    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+        emit_apply_postfix_member_access_to_reg_now (reg);
+    }
+    
+    /*
+     * The postfix member helper deliberately leaves aggregates and 64-bit
+     * scalar members as an address because the pair/aggregate paths may need
+     * the full object.  This single-register expression path, however, only
+     * has EAX/EDX-style 32-bit arithmetic available.  When such a member is
+     * used inside ordinary arithmetic/comparison code (for example the
+     * CHECK_READ macro in pdld with address_type fields), load the low word
+     * from the member address instead of adding the member address itself.
+     */
+    if (postfix_member_seen
+        && postfix_member_pointer_depth == 0
+        && postfix_member_size == (DATA_LLONG & 0x1f)
+        && !postfix_member_is_floating) {
+    
+        emit_load_deref_reg_now (reg, DATA_INT & 0x1f);
+        postfix_member_size = DATA_INT & 0x1f;
+    
+    }
+    
+    if (postfix_member_seen && postfix_member_is_unsigned) {
+        is_unsigned = 1;
+    }
+    
+    expr_pointer_depth = rhs_last_pointer_depth;
+    expr_pointed_size = rhs_last_pointed_size;
+    
+    while (is_arithmetic_binary_operator (tok.kind) && arithmetic_operator_precedence_now (tok.kind) >= min_prec) {
+        
+        enum token_kind op;
+        
+        int prec;
+        int rhs_is_unsigned;
+        int lhs_pointer_depth;
+        int lhs_pointed_size;
+        int rhs_pointer_depth;
+        int rhs_pointed_size;
+        int scale_rhs = 0;
+        int scale_lhs = 0;
+        
+        op = tok.kind;
+        prec = arithmetic_operator_precedence_now (op);
+        
+        lhs_pointer_depth = expr_pointer_depth;
+        lhs_pointed_size = expr_pointed_size;
+        
+        if ((op == TOK_PLUS || op == TOK_MINUS) && lhs_pointer_depth > 0 &&
+            source_lhs_has_char_pointer_cast_before_now (tok.caret)) {
+            lhs_pointed_size = DATA_CHAR & 0x1f;
+        }
+        
+        get_token ();
+        rhs_is_unsigned = rhs_current_operand_is_unsigned_now ();
+        
+        if (rhs_is_unsigned) {
+            is_unsigned = 1;
+        }
+        
+        if (strcmp (reg, "eax") != 0 && state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    mov eax, %s\n", reg);
+            } else {
+                fprintf (state->ofp, "    movl %%%s, %%eax\n", reg);
+            }
+        
+        }
+        
+        emit_push_reg_now ("eax");
+        rhs_is_unsigned = emit_load_assignment_binary_expression_prec_to_reg ("edx", prec + 1);
+        
+        if (rhs_is_unsigned) {
+            is_unsigned = 1;
+        }
+        
+        rhs_pointer_depth = rhs_last_pointer_depth;
+        rhs_pointed_size = rhs_last_pointed_size;
+        
+        if ((op == TOK_PLUS || op == TOK_MINUS) && lhs_pointer_depth > 0 && rhs_pointer_depth == 0) {
+            scale_rhs = index_step_size (lhs_pointed_size);
+        } else if (op == TOK_PLUS && lhs_pointer_depth == 0 && rhs_pointer_depth > 0) {
+            scale_lhs = index_step_size (rhs_pointed_size);
+        }
+        
+        if (scale_rhs > 1) {
+            emit_scale_reg_by_const_now ("edx", scale_rhs);
+        }
+        
+        emit_pop_reg_now ("eax");
+        
+        if (scale_lhs > 1) {
+            emit_scale_reg_by_const_now ("eax", scale_lhs);
+        }
+        
+        emit_assignment_binary_op (op, is_unsigned);
+        
+        if (op == TOK_MINUS && lhs_pointer_depth > 0 && rhs_pointer_depth > 0 && index_step_size (lhs_pointed_size) > 1) {
+            emit_divide_eax_by_const_now (index_step_size (lhs_pointed_size));
+        }
+        
+        if (op == TOK_PLUS && lhs_pointer_depth == 0 && rhs_pointer_depth > 0) {
+        
+            expr_pointer_depth = rhs_pointer_depth;
+            expr_pointed_size = rhs_pointed_size;
+        
+        } else if (op == TOK_MINUS && lhs_pointer_depth > 0 && rhs_pointer_depth > 0) {
+        
+            expr_pointer_depth = 0;
+            expr_pointed_size = 0;
+        
+        } else if (op != TOK_PLUS && op != TOK_MINUS) {
+        
+            expr_pointer_depth = 0;
+            expr_pointed_size = 0;
+        
+        }
+        
+        if (strcmp (reg, "eax") != 0 && state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    mov %s, eax\n", reg);
+            } else {
+                fprintf (state->ofp, "    movl %%eax, %%%s\n", reg);
+            }
+        
+        }
+    
+    }
+    
+    set_rhs_last_pointer_info (expr_pointer_depth, expr_pointed_size);
+    return is_unsigned;
+
+}
+
+static void emit_load_assignment_binary_expression_to_reg (const char *reg) {
+
+    if (current_integer_expr_is_foldable_now ()) {
+    
+        int64_s v = const64_from_current_foldable_expr ();
+        emit_load_const32_to_reg_now (reg, v);
+        
+        return;
+    
+    }
+    
+    emit_load_assignment_binary_expression_prec_to_reg (reg, 1);
+
+}
+
+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 ();
+    
+    if (emit_load_assignment_binary_expression_prec_to_reg (reg, 1)) {
+        is_unsigned = 1;
+    }
+    
+    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) {
+                fprintf (state->ofp, "    mov eax, %s\n", reg);
+            } else {
+                fprintf (state->ofp, "    movl %%%s, %%eax\n", 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;
+        }
+        
+        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;
+        }
+        
+        emit_pop_reg_now ("eax");
+        emit_compare_eax_edx_to_reg (op, reg, is_unsigned);
+    
+    }
+
+}
+
+static void emit_test_reg_jump_zero_now (const char *reg, int label) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    test %s, %s\n", reg, reg);
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jz L%d\n" : "    jz .L%d\n"), label);
+    
+    } else {
+    
+        fprintf (state->ofp, "    testl %%%s, %%%s\n", reg, reg);
+        fprintf (state->ofp, "    jz .L%d\n", label);
+    
+    }
+
+}
+
+static void emit_test_reg_jump_nonzero_now (const char *reg, int label) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    test %s, %s\n", reg, reg);
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), label);
+    
+    } else {
+    
+        fprintf (state->ofp, "    testl %%%s, %%%s\n", reg, reg);
+        fprintf (state->ofp, "    jnz .L%d\n", label);
+    
+    }
+
+}
+
+static void emit_mov_imm_to_reg_now (const char *reg, long value) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    mov %s, %ld\n", reg, value);
+    } else {
+        fprintf (state->ofp, "    movl $%ld, %%%s\n", value, reg);
+    }
+
+}
+
+static void emit_floating_stack_to_int_reg_now (const char *reg) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    /*
+     * C requires floating-to-integer conversion to discard the fractional
+     * part.  x87 fistp uses the current FPU rounding mode, which is normally
+     * round-to-nearest, so values such as 0.5000000001 become 1 instead of 0.
+     * Temporarily switch the x87 control word to truncate for this conversion.
+     */
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    sub esp, 8\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fnstcw word [esp + 4]\n" : "    fnstcw word ptr [esp + 4]\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov ax, word [esp + 4]\n" : "    mov ax, word ptr [esp + 4]\n");
+        fprintf (state->ofp, "    or ah, 12\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov word [esp + 6], ax\n" : "    mov word ptr [esp + 6], ax\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fldcw word [esp + 6]\n" : "    fldcw word ptr [esp + 6]\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fistp dword [esp]\n" : "    fistp dword ptr [esp]\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fldcw word [esp + 4]\n" : "    fldcw word ptr [esp + 4]\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [esp]\n" : "    mov %s, dword ptr [esp]\n", reg);
+        fprintf (state->ofp, "    add esp, 8\n");
+    
+    } else {
+    
+        fprintf (state->ofp, "    subl $8, %%esp\n");
+        fprintf (state->ofp, "    fnstcw 4(%%esp)\n");
+        fprintf (state->ofp, "    movw 4(%%esp), %%ax\n");
+        fprintf (state->ofp, "    orb $12, %%ah\n");
+        fprintf (state->ofp, "    movw %%ax, 6(%%esp)\n");
+        fprintf (state->ofp, "    fldcw 6(%%esp)\n");
+        fprintf (state->ofp, "    fistpl (%%esp)\n");
+        fprintf (state->ofp, "    fldcw 4(%%esp)\n");
+        fprintf (state->ofp, "    movl (%%esp), %%%s\n", reg);
+        fprintf (state->ofp, "    addl $8, %%esp\n");
+    
+    }
+
+}
+
+static void emit_floating_stack_to_int_pair_now (const char *lo, const char *hi) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    sub esp, 12\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fnstcw word [esp + 8]\n" : "    fnstcw word ptr [esp + 8]\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov ax, word [esp + 8]\n" : "    mov ax, word ptr [esp + 8]\n");
+        fprintf (state->ofp, "    or ah, 12\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov word [esp + 10], ax\n" : "    mov word ptr [esp + 10], ax\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fldcw word [esp + 10]\n" : "    fldcw word ptr [esp + 10]\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fistp qword [esp]\n" : "    fistp qword ptr [esp]\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fldcw word [esp + 8]\n" : "    fldcw word ptr [esp + 8]\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [esp]\n" : "    mov %s, dword ptr [esp]\n", lo);
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [esp + 4]\n" : "    mov %s, dword ptr [esp + 4]\n", hi);
+        fprintf (state->ofp, "    add esp, 12\n");
+    
+    } else {
+    
+        fprintf (state->ofp, "    subl $12, %%esp\n");
+        fprintf (state->ofp, "    fnstcw 8(%%esp)\n");
+        fprintf (state->ofp, "    movw 8(%%esp), %%ax\n");
+        fprintf (state->ofp, "    orb $12, %%ah\n");
+        fprintf (state->ofp, "    movw %%ax, 10(%%esp)\n");
+        fprintf (state->ofp, "    fldcw 10(%%esp)\n");
+        fprintf (state->ofp, "    fistpll (%%esp)\n");
+        fprintf (state->ofp, "    fldcw 8(%%esp)\n");
+        fprintf (state->ofp, "    movl (%%esp), %%%s\n", lo);
+        fprintf (state->ofp, "    movl 4(%%esp), %%%s\n", hi);
+        fprintf (state->ofp, "    addl $12, %%esp\n");
+    
+    }
+
+}
+
+static void emit_integer_pair_to_floating_stack_now (const char *lo, const char *hi, int size) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if ((size & 0x1f) == (DATA_LLONG & 0x1f)) {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            fprintf (state->ofp, "    sub esp, 8\n");
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov dword [esp], %s\n" : "    mov dword ptr [esp], %s\n", lo);
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov dword [esp + 4], %s\n" : "    mov dword ptr [esp + 4], %s\n", hi);
+            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fild qword [esp]\n" : "    fild qword ptr [esp]\n");
+            fprintf (state->ofp, "    add esp, 8\n");
+        
+        } else {
+        
+            fprintf (state->ofp, "    subl $8, %%esp\n");
+            fprintf (state->ofp, "    movl %%%s, (%%esp)\n", lo);
+            fprintf (state->ofp, "    movl %%%s, 4(%%esp)\n", hi);
+            fprintf (state->ofp, "    fildll (%%esp)\n");
+            fprintf (state->ofp, "    addl $8, %%esp\n");
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    sub esp, 4\n");
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov dword [esp], %s\n" : "    mov dword ptr [esp], %s\n", lo);
+        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fild dword [esp]\n" : "    fild dword ptr [esp]\n");
+        fprintf (state->ofp, "    add esp, 4\n");
+    
+    } else {
+    
+        fprintf (state->ofp, "    subl $4, %%esp\n");
+        fprintf (state->ofp, "    movl %%%s, (%%esp)\n", lo);
+        fprintf (state->ofp, "    fildl (%%esp)\n");
+        fprintf (state->ofp, "    addl $4, %%esp\n");
+    
+    }
+
+}
+
+static void emit_load_assignment_rhs_expression_to_reg (const char *reg) {
+
+    int false_label;
+    int true_label;
+    int end_label;
+    
+    if (rhs_current_operand_is_floating_now ()) {
+    
+        emit_load_floating_rhs_expression_now (DATA_DOUBLE & 0x1f);
+        
+        /*
+         * Floating comparisons leave their boolean result in eax.
+         * Do not run that through fistp: emit_floating_compare_to_eax_now()
+         * has already consumed both x87 operands with fcompp, so the x87
+         * stack no longer contains a value to convert.
+         */
+        if (floating_rhs_result_in_eax_bool) {
+        
+            if (state->ofp && strcmp (reg, "eax") != 0) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    mov %s, eax\n", reg);
+                } else {
+                    fprintf (state->ofp, "    movl %%eax, %%%s\n", reg);
+                }
+            
+            }
+            
+            floating_rhs_result_in_eax_bool = 0;
+            return;
+        
+        }
+        
+        emit_floating_stack_to_int_reg_now (reg);
+        return;
+    
+    }
+    
+    emit_load_assignment_compare_expression_to_reg (reg);
+    
+    for (;;) {
+    
+        if (assignment32_stop_before_condition_operator && is_assignment32_condition_stop_operator (tok.kind)) {
+            break;
+        }
+        
+        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);
+            emit_mov_imm_to_reg_now (reg, 1);
+            emit_statement_jump (end_label);
+            emit_statement_label (false_label);
+            emit_mov_imm_to_reg_now (reg, 0);
+            emit_statement_label (end_label);
+            
+            continue;
+        
+        }
+        
+        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);
+            emit_mov_imm_to_reg_now (reg, 0);
+            emit_statement_jump (end_label);
+            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) {
+    
+        false_label = anon_label++;
+        end_label = anon_label++;
+        
+        get_token ();
+        
+        if (state->ofp) {
+        
+            if (strcmp (reg, "eax") != 0) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    mov eax, %s\n", reg);
+                } else {
+                    fprintf (state->ofp, "    movl %%%s, %%eax\n", reg);
+                }
+            
+            }
+            
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                fprintf (state->ofp, "    test eax, eax\n");
+                
+                if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+                    fprintf (state->ofp, "    jz L%d\n", false_label);
+                } else {
+                    fprintf (state->ofp, "    jz .L%d\n", false_label);
+                }
+            
+            } else {
+            
+                fprintf (state->ofp, "    testl %%eax, %%eax\n");
+                fprintf (state->ofp, "    jz .L%d\n", false_label);
+            
+            }
+        
+        }
+        
+        emit_load_assignment_rhs_expression_to_reg (reg);
+        expect (TOK_COLON, ":");
+        emit_statement_jump (end_label);
+        emit_statement_label (false_label);
+        emit_load_assignment_rhs_expression_to_reg (reg);
+        emit_statement_label (end_label);
+    
+    }
+
+}
+
+static void emit_statement_cmp64_to_eax (enum token_kind op, int is_unsigned);
+
+static int is_assignment64_condition_stop_operator (enum token_kind k) {
+
+    return  k == TOK_LESS || k == TOK_LTEQ || k == TOK_GREATER ||
+                k == TOK_GTEQ || k == TOK_EQEQ || k == TOK_NOTEQ ||
+                    k == TOK_LOGAND || k == TOK_LOGOR;
+
+}
+
+static int is_assignment64_binary_operator (enum token_kind k) {
+
+    return  is_arithmetic_binary_operator (k) ||
+                k == TOK_LESS || k == TOK_LTEQ || k == TOK_GREATER ||
+                    k == TOK_GTEQ || k == TOK_EQEQ || k == TOK_NOTEQ ||
+                        k == TOK_LOGAND || k == TOK_LOGOR;
+
+}
+
+static void emit_assignment64_bool_result_to_pair_now (const char *lo, const char *hi) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (strcmp (lo, "eax") != 0) {
+            fprintf (state->ofp, "    mov %s, eax\n", lo);
+        }
+        
+        fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
+    
+    } else {
+    
+        if (strcmp (lo, "eax") != 0) {
+            fprintf (state->ofp, "    movl %%eax, %%%s\n", lo);
+        }
+        
+        fprintf (state->ofp, "    xorl %%%s, %%%s\n", hi, hi);
+    
+    }
+
+}
+
+static void emit_assignment64_logical_op_to_pair_now (enum token_kind op, const char *lo, const char *hi) {
+
+    int true_label;
+    int false_label;
+    int end_label;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    true_label = anon_label++;
+    false_label = anon_label++;
+    end_label = anon_label++;
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    test edx, edx\n");
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), op == TOK_LOGOR ? true_label : end_label);
+        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"), op == TOK_LOGOR ? true_label : end_label);
+        
+        if (op == TOK_LOGAND) {
+        
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jmp L%d\n" : "    jmp .L%d\n"), false_label);
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), end_label);
+            fprintf (state->ofp, "    test ecx, ecx\n");
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), true_label);
+            fprintf (state->ofp, "    test ebx, ebx\n");
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), true_label);
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), false_label);
+            fprintf (state->ofp, "    xor eax, eax\n");
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jmp L%d\n" : "    jmp .L%d\n"), end_label + 1);
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), true_label);
+            fprintf (state->ofp, "    mov eax, 1\n");
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), end_label + 1);
+        
+        } else {
+        
+            fprintf (state->ofp, "    test ecx, ecx\n");
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), true_label);
+            fprintf (state->ofp, "    test ebx, ebx\n");
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), true_label);
+            fprintf (state->ofp, "    xor eax, eax\n");
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jmp L%d\n" : "    jmp .L%d\n"), end_label);
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), true_label);
+            fprintf (state->ofp, "    mov eax, 1\n");
+            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), end_label);
+        
+        }
+    
+    } else {
+    
+        fprintf (state->ofp, "    testl %%edx, %%edx\n");
+        fprintf (state->ofp, op == TOK_LOGOR ? "    jnz .L%d\n" : "    jnz .L%d\n", op == TOK_LOGOR ? true_label : end_label);
+        fprintf (state->ofp, "    testl %%eax, %%eax\n");
+        fprintf (state->ofp, op == TOK_LOGOR ? "    jnz .L%d\n" : "    jnz .L%d\n", op == TOK_LOGOR ? true_label : end_label);
+        
+        if (op == TOK_LOGAND) {
+        
+            fprintf (state->ofp, "    jmp .L%d\n", false_label);
+            fprintf (state->ofp, ".L%d:\n", end_label);
+            fprintf (state->ofp, "    testl %%ecx, %%ecx\n");
+            fprintf (state->ofp, "    jnz .L%d\n", true_label);
+            fprintf (state->ofp, "    testl %%ebx, %%ebx\n");
+            fprintf (state->ofp, "    jnz .L%d\n", true_label);
+            fprintf (state->ofp, ".L%d:\n", false_label);
+            fprintf (state->ofp, "    xorl %%eax, %%eax\n");
+            fprintf (state->ofp, "    jmp .L%d\n", end_label + 1);
+            fprintf (state->ofp, ".L%d:\n", true_label);
+            fprintf (state->ofp, "    movl $1, %%eax\n");
+            fprintf (state->ofp, ".L%d:\n", end_label + 1);
+        
+        } else {
+        
+            fprintf (state->ofp, "    testl %%ecx, %%ecx\n");
+            fprintf (state->ofp, "    jnz .L%d\n", true_label);
+            fprintf (state->ofp, "    testl %%ebx, %%ebx\n");
+            fprintf (state->ofp, "    jnz .L%d\n", true_label);
+            fprintf (state->ofp, "    xorl %%eax, %%eax\n");
+            fprintf (state->ofp, "    jmp .L%d\n", end_label);
+            fprintf (state->ofp, ".L%d:\n", true_label);
+            fprintf (state->ofp, "    movl $1, %%eax\n");
+            fprintf (state->ofp, ".L%d:\n", end_label);
+        
+        }
+    
+    }
+    
+    anon_label++;
+    emit_assignment64_bool_result_to_pair_now (lo, hi);
+
+}
+
+static void emit_assignment64_compare_op_to_pair_now (enum token_kind op, const char *lo, const char *hi, int is_unsigned) {
+
+    emit_statement_cmp64_to_eax (op, is_unsigned);
+    emit_assignment64_bool_result_to_pair_now (lo, hi);
+
+}
+
+static void emit_load_assignment_rhs_expression_to_pair (const char *lo, const char *hi, int is_unsigned) {
+
+    enum token_kind op;
+    
+    int result_pair_is_eax_edx = (strcmp (lo, "eax") == 0 && strcmp (hi, "edx") == 0);
+    int current_pair_is_eax_edx = result_pair_is_eax_edx;
+    
+    if (current_integer_expr_is_foldable_now ()) {
+    
+        int64_s v = const64_from_current_foldable_expr ();
+        emit_load_const64_to_pair_now (lo, hi, v);
+        
+        return;
+    
+    }
+    
+    emit_load_assignment_rhs_to_pair (lo, hi);
+    
+    while (is_assignment64_binary_operator (tok.kind) && !(assignment64_stop_before_condition_operator && is_assignment64_condition_stop_operator (tok.kind))) {
+    
+        op = tok.kind;
+        get_token ();
+        
+        if (!current_pair_is_eax_edx) {
+        
+            emit_mov_reg_to_reg_now ("eax", lo);
+            emit_mov_reg_to_reg_now ("edx", hi);
+            
+            current_pair_is_eax_edx = 1;
+        
+        }
+        
+        emit_preserve_assignment64_regs (op);
+        
+        /*
+         * The right operand of a 64-bit shift is a plain integer shift
+         * count, not a 64-bit value.  Loading it through the 64-bit primary
+         * path loses precedence for cases such as:
+         *
+         *     ((address_type)1) << (CHAR_BIT * rel->howto->size)
+         *
+         * Worse, the RHS loader uses EAX internally for nested expressions;
+         * preserve the 64-bit LHS in EDX:EAX while the count is evaluated
+         * into EBX.
+         */
+        if (op == TOK_LSH || op == TOK_RSH || op == TOK_LSHEQ || op == TOK_RSHEQ) {
+        
+            emit_push_reg_now ("eax");
+            emit_push_reg_now ("edx");
+            
+            emit_load_assignment_binary_expression_to_reg ("ebx");
+            
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    xor ecx, ecx\n");
+            } else {
+                fprintf (state->ofp, "    xorl %%ecx, %%ecx\n");
+            }
+            
+            emit_pop_reg_now ("edx");
+            emit_pop_reg_now ("eax");
+        
+        } else {
+        
+            /*
+             * The generic 64-bit RHS loader uses EAX:EDX as scratch even
+             * when asked to leave the final value in EBX:ECX.  Preserve the
+             * left operand around RHS evaluation; otherwise expressions such
+             * as:
+             *
+             *     result &= (((address_type)1) << n) - 1
+             *
+             * end up applying the operator to the RHS twice, because the
+             * computed mask clobbers the original result in EAX:EDX.
+             */
+            emit_push_reg_now ("eax");
+            emit_push_reg_now ("edx");
+            
+            emit_load_assignment_rhs_to_pair ("ebx", "ecx");
+            
+            emit_pop_reg_now ("edx");
+            emit_pop_reg_now ("eax");
+        
+        }
+        
+        if (op == TOK_LOGAND || op == TOK_LOGOR) {
+        
+            emit_assignment64_logical_op_to_pair_now (op, lo, hi);
+            current_pair_is_eax_edx = result_pair_is_eax_edx;
+        
+        } else if (is_value_compare_operator (op)) {
+        
+            emit_assignment64_compare_op_to_pair_now (op, lo, hi, is_unsigned);
+            current_pair_is_eax_edx = result_pair_is_eax_edx;
+        
+        } else {
+        
+            emit_assignment_binary_op64 (op, is_unsigned);
+            current_pair_is_eax_edx = 1;
+        
+        }
+        
+        emit_restore_assignment64_regs (op);
+    
+    }
+    
+    if (current_pair_is_eax_edx && !result_pair_is_eax_edx) {
+    
+        emit_mov_reg_to_reg_now (lo, "eax");
+        emit_mov_reg_to_reg_now (hi, "edx");
+        
+        current_pair_is_eax_edx = 0;
+    
+    }
+    
+    if (tok.kind == TOK_QMARK) {
+    
+        int false_label = anon_label++;
+        int end_label = anon_label++;
+        
+        get_token ();
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                fprintf (state->ofp, "    test %s, %s\n", hi, hi);
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), false_label + 2);
+                fprintf (state->ofp, "    test %s, %s\n", lo, lo);
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jz L%d\n" : "    jz .L%d\n"), false_label);
+                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), false_label + 2);
+            
+            } else {
+            
+                fprintf (state->ofp, "    testl %%%s, %%%s\n", hi, hi);
+                fprintf (state->ofp, "    jnz .L%d\n", false_label + 2);
+                fprintf (state->ofp, "    testl %%%s, %%%s\n", lo, lo);
+                fprintf (state->ofp, "    jz .L%d\n", false_label);
+                fprintf (state->ofp, ".L%d:\n", false_label + 2);
+            
+            }
+        
+        }
+        
+        anon_label++;
+        
+        emit_load_assignment_rhs_expression_to_pair (lo, hi, is_unsigned);
+        expect (TOK_COLON, ":");
+        
+        emit_statement_jump (end_label);
+        emit_statement_label (false_label);
+        emit_load_assignment_rhs_expression_to_pair (lo, hi, is_unsigned);
+        emit_statement_label (end_label);
+    
+    }
+
+}
+
+static void emit_incdec_integral_symbol_now (struct local_symbol *sym, const char *name, int size, enum token_kind op) {
+
+    char memref[64];
+    char nasm_memref[256];
+    
+    const char *symbol;
+    const char *mnemonic;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (size == (DATA_LLONG & 0x1f)) {
+    
+        if (sym) {
+        
+            if (sym->is_static && sym->static_label) {
+                emit_load_global64_to_pair ("eax", "edx", sym->static_label);
+            } else {
+                emit_load_local64_to_pair (sym->offset, "eax", "edx");
+            }
+        
+        } else {
+            emit_load_global64_to_pair ("eax", "edx", name);
+        }
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            if (op == TOK_INCR) {
+            
+                fprintf (state->ofp, "    add eax, 1\n");
+                fprintf (state->ofp, "    adc edx, 0\n");
+            
+            } else {
+            
+                fprintf (state->ofp, "    sub eax, 1\n");
+                fprintf (state->ofp, "    sbb edx, 0\n");
+            
+            }
+        
+        } else {
+        
+            if (op == TOK_INCR) {
+            
+                fprintf (state->ofp, "    addl $1, %%eax\n");
+                fprintf (state->ofp, "    adcl $0, %%edx\n");
+            
+            } else {
+            
+                fprintf (state->ofp, "    subl $1, %%eax\n");
+                fprintf (state->ofp, "    sbbl $0, %%edx\n");
+            
+            }
+        
+        }
+        
+        if (sym) {
+        
+            if (sym->is_static && sym->static_label) {
+                emit_store_pair_to_global64 (sym->static_label, "eax", "edx");
+            } else {
+                emit_store_pair_to_local64 (sym->offset, "eax", "edx");
+            }
+        
+        } else {
+            emit_store_pair_to_global64 (name, "eax", "edx");
+        }
+        
+        return;
+    
+    }
+    
+    if (size != (DATA_CHAR & 0x1f) && size != (DATA_SHORT & 0x1f) && size != (DATA_INT & 0x1f) && size != DATA_PTR) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        mnemonic = op == TOK_INCR ? "add" : "sub";
+        
+        if (sym && !sym->is_static) {
+        
+            format_intel_ebp_offset (memref, sizeof (memref), sym->offset);
+            symbol = memref;
+        
+        } else if (sym && sym->static_label) {
+            symbol = asm_global_symbol_name (sym->static_label);
+        } else {
+            symbol = asm_global_symbol_name (name);
+        }
+        
+        if (state->syntax & ASM_SYNTAX_NASM) {
+            symbol = format_nasm_memory_operand (nasm_memref, sizeof (nasm_memref), symbol);
+        }
+        
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s byte %s, 1\n" : "    %s byte ptr %s, 1\n"), mnemonic, symbol);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s word %s, 1\n" : "    %s word ptr %s, 1\n"), mnemonic, symbol);
+        } else {
+            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s dword %s, 1\n" : "    %s dword ptr %s, 1\n"), mnemonic, symbol);
+        }
+    
+    } else {
+    
+        if (sym && !sym->is_static) {
+        
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, op == TOK_INCR ? "    incb %ld(%%ebp)\n" : "    decb %ld(%%ebp)\n", sym->offset);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, op == TOK_INCR ? "    incw %ld(%%ebp)\n" : "    decw %ld(%%ebp)\n", sym->offset);
+            } else {
+                fprintf (state->ofp, op == TOK_INCR ? "    incl %ld(%%ebp)\n" : "    decl %ld(%%ebp)\n", sym->offset);
+            }
+        
+        } else {
+        
+            symbol = asm_global_symbol_name ((sym && sym->static_label) ? sym->static_label : name);
+            
+            if (size == (DATA_CHAR & 0x1f)) {
+                fprintf (state->ofp, op == TOK_INCR ? "    incb %s\n" : "    decb %s\n", symbol);
+            } else if (size == (DATA_SHORT & 0x1f)) {
+                fprintf (state->ofp, op == TOK_INCR ? "    incw %s\n" : "    decw %s\n", symbol);
+            } else {
+                fprintf (state->ofp, op == TOK_INCR ? "    incl %s\n" : "    decl %s\n", symbol);
+            }
+        
+        }
+    
+    }
+
+}
+
+static void emit_incdec_pointer_symbol_now (struct local_symbol *sym, const char *name, enum token_kind op, int step) {
+
+    const char *mnemonic = op == TOK_INCR ? "add" : "sub";
+    const char *symbol;
+    
+    char memref[64];
+    char nasm_memref[128];
+    
+    if (step <= 0) {
+        step = 1;
+    }
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (step == 1) {
+    
+        emit_incdec_integral_symbol_now (sym, name, DATA_PTR, op);
+        return;
+    
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        if (sym && !sym->is_static) {
+        
+            format_intel_ebp_offset (memref, sizeof (memref), sym->offset);
+            symbol = memref;
+        
+        } else if (sym && sym->static_label) {
+            symbol = asm_global_symbol_name (sym->static_label);
+        } else {
+            symbol = asm_global_symbol_name (name);
+        }
+        
+        if (state->syntax & ASM_SYNTAX_NASM) {
+        
+            symbol = format_nasm_memory_operand (nasm_memref, sizeof (nasm_memref), symbol);
+            fprintf (state->ofp, "    %s dword %s, %d\n", mnemonic, symbol, step);
+        
+        } else {
+            fprintf (state->ofp, "    %s dword ptr %s, %d\n", mnemonic, symbol, step);
+        }
+    
+    } else {
+    
+        if (sym && !sym->is_static) {
+            fprintf (state->ofp, "    %sl $%d, %ld(%%ebp)\n", mnemonic, step, sym->offset);
+        } else {
+        
+            symbol = asm_global_symbol_name ((sym && sym->static_label) ? sym->static_label : name);
+            fprintf (state->ofp, "    %sl $%d, %s\n", mnemonic, step, symbol);
+        
+        }
+    
+    }
+
+}
+
+static void emit_incdec_symbol_now (struct local_symbol *sym, const char *name, enum token_kind op, int line, const char *start, const char *caret) {
+
+    int global_index;
+    int is_floating;
+    int pointer_depth;
+    int pointed_size;
+    
+    int size;
+    
+    if (!sym) {
+    
+        global_index = find_global_symbol (name);
+        
+        if (global_index < 0) {
+        
+            report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "unknown symbol '%s'", name);
+            return;
+        
+        }
+        
+        if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION) {
+        
+            report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "function '%s' cannot be incremented or decremented", name);
+            return;
+        
+        }
+    
+    }
+    
+    size = sym ? sym->size : get_global_symbol_size (name);
+    is_floating = sym ? sym->is_floating : get_global_symbol_floating (name);
+    
+    pointer_depth = sym ? sym->pointer_depth : get_global_symbol_pointer_depth (name);
+    pointed_size = sym ? sym->pointed_size : get_global_symbol_pointed_size (name);
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (is_floating) {
+    
+        emit_load_floating_symbol_now (sym, name, size);
+        fprintf (state->ofp, "    fld1\n");
+        
+        if (op == TOK_INCR) {
+            emit_floating_binary_now (TOK_PLUS);
+        } else {
+            emit_floating_binary_now (TOK_MINUS);
+        }
+        
+        emit_store_floating_symbol_now (sym, name, size);
+        return;
+    
+    }
+    
+    if (pointer_depth > 0) {
+    
+        emit_incdec_pointer_symbol_now (sym, name, op, pointed_size);
+        return;
+    
+    }
+    
+    emit_incdec_integral_symbol_now (sym, name, size, op);
+
+}
+
+static int parse_prefix_incdec_statement (void) {
+
+    enum token_kind op;
+    char *name;
+    
+    const char *name_start, *name_caret;
+    unsigned long name_line;
+    
+    struct local_symbol *sym;
+    
+    int deref_size = DATA_INT & 0x1f;
+    int indirect = 0;
+    
+    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+    
+        if (emit_load_prefix_incdec_member_to_reg_now ("eax")) {
+        
+            expect_semi_or_recover ();
+            return 1;
+        
+        }
+    
+    }
+    
+    if (emit_load_prefix_incdec_parenthesized_deref_to_reg_now ("eax")) {
+    
+        expect_semi_or_recover ();
+        return 1;
+    
+    }
+    
+    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
+        return 0;
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    if (tok.kind == TOK_STAR) {
+    
+        indirect = 1;
+        get_token ();
+    
+    }
+    
+    if (tok.kind != TOK_IDENT) {
+    
+        if (indirect) {
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after *");
+        } else {
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after %s", op == TOK_INCR ? "++" : "--");
+        }
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    get_token ();
+
+    sym = find_local_symbol (name);
+    
+    if (indirect) {
+    
+        if (sym) {
+        
+            if (sym->pointer_depth > 1) {
+                deref_size = DATA_PTR & 0x1f;
+            } else if (sym->pointer_depth == 1 && sym->pointed_size > 0) {
+                deref_size = sym->pointed_size & 0x1f;
+            }
+            
+            if (sym->is_static && sym->static_label) {
+                emit_load_global_to_reg ("edx", sym->static_label, DATA_PTR);
+            } else {
+                emit_load_local_to_reg ("edx", sym->offset, DATA_PTR);
+            }
+        
+        } else if (find_global_symbol (name) >= 0) {
+        
+            if (get_global_symbol_pointer_depth (name) > 1) {
+                deref_size = DATA_PTR & 0x1f;
+            } else if (get_global_symbol_pointer_depth (name) == 1 && get_global_symbol_pointed_size (name) > 0) {
+                deref_size = get_global_symbol_pointed_size (name) & 0x1f;
+            }
+            
+            emit_load_global_to_reg ("edx", name, DATA_PTR);
+        
+        } else {
+        
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        emit_push_reg_now ("edx");
+        emit_load_member_from_addr_reg_now ("eax", "edx", 0, deref_size);
+        
+        if (state->ofp) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, op == TOK_INCR ? "    add eax, 1\n" : "    sub eax, 1\n");
+            } else {
+                fprintf (state->ofp, op == TOK_INCR ? "    addl $1, %%eax\n" : "    subl $1, %%eax\n");
+            }
+        
+        }
+        
+        emit_pop_reg_now ("edx");
+        emit_store_reg_to_deref_reg_now ("edx", "eax", deref_size);
+        
+        expect_semi_or_recover ();
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    emit_incdec_symbol_now (sym, name, op, name_line, name_start, name_caret);
+    
+    expect_semi_or_recover ();
+    free (name);
+    
+    return 1;
+
+}
+
+static int parse_parenthesized_pointer_member_indirect_assignment_statement (void) {
+
+    char *name = 0;
+    char *member = 0;
+    
+    struct local_symbol *sym;
+    
+    int global_index;
+    int parens = 0;
+    int offset = 0;
+    int member_size = DATA_PTR & 0x1f;
+    int member_elem_size = DATA_INT & 0x1f;
+    int member_pointer_depth = 0;
+    int deref_size = DATA_INT & 0x1f;
+    int step = 1;
+    
+    enum token_kind postfix_op = TOK_EOF;
+    enum token_kind op;
+    
+    const char *name_start;
+    const char *name_caret;
+    const char *member_start;
+    const char *member_caret;
+    
+    unsigned long name_line;
+    unsigned long member_line;
+    
+    if (tok.kind != TOK_LPAREN) {
+        return 0;
+    }
+    
+    while (tok.kind == TOK_LPAREN) {
+        ++parens;
+        get_token ();
+    }
+    
+    if (tok.kind != TOK_STAR) {
+    
+        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+        
+            enum token_kind prefix_op = tok.kind;
+            char *prefix_name;
+            
+            const char *prefix_start;
+            const char *prefix_caret;
+            
+            unsigned long prefix_line;
+            
+            struct local_symbol *prefix_sym;
+            
+            int prefix_global_index;
+            int prefix_deref_size = DATA_INT & 0x1f;
+            
+            enum token_kind prefix_assign_op;
+            get_token ();
+            
+            if (tok.kind != TOK_IDENT) {
+            
+                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                
+                expect_semi_or_recover ();
+                return 1;
+            
+            }
+            
+            prefix_name = xstrdup (tok.ident);
+            prefix_start = tok.start;
+            prefix_caret = tok.caret;
+            prefix_line = get_line_number ();
+            
+            get_token ();
+            
+            while (tok.kind == TOK_RPAREN && parens > 0) {
+            
+                --parens;
+                get_token ();
+            
+            }
+            
+            if (parens != 0 || !is_assignment_operator (tok.kind)) {
+            
+                free (prefix_name);
+                
+                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                expect_semi_or_recover ();
+                
+                return 1;
+            
+            }
+            
+            prefix_assign_op = tok.kind;
+            get_token ();
+            
+            prefix_sym = find_local_symbol (prefix_name);
+            prefix_global_index = find_global_symbol (prefix_name);
+            
+            if (!prefix_sym && prefix_global_index < 0) {
+            
+                report_line_at (get_filename (), prefix_line, REPORT_ERROR, prefix_start, prefix_caret, "unknown symbol '%s'", prefix_name);
+                
+                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                expect_semi_or_recover ();
+                
+                free (prefix_name);
+                return 1;
+            
+            }
+            
+            if (prefix_sym) {
+            
+                if (prefix_sym->pointer_depth > 1) {
+                    prefix_deref_size = DATA_PTR & 0x1f;
+                } else if (prefix_sym->pointer_depth == 1 && prefix_sym->pointed_size > 0) {
+                    prefix_deref_size = prefix_sym->pointed_size & 0x1f;
+                }
+            
+            } else {
+            
+                if (get_global_symbol_pointer_depth (prefix_name) > 1) {
+                    prefix_deref_size = DATA_PTR & 0x1f;
+                } else if (get_global_symbol_pointer_depth (prefix_name) == 1 && get_global_symbol_pointed_size (prefix_name) > 0) {
+                    prefix_deref_size = get_global_symbol_pointed_size (prefix_name) & 0x1f;
+                }
+            
+            }
+            
+            if (prefix_deref_size == 0) {
+                prefix_deref_size = DATA_INT & 0x1f;
+            }
+            
+            emit_incdec_symbol_now (prefix_sym, prefix_name, prefix_op, prefix_line, prefix_start, prefix_caret);
+            
+            if (state->ofp) {
+            
+                if (prefix_sym) {
+                
+                    if (prefix_sym->is_static && prefix_sym->static_label) {
+                        emit_load_global_to_reg ("ecx", prefix_sym->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg ("ecx", prefix_sym->offset, DATA_PTR);
+                    }
+                
+                } else {
+                    emit_load_global_to_reg ("ecx", prefix_name, DATA_PTR);
+                }
+                
+                emit_push_reg_now ("ecx");
+                
+                if (prefix_assign_op == TOK_ASSIGN) {
+                    emit_load_assignment_rhs_expression_to_reg ("eax");
+                } else {
+                
+                    emit_pop_reg_now ("edx");
+                    emit_push_reg_now ("edx");
+                    
+                    emit_load_member_from_addr_reg_now ("eax", "edx", 0, prefix_deref_size);
+                    emit_push_reg_now ("eax");
+                    
+                    emit_load_assignment_rhs_expression_to_reg ("edx");
+                    emit_pop_reg_now ("eax");
+                    
+                    emit_assignment_binary_op (prefix_assign_op, 0);
+                
+                }
+                
+                emit_pop_reg_now ("edx");
+                emit_store_reg_to_deref_reg_now ("edx", "eax", prefix_deref_size);
+            
+            } else {
+                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            }
+            
+            expect_semi_or_recover ();
+            
+            free (prefix_name);
+            return 1;
+        
+        }
+        
+        if (tok.kind == TOK_IDENT) {
+        
+            name = xstrdup (tok.ident);
+            name_start = tok.start;
+            name_caret = tok.caret;
+            name_line = get_line_number ();
+            
+            get_token ();
+            
+            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+            
+                postfix_op = tok.kind;
+                get_token ();
+            
+            }
+            
+            while (tok.kind == TOK_RPAREN && parens > 0) {
+            
+                --parens;
+                get_token ();
+            
+            }
+            
+            if (parens != 0 || !is_assignment_operator (tok.kind)) {
+            
+                free (name);
+                
+                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                expect_semi_or_recover ();
+                
+                return 1;
+            
+            }
+            
+            op = tok.kind;
+            get_token ();
+            
+            sym = find_local_symbol (name);
+            global_index = find_global_symbol (name);
+            
+            if (!sym && global_index < 0) {
+            
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+                
+                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                expect_semi_or_recover ();
+                
+                free (name);
+                return 1;
+            
+            }
+            
+            if (sym) {
+            
+                if (sym->pointer_depth > 1) {
+                
+                    deref_size = DATA_PTR & 0x1f;
+                    step = DATA_PTR & 0x1f;
+                
+                } else if (sym->pointer_depth == 1) {
+                
+                    deref_size = sym->pointed_size & 0x1f;
+                    step = sym->pointed_size > 0 ? sym->pointed_size : 1;
+                
+                }
+            
+            } else {
+            
+                if (get_global_symbol_pointer_depth (name) > 1) {
+                
+                    deref_size = DATA_PTR & 0x1f;
+                    step = DATA_PTR & 0x1f;
+                
+                } else if (get_global_symbol_pointer_depth (name) == 1) {
+                
+                    deref_size = get_global_symbol_pointed_size (name) & 0x1f;
+                    step = get_global_symbol_pointed_size (name) > 0 ? get_global_symbol_pointed_size (name) : 1;
+                
+                }
+            
+            }
+            
+            if (deref_size == 0) {
+                deref_size = DATA_INT & 0x1f;
+            }
+            
+            if (state->ofp) {
+            
+                if (sym) {
+                
+                    if (sym->is_static && sym->static_label) {
+                        emit_load_global_to_reg ("ecx", sym->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg ("ecx", sym->offset, DATA_PTR);
+                    }
+                
+                } else {
+                    emit_load_global_to_reg ("ecx", name, DATA_PTR);
+                }
+                
+                emit_push_reg_now ("ecx");
+                
+                if (postfix_op == TOK_INCR || postfix_op == TOK_DECR) {
+                
+                    if (sym) {
+                    
+                        if (sym->is_static && sym->static_label) {
+                        
+                            if (state->syntax & ASM_SYNTAX_INTEL) {
+                                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s dword [%s], %d\n" : "    %s dword ptr [%s], %d\n"), postfix_op == TOK_INCR ? "add" : "sub", sym->static_label, step);
+                            } else {
+                                fprintf (state->ofp, "    %sl $%d, %s\n", postfix_op == TOK_INCR ? "add" : "sub", step, sym->static_label);
+                            }
+                        
+                        } else {
+                        
+                            if (state->syntax & ASM_SYNTAX_INTEL) {
+                            
+                                char memref[64];
+                                
+                                format_intel_ebp_offset (memref, sizeof (memref), sym->offset);
+                                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s dword %s, %d\n" : "    %s dword ptr %s, %d\n"), postfix_op == TOK_INCR ? "add" : "sub", memref, step);
+                                
+                            } else {
+                                fprintf (state->ofp, "    %sl $%d, %ld(%%ebp)\n", postfix_op == TOK_INCR ? "add" : "sub", step, sym->offset);
+                            }
+                        
+                        }
+                    
+                    } else {
+                    
+                        if (state->syntax & ASM_SYNTAX_INTEL) {
+                            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s dword [%s], %d\n" : "    %s dword ptr [%s], %d\n"), postfix_op == TOK_INCR ? "add" : "sub", name, step);
+                        } else {
+                            fprintf (state->ofp, "    %sl $%d, %s\n", postfix_op == TOK_INCR ? "add" : "sub", step, name);
+                        }
+                    
+                    }
+                
+                }
+                
+                if (op == TOK_ASSIGN) {
+                    emit_load_assignment_rhs_expression_to_reg ("eax");
+                } else {
+                
+                    emit_pop_reg_now ("edx");
+                    emit_push_reg_now ("edx");
+                    emit_load_member_from_addr_reg_now ("eax", "edx", 0, deref_size);
+                    emit_push_reg_now ("eax");
+                    emit_load_assignment_rhs_expression_to_reg ("edx");
+                    emit_pop_reg_now ("eax");
+                    emit_assignment_binary_op (op, 0);
+                
+                }
+                
+                emit_pop_reg_now ("edx");
+                emit_store_reg_to_deref_reg_now ("edx", "eax", deref_size);
+            
+            } else {
+                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            }
+            
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        
+        expect_semi_or_recover ();
+        return 1;
+    
+    }
+    
+    get_token ();
+    
+    while (tok.kind == TOK_LPAREN) {
+    
+        ++parens;
+        get_token ();
+    
+    }
+    
+    if (tok.kind != TOK_IDENT) {
+    
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        
+        expect_semi_or_recover ();
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    get_token ();
+    
+    if (state->ofp) {
+    
+        if (tok.kind == TOK_LPAREN) {
+            emit_call_identifier_to_reg_now (name, "eax", name_start, name_caret, name_line);
+        } else {
+        
+            sym = find_local_symbol (name);
+            global_index = find_global_symbol (name);
+            
+            if (sym) {
+            
+                if (sym->is_static && sym->static_label) {
+                    emit_load_global_to_reg ("eax", sym->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg ("eax", sym->offset, DATA_PTR);
+                }
+            
+            } else if (global_index >= 0) {
+                emit_load_global_to_reg ("eax", name, DATA_PTR);
+            } else {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            }
+        
+        }
+        
+        emit_load_deref_reg_now ("eax", DATA_PTR);
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    mov edx, eax\n");
+        } else {
+            fprintf (state->ofp, "    movl %%eax, %%edx\n");
+        }
+    
+    } else if (tok.kind == TOK_LPAREN) {
+        emit_call_identifier_to_reg_now (name, "eax", name_start, name_caret, name_line);
+    }
+    
+    while (tok.kind == TOK_RPAREN && parens > 0) {
+    
+        --parens;
+        get_token ();
+    
+    }
+    
+    if (tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
+    
+        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+        
+            postfix_op = tok.kind;
+            get_token ();
+            
+            sym = find_local_symbol (name);
+            global_index = find_global_symbol (name);
+            
+            if (sym) {
+            
+                if (sym->pointer_depth > 1) {
+                
+                    deref_size = DATA_PTR & 0x1f;
+                    step = DATA_PTR & 0x1f;
+                
+                } else if (sym->pointer_depth == 1) {
+                
+                    deref_size = sym->pointed_size & 0x1f;
+                    step = 1;
+                
+                }
+                
+                if (deref_size == 0) {
+                    deref_size = DATA_INT & 0x1f;
+                }
+                
+                if (sym->is_static && sym->static_label) {
+                    emit_load_global_to_reg ("edx", sym->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg ("edx", sym->offset, DATA_PTR);
+                }
+            
+            } else if (global_index >= 0) {
+            
+                if (get_global_symbol_pointer_depth (name) > 1) {
+                
+                    deref_size = DATA_PTR & 0x1f;
+                    step = DATA_PTR & 0x1f;
+                
+                } else if (get_global_symbol_pointer_depth (name) == 1) {
+                
+                    deref_size = get_global_symbol_pointed_size (name) & 0x1f;
+                    step = 1;
+                
+                }
+                
+                if (deref_size == 0) {
+                    deref_size = DATA_INT & 0x1f;
+                }
+                
+                emit_load_global_to_reg ("edx", name, DATA_PTR);
+            
+            } else {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            }
+            
+            if (state->ofp) {
+            
+                emit_load_deref_reg_now ("edx", deref_size);
+
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    %s edx, %d\n", postfix_op == TOK_INCR ? "add" : "sub", step);
+                } else {
+                    fprintf (state->ofp, "    %sl $%d, %%edx\n", postfix_op == TOK_INCR ? "add" : "sub", step);
+                }
+                
+                if (sym) {
+                
+                    if (sym->is_static && sym->static_label) {
+                        emit_load_global_to_reg ("eax", sym->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg ("eax", sym->offset, DATA_PTR);
+                    }
+                
+                } else if (global_index >= 0) {
+                    emit_load_global_to_reg ("eax", name, DATA_PTR);
+                }
+                
+                emit_store_reg_to_deref_reg_now ("eax", "edx", deref_size);
+            
+            }
+            
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        free (name);
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        return 1;
+    
+    }
+    
+    get_token ();
+    
+    member_start = tok.start;
+    member_caret = tok.caret;
+    member_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT) {
+    
+        report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name");
+        free (name);
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        
+        expect_semi_or_recover ();
+        return 1;
+    
+    }
+    
+    member = xstrdup (tok.ident);
+    get_token ();
+    
+    if (!find_member_info_ex (member, &offset, &member_size, &member_elem_size, &member_pointer_depth, 0, 0)) {
+    
+        report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+        
+        free (member);
+        free (name);
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        return 1;
+    
+    }
+    
+    free (member);
+    
+    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+    
+        postfix_op = tok.kind;
+        get_token ();
+    
+    }
+    
+    if (!is_assignment_operator (tok.kind)) {
+    
+        free (name);
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        return 1;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    if (member_pointer_depth > 1) {
+        deref_size = DATA_PTR & 0x1f;
+    } else if (member_pointer_depth == 1 && member_elem_size > 0) {
+        deref_size = member_elem_size & 0x1f;
+    } else if (member_size > 0) {
+        deref_size = member_size & 0x1f;
+    }
+    
+    if (deref_size == 0) {
+        deref_size = DATA_INT & 0x1f;
+    }
+    
+    step = member_elem_size > 0 ? member_elem_size : 1;
+    
+    if (state->ofp) {
+    
+        emit_load_member_from_addr_reg_now ("ecx", "edx", offset, DATA_PTR & 0x1f);
+        
+        if (postfix_op == TOK_INCR || postfix_op == TOK_DECR) {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+            
+                if (state->syntax & ASM_SYNTAX_NASM) {
+                    fprintf (state->ofp, "    %s dword [edx + %d], %d\n", postfix_op == TOK_INCR ? "add" : "sub", offset, step);
+                } else {
+                    fprintf (state->ofp, "    %s dword ptr [edx + %d], %d\n", postfix_op == TOK_INCR ? "add" : "sub", offset, step);
+                }
+            
+            } else {
+                fprintf (state->ofp, "    %sl $%d, %d(%%edx)\n", postfix_op == TOK_INCR ? "add" : "sub", step, offset);
+            }
+        
+        }
+        
+        emit_push_reg_now ("ecx");
+        
+        if (op == TOK_ASSIGN) {
+            emit_load_assignment_rhs_expression_to_reg ("eax");
+        } else {
+        
+            emit_load_member_from_addr_reg_now ("eax", "edx", 0, deref_size);
+            emit_push_reg_now ("eax");
+            emit_load_assignment_rhs_expression_to_reg ("edx");
+            emit_pop_reg_now ("eax");
+            emit_assignment_binary_op (op, 0);
+        
+        }
+        
+        emit_pop_reg_now ("edx");
+        emit_store_reg_to_deref_reg_now ("edx", "eax", deref_size);
+    
+    } else {
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+    }
+    
+    expect_semi_or_recover ();
+    
+    free (name);
+    return 1;
+
+}
+
+static int paren_text_starts_type_name_now (void) {
+
+    const char *p;
+    
+    char name[128];
+    int n = 0;
+    
+    if (tok.caret) {
+        p = tok.caret;
+    } else if (tok.start) {
+        p = tok.start;
+    } else {
+        return 0;
+    }
+    
+    if (*p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p == '(') {
+    
+        p++;
+        
+        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 == '_') && n < (int) sizeof (name) - 1) {
+        name[n++] = *p++;
+    }
+    
+    name[n] = '\0';
+    
+    if (strcmp (name, "char") == 0 || strcmp (name, "short") == 0 ||
+        strcmp (name, "int") == 0 || strcmp (name, "long") == 0 ||
+        strcmp (name, "signed") == 0 || strcmp (name, "unsigned") == 0 ||
+        strcmp (name, "void") == 0 || strcmp (name, "struct") == 0 ||
+        strcmp (name, "union") == 0 || strcmp (name, "enum") == 0) {
+        return 1;
+    }
+    
+    return find_typedef_name (name) != 0;
+
+}
+
+static int parse_cast_indirect_assignment_statement (void) {
+
+    int saved_type_size = parsed_type_size;
+    int saved_storage_class = parsed_storage_class;
+    int saved_is_aggregate = parsed_type_is_aggregate;
+    int saved_is_void = parsed_type_is_void;
+    int saved_is_unsigned = parsed_type_is_unsigned;
+    int saved_is_floating = parsed_type_is_floating;
+    int saved_has_tag = parsed_type_has_tag;
+    int saved_is_inline = parsed_type_is_inline;
+    int saved_field_count = parsed_field_count;
+    int saved_fields[MAX_AGG_FIELDS];
+    int saved_declarator_is_pointer = declarator_is_pointer;
+    int saved_declarator_pointer_depth = declarator_pointer_depth;
+    int saved_declarator_has_array = declarator_has_array;
+    int saved_declarator_has_function = declarator_has_function;
+    int saved_declarator_array_unsized = declarator_array_unsized;
+    int saved_declarator_array_dimensions = declarator_array_dimensions;
+    
+    long saved_declarator_first_array_count = declarator_first_array_count;
+    long saved_declarator_array_count = declarator_array_count;
+    
+    char *cast_name = 0;
+    int base_size;
+    int deref_size;
+    int pointer_depth;
+    int i;
+    
+    enum token_kind op;
+    int has_outer_paren = 0;
+    
+    if (tok.kind != TOK_LPAREN) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    /*
+     * Accept the common casted-dereference lvalue spelling:
+     *
+     *     *((char *)ptr + n) = v;
+     *
+     * parse_indirect_assignment_statement() enters here at the outer '(';
+     * the actual cast type begins after the inner '('.
+     */
+    if (tok.kind == TOK_LPAREN) {
+    
+        has_outer_paren = 1;
+        get_token ();
+    
+    }
+    
+    if (!is_type_start (tok.kind)) {
+        return 0;
+    }
+    
+    for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
+        saved_fields[i] = parsed_field_sizes[i];
+    }
+    
+    parse_type_spec ();
+    base_size = parsed_type_size & 0x1f;
+    
+    if (tok.kind != TOK_RPAREN) {
+        parse_declarator (&cast_name);
+    }
+    
+    pointer_depth = declarator_is_pointer ? (declarator_pointer_depth > 0 ? declarator_pointer_depth : 1) : 0;
+    deref_size = pointer_depth > 1 ? (DATA_PTR & 0x1f) : base_size;
+    
+    if (deref_size <= 0) {
+        deref_size = DATA_INT & 0x1f;
+    }
+    
+    if (cast_name) {
+        free (cast_name);
+    }
+    
+    expect (TOK_RPAREN, ")");
+    
+    parsed_type_size = saved_type_size;
+    parsed_storage_class = saved_storage_class;
+    parsed_type_is_aggregate = saved_is_aggregate;
+    parsed_type_is_void = saved_is_void;
+    parsed_type_is_unsigned = saved_is_unsigned;
+    parsed_type_is_floating = saved_is_floating;
+    parsed_type_has_tag = saved_has_tag;
+    parsed_type_is_inline = saved_is_inline;
+    
+    clear_parsed_fields ();
+    
+    for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
+        parsed_field_sizes[i] = saved_fields[i];
+    }
+    
+    parsed_field_count = saved_field_count;
+    
+    declarator_is_pointer = saved_declarator_is_pointer;
+    declarator_pointer_depth = saved_declarator_pointer_depth;
+    declarator_has_array = saved_declarator_has_array;
+    declarator_has_function = saved_declarator_has_function;
+    declarator_array_unsized = saved_declarator_array_unsized;
+    declarator_array_count = saved_declarator_array_count;
+    declarator_first_array_count = saved_declarator_first_array_count;
+    declarator_array_dimensions = saved_declarator_array_dimensions;
+    
+    if (state->ofp) {
+    
+        /*
+         * Parse the address expression inside the outer dereference without
+         * allowing the first operand parser to consume the assignment operator.
+         *
+         * For:
+         *
+         *     *(size_t *)ptr = size;
+         *
+         * emit_load_assignment_rhs_to_reg() sees the identifier "ptr" followed
+         * by '=' and treats it as an assignment expression, generating
+         * "ptr = size" instead of using ptr as the destination address.  Load a
+         * plain identifier operand directly, then let the explicit '+'/'-' loop
+         * below handle the casted pointer arithmetic case:
+         *
+         *     *((char *)ptr + *actualRead) = '\n';
+         */
+        if (tok.kind == TOK_IDENT) {
+        
+            char *addr_name = xstrdup (tok.ident);
+            
+            const char *addr_start = tok.start;
+            const char *addr_caret = tok.caret;
+            
+            unsigned long addr_line = get_line_number ();
+            
+            struct local_symbol *addr_sym;
+            int addr_global_index;
+            
+            get_token ();
+            
+            addr_sym = find_local_symbol (addr_name);
+            addr_global_index = find_global_symbol (addr_name);
+            
+            if (addr_sym) {
+            
+                if (addr_sym->is_static && addr_sym->static_label) {
+                    emit_load_global_to_reg ("edx", addr_sym->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg ("edx", addr_sym->offset, DATA_PTR);
+                }
+            
+            } else if (addr_global_index >= 0) {
+                emit_load_global_to_reg ("edx", addr_name, DATA_PTR);
+            } else {
+                report_line_at (get_filename (), addr_line, REPORT_ERROR, addr_start, addr_caret, "unknown symbol '%s'", addr_name);
+            }
+            
+            free (addr_name);
+        
+        } else {
+            emit_load_assignment_rhs_to_reg ("edx");
+        }
+        
+        while (tok.kind == TOK_PLUS || tok.kind == TOK_MINUS) {
+        
+            enum token_kind addr_op = tok.kind;
+            get_token ();
+            
+            emit_push_reg_now ("edx");
+            emit_load_assignment_rhs_to_reg ("eax");
+            
+            if (deref_size > 1) {
+                emit_scale_reg_by_const_now ("eax", deref_size);
+            }
+            
+            emit_pop_reg_now ("edx");
+            
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                fprintf (state->ofp, "    %s edx, eax\n", addr_op == TOK_PLUS ? "add" : "sub");
+            } else {
+                fprintf (state->ofp, "    %sl %%eax, %%edx\n", addr_op == TOK_PLUS ? "add" : "sub");
+            }
+        
+        }
+    
+    } else {
+        skip_balanced_until (TOK_RPAREN, TOK_SEMI, TOK_EOF);
+    }
+    
+    if (has_outer_paren) {
+        expect (TOK_RPAREN, ")");
+    }
+    
+    if (!is_assignment_operator (tok.kind)) {
+    
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        
+        expect_semi_or_recover ();
+        return 1;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    if (op == TOK_ASSIGN) {
+    
+        emit_push_reg_now ("edx");
+        emit_load_assignment_rhs_expression_to_reg ("eax");
+        emit_pop_reg_now ("edx");
+    
+    } else {
+    
+        emit_push_reg_now ("edx");
+        emit_load_deref_reg_now ("eax", deref_size);
+        emit_push_reg_now ("eax");
+        emit_load_assignment_rhs_expression_to_reg ("edx");
+        emit_pop_reg_now ("eax");
+        emit_assignment_binary_op (op, 0);
+        emit_pop_reg_now ("edx");
+    
+    }
+    
+    emit_store_reg_to_deref_reg_now ("edx", "eax", deref_size);
+    expect_semi_or_recover ();
+    
+    return 1;
+
+}
+
+static int lparen_expression_starts_with_star_now (void) {
+
+    const char *p;
+    
+    if (tok.kind != TOK_LPAREN || !tok.caret) {
+        return 0;
+    }
+    
+    p = tok.caret + 1;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '*';
+
+}
+
+static int parse_parenthesized_indirect_assignment_statement (void) {
+
+    enum token_kind op;
+    
+    int pointer_depth;
+    int pointed_size;
+    int deref_size = DATA_INT & 0x1f;
+    
+    if (tok.kind != TOK_LPAREN) {
+        return 0;
+    }
+    
+    get_token ();
+    emit_load_assignment_rhs_expression_to_reg ("edx");
+    
+    pointer_depth = rhs_last_pointer_depth;
+    pointed_size = rhs_last_pointed_size;
+    
+    if (pointer_depth > 1) {
+        deref_size = DATA_PTR & 0x1f;
+    } else if (pointer_depth == 1 && pointed_size > 0) {
+        deref_size = pointed_size & 0x1f;
+    }
+    
+    if (deref_size <= 0) {
+        deref_size = DATA_INT & 0x1f;
+    }
+    
+    expect (TOK_RPAREN, ")");
+    
+    if (!is_assignment_operator (tok.kind)) {
+    
+        expect_semi_or_recover ();
+        return 1;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    if (op == TOK_ASSIGN) {
+    
+        emit_push_reg_now ("edx");
+        
+        emit_load_assignment_rhs_expression_to_reg ("eax");
+        emit_pop_reg_now ("edx");
+    
+    } else {
+    
+        emit_push_reg_now ("edx");
+        
+        emit_load_deref_reg_now ("eax", deref_size);
+        emit_push_reg_now ("eax");
+        
+        emit_load_assignment_rhs_expression_to_reg ("edx");
+        emit_pop_reg_now ("eax");
+        
+        emit_assignment_binary_op (op, 0);
+        emit_pop_reg_now ("edx");
+    
+    }
+    
+    emit_store_reg_to_deref_reg_now ("edx", "eax", deref_size);
+    expect_semi_or_recover ();
+    
+    return 1;
+
+}
+
+static int parse_indirect_assignment_statement (void) {
+
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    struct local_symbol *lhs;
+    
+    int deref_size = DATA_INT & 0x1f;
+    int deref_is_floating = 0;
+    
+    enum token_kind op;
+    int global_index;
+    
+    if (tok.kind != TOK_STAR) {
+        return 0;
+    }
+    
+    if (emit_store_to_deref_parenthesized_deref_postfix_incdec_now ("eax")) {
+    
+        expect_semi_or_recover ();
+        return 1;
+    
+    }
+    
+    get_token ();
+    
+    if (tok.kind == TOK_STAR) {
+    
+        get_token ();
+        
+        if (tok.kind == TOK_IDENT) {
+        
+            name = xstrdup (tok.ident);
+            
+            name_start = tok.start;
+            name_caret = tok.caret;
+            
+            name_line = get_line_number ();
+            get_token ();
+            
+            if (is_assignment_operator (tok.kind)) {
+            
+                op = tok.kind;
+                get_token ();
+                
+                lhs = find_local_symbol (name);
+                global_index = find_global_symbol (name);
+                
+                if (!lhs && global_index < 0) {
+                
+                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+                    
+                    skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                    expect_semi_or_recover ();
+                    
+                    free (name);
+                    return 1;
+                
+                }
+                
+                if (lhs) {
+                
+                    if (lhs->pointer_depth > 2) {
+                        deref_size = DATA_PTR & 0x1f;
+                    } else if (lhs->pointer_depth == 2) {
+                        deref_size = lhs->pointed_size & 0x1f;
+                    }
+                
+                } else {
+                
+                    if (get_global_symbol_pointer_depth (name) > 2) {
+                        deref_size = DATA_PTR & 0x1f;
+                    } else if (get_global_symbol_pointer_depth (name) == 2) {
+                        deref_size = get_global_symbol_pointed_size (name) & 0x1f;
+                    }
+                
+                }
+                
+                if (deref_size <= 0) {
+                    deref_size = DATA_INT & 0x1f;
+                }
+                
+                if (state->ofp) {
+                
+                    if (lhs) {
+                    
+                        if (lhs->is_static && lhs->static_label) {
+                            emit_load_global_to_reg ("ecx", lhs->static_label, DATA_PTR);
+                        } else {
+                            emit_load_local_to_reg ("ecx", lhs->offset, DATA_PTR);
+                        }
+                    
+                    } else {
+                        emit_load_global_to_reg ("ecx", name, DATA_PTR);
+                    }
+                    
+                    emit_load_deref_reg_now ("ecx", DATA_PTR & 0x1f);
+                    
+                    if (op == TOK_ASSIGN) {
+                    
+                        emit_push_reg_now ("ecx");
+                        
+                        emit_load_assignment_rhs_expression_to_reg ("eax");
+                        emit_pop_reg_now ("ecx");
+                    
+                    } else {
+                    
+                        emit_push_reg_now ("ecx");
+                        
+                        emit_load_member_from_addr_reg_now ("eax", "ecx", 0, deref_size);
+                        emit_push_reg_now ("eax");
+                        
+                        emit_load_assignment_rhs_expression_to_reg ("edx");
+                        emit_pop_reg_now ("eax");
+                        
+                        emit_assignment_binary_op (op, 0);
+                        emit_pop_reg_now ("ecx");
+                    
+                    }
+                    
+                    emit_store_reg_to_deref_reg_now ("ecx", "eax", deref_size);
+                
+                } else {
+                    skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                }
+                
+                expect_semi_or_recover ();
+                
+                free (name);
+                return 1;
+            
+            }
+            
+            free (name);
+        
+        }
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        
+        expect_semi_or_recover ();
+        return 1;
+    
+    }
+    
+    if (tok.kind != TOK_IDENT) {
+    
+        if (tok.kind == TOK_LPAREN) {
+        
+            if (paren_text_starts_type_name_now () ||
+                (tok.start && tok.start[0] == '(' && tok.start[1] == '(')) {
+                return parse_cast_indirect_assignment_statement ();
+            }
+            
+            if (lparen_expression_starts_with_star_now ()) {
+                return parse_parenthesized_pointer_member_indirect_assignment_statement ();
+            }
+            
+            return parse_parenthesized_indirect_assignment_statement ();
+        
+        }
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    get_token ();
+    
+    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+    
+        enum token_kind postfix_op = tok.kind;
+        int step = 1;
+        
+        get_token ();
+        
+        if (!is_assignment_operator (tok.kind)) {
+        
+            free (name);
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect_semi_or_recover ();
+            
+            return 1;
+        
+        }
+        
+        op = tok.kind;
+        get_token ();
+        
+        lhs = find_local_symbol (name);
+        global_index = find_global_symbol (name);
+        
+        if (!lhs && global_index < 0) {
+        
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        if (lhs) {
+        
+            if (lhs->pointer_depth > 1) {
+            
+                deref_size = DATA_PTR & 0x1f;
+                step = DATA_PTR & 0x1f;
+            
+            } else if (lhs->pointer_depth == 1) {
+            
+                deref_size = lhs->pointed_size & 0x1f;
+                step = lhs->pointed_size > 0 ? lhs->pointed_size : 1;
+            
+            }
+        
+        } else {
+            
+            if (get_global_symbol_pointer_depth (name) > 1) {
+            
+                deref_size = DATA_PTR & 0x1f;
+                step = DATA_PTR & 0x1f;
+            
+            } else if (get_global_symbol_pointer_depth (name) == 1) {
+            
+                deref_size = get_global_symbol_pointed_size (name) & 0x1f;
+                step = get_global_symbol_pointed_size (name) > 0 ? get_global_symbol_pointed_size (name) : 1;
+            
+            }
+        
+        }
+        
+        if (deref_size == 0) {
+            deref_size = DATA_INT & 0x1f;
+        }
+        
+        if (state->ofp) {
+        
+            if (lhs) {
+            
+                if (lhs->is_static && lhs->static_label) {
+                    emit_load_global_to_reg ("ecx", lhs->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg ("ecx", lhs->offset, DATA_PTR);
+                }
+            
+            } else {
+                emit_load_global_to_reg ("ecx", name, DATA_PTR);
+            }
+            
+            emit_push_reg_now ("ecx");
+            
+            if (lhs) {
+            
+                if (lhs->is_static && lhs->static_label) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s dword [%s], %d\n" : "    %s dword ptr [%s], %d\n"), postfix_op == TOK_INCR ? "add" : "sub", lhs->static_label, step);
+                    } else {
+                        fprintf (state->ofp, "    %sl $%d, %s\n", postfix_op == TOK_INCR ? "add" : "sub", step, lhs->static_label);
+                    }
+                
+                } else {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                    
+                        char memref[64];
+                        
+                        format_intel_ebp_offset (memref, sizeof (memref), lhs->offset);
+                        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s dword %s, %d\n" : "    %s dword ptr %s, %d\n"), postfix_op == TOK_INCR ? "add" : "sub", memref, step);
+                    
+                    } else {
+                        fprintf (state->ofp, "    %sl $%d, %ld(%%ebp)\n", postfix_op == TOK_INCR ? "add" : "sub", step, lhs->offset);
+                    }
+                
+                }
+            
+            } else {
+                
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s dword [%s], %d\n" : "    %s dword ptr [%s], %d\n"), postfix_op == TOK_INCR ? "add" : "sub", name, step);
+                } else {
+                    fprintf (state->ofp, "    %sl $%d, %s\n", postfix_op == TOK_INCR ? "add" : "sub", step, name);
+                }
+            
+            }
+            
+            if (op == TOK_ASSIGN) {
+                emit_load_assignment_rhs_expression_to_reg ("eax");
+            } else {
+            
+                emit_pop_reg_now ("edx");
+                emit_push_reg_now ("edx");
+                emit_load_member_from_addr_reg_now ("eax", "edx", 0, deref_size);
+                emit_push_reg_now ("eax");
+                emit_load_assignment_rhs_expression_to_reg ("edx");
+                emit_pop_reg_now ("eax");
+                emit_assignment_binary_op (op, 0);
+            
+            }
+            
+            emit_pop_reg_now ("edx");
+            emit_store_reg_to_deref_reg_now ("edx", "eax", deref_size);
+        
+        } else {
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        }
+        
+        expect_semi_or_recover ();
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+    
+        enum token_kind member_op = tok.kind;
+        enum token_kind postfix_op = TOK_EOF;
+        
+        char *member;
+        
+        const char *member_start;
+        const char *member_caret;
+        
+        unsigned long member_line;
+        
+        int offset = 0;
+        int member_size = DATA_PTR & 0x1f;
+        int member_elem_size = DATA_INT & 0x1f;
+        int member_pointer_depth = 0;
+        int step;
+        
+        get_token ();
+        
+        member_start = tok.start;
+        member_caret = tok.caret;
+        member_line = get_line_number ();
+        
+        if (tok.kind != TOK_IDENT) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        member = xstrdup (tok.ident);
+        get_token ();
+        
+        if (!find_member_info_ex (member, &offset, &member_size, &member_elem_size, &member_pointer_depth, 0, 0)) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect_semi_or_recover ();
+            
+            free (member);
+            free (name);
+            
+            return 1;
+        
+        }
+        
+        free (member);
+        
+        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+        
+            postfix_op = tok.kind;
+            get_token ();
+        
+        }
+        
+        if (!is_assignment_operator (tok.kind)) {
+        
+            free (name);
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect_semi_or_recover ();
+            
+            return 1;
+        
+        }
+        
+        op = tok.kind;
+        get_token ();
+        
+        lhs = find_local_symbol (name);
+        global_index = find_global_symbol (name);
+        
+        if (!lhs && global_index < 0) {
+        
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        if (member_pointer_depth > 1) {
+            deref_size = DATA_PTR & 0x1f;
+        } else if (member_pointer_depth == 1 && member_elem_size > 0) {
+            deref_size = member_elem_size & 0x1f;
+        }
+        
+        if (deref_size == 0) {
+            deref_size = DATA_INT & 0x1f;
+        }
+        
+        step = member_elem_size > 0 ? member_elem_size : 1;
+        
+        if (state->ofp) {
+        
+            if (lhs) {
+            
+                if (member_op == TOK_ARROW) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_global_to_reg ("edx", lhs->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg ("edx", lhs->offset, DATA_PTR);
+                    }
+                
+                } else {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_address_to_reg_now ("edx", lhs->static_label);
+                    } else {
+                        emit_load_local_address_to_reg_now ("edx", lhs->offset);
+                    }
+                
+                }
+            
+            } else {
+            
+                if (member_op == TOK_ARROW) {
+                    emit_load_global_to_reg ("edx", name, DATA_PTR);
+                } else {
+                    emit_load_address_to_reg_now ("edx", name);
+                }
+            
+            }
+            
+            emit_load_member_from_addr_reg_now ("ecx", "edx", offset, DATA_PTR & 0x1f);
+            
+            if (postfix_op == TOK_INCR || postfix_op == TOK_DECR) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    if (state->syntax & ASM_SYNTAX_NASM) {
+                        fprintf (state->ofp, "    %s dword [edx + %d], %d\n", postfix_op == TOK_INCR ? "add" : "sub", offset, step);
+                    } else {
+                        fprintf (state->ofp, "    %s dword ptr [edx + %d], %d\n", postfix_op == TOK_INCR ? "add" : "sub", offset, step);
+                    }
+                
+                } else {
+                    fprintf (state->ofp, "    %sl $%d, %d(%%edx)\n", postfix_op == TOK_INCR ? "add" : "sub", step, offset);
+                }
+            
+            }
+            
+            emit_push_reg_now ("ecx");
+            
+            if (op == TOK_ASSIGN) {
+                emit_load_assignment_rhs_expression_to_reg ("eax");
+            } else {
+            
+                emit_load_member_from_addr_reg_now ("eax", "edx", 0, deref_size);
+                emit_push_reg_now ("eax");
+                emit_load_assignment_rhs_expression_to_reg ("edx");
+                emit_pop_reg_now ("eax");
+                emit_assignment_binary_op (op, 0);
+            
+            }
+            
+            emit_pop_reg_now ("edx");
+            emit_store_reg_to_deref_reg_now ("edx", "eax", deref_size);
+        
+        } else {
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        }
+        
+        expect_semi_or_recover ();
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (!is_assignment_operator (tok.kind)) {
+    
+        free (name);
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        return 1;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    lhs = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (!lhs && global_index < 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (lhs) {
+    
+        if (lhs->pointer_depth > 1) {
+        
+            deref_size = DATA_PTR & 0x1f;
+            deref_is_floating = 0;
+        
+        } else if (lhs->pointer_depth == 1) {
+        
+            /**
+             * Keep aggregate pointed-to sizes intact for assignments like
+             * *hashtab = old_hashtab;  Masking with 0x1f corrupts struct
+             * copies whose size is greater than 31 bytes.
+             */
+            deref_size = lhs->pointed_size;
+            deref_is_floating = lhs->pointed_is_floating;
+        
+        }
+    
+    } else {
+    
+        if (get_global_symbol_pointer_depth (name) > 1) {
+        
+            deref_size = DATA_PTR & 0x1f;
+            deref_is_floating = 0;
+        
+        } else if (get_global_symbol_pointer_depth (name) == 1) {
+        
+            deref_size = get_global_symbol_pointed_size (name);
+            deref_is_floating = get_global_symbol_pointed_is_floating (name);
+        
+        }
+    
+    }
+    
+    if (deref_size == 0) {
+        deref_size = DATA_INT & 0x1f;
+    }
+    
+    if (state->ofp) {
+    
+        if (lhs) {
+        
+            if (lhs->is_static && lhs->static_label) {
+                emit_load_global_to_reg ("edx", lhs->static_label, DATA_PTR);
+            } else {
+                emit_load_local_to_reg ("edx", lhs->offset, DATA_PTR);
+            }
+        
+        } else {
+            emit_load_global_to_reg ("edx", name, DATA_PTR);
+        }
+        
+        if (op == TOK_ASSIGN) {
+        
+            if (deref_is_floating) {
+            
+                emit_push_reg_now ("edx");
+                
+                emit_load_floating_rhs_expression_now (deref_size);
+                emit_pop_reg_now ("edx");
+                
+                emit_store_floating_member_to_addr_reg_now ("edx", 0, deref_size);
+                expect_semi_or_recover ();
+                
+                free (name);
+                return 1;
+            
+            }
+            
+            if (deref_size != (DATA_LLONG & 0x1f) && emit_aggregate_copy_from_current_rhs_to_addr_reg_now ("edx", 0, deref_size)) {
+            
+                expect_semi_or_recover ();
+                
+                free (name);
+                return 1;
+            
+            }
+            
+            emit_push_reg_now ("edx");
+            
+            if (deref_size == (DATA_LLONG & 0x1f)) {
+            
+                emit_load_assignment_rhs_expression_to_pair ("eax", "edx", 1);
+                emit_pop_reg_now ("ecx");
+            
+            } else {
+            
+                emit_load_assignment_rhs_expression_to_reg ("eax");
+                emit_pop_reg_now ("edx");
+            
+            }
+        
+        } else {
+        
+            emit_load_member_from_addr_reg_now ("eax", "edx", 0, deref_size);
+            
+            emit_push_reg_now ("edx");
+            emit_push_reg_now ("eax");
+            
+            emit_load_assignment_rhs_expression_to_reg ("edx");
+            emit_pop_reg_now ("eax");
+            
+            emit_assignment_binary_op (op, 0);
+            emit_pop_reg_now ("edx");
+        
+        }
+        
+        if (deref_size == (DATA_LLONG & 0x1f) && !deref_is_floating) {
+            emit_store_pair_to_deref_reg_now ("ecx", "eax", "edx");
+        } else {
+            emit_store_reg_to_deref_reg_now ("edx", "eax", deref_size);
+        }
+    
+    } else {
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+    }
+    
+    expect_semi_or_recover ();
+    
+    free (name);
+    return 1;
+
+}
+
+static int source_starts_parenthesized_star_now (void) {
+
+    const char *p = tok.caret ? tok.caret : tok.start;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (*p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    return *p == '*';
+
+}
+
+static int parse_parenthesized_indirect_member_assignment_statement (void) {
+
+    enum token_kind member_op;
+    enum token_kind op;
+    
+    char *member;
+    
+    const char *member_start;
+    const char *member_caret;
+    
+    unsigned long member_line;
+    
+    int member_offset = 0;
+    int member_size = DATA_INT & 0x1f;
+    int saw_close = 0;
+    
+    if (tok.kind != TOK_LPAREN || !source_starts_parenthesized_star_now ()) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    if (tok.kind != TOK_STAR) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    /*
+     * Parse only the object expression inside the parenthesized dereference.
+     * For macro-expanded lvalues such as
+     *
+     *     (*(__gtin()))->field = value;
+     *
+     * the normal assignment-expression loader can consume the complete
+     * "->field = value" tail as a value expression.  That emits only
+     * member loads and drops the store.
+     */
+    if (tok.kind == TOK_LPAREN) {
+    
+        int parens = 0;
+        char *inner_name = 0;
+        
+        const char *inner_start = 0;
+        const char *inner_caret = 0;
+        
+        unsigned long inner_line = 0;
+        struct local_symbol *inner_lhs;
+        
+        while (tok.kind == TOK_LPAREN) {
+        
+            parens++;
+            get_token ();
+        
+        }
+        
+        if (tok.kind == TOK_IDENT) {
+        
+            inner_name = xstrdup (tok.ident);
+            inner_start = tok.start;
+            inner_caret = tok.caret;
+            inner_line = get_line_number ();
+            
+            get_token ();
+            
+            if (tok.kind == TOK_LPAREN) {
+                emit_call_identifier_to_reg_now (inner_name, "edx", inner_start, inner_caret, inner_line);
+            } else {
+            
+                inner_lhs = find_local_symbol (inner_name);
+                
+                if (inner_lhs) {
+                
+                    if (inner_lhs->is_static && inner_lhs->static_label) {
+                        emit_load_global_to_reg ("edx", inner_lhs->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg ("edx", inner_lhs->offset, DATA_PTR);
+                    }
+                
+                } else {
+                    emit_load_global_to_reg ("edx", inner_name, DATA_PTR);
+                }
+            
+            }
+            
+            free (inner_name);
+            
+            while (parens > 0 && tok.kind == TOK_RPAREN) {
+            
+                saw_close = 1;
+                parens--;
+                
+                get_token ();
+            
+            }
+        
+        } else {
+            emit_load_assignment_rhs_expression_to_reg ("edx");
+        }
+    
+    } else {
+        emit_load_assignment_rhs_expression_to_reg ("edx");
+    }
+    
+    while (tok.kind == TOK_RPAREN) {
+    
+        saw_close = 1;
+        get_token ();
+    
+    }
+    
+    if (!saw_close) {
+    
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        return 1;
+    
+    }
+    
+    if (tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
+    
+        int deref_size = DATA_INT & 0x1f;
+        int step = 1;
+        
+        if (rhs_last_pointer_depth > 1) {
+        
+            deref_size = DATA_PTR & 0x1f;
+            step = DATA_PTR & 0x1f;
+        
+        } else if (rhs_last_pointer_depth == 1 && rhs_last_pointed_size > 0) {
+            deref_size = rhs_last_pointed_size & 0x1f;
+        }
+        
+        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+        
+            op = tok.kind;
+            get_token ();
+            
+            if (state->ofp) {
+            
+                emit_load_member_from_addr_reg_now ("eax", "edx", 0, deref_size);
+                
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    %s eax, %d\n", op == TOK_INCR ? "add" : "sub", step);
+                } else {
+                    fprintf (state->ofp, "    %sl $%d, %%eax\n", op == TOK_INCR ? "add" : "sub", step);
+                }
+                
+                emit_store_reg_to_deref_reg_now ("edx", "eax", deref_size);
+            
+            }
+            
+            expect_semi_or_recover ();
+            return 1;
+        
+        }
+        
+        if (!is_assignment_operator (tok.kind)) {
+        
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect_semi_or_recover ();
+            
+            return 1;
+        
+        }
+        
+        op = tok.kind;
+        get_token ();
+        
+        if (state->ofp) {
+        
+            if (op == TOK_ASSIGN) {
+            
+                emit_push_reg_now ("edx");
+                emit_load_assignment_rhs_expression_to_reg ("eax");
+                emit_pop_reg_now ("edx");
+            
+            } else {
+            
+                emit_load_member_from_addr_reg_now ("eax", "edx", 0, deref_size);
+                emit_push_reg_now ("edx");
+                emit_push_reg_now ("eax");
+                emit_load_assignment_rhs_expression_to_reg ("edx");
+                emit_pop_reg_now ("eax");
+                emit_assignment_binary_op (op, 0);
+                emit_pop_reg_now ("edx");
+            
+            }
+            
+            emit_store_reg_to_deref_reg_now ("edx", "eax", deref_size);
+        
+        } else {
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        }
+        
+        expect_semi_or_recover ();
+        return 1;
+    
+    }
+    
+    if (state->ofp) {
+        emit_load_deref_reg_now ("edx", DATA_PTR);
+    }
+    
+    member_op = tok.kind;
+    get_token ();
+    
+    member_start = tok.start;
+    member_caret = tok.caret;
+    member_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT) {
+    
+        report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        return 1;
+    
+    }
+    
+    member = xstrdup (tok.ident);
+    get_token ();
+    
+    if (!find_member_info (member, &member_offset, &member_size)) {
+    
+        report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+        free (member);
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        return 1;
+    
+    }
+    
+    free (member);
+    
+    if (!is_assignment_operator (tok.kind)) {
+    
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect_semi_or_recover ();
+        
+        return 1;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    if (state->ofp) {
+    
+        if (op == TOK_ASSIGN) {
+        
+            emit_push_reg_now ("edx");
+            emit_load_assignment_rhs_expression_to_reg ("eax");
+            emit_pop_reg_now ("edx");
+        
+        } else {
+        
+            emit_load_member_from_addr_reg_now ("eax", "edx", member_offset, member_size);
+            emit_push_reg_now ("edx");
+            emit_push_reg_now ("eax");
+            emit_load_assignment_rhs_expression_to_reg ("edx");
+            emit_pop_reg_now ("eax");
+            emit_assignment_binary_op (op, 0);
+            emit_pop_reg_now ("edx");
+        
+        }
+        
+        emit_store_member_to_addr_reg_now ("edx", member_offset, "eax", member_size);
+    
+    } else {
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+    }
+    
+    expect_semi_or_recover ();
+    return 1;
+
+}
+
+static int token_text_looks_like_postfix_call_now (void) {
+
+    const char *p;
+    
+    int saw_postfix;
+    int paren_depth;
+    int bracket_depth;
+    
+    if (tok.caret) {
+        p = tok.caret;
+    } else if (tok.start) {
+        p = tok.start;
+    } else {
+        return 0;
+    }
+    
+    saw_postfix = 0;
+    paren_depth = 0;
+    bracket_depth = 0;
+    
+    while (*p && *p != ';' && *p != '\n') {
+    
+        if (*p == '(') {
+        
+            if (saw_postfix && paren_depth == 0 && bracket_depth == 0) {
+                return 1;
+            }
+            
+            paren_depth++;
+        
+        } else if (*p == ')') {
+        
+            if (paren_depth > 0) {
+                paren_depth--;
+            }
+        
+        } else if (*p == '[') {
+            bracket_depth++;
+        } else if (*p == ']') {
+        
+            if (bracket_depth > 0) {
+                bracket_depth--;
+            }
+        
+        } else if (paren_depth == 0 && bracket_depth == 0 && *p == '.') {
+            saw_postfix = 1;
+        } else if (paren_depth == 0 && bracket_depth == 0 && *p == '-' && p[1] == '>') {
+        
+            saw_postfix = 1;
+            p++;
+        
+        } else if (paren_depth == 0 && bracket_depth == 0 && *p == '=') {
+            return 0;
+        }
+        
+        p++;
+    
+    }
+    
+    return 0;
+
+}
+
+static int parse_parenthesized_deref_subscript_statement (void) {
+
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    struct local_symbol *src;
+    
+    int global_index;
+    int pointer_depth;
+    int pointed_size;
+    
+    if (tok.kind != TOK_LPAREN || !source_starts_lparen_deref_subscript_at (tok.caret)) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    if (tok.kind != TOK_STAR) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
+        return 1;
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    get_token ();
+    
+    expect (TOK_RPAREN, ")");
+    
+    src = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    pointer_depth = 0;
+    pointed_size = DATA_INT & 0x1f;
+    
+    if (src) {
+    
+        pointer_depth = src->pointer_depth;
+        pointed_size = src->pointed_size;
+        
+        if (src->is_static && src->static_label) {
+            emit_load_global_to_reg ("eax", src->static_label, DATA_PTR);
+        } else {
+            emit_load_local_to_reg ("eax", src->offset, DATA_PTR);
+        }
+    
+    } else if (global_index >= 0) {
+    
+        pointer_depth = get_global_symbol_pointer_depth (name);
+        pointed_size = get_global_symbol_pointed_size (name);
+        
+        emit_load_global_to_reg ("eax", name, DATA_PTR);
+    
+    } else {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (pointer_depth <= 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid indirection of non-pointer '%s'", name);
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    emit_load_deref_reg_now ("eax", DATA_PTR & 0x1f);
+    emit_handle_subscript_after_loaded_pointer_to_reg_now ("eax", pointer_depth - 1, pointed_size, src ? src->pointed_is_unsigned : get_global_symbol_pointed_is_unsigned (name));
+    
+    free (name);
+    return 1;
+
+}
+
+static int parse_identifier_assignment_statement (void) {
+
+    char *name;
+    int global_index;
+    
+    const char *name_start, *name_caret;
+    unsigned long name_line;
+    
+    enum token_kind op;
+    struct local_symbol *lhs;
+    
+    int is_simple_assign;
+    int lhs_size;
+    int lhs_is_floating;
+    
+    if (tok.kind != TOK_IDENT) {
+        return 0;
+    }
+    
+    if (token_text_looks_like_postfix_call_now ()) {
+        return 0;
+    }
+    
+    name = xstrdup (tok.ident);
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    get_token ();
+    
+    if (tok.kind == TOK_COLON) {
+    
+        define_goto_label (name, name_line, name_start, name_caret);
+        
+        get_token ();
+        free (name);
+        
+        parse_statement ();
+        return 1;
+    
+    }
+    
+    if (tok.kind == TOK_DOT || tok.kind == TOK_ARROW) {
+    
+        enum token_kind member_op = tok.kind;
+        char *member;
+        
+        const char *member_start;
+        const char *member_caret;
+        
+        unsigned long member_line;
+        
+        int member_offset = 0;
+        int member_size = DATA_INT & 0x1f;
+        int member_elem_size = DATA_INT & 0x1f;
+        int member_pointer_depth = 0;
+        int member_is_floating = 0;
+        int member_assignment_is_floating = 0;
+        
+        get_token ();
+        
+        member_start = tok.start;
+        member_caret = tok.caret;
+        member_line = get_line_number ();
+        
+        if (tok.kind != TOK_IDENT) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        member = xstrdup (tok.ident);
+        get_token ();
+        
+        lhs = find_local_symbol (name);
+        global_index = find_global_symbol (name);
+        
+        if (!find_member_info_ex_bounded (member,
+                member_op == TOK_DOT
+                    ? (lhs ? lhs->size : (global_index >= 0 ? get_global_symbol_size (name) : 0))
+                    : (lhs ? lhs->pointed_size : (global_index >= 0 ? get_global_symbol_pointed_size (name) : 0)),
+                member_op == TOK_DOT
+                    ? (lhs ? lhs->tag_name : (global_index >= 0 ? get_global_symbol_tag_name (name) : 0))
+                    : (lhs ? lhs->pointed_tag_name : 0),
+                &member_offset, &member_size, &member_elem_size, &member_pointer_depth, 0, &member_is_floating)) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+            
+            free (member);
+            free (name);
+            
+            return 1;
+        
+        }
+        
+        free (member);
+        
+        if (!is_assignment_operator (tok.kind)) {
+        
+            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+            
+                enum token_kind postfix_op = tok.kind;
+                int step = member_pointer_depth > 0 && member_elem_size > 0 ? member_elem_size : 1;
+                
+                get_token ();
+                
+                lhs = find_local_symbol (name);
+                global_index = find_global_symbol (name);
+                
+                if (!lhs && global_index < 0) {
+                
+                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+                    
+                    skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                    expect (TOK_SEMI, ";");
+                    
+                    free (name);
+                    return 1;
+                
+                }
+                
+                if (state->ofp) {
+                
+                    if (member_op == TOK_ARROW) {
+                    
+                        if (lhs) {
+                        
+                            if (lhs->is_static && lhs->static_label) {
+                                emit_load_global_to_reg ("edx", lhs->static_label, DATA_PTR);
+                            } else {
+                                emit_load_local_to_reg ("edx", lhs->offset, DATA_PTR);
+                            }
+                        
+                        } else {
+                            emit_load_global_to_reg ("edx", name, DATA_PTR);
+                        }
+                    
+                    } else {
+                    
+                        if (lhs) {
+                        
+                            if (lhs->is_static && lhs->static_label) {
+                                emit_load_address_to_reg_now ("edx", lhs->static_label);
+                            } else {
+                                emit_load_local_address_to_reg_now ("edx", lhs->offset);
+                            }
+                        
+                        } else {
+                            emit_load_address_to_reg_now ("edx", name);
+                        }
+                    
+                    }
+                    
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                    
+                        const char *opname = postfix_op == TOK_INCR ? "add" : "sub";
+                        const char *opsize = member_size == 1 ? "byte" : (member_size == 2 ? "word" : "dword");
+                        
+                        if (state->syntax & ASM_SYNTAX_NASM) {
+                            fprintf (state->ofp, "    %s %s [edx + %d], %d\n", opname, opsize, member_offset, step);
+                        } else {
+                            fprintf (state->ofp, "    %s %s ptr [edx + %d], %d\n", opname, opsize, member_offset, step);
+                        }
+                    
+                    } else {
+                    
+                        const char *suffix = member_size == 1 ? "b" : (member_size == 2 ? "w" : "l");
+                        fprintf (state->ofp, "    %s%s $%d, %d(%%edx)\n", postfix_op == TOK_INCR ? "add" : "sub", suffix, step, member_offset);
+                    
+                    }
+                
+                }
+                
+                expect_semi_or_recover ();
+                
+                free (name);
+                return 1;
+            
+            }
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect (TOK_SEMI, ";");
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        op = tok.kind;
+        
+        is_simple_assign = (tok.kind == TOK_ASSIGN);
+        get_token ();
+        
+        if (!lhs && global_index < 0) {
+        
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect (TOK_SEMI, ";");
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        if (state->ofp) {
+        
+            if (member_op == TOK_ARROW) {
+            
+                if (lhs) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_global_to_reg ("edx", lhs->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg ("edx", lhs->offset, DATA_PTR);
+                    }
+                
+                } else {
+                    emit_load_global_to_reg ("edx", name, DATA_PTR);
+                }
+            
+            } else {
+            
+                if (lhs) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_address_to_reg_now ("edx", lhs->static_label);
+                    } else {
+                        emit_load_local_address_to_reg_now ("edx", lhs->offset);
+                    }
+                
+                } else {
+                    emit_load_address_to_reg_now ("edx", name);
+                }
+            
+            }
+            
+            if (is_simple_assign) {
+            
+                member_assignment_is_floating = member_is_floating || rhs_current_operand_is_floating_now ();
+                emit_push_reg_now ("edx");
+                
+                if (member_assignment_is_floating) {
+                    emit_load_floating_rhs_expression_now (member_size);
+                } else {
+                    emit_load_assignment_rhs_expression_to_reg ("eax");
+                }
+                
+                emit_pop_reg_now ("edx");
+            
+            } else {
+            
+                emit_load_member_from_addr_reg_now ("eax", "edx", member_offset, member_size);
+                
+                emit_push_reg_now ("edx");
+                emit_push_reg_now ("eax");
+                
+                if (tok.kind == TOK_TILDE) {
+                
+                    int64_s rhs_const;
+                    get_token ();
+                    
+                    if (tok.kind == TOK_LPAREN) {
+                    
+                        get_token ();
+                        
+                        rhs_const = const64_from_current_foldable_expr ();
+                        expect (TOK_RPAREN, ")");
+                    
+                    } else {
+                        rhs_const = const64_from_current_foldable_expr ();
+                    }
+                    
+                    rhs_const.low = (~rhs_const.low) & U32_MASK;
+                    rhs_const.high = (~rhs_const.high) & U32_MASK;
+                    
+                    emit_load_const32_to_reg_now ("edx", rhs_const);
+                
+                } else if (current_integer_expr_is_foldable_now ()) {
+                
+                    int64_s rhs_const = const64_from_current_foldable_expr ();
+                    emit_load_const32_to_reg_now ("edx", rhs_const);
+                
+                } else {
+                    emit_load_assignment_rhs_expression_to_reg ("edx");
+                }
+                
+                emit_pop_reg_now ("eax");
+                emit_assignment_binary_op (op, 0);
+                emit_pop_reg_now ("edx");
+            
+            }
+            
+            if (member_assignment_is_floating && 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);
+            }
+        
+        } else {
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        }
+        
+        expect_semi_or_recover ();
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (tok.kind == TOK_LBRACK) {
+    
+        int elem_size = DATA_INT & 0x1f;
+        int elem_pointer_depth = 0;
+        int elem_pointed_size = DATA_INT & 0x1f;
+        
+        lhs = find_local_symbol (name);
+        global_index = find_global_symbol (name);
+        
+        if (!lhs && global_index < 0) {
+        
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        if (lhs) {
+        
+            elem_size = lhs->is_array ? (lhs->pointer_depth ? DATA_PTR : lhs->pointed_size) :
+                (lhs->pointer_depth > 1 ? DATA_PTR : lhs->pointed_size);
+            
+            elem_pointer_depth = lhs->pointer_depth > 0 ? lhs->pointer_depth - 1 : 0;
+            elem_pointed_size = lhs->pointed_size;
+        
+        } else {
+        
+            elem_size = get_global_symbol_array (name) ?
+                (get_global_symbol_pointer_depth (name) ? DATA_PTR : (get_global_symbol_array_element_size (name) > 0 ? get_global_symbol_array_element_size (name) : get_global_symbol_pointed_size (name))) :
+                    (get_global_symbol_pointer_depth (name) > 1 ? DATA_PTR : get_global_symbol_pointed_size (name));
+            
+            elem_pointer_depth = get_global_symbol_pointer_depth (name) > 0 ? get_global_symbol_pointer_depth (name) - 1 : 0;
+            elem_pointed_size = get_global_symbol_pointed_size (name);
+        
+        }
+        
+        if ((elem_size & 0x1f) == 0) {
+            elem_size = DATA_INT & 0x1f;
+        }
+        
+        if (state->ofp) {
+        
+            if (lhs) {
+            
+                if (lhs->is_array) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_symbol_address_to_reg_now ("edx", lhs->static_label, 0, 0);
+                    } else {
+                        emit_load_symbol_address_to_reg_now ("edx", 0, lhs->offset, 1);
+                    }
+                
+                } else if (lhs->is_static && lhs->static_label) {
+                    emit_load_global_to_reg ("edx", lhs->static_label, DATA_PTR);
+                } else {
+                    emit_load_local_to_reg ("edx", lhs->offset, DATA_PTR);
+                }
+            
+            } else if (get_global_symbol_array (name)) {
+                emit_load_symbol_address_to_reg_now ("edx", name, 0, 0);
+            } else {
+                emit_load_global_to_reg ("edx", name, DATA_PTR);
+            }
+            
+            emit_parse_postfix_subscript_scaled_address_to_reg_now ("edx", elem_size);
+        
+        } else {
+            emit_parse_postfix_subscript_scaled_address_to_reg_now ("edx", elem_size);
+        }
+        
+        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+        
+            op = tok.kind;
+            
+            is_simple_assign = (tok.kind == TOK_ASSIGN);
+            get_token ();
+            
+            if (state->ofp) {
+            
+                int inc_amount = (elem_pointer_depth > 0 && (elem_pointed_size & 0x1f) > 0) ?
+                    (elem_pointed_size & 0x1f) : 1;
+                
+                emit_load_member_from_addr_reg_now ("eax", "edx", 0, elem_size);
+                
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    %s eax, %d\n", op == TOK_INCR ? "add" : "sub", inc_amount);
+                } else {
+                    fprintf (state->ofp, "    %sl $%d, %%eax\n", op == TOK_INCR ? "add" : "sub", inc_amount);
+                }
+                
+                emit_store_reg_to_deref_reg_now ("edx", "eax", elem_size);
+            
+            }
+            
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        if (!is_assignment_operator (tok.kind)) {
+        
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        op = tok.kind;
+        
+        is_simple_assign = (tok.kind == TOK_ASSIGN);
+        get_token ();
+        
+        if (state->ofp) {
+        
+            if (is_simple_assign) {
+            
+                emit_push_reg_now ("edx");
+                emit_load_assignment_rhs_expression_to_reg ("eax");
+                emit_pop_reg_now ("edx");
+            
+            } else {
+            
+                emit_load_member_from_addr_reg_now ("eax", "edx", 0, elem_size);
+                emit_push_reg_now ("edx");
+                emit_push_reg_now ("eax");
+                emit_load_assignment_rhs_expression_to_reg ("edx");
+                emit_pop_reg_now ("eax");
+                emit_assignment_binary_op (op, 0);
+                emit_pop_reg_now ("edx");
+            
+            }
+            
+            emit_store_reg_to_deref_reg_now ("edx", "eax", elem_size);
+        
+        } else {
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        }
+        
+        expect_semi_or_recover ();
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (!is_assignment_operator (tok.kind)) {
+    
+        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);
+            emit_incdec_symbol_now (lhs, name, op, name_line, name_start, name_caret);
+            
+            expect_semi_or_recover ();
+            free (name);
+            
+            return 1;
+        
+        }
+        
+        if (tok.kind == TOK_LPAREN) {
+        
+            if (!find_local_symbol (name)) {
+                ensure_global_function_symbol (name, name_start, name_caret, name_line);
+            }
+            
+            emit_call_identifier_to_reg_now (name, "eax", name_start, name_caret, name_line);
+            
+            if (tok.kind == TOK_LBRACK) {
+            
+                int elem_size = get_global_symbol_pointed_size (name);
+                
+                if ((elem_size & 0x1f) == 0) {
+                    elem_size = DATA_INT & 0x1f;
+                }
+                
+                if (state->ofp) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    mov edx, eax\n");
+                    } else {
+                        fprintf (state->ofp, "    movl %%eax, %%edx\n");
+                    }
+                
+                }
+                
+                emit_parse_postfix_subscript_scaled_address_to_reg_now ("edx", elem_size);
+                
+                if (is_assignment_operator (tok.kind)) {
+                
+                    op = tok.kind;
+                    
+                    is_simple_assign = (tok.kind == TOK_ASSIGN);
+                    get_token ();
+                    
+                    if (state->ofp) {
+                    
+                        if (is_simple_assign) {
+                        
+                            emit_push_reg_now ("edx");
+                            emit_load_assignment_rhs_expression_to_reg ("eax");
+                            emit_pop_reg_now ("edx");
+                        
+                        } else {
+                        
+                            emit_load_member_from_addr_reg_now ("eax", "edx", 0, elem_size);
+                            emit_push_reg_now ("edx");
+                            emit_push_reg_now ("eax");
+                            emit_load_assignment_rhs_expression_to_reg ("edx");
+                            emit_pop_reg_now ("eax");
+                            emit_assignment_binary_op (op, 0);
+                            emit_pop_reg_now ("edx");
+                        
+                        }
+                        
+                        emit_store_reg_to_deref_reg_now ("edx", "eax", elem_size);
+                    
+                    } else {
+                        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                    }
+                    
+                    expect_semi_or_recover ();
+                    
+                    free (name);
+                    return 1;
+                
+                }
+            
+            }
+            
+            if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
+            
+                enum token_kind member_op = tok.kind;
+                char *member;
+                
+                const char *member_start;
+                const char *member_caret;
+                
+                unsigned long member_line;
+                
+                int member_offset = 0;
+                int member_size = DATA_PTR & 0x1f;
+                
+                get_token ();
+                
+                member_start = tok.start;
+                member_caret = tok.caret;
+                member_line = get_line_number ();
+                
+                if (tok.kind != TOK_IDENT) {
+                
+                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+                    
+                    skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                    expect_semi_or_recover ();
+                    
+                    free (name);
+                    return 1;
+                
+                }
+                
+                member = xstrdup (tok.ident);
+                get_token ();
+                
+                if (!find_member_info (member, &member_offset, &member_size)) {
+                
+                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+                    free (member);
+                    
+                    skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                    expect_semi_or_recover ();
+                    
+                    free (name);
+                    return 1;
+                
+                }
+                
+                free (member);
+                
+                if (member_op == TOK_DOT && state->ofp) {
+                    emit_load_deref_reg_now ("eax", DATA_PTR);
+                }
+                
+                if (is_assignment_operator (tok.kind)) {
+                
+                    op = tok.kind;
+                    
+                    is_simple_assign = (tok.kind == TOK_ASSIGN);
+                    get_token ();
+                    
+                    if (state->ofp) {
+                    
+                        if (state->syntax & ASM_SYNTAX_INTEL) {
+                            fprintf (state->ofp, "    mov edx, eax\n");
+                        } else {
+                            fprintf (state->ofp, "    movl %%eax, %%edx\n");
+                        }
+                        
+                        if (is_simple_assign) {
+                        
+                            emit_push_reg_now ("edx");
+                            emit_load_assignment_rhs_expression_to_reg ("eax");
+                            emit_pop_reg_now ("edx");
+                        
+                        } else {
+                        
+                            emit_load_member_from_addr_reg_now ("eax", "edx", member_offset, member_size);
+                            emit_push_reg_now ("edx");
+                            emit_push_reg_now ("eax");
+                            emit_load_assignment_rhs_expression_to_reg ("edx");
+                            emit_pop_reg_now ("eax");
+                            emit_assignment_binary_op (op, 0);
+                            emit_pop_reg_now ("edx");
+                        
+                        }
+                        
+                        emit_store_member_to_addr_reg_now ("edx", member_offset, "eax", member_size);
+                    
+                    } else {
+                        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                    }
+                    
+                    expect_semi_or_recover ();
+                    free (name);
+                    
+                    return 1;
+                
+                }
+                
+                if (tok.kind == TOK_LPAREN) {
+                
+                    enum token_kind member_calling_convention = last_found_member_calling_convention;
+                    
+                    FILE **arg_tmp_ofps = 0;
+                    FILE **new_arg_tmp_ofps;
+                    FILE *arg_tmp_ofp;
+                    FILE *arg_saved_ofp;
+                    
+                    int argc = 0;
+                    int i;
+                    int ch;
+                    int total_arg_bytes = 0;
+                    
+                    if (state->ofp) {
+                    
+                        emit_load_member_from_addr_reg_now ("ecx", "eax", member_offset, DATA_PTR & 0x1f);
+                        emit_push_reg_now ("ecx");
+                    
+                    }
+                    
+                    get_token ();
+                    
+                    if (tok.kind != TOK_RPAREN) {
+                    
+                        for (;;) {
+                        
+                            arg_tmp_ofp = 0;
+                            arg_saved_ofp = 0;
+                            
+                            if (state->ofp) {
+                            
+                                arg_tmp_ofp = scc_tmpfile ();
+                                
+                                if (arg_tmp_ofp) {
+                                    arg_saved_ofp = state->ofp;
+                                    state->ofp = arg_tmp_ofp;
+                                }
+                            
+                            }
+                            
+                            emit_load_assignment_rhs_expression_to_reg ("eax");
+                            
+                            if (state->ofp) {
+                                emit_push_reg_now ("eax");
+                            }
+                            
+                            if (arg_saved_ofp) {
+                            
+                                fflush (arg_tmp_ofp);
+                                state->ofp = arg_saved_ofp;
+                                
+                                new_arg_tmp_ofps = (FILE **) xrealloc (arg_tmp_ofps, sizeof (*arg_tmp_ofps) * (argc + 1));
+                                
+                                if (new_arg_tmp_ofps) {
+                                
+                                    arg_tmp_ofps = new_arg_tmp_ofps;
+                                    arg_tmp_ofps[argc] = arg_tmp_ofp;
+                                    arg_tmp_ofp = 0;
+                                
+                                }
+                            
+                            }
+                            
+                            if (arg_tmp_ofp) {
+                                scc_close (arg_tmp_ofp);
+                            }
+                            
+                            argc++;
+                            total_arg_bytes += DATA_PTR & 0x1f;
+                            
+                            if (!_accept (TOK_COMMA)) {
+                                break;
+                            }
+                        
+                        }
+                    
+                    }
+                    
+                    expect (TOK_RPAREN, ")");
+                    
+                    if (state->ofp) {
+                    
+                        for (i = argc - 1; i >= 0; i--) {
+                        
+                            if (arg_tmp_ofps && arg_tmp_ofps[i]) {
+                            
+                                fseek (arg_tmp_ofps[i], 0, SEEK_SET);
+                                
+                                while ((ch = fgetc (arg_tmp_ofps[i])) != EOF) {
+                                    fputc (ch, state->ofp);
+                                }
+                                
+                                scc_close (arg_tmp_ofps[i]);
+                                arg_tmp_ofps[i] = 0;
+                            
+                            }
+                        
+                        }
+                        
+                        if (arg_tmp_ofps) {
+                        
+                            free (arg_tmp_ofps);
+                            arg_tmp_ofps = 0;
+                        
+                        }
+                        
+                        if (state->syntax & ASM_SYNTAX_INTEL) {
+                        
+                            if (state->syntax & ASM_SYNTAX_NASM) {
+                                fprintf (state->ofp, "    mov ecx, dword [esp + %d]\n", total_arg_bytes);
+                            } else {
+                                fprintf (state->ofp, "    mov ecx, dword ptr [esp + %d]\n", total_arg_bytes);
+                            }
+                            
+                            fprintf (state->ofp, "    call ecx\n");
+                            
+                            if (member_calling_convention == TOK_STDCALL) {
+                                fprintf (state->ofp, "    add esp, %d\n", (DATA_PTR & 0x1f));
+                            } else {
+                                fprintf (state->ofp, "    add esp, %d\n", total_arg_bytes + (DATA_PTR & 0x1f));
+                            }
+                        
+                        } else {
+                        
+                            fprintf (state->ofp, "    movl %d(%%esp), %%ecx\n", total_arg_bytes);
+                            fprintf (state->ofp, "    call *%%ecx\n");
+                            
+                            if (member_calling_convention == TOK_STDCALL) {
+                                fprintf (state->ofp, "    addl $%d, %%esp\n", (DATA_PTR & 0x1f));
+                            } else {
+                                fprintf (state->ofp, "    addl $%d, %%esp\n", total_arg_bytes + (DATA_PTR & 0x1f));
+                            }
+                        
+                        }
+                    
+                    }
+                    
+                    expect_semi_or_recover ();
+                    free (name);
+                    
+                    return 1;
+                
+                }
+                
+                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+                
+                expect_semi_or_recover ();
+                free (name);
+                
+                return 1;
+            
+            }
+            
+            expect_semi_or_recover ();
+            free (name);
+            
+            return 1;
+        
+        }
+        
+        if (!find_local_symbol (name) && find_global_symbol (name) < 0) {
+        
+            int64_s ignored;
+            
+            if (!resolve_enum_constant (name, &ignored)) {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            }
+        
+        }
+        
+        free (name);
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect (TOK_SEMI, ";");
+        
+        return 1;
+    
+    }
+    
+    op = tok.kind;
+    
+    is_simple_assign = (tok.kind == TOK_ASSIGN);
+    get_token ();
+    
+    lhs = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (!lhs && global_index < 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect (TOK_SEMI, ";");
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (state->ofp) {
+    
+        lhs_size = lhs ? lhs->size : get_global_symbol_size (name);
+        lhs_is_floating = lhs ? lhs->is_floating : get_global_symbol_floating (name);
+        
+        if (is_simple_assign && lhs_size > (DATA_LLONG & 0x1f) && tok.kind == TOK_IDENT) {
+            
+            char *rhs_name = xstrdup (tok.ident);
+            
+            struct local_symbol *rhs_sym;
+            int rhs_global_index;
+            
+            get_token ();
+            
+            rhs_sym = find_local_symbol (rhs_name);
+            rhs_global_index = find_global_symbol (rhs_name);
+            
+            if (rhs_sym || rhs_global_index >= 0) {
+            
+                if (tok.kind == TOK_LPAREN && rhs_global_index >= 0 && get_global_symbol_kind (rhs_name) == GLOBAL_SYMBOL_FUNCTION) {
+                
+                    pending_struct_return_lhs = lhs;
+                    pending_struct_return_global_name = lhs ? 0 : name;
+                    
+                    emit_call_identifier_to_reg_now (rhs_name, "eax", name_start, name_caret, name_line);
+                
+                } else if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT || tok.kind == TOK_LBRACK) {
+                
+                    if (emit_parse_postfix_copy_source_address_now ("eax", rhs_sym, rhs_name, name_start, name_caret, name_line)) {
+                    
+                        emit_load_symbol_address_for_copy_now ("edx", lhs, name);
+                        emit_copy_fixed_size_now (lhs_size);
+                    
+                    }
+                
+                } else {
+                    emit_memcpy_symbol_to_symbol_now (lhs, name, rhs_sym, rhs_name, lhs_size);
+                }
+            
+            } else {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", rhs_name);
+            }
+            
+            free (rhs_name);
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        if (lhs_is_floating) {
+        
+            if (!floating_assignment_operator_supported_now (op)) {
+            
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid operands to floating assignment operator");
+                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            
+            } else {
+            
+                if (is_simple_assign) {
+                    emit_load_floating_rhs_expression_now (lhs_size);
+                } else {
+                
+                    emit_load_floating_symbol_now (lhs, name, lhs_size);
+                    emit_load_floating_rhs_expression_now (lhs_size);
+                    emit_floating_binary_now (op);
+                
+                }
+                
+                emit_store_floating_symbol_now (lhs, name, lhs_size);
+            
+            }
+        
+        } else if (lhs_size == (DATA_LLONG & 0x1f)) {
+        
+            if (is_simple_assign) {
+                emit_load_assignment_rhs_expression_to_pair ("eax", "edx", lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
+            } else {
+            
+                if (lhs) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_global64_to_pair ("eax", "edx", lhs->static_label);
+                    } else {
+                        emit_load_local64_to_pair (lhs->offset, "eax", "edx");
+                    }
+                
+                } else {
+                    emit_load_global64_to_pair ("eax", "edx", name);
+                }
+                
+                /*
+                 * Compound assignments need the complete RHS expression.
+                 * Using emit_load_assignment_rhs_to_pair() only consumes one
+                 * primary operand, so e.g.
+                 *
+                 *     final_value += symbol->frag->address + left_value;
+                 *
+                 * leaves the second + operand for the statement parser and
+                 * reports "expected ;".  Evaluate the full RHS in eax:edx,
+                 * copy it to the RHS pair ebx:ecx, then restore the original
+                 * LHS value before applying the compound operator.
+                 */
+                emit_push_reg_now ("eax");
+                emit_push_reg_now ("edx");
+                
+                emit_load_assignment_rhs_expression_to_pair ("eax", "edx", lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
+                
+                emit_mov_reg_to_reg_now ("ebx", "eax");
+                emit_mov_reg_to_reg_now ("ecx", "edx");
+                
+                emit_pop_reg_now ("edx");
+                emit_pop_reg_now ("eax");
+                
+                emit_preserve_assignment64_regs (op);
+                emit_assignment_binary_op64 (op, lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
+                emit_restore_assignment64_regs (op);
+            
+            }
+            
+            if (lhs) {
+            
+                if (lhs->is_static && lhs->static_label) {
+                    emit_store_pair_to_global64 (lhs->static_label, "eax", "edx");
+                } else {
+                    emit_store_pair_to_local64 (lhs->offset, "eax", "edx");
+                }
+            
+            } else {
+                emit_store_pair_to_global64 (name, "eax", "edx");
+            }
+        
+        } else {
+        
+            if (is_simple_assign) {
+                emit_load_assignment_rhs_expression_to_reg ("eax");
+            } else {
+            
+                if (lhs) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_global_to_reg_ex ("eax", lhs->static_label, lhs->size, lhs->is_unsigned);
+                    } else {
+                        emit_load_local_to_reg_ex ("eax", lhs->offset, lhs->size, lhs->is_unsigned);
+                    }
+                
+                } else {
+                    emit_load_global_to_reg ("eax", name, lhs_size);
+                }
+                
+                /*
+                 * Compound assignments still need the full RHS expression,
+                 * not just a single operand.  Otherwise cases such as:
+                 *
+                 *     processed += (int)(t - stream->upto) - 1;
+                 *
+                 * leave the trailing "- 1" unconsumed and the statement
+                 * parser reports "expected ;".  Preserve the current LHS
+                 * value in eax while the RHS expression is parsed, because
+                 * RHS binary-expression code may use eax internally even
+                 * when the requested result register is edx.
+                 */
+                emit_push_reg_now ("eax");
+                emit_load_assignment_rhs_expression_to_reg ("edx");
+                
+                emit_scale_reg_for_pointer_compound_assignment_now ("edx", lhs, name, op);
+                emit_pop_reg_now ("eax");
+                
+                emit_assignment_binary_op (op, lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
+            
+            }
+            
+            if (lhs) {
+            
+                if (lhs->is_static && lhs->static_label) {
+                    emit_store_reg_to_global (lhs->static_label, lhs->size, "eax");
+                } else {
+                    emit_store_reg_to_local (lhs->offset, lhs->size, "eax");
+                }
+            
+            } else {
+                emit_store_reg_to_global (name, lhs_size, "eax");
+            }
+        
+        }
+    
+    } else {
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+    }
+    
+    expect_semi_or_recover ();
+    
+    free (name);
+    return 1;
+
+}
+
+static void emit_statement_label_raw (int label) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+        fprintf (state->ofp, "L%d:\n", label);
+    } else {
+        fprintf (state->ofp, ".L%d:\n", label);
+    }
+
+}
+
+static void flush_pending_statement_labels (void) {
+
+    int i;
+    int count = pending_statement_label_count;
+    
+    /**
+     * A queued case/default/C label marks the next statement.  If the
+     * previous statement was a return, its jump to the common epilogue may
+     * still be pending.  Emit that jump before placing the next label,
+     * otherwise the label lands between the return value setup and the
+     * deferred jump.
+     *
+     * Also flush the deferred return before any other emitted control-flow
+     * boundary even when there are no queued labels.  A switch body is emitted
+     * into a temporary stream and then replayed before the switch break label;
+     * if the last case returns, there may be no following case/default label to
+     * force this flush.
+     */
+    if (pending_return_jump) {
+        emit_pending_return_jump ();
+    }
+    
+    if (count <= 0) {
+        return;
+    }
+    
+    pending_statement_label_count = 0;
+    
+    for (i = 0; i < count; i++) {
+        emit_statement_label_raw (pending_statement_labels[i]);
+    }
+
+}
+
+static void emit_statement_label (int label) {
+
+    flush_pending_statement_labels ();
+    emit_statement_label_raw (label);
+
+}
+
+static void emit_statement_jump (int label) {
+
+    flush_pending_statement_labels ();
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+        fprintf (state->ofp, "    jmp L%d\n", label);
+    } else {
+        fprintf (state->ofp, "    jmp .L%d\n", label);
+    }
+
+}
+
+static int token_is_integer_constant_now (enum token_kind k) {
+    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 == TOK_CUINT || k == TOK_CULONG || k == TOK_CULLONG;
+}
+
+#define     MAX_INLINE_ASM_INPUTS        16
+
+struct inline_asm_input_operand {
+
+    char constraint[16];
+    char subst[64];
+    int restore_reg;
+    const char *restore_name;
+
+};
+
+static void inline_asm_copy_trimmed_text (char *dst, size_t dst_size, const char *start, const char *end) {
+
+    size_t len;
+    
+    if (!dst || dst_size == 0) {
+        return;
+    }
+    
+    dst[0] = 0;
+    
+    if (!start || !end || end < start) {
+        return;
+    }
+    
+    while (start < end && (*start == ' ' || *start == '\t' || *start == '\r' || *start == '\n')) {
+        start++;
+    }
+    
+    while (end > start && (end[-1] == ' ' || end[-1] == '\t' || end[-1] == '\r' || end[-1] == '\n')) {
+        end--;
+    }
+    
+    len = (size_t) (end - start);
+    
+    if (len >= dst_size) {
+        len = dst_size - 1;
+    }
+    
+    memcpy (dst, start, len);
+    dst[len] = 0;
+
+}
+
+static void inline_asm_unquote_string_token (char *dst, size_t dst_size) {
+
+    const char *s;
+    char quote;
+    size_t n = 0;
+    
+    if (!dst || dst_size == 0) {
+        return;
+    }
+    
+    dst[0] = 0;
+    
+    if (!is_string_token ()) {
+        return;
+    }
+    
+    s = tok.ident;
+    
+    if (tok.kind == TOK_LSTR && *s == 'L') {
+        s++;
+    }
+    
+    quote = *s;
+    
+    if (quote != '"') {
+        return;
+    }
+    
+    s++;
+    
+    while (*s && *s != quote && n + 1 < dst_size) {
+    
+        if (*s == '\\' && s[1]) {
+        
+            s++;
+            
+            switch (*s) {
+            
+                case 'n':
+                
+                    dst[n++] = '\n'; s++;
+                    break;
+                
+                case 'r':
+                
+                    dst[n++] = '\r'; s++;
+                    break;
+                
+                case 't':
+                
+                    dst[n++] = '\t'; s++;
+                    break;
+                
+                case '\\':
+                
+                    dst[n++] = '\\'; s++;
+                    break;
+                
+                case '"':
+                
+                    dst[n++] = '"'; s++;
+                    break;
+                
+                default:
+                
+                    dst[n++] = *s++;
+                    break;
+            
+            }
+        
+        } else {
+            dst[n++] = *s++;
+        }
+    
+    }
+    
+    dst[n] = 0;
+
+}
+
+static const char *inline_asm_constraint_reg32 (const char *constraint) {
+
+    if (!constraint) {
+        return 0;
+    }
+    
+    if (strchr (constraint, 'a')) {
+        return "eax";
+    }
+    
+    if (strchr (constraint, 'b')) {
+        return "ebx";
+    }
+    
+    if (strchr (constraint, 'c')) {
+        return "ecx";
+    }
+    
+    if (strchr (constraint, 'd')) {
+        return "edx";
+    }
+    
+    if (strchr (constraint, 'S')) {
+        return "esi";
+    }
+    
+    if (strchr (constraint, 'D')) {
+        return "edi";
+    }
+    
+    return 0;
+
+}
+
+static const char *inline_asm_reg_for_template (const char *reg32) {
+
+    if (!reg32) {
+        return "";
+    }
+    
+    if (strcmp (reg32, "eax") == 0) {
+        return "al";
+    }
+    
+    if (strcmp (reg32, "ebx") == 0) {
+        return "bl";
+    }
+    
+    if (strcmp (reg32, "ecx") == 0) {
+        return "cl";
+    }
+    
+    if (strcmp (reg32, "edx") == 0) {
+        return "dx";
+    }
+    
+    if (strcmp (reg32, "esi") == 0) {
+        return "esi";
+    }
+    
+    if (strcmp (reg32, "edi") == 0) {
+        return "edi";
+    }
+    
+    return reg32;
+
+}
+
+static int inline_asm_reg_needs_restore (const char *reg32) {
+    return reg32 && (strcmp (reg32, "ebx") == 0 || strcmp (reg32, "esi") == 0 || strcmp (reg32, "edi") == 0);
+}
+
+static int inline_asm_template_is_out (const char *templ) {
+
+    if (!templ) {
+        return 0;
+    }
+    
+    while (*templ == ' ' || *templ == '\t') {
+        templ++;
+    }
+    
+    return  strncmp (templ, "outb ", 5) == 0 || strncmp (templ, "outw ", 5) == 0 ||
+                strncmp (templ, "outl ", 5) == 0 || strncmp (templ, "out ", 4) == 0;
+
+}
+
+static int inline_asm_is_reg32_name (const char *s, size_t len) {
+
+    return  (len == 3 && strncmp (s, "eax", 3) == 0) ||
+                (len == 3 && strncmp (s, "ebx", 3) == 0) ||
+                    (len == 3 && strncmp (s, "ecx", 3) == 0) ||
+                        (len == 3 && strncmp (s, "edx", 3) == 0) ||
+                            (len == 3 && strncmp (s, "esi", 3) == 0) ||
+                                (len == 3 && strncmp (s, "edi", 3) == 0);
+
+}
+
+static int inline_asm_rewrite_narrow_movzx (char *line, size_t line_size) {
+
+    char rewritten[512];
+    
+    const char *p;
+    const char *reg_start;
+    const char *reg_end;
+    const char *src;
+    
+    size_t reg_len;
+    size_t indent_len;
+    
+    if (!line || line_size == 0 || !(state->syntax & ASM_SYNTAX_INTEL)) {
+        return 0;
+    }
+    
+    p = line;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    indent_len = (size_t) (p - line);
+    
+    if (strncmp (p, "mov", 3) != 0 || (p[3] != ' ' && p[3] != '\t')) {
+        return 0;
+    }
+    
+    p += 3;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    reg_start = p;
+    
+    while ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9')) {
+        p++;
+    }
+    
+    reg_end = p;
+    reg_len = (size_t) (reg_end - reg_start);
+    
+    if (!inline_asm_is_reg32_name (reg_start, reg_len)) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (*p != ',') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    src = p;
+    
+    /**
+     * Only change true narrow memory loads.  This deliberately does not
+     * touch register/register moves, immediates, or lines that have already
+     * been rewritten.
+     */
+    if (strncmp (src, "byte ptr ", 9) != 0 && strncmp (src, "word ptr ", 9) != 0) {
+        return 0;
+    }
+    
+    if (indent_len + 6 + reg_len + 2 + strlen (src) + 1 >= sizeof (rewritten)) {
+        return 0;
+    }
+    
+    memcpy (rewritten, line, indent_len);
+    rewritten[indent_len] = 0;
+    
+    strcat (rewritten, "movzx ");
+    strncat (rewritten, reg_start, reg_len);
+    strcat (rewritten, ", ");
+    strcat (rewritten, src);
+    
+    inline_copy_string (line, rewritten, line_size);
+    return 1;
+
+}
+
+static const char *inline_asm_intel_ptr_name (int size) {
+
+    if (size <= 1) {
+        return "byte";
+    }
+    
+    if (size == 2) {
+        return "word";
+    }
+    
+    if (size == 8) {
+        return "qword";
+    }
+    
+    return "dword";
+
+}
+
+static int inline_asm_format_identifier_operand (char *dst, size_t dst_size, const char *name) {
+
+    struct local_symbol *sym;
+    char memref[64];
+    const char *asm_name;
+    
+    if (!dst || dst_size == 0 || !name || !*name) {
+        return 0;
+    }
+    
+    dst[0] = 0;
+    sym = find_local_symbol (name);
+    
+    if (sym) {
+    
+        if (sym->is_static && sym->static_label) {
+        
+            asm_name = asm_global_symbol_name (sym->static_label);
+            
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                sprintf (dst, (state->syntax & ASM_SYNTAX_NASM ? "%s %s" : "%s ptr %s"), inline_asm_intel_ptr_name (sym->size), asm_name);
+            } else {
+                sprintf (dst, "%s", asm_name);
+            }
+            
+            return 1;
+        
+        }
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+        
+            format_intel_ebp_offset (memref, sizeof (memref), sym->offset);
+            sprintf (dst, (state->syntax & ASM_SYNTAX_NASM ? "%s %s" : "%s ptr %s"), inline_asm_intel_ptr_name (sym->size), memref);
+        
+        } else {
+            sprintf (dst, "%ld(%%ebp)", sym->offset);
+        }
+        
+        return 1;
+    
+    }
+    
+    if (find_global_symbol (name) >= 0) {
+    
+        asm_name = asm_global_symbol_name (name);
+        
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            sprintf (dst, (state->syntax & ASM_SYNTAX_NASM ? "%s %s" : "%s ptr %s"), inline_asm_intel_ptr_name (get_global_symbol_size (name)), asm_name);
+        } else {
+            sprintf (dst, "%s", asm_name);
+        }
+        
+        return 1;
+    
+    }
+    
+    return 0;
+
+}
+
+static void inline_asm_emit_input_load (const char *constraint, int input_index, struct inline_asm_input_operand *inputs, const char *templ) {
+
+    char expr_text[64];
+    
+    const char *expr_start;
+    const char *expr_end;
+    const char *reg32;
+    const char *subst;
+    
+    expr_text[0] = 0;
+    expr_start = tok.caret;
+    
+    inputs[input_index].restore_reg = 0;
+    inputs[input_index].restore_name = 0;
+    
+    if (strchr (constraint, 'N')) {
+    
+        if (token_is_integer_constant_now (tok.kind)) {
+        
+            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+            expr_end = tok.caret;
+            
+            inline_asm_copy_trimmed_text (expr_text, sizeof (expr_text), expr_start, expr_end);
+            inline_copy_string (inputs[input_index].subst, expr_text, sizeof (inputs[input_index].subst));
+            
+            return;
+        
+        }
+        
+        if (inline_asm_template_is_out (templ)) {
+        
+            /**
+             * GCC's "N" constraint is really an 8-bit immediate port.
+             * For the OUT templates, allow a non-constant here as a
+             * convenience and lower it through DX, because x86 OUT cannot
+             * encode a variable port as an immediate.
+             */
+            emit_load_assignment_rhs_expression_to_reg ("edx");
+            inline_copy_string (inputs[input_index].subst, "dx", sizeof (inputs[input_index].subst));
+            
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_IDENT && tok.ident && inline_asm_format_identifier_operand (expr_text, sizeof (expr_text), tok.ident)) {
+        
+            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+            inline_copy_string (inputs[input_index].subst, expr_text, sizeof (inputs[input_index].subst));
+            
+            return;
+        
+        }
+        
+        skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+        expr_end = tok.caret;
+        
+        inline_asm_copy_trimmed_text (expr_text, sizeof (expr_text), expr_start, expr_end);
+        inline_copy_string (inputs[input_index].subst, expr_text, sizeof (inputs[input_index].subst));
+        
+        return;
+    
+    }
+    
+    reg32 = inline_asm_constraint_reg32 (constraint);
+    
+    if (reg32) {
+    
+        subst = inline_asm_reg_for_template (reg32);
+        
+        if (inline_asm_reg_needs_restore (reg32) && state->ofp) {
+        
+            fprintf (state->ofp, "    push %s\n", reg32);
+            
+            inputs[input_index].restore_reg = 1;
+            inputs[input_index].restore_name = reg32;
+        
+        }
+        
+        if (token_is_integer_constant_now (tok.kind)) {
+        
+            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+            expr_end = tok.caret;
+            
+            inline_asm_copy_trimmed_text (expr_text, sizeof (expr_text), expr_start, expr_end);
+            
+            if (state->ofp) {
+                fprintf (state->ofp, "    mov %s, %s\n", subst, expr_text[0] ? expr_text : "0");
+            }
+        
+        } else {
+            emit_load_assignment_rhs_expression_to_reg (reg32);
+        }
+        
+        inline_copy_string (inputs[input_index].subst, subst, sizeof (inputs[input_index].subst));
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_IDENT && tok.ident && inline_asm_format_identifier_operand (expr_text, sizeof (expr_text), tok.ident)) {
+    
+        skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+        inline_copy_string (inputs[input_index].subst, expr_text, sizeof (inputs[input_index].subst));
+        
+        return;
+    
+    }
+    
+    skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+    expr_end = tok.caret;
+    
+    inline_asm_copy_trimmed_text (expr_text, sizeof (expr_text), expr_start, expr_end);
+    inline_copy_string (inputs[input_index].subst, expr_text, sizeof (inputs[input_index].subst));
+
+}
+
+static void inline_asm_emit_template (const char *templ, struct inline_asm_input_operand *inputs, int input_count) {
+
+    char line[512];
+    size_t n = 0;
+    
+    const char *p;
+    
+    if (!state->ofp || !templ) {
+        return;
+    }
+    
+    for (p = templ; *p && n + 1 < sizeof (line); p++) {
+    
+        if (*p == '%' && p[1] == '%') {
+        
+            if (state->syntax & ASM_SYNTAX_INTEL) {
+                p++;
+            } else {
+            
+                line[n++] = '%';
+                p++;
+            
+            }
+        
+        } else if (*p == '%' && p[1] >= '0' && p[1] <= '9') {
+        
+            int index = p[1] - '0';
+            const char *subst = "";
+            
+            if (index >= 0 && index < input_count) {
+                subst = inputs[index].subst;
+            }
+            
+            while (*subst && n + 1 < sizeof (line)) {
+                line[n++] = *subst++;
+            }
+            
+            p++;
+        
+        } else {
+            line[n++] = *p;
+        }
+    
+    }
+    
+    line[n] = 0;
+    
+    if ((strncmp (line, "outb ", 5) == 0 || strncmp (line, "outw ", 5) == 0 || strncmp (line, "outl ", 5) == 0 || strncmp (line, "out ", 4) == 0)) {
+    
+        char *args;
+        char *comma;
+        char *lhs;
+        char *rhs;
+        
+        args = strchr (line, ' ');
+        
+        if (args) {
+        
+            args++;
+            comma = strchr (args, ',');
+            
+            if (comma) {
+            
+                *comma = 0;
+                
+                lhs = args;
+                rhs = comma + 1;
+                
+                while (*lhs == ' ' || *lhs == '\t') {
+                    lhs++;
+                }
+                
+                while (*rhs == ' ' || *rhs == '\t') {
+                    rhs++;
+                }
+                
+                fprintf (state->ofp, "    out %s, %s\n", rhs, lhs);
+                
+                while (input_count-- > 0) {
+                
+                    if (inputs[input_count].restore_reg && inputs[input_count].restore_name) {
+                        fprintf (state->ofp, "    pop %s\n", inputs[input_count].restore_name);
+                    }
+                
+                }
+                
+                return;
+            
+            }
+        
+        }
+    
+    }
+    
+    if (line[0]) {
+    
+        inline_asm_rewrite_narrow_movzx (line, sizeof (line));
+        fprintf (state->ofp, "    %s\n", line);
+    
+    }
+    
+    while (input_count-- > 0) {
+    
+        if (inputs[input_count].restore_reg && inputs[input_count].restore_name) {
+            fprintf (state->ofp, "    pop %s\n", inputs[input_count].restore_name);
+        }
+    
+    }
+
+}
+
+static int parse_inline_asm_statement (void) {
+
+    char templ[256];
+    
+    struct inline_asm_input_operand inputs[MAX_INLINE_ASM_INPUTS];
+    int input_count = 0;
+    
+    if (tok.kind != TOK_ASM) {
+        return 0;
+    }
+    
+    memset (inputs, 0, sizeof (inputs));
+    
+    get_token ();
+    expect (TOK_LPAREN, "(");
+    
+    if (!is_string_token ()) {
+    
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected asm template string");
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        expect (TOK_SEMI, ";");
+        
+        return 1;
+    
+    }
+    
+    inline_asm_unquote_string_token (templ, sizeof (templ));
+    get_token ();
+    
+    if (_accept (TOK_COLON)) {
+    
+        if (tok.kind != TOK_COLON) {
+            skip_balanced_until (TOK_COLON, TOK_RPAREN, TOK_EOF);
+        }
+        
+        if (_accept (TOK_COLON)) {
+        
+            while (tok.kind != TOK_RPAREN && tok.kind != TOK_EOF) {
+            
+                char constraint[16];
+                
+                if (!is_string_token ()) {
+                
+                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected asm input constraint string");
+                    
+                    skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+                    break;
+                
+                }
+                
+                inline_asm_unquote_string_token (constraint, sizeof (constraint));
+                get_token ();
+                
+                expect (TOK_LPAREN, "(");
+                
+                if (input_count < MAX_INLINE_ASM_INPUTS) {
+                
+                    inline_copy_string (inputs[input_count].constraint, constraint, sizeof (inputs[input_count].constraint));
+                    inline_asm_emit_input_load (constraint, input_count, inputs, templ);
+                    
+                    input_count++;
+                
+                } else {
+                    skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+                }
+                
+                expect (TOK_RPAREN, ")");
+                
+                if (!_accept (TOK_COMMA)) {
+                    break;
+                }
+            
+            }
+        
+        }
+    
+    }
+    
+    expect (TOK_RPAREN, ")");
+    expect (TOK_SEMI, ";");
+    
+    inline_asm_emit_template (templ, inputs, input_count);
+    return 1;
+
+}
+
+static int token_is_const_condition_operand_now (void) {
+    return token_is_sizeof_keyword () || token_is_integer_constant_now (tok.kind);
+}
+
+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 == '_';
+}
+
+static int ident_start_now (int ch) {
+    return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '_';
+}
+
+static int prefix_incdec_target_is_floating_now (void) {
+
+    const char *p;
+    const char *q;
+    
+    char *name;
+    int len;
+    
+    struct local_symbol *src;
+    int ret = 0;
+    
+    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
+        return 0;
+    }
+    
+    p = tok.caret;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!ident_start_now ((unsigned char) *p)) {
+        return 0;
+    }
+    
+    q = p + 1;
+    
+    while (ident_char_now ((unsigned char) *q)) {
+        q++;
+    }
+    
+    len = (int) (q - p);
+    name = xmalloc ((unsigned long) len + 1);
+    
+    memcpy (name, p, (unsigned long) len);
+    name[len] = 0;
+    
+    src = find_local_symbol (name);
+    
+    if (src) {
+        ret = src->is_floating ? 1 : 0;
+    } else if (find_global_symbol (name) >= 0) {
+        ret = get_global_symbol_floating (name) ? 1 : 0;
+    }
+    
+    free (name);
+    return ret;
+
+}
+
+static int source_parenthesized_floating_condition_now (const char *p) {
+
+    char name[128];
+    int i;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (*p != '(') {
+        return 0;
+    }
+    
+    while (*p == '(' || *p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    i = 0;
+    
+    while (((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') && i < (int) sizeof (name) - 1) {
+        name[i++] = *p++;
+    }
+    
+    name[i] = 0;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (*p == '.') {
+        return 0;
+    }
+    
+    if (*p == '(' && find_global_symbol (name) >= 0 && get_global_symbol_floating (name)) {
+        return 1;
+    }
+    
+    /*
+     * Parenthesized floating conditions such as:
+     *
+     *     if (num < 0)
+     *     while (b >= 10.0)
+     *
+     * arrive here while TOK_LPAREN is still current.  If we don't recognise
+     * the name inside the parens as floating, the generic parenthesized
+     * integer path consumes the expression and compares only the low dword.
+     */
+    if (find_local_symbol (name)) {
+    
+        struct local_symbol *src = find_local_symbol (name);
+        return src && src->is_floating ? 1 : 0;
+    
+    }
+    
+    if (find_global_symbol (name) >= 0) {
+        return get_global_symbol_floating (name) ? 1 : 0;
+    }
+    
+    return 0;
+
+}
+
+static int source_va_arg_type_is_double_now (const char *p) {
+
+    int paren;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '(') {
+        return 0;
+    }
+    
+    paren = 0;
+    
+    while (*p) {
+    
+        if (*p == '(') {
+            paren++;
+        } else if (*p == ')') {
+        
+            paren--;
+            
+            if (paren == 0) {
+                return 0;
+            }
+        
+        } else if (paren == 1 && *p == ',') {
+        
+            p++;
+            
+            while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+                p++;
+            }
+            
+            if (strncmp (p, "double", 6) == 0 &&
+                !(p[6] == '_' || (p[6] >= '0' && p[6] <= '9') ||
+                  (p[6] >= 'A' && p[6] <= 'Z') ||
+                  (p[6] >= 'a' && p[6] <= 'z'))) {
+                return 1;
+            }
+        
+        }
+        
+        p++;
+    
+    }
+    
+    return 0;
+
+}
+
+static int rhs_current_operand_is_floating_now (void) {
+
+    if (token_is_floating_constant_now ()) {
+        return 1;
+    }
+    
+    if (tok.kind == TOK_SCC_BUILTIN_VA_ARG) {
+    
+        const char *p = tok.caret ? tok.caret + tok.len : 0;
+        
+        if (source_va_arg_type_is_double_now (p)) {
+            return 1;
+        }
+    
+    }
+    
+    if (tok.kind == TOK_LPAREN && (source_parenthesized_floating_condition_now (tok.caret) || source_parenthesized_floating_condition_now (tok.start))) {
+        return 1;
+    }
+    
+    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+        return prefix_incdec_target_is_floating_now ();
+    }
+    
+    if (tok.kind == TOK_IDENT && tok.ident) {
+    
+        struct local_symbol *src = find_local_symbol (tok.ident);
+        const char *p = tok.caret ? tok.caret + tok.len : 0;
+        
+        while (p && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')) {
+            p++;
+        }
+        
+        if (strcmp (tok.ident, "__scc_builtin_va_arg") == 0 && source_va_arg_type_is_double_now (p)) {
+            return 1;
+        }
+        
+        if (p && *p == '(' && find_global_symbol (tok.ident) >= 0) {
+            return get_global_function_returns_floating (tok.ident) ? 1 : 0;
+        }
+        
+        if (p && ((p[0] == '-' && p[1] == '>') || p[0] == '.')) {
+        
+            const char *q = p + (p[0] == '-' ? 2 : 1);
+            char member[128];
+            
+            int n = 0;
+            int offset = 0;
+            int size = 0;
+            int elem_size = 0;
+            int pointer_depth = 0;
+            int is_array = 0;
+            int is_floating = 0;
+            int base_size = 0;
+            
+            const char *base_tag_name = 0;
+            
+            while (*q == ' ' || *q == '\t' || *q == '\r' || *q == '\n') {
+                q++;
+            }
+            
+            while (((*q >= 'A' && *q <= 'Z') || (*q >= 'a' && *q <= 'z') || (*q >= '0' && *q <= '9') || *q == '_') && n < (int) sizeof (member) - 1) {
+                member[n++] = *q++;
+            }
+            
+            member[n] = '\0';
+            
+            if (n > 0) {
+            
+                if (p[0] == '-') {
+                
+                    if (src) {
+                    
+                        base_size = src->pointed_size;
+                        base_tag_name = src->pointed_tag_name;
+                    
+                    } else if (find_global_symbol (tok.ident) >= 0) {
+                    
+                        base_size = get_global_symbol_pointed_size (tok.ident);
+                        base_tag_name = get_global_symbol_tag_name (tok.ident);
+                    
+                    }
+                
+                } else {
+                
+                    if (src) {
+                    
+                        base_size = src->size;
+                        base_tag_name = src->tag_name;
+                    
+                    } else if (find_global_symbol (tok.ident) >= 0) {
+                    
+                        base_size = get_global_symbol_size (tok.ident);
+                        base_tag_name = get_global_symbol_tag_name (tok.ident);
+                    
+                    }
+                
+                }
+                
+                if (find_member_info_ex_bounded (member, base_size, base_tag_name, &offset, &size, &elem_size, &pointer_depth, &is_array, &is_floating)) {
+                    return is_floating ? 1 : 0;
+                }
+            
+            }
+        
+        }
+        
+        if (src) {
+            return src->is_floating ? 1 : 0;
+        }
+        
+        if (find_global_symbol (tok.ident) >= 0) {
+            return get_global_function_returns_floating (tok.ident) ? 1 : 0;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int64_s floating_ld_to_bits_now (int size, double value) {
+
+    int64_s r;
+    
+    unsigned long bits32;
+    unsigned char bytes[8];
+    
+    int i;
+    
+    r.low = 0;
+    r.high = 0;
+    
+    if (size == (DATA_FLOAT & 0x1f)) {
+    
+        float f = (float) value;
+        
+        bits32 = 0;
+        
+        memcpy (&bits32, &f, sizeof (f));
+        r.low = bits32;
+        
+        return r;
+    
+    }
+    
+    {
+    
+        double d = (double) value;
+        
+        memset (bytes, 0, sizeof (bytes));
+        memcpy (bytes, &d, sizeof (d));
+        
+        for (i = 0; i < 4; i++) {
+            r.low |= ((unsigned long) bytes[i]) << (i * 8);
+        }
+        
+        for (i = 0; i < 4; i++) {
+            r.high |= ((unsigned long) bytes[i + 4]) << (i * 8);
+        }
+        
+        return r;
+    
+    }
+
+}
+
+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));
+}
+
+static int int64_statement_truth_value (int64_s v) {
+    return v.low != 0 || v.high != 0;
+}
+
+static long statement_int64_signed_high (int64_s v) {
+
+    unsigned long h = v.high & U32_MASK;
+    
+    if (h & 0x80000000UL) {
+        return -((long) ((~h + 1UL) & U32_MASK));
+    }
+    
+    return (long) h;
+
+}
+
+static int statement_cmp_const64_unsigned (int64_s left, int64_s right) {
+
+    unsigned long lh = left.high & U32_MASK;
+    unsigned long rh = right.high & U32_MASK;
+    unsigned long ll = left.low & U32_MASK;
+    unsigned long rl = right.low & U32_MASK;
+    
+    if (lh < rh) return -1;
+    if (lh > rh) return 1;
+    if (ll < rl) return -1;
+    if (ll > rl) return 1;
+    
+    return 0;
+
+}
+
+static int statement_cmp_const64_signed (int64_s left, int64_s right) {
+
+    long lh = statement_int64_signed_high (left);
+    long rh = statement_int64_signed_high (right);
+    
+    unsigned long ll = left.low & U32_MASK;
+    unsigned long rl = right.low & U32_MASK;
+
+    if (lh < rh) return -1;
+    if (lh > rh) return 1;
+    if (ll < rl) return -1;
+    if (ll > rl) return 1;
+    
+    return 0;
+
+}
+
+static int statement_compare_const64_true (int64_s left, enum token_kind op, int64_s right, int is_unsigned) {
+
+    int c = is_unsigned ? statement_cmp_const64_unsigned (left, right) : statement_cmp_const64_signed (left, right);
+    
+    switch (op) {
+    
+        case TOK_LESS:
+        
+            return c < 0;
+        
+        case TOK_LTEQ:
+        
+            return c <= 0;
+        
+        case TOK_GREATER:
+        
+            return c > 0;
+        
+        case TOK_GTEQ:
+        
+            return c >= 0;
+        
+        case TOK_EQEQ:
+        
+            return c == 0;
+        
+        case TOK_NOTEQ:
+        
+            return c != 0;
+        
+        default:
+        
+            return int64_statement_truth_value (left);
+    
+    }
+
+}
+
+static int rhs_current_operand_is_unsigned_now (void) {
+
+    if (token_is_sizeof_keyword ()) {
+        return 1;
+    }
+    
+    if (token_is_integer_unsigned_constant_now (tok.kind)) {
+        return 1;
+    }
+    
+    if (tok.kind == TOK_IDENT && tok.ident) {
+    
+        struct local_symbol *src = find_local_symbol (tok.ident);
+        
+        if (src) {
+            return src->is_unsigned ? 1 : 0;
+        }
+        
+        if (find_global_symbol (tok.ident) >= 0) {
+            return get_global_symbol_unsigned (tok.ident) ? 1 : 0;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int token_is_statement_compare_operator (enum token_kind k) {
+
+    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 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];
+    
+    const char *p;
+    int i;
+    
+    int64_s ignored;
+    
+    if (!pp || !*pp) {
+        return 0;
+    }
+    
+    p = *pp;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    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;
+    }
+    
+    for (;;) {
+    
+        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;
+        }
+        
+        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+            p++;
+        }
+        
+        if (source_condition_tail_end_now (p)) {
+            return 1;
+        }
+        
+        if (!((p[0] == '&' && p[1] == '&') || (p[0] == '|' && p[1] == '|'))) {
+            return 0;
+        }
+    
+    }
+
+}
+
+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;
+    }
+    
+    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;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    /*
+     * 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;
+    }
+    
+    name_len = (int) strlen (tok.ident);
+    p = source_find_current_ident_on_line (p);
+    
+    if (!p) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        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;
+    }
+    
+    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;
+
+}
+
+static int emit_statement_ident_enum_compare_jump_if_false_now (int label) {
+
+    enum token_kind op;
+    int is_unsigned;
+    
+    if (!source_condition_ident_enum_compare_now (tok.caret) && !source_condition_ident_enum_compare_now (tok.start)) {
+        return 0;
+    }
+    
+    is_unsigned = rhs_current_operand_is_unsigned_now ();
+    emit_load_assignment_rhs_to_reg ("eax");
+    
+    if (!token_is_statement_compare_operator (tok.kind)) {
+        return 0;
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    /*
+     * 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 ();
+    
+    if (rhs_current_operand_is_unsigned_now ()) {
+        is_unsigned = 1;
+    }
+    
+    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 statement_condition_ident_call_at (const char *p) {
+
+    int len;
+    
+    if (tok.kind != TOK_IDENT || !tok.ident || !p) {
+        return 0;
+    }
+    
+    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) len) == 0 && !ident_char_now ((unsigned char) p[len])) {
+        
+            p += len;
+            
+            while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+                p++;
+            }
+            
+            return *p == '(';
+        
+        }
+        
+        p++;
+    
+    }
+    
+    return 0;
+
+}
+
+static int statement_condition_starts_with_ident_call_now (void) {
+
+    if (statement_condition_ident_call_at (tok.caret)) {
+        return 1;
+    }
+    
+    if (statement_condition_ident_call_at (tok.start)) {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static const char *statement_false_jump_mnemonic (enum token_kind op, int is_unsigned) {
+
+    switch (op) {
+    
+        case TOK_LESS:
+        
+            return is_unsigned ? "jae" : "jge";
+        
+        case TOK_LTEQ:
+        
+            return is_unsigned ? "ja"  : "jg";
+        
+        case TOK_GREATER:
+        
+            return is_unsigned ? "jbe" : "jle";
+        
+        case TOK_GTEQ:
+        
+            return is_unsigned ? "jb"  : "jl";
+        
+        case TOK_EQEQ:
+        
+            return "jne";
+        
+        case TOK_NOTEQ:
+        
+            return "je";
+        
+        default:
+        
+            return "jz";
+    
+    }
+
+}
+
+static void emit_statement_const32_to_eax (int64_s v) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+        fprintf (state->ofp, "    mov eax, %lu\n", v.low & U32_MASK);
+    } else {
+        fprintf (state->ofp, "    movl $%lu, %%eax\n", v.low & U32_MASK);
+    }
+
+}
+
+static void emit_statement_cmp_eax_edx_jump_if_false (enum token_kind op, int is_unsigned, int label) {
+
+    const char *jmp;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    jmp = statement_false_jump_mnemonic (op, is_unsigned);
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    cmp eax, edx\n");
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    %s L%d\n" : "    %s .L%d\n"), jmp, label);
+    
+    } else {
+    
+        fprintf (state->ofp, "    cmpl %%edx, %%eax\n");
+        fprintf (state->ofp, "    %s .L%d\n", jmp, label);
+    
+    }
+
+}
+
+static void emit_statement_cmp64_to_eax (enum token_kind op, int is_unsigned) {
+
+    int true_label;
+    int false_label;
+    int end_label;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    true_label = anon_label++;
+    false_label = anon_label++;
+    end_label = anon_label++;
+    
+    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+    
+        switch (op) {
+        
+            case TOK_LESS:
+            
+                fprintf (state->ofp, "    cmp edx, ecx\n");
+                fprintf (state->ofp, is_unsigned ? "    jb L%d\n" : "    jl L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    ja L%d\n" : "    jg L%d\n", false_label);
+                fprintf (state->ofp, "    cmp eax, ebx\n");
+                fprintf (state->ofp, "    jb L%d\n", true_label);
+                break;
+            
+            case TOK_LTEQ:
+            
+                fprintf (state->ofp, "    cmp edx, ecx\n");
+                fprintf (state->ofp, is_unsigned ? "    jb L%d\n" : "    jl L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    ja L%d\n" : "    jg L%d\n", false_label);
+                fprintf (state->ofp, "    cmp eax, ebx\n");
+                fprintf (state->ofp, "    jbe L%d\n", true_label);
+                break;
+            
+            case TOK_GREATER:
+            
+                fprintf (state->ofp, "    cmp edx, ecx\n");
+                fprintf (state->ofp, is_unsigned ? "    ja L%d\n" : "    jg L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    jb L%d\n" : "    jl L%d\n", false_label);
+                fprintf (state->ofp, "    cmp eax, ebx\n");
+                fprintf (state->ofp, "    ja L%d\n", true_label);
+                break;
+            
+            case TOK_GTEQ:
+            
+                fprintf (state->ofp, "    cmp edx, ecx\n");
+                fprintf (state->ofp, is_unsigned ? "    ja L%d\n" : "    jg L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    jb L%d\n" : "    jl L%d\n", false_label);
+                fprintf (state->ofp, "    cmp eax, ebx\n");
+                fprintf (state->ofp, "    jae L%d\n", true_label);
+                break;
+            
+            case TOK_EQEQ:
+            
+                fprintf (state->ofp, "    cmp edx, ecx\n");
+                fprintf (state->ofp, "    jne L%d\n", false_label);
+                fprintf (state->ofp, "    cmp eax, ebx\n");
+                fprintf (state->ofp, "    je L%d\n", true_label);
+                break;
+            
+            case TOK_NOTEQ:
+            
+                fprintf (state->ofp, "    cmp edx, ecx\n");
+                fprintf (state->ofp, "    jne L%d\n", true_label);
+                fprintf (state->ofp, "    cmp eax, ebx\n");
+                fprintf (state->ofp, "    jne L%d\n", true_label);
+                break;
+            
+            default:
+            
+                fprintf (state->ofp, "    test edx, edx\n");
+                fprintf (state->ofp, "    jnz L%d\n", true_label);
+                fprintf (state->ofp, "    test eax, eax\n");
+                fprintf (state->ofp, "    jnz L%d\n", true_label);
+                break;
+        
+        }
+        
+        fprintf (state->ofp, "L%d:\n", false_label);
+        fprintf (state->ofp, "    xor eax, eax\n");
+        fprintf (state->ofp, "    jmp L%d\n", end_label);
+        fprintf (state->ofp, "L%d:\n", true_label);
+        fprintf (state->ofp, "    mov eax, 1\n");
+        fprintf (state->ofp, "L%d:\n", end_label);
+    
+    } else if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        switch (op) {
+        
+            case TOK_LESS:
+            
+                fprintf (state->ofp, "    cmp edx, ecx\n");
+                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", false_label);
+                fprintf (state->ofp, "    cmp eax, ebx\n");
+                fprintf (state->ofp, "    jb .L%d\n", true_label);
+                break;
+            
+            case TOK_LTEQ:
+            
+                fprintf (state->ofp, "    cmp edx, ecx\n");
+                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", false_label);
+                fprintf (state->ofp, "    cmp eax, ebx\n");
+                fprintf (state->ofp, "    jbe .L%d\n", true_label);
+                break;
+            
+            case TOK_GREATER:
+            
+                fprintf (state->ofp, "    cmp edx, ecx\n");
+                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", false_label);
+                fprintf (state->ofp, "    cmp eax, ebx\n");
+                fprintf (state->ofp, "    ja .L%d\n", true_label);
+                break;
+            
+            case TOK_GTEQ:
+            
+                fprintf (state->ofp, "    cmp edx, ecx\n");
+                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", false_label);
+                fprintf (state->ofp, "    cmp eax, ebx\n");
+                fprintf (state->ofp, "    jae .L%d\n", true_label);
+                break;
+            
+            case TOK_EQEQ:
+            
+                fprintf (state->ofp, "    cmp edx, ecx\n");
+                fprintf (state->ofp, "    jne .L%d\n", false_label);
+                fprintf (state->ofp, "    cmp eax, ebx\n");
+                fprintf (state->ofp, "    je .L%d\n", true_label);
+                break;
+            
+            case TOK_NOTEQ:
+            
+                fprintf (state->ofp, "    cmp edx, ecx\n");
+                fprintf (state->ofp, "    jne .L%d\n", true_label);
+                fprintf (state->ofp, "    cmp eax, ebx\n");
+                fprintf (state->ofp, "    jne .L%d\n", true_label);
+                break;
+            
+            default:
+            
+                fprintf (state->ofp, "    test edx, edx\n");
+                fprintf (state->ofp, "    jnz .L%d\n", true_label);
+                fprintf (state->ofp, "    test eax, eax\n");
+                fprintf (state->ofp, "    jnz .L%d\n", true_label);
+                break;
+        
+        }
+        
+        fprintf (state->ofp, ".L%d:\n", false_label);
+        fprintf (state->ofp, "    xor eax, eax\n");
+        fprintf (state->ofp, "    jmp .L%d\n", end_label);
+        fprintf (state->ofp, ".L%d:\n", true_label);
+        fprintf (state->ofp, "    mov eax, 1\n");
+        fprintf (state->ofp, ".L%d:\n", end_label);
+    
+    } else {
+    
+        switch (op) {
+        
+            case TOK_LESS:
+            
+                fprintf (state->ofp, "    cmpl %%ecx, %%edx\n");
+                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", false_label);
+                fprintf (state->ofp, "    cmpl %%ebx, %%eax\n");
+                fprintf (state->ofp, "    jb .L%d\n", true_label);
+                break;
+            
+            case TOK_LTEQ:
+            
+                fprintf (state->ofp, "    cmpl %%ecx, %%edx\n");
+                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", false_label);
+                fprintf (state->ofp, "    cmpl %%ebx, %%eax\n");
+                fprintf (state->ofp, "    jbe .L%d\n", true_label);
+                break;
+            
+            case TOK_GREATER:
+            
+                fprintf (state->ofp, "    cmpl %%ecx, %%edx\n");
+                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", false_label);
+                fprintf (state->ofp, "    cmpl %%ebx, %%eax\n");
+                fprintf (state->ofp, "    ja .L%d\n", true_label);
+                break;
+            
+            case TOK_GTEQ:
+            
+                fprintf (state->ofp, "    cmpl %%ecx, %%edx\n");
+                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", true_label);
+                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", false_label);
+                fprintf (state->ofp, "    cmpl %%ebx, %%eax\n");
+                fprintf (state->ofp, "    jae .L%d\n", true_label);
+                break;
+            
+            case TOK_EQEQ:
+            
+                fprintf (state->ofp, "    cmpl %%ecx, %%edx\n");
+                fprintf (state->ofp, "    jne .L%d\n", false_label);
+                fprintf (state->ofp, "    cmpl %%ebx, %%eax\n");
+                fprintf (state->ofp, "    je .L%d\n", true_label);
+                break;
+            
+            case TOK_NOTEQ:
+            
+                fprintf (state->ofp, "    cmpl %%ecx, %%edx\n");
+                fprintf (state->ofp, "    jne .L%d\n", true_label);
+                fprintf (state->ofp, "    cmpl %%ebx, %%eax\n");
+                fprintf (state->ofp, "    jne .L%d\n", true_label);
+                break;
+            
+            default:
+            
+                fprintf (state->ofp, "    testl %%edx, %%edx\n");
+                fprintf (state->ofp, "    jnz .L%d\n", true_label);
+                fprintf (state->ofp, "    testl %%eax, %%eax\n");
+                fprintf (state->ofp, "    jnz .L%d\n", true_label);
+                break;
+        
+        }
+        
+        fprintf (state->ofp, ".L%d:\n", false_label);
+        fprintf (state->ofp, "    xorl %%eax, %%eax\n");
+        fprintf (state->ofp, "    jmp .L%d\n", end_label);
+        fprintf (state->ofp, ".L%d:\n", true_label);
+        fprintf (state->ofp, "    movl $1, %%eax\n");
+        fprintf (state->ofp, ".L%d:\n", end_label);
+    
+    }
+
+}
+
+static const char *statement_float_false_jump_mnemonic (enum token_kind op) {
+
+    switch (op) {
+    
+        case TOK_LESS:
+        
+            return "jae";
+        
+        case TOK_LTEQ:
+        
+            return "ja";
+        
+        case TOK_GREATER:
+        
+            return "jbe";
+        
+        case TOK_GTEQ:
+        
+            return "jb";
+        
+        case TOK_EQEQ:
+        
+            return "jne";
+        
+        case TOK_NOTEQ:
+        
+            return "je";
+        
+        default:
+        
+            return "jz";
+    
+    }
+
+}
+
+static void emit_statement_floating_compare_jump_if_false (enum token_kind op, int label) {
+
+    const char *jmp;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    jmp = statement_float_false_jump_mnemonic (op);
+    
+    if (state->syntax & ASM_SYNTAX_NASM) {
+    
+        fprintf (state->ofp, "    fxch st1\n");
+        fprintf (state->ofp, "    fcompp\n");
+        fprintf (state->ofp, "    fnstsw ax\n");
+        fprintf (state->ofp, "    sahf\n");
+        fprintf (state->ofp, "    %s L%d\n", jmp, label);
+    
+    } else if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    fxch st(1)\n");
+        fprintf (state->ofp, "    fcompp\n");
+        fprintf (state->ofp, "    fnstsw ax\n");
+        fprintf (state->ofp, "    sahf\n");
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    %s L%d\n" : "    %s .L%d\n"), jmp, label);
+    
+    } else {
+    
+        fprintf (state->ofp, "    fxch %%st(1)\n");
+        fprintf (state->ofp, "    fcompp\n");
+        fprintf (state->ofp, "    fnstsw %%ax\n");
+        fprintf (state->ofp, "    sahf\n");
+        fprintf (state->ofp, "    %s .L%d\n", jmp, label);
+    
+    }
+
+}
+
+static int statement_compare_floating_const_true (double left, enum token_kind op, double right) {
+
+    switch (op) {
+    
+        case TOK_LESS:
+        
+            return left < right;
+        
+        case TOK_LTEQ:
+        
+            return left <= right;
+        
+        case TOK_GREATER:
+        
+            return left > right;
+        
+        case TOK_GTEQ:
+        
+            return left >= right;
+        
+        case TOK_EQEQ:
+        
+            return left == right;
+        
+        case TOK_NOTEQ:
+        
+            return left != right;
+        
+        default:
+        
+            return left != 0.0;
+    
+    }
+
+}
+
+static void emit_statement_test_eax_jump_if_false (int label) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    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)) ? "    jz L%d\n" : "    jz .L%d\n"), label);
+    
+    } else {
+    
+        fprintf (state->ofp, "    testl %%eax, %%eax\n");
+        fprintf (state->ofp, "    jz .L%d\n", label);
+    
+    }
+
+}
+
+static void emit_statement_test_pair_jump_if_false (const char *lo, const char *hi, int label) {
+
+    int nonzero_label;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    nonzero_label = anon_label++;
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    test %s, %s\n", hi, hi);
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), nonzero_label);
+        fprintf (state->ofp, "    test %s, %s\n", lo, lo);
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jz L%d\n" : "    jz .L%d\n"), label);
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), nonzero_label);
+    
+    } else {
+    
+        fprintf (state->ofp, "    testl %%%s, %%%s\n", hi, hi);
+        fprintf (state->ofp, "    jnz .L%d\n", nonzero_label);
+        fprintf (state->ofp, "    testl %%%s, %%%s\n", lo, lo);
+        fprintf (state->ofp, "    jz .L%d\n", label);
+        fprintf (state->ofp, ".L%d:\n", nonzero_label);
+    
+    }
+
+}
+
+static void emit_statement_test_pair_jump_if_true (const char *lo, const char *hi, int label) {
+
+    if (!state->ofp) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_INTEL) {
+    
+        fprintf (state->ofp, "    test %s, %s\n", hi, hi);
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), label);
+        fprintf (state->ofp, "    test %s, %s\n", lo, lo);
+        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), label);
+    
+    } else {
+    
+        fprintf (state->ofp, "    testl %%%s, %%%s\n", hi, hi);
+        fprintf (state->ofp, "    jnz .L%d\n", label);
+        fprintf (state->ofp, "    testl %%%s, %%%s\n", lo, lo);
+        fprintf (state->ofp, "    jnz .L%d\n", label);
+    
+    }
+
+}
+
+static int statement_condition_constant_known = 0;
+static int statement_condition_constant_value = 0;
+
+static void parse_statement (void);
+static void parse_statement_suppressed (void);
+static void emit_statement_jump_if_false (int label);
+
+static void replay_tmp_file_to_output (FILE *tmp, FILE *out) {
+
+    int ch;
+    
+    if (!tmp || !out) {
+        return;
+    }
+    
+    fflush (tmp);
+    fseek (tmp, 0, SEEK_SET);
+    
+    while ((ch = fgetc (tmp)) != EOF) {
+        fputc (ch, out);
+    }
+
+}
+
+static void parse_for_header_expression_until (enum token_kind end_token) {
+
+    char *name;
+    int global_index;
+    
+    const char *name_start, *name_caret;
+    unsigned long name_line;
+    
+    enum token_kind op;
+    struct local_symbol *lhs;
+    
+    int lhs_size;
+    int lhs_is_floating;
+    
+#define     FINISH_FOR_HEADER_EXPR(free_name)                                   \
+    do {                                                                        \
+        if (tok.kind == TOK_COMMA) {                                            \
+            get_token ();                                                       \
+            if (free_name) {                                                    \
+                free (name);                                                    \
+            }                                                                   \
+            parse_for_header_expression_until (end_token);                      \
+            return;                                                             \
+        }                                                                       \
+        if (tok.kind != end_token) {                                            \
+            skip_balanced_until (end_token, TOK_EOF, TOK_EOF);                  \
+        }                                                                       \
+        expect (end_token, end_token == TOK_SEMI ? ";" : ")");                  \
+        if (free_name) {                                                        \
+            free (name);                                                        \
+        }                                                                       \
+        return;                                                                 \
+    } while (0)
+    
+    if (tok.kind == end_token) {
+        return;
+    }
+    
+    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+    
+        op = tok.kind;
+        get_token ();
+        
+        if (tok.kind == TOK_IDENT) {
+        
+            name = xstrdup (tok.ident);
+            name_start = tok.start;
+            name_caret = tok.caret;
+            name_line = get_line_number ();
+            get_token ();
+            
+            lhs = find_local_symbol (name);
+            emit_incdec_symbol_now (lhs, name, op, name_line, name_start, name_caret);
+            free (name);
+        
+        } else {
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after %s", op == TOK_INCR ? "++" : "--");
+        }
+        
+        FINISH_FOR_HEADER_EXPR (0);
+    
+    }
+    
+    if (tok.kind != TOK_IDENT) {
+    
+        if (state->ofp) {
+            emit_load_assignment_rhs_expression_to_reg ("eax");
+        } else {
+            skip_balanced_until (end_token, TOK_EOF, TOK_EOF);
+        }
+        
+        FINISH_FOR_HEADER_EXPR (0);
+    
+    }
+    
+    name = xstrdup (tok.ident);
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    get_token ();
+    
+    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
+    
+        op = tok.kind;
+        get_token ();
+        
+        lhs = find_local_symbol (name);
+        emit_incdec_symbol_now (lhs, name, op, name_line, name_start, name_caret);
+        
+        FINISH_FOR_HEADER_EXPR (1);
+    
+    }
+    
+    if (tok.kind == TOK_LPAREN) {
+    
+        if (!find_local_symbol (name)) {
+            ensure_global_function_symbol (name, name_start, name_caret, name_line);
+        }
+        
+        emit_call_identifier_to_reg_now (name, "eax", name_start, name_caret, name_line);
+        FINISH_FOR_HEADER_EXPR (1);
+    
+    }
+    
+    if (!is_assignment_operator (tok.kind)) {
+    
+        if (!find_local_symbol (name) && find_global_symbol (name) < 0) {
+        
+            int64_s ignored;
+            
+            if (!resolve_enum_constant (name, &ignored)) {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            }
+        
+        }
+        
+        if (tok.kind == TOK_COMMA) {
+        
+            get_token ();
+            free (name);
+            
+            parse_for_header_expression_until (end_token);
+            return;
+        
+        }
+        
+        skip_balanced_until (end_token, TOK_EOF, TOK_EOF);
+        expect (end_token, end_token == TOK_SEMI ? ";" : ")");
+        
+        free (name);
+        return;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    lhs = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (!lhs && global_index < 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        FINISH_FOR_HEADER_EXPR (1);
+    
+    }
+    
+    if (state->ofp) {
+    
+        lhs_size = lhs ? lhs->size : get_global_symbol_size (name);
+        lhs_is_floating = lhs ? lhs->is_floating : get_global_symbol_floating (name);
+        
+        if (lhs_is_floating) {
+        
+            if (!floating_assignment_operator_supported_now (op)) {
+            
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid operands to floating assignment operator");
+                skip_balanced_until (end_token, TOK_EOF, TOK_EOF);
+            
+            } else {
+            
+                if (op == TOK_ASSIGN) {
+                    emit_load_floating_rhs_expression_now (lhs_size);
+                } else {
+                
+                    emit_load_floating_symbol_now (lhs, name, lhs_size);
+                    emit_load_floating_rhs_expression_now (lhs_size);
+                    emit_floating_binary_now (op);
+                
+                }
+                
+                emit_store_floating_symbol_now (lhs, name, lhs_size);
+            
+            }
+        
+        } else if (lhs_size == (DATA_LLONG & 0x1f)) {
+        
+            if (op == TOK_ASSIGN) {
+                emit_load_assignment_rhs_expression_to_pair ("eax", "edx", lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
+            } else {
+            
+                if (lhs) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_global64_to_pair ("eax", "edx", lhs->static_label);
+                    } else {
+                        emit_load_local64_to_pair (lhs->offset, "eax", "edx");
+                    }
+                
+                } else {
+                    emit_load_global64_to_pair ("eax", "edx", name);
+                }
+                
+                /*
+                 * Compound assignments need the complete RHS expression.
+                 * Using emit_load_assignment_rhs_to_pair() only consumes one
+                 * primary operand, so e.g.
+                 *
+                 *     final_value += symbol->frag->address + left_value;
+                 *
+                 * leaves the second + operand for the statement parser and
+                 * reports "expected ;".  Evaluate the full RHS in eax:edx,
+                 * copy it to the RHS pair ebx:ecx, then restore the original
+                 * LHS value before applying the compound operator.
+                 */
+                emit_push_reg_now ("eax");
+                emit_push_reg_now ("edx");
+                
+                emit_load_assignment_rhs_expression_to_pair ("eax", "edx", lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
+                
+                emit_mov_reg_to_reg_now ("ebx", "eax");
+                emit_mov_reg_to_reg_now ("ecx", "edx");
+                
+                emit_pop_reg_now ("edx");
+                emit_pop_reg_now ("eax");
+                
+                emit_preserve_assignment64_regs (op);
+                emit_assignment_binary_op64 (op, lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
+                emit_restore_assignment64_regs (op);
+            
+            }
+            
+            if (lhs) {
+            
+                if (lhs->is_static && lhs->static_label) {
+                    emit_store_pair_to_global64 (lhs->static_label, "eax", "edx");
+                } else {
+                    emit_store_pair_to_local64 (lhs->offset, "eax", "edx");
+                }
+            
+            } else {
+                emit_store_pair_to_global64 (name, "eax", "edx");
+            }
+        
+        } else {
+        
+            if (op == TOK_ASSIGN) {
+                emit_load_assignment_rhs_expression_to_reg ("eax");
+            } else {
+            
+                if (lhs) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_global_to_reg_ex ("eax", lhs->static_label, lhs->size, lhs->is_unsigned);
+                    } else {
+                        emit_load_local_to_reg_ex ("eax", lhs->offset, lhs->size, lhs->is_unsigned);
+                    }
+                
+                } else {
+                    emit_load_global_to_reg ("eax", name, lhs_size);
+                }
+                
+                emit_load_assignment_rhs_to_reg ("edx");
+                emit_assignment_binary_op (op, lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
+            
+            }
+            
+            if (lhs) {
+            
+                if (lhs->is_static && lhs->static_label) {
+                    emit_store_reg_to_global (lhs->static_label, lhs->size, "eax");
+                } else {
+                    emit_store_reg_to_local (lhs->offset, lhs->size, "eax");
+                }
+            
+            } else {
+                emit_store_reg_to_global (name, lhs_size, "eax");
+            }
+        
+        }
+    
+    } else {
+        skip_balanced_until (end_token, TOK_EOF, TOK_EOF);
+    }
+    
+    FINISH_FOR_HEADER_EXPR (1);
+
+#undef      FINISH_FOR_HEADER_EXPR
+
+}
+
+static void parse_for_statement (void) {
+
+    int loop_label = anon_label++;
+    int body_label = anon_label++;
+    int continue_label = anon_label++;
+    int break_label = anon_label++;
+    int old_break_label = current_break_label;
+    int old_continue_label = current_continue_label;
+    
+    long old_break_cleanup_base = current_break_cleanup_base;
+    long old_continue_cleanup_base = current_continue_cleanup_base;
+    
+    int cond_known = 0;
+    int cond_value = 1;
+    
+    FILE *saved_ofp;
+    FILE *step_tmp = 0;
+    
+    get_token ();
+    expect (TOK_LPAREN, "(");
+    
+    if (tok.kind == TOK_SEMI) {
+        get_token ();
+    } else {
+        parse_for_header_expression_until (TOK_SEMI);
+    }
+    
+    emit_statement_label (loop_label);
+    
+    if (tok.kind == TOK_SEMI) {
+        get_token ();
+    } else {
+    
+        emit_statement_jump_if_false (break_label);
+        
+        cond_known = statement_condition_constant_known;
+        cond_value = statement_condition_constant_value;
+        
+        if (tok.kind != TOK_SEMI) {
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        }
+        
+        expect (TOK_SEMI, ";");
+    
+    }
+    
+    if (tok.kind == TOK_RPAREN) {
+        get_token ();
+    } else {
+    
+        if (state->ofp) {
+            step_tmp = scc_tmpfile ();
+        }
+        
+        if (step_tmp) {
+        
+            saved_ofp = state->ofp;
+            
+            state->ofp = step_tmp;
+            parse_for_header_expression_until (TOK_RPAREN);
+            
+            state->ofp = saved_ofp;
+        
+        } else {
+            parse_for_header_expression_until (TOK_RPAREN);
+        }
+    
+    }
+    
+    current_break_label = break_label;
+    current_continue_label = continue_label;
+    current_break_cleanup_base = current_block_cleanup_bytes;
+    current_continue_cleanup_base = current_block_cleanup_bytes;
+    
+    if (cond_known && !cond_value) {
+        parse_statement_suppressed ();
+    } else {
+    
+        emit_statement_jump (body_label);
+        emit_statement_label (body_label);
+        
+        parse_statement ();
+        emit_statement_label (continue_label);
+        
+        if (step_tmp) {
+        
+            replay_tmp_file_to_output (step_tmp, state->ofp);
+            scc_close (step_tmp);
+            
+            step_tmp = 0;
+        
+        }
+        
+        emit_statement_jump (loop_label);
+    
+    }
+    
+    if (step_tmp) {
+        scc_close (step_tmp);
+    }
+    
+    emit_statement_label (break_label);
+    
+    current_break_label = old_break_label;
+    current_continue_label = old_continue_label;
+    current_break_cleanup_base = old_break_cleanup_base;
+    current_continue_cleanup_base = old_continue_cleanup_base;
+    
+    statement_ends_control_flow = 0;
+
+}
+
+static void parse_while_statement (void) {
+
+    int loop_label = anon_label++;
+    int body_label = anon_label++;
+    int break_label = anon_label++;
+    int old_break_label = current_break_label;
+    int old_continue_label = current_continue_label;
+    
+    long old_break_cleanup_base = current_break_cleanup_base;
+    long old_continue_cleanup_base = current_continue_cleanup_base;
+    
+    int cond_known;
+    int cond_value;
+    
+    get_token ();
+    expect (TOK_LPAREN, "(");
+    
+    emit_statement_label (loop_label);
+    emit_statement_jump_if_false (break_label);
+    
+    cond_known = statement_condition_constant_known;
+    cond_value = statement_condition_constant_value;
+    
+    if (tok.kind != TOK_RPAREN) {
+        skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+    }
+    
+    expect (TOK_RPAREN, ")");
+    
+    current_break_label = break_label;
+    current_continue_label = loop_label;
+    current_break_cleanup_base = current_block_cleanup_bytes;
+    current_continue_cleanup_base = current_block_cleanup_bytes;
+    
+    if (cond_known && !cond_value) {
+        parse_statement_suppressed ();
+    } else {
+    
+        emit_statement_jump (body_label);
+        emit_statement_label (body_label);
+        
+        parse_statement ();
+        
+        if (!statement_ends_control_flow) {
+            emit_statement_jump (loop_label);
+        }
+    
+    }
+    
+    emit_statement_label (break_label);
+    
+    current_break_label = old_break_label;
+    current_continue_label = old_continue_label;
+    current_break_cleanup_base = old_break_cleanup_base;
+    current_continue_cleanup_base = old_continue_cleanup_base;
+    
+    statement_ends_control_flow = 0;
+
+}
+
+static void parse_do_statement (void) {
+
+    int body_label = anon_label++;
+    int cond_label = anon_label++;
+    int break_label = anon_label++;
+    int old_break_label = current_break_label;
+    int old_continue_label = current_continue_label;
+    
+    long old_break_cleanup_base = current_break_cleanup_base;
+    long old_continue_cleanup_base = current_continue_cleanup_base;
+    
+    int cond_known = 0;
+    int cond_value = 0;
+    
+    get_token ();
+    
+    current_break_label = break_label;
+    current_continue_label = cond_label;
+    current_break_cleanup_base = current_block_cleanup_bytes;
+    current_continue_cleanup_base = current_block_cleanup_bytes;
+    
+    emit_statement_jump (body_label);
+    
+    emit_statement_label (body_label);
+    parse_statement ();
+    
+    emit_statement_label (cond_label);
+    
+    if (_accept (TOK_WHILE)) {
+    
+        expect (TOK_LPAREN, "(");
+        emit_statement_jump_if_false (break_label);
+        
+        cond_known = statement_condition_constant_known;
+        cond_value = statement_condition_constant_value;
+        
+        if (tok.kind != TOK_RPAREN) {
+            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+        }
+        
+        expect (TOK_RPAREN, ")");
+        expect (TOK_SEMI, ";");
+        
+        if (!cond_known || cond_value) {
+            emit_statement_jump (body_label);
+        }
+    
+    } else {
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected while after do statement");
+    }
+    
+    emit_statement_label (break_label);
+    
+    current_break_label = old_break_label;
+    current_continue_label = old_continue_label;
+    current_break_cleanup_base = old_break_cleanup_base;
+    current_continue_cleanup_base = old_continue_cleanup_base;
+    
+    statement_ends_control_flow = 0;
+
+}
+
+static int statement_condition_emit_logical_tail (int label) {
+
+    int skip_label;
+    
+    if (tok.kind == TOK_LOGAND) {
+    
+        get_token ();
+        
+        emit_statement_jump_if_false (label);
+        return 1;
+    
+    }
+    
+    if (tok.kind == TOK_LOGOR) {
+    
+        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);
+            }
+        
+        }
+        
+        emit_statement_jump_if_false (label);
+        emit_statement_label (skip_label);
+        
+        return 1;
+    
+    }
+    
+    return 0;
+
+}
+
+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 ();
+        
+        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);
+        return 1;
+    
+    }
+    
+    emit_statement_cmp_eax_edx_jump_if_false (op, is_unsigned, label);
+    return 1;
+
+}
+
+static int statement_condition_fold_logical_tail (int label) {
+
+    enum token_kind logop;
+    
+    while (tok.kind == TOK_LOGOR || tok.kind == TOK_LOGAND) {
+    
+        logop = tok.kind;
+        
+        /*
+         * Constant short-circuit cases can discard the rest of the condition.
+         *
+         *     true  || anything  -> true
+         *     false && anything  -> false
+         *
+         * Leave tok on ')' so the caller's expect(TOK_RPAREN) still works.
+         */
+        if ((logop == TOK_LOGOR && statement_condition_constant_value) || (logop == TOK_LOGAND && !statement_condition_constant_value)) {
+        
+            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+            return 1;
+        
+        }
+        
+        /*
+         * The left side is non-decisive:
+         *
+         *     false || rhs  -> rhs
+         *     true  && rhs  -> rhs
+         *
+         * So consume the logical operator and emit/fold the RHS normally.
+         */
+        get_token ();
+        
+        statement_condition_constant_known = 0;
+        statement_condition_constant_value = 0;
+        
+        emit_statement_jump_if_false (label);
+        return 1;
+    
+    }
+    
+    return 0;
+
+}
+
+static int source_starts_with_parenthesized_assignment_at (const char *p) {
+
+    int parens = 0;
+    
+    if (!p || *p != '(') {
+        return 0;
+    }
+    
+    /*
+     * 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++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p == '(') {
+        return 0;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    p++;
+    
+    while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+        p++;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    while (parens > 0 && *p == ')') {
+    
+        parens--;
+        p++;
+        
+        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+            p++;
+        }
+    
+    }
+    
+    /*
+     * A condition assignment normally looks like:
+     *
+     *     if ((x = y))
+     *
+     * At this point the scanner has consumed the opening paren(s) and the
+     * identifier.  For the common form above, the assignment operator appears
+     * before the closing paren, so `parens' is still non-zero.  The previous
+     * guard returned 0 before checking for '=', which made the statement
+     * condition parser treat the expression as just `(x' and then report a
+     * false "expected )" at the assignment operator.  Check for assignment
+     * operators first, while still rejecting comparison operators.
+     */
+    if (*p == '=') {
+        return p[1] != '=';
+    }
+    
+    if (parens != 0) {
+        return 0;
+    }
+    
+    if ((*p == '+' || *p == '-' || *p == '*' || *p == '/' || *p == '%' ||
+         *p == '&' || *p == '|' || *p == '^') && p[1] == '=') {
+        return 1;
+    }
+    
+    if ((*p == '<' && p[1] == '<' && p[2] == '=') ||
+        (*p == '>' && p[1] == '>' && p[2] == '=')) {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static int source_starts_with_parenthesized_assignment_now (void) {
+
+    /**
+     * Only test the current token text.  tok.start can point at the start of
+     * the whole source line, so scanning the whole line misclassifies a for
+     * condition such as:
+     *
+     *     for (len = 0; (len < max_len) && str[len]; len++);
+     *
+     * as a parenthesized assignment because of the earlier ``(len = 0`` in the
+     * same line.  This helper is a look-ahead guard; it must not match any
+     * parenthesized assignment except the one beginning at the current token.
+     */
+    if (source_starts_with_parenthesized_assignment_at (tok.caret)) {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static int parenthesized_assignment_open_parens = 0;
+static int parenthesized_assignment_closed_parens = 0;
+
+static void consume_parenthesized_assignment_remaining_closes (void) {
+
+    while (parenthesized_assignment_closed_parens < parenthesized_assignment_open_parens && tok.kind == TOK_RPAREN) {
+    
+        get_token ();
+        parenthesized_assignment_closed_parens++;
+    
+    }
+
+}
+
+static int emit_load_parenthesized_assignment_expression_to_reg_now (const char *reg, int *out_is_unsigned) {
+
+    char *name;
+    int global_index;
+    
+    const char *name_start, *name_caret;
+    unsigned long name_line;
+    
+    enum token_kind op;
+    struct local_symbol *lhs;
+    
+    int lhs_size;
+    int lhs_is_floating;
+    int lhs_is_unsigned;
+    int paren_count = 0;
+    
+    parenthesized_assignment_open_parens = 0;
+    parenthesized_assignment_closed_parens = 0;
+    
+    if (out_is_unsigned) {
+        *out_is_unsigned = 0;
+    }
+    
+    if (tok.kind != TOK_LPAREN || !source_starts_with_parenthesized_assignment_now ()) {
+        return 0;
+    }
+    
+    while (tok.kind == TOK_LPAREN) {
+    
+        paren_count++;
+        get_token ();
+    
+    }
+    
+    if (tok.kind != TOK_IDENT) {
+        return 0;
+    }
+    
+    parenthesized_assignment_open_parens = paren_count;
+    
+    name = xstrdup (tok.ident);
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    get_token ();
+    
+    while (parenthesized_assignment_closed_parens < parenthesized_assignment_open_parens && tok.kind == TOK_RPAREN) {
+    
+        get_token ();
+        parenthesized_assignment_closed_parens++;
+    
+    }
+    
+    if (tok.kind == TOK_DOT || tok.kind == TOK_ARROW) {
+    
+        enum token_kind member_op = tok.kind;
+        char *member;
+        
+        const char *member_start;
+        const char *member_caret;
+        
+        unsigned long member_line;
+        
+        int member_offset = 0;
+        int member_size = DATA_INT & 0x1f;
+        
+        get_token ();
+        
+        member_start = tok.start;
+        member_caret = tok.caret;
+        member_line = get_line_number ();
+        
+        if (tok.kind != TOK_IDENT) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        member = xstrdup (tok.ident);
+        get_token ();
+        
+        if (!find_member_info (member, &member_offset, &member_size)) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
+            
+            free (member);
+            free (name);
+            
+            return 1;
+        
+        }
+        
+        free (member);
+        
+        if (!is_assignment_operator (tok.kind)) {
+        
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect (TOK_SEMI, ";");
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        op = tok.kind;
+        get_token ();
+        
+        lhs = find_local_symbol (name);
+        global_index = find_global_symbol (name);
+        
+        if (!lhs && global_index < 0) {
+        
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            expect (TOK_SEMI, ";");
+            
+            free (name);
+            return 1;
+        
+        }
+        
+        if (state->ofp) {
+        
+            if (member_op == TOK_ARROW) {
+            
+                if (lhs) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_global_to_reg ("edx", lhs->static_label, DATA_PTR);
+                    } else {
+                        emit_load_local_to_reg ("edx", lhs->offset, DATA_PTR);
+                    }
+                
+                } else {
+                    emit_load_global_to_reg ("edx", name, DATA_PTR);
+                }
+            
+            } else {
+            
+                if (lhs) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_address_to_reg_now ("edx", lhs->static_label);
+                    } else {
+                        emit_load_local_address_to_reg_now ("edx", lhs->offset);
+                    }
+                
+                } else {
+                    emit_load_address_to_reg_now ("edx", name);
+                }
+            
+            }
+            
+            if (op == TOK_ASSIGN) {
+            
+                emit_push_reg_now ("edx");
+                emit_load_assignment_rhs_expression_to_reg ("eax");
+                emit_pop_reg_now ("edx");
+            
+            } else {
+            
+                emit_load_member_from_addr_reg_now ("eax", "edx", member_offset, member_size);
+                emit_push_reg_now ("edx");
+                emit_push_reg_now ("eax");
+                
+                if (tok.kind == TOK_TILDE) {
+                
+                    int64_s rhs_const;
+                    get_token ();
+                    
+                    if (tok.kind == TOK_LPAREN) {
+                    
+                        get_token ();
+                        
+                        rhs_const = const64_from_current_foldable_expr ();
+                        expect (TOK_RPAREN, ")");
+                    
+                    } else {
+                        rhs_const = const64_from_current_foldable_expr ();
+                    }
+                    
+                    rhs_const.low = (~rhs_const.low) & U32_MASK;
+                    rhs_const.high = (~rhs_const.high) & U32_MASK;
+                    
+                    emit_load_const32_to_reg_now ("edx", rhs_const);
+                
+                } else if (current_integer_expr_is_foldable_now ()) {
+                
+                    int64_s rhs_const = const64_from_current_foldable_expr ();
+                    emit_load_const32_to_reg_now ("edx", rhs_const);
+                
+                } else {
+                    emit_load_assignment_rhs_expression_to_reg ("edx");
+                }
+                
+                emit_pop_reg_now ("eax");
+                emit_assignment_binary_op (op, 0);
+                emit_pop_reg_now ("edx");
+            
+            }
+            
+            emit_store_member_to_addr_reg_now ("edx", member_offset, "eax", member_size);
+        
+        } else {
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        }
+        
+        expect_semi_or_recover ();
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    if (!is_assignment_operator (tok.kind)) {
+    
+        free (name);
+        return 0;
+    
+    }
+    
+    op = tok.kind;
+    get_token ();
+    
+    lhs = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (!lhs && global_index < 0) {
+    
+        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
+        
+        skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+        expect (TOK_RPAREN, ")");
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    lhs_size = lhs ? lhs->size : get_global_symbol_size (name);
+    lhs_is_floating = lhs ? lhs->is_floating : get_global_symbol_floating (name);
+    lhs_is_unsigned = lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name);
+    
+    if (out_is_unsigned) {
+        *out_is_unsigned = lhs_is_unsigned;
+    }
+    
+    if (state->ofp) {
+    
+        if (lhs_is_floating) {
+        
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "floating assignment expression in condition not implemented");
+            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+        
+        } else if (lhs_size == (DATA_LLONG & 0x1f)) {
+        
+            if (op == TOK_ASSIGN) {
+                emit_load_assignment_rhs_expression_to_pair ("eax", "edx", lhs_is_unsigned);
+            } else {
+            
+                if (lhs) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_global64_to_pair ("eax", "edx", lhs->static_label);
+                    } else {
+                        emit_load_local64_to_pair (lhs->offset, "eax", "edx");
+                    }
+                
+                } else {
+                    emit_load_global64_to_pair ("eax", "edx", name);
+                }
+                
+                /*
+                 * Compound assignments need the complete RHS expression.
+                 * Using emit_load_assignment_rhs_to_pair() only consumes one
+                 * primary operand, so e.g.
+                 *
+                 *     final_value += symbol->frag->address + left_value;
+                 *
+                 * leaves the second + operand for the statement parser and
+                 * reports "expected ;".  Evaluate the full RHS in eax:edx,
+                 * copy it to the RHS pair ebx:ecx, then restore the original
+                 * LHS value before applying the compound operator.
+                 */
+                emit_push_reg_now ("eax");
+                emit_push_reg_now ("edx");
+                
+                emit_load_assignment_rhs_expression_to_pair ("eax", "edx", lhs_is_unsigned);
+                
+                emit_mov_reg_to_reg_now ("ebx", "eax");
+                emit_mov_reg_to_reg_now ("ecx", "edx");
+                
+                emit_pop_reg_now ("edx");
+                emit_pop_reg_now ("eax");
+                
+                emit_preserve_assignment64_regs (op);
+                emit_assignment_binary_op64 (op, lhs_is_unsigned);
+                emit_restore_assignment64_regs (op);
+            
+            }
+            
+            if (lhs) {
+            
+                if (lhs->is_static && lhs->static_label) {
+                    emit_store_pair_to_global64 (lhs->static_label, "eax", "edx");
+                } else {
+                    emit_store_pair_to_local64 (lhs->offset, "eax", "edx");
+                }
+            
+            } else {
+                emit_store_pair_to_global64 (name, "eax", "edx");
+            }
+        
+        } else {
+        
+            if (op == TOK_ASSIGN) {
+                emit_load_assignment_rhs_expression_to_reg (reg);
+            } else {
+            
+                if (lhs) {
+                
+                    if (lhs->is_static && lhs->static_label) {
+                        emit_load_global_to_reg_ex (reg, lhs->static_label, lhs->size, lhs->is_unsigned);
+                    } else {
+                        emit_load_local_to_reg_ex (reg, lhs->offset, lhs->size, lhs->is_unsigned);
+                    }
+                
+                } else {
+                    emit_load_global_to_reg (reg, name, lhs_size);
+                }
+                
+                emit_load_assignment_rhs_to_reg ("edx");
+                
+                if (strcmp (reg, "eax") != 0 && state->ofp) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    mov eax, %s\n", reg);
+                    } else {
+                        fprintf (state->ofp, "    movl %%%s, %%eax\n", reg);
+                    }
+                
+                }
+                
+                emit_assignment_binary_op (op, lhs_is_unsigned);
+                
+                if (strcmp (reg, "eax") != 0 && state->ofp) {
+                
+                    if (state->syntax & ASM_SYNTAX_INTEL) {
+                        fprintf (state->ofp, "    mov %s, eax\n", reg);
+                    } else {
+                        fprintf (state->ofp, "    movl %%eax, %%%s\n", reg);
+                    }
+                
+                }
+            
+            }
+            
+            if (lhs) {
+            
+                if (lhs->is_static && lhs->static_label) {
+                    emit_store_reg_to_global (lhs->static_label, lhs->size, reg);
+                } else {
+                    emit_store_reg_to_local (lhs->offset, lhs->size, reg);
+                }
+            
+            } else {
+                emit_store_reg_to_global (name, lhs_size, reg);
+            }
+        
+        }
+    
+    } else {
+        skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+    }
+    
+    consume_parenthesized_assignment_remaining_closes ();
+    
+    free (name);
+    return 1;
+
+}
+
+static int source_condition_has_top_level_compare_now (const char *p) {
+
+    int paren_depth = 0;
+    int bracket_depth = 0;
+    int saw_operand = 0;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    while (*p) {
+    
+        if (*p == '\'' || *p == '"') {
+        
+            int quote = *p++;
+            
+            while (*p) {
+            
+                if (*p == '\\' && p[1]) {
+                
+                    p += 2;
+                    continue;
+                
+                }
+                
+                if (*p == quote) {
+                
+                    p++;
+                    break;
+                
+                }
+                
+                p++;
+            
+            }
+            
+            saw_operand = 1;
+            continue;
+        
+        }
+        
+        if (*p == '(') {
+        
+            paren_depth++;
+            
+            saw_operand = 1;
+            p++;
+            
+            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;
+                }
+                
+                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]) {
+                
+                    p += 2;
+                    continue;
+                
+                }
+                
+                if (*p == quote) {
+                
+                    p++;
+                    break;
+                
+                }
+                
+                p++;
+            
+            }
+            
+            continue;
+        
+        }
+        
+        if (*p == '(') {
+        
+            paren_depth++;
+            p++;
+            
+            continue;
+        
+        }
+        
+        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;
+    }
+    
+    /*
+     * Do not let the generic integer direct-compare fast path consume
+     * floating conditions such as:
+     *
+     *     while (value_fractional_d - ((int64_t)value_fractional_d) != 0)
+     *
+     * That path lowers the LHS through eax and compares integer dwords,
+     * so the example above becomes low_word - low_word and the fractional
+     * loop exits immediately.  Leave floating expressions for the x87
+     * condition path below.
+     */
+    if (token_is_const_floating_condition_operand_now () || rhs_current_operand_is_floating_now ()) {
+        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)) {
+    
+        while (is_arithmetic_binary_operator (tok.kind)) {
+        
+            op = tok.kind;
+            get_token ();
+            
+            if (rhs_current_operand_is_unsigned_now ()) {
+                is_unsigned = 1;
+            }
+            
+            emit_load_assignment_rhs_to_reg ("edx");
+            emit_assignment_binary_op (op, is_unsigned);
+        
+        }
+        
+        if (token_is_statement_compare_operator (tok.kind)) {
+        
+            op = tok.kind;
+            get_token ();
+            
+            if (rhs_current_operand_is_unsigned_now ()) {
+                is_unsigned = 1;
+            }
+            
+            emit_load_assignment_compare_expression_to_reg ("edx");
+            consume_parenthesized_assignment_remaining_closes ();
+            
+            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_eax_truth_jump_if_false_and_tail (label);
+        return;
+    
+    }
+    
+    if (emit_statement_parenthesized_lhs_compare_jump_if_false_now (label)) {
+        return;
+    }
+    
+    if (emit_statement_direct_compare_jump_if_false_now (label)) {
+        return;
+    }
+    
+    if (tok.kind == TOK_LPAREN && (token_is_const_floating_condition_operand_now () || rhs_current_operand_is_floating_now ())) {
+    
+        double left_float = 0.0;
+        
+        int left_float_constant = 0;
+        int float_size = DATA_DOUBLE & 0x1f;
+        
+        if (token_is_const_floating_condition_operand_now ()) {
+        
+            left_float = parse_floating_const_expr_value_now ();
+            left_float_constant = 1;
+        
+        } else {
+            emit_load_floating_rhs_expression_now (float_size);
+        }
+        
+        if (token_is_statement_compare_operator (tok.kind)) {
+        
+            op = tok.kind;
+            get_token ();
+            
+            if (left_float_constant && (token_is_floating_constant_now () || token_is_const_condition_operand_now ())) {
+            
+                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 = int64_to_double_now (right_int);
+                
+                }
+                
+                statement_condition_constant_known = 1;
+                statement_condition_constant_value = statement_compare_floating_const_true (left_float, op, right_float) ? 1 : 0;
+                
+                if (statement_condition_fold_logical_tail (label)) {
+                    return;
+                }
+                
+                return;
+            
+            }
+            
+            if (left_float_constant) {
+                emit_load_floating_ld_now (float_size, left_float);
+            }
+            
+            emit_load_floating_rhs_expression_now (float_size);
+            emit_statement_floating_compare_jump_if_false (op, label);
+            
+            return;
+        
+        }
+        
+        if (floating_rhs_result_in_eax_bool) {
+        
+            emit_statement_eax_truth_jump_if_false_and_tail (label);
+            
+            floating_rhs_result_in_eax_bool = 0;
+            return;
+        
+        }
+        
+        if (left_float_constant) {
+        
+            statement_condition_constant_known = 1;
+            statement_condition_constant_value = left_float != 0.0 ? 1 : 0;
+            
+            if (statement_condition_fold_logical_tail (label)) {
+                return;
+            }
+            
+            return;
+        
+        }
+        
+        emit_load_floating_ld_now (float_size, 0.0);
+        
+        emit_statement_floating_compare_jump_if_false (TOK_NOTEQ, 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");
+        
+        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;
+
+    }
+    
+    if (tok.kind == TOK_LPAREN && !source_starts_with_parenthesized_assignment_now ()) {
+    
+        get_token ();
+        
+        emit_statement_jump_if_false (label);
+        expect (TOK_RPAREN, ")");
+        
+        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;
+    
+    }
+    
+    /*
+     * Fold simple constant conditions at parse time.  This avoids emitting:
+     *
+     *     mov eax, 1
+     *     test eax, eax
+     *     jz ...
+     *
+     * for things like if (1), and avoids cmp/jcc for things like
+     * if (1 < 10), if (5 > 2), if (1ULL < 10LL), etc.
+     */
+    if (token_is_const_floating_condition_operand_now () || rhs_current_operand_is_floating_now ()) {
+    
+        double left_float = 0.0;
+        
+        int left_float_constant = 0;
+        int float_size = DATA_DOUBLE & 0x1f;
+        
+        if (token_is_const_floating_condition_operand_now ()) {
+        
+            left_float = parse_floating_const_expr_value_now ();
+            left_float_constant = 1;
+        
+        } else {
+            emit_load_floating_rhs_expression_now (float_size);
+        }
+        
+        if (token_is_statement_compare_operator (tok.kind)) {
+        
+            op = tok.kind;
+            get_token ();
+            
+            if (left_float_constant && (token_is_floating_constant_now () || token_is_const_condition_operand_now ())) {
+            
+                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 = int64_to_double_now (right_int);
+                
+                }
+                
+                statement_condition_constant_known = 1;
+                statement_condition_constant_value = statement_compare_floating_const_true (left_float, op, right_float) ? 1 : 0;
+                
+                if (statement_condition_fold_logical_tail (label)) {
+                    return;
+                }
+                
+                return;
+            
+            }
+            
+            if (left_float_constant) {
+                emit_load_floating_ld_now (float_size, left_float);
+            }
+            
+            emit_load_floating_rhs_expression_now (float_size);
+            emit_statement_floating_compare_jump_if_false (op, label);
+            
+            return;
+        
+        }
+        
+        if (floating_rhs_result_in_eax_bool) {
+        
+            emit_statement_eax_truth_jump_if_false_and_tail (label);
+            
+            floating_rhs_result_in_eax_bool = 0;
+            return;
+        
+        }
+        
+        if (left_float_constant) {
+        
+            statement_condition_constant_known = 1;
+            statement_condition_constant_value = left_float != 0.0 ? 1 : 0;
+            
+            if (statement_condition_fold_logical_tail (label)) {
+                return;
+            }
+            
+            return;
+        
+        }
+        
+        emit_load_floating_ld_now (float_size, 0.0);
+        emit_statement_floating_compare_jump_if_false (TOK_NOTEQ, label);
+        
+        return;
+    
+    }
+    
+    /*
+     * 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 = current_integer_expr_is_foldable_now ();
+        int left_unsigned = rhs_current_operand_is_unsigned_now ();
+        
+        int64_s left;
+        
+        if (fold_whole_expr) {
+            left = const64_from_current_foldable_expr ();
+        } else {
+            left = const64_from_current_operand ();
+        }
+        
+        if (is_arithmetic_binary_operator (tok.kind)) {
+        
+            emit_statement_const32_to_eax (left);
+            
+            while (is_arithmetic_binary_operator (tok.kind)) {
+            
+                op = tok.kind;
+                get_token ();
+                
+                if (rhs_current_operand_is_unsigned_now ()) {
+                    left_unsigned = 1;
+                }
+                
+                emit_load_assignment_rhs_to_reg ("edx");
+                emit_assignment_binary_op (op, left_unsigned);
+            
+            }
+            
+            if (token_is_statement_compare_operator (tok.kind)) {
+            
+                op = tok.kind;
+                get_token ();
+                
+                is_unsigned = left_unsigned;
+                
+                if (rhs_current_operand_is_unsigned_now ()) {
+                    is_unsigned = 1;
+                }
+                
+                emit_statement_cmp_eax_edx_jump_if_false_and_tail (op, is_unsigned, label);
+                return;
+            
+            }
+            
+            emit_statement_test_eax_jump_if_false (label);
+            return;
+        
+        }
+        
+        if (token_is_statement_compare_operator (tok.kind)) {
+        
+            op = tok.kind;
+            get_token ();
+            
+            is_unsigned = left_unsigned;
+            
+            if (rhs_current_operand_is_unsigned_now ()) {
+                is_unsigned = 1;
+            }
+            
+            if (token_is_floating_constant_now ()) {
+            
+                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;
+                statement_condition_constant_value = statement_compare_floating_const_true (left_float, op, right_float) ? 1 : 0;
+                
+                if (statement_condition_fold_logical_tail (label)) {
+                    return;
+                }
+                
+                return;
+            
+            }
+            
+            if (token_is_const_condition_operand_now ()) {
+            
+                int64_s right;
+                
+                if (current_integer_expr_is_foldable_now ()) {
+                    right = const64_from_current_foldable_expr ();
+                } else {
+                    right = const64_from_current_operand ();
+                }
+                
+                statement_condition_constant_known = 1;
+                statement_condition_constant_value = statement_compare_const64_true (left, op, right, is_unsigned) ? 1 : 0;
+                
+                if (statement_condition_fold_logical_tail (label)) {
+                    return;
+                }
+                
+                return;
+            
+            }
+            
+            if (rhs_current_operand_is_floating_now ()) {
+            
+                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);
+                emit_statement_floating_compare_jump_if_false (op, label);
+                
+                return;
+            
+            }
+            
+            emit_statement_const32_to_eax (left);
+            emit_load_assignment_rhs_expression_to_reg ("edx");
+            
+            emit_statement_cmp_eax_edx_jump_if_false_and_tail (op, is_unsigned, label);
+            return;
+        
+        }
+        
+        statement_condition_constant_known = 1;
+        statement_condition_constant_value = int64_statement_truth_value (left) ? 1 : 0;
+        
+        if (statement_condition_fold_logical_tail (label)) {
+            return;
+        }
+        
+        return;
+    
+    }
+    
+    /*
+     * A leading unary ! always yields an int truth value.  Do not route it
+     * through the 64-bit condition path just because the operand text happens
+     * to mention a symbol that the coarse scanner thinks is 64-bit; that path
+     * expects an unconverted 64-bit value and will compare EDX:EAX against
+     * uninitialised ECX:EBX for a plain if (!p).
+     */
+    if (tok.kind == TOK_XMARK) {
+    
+        emit_load_assignment_rhs_expression_to_reg ("eax");
+        
+        emit_statement_eax_truth_jump_if_false_and_tail (label);
+        return;
+    
+    }
+    
+    if (current_expression_mentions_64bit_symbol_now ()) {
+    
+        int old_assignment64_stop_before_condition_operator;
+        is_unsigned = rhs_current_operand_is_unsigned_now ();
+        
+        old_assignment64_stop_before_condition_operator = assignment64_stop_before_condition_operator;
+        assignment64_stop_before_condition_operator = 1;
+        
+        emit_load_assignment_rhs_expression_to_pair ("eax", "edx", is_unsigned);
+        assignment64_stop_before_condition_operator = old_assignment64_stop_before_condition_operator;
+        
+        if (token_is_statement_compare_operator (tok.kind)) {
+        
+            op = tok.kind;
+            get_token ();
+            
+            if (rhs_current_operand_is_unsigned_now ()) {
+                is_unsigned = 1;
+            }
+            
+            if (state->ofp) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    fprintf (state->ofp, "    push ebx\n");
+                    fprintf (state->ofp, "    push eax\n");
+                    fprintf (state->ofp, "    push edx\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    pushl %%ebx\n");
+                    fprintf (state->ofp, "    pushl %%eax\n");
+                    fprintf (state->ofp, "    pushl %%edx\n");
+                
+                }
+            
+            }
+            
+            /*
+             * The stop-before-compare guard is only needed while loading the
+             * left hand side of the statement condition.  After the condition
+             * operator has been consumed, the right hand side must be parsed as
+             * a complete expression.  Keeping the guard enabled here makes a
+             * parenthesized conditional expression such as:
+             *
+             *     i < (len_fract == 0 ? 1 : precision - len_fract)
+             *
+             * stop at the nested == and leave the parser expecting the closing
+             * ')'.  That is what produced the false "expected )" diagnostic.
+             */
+            emit_load_assignment_rhs_expression_to_pair ("eax", "edx", is_unsigned);
+            
+            if (state->ofp) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    fprintf (state->ofp, "    mov ebx, eax\n");
+                    fprintf (state->ofp, "    mov ecx, edx\n");
+                    fprintf (state->ofp, "    pop edx\n");
+                    fprintf (state->ofp, "    pop eax\n");
+                
+                } else {
+                
+                    fprintf (state->ofp, "    movl %%eax, %%ebx\n");
+                    fprintf (state->ofp, "    movl %%edx, %%ecx\n");
+                    fprintf (state->ofp, "    popl %%edx\n");
+                    fprintf (state->ofp, "    popl %%eax\n");
+                
+                }
+            
+            }
+            
+            emit_statement_cmp64_to_eax (op, is_unsigned);
+            
+            if (state->ofp) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                    fprintf (state->ofp, "    pop ebx\n");
+                } else {
+                    fprintf (state->ofp, "    popl %%ebx\n");
+                }
+            
+            }
+            
+            emit_statement_test_eax_jump_if_false (label);
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_LOGAND) {
+        
+            get_token ();
+            
+            emit_statement_test_pair_jump_if_false ("eax", "edx", label);
+            emit_statement_jump_if_false (label);
+            
+            return;
+        
+        }
+        
+        if (tok.kind == TOK_LOGOR) {
+        
+            int skip_label = anon_label++;
+            get_token ();
+            
+            emit_statement_test_pair_jump_if_true ("eax", "edx", skip_label);
+            emit_statement_jump_if_false (label);
+            emit_statement_label (skip_label);
+            
+            return;
+        
+        }
+        
+        emit_statement_test_pair_jump_if_false ("eax", "edx", label);
+        return;
+    
+    }
+    
+    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)) {
+    
+        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);
+
+}
+
+static int token_text_starts_void_cast_now (void) {
+
+    const char *p = tok.caret;
+    
+    if (!p || *p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    if (strncmp (p, "void", 4) != 0) {
+        return 0;
+    }
+    
+    p += 4;
+    
+    if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t') {
+        p++;
+    }
+    
+    return *p == ')';
+
+}
+
+static int parse_void_cast_discard_statement (void) {
+
+    if (tok.kind != TOK_LPAREN || !token_text_starts_void_cast_now ()) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    expect (TOK_VOID, "void");
+    expect (TOK_RPAREN, ")");
+    
+    if (tok.kind != TOK_SEMI) {
+    
+        emit_load_assignment_rhs_expression_to_reg ("eax");
+        
+        if (tok.kind != TOK_SEMI) {
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        }
+    
+    }
+    
+    expect (TOK_SEMI, ";");
+    return 1;
+
+}
+
+static int token_text_looks_like_postfix_assignment_now (void) {
+
+    const char *p;
+    int saw_postfix;
+    int paren_depth;
+    int bracket_depth;
+    
+    if (tok.caret) {
+        p = tok.caret;
+    } else if (tok.start) {
+        p = tok.start;
+    } else {
+        return 0;
+    }
+    
+    saw_postfix = 0;
+    paren_depth = 0;
+    bracket_depth = 0;
+    
+    while (*p && *p != ';' && *p != '\n') {
+    
+        if (*p == '(') {
+        
+            /**
+             * A postfix/member expression followed by a top-level '(' is a
+             * function call through that member, not a postfix assignment.
+             * This pre-scan must reject it before the destructive postfix
+             * assignment parser consumes the tokens.
+             */
+            if (saw_postfix && paren_depth == 0 && bracket_depth == 0) {
+                return 0;
+            }
+            
+            paren_depth++;
+        
+        } else if (*p == ')') {
+            if (paren_depth > 0) paren_depth--;
+        } else if (*p == '[') {
+        
+            saw_postfix = 1;
+            bracket_depth++;
+        
+        } else if (*p == ']') {
+            if (bracket_depth > 0) bracket_depth--;
+        } else if (paren_depth == 0 && bracket_depth == 0 && *p == ',') {
+            return 0;
+        } else if (paren_depth == 0 && bracket_depth == 0 && *p == '.') {
+            saw_postfix = 1;
+        } else if (paren_depth == 0 && bracket_depth == 0 && *p == '-' && p[1] == '>') {
+        
+            saw_postfix = 1;
+            p++;
+        
+        } else if (paren_depth == 0 && bracket_depth == 0 && *p == '=') {
+        
+            if (p[1] == '=') {
+                return 0;
+            }
+            
+            return saw_postfix;
+        
+        }
+        
+        p++;
+    
+    }
+    
+    return 0;
+
+}
+
+static int source_starts_with_parenthesized_indirect_call_now (void) {
+
+    const char *p = tok.caret;
+    
+    int member_depth = 1;
+    int saw_member = 0;
+    int depth;
+    
+    if (!p || *p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '*') {
+        return 0;
+    }
+    
+    depth = 1;
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    /*
+     * Accept both
+     *
+     *     (*obj->member)(...)
+     *     (*(obj->member))(...)
+     *
+     * but keep this recognizer deliberately narrow.  It must not claim an
+     * arbitrary parenthesized expression, otherwise normal statement parsing
+     * and C labels can be pulled into this special call path.
+     */
+    if (*p == '(') {
+    
+        depth++;
+        
+        member_depth = 2;
+        p++;
+    
+    }
+    
+    while (*p && depth > 0) {
+    
+        if (*p == '(') {
+            depth++;
+        } else if (*p == ')') {
+        
+            depth--;
+            
+            if (depth == 0) {
+                break;
+            }
+        
+        } else if (depth == member_depth && *p == '-' && p[1] == '>') {
+        
+            saw_member = 1;
+            p++;
+        
+        } else if (depth == member_depth && *p == '.') {
+            saw_member = 1;
+        }
+        
+        p++;
+    
+    }
+    
+    if (depth != 0 || !saw_member) {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '(';
+
+}
+
+static int parse_postfix_assignment_statement_now (void) {
+
+    char *name;
+    
+    struct local_symbol *src;
+    int global_index;
+    
+    enum token_kind assign_op;
+    int lvalue_size;
+    
+    if (tok.kind != TOK_IDENT || !token_text_looks_like_postfix_assignment_now ()) {
+        return 0;
+    }
+    
+    name = xstrdup (tok.ident);
+    
+    {
+    
+        const char *name_start = tok.start;
+        const char *name_caret = tok.caret;
+        
+        unsigned long name_line = get_line_number ();
+        get_token ();
+        
+        src = find_local_symbol (name);
+        global_index = find_global_symbol (name);
+        
+        if (!src && global_index < 0) {
+        
+            free (name);
+            return 0;
+        
+        }
+        
+        if (!emit_parse_postfix_copy_source_address_now ("edx", src, name, name_start, name_caret, name_line)) {
+        
+            free (name);
+            return 0;
+        
+        }
+    
+    }
+    
+    free (name);
+    
+    if (!is_assignment_operator (tok.kind)) {
+        return 0;
+    }
+    
+    assign_op = tok.kind;
+    lvalue_size = index_step_size (postfix_copy_lvalue_size);
+    
+    if (lvalue_size <= 0) {
+        lvalue_size = DATA_INT & 0x1f;
+    }
+    
+    get_token ();
+    
+    if (assign_op == TOK_ASSIGN) {
+    
+        if (postfix_member_is_floating || token_is_floating_constant_now () || rhs_current_operand_is_floating_now ()) {
+        
+            emit_push_reg_now ("edx");
+            emit_load_floating_rhs_expression_now (lvalue_size);
+            
+            emit_pop_reg_now ("edx");
+            emit_store_floating_member_to_addr_reg_now ("edx", 0, lvalue_size);
+            
+            return 1;
+        
+        }
+        
+        if (lvalue_size == (DATA_LLONG & 0x1f)) {
+        
+            emit_push_reg_now ("edx");
+            
+            emit_load_assignment_rhs_expression_to_pair ("eax", "edx", 1);
+            emit_pop_reg_now ("ecx");
+            
+            emit_store_pair_to_deref_reg_now ("ecx", "eax", "edx");
+            return 1;
+        
+        }
+        
+        if (lvalue_size > (DATA_LLONG & 0x1f)
+            && tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now ()
+            && get_global_symbol_kind (tok.ident) == GLOBAL_SYMBOL_FUNCTION
+            && get_global_symbol_size (tok.ident) > (DATA_LLONG & 0x1f)) {
+        
+            char *rhs_name = xstrdup (tok.ident);
+            const char *rhs_start = tok.start;
+            const char *rhs_caret = tok.caret;
+            unsigned long rhs_line = get_line_number ();
+            
+            emit_push_reg_now ("edx");
+            
+            pending_struct_return_lhs = 0;
+            pending_struct_return_global_name = 0;
+            pending_struct_return_stack_address = 1;
+            pending_struct_return_stack_offset = 0;
+            
+            get_token ();
+            emit_call_identifier_to_reg_now (rhs_name, "eax", rhs_start, rhs_caret, rhs_line);
+            
+            pending_struct_return_stack_address = 0;
+            pending_struct_return_stack_offset = 0;
+            
+            emit_pop_reg_now ("edx");
+            
+            free (rhs_name);
+            return 1;
+        
+        }
+        
+        if (emit_aggregate_copy_from_current_rhs_to_addr_reg_now ("edx", 0, lvalue_size)) {
+            return 1;
+        }
+        
+        /**
+         * Keep the computed lvalue address across the RHS evaluation.
+         * The RHS emitter is free to use edx for indexing, calls, and
+         * arithmetic, so storing through edx after it can corrupt memory.
+         */
+        emit_push_reg_now ("edx");
+        
+        emit_load_assignment_rhs_expression_to_reg ("eax");
+        emit_pop_reg_now ("edx");
+
+    } else {
+    
+        emit_push_reg_now ("edx");
+        
+        emit_load_member_from_addr_reg_now ("eax", "edx", 0, lvalue_size);
+        emit_push_reg_now ("eax");
+        
+        emit_load_assignment_rhs_expression_to_reg ("edx");
+        emit_pop_reg_now ("eax");
+        
+        emit_assignment_binary_op (assign_op, 0);
+        emit_pop_reg_now ("edx");
+    
+    }
+    
+    emit_store_reg_to_deref_reg_now ("edx", "eax", lvalue_size);
+    return 1;
+
+}
+
+static int parse_parenthesized_member_function_pointer_call_statement (void) {
+
+    struct local_symbol *src;
+    char *name;
+    
+    int global_index;
+    int wrapped_member_expr = 0;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    int base_size = DATA_INT & 0x1f;
+    
+    const char *base_tag_name = 0;
+    
+    if (tok.kind != TOK_LPAREN || !source_starts_with_parenthesized_indirect_call_now ()) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    if (tok.kind != TOK_STAR) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    if (tok.kind == TOK_LPAREN) {
+    
+        wrapped_member_expr = 1;
+        get_token ();
+    
+    }
+    
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+        return 0;
+    }
+    
+    name = xstrdup (tok.ident);
+    name_start = tok.start;
+    name_caret = tok.caret;
+    name_line = get_line_number ();
+    
+    get_token ();
+    
+    src = find_local_symbol (name);
+    global_index = find_global_symbol (name);
+    
+    if (!src && global_index < 0) {
+    
+        free (name);
+        return 0;
+    
+    }
+    
+    if (tok.kind == TOK_ARROW || tok.kind == TOK_LBRACK) {
+    
+        if (src) {
+        
+            base_size = src->pointer_depth > 0 ? src->pointed_size : src->size;
+            base_tag_name = src->pointer_depth > 0 ? src->pointed_tag_name : 0;
+        
+        } else {
+        
+            base_size = get_global_symbol_pointer_depth (name) > 0 ? get_global_symbol_pointed_size (name) : get_global_symbol_size (name);
+            base_tag_name = get_global_symbol_pointer_depth (name) > 0 ? get_global_symbol_tag_name (name) : 0;
+        
+        }
+    
+    } else if (tok.kind == TOK_DOT) {
+    
+        if (src) {
+        
+            base_size = src->size;
+            base_tag_name = src->tag_name;
+        
+        } else {
+        
+            base_size = get_global_symbol_size (name);
+            base_tag_name = get_global_symbol_tag_name (name);
+        
+        }
+    
+    } else {
+    
+        free (name);
+        return 0;
+    
+    }
+    
+    postfix_copy_lvalue_size = base_size;
+    postfix_copy_lvalue_tag_name = base_tag_name;
+    
+    if (!emit_parse_postfix_copy_source_address_now ("ecx", src, name, name_start, name_caret, name_line)) {
+    
+        free (name);
+        return 0;
+    
+    }
+    
+    free (name);
+    
+    if (wrapped_member_expr) {
+        expect (TOK_RPAREN, ")");
+    }
+    
+    expect (TOK_RPAREN, ")");
+    
+    if (tok.kind != TOK_LPAREN) {
+        return 0;
+    }
+    
+    emit_load_deref_reg_now ("ecx", DATA_PTR & 0x1f);
+    emit_call_pointer_in_reg_now ("ecx", "eax");
+    
+    expect_semi_or_recover ();
+    return 1;
+
+}
+
+static void parse_statement_suppressed (void) {
+
+    FILE *save_ofp = state->ofp;
+    
+    state->ofp = 0;
+    parse_statement ();
+    state->ofp = save_ofp;
+
+}
+
+static void parse_statement (void) {
+
+    statement_ends_control_flow = 0;
+    flush_pending_statement_labels ();
+    
+    if (parse_inline_asm_statement ()) {
+        return;
+    }
+    
+    if (parse_prefix_incdec_statement ()) {
+        return;
+    }
+    
+    if (parse_void_cast_discard_statement ()) {
+        return;
+    }
+    
+    
+    if (tok.kind == TOK_LPAREN && source_starts_lparen_deref_postfix_incdec_at (tok.caret)) {
+    
+        get_token ();
+        
+        if (emit_load_parenthesized_deref_postfix_incdec_subscript_to_reg_now ("eax")) {
+        
+            expect_semi_or_recover ();
+            return;
+        
+        }
+    
+    }
+    
+    if (parse_parenthesized_deref_subscript_statement ()) {
+    
+        expect_semi_or_recover ();
+        return;
+    
+    }
+    
+    if (parse_parenthesized_member_function_pointer_call_statement ()) {
+        return;
+    }
+    
+    if (tok.kind == TOK_LPAREN) {
+    
+        int parenthesized_assignment_is_unsigned;
+        
+        if (emit_load_parenthesized_assignment_expression_to_reg_now ("eax", &parenthesized_assignment_is_unsigned)) {
+        
+            expect_semi_or_recover ();
+            return;
+        
+        }
+    
+    }
+    
+    if (tok.kind == TOK_LPAREN && parse_parenthesized_indirect_member_assignment_statement ()) {
+        return;
+    }
+    
+    if (parse_indirect_assignment_statement ()) {
+        return;
+    }
+    
+    if (parse_postfix_assignment_statement_now ()) {
+    
+        expect_semi_or_recover ();
+        return;
+    
+    }
+    
+    if (parse_identifier_assignment_statement ()) {
+        return;
+    }
+    
+    if (tok.kind == TOK_RETURN) {
+    
+        int has_value = 0;
+        long v = 0;
+        
+        const char *ret_start = tok.start;
+        const char *ret_caret = tok.caret;
+        
+        int ret_line = get_line_number ();
+        
+        current_function_has_return_statement = 1;
+        get_token ();
+        
+        if (tok.kind != TOK_SEMI) {
+        
+            if (current_function_is_void) {
+            
+                FILE *saved_return_ofp = state->ofp;
+                state->ofp = 0;
+                
+                emit_load_assignment_rhs_expression_to_reg ("eax");
+                state->ofp = saved_return_ofp;
+            
+            } else if (current_function_is_floating) {
+            
+                if (state->ofp && pending_return_jump) {
+                    emit_pending_return_jump ();
+                }
+                
+                emit_load_floating_rhs_expression_now (current_function_return_size);
+            
+            } else {
+            
+                if (state->ofp && pending_return_jump) {
+                    emit_pending_return_jump ();
+                }
+                
+                if (state->ofp) {
+                
+                    if (current_function_returns_aggregate) {
+                    
+                        if (state->syntax & ASM_SYNTAX_INTEL) {
+                            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov edx, dword [ebp + 8]\n" : "    mov edx, dword ptr [ebp + 8]\n"));
+                        } else {
+                            fprintf (state->ofp, "    movl 8(%%ebp), %%edx\n");
+                        }
+                        
+                        if (!emit_aggregate_copy_from_current_rhs_to_addr_reg_now ("edx", 0, current_function_return_size)) {
+                            emit_load_assignment_rhs_expression_to_reg ("eax");
+                        }
+                    
+                    } else if (current_function_return_size == (DATA_LLONG & 0x1f)) {
+                        emit_load_assignment_rhs_expression_to_pair ("eax", "edx", current_function_return_is_unsigned);
+                    } else if (current_expression_mentions_64bit_symbol_now ()) {
+                        emit_load_assignment_rhs_expression_to_pair ("eax", "edx", current_function_return_is_unsigned);
+                    } else {
+                        emit_load_assignment_rhs_expression_to_reg ("eax");
+                    }
+                
+                } else {
+                    v = const_from_current_expr ();
+                }
+            
+            }
+            
+            has_value = 1;
+        
+        }
+        
+        if (current_function_is_void && has_value) {
+            report_line_at (get_filename (), ret_line, REPORT_WARNING, ret_start, ret_caret, "return with a value in void function");
+        } else if (!current_function_is_void && !has_value) {
+            report_line_at (get_filename (), ret_line, REPORT_WARNING, ret_start, ret_caret, "return with no value in non-void function");
+        }
+        
+        if (state->ofp) {
+        
+            if (pending_return_jump) {
+                emit_pending_return_jump ();
+            }
+            
+            if (!current_function_is_floating && !has_value) {
+            
+                if (state->syntax & ASM_SYNTAX_INTEL) {
+                
+                    fprintf (state->ofp, "    mov eax, %ld\n", v);
+                    
+                    if (current_function_return_size == (DATA_LLONG & 0x1f)) {
+                        fprintf (state->ofp, "    cdq\n");
+                    }
+                
+                } else {
+                
+                    fprintf (state->ofp, "    movl $%ld, %%eax\n", v);
+                    
+                    if (current_function_return_size == (DATA_LLONG & 0x1f)) {
+                        fprintf (state->ofp, "    cdq\n");
+                    }
+                
+                }
+            
+            }
+            
+            pending_return_jump = 1;
+            statement_ends_control_flow = 1;
+        
+        }
+        
+        expect (TOK_SEMI, ";");
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_LBRACE) {
+    
+        parse_block ();
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_IF) {
+    
+        int else_label = anon_label++;
+        int end_label = anon_label++;
+        
+        get_token ();
+        expect (TOK_LPAREN, "(");
+        
+        /*
+         * Compile the full if-condition as an expression before testing it.
+         * The older specialised condition emitter jumps to the false label as
+         * soon as the left side of a logical OR is false, which skips the RHS.
+         * That miscompiled expressions such as:
+         *
+         *     if ((base && !base->dword) || (index && ...))
+         *
+         * and made pdas reject valid 32-bit AT&T base/index operands.
+         */
+        emit_statement_jump_if_false (else_label);
+        
+        if (tok.kind != TOK_RPAREN) {
+            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
+        }
+        
+        expect (TOK_RPAREN, ")");
+        
+        if (statement_condition_constant_known) {
+        
+            if (statement_condition_constant_value) {
+            
+                parse_statement ();
+                
+                if (_accept (TOK_ELSE)) {
+                    parse_statement_suppressed ();
+                }
+            
+            } else {
+            
+                parse_statement_suppressed ();
+                
+                if (_accept (TOK_ELSE)) {
+                    parse_statement ();
+                }
+            
+            }
+            
+            return;
+        
+        }
+        
+        parse_statement ();
+        
+        {
+        
+            int then_ends_control_flow = statement_ends_control_flow;
+            
+            if (_accept (TOK_ELSE)) {
+            
+                if (pending_return_jump) {
+                
+                    emit_pending_return_jump ();
+                    then_ends_control_flow = 1;
+                
+                } else if (!then_ends_control_flow) {
+                    emit_statement_jump (end_label);
+                }
+                
+                emit_statement_label (else_label);
+                parse_statement ();
+                
+                if (pending_return_jump) {
+                
+                    emit_pending_return_jump ();
+                    statement_ends_control_flow = 1;
+                
+                }
+                
+                emit_statement_label (end_label);
+                statement_ends_control_flow = then_ends_control_flow && statement_ends_control_flow;
+            
+            } else {
+            
+                if (pending_return_jump) {
+                    emit_pending_return_jump ();
+                }
+                
+                emit_statement_label (else_label);
+                statement_ends_control_flow = 0;
+            
+            }
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_SWITCH) {
+    
+        parse_switch_statement ();
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_WHILE) {
+    
+        parse_while_statement ();
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_DO) {
+    
+        parse_do_statement ();
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_FOR) {
+    
+        parse_for_statement ();
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_GOTO) {
+    
+        const char *label_start;
+        const char *label_caret;
+        
+        unsigned long label_line;
+        char *label_name = 0;
+        
+        get_token ();
+        
+        label_start = tok.start;
+        label_caret = tok.caret;
+        label_line = get_line_number ();
+        
+        if (tok.kind == TOK_IDENT) {
+        
+            label_name = xstrdup (tok.ident);
+            get_token ();
+            
+            /*
+             * Do not eagerly pop block-local temporary storage for a forward
+             * goto.  A label can legally be later in the same block after
+             * nested statements, and the earlier text scan was too
+             * conservative: it treated the first nested '}' as the end of the
+             * current block.  That produced an extra add to esp before
+             * `goto skip;` in i386_gen.c's process_bitfield_init(), corrupting
+             * the stack before the local label was reached.
+             */
+            
+            reference_goto_label (label_name, label_line, label_start, label_caret);
+            statement_ends_control_flow = 1;
+            
+            free (label_name);
+        
+        } else {
+            report_line_at (get_filename (), label_line, REPORT_ERROR, label_start, label_caret, "expected label name after goto");
+        }
+        
+        expect (TOK_SEMI, ";");
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_BREAK) {
+    
+        int target_label = current_break_label;
+        
+        long cleanup_base = current_break_cleanup_base;
+        long cleanup_bytes;
+        
+        get_token ();
+        
+        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) {
+        
+            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_CASE) {
+    
+        long value;
+        unsigned long case_line = get_line_number ();
+        
+        const char *case_start = tok.start;
+        const char *case_caret = tok.caret;
+        
+        get_token ();
+        
+        value = const_from_current_case_expr ();
+        add_switch_case_label (value, case_line, case_start, case_caret);
+        
+        if (tok.kind != TOK_COLON) {
+            skip_balanced_until (TOK_COLON, TOK_EOF, TOK_EOF);
+        }
+        
+        expect (TOK_COLON, ":");
+        statement_ends_control_flow = 0;
+        
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_DEFAULT) {
+    
+        unsigned long default_line = get_line_number ();
+        
+        const char *default_start = tok.start;
+        const char *default_caret = tok.caret;
+        
+        get_token ();
+        
+        set_switch_default_label (default_line, default_start, default_caret);
+        expect (TOK_COLON, ":");
+        
+        statement_ends_control_flow = 0;
+        return;
+    
+    }
+    
+    if (tok.kind != TOK_SEMI && tok.kind != TOK_RBRACE && tok.kind != TOK_EOF) {
+    
+        if (parse_postfix_assignment_statement_now ()) {
+        
+            if (tok.kind == TOK_SEMI) {
+            
+                get_token ();
+                return;
+            
+            }
+            
+            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+            
+            expect (TOK_SEMI, ";");
+            return;
+        
+        }
+        
+        emit_load_assignment_rhs_expression_to_reg ("eax");
+        
+        if (tok.kind == TOK_SEMI) {
+        
+            get_token ();
+            return;
+        
+        }
+        
+        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
+        
+        expect (TOK_SEMI, ";");
+        return;
+    
+    }
+    
+    expect (TOK_SEMI, ";");
+
+}
+
+static void parse_function_body (const char *name, int storage_class, int is_inline, int return_is_void, int return_is_floating, int return_is_unsigned, int return_size, unsigned long function_line, const char *function_start, const char *function_caret) {
+
+    int old_return_label = current_return_label;
+    int should_emit = 1;
+    int emit_body = 1;
+    int emit_public = 1;
+    int emit_inline_definition_to_output = 1;
+    
+    FILE *saved_ofp;
+    FILE *function_tmp = 0;
+    
+    char *inline_asm_text = 0;
+    char *function_asm_text = 0;
+    
+    int capture_inline_body = 0;
+    int capture_function_body = 0;
+    
+    int saved_declarator_function_param_count;
+    int saved_declarator_function_has_prototype;
+    int saved_declarator_function_is_variadic;
+    int saved_current_section = current_section;
+    
+    int old_function_is_void;
+    int old_function_is_floating;
+    int old_function_return_size;
+    int old_function_return_is_unsigned;
+    int old_function_returns_aggregate;
+    int old_function_has_return_statement;
+    
+    char *function_filename_copy = 0;
+    
+    /**
+     * Inline definitions are compiled into a temporary assembler buffer so
+     * calls in this translation unit can be expanded at the call site.
+     *
+     *   inline int f(...) { ... }
+     *   static inline int f(...) { ... }
+     *       Remember the generated body for inline expansion.  Do not emit an
+     *       out-of-line copy unless a later rule explicitly asks for one.
+     *
+     *   extern inline int f(...) { ... }
+     *       Remember the generated body and also emit the normal public
+     *       definition.
+     *
+     *   int f(...) { ... }
+     *       Normal external definition.  Emit it as public.
+     */
+    if (storage_class == STORAGE_STATIC) {
+        emit_public = 0;
+    } else if (is_inline && storage_class != STORAGE_EXTERN) {
+        emit_public = 0;
+    }
+    
+    if (is_inline && storage_class != STORAGE_EXTERN && !return_is_floating) {
+        emit_inline_definition_to_output = 0;
+    }
+    
+    saved_ofp = state->ofp;
+    
+    saved_declarator_function_param_count = declarator_function_param_count;
+    saved_declarator_function_has_prototype = declarator_function_has_prototype;
+    saved_declarator_function_is_variadic = declarator_function_is_variadic;
+    
+    if (get_filename ()) {
+        function_filename_copy = xstrdup (get_filename ());
+    }
+    
+    capture_inline_body = is_inline && saved_ofp != 0;
+    capture_function_body = saved_ofp != 0;
+    
+    if (capture_function_body) {
+    
+        function_tmp = scc_tmpfile ();
+        
+        if (!function_tmp) {
+            capture_function_body = 0;
+        }
+    
+    }
+    
+    if (emit_body) {
+    
+        if (parsed_dllimport) {
+            report_line_at (get_filename (), last_declarator_name_line, REPORT_ERROR, last_declarator_name_start, last_declarator_name_caret, "function '%s' cannot be defined with '__dllimport'", name);
+        }
+        
+        should_emit = add_global_symbol (name, GLOBAL_SYMBOL_FUNCTION, 0, last_declarator_name_start, last_declarator_name_caret, last_declarator_name_line);
+        
+        set_global_symbol_size (name, return_is_void ? DATA_VOID : return_size);
+        set_global_symbol_unsigned (name, 0);
+        set_global_symbol_floating (name, return_is_floating);
+        set_global_symbol_returns_void (name, return_is_void);
+        set_global_symbol_calling_convention (name, (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention);
+        set_global_symbol_dllimport (name, 0);
+        set_global_symbol_param_count (name, saved_declarator_function_param_count, saved_declarator_function_has_prototype || saved_declarator_function_param_count > 0, saved_declarator_function_is_variadic);
+        
+        if (is_inline) {
+        
+            remember_inline_function_signature (name, saved_declarator_function_param_count, saved_declarator_function_has_prototype || saved_declarator_function_param_count > 0,
+                return_is_void, return_is_floating, return_size);
+        
+        }
+    
+    }
+    
+    old_function_has_return_statement = current_function_has_return_statement;
+    old_function_is_void = current_function_is_void;
+    old_function_is_floating = current_function_is_floating;
+    old_function_return_size = current_function_return_size;
+    old_function_return_is_unsigned = current_function_return_is_unsigned;
+    old_function_returns_aggregate = current_function_returns_aggregate;
+    
+    current_function_is_void = return_is_void;
+    current_function_is_floating = return_is_floating;
+    current_function_return_is_unsigned = return_is_unsigned;
+    current_function_return_size = return_size;
+    current_function_returns_aggregate = (!return_is_void && !return_is_floating && return_size > (DATA_LLONG & 0x1f));
+    current_function_calling_convention = (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention;
+    current_function_param_stack_bytes = 0;
+    current_function_has_return_statement = 0;
+    
+    parse_old_style_param_decls ();
+    remove_duplicate_pending_params ();
+    
+    /*
+     * Old-style definitions start with an identifier list, so the first
+     * function-symbol install only knows the default int-sized parameter
+     * placeholders.  The declaration list between ')' and '{' is what gives
+     * those parameters their real types.  Refresh the saved call signature
+     * after that list has been parsed, otherwise later calls in the same
+     * translation unit pass 64-bit parameters as single words.
+     */
+    if (emit_body && should_emit) {
+        copy_pending_params_to_global_symbol (name);
+    }
+    
+    current_function_param_stack_bytes = global_symbol_stdcall_stack_bytes (name);
+    
+    reset_local_symbols ();
+    reset_goto_labels ();
+    
+    install_pending_params_as_locals ();
+    clear_pending_params ();
+    
+    if (!emit_body || !should_emit) {
+        state->ofp = 0;
+    } else if (capture_function_body) {
+        state->ofp = function_tmp;
+    }
+    
+    current_return_label = anon_label++;
+    pending_return_jump = 0;
+    current_function_preserve_assignment64_regs = 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 ();
+    check_goto_labels ();
+    
+    if (!current_function_is_void && !current_function_has_return_statement) {
+        report_line_at (function_filename_copy ? function_filename_copy : get_filename (), function_line, REPORT_WARNING, function_start, function_caret, "control reaches end of non-void function");
+    }
+    
+    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_function_body && function_tmp) {
+    
+        function_asm_text = read_tmp_file_text (function_tmp);
+        
+        if (function_asm_text) {
+        
+            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);
+            }
+            
+            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);
+            
+            }
+        
+        }
+        
+        if (function_asm_text) {
+            free (function_asm_text);
+        }
+        
+        if (inline_asm_text) {
+        
+            free (inline_asm_text);
+            inline_asm_text = 0;
+        
+        }
+        
+        scc_close (function_tmp);
+        function_tmp = 0;
+    
+    }
+    
+    reset_local_symbols ();
+    reset_goto_labels ();
+    
+    current_function_has_return_statement = old_function_has_return_statement;
+    current_function_is_void = old_function_is_void;
+    current_function_is_floating = old_function_is_floating;
+    current_function_return_size = old_function_return_size;
+    current_function_return_is_unsigned = old_function_return_is_unsigned;
+    current_function_returns_aggregate = old_function_returns_aggregate;
+    
+    current_return_label = old_return_label;
+    state->ofp = saved_ofp;
+    
+    if (capture_inline_body) {
+        current_section = saved_current_section;
+    }
+    
+    if (function_filename_copy) {
+        free (function_filename_copy);
+    }
+    
+    if (inline_asm_text) {
+        free (inline_asm_text);
+    }
+
+}
+
+static int parse_possible_knr_function (void) {
+
+    char *name;
+    
+    const char *name_start;
+    const char *name_caret;
+    
+    unsigned long name_line;
+    
+    if (!token_is_ident ()) {
+        return 0;
+    }
+    
+    name_line = get_line_number ();
+    
+    name_start = tok.start;
+    name_caret = tok.caret;
+    
+    name = take_ident ();
+    
+    if (!_accept (TOK_LPAREN)) {
+    
+        free (name);
+        return 0;
+    
+    }
+    
+    clear_pending_params ();
+    
+    declarator_function_param_count = 0;
+    declarator_function_has_prototype = 0;
+    declarator_function_is_variadic = 0;
+    
+    if (tok.kind != TOK_RPAREN) {
+    
+        int old_style_param_start = pending_param_count;
+        
+        for (;;) {
+       
+            if (tok.kind == TOK_ELLIPSIS) {
+            
+                declarator_function_is_variadic = 1;
+                declarator_function_has_prototype = 1;
+                
+                get_token ();
+            
+            } else if (is_type_start (tok.kind)) {
+            
+                int param_base_size;
+                int param_size;
+                int param_pointer_depth;
+                int saved_function_param_count;
+                
+                int count_this_param = 0;
+                int saw_void_param_list = 0;
+                
+                char *param_name = 0;
+                
+                parse_type_spec ();
+                param_base_size = parsed_type_size;
+                
+                preserve_pending_params++;
+                
+                declarator_is_pointer = 0;
+                declarator_pointer_depth = 0;
+                declarator_has_array = 0;
+                declarator_has_function = 0;
+                declarator_function_is_pointer = 0;
+                declarator_array_unsized = 0;
+                declarator_array_count = 1;
+                declarator_last_array_count = 1;
+                
+                if (parsed_type_only_qualifiers && token_is_ident ()) {
+                    get_token ();
+                }
+                
+                saved_function_param_count = declarator_function_param_count;
+                
+                if (tok.kind != TOK_COMMA && tok.kind != TOK_RPAREN) {
+                    parse_declarator (&param_name);
+                }
+                
+                preserve_pending_params--;
+                
+                if (!parsed_type_is_void || declarator_is_pointer || declarator_has_array || declarator_has_function || param_name) {
+                
+                    count_this_param = 1;
+                    
+                    param_size = (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef) ? DATA_PTR : declarator_object_size (param_base_size);
+                    param_pointer_depth = declarator_pointer_depth;
+                    
+                    if ((declarator_has_array || declarator_has_function || parsed_type_is_array_typedef) && param_pointer_depth < 1) {
+                        param_pointer_depth = 1;
+                    }
+                    
+                    if (param_name && find_pending_param_from (param_name, old_style_param_start) >= 0) {
+                        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate parameter '%s'", param_name);
+                    } else {
+                    
+                        add_pending_param (param_name, param_size, type_alignment (param_size),
+                            (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef ? 0 : parsed_type_is_unsigned),
+                                (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef ? 0 : parsed_type_is_floating),
+                                    param_pointer_depth, parsed_type_is_aggregate ? parsed_type_size : (parsed_type_size & 0x1f), parsed_type_is_unsigned);
+                    
+                    }
+                
+                } else {
+                    saw_void_param_list = 1;
+                }
+                
+                if (param_name) {
+                    free (param_name);
+                }
+                
+                declarator_function_param_count = saved_function_param_count + (count_this_param ? 1 : 0);
+                declarator_function_has_prototype = declarator_function_has_prototype || count_this_param || saw_void_param_list;
+            
+            } else if (token_is_ident ()) {
+            
+                if (find_pending_param_from (tok.ident, old_style_param_start) >= 0) {
+                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate parameter '%s'", tok.ident);
+                } else {
+                
+                    add_pending_param (tok.ident, DATA_INT & 0x1f, type_alignment (DATA_INT & 0x1f), 0, 0, 0, 0, 0);
+                    declarator_function_param_count++;
+                
+                }
+                
+                get_token ();
+            
+            } else {
+                skip_balanced_until (TOK_COMMA, TOK_RPAREN, TOK_EOF);
+            }
+            
+            if (!_accept (TOK_COMMA)) {
+                break;
+            }
+        
+        }
+    
+    }
+    
+    expect (TOK_RPAREN, ")");
+    
+    if (is_type_start (tok.kind) || tok.kind == TOK_LBRACE) {
+    
+        parse_function_body (name, STORAGE_NONE, 0, 0, 0, 0, DATA_INT & 0x1f, name_line, name_start, name_caret);
+        
+        if (parsed_dllexport || declarator_dllexport) {
+        
+            vec_push (&vec_dllexports, xstrdup (name));
+            
+            declarator_dllexport = 0;
+            parsed_dllexport = 0;
+        
+        }
+        
+        free (name);
+        return 1;
+    
+    }
+    
+    free (name);
+    return 0;
+
+}
+
+static void append_global_init_byte (int64_s *values, int max_values, int *count, unsigned int value) {
+    append_global_init_value (values, max_values, count, value, DATA_CHAR & 0x1f);
+}
+
+static void parse_char_array_initializer_values (int64_s *values, int max_values, int *count, long row_width) {
+
+    if (tok.kind == TOK_LBRACE) {
+    
+        get_token ();
+        
+        while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
+        
+            parse_char_array_initializer_values (values, max_values, count, row_width);
+            
+            if (!_accept (TOK_COMMA)) {
+                break;
+            }
+        
+        }
+        
+        expect (TOK_RBRACE, "}");
+        return;
+    
+    }
+    
+    if (is_string_token ()) {
+    
+        int64_s tmp[MAX_STRING_INIT_BYTES];
+        int tmp_count = 0;
+        
+        int i;
+        int n;
+        
+        parse_string_initializer_values (tmp, MAX_STRING_INIT_BYTES, &tmp_count);
+        
+        if (row_width <= 0) {
+            n = tmp_count;
+        } else {
+            n = (tmp_count < row_width) ? tmp_count : (int) row_width;
+        }
+        
+        for (i = 0; i < n; i++) {
+            append_global_init_byte (values, max_values, count, (unsigned int) (tmp[i].low & 0xff));
+        }
+        
+        while (row_width > 0 && i < row_width) {
+        
+            append_global_init_byte (values, max_values, count, 0);
+            i++;
+        
+        }
+        
+        return;
+    
+    }
+    
+    if (tok.kind != TOK_COMMA && tok.kind != TOK_SEMI && tok.kind != TOK_RBRACE && tok.kind != TOK_EOF) {
+    
+        if (*count < max_values) {
+            values[*count] = const64_from_current_expr ();
+        } else {
+            const64_from_current_expr ();
+        }
+        
+        (*count)++;
+    
+    }
+
+}
+
+static int global_initializer_parenthesized_string_now (void) {
+
+    const char *p = tok.caret;
+    
+    if (!p || *p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p == '"') {
+        return 1;
+    }
+    
+    if ((*p == 'L' || *p == 'u' || *p == 'U') && p[1] == '"') {
+        return 1;
+    }
+    
+    if (*p == 'u' && p[1] == '8' && p[2] == '"') {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static int global_initializer_cast_before_string_now (void) {
+
+    const char *p = tok.caret;
+    int depth;
+    
+    if (!p || *p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!(ident_start_now ((unsigned char) *p))) {
+        return 0;
+    }
+    
+    depth = 1;
+    
+    while (*p && depth > 0) {
+    
+        if (*p == '(') {
+            depth++;
+        } else if (*p == ')') {
+            depth--;
+        }
+        
+        p++;
+    
+    }
+    
+    if (depth != 0) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p == '"') {
+        return 1;
+    }
+    
+    if ((*p == 'L' || *p == 'u' || *p == 'U') && p[1] == '"') {
+        return 1;
+    }
+    
+    if (*p == 'u' && p[1] == '8' && p[2] == '"') {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static void append_global_zero_initializer_value (int64_s *values, char **symbols, int max_values, int *count) {
+
+    if (*count < max_values) {
+    
+        values[*count].low = 0;
+        values[*count].high = 0;
+        
+        if (symbols) {
+            symbols[*count] = 0;
+        }
+    
+    }
+
+    (*count)++;
+
+}
+
+static int aggregate_initializer_value_field_count (const int *field_sizes, int field_count) {
+
+    int count = 0;
+    int i;
+    
+    for (i = 0; i < field_count; i++) {
+    
+        if (field_sizes[i] > 0) {
+            count++;
+        }
+    
+    }
+    
+    return count;
+
+}
+
+static void parse_global_initializer_values_padded_elements (int64_s *values, char **symbols, int max_values, int *count, int element_field_count) {
+
+    if (element_field_count <= 0 || tok.kind != TOK_LBRACE) {
+    
+        parse_global_initializer_values (values, symbols, max_values, count);
+        return;
+    
+    }
+    
+    get_token ();
+    
+    while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
+    
+        int before = *count;
+        parse_global_initializer_values (values, symbols, max_values, count);
+        
+        if (*count > before) {
+        
+            while ((*count - before) < element_field_count) {
+                append_global_zero_initializer_value (values, symbols, max_values, count);
+            }
+        
+        }
+        
+        if (!_accept (TOK_COMMA)) {
+            break;
+        }
+    
+    }
+    
+    expect (TOK_RBRACE, "}");
+
+}
+
+static void parse_global_initializer_values (int64_s *values, char **symbols, int max_values, int *count) {
+
+    if (tok.kind == TOK_LBRACE) {
+    
+        get_token ();
+        
+        while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
+        
+            parse_global_initializer_values (values, symbols, max_values, count);
+            
+            if (!_accept (TOK_COMMA)) {
+                break;
+            }
+        
+        }
+        
+        expect (TOK_RBRACE, "}");
+        return;
+    
+    }
+    
+    if (tok.kind != TOK_COMMA && tok.kind != TOK_SEMI && tok.kind != TOK_RBRACE && tok.kind != TOK_EOF) {
+    
+        if (is_string_token ()) {
+        
+            if (*count < max_values) {
+            
+                values[*count].low = 0;
+                values[*count].high = 0;
+                
+                if (symbols) {
+                    symbols[*count] = emit_string_literal_global ();
+                }
+            
+            } else {
+                get_token ();
+            }
+            
+            (*count)++;
+        
+        } else if (tok.kind == TOK_LPAREN && global_initializer_parenthesized_string_now ()) {
+        
+            get_token ();
+            
+            if (*count < max_values) {
+            
+                values[*count].low = 0;
+                values[*count].high = 0;
+                
+                if (symbols) {
+                    symbols[*count] = emit_string_literal_global ();
+                } else {
+                
+                    int64_s ignored_values[MAX_AGG_FIELDS];
+                    int ignored_count = 0;
+                    
+                    parse_string_initializer_values (ignored_values, MAX_AGG_FIELDS, &ignored_count);
+                
+                }
+            
+            } else {
+            
+                int64_s ignored_values[MAX_AGG_FIELDS];
+                int ignored_count = 0;
+                
+                parse_string_initializer_values (ignored_values, MAX_AGG_FIELDS, &ignored_count);
+            
+            }
+            
+            expect (TOK_RPAREN, ")");
+            (*count)++;
+        
+        } else if (tok.kind == TOK_LPAREN && global_initializer_cast_before_string_now ()) {
+        
+            int cast_size = 0;
+            int cast_is_unsigned = 0;
+            int cast_is_pointer = 0;
+            
+            get_token ();
+            
+            if (token_starts_type_name () && parse_cast_type_name (&cast_size, &cast_is_unsigned, &cast_is_pointer) && is_string_token ()) {
+            
+                if (*count < max_values) {
+                
+                    values[*count].low = 0;
+                    values[*count].high = 0;
+                    
+                    if (symbols) {
+                        symbols[*count] = emit_string_literal_global ();
+                    }
+                
+                } else {
+                    get_token ();
+                }
+                
+                (*count)++;
+            
+            } else {
+            
+                if (*count < max_values) {
+                
+                    values[*count] = const64_from_current_expr ();
+                    
+                    if (symbols) {
+                        symbols[*count] = 0;
+                    }
+                
+                } else {
+                    const64_from_current_expr ();
+                }
+                
+                (*count)++;
+            
+            }
+        
+        } else if (tok.kind == TOK_AMPER) {
+        
+            get_token ();
+            
+            if (tok.kind != TOK_IDENT) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after '&'");
+            } else {
+            
+                char addr_symbol[256];
+                char *base_name = xstrdup (tok.ident);
+                long addr_offset = 0;
+                int sym_index = find_global_symbol (base_name);
+                long array_count = get_global_symbol_array_count (base_name);
+                long base_size = sym_index >= 0 ? global_symbols[sym_index].size : 0;
+                long elem_size = 0;
+                
+                if (array_count > 0 && base_size > 0) {
+                    elem_size = base_size / array_count;
+                }
+                
+                get_token ();
+                
+                while (tok.kind == TOK_LBRACK) {
+                
+                    int64_s index_value;
+                    long index;
+                    
+                    get_token ();
+                    
+                    index_value.low = 0;
+                    index_value.high = 0;
+                    
+                    if (tok.kind != TOK_RBRACK) {
+                        index_value = const64_from_current_expr ();
+                    }
+                    
+                    index = (long) index_value.low;
+                    
+                    if (elem_size > 0) {
+                        addr_offset += index * elem_size;
+                    }
+                    
+                    expect (TOK_RBRACK, "]");
+                
+                }
+                
+                if (*count < max_values) {
+                
+                    values[*count].low = 0;
+                    values[*count].high = 0;
+                    
+                    if (symbols) {
+                    
+                        if (addr_offset != 0) {
+                        
+                            sprintf (addr_symbol, "%s+%ld", base_name, addr_offset);
+                            symbols[*count] = xstrdup (addr_symbol);
+                        
+                        } else {
+                            symbols[*count] = xstrdup (base_name);
+                        }
+                    
+                    }
+                
+                }
+                
+                (*count)++;
+                free (base_name);
+            
+            }
+        
+        } else if (global_initializer_accept_symbol_addresses && tok.kind == TOK_IDENT && find_global_symbol (tok.ident) >= 0) {
+        
+            if (*count < max_values) {
+            
+                values[*count].low = 0;
+                values[*count].high = 0;
+                
+                if (symbols) {
+                    symbols[*count] = xstrdup (tok.ident);
+                }
+            
+            }
+            
+            (*count)++;
+            get_token ();
+        
+        } else if (*count < max_values) {
+        
+            values[*count] = const64_from_current_expr ();
+                        
+            if (symbols) {
+                symbols[*count] = 0;
+            }
+            
+            (*count)++;
+        
+        } else {
+            const64_from_current_expr ();
+        }
+    
+    }
+
+}
+
+static int int64_is_zero_value (int64_s value) {
+    return value.low == 0 && value.high == 0;
+}
+
+static char masm_pending_data_label[512];
+static char masm_open_data_directive[8];
+
+static int masm_has_pending_data_label = 0;
+static int masm_data_line_open = 0;
+static int masm_data_line_values = 0;
+
+static void masm_set_pending_data_label (const char *name) {
+
+    const char *asm_name = asm_global_symbol_name (name);
+    unsigned long len;
+    
+    if (!asm_name) {
+    
+        masm_has_pending_data_label = 0;
+        masm_pending_data_label[0] = 0;
+        
+        return;
+    
+    }
+    
+    len = strlen (asm_name);
+    
+    if (len >= sizeof (masm_pending_data_label)) {
+        len = sizeof (masm_pending_data_label) - 1;
+    }
+    
+    memcpy (masm_pending_data_label, asm_name, len);
+    
+    masm_pending_data_label[len] = 0;
+    masm_has_pending_data_label = 1;
+
+}
+
+static void masm_flush_data_line (void) {
+
+    if (masm_data_line_open) {
+    
+        fprintf (state->ofp, "\n");
+        
+        masm_data_line_open = 0;
+        masm_data_line_values = 0;
+        
+        masm_open_data_directive[0] = 0;
+    
+    }
+
+}
+
+static void masm_emit_data_prefix (const char *directive) {
+
+    if (masm_has_pending_data_label) {
+    
+        masm_flush_data_line ();
+        fprintf (state->ofp, "%s %s ", masm_pending_data_label, directive);
+        
+        masm_has_pending_data_label = 0;
+        masm_pending_data_label[0] = 0;
+        
+        strncpy (masm_open_data_directive, directive, sizeof (masm_open_data_directive) - 1);
+        
+        masm_open_data_directive[sizeof (masm_open_data_directive) - 1] = 0;
+        masm_data_line_open = 1;
+        masm_data_line_values = 0;
+    
+    } else if (masm_data_line_open && strcmp (masm_open_data_directive, directive) == 0) {
+    
+        if (masm_data_line_values >= 8) {
+        
+            fprintf (state->ofp, "\n    %s ", directive);
+            masm_data_line_values = 0;
+        
+        } else {
+            fprintf (state->ofp, ", ");
+        }
+    
+    } else {
+    
+        masm_flush_data_line ();
+        
+        fprintf (state->ofp, "    %s ", directive);
+        strncpy (masm_open_data_directive, directive, sizeof (masm_open_data_directive) - 1);
+        
+        masm_open_data_directive[sizeof (masm_open_data_directive) - 1] = 0;
+        masm_data_line_open = 1;
+        masm_data_line_values = 0;
+    
+    }
+    
+    masm_data_line_values++;
+
+}
+
+static void emit_global_scalar (int64_s value, int size) {
+
+    unsigned long high = value.high;
+    unsigned long low = value.low;
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+        
+            masm_emit_data_prefix ("db");
+            fprintf (state->ofp, "%ld", low & 0xFFUL);
+        
+        } else if (size == (DATA_SHORT & 0x1f)) {
+        
+            masm_emit_data_prefix ("dw");
+            fprintf (state->ofp, "%ld", low & 0xFFFFUL);
+        
+        } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
+        
+            masm_emit_data_prefix ("dq");
+            fprintf (state->ofp, "0%08lX%08lXh", high & U32_MASK, low & U32_MASK);
+        
+        } else {
+        
+            masm_emit_data_prefix ("dd");
+            fprintf (state->ofp, "%lu", low & U32_MASK);
+        
+        }
+    
+    } else if (state->syntax & ASM_SYNTAX_NASM) {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, "    db %ld\n", low & 0xFFUL);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, "    dw %ld\n", low & 0xFFFFUL);
+        } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
+        
+            fprintf (state->ofp, "    dd %lu\n", low & U32_MASK);
+            fprintf (state->ofp, "    dd %lu\n", high & U32_MASK);
+        
+        } else {
+            fprintf (state->ofp, "    dd %lu\n", low & U32_MASK);
+        }
+    
+    } else {
+    
+        if (size == (DATA_CHAR & 0x1f)) {
+            fprintf (state->ofp, "    .byte %ld\n", low & 0xFFUL);
+        } else if (size == (DATA_SHORT & 0x1f)) {
+            fprintf (state->ofp, "    .word %ld\n", low & 0xFFFFUL);
+        } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
+        
+            fprintf (state->ofp, "    .long %lu\n", low & U32_MASK);
+            fprintf (state->ofp, "    .long %lu\n", high & U32_MASK);
+        
+        } else {
+            fprintf (state->ofp, "    .long %lu\n", low & U32_MASK);
+        }
+    
+    }
+
+}
+
+static void emit_global_address (const char *symbol, int size) {
+
+    const char *asm_symbol;
+    int64_s zero;
+    
+    if (!symbol || !*symbol) {
+    
+        zero.low = 0;
+        zero.high = 0;
+        
+        emit_global_scalar (zero, size);
+        return;
+    
+    }
+    
+    if (size != DATA_PTR) {
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "address initializer requires pointer-sized object");
+    }
+    
+    emit_extern_reference_symbol (symbol, DATA_PTR);
+    asm_symbol = asm_global_symbol_name (symbol);
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+    
+        masm_emit_data_prefix ("dd");
+        fprintf (state->ofp, "offset %s", asm_symbol);
+    
+    } else if (state->syntax & ASM_SYNTAX_NASM) {
+        fprintf (state->ofp, "    dd %s\n", asm_symbol);
+    } else {
+    
+        if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, "    .long offset %s\n", asm_symbol);
+        } else {
+            fprintf (state->ofp, "    .long %s\n", asm_symbol);
+        }
+    
+    }
+
+}
+
+static void emit_global_value (const int64_s *value, const char *symbol, int size) {
+
+    int64_s zero;
+    
+    if (symbol) {
+    
+        emit_global_address (symbol, size);
+        return;
+    
+    }
+    
+    if (value) {
+    
+        emit_global_scalar (*value, size);
+        return;
+    
+    }
+    
+    zero.low = 0;
+    zero.high = 0;
+    
+    emit_global_scalar (zero, size);
+
+}
+
+static void emit_global_space (long bytes) {
+
+    if (bytes <= 0) {
+        return;
+    }
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+    
+        masm_emit_data_prefix ("db");
+        fprintf (state->ofp, "%ld dup (?)", bytes);
+    
+    } else if (state->syntax & ASM_SYNTAX_NASM) {
+        fprintf (state->ofp, "    resb %ld\n", bytes);
+    } else {
+        fprintf (state->ofp, "    .space %ld\n", bytes);
+    }
+
+}
+
+static int field_size_bytes (int field_size) {
+
+    if (field_size < 0) {
+        return -field_size;
+    }
+    
+    return field_size;
+
+}
+
+static int global_initializer_is_all_zero (const int64_s *values, char **symbols, int value_count) {
+
+    int i;
+
+    if (symbols) {
+        for (i = 0; i < value_count; i++) {
+            if (symbols[i]) {
+                return 0;
+            }
+        }
+    }
+
+    if (!values || value_count <= 0) {
+        return 1;
+    }
+
+    for (i = 0; i < value_count; i++) {
+        if (!int64_is_zero_value (values[i])) {
+            return 0;
+        }
+    }
+
+    return 1;
+
+}
+
+static void emit_global_label (const char *name, int is_static) {
+
+    const char *asm_name = asm_global_symbol_name (name);
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+    
+        if (!is_static) {
+            fprintf (state->ofp, "public %s\n", asm_name);
+        }
+        
+        fprintf (state->ofp, "%s:\n", asm_name);
+    
+    } else if (state->syntax & ASM_SYNTAX_NASM) {
+    
+        if (!is_static) {
+            fprintf (state->ofp, "global %s\n", asm_name);
+        }
+        
+        fprintf (state->ofp, "%s:\n", asm_name);
+    
+    } else {
+    
+        if (!is_static) {
+            fprintf (state->ofp, ".globl %s\n", asm_name);
+        }
+        
+        fprintf (state->ofp, "%s:\n", asm_name);
+    
+    }
+
+}
+
+static void emit_global_data_label (const char *name, int is_static) {
+
+    const char *asm_name = asm_global_symbol_name (name);
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+    
+        masm_flush_data_line ();
+        
+        if (!is_static) {
+            fprintf (state->ofp, "public %s\n", asm_name);
+        }
+        
+        masm_set_pending_data_label (name);
+    
+    } else {
+        emit_global_label (name, is_static);
+    }
+
+}
+
+static void emit_global_object (const char *name, int size, int is_array, long array_count, const int *field_sizes, int field_count, const int64_s *values, char **symbols, int value_count, int is_aggregate, int is_static) {
+
+    int64_s zero;
+    
+    int value_index, use_bss, i;
+    long emitted, total;
+
+    zero.low = 0;
+    zero.high = 0;
+    
+    if (!state->ofp || !name || !*name) {
+        return;
+    }
+    
+    if (size <= 0) {
+        size = DATA_INT & 0x1f;
+    }
+    
+    if (array_count <= 0) {
+        array_count = 1;
+    }
+    
+    total = size * array_count;
+    use_bss = global_initializer_is_all_zero (values, symbols, value_count);
+
+    if (use_bss) {
+    
+        switch_section (SECTION_BSS);
+        
+        emit_global_data_label (name, is_static);
+        emit_global_space (total);
+        
+        return;
+    
+    }
+    
+    switch_section (SECTION_DATA);
+    emit_global_data_label (name, is_static);
+    
+    value_index = 0;
+    emitted = 0;
+    
+    if (!is_array && !is_aggregate) {
+    
+        if (value_count > 0) {
+            emit_global_value (&values[0], symbols ? symbols[0] : 0, size);
+        } else {
+            emit_global_value (0, 0, size);
+        }
+        
+        return;
+    
+    }
+    
+    if (is_aggregate && field_count > 0) {
+    
+        while (emitted < total) {
+        
+            for (i = 0; i < field_count && emitted < total; i++) {
+            
+                int fsize = field_sizes[i];
+                
+                if (fsize < 0) {
+                
+                    emit_global_space (-fsize);
+                    
+                    emitted += -fsize;
+                    continue;
+                
+                }
+                
+                if (value_index < value_count) {
+                
+                    emit_global_value (&values[value_index], symbols ? symbols[value_index] : 0, fsize);
+                    value_index++;
+                
+                } else {
+                    emit_global_scalar (zero, fsize);
+                }
+                
+                emitted += field_size_bytes (fsize);
+            
+            }
+        
+        }
+        
+        emit_global_space (total - emitted);
+        return;
+    
+    }
+    
+    if (is_array) {
+    
+        int elem_size = size;
+        
+        if (field_count > 0 && field_sizes[0] > 0) {
+            elem_size = field_sizes[0];
+        }
+        
+        while (emitted + elem_size <= total) {
+        
+            if (value_index < value_count) {
+            
+                emit_global_value (&values[value_index], symbols ? symbols[value_index] : 0, elem_size);
+                value_index++;
+            
+            } else {
+                emit_global_scalar (zero, elem_size);
+            }
+            
+            emitted += elem_size;
+        
+        }
+        
+        emit_global_space (total - emitted);
+        return;
+    
+    }
+    
+    emit_global_space (total);
+
+}
+
+static char *emit_string_literal_global (void) {
+
+    int64_s values[MAX_AGG_FIELDS];
+    
+    char label[64];
+    char skip_label[64];
+    
+    int elem_size = DATA_CHAR & 0x1f;
+    int value_count = 0, i;
+    
+    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+        sprintf (label, "LC%d", anon_label++);
+    } else {
+        sprintf (label, ".LC%d", anon_label++);
+    }
+    
+    parse_string_initializer_values (values, MAX_AGG_FIELDS, &value_count);
+    elem_size = parsed_string_initializer_elem_size;
+    
+    /*
+     * Dead statement parsing suppresses output by temporarily clearing
+     * state->ofp.  Still consume the literal so the token stream remains
+     * correct, but do not try to emit a .data label through a NULL FILE *.
+     * This is needed for optimised-away bodies such as:
+     *
+     *     while (0) { printf ("Hello\n"); }
+     */
+    if (!state->ofp) {
+        return xstrdup (label);
+    }
+    
+    if (current_section == SECTION_TEXT) {
+    
+        if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
+            sprintf (skip_label, "L%d", anon_label++);
+        } else {
+            sprintf (skip_label, ".L%d", anon_label++);
+        }
+        
+        fprintf (state->ofp, "    jmp %s\n", skip_label);
+        
+        switch_section (SECTION_DATA);
+        emit_global_data_label (label, 1);
+        
+        for (i = 0; i < value_count; i++) {
+            emit_global_scalar (values[i], elem_size);
+        }
+        
+        switch_section (SECTION_TEXT);
+        emit_global_label (skip_label, 1);
+        
+        return xstrdup (label);
+    
+    }
+    
+    switch_section (SECTION_DATA);
+    emit_global_data_label (label, 1);
+    
+    for (i = 0; i < value_count; i++) {
+        emit_global_scalar (values[i], elem_size);
+    }
+    
+    return xstrdup (label);
+
+}
+
+static const char *masm_extern_type_name (int size, int is_function) {
+
+    if (is_function) {
+        return "PROC";
+    }
+
+    if (size == (DATA_CHAR & 0x1f)) {
+        return "BYTE";
+    }
+
+    if (size == (DATA_SHORT & 0x1f)) {
+        return "WORD";
+    }
+
+    if (size == (DATA_LLONG & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
+        return "QWORD";
+    }
+
+    return "DWORD";
+
+}
+
+static void emit_extern_line (const char *name, int size, int is_function) {
+
+    const char *asm_name = get_global_symbol_dllimport (name) ? asm_global_import_symbol_name (name) : asm_global_symbol_name (name);
+    
+    if (get_global_symbol_dllimport (name)) {
+    
+        size = DATA_PTR & 0x1f;
+        is_function = 0;
+    
+    }
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+        fprintf (state->ofp, "extrn %s:%s\n", asm_name, masm_extern_type_name (size, is_function));
+    } else if (state->syntax & ASM_SYNTAX_NASM) {
+        fprintf (state->ofp, "extern %s\n", asm_name);
+    } else {
+        fprintf (state->ofp, ".extern %s\n", asm_name);
+    }
+
+}
+
+static void emit_extern_symbol (const char *name, int size, int is_function) {
+
+    int i;
+    
+    (void) size;
+    (void) is_function;
+    
+    if (!state->ofp || !name || !*name) {
+        return;
+    }
+    
+    i = find_global_symbol (name);
+    
+    /**
+     * Do not write assembler externs at the point of use.  A symbol can be
+     * declared/called before its real definition appears later in the same
+     * translation unit; NASM then rejects "extern foo" followed by "foo:" as
+     * an inconsistent redefinition.  Just mark that generated code referenced
+     * the external-looking symbol, and emit the actual assembler externs once
+     * the whole file has been parsed and we know which names stayed external.
+     */
+    if (i < 0 || !global_symbols[i].is_extern) {
+        return;
+    }
+    
+    global_symbols[i].extern_emitted = 1;
+
+}
+
+static void emit_pending_extern_symbols (void) {
+
+    int i;
+    
+    if (!state->ofp) {
+        return;
+    }
+    
+    for (i = 0; i < global_symbol_count; i++) {
+    
+        if (!global_symbols[i].is_extern || !global_symbols[i].extern_emitted) {
+            continue;
+        }
+        
+        emit_extern_line (global_symbols[i].name,
+            global_symbols[i].size > 0 ? global_symbols[i].size : (DATA_INT & 0x1f),
+                global_symbols[i].kind == GLOBAL_SYMBOL_FUNCTION);
+    
+    }
+
+}
+
+static void emit_extern_reference_symbol (const char *name, int size) {
+    emit_extern_symbol (name, size, get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION);
+}
+
+static void parse_external_after_type (void) {
+
+    for (;;) {
+    
+        char **init_symbols = 0;
+        int64_s *init_values = 0;
+        
+        char *name = 0;
+        int init_value_count = 0, i;
+        
+        int object_fields[MAX_AGG_FIELDS];
+        int object_field_count = 0;
+        
+        const char *name_start, *name_caret;
+        unsigned long name_line;
+        
+        int saved_field_count = parsed_field_count;
+        
+        int declaration_is_inline;
+        int declaration_storage;
+        int declaration_dllimport = 0;
+        
+        int decl_is_pointer;
+        int decl_pointer_depth;
+        int decl_has_array;
+        int decl_has_function;
+        int decl_function_is_pointer;
+        int decl_function_param_count;
+        int decl_function_has_prototype;
+        int decl_function_is_variadic;
+        int decl_array_unsized;
+        
+        long decl_array_count;
+        long decl_first_array_count;
+        long decl_last_array_count;
+        
+        for (i = 0; i < saved_field_count; i++) {
+            object_fields[i] = parsed_field_sizes[i];
+        }
+        
+        object_field_count = saved_field_count;
+        
+        declaration_is_inline = parsed_type_is_inline;
+        declaration_storage = parsed_storage_class;
+        declaration_dllimport = parsed_dllimport;
+        
+        parse_declarator (&name);
+        
+        declaration_dllimport = declaration_dllimport || parsed_dllimport || declarator_dllimport;
+        apply_typedef_array_to_declarator ();
+        
+        decl_is_pointer = declarator_is_pointer;
+        decl_pointer_depth = declarator_pointer_depth;
+        decl_has_array = declarator_has_array;
+        decl_has_function = declarator_has_function;
+        decl_function_is_pointer = declarator_function_is_pointer;
+        decl_function_param_count = declarator_function_param_count;
+        decl_function_has_prototype = declarator_function_has_prototype;
+        decl_function_is_variadic = declarator_function_is_variadic;
+        decl_array_unsized = declarator_array_unsized;
+        decl_array_count = declarator_array_count;
+        decl_first_array_count = declarator_first_array_count;
+        decl_last_array_count = declarator_last_array_count;
+        
+        name_start = last_declarator_name_start;
+        name_caret = last_declarator_name_caret;
+        
+        name_line = last_declarator_name_line;
+        
+        if (declaration_storage == STORAGE_TYPEDEF) {
+        
+            if (name) {
+            
+                make_declarator_fields (object_fields, &object_field_count, parsed_field_sizes, parsed_field_count, parsed_type_size, parsed_type_is_aggregate);
+                
+                save_typedef_name (name, declarator_object_size (parsed_type_size),
+                    (declarator_is_pointer ? 0 : parsed_type_is_unsigned),
+                        (declarator_is_pointer ? 0 : parsed_type_is_void),
+                            (!declarator_is_pointer && (parsed_type_is_aggregate || declarator_has_array)),
+                                (!declarator_is_pointer && declarator_has_array),
+                                    declarator_array_count, parsed_type_size,
+                                        (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention,
+                                            object_fields, object_field_count);
+            
+            }
+            
+            if (_accept (TOK_ASSIGN)) {
+            
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "typedef '%s' is initialized", name ? name : "");
+                skip_initializer ();
+            
+            }
+            
+            if (name) {
+                free (name);
+            }
+            
+            if (!_accept (TOK_COMMA)) {
+                break;
+            }
+            
+            continue;
+        
+        }
+        
+        if (name && declarator_has_function && (tok.kind == TOK_LBRACE || is_type_start (tok.kind))) {
+        
+            if (parsed_dllexport || declarator_dllexport) {
+            
+                vec_push (&vec_dllexports, xstrdup (name));
+                
+                declarator_dllexport = 0;
+                parsed_dllexport = 0;
+            
+            }
+            
+            parse_function_body (name, declaration_storage, declaration_is_inline,
+                (parsed_type_is_void && !declarator_is_pointer),
+                    (declarator_is_pointer ? 0 : parsed_type_is_floating),
+                        (declarator_is_pointer ? 0 : parsed_type_is_unsigned),
+                            (declarator_is_pointer ? DATA_PTR : parsed_type_size),
+                                name_line, name_start, name_caret);
+            
+            free (name);
+            return;
+        
+        }
+        
+        if (parsed_type_is_void && !declarator_is_pointer && !declarator_has_function) {
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "variable '%s' declared void", name ? name : "");
+        }
+        
+        if (declarator_is_pointer) {
+        
+            object_field_count = 1;
+            object_fields[0] = DATA_PTR;
+        
+        }
+        
+        init_values = xmalloc (sizeof (*init_values) * MAX_GLOBAL_INIT_FIELDS);
+        init_symbols = xmalloc (sizeof (*init_symbols) * MAX_GLOBAL_INIT_FIELDS);
+        
+        for (i = 0; i < MAX_GLOBAL_INIT_FIELDS; i++) {
+            init_symbols[i] = 0;
+        }
+        
+        if (_accept (TOK_ASSIGN)) {
+        
+            if (declarator_has_array && !declarator_is_pointer && (parsed_type_size & 0x1f) == (DATA_CHAR & 0x1f) && (is_string_token () || tok.kind == TOK_LBRACE)) {
+            
+                if (is_string_token ()) {
+                    parse_string_initializer_values (init_values, MAX_GLOBAL_INIT_FIELDS, &init_value_count);
+                } else {
+                    parse_char_array_initializer_values (init_values, MAX_GLOBAL_INIT_FIELDS, &init_value_count, declarator_last_array_count);
+                }
+                
+                if (decl_array_unsized) {
+                    decl_array_count = init_value_count;
+                }
+            
+            } else if (declarator_is_pointer && is_string_token ()) {
+            
+                init_values[0].low = 0;
+                init_values[0].high = 0;
+                
+                init_symbols[0] = emit_string_literal_global ();
+                init_value_count = 1;
+            
+            } else if (!declarator_is_pointer && parsed_type_is_floating) {
+            
+                init_values[0] = parse_floating_const_expr_bits_now (parsed_type_size);
+                init_symbols[0] = 0;
+                init_value_count = 1;
+            
+            } else {
+            
+                {
+                
+                    int saved_accept_symbol_addresses = global_initializer_accept_symbol_addresses;
+                    global_initializer_accept_symbol_addresses = declarator_is_pointer || declarator_has_function || parsed_type_is_aggregate || declarator_has_array;
+                    
+                    if (declarator_has_array && !declarator_is_pointer && parsed_type_is_aggregate && parsed_field_count > 0 && tok.kind == TOK_LBRACE) {
+                        parse_global_initializer_values_padded_elements (init_values, init_symbols, MAX_GLOBAL_INIT_FIELDS, &init_value_count, aggregate_initializer_value_field_count (parsed_field_sizes, parsed_field_count));
+                    } else {
+                        parse_global_initializer_values (init_values, init_symbols, MAX_GLOBAL_INIT_FIELDS, &init_value_count);
+                    }
+                    
+                    global_initializer_accept_symbol_addresses = saved_accept_symbol_addresses;
+                
+                }
+                
+                if (decl_has_array && decl_array_unsized) {
+                
+                    if (parsed_type_is_aggregate && object_field_count > 0) {
+                        decl_array_count = (init_value_count + object_field_count - 1) / object_field_count;
+                    } else {
+                        decl_array_count = init_value_count;
+                    }
+                
+                }
+            
+            }
+        
+        }
+        
+        if (init_value_count > MAX_GLOBAL_INIT_FIELDS) {
+        
+            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "too many initializer values for '%s'", name ? name : "");
+            init_value_count = MAX_GLOBAL_INIT_FIELDS;
+        
+        }
+        
+        declarator_is_pointer = decl_is_pointer;
+        declarator_pointer_depth = decl_pointer_depth;
+        declarator_has_array = decl_has_array;
+        declarator_has_function = decl_has_function;
+        declarator_function_is_pointer = decl_function_is_pointer;
+        declarator_function_param_count = decl_function_param_count;
+        declarator_function_has_prototype = decl_function_has_prototype;
+        declarator_function_is_variadic = decl_function_is_variadic;
+        declarator_array_unsized = decl_array_unsized;
+        declarator_array_count = decl_array_count;
+        declarator_first_array_count = decl_first_array_count;
+        declarator_last_array_count = decl_last_array_count;
+        
+        if (name) {
+        
+            if (declarator_has_function && !declarator_function_is_pointer && !declarator_has_array) {
+            
+                /*
+                 * A file-scope function declaration is a declaration even
+                 * without an explicit extern storage class.  Keep it in the
+                 * global symbol table so a later call does not fall back to
+                 * the implicit-function-declaration path.
+                 *
+                 * Store prototypes as extern-like declarations here.  A real
+                 * function body will later turn the symbol into a definition
+                 * through add_global_symbol(), which already handles replacing
+                 * an extern declaration with the definition.
+                 */
+                add_global_symbol (name, GLOBAL_SYMBOL_FUNCTION, 1, name_start, name_caret, name_line);
+                
+                if (find_global_symbol (name) >= 0) {
+                
+                    set_global_symbol_size (name, declarator_is_pointer ? DATA_PTR : (parsed_type_is_void ? DATA_VOID : parsed_type_size));
+                    set_global_symbol_pointer_info (name, declarator_effective_pointer_depth_now (),
+                        declarator_effective_pointed_size_now (parsed_type_size, object_fields, object_field_count));
+                    set_global_symbol_tag_name (name, parsed_type_tag_name);
+                    set_global_symbol_unsigned (name, 0);
+                    set_global_symbol_floating (name, declarator_is_pointer ? 0 : parsed_type_is_floating);
+                    set_global_symbol_returns_void (name, parsed_type_is_void && !declarator_is_pointer && !declarator_function_is_pointer);
+                    set_global_symbol_param_count (name, declarator_function_param_count, declarator_function_has_prototype || declarator_function_param_count > 0, declarator_function_is_variadic);
+                    
+                    set_global_symbol_calling_convention (name, (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention);
+                    set_global_symbol_dllimport (name, declaration_dllimport);
+                    
+                    copy_pending_params_to_global_symbol (name);
+                
+                }
+            
+            } else if ((declaration_storage == STORAGE_EXTERN || declaration_dllimport) && init_value_count == 0) {
+            
+                add_global_symbol (name, GLOBAL_SYMBOL_OBJECT, 1, name_start, name_caret, name_line);
+                
+                if (find_global_symbol (name) >= 0) {
+                
+                    set_global_symbol_size (name, declarator_is_pointer ? DATA_PTR : declarator_object_size (parsed_type_size));
+                    set_global_symbol_pointer_info (name, declarator_effective_pointer_depth_now (),
+                        declarator_effective_pointed_size_now (parsed_type_size, object_fields, object_field_count));
+                    set_global_symbol_tag_name (name, parsed_type_tag_name);
+                    set_global_symbol_unsigned (name, declarator_is_pointer ? 0 : parsed_type_is_unsigned);
+                    set_global_symbol_array (name, declarator_has_array);
+                    set_global_symbol_array_count (name, declarator_has_array ? declarator_array_count : 0);
+                    set_global_symbol_array_dimensions (name, declarator_has_array ? declarator_array_dimensions : 0);
+                    set_global_symbol_array_element_size (name, declarator_array_element_size_now (parsed_type_size));
+                    set_global_symbol_dllimport (name, declaration_dllimport);
+                
+                }
+            
+            } else {
+            
+                if (add_global_symbol (name, GLOBAL_SYMBOL_OBJECT, 0, name_start, name_caret, name_line)) {
+                
+                    set_global_symbol_size (name, declarator_is_pointer ? DATA_PTR : declarator_object_size (parsed_type_size));
+                    set_global_symbol_pointer_info (name, declarator_effective_pointer_depth_now (),
+                        declarator_effective_pointed_size_now (parsed_type_size, object_fields, object_field_count));
+                    set_global_symbol_tag_name (name, parsed_type_tag_name);
+                    set_global_symbol_unsigned (name, declarator_is_pointer ? 0 : parsed_type_is_unsigned);
+                    set_global_symbol_floating (name, declarator_is_pointer ? 0 : parsed_type_is_floating);
+                    set_global_symbol_array (name, declarator_has_array);
+                    set_global_symbol_array_count (name, declarator_has_array ? declarator_array_count : 0);
+                    set_global_symbol_array_dimensions (name, declarator_has_array ? declarator_array_dimensions : 0);
+                    set_global_symbol_array_element_size (name, declarator_array_element_size_now (parsed_type_size));
+                    
+                    emit_global_object (name, declarator_is_pointer ? DATA_PTR : (declarator_has_array ? parsed_type_size : (parsed_type_is_aggregate ? parsed_type_size : (parsed_type_size & 0x1f))),
+                        declarator_has_array, declarator_array_count, object_fields, object_field_count,
+                            init_values, init_symbols, init_value_count, (!declarator_is_pointer && parsed_type_is_aggregate),
+                                declaration_storage == STORAGE_STATIC);
+                
+                }
+            
+            }
+            
+            free (name);
+        
+        }
+        
+        for (i = 0; i < MAX_GLOBAL_INIT_FIELDS; i++) {
+        
+            if (init_symbols[i]) {
+            
+                free (init_symbols[i]);
+                init_symbols[i] = 0;
+            
+            }
+        
+        }
+        
+        free (init_symbols);
+        free (init_values);
+        
+        if (!_accept (TOK_COMMA)) {
+            break;
+        }
+    
+    }
+    
+    if (tok.kind == TOK_SEMI) {
+        get_token ();
+    } else if (is_type_start (tok.kind)) {
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "missing ';' after declaration");
+    } else {
+        expect (TOK_SEMI, ";");
+    }
+
+}
+
+void compile_translation_unit32 (void) {
+
+    if (state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_MASM) {
+        
+            fprintf (state->ofp, ".386\n");
+            fprintf (state->ofp, ".model flat\n");
+        
+        } else if (state->syntax & ASM_SYNTAX_NASM) {
+        
+            fprintf (state->ofp, "cpu 386\n");
+            fprintf (state->ofp, "bits 32\n");
+        
+        } else if (state->syntax & ASM_SYNTAX_INTEL) {
+            fprintf (state->ofp, ".intel_syntax noprefix\n");
+        }
+    
+    }
+    
+    current_section = SECTION_NONE;
+    
+    clear_global_symbols ();
+    clear_inline_functions ();
+    clear_enum_constants ();
+    clear_typedef_names ();
+    
+    get_token ();
+    
+    while (tok.kind != TOK_EOF) {
+    
+        if (is_type_start (tok.kind)) {
+        
+            parse_type_spec ();
+            parse_external_after_type ();
+            
+            continue;
+        
+        }
+        
+        if (parse_possible_knr_function ()) {
+            continue;
+        }
+        
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected external declaration");
+        get_token ();
+    
+    }
+    
+    if (state->syntax & ASM_SYNTAX_MASM) {
+        masm_flush_data_line ();
+    }
+    
+    emit_pending_extern_symbols ();
+    
+    if (vec_dllexports.length) {
+    
+        char *p, *tmp;
+        
+        const char *name;
+        long i;
+        
+        FILE *fp;
+        
+        if ((p = strrchr (state->ofile, '.'))) {
+        
+            tmp = xmalloc (p - state->ofile + 5);
+            sprintf (tmp, "%.*s.def", (int) (p - state->ofile), state->ofile);
+        
+        } else {
+        
+            tmp = xmalloc (strlen (state->ofile) + 5);
+            sprintf (tmp, "%s.def", state->ofile);
+        
+        }
+        
+        if ((fp = fopen (tmp, "w"))) {
+        
+            fprintf (fp, "EXPORTS\n");
+            
+            for (i = 0; i < vec_dllexports.length; i++) {
+            
+                if ((name = asm_global_symbol_name (vec_dllexports.data[i]))) {
+                    fprintf (fp, "    %s\n", name);
+                }
+            
+            }
+            
+            fclose (fp);
+            
+        }
+    
+    }
+    
+    if (state->ofp) {
+    
+        if (state->syntax & ASM_SYNTAX_MASM) {
+        
+            masm_flush_data_line ();
+            fprintf (state->ofp, "end\n");
+        
+        }
+    
+    }
+
+}
diff --git a/lib.c b/lib.c
index d833b26db7127911e05f204816856c31513ad4da..c5dfed473d674332a626c87a6fd6c8212de67e38 100755 (executable)
--- a/lib.c
+++ b/lib.c
@@ -31,24 +31,29 @@ struct cc_option {
 #define     CC_OPTION_EQUALS_ARG        3
 
 #define     CC_OPTION_NONE                                  0
-#define     CC_OPTION_COMPILE                               1
-#define     CC_OPTION_DEFINE                                2
-#define     CC_OPTION_HELP                                  3
-#define     CC_OPTION_INCLUDE                               4
-#define     CC_OPTION_NO_LEADING_UNDERSCORE                 5
-#define     CC_OPTION_NO_LINEMARKERS                        6
-#define     CC_OPTION_MASM                                  7
-#define     CC_OPTION_MAX_ERRORS                            8
-#define     CC_OPTION_MLONG64                               9
-#define     CC_OPTION_OUTFILE                               10
-#define     CC_OPTION_PEDANTIC                              11
-#define     CC_OPTION_PREPOCESS                             12
-#define     CC_OPTION_STD                                   13
-#define     CC_OPTION_TRANDITIONAL_LINEMARKERS              14
-#define     CC_OPTION_UNDEF                                 15
+#define     CC_OPTION_BITS32                                1
+#define     CC_OPTION_BITS64                                2
+#define     CC_OPTION_COMPILE                               3
+#define     CC_OPTION_DEFINE                                4
+#define     CC_OPTION_HELP                                  5
+#define     CC_OPTION_INCLUDE                               6
+#define     CC_OPTION_NO_LEADING_UNDERSCORE                 7
+#define     CC_OPTION_NO_LINEMARKERS                        8
+#define     CC_OPTION_MASM                                  9
+#define     CC_OPTION_MAX_ERRORS                            10
+#define     CC_OPTION_MLONG64                               11
+#define     CC_OPTION_OUTFILE                               12
+#define     CC_OPTION_PEDANTIC                              13
+#define     CC_OPTION_PREPOCESS                             14
+#define     CC_OPTION_STD                                   15
+#define     CC_OPTION_TRANDITIONAL_LINEMARKERS              16
+#define     CC_OPTION_UNDEF                                 17
 
 static struct cc_option opts[] = {
 
+    {   "-m32",                             CC_OPTION_BITS32,                       CC_OPTION_NO_ARG        },
+    {   "-m64",                             CC_OPTION_BITS64,                       CC_OPTION_NO_ARG        },
+    
     {   "-pedantic",                        CC_OPTION_PEDANTIC,                     CC_OPTION_NO_ARG        },
     {   "-std",                             CC_OPTION_STD,                          CC_OPTION_EQUALS_ARG    },
     
@@ -111,6 +116,10 @@ static void print_usage (void) {
         fprintf (stderr, "    -E                                Preprocess only; do not compile.\n");
         fprintf (stderr, "    -S                                Compile only.\n");
         
+        fprintf (stderr, "\n");
+        fprintf (stderr, "    -m32                              Generate code for Intel 386.\n");
+        fprintf (stderr, "    -m64                              Generate code for AMD64.\n");
+        
         fprintf (stderr, "\n");
         fprintf (stderr, "    -std=<standard>                   Assume that the input sources are for\n");
         fprintf (stderr, "                                      <standard>.\n");
@@ -266,6 +275,8 @@ void parse_args (int argc, char **argv, int optind) {
     
     }
     
+    state->bits = 32;
+    
     while (optind < argc) {
     
         r = argv[optind++];
@@ -342,6 +353,20 @@ void parse_args (int argc, char **argv, int optind) {
         
         switch (popt->idx) {
         
+            case CC_OPTION_BITS32: {
+            
+                state->bits = 32;
+                break;
+            
+            }
+            
+            case CC_OPTION_BITS64: {
+            
+                state->bits = 64;
+                break;
+            
+            }
+            
             case CC_OPTION_COMPILE: {
             
                 state->mode = CC_MODE_COMPILE;
@@ -349,7 +374,7 @@ void parse_args (int argc, char **argv, int optind) {
             
             }
             
-            case CC_OPTION_DEFINE : {
+            case CC_OPTION_DEFINE: {
             
                 char *arg;
                 
diff --git a/parse.c b/parse.c
index bc06c88d058d474f20806fa4808fadac72fdec8e..017890ed5a7c26e938c9364c1992e116b26bb563 100644 (file)
--- a/parse.c
+++ b/parse.c
 /******************************************************************************
  * @file            parse.c
  *****************************************************************************/
-#include    <stdio.h>
 #include    <stdlib.h>
 #include    <string.h>
 
 #include    "cc.h"
 #include    "expr.h"
+#include    "token.h"
 #include    "lib.h"
 #include    "parse.h"
+#include    "int64.h"
 #include    "report.h"
-#include    "token.h"
-
-static enum token_kind parsed_calling_convention = TOK_EOF;
-
-static struct vector vec_dllexports = { 0 };
-static int parsed_dllexport = 0;
-static int parsed_dllimport = 0;
-
-#define     SECTION_NONE                0
-#define     SECTION_TEXT                1
-#define     SECTION_DATA                2
-#define     SECTION_BSS                 3
-
-static int current_section = 0;
-static int anon_label = 1;
-static int anonymous_aggregate_owner_id = 1;
-
-static int pending_return_jump = 0;
-static int local_static_id = 1;
-
-#define     MAX_PENDING_STATEMENT_LABELS                    256
-
-static int pending_statement_labels[MAX_PENDING_STATEMENT_LABELS];
-static int pending_statement_label_count = 0;
-
-static void flush_pending_statement_labels (void);
-
-#define     DATA_NONE                   0
-#define     DATA_VOID                   4
-#define     DATA_PTR                    4
-
-static int current_function_preserve_assignment64_regs = 0;
-static int current_return_label = 0;
-
-#define     DATA_CHAR                   (1 | (1 << 5))
-#define     DATA_SHORT                  (2 | (1 << 6))
-#define     DATA_INT                    (4 | (1 << 7))
-#define     DATA_LONG                   (4 | (1 << 8))
-#define     DATA_LLONG                  (8 | (1 << 9))
-#define     DATA_FLOAT                  (4 | (1 << 10))
-#define     DATA_DOUBLE                 (8 | (1 << 11))
-
-static int index_step_size (int size) {
-
-    if (size == DATA_CHAR || size == DATA_SHORT || size == DATA_INT ||
-        size == DATA_LONG || size == DATA_LLONG || size == DATA_FLOAT ||
-        size == DATA_DOUBLE) {
-        return size & 0x1f;
-    }
-    
-    if (size <= 0) {
-        return DATA_INT & 0x1f;
-    }
-    
-    return size;
-
-}
-
-static int rhs_last_pointer_depth = 0;
-static int rhs_last_pointed_size = 0;
-
-static void set_rhs_last_pointer_info (int depth, int size) {
+#include    "vector.h"
 
-    rhs_last_pointer_depth = depth;
-    rhs_last_pointed_size = depth > 1 ? DATA_PTR : (size > 0 ? size : (DATA_INT & 0x1f));
+struct typedef_entry typedef_names[MAX_TYPEDEF_NAMES];
+int typedef_name_count = 0;
+int anonymous_aggregate_owner_id = 1;
 
-}
-
-static void clear_rhs_last_pointer_info (void) {
-
-    rhs_last_pointer_depth = 0;
-    rhs_last_pointed_size = 0;
-
-}
+enum token_kind last_found_member_calling_convention = TOK_EOF;
+enum token_kind postfix_member_calling_convention = TOK_EOF;
+enum token_kind parsed_calling_convention = TOK_EOF;
 
-static int current_function_has_return_statement = 0;
-static int current_parse_block_depth = 0;
-static int current_function_is_void = 0;
-static int current_function_is_floating = 0;
-static int current_function_return_size = DATA_NONE;
-static int current_function_return_is_unsigned = 0;
-static int current_function_returns_aggregate = 0;
-static int current_function_param_stack_bytes = 0;
+struct vector vec_dllexports = { 0 };
+int parsed_dllexport = 0;
+int parsed_dllimport = 0;
 
-static enum token_kind current_function_calling_convention = TOK_EOF;
+int parsed_type_size = DATA_NONE;
+int parsed_type_is_inline = 0;
+int parsed_type_is_void = 0;
+int parsed_type_is_unsigned = 0;
+int parsed_type_is_floating = 0;
+int parsed_type_only_qualifiers = 0;
 
-static struct local_symbol *pending_struct_return_lhs = 0;
-static const char *pending_struct_return_global_name = 0;
+int parsed_type_is_aggregate = 0;
+int parsed_type_has_tag = 0;
 
-static int pending_struct_return_stack_address = 0;
-static int pending_struct_return_stack_offset = 0;
-static int pending_struct_return_stack_top = 0;
+char parsed_type_tag_name[128];
+char last_cast_type_tag_name[128];
 
-static int suppress_next_struct_return_scalar_store = 0;
-static int token_identifier_is_function_call_rhs_now (void);
+int last_cast_type_object_size = 0;
+int last_cast_type_is_floating = 0;
+int floating_rhs_result_in_eax_bool = 0;
 
-static int assignment32_stop_before_condition_operator = 0;
-static int assignment64_stop_before_condition_operator = 0;
+int parsed_type_is_array_typedef = 0;
+int parsed_type_array_element_size = DATA_NONE;
 
-static int parsed_type_size = DATA_NONE;
-static int parsed_type_is_inline = 0;
-static int parsed_type_is_void = 0;
-static int parsed_type_is_unsigned = 0;
-static int parsed_type_is_floating = 0;
-static int parsed_type_only_qualifiers = 0;
+long parsed_type_array_count = 1;
 
-static int parsed_type_is_aggregate = 0;
-static int parsed_type_has_tag = 0;
+int declarator_depth = 0;
+int declarator_has_function = 0;
+int declarator_function_is_pointer = 0;
+int declarator_function_param_count = 0;
+int declarator_function_has_prototype = 0;
+int declarator_function_is_variadic = 0;
+int declarator_array_unsized = 0;
 
-static char parsed_type_tag_name[128];
-static char last_cast_type_tag_name[128];
+int declarator_is_pointer = 0;
+int declarator_pointer_depth = 0;
+int declarator_has_array = 0;
 
-static int last_cast_type_object_size = 0;
-static int last_cast_type_is_floating = 0;
-static int floating_rhs_result_in_eax_bool = 0;
+int declarator_dllexport = 0;
+int declarator_dllimport = 0;
 
-static int parsed_type_is_array_typedef = 0;
-static int parsed_type_array_element_size = DATA_NONE;
+enum token_kind declarator_calling_convention = TOK_EOF;
+int global_initializer_accept_symbol_addresses = 0;
 
-static long parsed_type_array_count = 1;
+long declarator_array_count = 1;
+long declarator_first_array_count = 1;
+long declarator_last_array_count = 1;
 
-static int declarator_has_function = 0;
-static int declarator_function_is_pointer = 0;
-static int declarator_function_param_count = 0;
-static int declarator_function_has_prototype = 0;
-static int declarator_function_is_variadic = 0;
-static int declarator_array_unsized = 0;
+int declarator_array_dimensions = 0;
+int parsed_storage_class = STORAGE_NONE;
 
-static int declarator_is_pointer = 0;
-static int declarator_pointer_depth = 0;
-static int declarator_has_array = 0;
+int parsed_field_sizes[MAX_AGG_FIELDS];
+int parsed_field_count = 0;
 
-static int declarator_dllexport = 0;
-static int declarator_dllimport = 0;
+struct member_info_entry member_infos[MAX_MEMBER_INFOS];
+int member_info_count = 0;
 
-static enum token_kind declarator_calling_convention = TOK_EOF;
+const char *last_found_member_tag_name = 0;
+int last_found_member_is_unsigned = 0;
 
-static int global_initializer_accept_symbol_addresses = 0;
-static void masm_flush_data_line (void);
+struct pending_param pending_params[MAX_PENDING_PARAMS];
 
-static long declarator_array_count = 1;
-static long declarator_first_array_count = 1;
-static long declarator_last_array_count = 1;
+int pending_param_count;
+int preserve_pending_params;
 
-static int declarator_array_dimensions = 0;
+const char *last_declarator_name_start = 0;
+const char *last_declarator_name_caret = 0;
 
-#define     STORAGE_NONE                0
-#define     STORAGE_EXTERN              1
-#define     STORAGE_STATIC              2
-#define     STORAGE_TYPEDEF             3
+unsigned long last_declarator_name_line = 0;
 
-static int parsed_storage_class = STORAGE_NONE;
 
-#define     MAX_GLOBAL_INIT_FIELDS      262144
-#define     MAX_AGG_FIELDS              512
+int capture_declarator_name_location = 0;
+int captured_declarator_name_location = 0;
 
-static int parsed_field_sizes[MAX_AGG_FIELDS];
-static int parsed_field_count = 0;
+const char *captured_declarator_name_start = 0;
+const char *captured_declarator_name_caret = 0;
 
-#define     MAX_STRING_INIT_BYTES       4096
+unsigned long captured_declarator_name_line = 0;
 
-static void clear_parsed_fields (void) {
+void clear_parsed_fields (void) {
     parsed_field_count = 0;
 }
 
-static void append_parsed_field (int size) {
+void append_parsed_field (int size) {
 
     if (parsed_field_count < MAX_AGG_FIELDS) {
         parsed_field_sizes[parsed_field_count++] = size;
@@ -183,446 +112,538 @@ static void append_parsed_field (int size) {
 
 }
 
-static int fields_storage_size (const int *sizes, int count) {
+int is_string_token (void) {
+    return tok.kind == TOK_PPSTR || tok.kind == TOK_LSTR;
+}
 
-    int total = 0, i;
-    
-    for (i = 0; i < count; i++) {
+int expect (enum token_kind k, const char *what) {
+
+    if (tok.kind == k) {
     
-        if (sizes[i] < 0) {
-            total += -sizes[i];
-        } else {
-            total += sizes[i];
-        }
+        get_token ();
+        return 1;
     
     }
     
-    return total;
+    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected %s", what);
+    return 0;
 
 }
 
-#define     MAX_MEMBER_INFOS            4096
-
-struct member_info_entry {
+int declarator_object_size (int base_size) {
 
-    char *name;
-    int offset;
-    int size;
-    int elem_size;
-    int pointer_depth;
+    if (declarator_has_array) {
+    
+        int elem_size = declarator_is_pointer ? DATA_PTR : base_size;
+        
+        if (declarator_array_count <= 0) {
+            return elem_size;
+        }
+        
+        return elem_size * declarator_array_count;
     
-    int is_array;
-    int is_floating;
-    int is_unsigned;
+    }
     
-    char *tag_name;
-    char *owner_tag_name;
+    if (declarator_is_pointer) {
+        return DATA_PTR;
+    }
     
-    enum token_kind calling_convention;
-    int owner_size;
-
-};
-
-static struct member_info_entry member_infos[MAX_MEMBER_INFOS];
-static int member_info_count = 0;
+    return base_size;
 
-static int postfix_member_pointer_depth = 0;
-static int postfix_member_pointed_size = 0;
-static int postfix_member_seen = 0;
-static int postfix_copy_lvalue_size = 0;
+}
 
-static const char *postfix_copy_lvalue_tag_name = 0;
+struct enum_const_entry enum_constants[MAX_ENUM_CONSTANTS];
+int enum_constant_count = 0;
 
-static const char *last_found_member_tag_name = 0;
-static int last_found_member_is_unsigned = 0;
+struct typedef_entry *find_typedef_name (const char *name) {
 
-static enum token_kind last_found_member_calling_convention = TOK_EOF;
-static enum token_kind postfix_member_calling_convention = TOK_EOF;
+    int i;
+    
+    if (!name) {
+        return 0;
+    }
 
-static int postfix_member_offset = 0;
-static int postfix_member_size = 0;
+    for (i = 0; i < typedef_name_count; i++) {
+    
+        if (strcmp (typedef_names[i].name, name) == 0) {
+            return &typedef_names[i];
+        }
+    
+    }
+    
+    return 0;
 
-static int postfix_member_is_floating = 0;
-static int postfix_member_is_unsigned = 0;
+}
 
-static void remember_member_info_ex (const char *name, int offset, int size, int elem_size, int pointer_depth, int is_array, int is_floating) {
+static void update_typedef_name_from_aggregate_tag (const char *name, int size, const int *field_sizes, int field_count) {
 
+    struct typedef_entry *entry;
+    int i;
+    
     if (!name) {
         return;
     }
     
-    if (member_info_count >= MAX_MEMBER_INFOS) {
+    entry = find_typedef_name (name);
+    
+    if (!entry) {
         return;
     }
     
-    member_infos[member_info_count].name = xstrdup (name);
-    member_infos[member_info_count].offset = offset;
-    member_infos[member_info_count].size = size;
-    member_infos[member_info_count].elem_size = elem_size > 0 ? elem_size : size;
-    member_infos[member_info_count].pointer_depth = pointer_depth;
-    member_infos[member_info_count].is_array = is_array;
-    member_infos[member_info_count].is_floating = is_floating ? 1 : 0;
-    member_infos[member_info_count].is_unsigned = parsed_type_is_unsigned ? 1 : 0;
-    member_infos[member_info_count].calling_convention = (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention;
-    member_infos[member_info_count].tag_name = parsed_type_tag_name[0] ? xstrdup (parsed_type_tag_name) : 0;
-    member_infos[member_info_count].owner_size = 0;
-    member_infos[member_info_count].owner_tag_name = 0;
+    entry->size = size;
+    entry->is_aggregate = 1;
+    entry->is_void = 0;
+    entry->is_array = 0;
+    entry->array_count = 1;
+    entry->array_element_size = DATA_NONE;
+    entry->calling_convention = TOK_EOF;
+    entry->field_count = 0;
     
-    member_info_count++;
+    if (entry->tag_name) {
+    
+        free (entry->tag_name);
+        entry->tag_name = 0;
+    
+    }
+    
+    if (name && *name) {
+        entry->tag_name = xstrdup (name);
+    }
+    
+    for (i = 0; i < field_count && i < MAX_AGG_FIELDS; i++) {
+        entry->field_sizes[entry->field_count++] = field_sizes[i];
+    }
 
 }
 
-static int find_member_info_ex (const char *name, int *offset, int *size, int *elem_size, int *pointer_depth, int *is_array, int *is_floating) {
+static int is_current_typedef_name (void) {
 
-    int best;
-    int i;
-    
-    last_found_member_tag_name = 0;
-    last_found_member_is_unsigned = 0;
-    last_found_member_calling_convention = TOK_EOF;
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+        return 0;
+    }
     
-    if (!name) {
+    if (find_local_symbol (tok.ident)) {
         return 0;
     }
     
-    best = -1;
+    return find_typedef_name (tok.ident) != 0;
+
+}
+
+static void load_aggregate_tag_fields (struct aggregate_tag_entry *entry) {
+
+    int i;
+    clear_parsed_fields ();
     
-    for (i = member_info_count - 1; i >= 0; i--) {
+    if (!entry) {
+        return;
+    }
     
-        if (member_infos[i].name && strcmp (member_infos[i].name, name) == 0) {
-        
-            best = i;
-            break;
-        
-        }
+    parsed_type_size = entry->size;
+    parsed_type_is_aggregate = 1;
+    parsed_type_is_void = 0;
+    parsed_type_has_tag = 1;
     
+    for (i = 0; i < entry->field_count; i++) {
+        append_parsed_field (entry->field_sizes[i]);
     }
 
-    if (best < 0) {
-        return 0;
-    }
-    
-    last_found_member_tag_name = member_infos[best].tag_name;
-    last_found_member_is_unsigned = member_infos[best].is_unsigned ? 1 : 0;
-    last_found_member_calling_convention = member_infos[best].calling_convention;
+}
 
-    if (offset) {
-        *offset = member_infos[best].offset;
-    }
+static void save_aggregate_tag (const char *name, int is_union, int size, const int *field_sizes, int field_count) {
+
+    struct aggregate_tag_entry *entry;
+    int i;
     
-    if (size) {
-        *size = member_infos[best].size;
+    if (!name) {
+        return;
     }
     
-    if (elem_size) {
-        *elem_size = member_infos[best].elem_size;
-    }
+    entry = find_aggregate_tag (name, is_union);
     
-    if (pointer_depth) {
-        *pointer_depth = member_infos[best].pointer_depth;
-    }
+    if (!entry) {
     
-    if (is_array) {
-        *is_array = member_infos[best].is_array;
-    }
+        if (aggregate_tag_count >= MAX_AGG_TAGS) {
+            return;
+        }
+        
+        entry = &aggregate_tags[aggregate_tag_count++];
+        entry->name = xstrdup (name);
+        entry->is_union = is_union;
     
-    if (is_floating) {
-        *is_floating = member_infos[best].is_floating;
     }
     
-    return 1;
-
-}
+    entry->size = size;
+    entry->field_count = 0;
+    
+    for (i = 0; i < field_count && i < MAX_AGG_FIELDS; i++) {
+        entry->field_sizes[entry->field_count++] = field_sizes[i];
+    }
 
-static int find_member_info (const char *name, int *offset, int *size) {
-    return find_member_info_ex (name, offset, size, 0, 0, 0, 0);
 }
 
-static int find_member_info_ex_bounded (const char *name, int max_size, const char *owner_tag_name, int *offset, int *size, int *elem_size, int *pointer_depth, int *is_array, int *is_floating) {
+static struct enum_const_entry *find_enum_constant (const char *name) {
 
-    int best;
     int i;
     
-    last_found_member_tag_name = 0;
-    last_found_member_is_unsigned = 0;
-    last_found_member_calling_convention = TOK_EOF;
-    
     if (!name) {
         return 0;
     }
     
-    if (max_size <= 0 && (!owner_tag_name || !owner_tag_name[0])) {
-        return find_member_info_ex (name, offset, size, elem_size, pointer_depth, is_array, is_floating);
+    for (i = 0; i < enum_constant_count; i++) {
+    
+        if (strcmp (enum_constants[i].name, name) == 0) {
+            return &enum_constants[i];
+        }
+    
     }
     
-    best = -1;
+    return 0;
+
+}
+
+static void save_enum_constant (const char *name, int64_s value, const char *start, const char *caret) {
+
+    struct enum_const_entry *entry;
     
-    if (owner_tag_name && owner_tag_name[0]) {
+    if (!name || !*name) {
+        return;
+    }
     
-        for (i = member_info_count - 1; i >= 0; i--) {
-        
-            if (member_infos[i].name && strcmp (member_infos[i].name, name) == 0
-                && member_infos[i].owner_tag_name
-                && strcmp (member_infos[i].owner_tag_name, owner_tag_name) == 0) {
-            
-                best = i;
-                break;
-            
-            }
-        
-        }
+    entry = find_enum_constant (name);
+    
+    if (entry) {
+    
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, start, caret, "duplicate enum constant '%s'", name);
+        return;
     
     }
     
-    if (best < 0) {
+    if (enum_constant_count >= MAX_ENUM_CONSTANTS) {
     
-        for (i = member_info_count - 1; i >= 0; i--) {
-        
-            if (member_infos[i].name && strcmp (member_infos[i].name, name) == 0
-                && member_infos[i].owner_size == max_size) {
-            
-                if (best < 0 || member_infos[i].offset < member_infos[best].offset) {
-                    best = i;
-                }
-            
-            }
-        
-        }
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, start, caret, "too many enum constants");
+        return;
     
     }
     
-    if (best < 0) {
+    entry = &enum_constants[enum_constant_count++];
+    entry->name = xstrdup (name);
+    entry->value = value;
+
+}
+
+int token_is_ident (void) {
+    return tok.kind == TOK_IDENT;
+}
+
+static void parse_enum_body (void) {
+
+    int64_s value;
+    zext64 (&value, 0);
     
-        for (i = member_info_count - 1; i >= 0; i--) {
+    expect (TOK_LBRACE, "{");
+    
+    while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
+    
+        if (!token_is_ident ()) {
         
-            if (member_infos[i].name && strcmp (member_infos[i].name, name) == 0
-                && member_infos[i].offset + member_infos[i].size <= max_size) {
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected enum constant");
             
-                if (best < 0 || member_infos[i].offset < member_infos[best].offset) {
-                    best = i;
-                }
+            get_token ();
+            continue;
+        
+        } else {
+        
+            char *name;
+            
+            const char *name_start;
+            const char *name_caret;
+            
+            name = xstrdup (tok.ident);
+            
+            name_start = tok.start;
+            name_caret = tok.caret;
+            
+            get_token ();
+            
+            if (_accept (TOK_ASSIGN)) {
+            
+                enum token_kind kill[4];
+                
+                kill[0] = TOK_COMMA;
+                kill[1] = TOK_RBRACE;
+                kill[2] = TOK_EOF;
+                kill[3] = 0;
+                
+                value = expr_const64 (kill);
             
             }
+            
+            save_enum_constant (name, value, name_start, name_caret);
+            free (name);
+            
+            inc64 (&value);
         
         }
+        
+        if (!_accept (TOK_COMMA)) {
+            break;
+        }
     
     }
     
-    if (best >= 0) {
+    expect (TOK_RBRACE, "}");
+
+}
+
+static void parse_decl_modifier (void) {
+
+    if (tok.kind == TOK_STDCALL) {
     
-        last_found_member_tag_name = member_infos[best].tag_name;
-        last_found_member_is_unsigned = member_infos[best].is_unsigned ? 1 : 0;
-        last_found_member_calling_convention = member_infos[best].calling_convention;
-        
-        if (offset) {
-            *offset = member_infos[best].offset;
-        }
-        
-        if (size) {
-            *size = member_infos[best].size;
+        if (parsed_calling_convention == TOK_EOF && declarator_calling_convention == TOK_EOF) {
+            parsed_calling_convention = TOK_STDCALL;
         }
+    
+    } else if (tok.kind == TOK_DLLEXPORT) {
+    
+        if (parsed_dllexport) {
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate '__dllexport'");
+        } else if (parsed_dllimport) {
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "'__dllexport' and '__dllimport' cannot both be specified");
+        } else {
         
-        if (elem_size) {
-            *elem_size = member_infos[best].elem_size;
-        }
+            declarator_dllexport = 1;
+            parsed_dllexport = 1;
         
-        if (pointer_depth) {
-            *pointer_depth = member_infos[best].pointer_depth;
         }
+    
+    } else if (tok.kind == TOK_DLLIMPORT) {
+    
+        if (parsed_dllimport) {
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate '__dllimport'");
+        } else if (parsed_dllexport) {
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "'__dllexport' and '__dllimport' cannot both be specified");
+        } else {
         
-        if (is_array) {
-            *is_array = member_infos[best].is_array;
-        }
+            declarator_dllimport = 1;
+            parsed_dllimport = 1;
         
-        if (is_floating) {
-            *is_floating = member_infos[best].is_floating;
         }
-        
-        return 1;
     
     }
     
-    return find_member_info_ex (name, offset, size, elem_size, pointer_depth, is_array, is_floating);
+    get_token ();
 
 }
 
-static const char *find_member_tag_name (const char *name) {
+void parse_declarator_inner (char **out_name) {
 
-    int i;
+    while (tok.kind == TOK_STDCALL || tok.kind == TOK_DLLEXPORT || tok.kind == TOK_DLLIMPORT) {
+    
+        if (tok.kind == TOK_STDCALL) {
+        
+            if (declarator_calling_convention == TOK_EOF && parsed_calling_convention == TOK_EOF) {
+                declarator_calling_convention = tok.kind;
+            }
+            
+            get_token ();
+        
+        } else {
+            parse_decl_modifier ();
+        }
     
-    if (!name) {
-        return 0;
     }
     
-    for (i = member_info_count - 1; i >= 0; i--) {
+    while (tok.kind == TOK_STAR) {
     
-        if (member_infos[i].name && strcmp (member_infos[i].name, name) == 0) {
-            return member_infos[i].tag_name;
+        declarator_is_pointer = 1;
+        declarator_pointer_depth++;
+        
+        get_token ();
+        
+        while (tok.kind == TOK_CONST || tok.kind == TOK_VOLATILE || tok.kind == TOK_RESTRICT || tok.kind == TOK_STDCALL || tok.kind == TOK_DLLEXPORT || tok.kind == TOK_DLLIMPORT) {
+        
+            if (tok.kind == TOK_STDCALL) {
+            
+                if (declarator_calling_convention == TOK_EOF && parsed_calling_convention == TOK_EOF) {
+                    declarator_calling_convention = tok.kind;
+                }
+                
+                get_token ();
+            
+            } else if (tok.kind == TOK_DLLEXPORT || tok.kind == TOK_DLLIMPORT) {
+                parse_decl_modifier ();
+            } else {
+                get_token ();
+            }
+        
         }
     
     }
     
-    return 0;
+    parse_direct_declarator (out_name);
 
 }
 
-#define     MAX_AGG_TAGS                256
-
-struct aggregate_tag_entry {
-
-    char *name;
-    
-    int is_union;
-    int size;
-    
-    int field_count;
-    int field_sizes[MAX_AGG_FIELDS];
-
-};
-
-static struct aggregate_tag_entry aggregate_tags[MAX_AGG_TAGS];
-static int aggregate_tag_count = 0;
-
-static struct aggregate_tag_entry *find_aggregate_tag (const char *name, int is_union) {
+void clear_pending_params (void) {
 
     int i;
     
-    if (!name) {
-        return 0;
-    }
-    
-    for (i = 0; i < aggregate_tag_count; i++) {
+    for (i = 0; i < pending_param_count; i++) {
     
-        if (aggregate_tags[i].is_union == is_union && strcmp (aggregate_tags[i].name, name) == 0) {
-            return &aggregate_tags[i];
+        if (pending_params[i].name) {
+        
+            free (pending_params[i].name);
+            pending_params[i].name = 0;
+        
+        }
+        
+        pending_params[i].size = 0;
+        pending_params[i].align = 0;
+        pending_params[i].is_unsigned = 0;
+        pending_params[i].is_floating = 0;
+        pending_params[i].pointer_depth = 0;
+        pending_params[i].pointed_size = 0;
+        pending_params[i].pointed_is_floating = 0;
+        pending_params[i].pointed_is_unsigned = 0;
+        pending_params[i].knr_declared = 0;
+        
+        if (pending_params[i].pointed_tag_name) {
+        
+            free (pending_params[i].pointed_tag_name);
+            pending_params[i].pointed_tag_name = 0;
+        
         }
     
     }
     
-    return 0;
+    pending_param_count = 0;
 
 }
 
-static void save_aggregate_tag (const char *name, int is_union, int size, const int *field_sizes, int field_count) {
+void parse_declarator (char **out_name) {
 
-    struct aggregate_tag_entry *entry;
-    int i;
+    int top_level = (declarator_depth == 0);
     
-    if (!name) {
-        return;
-    }
+    int saved_capture_declarator_name_location = capture_declarator_name_location;
+    int saved_captured_declarator_name_location = captured_declarator_name_location;
+
+    const char *saved_captured_declarator_name_start = captured_declarator_name_start;
+    const char *saved_captured_declarator_name_caret = captured_declarator_name_caret;
+
+    enum token_kind saved_declarator_calling_convention = declarator_calling_convention;
     
-    entry = find_aggregate_tag (name, is_union);
+    int saved_declarator_dllexport = declarator_dllexport;
+    int saved_declarator_dllimport = declarator_dllimport;
     
-    if (!entry) {
+    unsigned long saved_captured_declarator_name_line = captured_declarator_name_line;
     
-        if (aggregate_tag_count >= MAX_AGG_TAGS) {
-            return;
+    if (top_level) {
+    
+        if (!preserve_pending_params) {
+            clear_pending_params ();
         }
         
-        entry = &aggregate_tags[aggregate_tag_count++];
-        entry->name = xstrdup (name);
-        entry->is_union = is_union;
+        declarator_calling_convention = TOK_EOF;
+        capture_declarator_name_location = 1;
+        
+        declarator_dllexport = 0;
+        declarator_dllimport = 0;
+        
+        captured_declarator_name_location = 0;
+        captured_declarator_name_start = 0;
+        captured_declarator_name_caret = 0;
+        captured_declarator_name_line = 0;
     
     }
     
-    entry->size = size;
-    entry->field_count = 0;
+    declarator_depth++;
     
-    for (i = 0; i < field_count && i < MAX_AGG_FIELDS; i++) {
-        entry->field_sizes[entry->field_count++] = field_sizes[i];
-    }
-
-}
-
-static void load_aggregate_tag_fields (struct aggregate_tag_entry *entry) {
-
-    int i;
-    clear_parsed_fields ();
+    declarator_is_pointer = 0;
+    declarator_pointer_depth = 0;
+    declarator_has_array = 0;
+    declarator_has_function = 0;
+    declarator_function_is_pointer = 0;
+    declarator_function_param_count = 0;
+    declarator_function_has_prototype = 0;
+    declarator_function_is_variadic = 0;
+    declarator_array_unsized = 0;
+    declarator_array_count = 1;
+    declarator_first_array_count = 1;
+    declarator_last_array_count = 1;
+    declarator_array_dimensions = 0;
     
-    if (!entry) {
-        return;
-    }
+    parse_declarator_inner (out_name);
     
-    parsed_type_size = entry->size;
-    parsed_type_is_aggregate = 1;
-    parsed_type_is_void = 0;
-    parsed_type_has_tag = 1;
+    if (top_level && parsed_type_is_array_typedef && !declarator_is_pointer && !declarator_has_array && !declarator_has_function) {
+    
+        declarator_has_array = 1;
+        
+        declarator_array_count = parsed_type_array_count > 0 ? parsed_type_array_count : 1;
+        declarator_first_array_count = declarator_array_count;
+        declarator_last_array_count = declarator_array_count;
+        declarator_array_dimensions = 1;
+        
+        if (parsed_type_array_element_size > 0) {
+            parsed_type_size = parsed_type_array_element_size;
+        }
     
-    for (i = 0; i < entry->field_count; i++) {
-        append_parsed_field (entry->field_sizes[i]);
     }
-
-}
-
-#define     MAX_TYPEDEF_NAMES            512
-
-struct typedef_entry {
-
-    char *name;
-    int size;
     
-    int is_aggregate;
-    int is_unsigned;
-    int is_void;
+    declarator_depth--;
+    
+    if (top_level) {
     
-    int field_count;
-    int field_sizes[MAX_AGG_FIELDS];
+        if (captured_declarator_name_location) {
+        
+            last_declarator_name_line = captured_declarator_name_line;
+            last_declarator_name_start = captured_declarator_name_start;
+            last_declarator_name_caret = captured_declarator_name_caret;
+        
+        }
+        
+        capture_declarator_name_location = saved_capture_declarator_name_location;
+        captured_declarator_name_location = saved_captured_declarator_name_location;
+        captured_declarator_name_start = saved_captured_declarator_name_start;
+        captured_declarator_name_caret = saved_captured_declarator_name_caret;
+        captured_declarator_name_line = saved_captured_declarator_name_line;
     
-    int array_element_size;
-    int is_array;
+    } else {
     
-    char *tag_name;
-    long array_count;
+        declarator_calling_convention = saved_declarator_calling_convention;
+        declarator_dllexport = saved_declarator_dllexport;
+        declarator_dllimport = saved_declarator_dllimport;
     
-    enum token_kind calling_convention;
+    }
 
-};
+}
 
-static struct typedef_entry typedef_names[MAX_TYPEDEF_NAMES];
-static int typedef_name_count = 0;
 
-static void clear_typedef_names (void) {
+int _accept (enum token_kind k) {
 
-    int i;
-    
-    for (i = 0; i < typedef_name_count; i++) {
+    if (tok.kind == k) {
     
-        free (typedef_names[i].name);
-        
-        typedef_names[i].name = 0;
-        typedef_names[i].size = 0;
-        
-        typedef_names[i].tag_name = 0;
-        
-        typedef_names[i].is_aggregate = 0;
-        typedef_names[i].is_unsigned = 0;
-        
-        typedef_names[i].field_count = 0;
-        typedef_names[i].is_array = 0;
-        typedef_names[i].array_count = 1;
-        typedef_names[i].array_element_size = DATA_NONE;
-        
-        typedef_names[i].calling_convention = TOK_EOF;
+        get_token ();
+        return 1;
     
     }
     
-    typedef_name_count = 0;
+    return 0;
 
 }
 
-static struct typedef_entry *find_typedef_name (const char *name) {
+static const char *find_member_tag_name (const char *name) {
 
     int i;
     
     if (!name) {
         return 0;
     }
-
-    for (i = 0; i < typedef_name_count; i++) {
     
-        if (strcmp (typedef_names[i].name, name) == 0) {
-            return &typedef_names[i];
+    for (i = member_info_count - 1; i >= 0; i--) {
+    
+        if (member_infos[i].name && strcmp (member_infos[i].name, name) == 0) {
+            return member_infos[i].tag_name;
         }
     
     }
@@ -631,36771 +652,605 @@ static struct typedef_entry *find_typedef_name (const char *name) {
 
 }
 
-struct local_symbol;
-static struct local_symbol *find_local_symbol (const char *name);
-
-static int is_current_typedef_name (void) {
+static int parse_sizeof_member_expr_size (int leading_stars, int *out_size) {
 
-    if (tok.kind != TOK_IDENT || !tok.ident) {
-        return 0;
-    }
-    
-    if (find_local_symbol (tok.ident)) {
-        return 0;
-    }
+    int size = DATA_INT & 0x1f;
+    int pointer_depth = 0;
+    int pointed_size = 0;
+    int is_array = 0;
+    int array_element_size = 0;
+    int final_pointer_depth = 0;
+    int final_pointed_size = 0;
+    int final_is_array = 0;
+    int final_array_element_size = 0;
     
-    return find_typedef_name (tok.ident) != 0;
-
-}
-
-static void save_typedef_name (const char *name, int size, int is_unsigned, int is_void, int is_aggregate, int is_array, long array_count, int array_element_size, enum token_kind calling_convention, const int *field_sizes, int field_count) {
-
-    struct typedef_entry *entry;
-    int i;
+    struct local_symbol *local;
     
-    if (!name || !*name) {
-        return;
+    if (tok.kind != TOK_IDENT) {
+        return 0;
     }
     
-    entry = find_typedef_name (name);
+    local = find_local_symbol (tok.ident);
     
-    if (!entry) {
+    if (local) {
     
-        if (typedef_name_count >= MAX_TYPEDEF_NAMES) {
-        
-            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "too many typedef names");
-            return;
+        size = local->size;
         
-        }
+        pointer_depth = local->pointer_depth;
+        pointed_size = local->pointed_size;
         
-        entry = &typedef_names[typedef_name_count++];
-        entry->name = xstrdup (name);
-        entry->tag_name = 0;
-        entry->calling_convention = TOK_EOF;
-    
-    }
-    
-    if (entry->tag_name) {
+        is_array = local->is_array;
+        array_element_size = local->array_element_size;
     
-        free (entry->tag_name);
-        entry->tag_name = 0;
+    } else if (find_global_symbol (tok.ident) >= 0) {
     
-    }
+        size = get_global_symbol_size (tok.ident);
+        
+        pointer_depth = get_global_symbol_pointer_depth (tok.ident);
+        pointed_size = get_global_symbol_pointed_size (tok.ident);
+        
+        is_array = get_global_symbol_array (tok.ident);
+        array_element_size = get_global_symbol_array_element_size (tok.ident);
     
-    if (parsed_type_tag_name[0]) {
-        entry->tag_name = xstrdup (parsed_type_tag_name);
-    } else if (is_aggregate && name && *name) {
-        entry->tag_name = xstrdup (name);
+    } else {
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "unknown symbol '%s'", tok.ident ? tok.ident : "");
     }
     
-    entry->is_void = is_void;
-    entry->size = size;
-    
-    entry->is_unsigned = is_unsigned;
-    entry->is_aggregate = is_aggregate;
-    
-    entry->field_count = 0;
-    entry->is_array = is_array ? 1 : 0;
-    entry->array_count = array_count > 0 ? array_count : 1;
-    entry->array_element_size = array_element_size > 0 ? array_element_size : DATA_INT;
-    entry->calling_convention = calling_convention;
+    final_pointer_depth = pointer_depth;
+    final_pointed_size = pointed_size;
+    final_is_array = is_array;
+    final_array_element_size = array_element_size;
     
-    for (i = 0; i < field_count && i < MAX_AGG_FIELDS; i++) {
-        entry->field_sizes[entry->field_count++] = field_sizes[i];
-    }
+    get_token ();
     
-    if (is_aggregate && !parsed_type_tag_name[0] && name && *name) {
+    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
     
-        int mi;
+        int member_pointer_depth = 0;
+        int member_pointed_size = 0;
+        int member_offset = 0;
+        int member_size = 0;
+        int member_is_array = 0;
+        
+        const char *member_tag_name = 0;
+        enum token_kind member_op = tok.kind;
+        
+        get_token ();
+        
+        if (tok.kind != TOK_IDENT) {
+        
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret,
+                            "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+            break;
+        
+        }
+        
+        if (find_member_info_ex (tok.ident, &member_offset, &member_size,
+                                 &member_pointed_size, &member_pointer_depth,
+                                 &member_is_array, 0)) {
         
-        for (mi = 0; mi < member_info_count; mi++) {
+            member_tag_name = last_found_member_tag_name ? last_found_member_tag_name : find_member_tag_name (tok.ident);
+            size = member_size;
+            
+            final_pointer_depth = member_pointer_depth;
+            final_pointed_size = member_pointed_size;
+            
+            final_is_array = member_is_array;
+            final_array_element_size = member_is_array ? member_size : 0;
         
-            if (member_infos[mi].owner_size == size
-                && member_infos[mi].owner_tag_name == 0) {
-                member_infos[mi].owner_tag_name = xstrdup (name);
+            if (final_pointer_depth > 0 && member_tag_name) {
+            
+                struct aggregate_tag_entry *entry = find_aggregate_tag (member_tag_name, 0);
+                
+                if (entry) {
+                    final_pointed_size = entry->size;
+                }
+            
             }
         
+        } else {
+        
+            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret,
+                            "unknown member '%s'", tok.ident ? tok.ident : "");
+        
         }
-    
-    }
-
-}
-
-static void update_typedef_name_from_aggregate_tag (const char *name, int size, const int *field_sizes, int field_count) {
-
-    struct typedef_entry *entry;
-    int i;
-    
-    if (!name) {
-        return;
-    }
-    
-    entry = find_typedef_name (name);
-    
-    if (!entry) {
-        return;
-    }
-    
-    entry->size = size;
-    entry->is_aggregate = 1;
-    entry->is_void = 0;
-    entry->is_array = 0;
-    entry->array_count = 1;
-    entry->array_element_size = DATA_NONE;
-    entry->calling_convention = TOK_EOF;
-    entry->field_count = 0;
-    
-    if (entry->tag_name) {
-    
-        free (entry->tag_name);
-        entry->tag_name = 0;
+        
+        get_token ();
     
     }
     
-    if (name && *name) {
-        entry->tag_name = xstrdup (name);
-    }
+    while (tok.kind == TOK_LBRACK) {
     
-    for (i = 0; i < field_count && i < MAX_AGG_FIELDS; i++) {
-        entry->field_sizes[entry->field_count++] = field_sizes[i];
-    }
-
-}
-
-static void load_typedef_name (struct typedef_entry *entry) {
-
-    int i;
-    clear_parsed_fields ();
-    
-    if (!entry) {
-    
-        parsed_type_size = DATA_INT & 0x1f;
+        int depth = 1;
+        get_token ();
         
-        parsed_type_is_aggregate = 0;
-        parsed_type_is_unsigned = 0;
-        parsed_type_is_void = 0;
-        parsed_type_is_floating = 0;
-        parsed_type_is_array_typedef = 0;
-        parsed_type_array_count = 1;
-        parsed_type_array_element_size = DATA_NONE;
-        parsed_calling_convention = TOK_EOF;
+        while (tok.kind != TOK_EOF && depth > 0) {
         
-        append_parsed_field (DATA_INT & 0x1f);
-        return;
+            if (tok.kind == TOK_LBRACK) {
+                depth++;
+            } else if (tok.kind == TOK_RBRACK) {
+            
+                depth--;
+                
+                if (depth == 0) {
+                    break;
+                }
+            
+            }
+            
+            get_token ();
+        
+        }
+        
+        if (tok.kind == TOK_RBRACK) {
+            get_token ();
+        }
+        
+        if (final_is_array && leading_stars > 0) {
+        
+            int remaining_stars = leading_stars - 1;
+            int elem_size = final_array_element_size > 0 ? final_array_element_size :
+                (final_pointer_depth > 0 ? DATA_PTR : final_pointed_size);
+            
+            /*
+             * In expressions, an array object decays to a pointer to its first
+             * element before the leading '*' operators are applied.  For an
+             * array of pointers, sizeof(*array) is therefore pointer-sized,
+             * not the size of the pointed-to base type.
+             */
+            size = elem_size > 0 ? elem_size : size;
+            
+            if (remaining_stars > 0 && final_pointer_depth >= remaining_stars) {
+            
+                int remaining_depth = final_pointer_depth - remaining_stars;
+                size = remaining_depth > 0 ? DATA_PTR : final_pointed_size;
+            
+            }
+            
+            final_is_array = 0;
+            final_pointer_depth = 0;
+        
+        } else if (final_pointer_depth > 0) {
+         
+            size = final_pointer_depth > 1 ? DATA_PTR : final_pointed_size;
+            final_pointer_depth--;
+        
+        } else if (final_is_array && final_array_element_size > 0) {
+            size = final_array_element_size;
+        } else if (final_is_array && final_pointed_size > 0) {
+            size = final_pointed_size;
+        }
+        
+        final_is_array = 0;
     
     }
     
-    parsed_type_size = entry->size;
-    
-    parsed_type_is_aggregate = entry->is_aggregate;
-    parsed_type_is_unsigned = entry->is_unsigned;
-    parsed_type_is_void = entry->is_void;
-    parsed_type_is_floating = 0;
-    parsed_type_is_array_typedef = entry->is_array;
-    parsed_type_array_count = entry->array_count > 0 ? entry->array_count : 1;
-    parsed_type_array_element_size = entry->array_element_size > 0 ? entry->array_element_size : DATA_INT;
-    parsed_calling_convention = entry->calling_convention;
-    
-    parsed_type_has_tag = 0;
-    parsed_type_tag_name[0] = '\0';
+    if (leading_stars > 0 && final_is_array) {
     
-    if (entry->tag_name && entry->tag_name[0]) {
+        int remaining_stars = leading_stars - 1;
+        int elem_size = final_array_element_size > 0 ? final_array_element_size :
+            (final_pointer_depth > 0 ? DATA_PTR : final_pointed_size);
         
-        strncpy (parsed_type_tag_name, entry->tag_name, sizeof (parsed_type_tag_name) - 1);
-        parsed_type_tag_name[sizeof (parsed_type_tag_name) - 1] = '\0';
+        /*
+         * In an expression, an array object decays to a pointer to its first
+         * element before unary '*' is applied.  This is needed for plain
+         * sizeof(*array) as well as for forms that later include subscripts.
+         * For example, with char *builtins[], sizeof(*builtins) is the size
+         * of one array element, i.e. pointer-sized, not sizeof(char).
+         */
+        size = elem_size > 0 ? elem_size : size;
         
-        parsed_type_has_tag = 1;
+        if (remaining_stars > 0 && final_pointer_depth >= remaining_stars) {
+        
+            int remaining_depth = final_pointer_depth - remaining_stars;
+            size = remaining_depth > 0 ? DATA_PTR : final_pointed_size;
+        
+        }
+        
+        final_is_array = 0;
+        final_pointer_depth = 0;
+    
+    } else if (leading_stars > 0 && final_pointer_depth >= leading_stars) {
+    
+        int remaining_depth = final_pointer_depth - leading_stars;
+        size = remaining_depth > 0 ? DATA_PTR : final_pointed_size;
     
     }
     
-    for (i = 0; i < entry->field_count; i++) {
-        append_parsed_field (entry->field_sizes[i]);
+    if (size < 1) {
+        size = DATA_INT & 0x1f;
     }
+    
+    *out_size = size;
+    return 1;
 
 }
 
-#define     MAX_ENUM_CONSTANTS          4096
-
-struct enum_const_entry {
-
-    char *name;
-    int64_s value;
-
-};
-
-static struct enum_const_entry enum_constants[MAX_ENUM_CONSTANTS];
-static int enum_constant_count = 0;
-
-static struct enum_const_entry *find_enum_constant (const char *name) {
+static int parse_octal_escape_value (const char **ps) {
 
-    int i;
-    
-    if (!name) {
-        return 0;
-    }
+    const char *s = *ps;
+    int value = 0, i;
     
-    for (i = 0; i < enum_constant_count; i++) {
+    for (i = 0; i < 3; i++) {
     
-        if (strcmp (enum_constants[i].name, name) == 0) {
-            return &enum_constants[i];
+        if (*s < '0' || *s > '7') {
+            break;
         }
+        
+        value = value * 8 + (*s - '0');
+        s++;
     
     }
     
-    return 0;
+    *ps = s;
+    return value;
 
 }
 
-static void save_enum_constant (const char *name, int64_s value, const char *start, const char *caret) {
+static int parse_hex_escape_value (const char **ps) {
 
-    struct enum_const_entry *entry;
-    
-    if (!name || !*name) {
-        return;
-    }
+    const char *s = *ps;
     
-    entry = find_enum_constant (name);
+    int value = 0;
+    int any = 0;
     
-    if (entry) {
+    while ((*s >= '0' && *s <= '9') || (*s >= 'a' && *s <= 'f') || (*s >= 'A' && *s <= 'F')) {
     
-        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, start, caret, "duplicate enum constant '%s'", name);
-        return;
+        int digit;
+        
+        if (*s >= '0' && *s <= '9') {
+            digit = *s - '0';
+        } else if (*s >= 'a' && *s <= 'f') {
+            digit = *s - 'a' + 10;
+        } else {
+            digit = *s - 'A' + 10;
+        }
+        
+        value = (value << 4) + digit;
+        any = 1;
+        
+        s++;
     
     }
     
-    if (enum_constant_count >= MAX_ENUM_CONSTANTS) {
-    
-        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, start, caret, "too many enum constants");
-        return;
-    
+    if (!any) {
+        value = 'x';
     }
     
-    entry = &enum_constants[enum_constant_count++];
-    entry->name = xstrdup (name);
-    entry->value = value;
+    *ps = s;
+    return value;
 
 }
 
-int resolve_enum_constant (const char *name, int64_s *out) {
+void append_global_init_value (int64_s *values, int max_values, int *count, unsigned int value, int elem_size) {
 
-    struct enum_const_entry *entry = find_enum_constant (name);
-    
-    if (!entry) {
-        return 0;
-    }
+    unsigned int mask = 0xffU;
     
-    if (out) {
-        *out = entry->value;
+    if (elem_size == (DATA_SHORT & 0x1f)) {
+        mask = 0xffffU;
     }
     
-    return 1;
-
-}
-
-static void clear_enum_constants (void) {
-
-    int i;
-    
-    for (i = 0; i < enum_constant_count; i++) {
-    
-        free (enum_constants[i].name);
-        
-        enum_constants[i].name = 0;
-        enum_constants[i].value.low = 0;
-        enum_constants[i].value.high = 0;
-    
+    if (*count < max_values) {
+        zext64 (&values[*count], value & mask);
     }
     
-    enum_constant_count = 0;
+    (*count)++;
 
 }
 
-#define     MAX_GLOBAL_SYMBOLS          4096
-
-#define     GLOBAL_SYMBOL_OBJECT        1
-#define     GLOBAL_SYMBOL_FUNCTION      2
+void skip_balanced_until (enum token_kind stop1, enum token_kind stop2, enum token_kind stop3) {
 
-struct global_symbol_entry {
-
-    char *name;
-    
-    int is_unsigned, is_extern;
-    int is_dllimport;
-    int kind, size;
-    
-    int array_element_size;
-    int is_array;
-    int array_dimensions;
-    
-    long array_count;
-    
-    int is_floating;
-    int pointer_depth;
-    int pointed_size;
-    int pointed_is_floating;
-    int pointed_is_unsigned;
-    int returns_void;
-    
-    int param_count;
-    int has_prototype;
-    int is_variadic;
-    
-    int param_sizes[128];
-    int param_unsigneds[128];
-    int param_floatings[128];
-    
-    int import_call_stack_bytes;
-    int is_implicit;
-    int extern_emitted;
-    
-    enum token_kind calling_convention;
-    char *tag_name;
-
-};
-
-static struct global_symbol_entry global_symbols[MAX_GLOBAL_SYMBOLS];
-static int global_symbol_count = 0;
-
-static const char *last_declarator_name_start = 0;
-static const char *last_declarator_name_caret = 0;
-
-static unsigned long last_declarator_name_line = 0;
-
-static int capture_declarator_name_location = 0;
-static int captured_declarator_name_location = 0;
-
-static const char *captured_declarator_name_start = 0;
-static const char *captured_declarator_name_caret = 0;
-
-static unsigned long captured_declarator_name_line = 0;
-
-static void clear_global_symbols (void) {
-
-    int i;
+    int paren = 0, brace = 0, brack = 0;
     
-    for (i = 0; i < global_symbol_count; i++) {
+    while (tok.kind != TOK_EOF) {
     
-        free (global_symbols[i].name);
-        
-        global_symbols[i].name = 0;
-        global_symbols[i].kind = 0;
-        global_symbols[i].size = 0;
+        if (paren == 0 && brace == 0 && brack == 0) {
         
-        global_symbols[i].array_element_size = 0;
-        global_symbols[i].is_array = 0;
-        global_symbols[i].array_dimensions = 0;
+            if (tok.kind == stop1 || tok.kind == stop2 || tok.kind == stop3) {
+                return;
+            }
         
-        global_symbols[i].is_dllimport = 0;
-        global_symbols[i].is_extern = 0;
-        global_symbols[i].is_unsigned = 0;
-        global_symbols[i].is_floating = 0;
-        global_symbols[i].returns_void = 0;
+        }
         
-        global_symbols[i].calling_convention = TOK_EOF;
+        if (tok.kind == TOK_LPAREN) {
+            paren++;
+        } else if (tok.kind == TOK_RPAREN) {
         
-        {
-        
-            int pi;
-            
-            for (pi = 0; pi < 128; pi++) {
+            if (paren > 0) {
+                paren--;
+            } else {
             
-                global_symbols[i].param_sizes[pi] = 0;
-                global_symbols[i].param_unsigneds[pi] = 0;
-                global_symbols[i].param_floatings[pi] = 0;
+                if (stop1 == TOK_RPAREN || stop2 == TOK_RPAREN || stop3 == TOK_RPAREN) {
+                    return;
+                }
             
             }
         
-        }
+        } else if (tok.kind == TOK_LBRACE) {
+            brace++;
+        } else if (tok.kind == TOK_RBRACE) {
         
-        global_symbols[i].import_call_stack_bytes = 0;
-        global_symbols[i].param_count = 0;
-        global_symbols[i].has_prototype = 0;
-        global_symbols[i].is_variadic = 0;
-        global_symbols[i].is_implicit = 0;
-        global_symbols[i].extern_emitted = 0;
+            if (brace > 0) {
+                brace--;
+            } else {
+            
+                if (stop1 == TOK_RPAREN || stop2 == TOK_RPAREN || stop3 == TOK_RPAREN) {
+                    return;
+                }
+            
+            }
         
-        if (global_symbols[i].tag_name) {
+        } else if (tok.kind == TOK_LBRACK) {
+            brack++;
+        } else if (tok.kind == TOK_RBRACK) {
         
-            free (global_symbols[i].tag_name);
-            global_symbols[i].tag_name = 0;
+            if (brack > 0) {
+                brack--;
+            } else {
+            
+                if (stop1 == TOK_RPAREN || stop2 == TOK_RPAREN || stop3 == TOK_RPAREN) {
+                    return;
+                }
+            
+            }
         
         }
+        
+        get_token ();
     
     }
-    
-    global_symbol_count = 0;
 
 }
 
-static int find_global_symbol (const char *name) {
+int find_member_info_ex_bounded (const char *name, int max_size, const char *owner_tag_name, int *offset, int *size, int *elem_size, int *pointer_depth, int *is_array, int *is_floating) {
 
+    int best;
     int i;
     
+    last_found_member_tag_name = 0;
+    last_found_member_is_unsigned = 0;
+    last_found_member_calling_convention = TOK_EOF;
+    
     if (!name) {
-        return -1;
+        return 0;
     }
     
-    for (i = 0; i < global_symbol_count; i++) {
+    if (max_size <= 0 && (!owner_tag_name || !owner_tag_name[0])) {
+        return find_member_info_ex (name, offset, size, elem_size, pointer_depth, is_array, is_floating);
+    }
     
-        if (strcmp (global_symbols[i].name, name) == 0) {
-            return i;
-        }
+    best = -1;
     
-    }
+    if (owner_tag_name && owner_tag_name[0]) {
     
-    return -1;
-
-}
-
-static int asm_symbol_is_internal (const char *name) {
-
-    if (!name || !*name) {
-        return 1;
-    }
+        for (i = member_info_count - 1; i >= 0; i--) {
+        
+            if (member_infos[i].name && strcmp (member_infos[i].name, name) == 0
+                && member_infos[i].owner_tag_name
+                && strcmp (member_infos[i].owner_tag_name, owner_tag_name) == 0) {
+            
+                best = i;
+                break;
+            
+            }
+        
+        }
     
-    if (name[0] == '.') {
-        return 1;
     }
     
-    if (name[0] == 'L') {
+    if (best < 0) {
     
-        if (name[1] >= '0' && name[1] <= '9') {
-            return 1;
-        }
+        for (i = member_info_count - 1; i >= 0; i--) {
+        
+            if (member_infos[i].name && strcmp (member_infos[i].name, name) == 0
+                && member_infos[i].owner_size == max_size) {
+            
+                if (best < 0 || member_infos[i].offset < member_infos[best].offset) {
+                    best = i;
+                }
+            
+            }
         
-        if (name[1] == 'C' && name[2] >= '0' && name[2] <= '9') {
-            return 1;
         }
     
     }
     
-    return 0;
-
-}
-
-static int global_symbol_stdcall_stack_bytes (const char *name) {
-
-    int i = find_global_symbol (name);
-    int pi;
-    int bytes = 0;
-    
-    if (i < 0 || global_symbols[i].kind != GLOBAL_SYMBOL_FUNCTION || global_symbols[i].calling_convention != TOK_STDCALL ||
+    if (best < 0) {
     
-        global_symbols[i].is_variadic) {
-        return 0;
+        for (i = member_info_count - 1; i >= 0; i--) {
+        
+            if (member_infos[i].name && strcmp (member_infos[i].name, name) == 0
+                && member_infos[i].offset + member_infos[i].size <= max_size) {
+            
+                if (best < 0 || member_infos[i].offset < member_infos[best].offset) {
+                    best = i;
+                }
+            
+            }
+        
+        }
     
     }
     
-    for (pi = 0; pi < global_symbols[i].param_count && pi < 128; pi++) {
+    if (best >= 0) {
     
-        int size = global_symbols[i].param_sizes[pi];
+        last_found_member_tag_name = member_infos[best].tag_name;
+        last_found_member_is_unsigned = member_infos[best].is_unsigned ? 1 : 0;
+        last_found_member_calling_convention = member_infos[best].calling_convention;
         
-        if (size < 1) {
-            size = DATA_PTR & 0x1f;
+        if (offset) {
+            *offset = member_infos[best].offset;
         }
         
-        bytes += ((size + (DATA_PTR & 0x1f) - 1) / (DATA_PTR & 0x1f)) * (DATA_PTR & 0x1f);
-    
-    }
+        if (size) {
+            *size = member_infos[best].size;
+        }
+        
+        if (elem_size) {
+            *elem_size = member_infos[best].elem_size;
+        }
+        
+        if (pointer_depth) {
+            *pointer_depth = member_infos[best].pointer_depth;
+        }
+        
+        if (is_array) {
+            *is_array = member_infos[best].is_array;
+        }
+        
+        if (is_floating) {
+            *is_floating = member_infos[best].is_floating;
+        }
+        
+        return 1;
     
-    if (bytes <= 0 && global_symbols[i].import_call_stack_bytes > 0) {
-        bytes = global_symbols[i].import_call_stack_bytes;
     }
     
-    return bytes;
+    return find_member_info_ex (name, offset, size, elem_size, pointer_depth, is_array, is_floating);
 
 }
 
-static void remember_global_symbol_import_call_stack_bytes (const char *name, int bytes) {
+int parse_constexpr_null_member_address_after_lparen (int64_s *out) {
 
-    int i = find_global_symbol (name);
+    char current_tag_name[128];
     
-    if (i < 0 || bytes <= 0) {
-        return;
-    }
+    int current_object_size;
+    unsigned long total_offset = 0;
     
-    if (global_symbols[i].kind != GLOBAL_SYMBOL_FUNCTION || !global_symbols[i].is_dllimport || global_symbols[i].calling_convention != TOK_STDCALL) {
-        return;
+    if (tok.kind != TOK_LPAREN) {
+        return 0;
     }
     
-    if (global_symbol_stdcall_stack_bytes (name) <= 0) {
-        global_symbols[i].import_call_stack_bytes = bytes;
-    }
-
-}
-
-static const char *asm_global_symbol_name (const char *name) {
-
-    static char buffers[8][512];
-    static int index = 0;
+    get_token ();
     
-    char *out, suffix[32];
-    int stdcall_bytes, symbol_index;
+    if (tok.kind != TOK_LPAREN) {
+        return 0;
+    }
     
-    unsigned long avail, len;
+    get_token ();
     
-    if (asm_symbol_is_internal (name)) {
-        return name;
+    if (!parse_cast_type_name (0, 0, 0)) {
+        return 0;
     }
     
-    index = (index + 1) & 7;
+    current_tag_name[0] = '\0';
+    
+    if (last_cast_type_tag_name[0]) {
     
-    out = buffers[index];
-    len = strlen (name);
+        strncpy (current_tag_name, last_cast_type_tag_name, sizeof (current_tag_name) - 1);
+        current_tag_name[sizeof (current_tag_name) - 1] = '\0';
     
-    stdcall_bytes = global_symbol_stdcall_stack_bytes (name);
-    suffix[0] = '\0';
+    }
     
-    symbol_index = find_global_symbol (name);
+    current_object_size = last_cast_type_object_size;
     
-    if (symbol_index >= 0 && global_symbols[symbol_index].kind == GLOBAL_SYMBOL_FUNCTION  && global_symbols[symbol_index].calling_convention == TOK_STDCALL && !global_symbols[symbol_index].is_variadic) {
-        sprintf (suffix, "@%d", stdcall_bytes);
+    if (!((tok.kind == TOK_CINT || tok.kind == TOK_CUINT || tok.kind == TOK_CLONG ||
+           tok.kind == TOK_CULONG || tok.kind == TOK_CLLONG || tok.kind == TOK_CULLONG) &&
+          tok.val.i.low == 0 && tok.val.i.high == 0)) {
+        return 0;
     }
     
-    avail = sizeof (buffers[0]) - 1 - strlen (suffix);
+    get_token ();
+    expect (TOK_RPAREN, ")");
     
-    if (!state->no_leading_underscore) {
+    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
     
-        if (avail > 0) {
-            avail--;
+        enum token_kind member_op = tok.kind;
+        char *member;
+        
+        const char *member_start;
+        const char *member_caret;
+        
+        unsigned long member_line;
+        
+        int offset = 0;
+        int size = DATA_INT & 0x1f;
+        int elem_size = DATA_INT & 0x1f;
+        int pointer_depth = 0;
+        int is_array = 0;
+        
+        get_token ();
+        
+        member_start = tok.start;
+        member_caret = tok.caret;
+        member_line = get_line_number ();
+        
+        if (tok.kind != TOK_IDENT) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret,
+                            "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
+            return 1;
+        
         }
         
-        if (len > avail) {
-            len = avail;
+        member = xstrdup (tok.ident);
+        get_token ();
+        
+        if (!find_member_info_ex_bounded (member, current_object_size,
+                                          current_tag_name[0] ? current_tag_name : 0,
+                                          &offset, &size, &elem_size, &pointer_depth, &is_array, 0)) {
+        
+            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret,
+                            "unknown member '%s'", member);
+            
+            free (member);
+            return 1;
+        
         }
         
-        out[0] = '_';
+        free (member);
+        total_offset += (unsigned long) offset;
+        
+        if (last_found_member_tag_name && last_found_member_tag_name[0]) {
+        
+            strncpy (current_tag_name, last_found_member_tag_name, sizeof (current_tag_name) - 1);
+            current_tag_name[sizeof (current_tag_name) - 1] = '\0';
+        
+        } else {
+            current_tag_name[0] = '\0';
+        }
+        
+        while (tok.kind == TOK_LBRACK) {
+        
+            enum token_kind kill[2];
+            int64_s index;
+            
+            get_token ();
+            
+            kill[0] = TOK_RBRACK;
+            kill[1] = 0;
+            
+            index = expr_const64 (kill);
+            
+            expect (TOK_RBRACK, "]");
+            total_offset += index.low * (unsigned long) (elem_size > 0 ? elem_size : (DATA_INT & 0x1f));
         
-        memcpy (out + 1, name, len);
-        out[len + 1] = 0;
-    
-    } else {
-    
-        if (len > avail) {
-            len = avail;
         }
         
-        memcpy (out, name, len);
-        out[len] = 0;
+        if (pointer_depth > 0) {
+            current_object_size = elem_size > 0 ? elem_size : (DATA_PTR & 0x1f);
+        } else if (is_array && elem_size > 0) {
+            current_object_size = elem_size;
+        } else {
+            current_object_size = size;
+        }
     
     }
     
-    if (suffix[0]) {
-        strcat (out, suffix);
+    expect (TOK_RPAREN, ")");
+    
+    if (out) {
+        zext64 (out, total_offset);
     }
     
-    return out;
+    return 1;
 
 }
 
-static const char *asm_global_import_symbol_name (const char *name) {
+int parsed_string_initializer_elem_size = DATA_CHAR & 0x1f;
 
-    static char buffers[8][512];
-    static int index = 0;
-    
-    const char *decorated;
-    char *out;
-    
-    unsigned long len;
-    
-    if (!(decorated = asm_global_symbol_name (name)) || asm_symbol_is_internal (name)) {
-        return decorated;
-    }
-    
-    index = (index + 1) & 7;
-    
-    out = buffers[index];
-    len = strlen (decorated);
-    
-    if (len > sizeof (buffers[0]) - 7) {
-        len = sizeof (buffers[0]) - 7;
-    }
-    
-    sprintf (out, "__imp_");
-    
-    memcpy (out + 6, decorated, len);
-    out[len + 6] = 0;
-    
-    return out;
-
-}
-
-static int get_global_symbol_kind (const char *name) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        return global_symbols[i].kind;
-    }
-    
-    return 0;
-
-}
-
-static void set_global_symbol_unsigned (const char *name, int is_unsigned) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        global_symbols[i].is_unsigned = is_unsigned ? 1 : 0;
-    }
-
-}
-
-static int get_global_symbol_unsigned (const char *name) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        return global_symbols[i].is_unsigned;
-    }
-    
-    return 0;
-
-}
-
-static void set_global_symbol_dllimport (const char *name, int is_dllimport) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-    
-        global_symbols[i].is_dllimport = is_dllimport ? 1 : 0;
-        
-        if (is_dllimport) {
-            global_symbols[i].is_extern = 1;
-        }
-    
-    }
-
-}
-
-static int get_global_symbol_dllimport (const char *name) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        return global_symbols[i].is_dllimport ? 1 : 0;
-    }
-    
-    return 0;
-
-}
-
-static void set_global_symbol_array (const char *name, int is_array) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        global_symbols[i].is_array = is_array ? 1 : 0;
-    }
-
-}
-
-static int get_global_symbol_array (const char *name) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        return global_symbols[i].is_array;
-    }
-    
-    return 0;
-
-}
-
-static void set_global_symbol_array_count (const char *name, long array_count) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        global_symbols[i].array_count = array_count;
-    }
-
-}
-
-static long get_global_symbol_array_count (const char *name) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        return global_symbols[i].array_count;
-    }
-    
-    return 0;
-
-}
-
-static void set_global_symbol_array_dimensions (const char *name, int dims) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        global_symbols[i].array_dimensions = dims > 0 ? dims : 0;
-    }
-
-}
-
-static int get_global_symbol_array_dimensions (const char *name) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        return global_symbols[i].array_dimensions;
-    }
-    
-    return 0;
-
-}
-
-static void set_global_symbol_array_element_size (const char *name, int elem_size) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        global_symbols[i].array_element_size = elem_size > 0 ? elem_size : 0;
-    }
-
-}
-
-static int get_global_symbol_array_element_size (const char *name) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-    
-        if (global_symbols[i].array_element_size > 0) {
-            return global_symbols[i].array_element_size;
-        }
-        
-        if (global_symbols[i].tag_name && global_symbols[i].tag_name[0]) {
-        
-            struct aggregate_tag_entry *entry = find_aggregate_tag (global_symbols[i].tag_name, 0);
-            
-            if (entry && entry->size > 0) {
-                return entry->size;
-            }
-        
-        }
-    
-    }
-    
-    return 0;
-
-}
-
-static void set_global_symbol_floating (const char *name, int is_floating) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        global_symbols[i].is_floating = is_floating ? 1 : 0;
-    }
-
-}
-
-static int get_global_symbol_floating (const char *name) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        return global_symbols[i].is_floating;
-    }
-    
-    return 0;
-
-}
-
-static int get_global_function_returns_floating (const char *name) {
-
-    int i = find_global_symbol (name);
-    
-    if (i < 0 || global_symbols[i].kind != GLOBAL_SYMBOL_FUNCTION) {
-        return 0;
-    }
-    
-    if (global_symbols[i].is_floating) {
-        return 1;
-    }
-    
-    /*
-     * Do not infer floating return types from the masked object size.
-     *
-     * DATA_INT and DATA_FLOAT both have a 4-byte payload size, so checking
-     * only (size & 0x1f) makes every int-returning function look like it
-     * returns float.  That breaks expressions such as:
-     *
-     *     printf("%p", main);
-     *
-     * because the function designator gets loaded as a floating object from
-     * memory instead of as a plain code address.  The declaration/definition
-     * paths already record real floating function returns in is_floating.
-     */
-    return global_symbols[i].is_floating ? 1 : 0;
-
-}
-
-static void set_global_symbol_pointer_info (const char *name, int pointer_depth, int pointed_size) {
-
-    int i = find_global_symbol (name);
-    
-    if (pointer_depth > 0 && parsed_type_is_aggregate && parsed_type_size > (DATA_PTR & 0x1f) && pointed_size <= (DATA_PTR & 0x1f)) {
-        pointed_size = parsed_type_size;
-    }
-    
-    if (i >= 0) {
-    
-        global_symbols[i].pointer_depth = pointer_depth;
-        global_symbols[i].pointed_size = pointed_size;
-        
-        global_symbols[i].pointed_is_floating = pointer_depth > 0 ? (parsed_type_is_floating ? 1 : 0) : 0;
-        global_symbols[i].pointed_is_unsigned = pointer_depth > 0 ? (parsed_type_is_unsigned ? 1 : 0) : 0;
-    
-    }
-
-}
-
-static int get_global_symbol_pointer_depth (const char *name) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        return global_symbols[i].pointer_depth;
-    }
-    
-    return 0;
-
-}
-
-static int get_global_symbol_pointed_size (const char *name) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0 && global_symbols[i].pointed_size > 0) {
-        return global_symbols[i].pointed_size;
-    }
-    
-    return DATA_INT & 0x1f;
-
-}
-
-static int get_global_symbol_pointed_is_floating (const char *name) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        return global_symbols[i].pointed_is_floating;
-    }
-    
-    return 0;
-
-}
-
-static int get_global_symbol_pointed_is_unsigned (const char *name) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        return global_symbols[i].pointed_is_unsigned;
-    }
-    
-    return 0;
-
-}
-
-static void set_global_symbol_tag_name (const char *name, const char *tag_name) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-    
-        if (global_symbols[i].tag_name) {
-        
-            free (global_symbols[i].tag_name);
-            global_symbols[i].tag_name = 0;
-        
-        }
-        
-        if (tag_name && tag_name[0]) {
-            global_symbols[i].tag_name = xstrdup (tag_name);
-        }
-    
-    }
-
-}
-
-static const char *get_global_symbol_tag_name (const char *name) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        return global_symbols[i].tag_name;
-    }
-    
-    return 0;
-
-}
-
-static void set_global_symbol_returns_void (const char *name, int returns_void) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        global_symbols[i].returns_void = returns_void ? 1 : 0;
-    }
-
-}
-
-static void set_global_symbol_calling_convention (const char *name, enum token_kind calling_convention) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        global_symbols[i].calling_convention = calling_convention;
-    }
-
-}
-
-static enum token_kind get_global_symbol_calling_convention (const char *name) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        return global_symbols[i].calling_convention;
-    }
-    
-    return TOK_EOF;
-
-}
-
-static int get_global_symbol_returns_void (const char *name) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        return global_symbols[i].returns_void;
-    }
-    
-    return 0;
-
-}
-
-static void set_global_symbol_param_count (const char *name, int param_count, int has_prototype, int is_variadic) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-    
-        global_symbols[i].param_count = param_count < 0 ? 0 : param_count;
-        global_symbols[i].has_prototype = has_prototype ? 1 : 0;
-        global_symbols[i].is_variadic = is_variadic ? 1 : 0;
-    
-    }
-
-}
-
-static int get_global_symbol_has_prototype (const char *name) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        return global_symbols[i].has_prototype;
-    }
-    
-    return 0;
-
-}
-
-static int get_global_symbol_is_variadic (const char *name) {
-
-    int i = find_global_symbol (name);
-
-    if (i >= 0) {
-        return global_symbols[i].is_variadic;
-    }
-
-    return 0;
-
-}
-
-static int get_global_symbol_param_count (const char *name) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        return global_symbols[i].param_count;
-    }
-    
-    return 0;
-
-}
-
-static int get_global_symbol_param_size (const char *name, int param_index) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0 && param_index >= 0 && param_index < 128 && global_symbols[i].param_sizes[param_index] > 0) {
-        return global_symbols[i].param_sizes[param_index];
-    }
-    
-    return DATA_PTR & 0x1f;
-
-}
-
-static int get_global_symbol_param_unsigned (const char *name, int param_index) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0 && param_index >= 0 && param_index < 128) {
-        return global_symbols[i].param_unsigneds[param_index] ? 1 : 0;
-    }
-    
-    return 0;
-
-}
-
-static int get_global_symbol_param_floating (const char *name, int param_index) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0 && param_index >= 0 && param_index < 128) {
-        return global_symbols[i].param_floatings[param_index] ? 1 : 0;
-    }
-    
-    return 0;
-
-}
-
-static void set_global_symbol_size (const char *name, int size) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        global_symbols[i].size = size;
-    }
-
-}
-
-static int get_global_symbol_size (const char *name) {
-
-    int i = find_global_symbol (name);
-    
-    if (i >= 0 && global_symbols[i].size > 0) {
-        return global_symbols[i].size;
-    }
-    
-    return DATA_INT & 0x1f;
-
-}
-
-static int add_global_symbol (const char *name, int kind, int is_extern, const char *line_start, const char *name_caret, unsigned long lineno) {
-
-    int old;
-    
-    if (!name || !*name) {
-        return 0;
-    }
-    
-    if (!line_start) {
-        line_start = tok.start;
-    }
-
-    if (!name_caret) {
-        name_caret = tok.caret;
-    }
-
-    if (lineno == 0) {
-        lineno = get_line_number ();
-    }
-    
-    old = find_global_symbol (name);
-    
-    if (old >= 0) {
-    
-        if (global_symbols[old].is_implicit) {
-        
-            global_symbols[old].is_extern = is_extern ? 1 : 0;
-            global_symbols[old].is_implicit = 0;
-            
-            global_symbols[old].kind = kind;
-            return 1;
-        
-        }
-        
-        if (is_extern) {
-            return 0;
-        }
-        
-        if (global_symbols[old].is_extern) {
-        
-            global_symbols[old].kind = kind;
-            global_symbols[old].is_extern = 0;
-            
-            return 1;
-        
-        }
-        
-        report_line_at (get_filename (), lineno, REPORT_ERROR, line_start, name_caret, "duplicate symbol '%s'", name);
-        return 0;
-    
-    }
-    
-    if (global_symbol_count >= MAX_GLOBAL_SYMBOLS) {
-    
-        report_line_at (get_filename (), lineno, REPORT_ERROR, line_start, name_caret, "too many global symbols");
-        return 0;
-    
-    }
-    
-    global_symbols[global_symbol_count].name = xstrdup (name);
-    global_symbols[global_symbol_count].kind = kind;
-    global_symbols[global_symbol_count].is_extern = is_extern;
-    global_symbols[global_symbol_count].is_dllimport = 0;
-    global_symbols[global_symbol_count].is_unsigned = 0;
-    global_symbols[global_symbol_count].is_floating = 0;
-    global_symbols[global_symbol_count].is_array = 0;
-    global_symbols[global_symbol_count].pointer_depth = 0;
-    global_symbols[global_symbol_count].pointed_size = 0;
-    global_symbols[global_symbol_count].pointed_is_floating = 0;
-    global_symbols[global_symbol_count].pointed_is_unsigned = 0;
-    global_symbols[global_symbol_count].returns_void = 0;
-    global_symbols[global_symbol_count].calling_convention = TOK_EOF;
-    
-    {
-    
-        int pi;
-        
-        for (pi = 0; pi < 128; pi++) {
-        
-            global_symbols[global_symbol_count].param_sizes[pi] = 0;
-            global_symbols[global_symbol_count].param_unsigneds[pi] = 0;
-            global_symbols[global_symbol_count].param_floatings[pi] = 0;
-        
-        }
-    
-    }
-    
-    global_symbols[global_symbol_count].import_call_stack_bytes = 0;
-    global_symbols[global_symbol_count].param_count = 0;
-    global_symbols[global_symbol_count].has_prototype = 0;
-    global_symbols[global_symbol_count].is_variadic = 0;
-    global_symbols[global_symbol_count].is_implicit = 0;
-    global_symbols[global_symbol_count].extern_emitted = 0;
-    global_symbols[global_symbol_count].tag_name = 0;
-    
-    global_symbol_count++;
-    return 1;
-
-}
-
-static void ensure_global_function_symbol (const char *name, const char *line_start, const char *name_caret, unsigned long lineno) {
-
-    int i;
-    
-    if (!name || !*name) {
-        return;
-    }
-    
-    i = find_global_symbol (name);
-    
-    if (i >= 0) {
-        return;
-    }
-    
-    report_line_at (get_filename (), lineno, REPORT_WARNING, line_start, name_caret, "implicit declaration of function '%s'", name);
-    
-    if (add_global_symbol (name, GLOBAL_SYMBOL_FUNCTION, 1, line_start, name_caret, lineno)) {
-    
-        i = find_global_symbol (name);
-        
-        if (i >= 0) {
-        
-            global_symbols[i].calling_convention = TOK_EOF;
-            global_symbols[i].size = DATA_INT & 0x1f;
-            global_symbols[i].is_unsigned = 0;
-            global_symbols[i].is_floating = 0;
-            global_symbols[i].returns_void = 0;
-            global_symbols[i].param_count = 0;
-            global_symbols[i].has_prototype = 0;
-            global_symbols[i].is_variadic = 0;
-            global_symbols[i].is_implicit = 1;
-        
-        }
-    
-    }
-
-}
-
-#define     MAX_INLINE_FUNCTIONS        256
-
-struct inline_function_entry {
-
-    char *name;
-    char *body;
-    char *data;
-    
-    int param_count;
-    int has_prototype;
-    int returns_void;
-    int is_floating;
-    int return_size;
-    int return_label;
-    int data_emitted;
-    int expanding;
-
-    int usable;
-
-};
-
-static struct inline_function_entry inline_functions[MAX_INLINE_FUNCTIONS];
-static int inline_function_count = 0;
-
-static void clear_inline_functions (void) {
-
-    int i;
-    
-    for (i = 0; i < inline_function_count; i++) {
-    
-        free (inline_functions[i].name);
-        free (inline_functions[i].body);
-        free (inline_functions[i].data);
-        
-        inline_functions[i].name = 0;
-        inline_functions[i].body = 0;
-        inline_functions[i].data = 0;
-        inline_functions[i].param_count = 0;
-        inline_functions[i].has_prototype = 0;
-        inline_functions[i].returns_void = 0;
-        inline_functions[i].is_floating = 0;
-        inline_functions[i].return_size = 0;
-        inline_functions[i].return_label = 0;
-        inline_functions[i].data_emitted = 0;
-        inline_functions[i].expanding = 0;
-        inline_functions[i].usable = 0;
-    
-    }
-    
-    inline_function_count = 0;
-
-}
-
-static int find_inline_function (const char *name) {
-
-    int i;
-    
-    if (!name) {
-        return -1;
-    }
-    
-    for (i = 0; i < inline_function_count; i++) {
-    
-        if (strcmp (inline_functions[i].name, name) == 0) {
-            return i;
-        }
-    
-    }
-    
-    return -1;
-
-}
-
-static void remember_inline_function_signature (const char *name, int param_count, int has_prototype, int returns_void, int is_floating, int return_size) {
-
-    int i;
-    
-    if (!name || !*name) {
-        return;
-    }
-    
-    i = find_inline_function (name);
-    
-    if (i < 0) {
-    
-        if (inline_function_count >= MAX_INLINE_FUNCTIONS) {
-            return;
-        }
-        
-        i = inline_function_count++;
-        inline_functions[i].name = xstrdup (name);
-        inline_functions[i].body = 0;
-        inline_functions[i].data = 0;
-        inline_functions[i].data_emitted = 0;
-        inline_functions[i].expanding = 0;
-    
-    }
-    
-    inline_functions[i].param_count = param_count < 0 ? 0 : param_count;
-    inline_functions[i].has_prototype = has_prototype ? 1 : 0;
-    inline_functions[i].returns_void = returns_void ? 1 : 0;
-    inline_functions[i].is_floating = is_floating ? 1 : 0;
-    inline_functions[i].return_size = return_size;
-    inline_functions[i].return_label = 0;
-    inline_functions[i].data_emitted = 0;
-    inline_functions[i].expanding = 0;
-    inline_functions[i].usable = 0;
-
-}
-
-static int inline_asm_body_is_safe (const char *body) {
-
-    const char *p = body;
-    
-    if (!body) {
-        return 0;
-    }
-    
-    while (*p) {
-    
-        const char *line = p;
-        const char *eol = strchr (p, '\n');
-        
-        size_t len = eol ? (size_t) (eol - line) : strlen (line);
-        
-        while (len > 0 && (line[len - 1] == '\r' || line[len - 1] == '\n')) {
-            len--;
-        }
-        
-        while (len > 0 && (*line == ' ' || *line == '\t')) {
-        
-            line++;
-            len--;
-        
-        }
-        
-        if (len >= 4 && strncmp (line, "ret", 3) == 0) {
-            return 0;
-        }
-        
-        if (len >= 5 && strncmp (line, "leave", 5) == 0) {
-            return 0;
-        }
-        
-        if (len > 0 && line[0] == '.' && !(len >= 3 && line[1] == 'L' && line[2] >= '0' && line[2] <= '9')) {
-        
-            if (!((len == 5 && strncmp (line, ".data", 5) == 0) ||
-                  (len == 6 && strncmp (line, ".data?", 6) == 0) ||
-                  (len == 5 && strncmp (line, ".code", 5) == 0) ||
-                  (len == 5 && strncmp (line, ".text", 5) == 0) ||
-                  (len == 4 && strncmp (line, ".bss", 4) == 0))) {
-            
-                return 0;
-            
-            }
-        
-        }
-        
-        if (len >= 6 && strncmp (line, "public", 6) == 0) {
-            return 0;
-        }
-        
-        if (!eol) {
-            break;
-        }
-        
-        p = eol + 1;
-    
-    }
-    
-    return 1;
-
-}
-
-static char *extract_inline_asm_body (const char *asm_text, int return_label) {
-
-    char marker[64];
-    char *body;
-    
-    const char *start, *end;
-    size_t len;
-    
-    if (!asm_text) {
-        return 0;
-    }
-    
-    start = strstr (asm_text, "    mov ebp, esp\n");
-    
-    if (start) {
-        start += strlen ("    mov ebp, esp\n");
-    } else {
-    
-        start = strstr (asm_text, "    movl %esp, %ebp\n");
-        
-        if (start) {
-            start += strlen ("    movl %esp, %ebp\n");
-        }
-    
-    }
-    
-    if (!start) {
-        return 0;
-    }
-    
-    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
-        sprintf (marker, "\nL%d:\n", return_label);
-    } else {
-        sprintf (marker, "\n.L%d:\n", return_label);
-    }
-    
-    end = strstr (start, marker);
-    
-    if (!end) {
-
-        if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
-            sprintf (marker, "L%d:\n", return_label);
-        } else {
-            sprintf (marker, ".L%d:\n", return_label);
-        }
-
-        if (strncmp (start, marker, strlen (marker)) == 0) {
-            end = start;
-        } else {
-            return 0;
-        }
-
-    }
-    
-    if (*start == '\n') {
-        start++;
-    }
-    
-    len = (size_t) (end - start);
-    
-    while (len > 0 && (start[len - 1] == '\r' || start[len - 1] == '\n')) {
-        len--;
-    }
-    
-    body = xmalloc (len + 2);
-    memcpy (body, start, len);
-    
-    body[len++] = '\n';
-    body[len] = 0;
-    
-    if (!inline_asm_body_is_safe (body)) {
-    
-        free (body);
-        return 0;
-    
-    }
-    
-    return body;
-
-}
-
-static char *read_tmp_file_text (FILE *fp) {
-
-    long len;
-    char *text;
-    
-    if (!fp) {
-        return 0;
-    }
-    
-    fflush (fp);
-    
-    if (fseek (fp, 0, SEEK_END) != 0) {
-        return 0;
-    }
-    
-    len = ftell (fp);
-    
-    if (len < 0) {
-        return 0;
-    }
-    
-    if (fseek (fp, 0, SEEK_SET) != 0) {
-        return 0;
-    }
-    
-    text = xmalloc ((size_t) len + 1);
-    
-    if (len > 0 && fread (text, 1, (size_t) len, fp) != (size_t) len) {
-        free (text);
-        return 0;
-    }
-    
-    text[len] = 0;
-    return text;
-
-}
-
-static void append_inline_text (char **dst, const char *start, size_t len);
-
-static long function_frame_saved_assignment64_bytes (void) {
-    return current_function_preserve_assignment64_regs ? 12 : 0;
-}
-
-static void emit_function_frame_adjust_text (char **dst, long frame_size) {
-
-    char buf[128];
-    long save_bytes;
-    
-    int n;
-    
-    if (!dst) {
-        return;
-    }
-    
-    frame_size = (frame_size + 3) & ~3L;
-    save_bytes = function_frame_saved_assignment64_bytes ();
-    
-    if (frame_size <= 0 && save_bytes <= 0) {
-        return;
-    }
-    
-    if (frame_size > 2147483647L) {
-        frame_size = 2147483647L;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (frame_size > 0) {
-        
-            n = sprintf (buf, "    sub esp, %ld\n", frame_size);
-            append_inline_text (dst, buf, (size_t) n);
-        
-        }
-        
-        if (save_bytes) {
-        
-            append_inline_text (dst, "    push ebx\n", strlen ("    push ebx\n"));
-            append_inline_text (dst, "    push esi\n", strlen ("    push esi\n"));
-            append_inline_text (dst, "    push edi\n", strlen ("    push edi\n"));
-        
-        }
-    
-    } else {
-    
-        if (frame_size > 0) {
-        
-            n = sprintf (buf, "    subl $%ld, %%esp\n", frame_size);
-            append_inline_text (dst, buf, (size_t) n);
-        
-        }
-        
-        if (save_bytes) {
-        
-            append_inline_text (dst, "    pushl %ebx\n", strlen ("    pushl %ebx\n"));
-            append_inline_text (dst, "    pushl %esi\n", strlen ("    pushl %esi\n"));
-            append_inline_text (dst, "    pushl %edi\n", strlen ("    pushl %edi\n"));
-        
-        }
-    
-    }
-
-}
-
-static void emit_function_frame_restore_text (char **dst, long frame_size) {
-
-    if (!dst || !function_frame_saved_assignment64_bytes ()) {
-        return;
-    }
-    
-    (void) frame_size;
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        append_inline_text (dst, "    pop edi\n", strlen ("    pop edi\n"));
-        append_inline_text (dst, "    pop esi\n", strlen ("    pop esi\n"));
-        append_inline_text (dst, "    pop ebx\n", strlen ("    pop ebx\n"));
-    
-    } else {
-    
-        append_inline_text (dst, "    popl %edi\n", strlen ("    popl %edi\n"));
-        append_inline_text (dst, "    popl %esi\n", strlen ("    popl %esi\n"));
-        append_inline_text (dst, "    popl %ebx\n", strlen ("    popl %ebx\n"));
-    
-    }
-
-}
-
-static char *replace_function_frame_placeholder (const char *text, long frame_size) {
-
-    const char *frame_marker = "__SCC_FRAME_PLACEHOLDER__\n";
-    const char *restore_marker = "__SCC_RESTORE_ASSIGNMENT64_REGS__\n";
-    
-    const char *pr, *pf, *p;
-    const char *marker, *last;
-    
-    char *out = 0;
-    size_t marker_len;
-    
-    if (!text) {
-        return 0;
-    }
-    
-    last = text;
-    
-    for (;;) {
-    
-        pf = strstr (last, frame_marker);
-        pr = strstr (last, restore_marker);
-        
-        if (!pf && !pr) {
-            break;
-        }
-        
-        if (pf && (!pr || pf < pr)) {
-            p = pf;
-            marker = frame_marker;
-        } else {
-            p = pr;
-            marker = restore_marker;
-        }
-        
-        marker_len = strlen (marker);
-        append_inline_text (&out, last, (size_t) (p - last));
-        
-        if (marker == frame_marker) {
-            emit_function_frame_adjust_text (&out, frame_size);
-        } else {
-            emit_function_frame_restore_text (&out, frame_size);
-        }
-        
-        last = p + marker_len;
-    
-    }
-    
-    append_inline_text (&out, last, strlen (last));
-    return out;
-
-}
-
-static void append_inline_text (char **dst, const char *start, size_t len) {
-
-    size_t old_len = 0;
-    char *out;
-    
-    if (!dst || !start || len == 0) {
-        return;
-    }
-    
-    if (*dst) {
-        old_len = strlen (*dst);
-    }
-    
-    out = xmalloc (old_len + len + 1);
-    
-    if (old_len) {
-        memcpy (out, *dst, old_len);
-        free (*dst);
-    }
-    
-    memcpy (out + old_len, start, len);
-    out[old_len + len] = 0;
-    *dst = out;
-
-}
-
-static void split_inline_asm_sections (char **bodyp, char **datap) {
-
-    const char *p;
-    
-    char *body = 0;
-    char *data = 0;
-    
-    int in_data = 0;
-    
-    if (!bodyp || !*bodyp) {
-        return;
-    }
-    
-    p = *bodyp;
-    
-    while (*p) {
-    
-        const char *line = p;
-        const char *eol = strchr (p, '\n');
-        const char *next = eol ? eol + 1 : p + strlen (p);
-        
-        size_t len = (size_t) (next - line);
-        
-        const char *trim = line;
-        size_t tlen = eol ? (size_t) (eol - line) : strlen (line);
-        
-        while (tlen > 0 && (trim[tlen - 1] == '\r' || trim[tlen - 1] == '\n')) {
-            tlen--;
-        }
-        
-        while (tlen > 0 && (*trim == ' ' || *trim == '\t')) {
-        
-            trim++;
-            tlen--;
-        
-        }
-        
-        if ((tlen == 5 && strncmp (trim, ".data", 5) == 0) ||
-            (tlen == 6 && strncmp (trim, ".data?", 6) == 0) ||
-            (tlen == 4 && strncmp (trim, ".bss", 4) == 0)) {
-        
-            in_data = 1;
-            append_inline_text (&data, line, len);
-        
-        } else if ((tlen == 5 && strncmp (trim, ".code", 5) == 0) ||
-                   (tlen == 5 && strncmp (trim, ".text", 5) == 0)) {
-            in_data = 0;
-        } else if (in_data) {
-            append_inline_text (&data, line, len);
-        } else {
-            append_inline_text (&body, line, len);
-        }
-        
-        p = next;
-    
-    }
-    
-    free (*bodyp);
-    
-    *bodyp = body;
-    *datap = data;
-
-}
-
-static void remember_inline_function (const char *name, const char *asm_text, int return_label, int param_count, int has_prototype, int returns_void, int is_floating, int return_size) {
-
-    char *body;
-    char *data = 0;
-    
-    int i;
-    
-    if (!name || !*name || !asm_text) {
-        return;
-    }
-    
-    body = extract_inline_asm_body (asm_text, return_label);
-    
-    if (!body) {
-        return;
-    }
-    
-    split_inline_asm_sections (&body, &data);
-    i = find_inline_function (name);
-    
-    if (i < 0) {
-    
-        if (inline_function_count >= MAX_INLINE_FUNCTIONS) {
-        
-            free (body);
-            free (data);
-            
-            return;
-        
-        }
-        
-        i = inline_function_count++;
-        
-        inline_functions[i].name = xstrdup (name);
-        inline_functions[i].body = 0;
-        inline_functions[i].data = 0;
-        inline_functions[i].data_emitted = 0;
-        inline_functions[i].expanding = 0;
-    
-    }
-    
-    free (inline_functions[i].body);
-    free (inline_functions[i].data);
-    
-    inline_functions[i].body = body;
-    inline_functions[i].data = data;
-    inline_functions[i].data_emitted = 0;
-    inline_functions[i].param_count = param_count;
-    inline_functions[i].has_prototype = has_prototype ? 1 : 0;
-    inline_functions[i].returns_void = returns_void ? 1 : 0;
-    inline_functions[i].is_floating = is_floating ? 1 : 0;
-    inline_functions[i].return_size = return_size;
-    inline_functions[i].return_label = return_label;
-    inline_functions[i].expanding = 0;
-    inline_functions[i].usable = 1;
-
-}
-
-static void emit_inline_label_reference (int label, int return_label, int call_id) {
-
-    if (label == return_label) {
-    
-        if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
-            fprintf (state->ofp, "L%d", call_id);
-        } else {
-            fprintf (state->ofp, ".L%d", call_id);
-        }
-    
-    } else {
-    
-        if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
-            fprintf (state->ofp, "L%d_%d", label, call_id);
-        } else {
-            fprintf (state->ofp, ".L%d_%d", label, call_id);
-        }
-    
-    }
-
-}
-
-static int emit_inline_parameter_reference_if_any (const char **pp, int argc, int stack_bytes) {
-
-    const char *p = *pp;
-    const char *q;
-    
-    int offset = 0;
-    int param_index;
-    int stack_offset;
-    
-    if (!(state->syntax & ASM_SYNTAX_MASM)) {
-        return 0;
-    }
-    
-    if (*p != '[') {
-        return 0;
-    }
-    
-    q = p + 1;
-    
-    while (*q == ' ' || *q == '\t') {
-        q++;
-    }
-    
-    if (strncmp (q, "ebp", 3) != 0) {
-        return 0;
-    }
-    
-    q += 3;
-    
-    while (*q == ' ' || *q == '\t') {
-        q++;
-    }
-    
-    if (*q != '+') {
-        return 0;
-    }
-    
-    q++;
-    
-    while (*q == ' ' || *q == '\t') {
-        q++;
-    }
-    
-    if (*q < '0' || *q > '9') {
-        return 0;
-    }
-    
-    while (*q >= '0' && *q <= '9') {
-    
-        offset = (offset * 10) + (*q - '0');
-        q++;
-    
-    }
-    
-    while (*q == ' ' || *q == '\t') {
-        q++;
-    }
-    
-    if (*q != ']') {
-        return 0;
-    }
-    
-    if (offset < 8 || ((offset - 8) % 4) != 0) {
-        return 0;
-    }
-    
-    param_index = (offset - 8) / 4;
-    
-    if (param_index < 0 || param_index >= argc) {
-        return 0;
-    }
-    
-    /*
-     * Inline arguments are copied into a compiler-owned temporary stack
-     * area before the inline body is emitted.  Parameter 0 lives at the
-     * lowest address in that area, so [ebp + 8] maps to [esp],
-     * [ebp + 12] maps to [esp + 4], [ebp + 16] maps to [esp + 8], etc.
-     * If the inlined body changes ESP temporarily, stack_bytes keeps all
-     * parameter references pointed at the same argument copies.
-     */
-    stack_offset = stack_bytes + (param_index * 4);
-    
-    if (stack_offset == 0) {
-        fprintf (state->ofp, "[esp]");
-    } else if (stack_offset > 0) {
-        fprintf (state->ofp, "[esp + %d]", stack_offset);
-    } else {
-        fprintf (state->ofp, "[esp - %d]", -stack_offset);
-    }
-    
-    *pp = q + 1;
-    return 1;
-
-}
-
-static void emit_inline_line_substituted (const char *line, size_t len, int return_label, int call_id, int argc, int stack_bytes) {
-
-    const char *p = line;
-    const char *end = line + len;
-    
-    while (p < end) {
-    
-        if ((state->syntax & ASM_SYNTAX_MASM) && *p == 'L' && p + 1 < end && p[1] >= '0' && p[1] <= '9') {
-        
-            const char *q = p + 1;
-            int label = 0;
-            
-            while (q < end && *q >= '0' && *q <= '9') {
-            
-                label = (label * 10) + (*q - '0');
-                q++;
-            
-            }
-            
-            emit_inline_label_reference (label, return_label, call_id);
-            p = q;
-            
-            continue;
-        
-        }
-        
-        if (!(state->syntax & ASM_SYNTAX_MASM) && p + 2 < end && p[0] == '.' && p[1] == 'L' && p[2] >= '0' && p[2] <= '9') {
-        
-            const char *q = p + 2;
-            int label = 0;
-            
-            while (q < end && *q >= '0' && *q <= '9') {
-            
-                label = (label * 10) + (*q - '0');
-                q++;
-            
-            }
-            
-            emit_inline_label_reference (label, return_label, call_id);
-            p = q;
-            
-            continue;
-        
-        }
-        
-        if (emit_inline_parameter_reference_if_any (&p, argc, stack_bytes)) {
-            continue;
-        }
-        
-        fputc (*p++, state->ofp);
-    
-    }
-
-}
-
-static int inline_line_stack_delta (const char *line, size_t len) {
-
-    const char *p = line;
-    long n = 0;
-    int neg = 0;
-    
-    while (len > 0 && (*p == ' ' || *p == '\t')) {
-    
-        p++;
-        len--;
-    
-    }
-    
-    while (len > 0 && (p[len - 1] == '\r' || p[len - 1] == '\n' || p[len - 1] == ' ' || p[len - 1] == '\t')) {
-        len--;
-    }
-    
-    if (len >= 4 && strncmp (p, "push", 4) == 0 && (p[4] == ' ' || p[4] == '\t')) {
-        return 4;
-    }
-    
-    if (len >= 3 && strncmp (p, "pop", 3) == 0 && (p[3] == ' ' || p[3] == '\t')) {
-        return -4;
-    }
-    
-    if (len >= 8 && (strncmp (p, "sub esp,", 8) == 0 || strncmp (p, "add esp,", 8) == 0)) {
-    
-        neg = (p[0] == 'a');
-        
-        p += 8;
-        len -= 8;
-        
-        while (len > 0 && (*p == ' ' || *p == '\t')) {
-        
-            p++;
-            len--;
-        
-        }
-        
-        while (len > 0 && *p >= '0' && *p <= '9') {
-        
-            n = (n * 10) + (*p - '0');
-            
-            p++;
-            len--;
-        
-        }
-        
-        return neg ? -(int) n : (int) n;
-    
-    }
-    
-    if (len >= 10 && (strncmp (p, "subl $", 6) == 0 || strncmp (p, "addl $", 6) == 0)) {
-    
-        neg = (p[0] == 'a');
-        
-        p += 6;
-        len -= 6;
-        
-        while (len > 0 && *p >= '0' && *p <= '9') {
-        
-            n = (n * 10) + (*p - '0');
-            
-            p++;
-            len--;
-        
-        }
-        
-        while (len > 0 && (*p == ' ' || *p == '\t')) {
-        
-            p++;
-            len--;
-        
-        }
-        
-        if (len >= 6 && strncmp (p, ", %esp", 6) == 0) {
-            return neg ? -(int) n : (int) n;
-        }
-    
-    }
-    
-    return 0;
-
-}
-
-static int inline_body_stack_delta (const char *body) {
-
-    const char *p = body;
-    int stack_bytes = 0;
-    
-    if (!body) {
-        return 0;
-    }
-    
-    while (*p) {
-    
-        const char *line = p;
-        const char *eol = strchr (p, '\n');
-        const char *next = eol ? eol + 1 : p + strlen (p);
-        size_t len = (size_t) (next - line);
-        
-        stack_bytes += inline_line_stack_delta (line, len);
-        p = next;
-    
-    }
-    
-    return stack_bytes;
-
-}
-
-static int inline_parse_mov_eax_imm (const char *line, long *value) {
-
-    const char *p = line;
-    
-    int neg = 0;
-    long v = 0;
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (strncmp (p, "mov eax,", 8) != 0) {
-        return 0;
-    }
-    
-    p += 8;
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (*p == '-') {
-    
-        neg = 1;
-        p++;
-    
-    }
-    
-    if (*p < '0' || *p > '9') {
-        return 0;
-    }
-    
-    while (*p >= '0' && *p <= '9') {
-    
-        v = (v * 10) + (*p - '0');
-        p++;
-    
-    }
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (*p != '\0') {
-        return 0;
-    }
-    
-    *value = neg ? -v : v;
-    return 1;
-
-}
-
-static int inline_parse_mov_edx_imm (const char *line, long *value) {
-
-    const char *p = line;
-    
-    int neg = 0;
-    long v = 0;
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (strncmp (p, "mov edx,", 8) != 0) {
-        return 0;
-    }
-    
-    p += 8;
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (*p == '-') {
-    
-        neg = 1;
-        p++;
-    
-    }
-    
-    if (*p < '0' || *p > '9') {
-        return 0;
-    }
-    
-    while (*p >= '0' && *p <= '9') {
-    
-        v = (v * 10) + (*p - '0');
-        p++;
-    
-    }
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (*p != '\0') {
-        return 0;
-    }
-    
-    *value = neg ? -v : v;
-    return 1;
-
-}
-
-static int inline_line_is_exact (const char *line, const char *text) {
-
-    const char *p = line;
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (strncmp (p, text, strlen (text)) != 0) {
-        return 0;
-    }
-    
-    p += strlen (text);
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    return *p == '\0';
-
-}
-
-
-static int inline_parse_jump_label (const char *line, const char *op, char *label, size_t label_size);
-
-static unsigned long inline_u32 (long v) {
-    return ((unsigned long) v) & 0xffffffffUL;
-}
-
-static long inline_s32 (long v) {
-
-    unsigned long u = inline_u32 (v);
-    
-    if (u & 0x80000000UL) {
-        return -((long) ((~u + 1UL) & 0xffffffffUL));
-    }
-    
-    return (long) u;
-
-}
-
-static int inline_fold_binary_eax_edx (const char *line, long lhs, long rhs, long *out) {
-
-    unsigned long ulhs;
-    unsigned long urhs;
-    unsigned long ures;
-    
-    if (!line || !out) {
-        return 0;
-    }
-    
-    ulhs = inline_u32 (lhs);
-    urhs = inline_u32 (rhs);
-    
-    if (inline_line_is_exact (line, "add eax, edx")) {
-        ures = ulhs + urhs;
-    } else if (inline_line_is_exact (line, "sub eax, edx")) {
-        ures = ulhs - urhs;
-    } else if (inline_line_is_exact (line, "imul eax, edx")) {
-        ures = (unsigned long) (inline_s32 (lhs) * inline_s32 (rhs));
-    } else if (inline_line_is_exact (line, "and eax, edx")) {
-        ures = ulhs & urhs;
-    } else if (inline_line_is_exact (line, "or eax, edx")) {
-        ures = ulhs | urhs;
-    } else if (inline_line_is_exact (line, "xor eax, edx")) {
-        ures = ulhs ^ urhs;
-    } else {
-        return 0;
-    }
-    
-    *out = inline_s32 ((long) ures);
-    return 1;
-
-}
-
-static int inline_fold_shift_eax_edx (const char *line, long lhs, long rhs, long *out) {
-
-    unsigned long ulhs;
-    unsigned long ures;
-    unsigned int count;
-    
-    long slhs;
-    
-    if (!line || !out) {
-        return 0;
-    }
-    
-    count = (unsigned int) (inline_u32 (rhs) & 31UL);
-    ulhs = inline_u32 (lhs);
-    
-    if (inline_line_is_exact (line, "shl eax, cl")) {
-        ures = ulhs << count;
-    } else if (inline_line_is_exact (line, "sal eax, cl")) {
-        ures = ulhs << count;
-    } else if (inline_line_is_exact (line, "sar eax, cl")) {
-    
-        slhs = inline_s32 (lhs);
-        ures = inline_u32 (slhs >> count);
-    
-    } else if (inline_line_is_exact (line, "shr eax, cl")) {
-        ures = ulhs >> count;
-    } else {
-        return 0;
-    }
-    
-    *out = inline_s32 ((long) ures);
-    return 1;
-
-}
-
-static int inline_fold_div_eax_edx (long lhs, long rhs, long *out) {
-
-    long slhs;
-    long srhs;
-    
-    if (!out) {
-        return 0;
-    }
-    
-    srhs = inline_s32 (rhs);
-    
-    if (srhs == 0) {
-        return 0;
-    }
-    
-    slhs = inline_s32 (lhs);
-    
-    *out = inline_s32 (slhs / srhs);
-    return 1;
-
-}
-
-static int inline_fold_mod_eax_edx (long lhs, long rhs, long *out) {
-
-    long slhs;
-    long srhs;
-    
-    if (!out) {
-        return 0;
-    }
-    
-    srhs = inline_s32 (rhs);
-    
-    if (srhs == 0) {
-        return 0;
-    }
-    
-    slhs = inline_s32 (lhs);
-    
-    *out = inline_s32 (slhs % srhs);
-    return 1;
-
-}
-
-static int inline_parse_cond_jump_label (const char *line, char *op, size_t op_size, char *label, size_t label_size) {
-
-    static const char *const ops[] = {
-        "jz", "jnz", "je", "jne", "ja", "jae", "jb", "jbe",
-        "jg", "jge", "jl", "jle", "js", "jns", 0
-    };
-    
-    int i;
-    
-    if (!op || op_size == 0) {
-        return 0;
-    }
-    
-    for (i = 0; ops[i]; i++) {
-    
-        if (inline_parse_jump_label (line, ops[i], label, label_size)) {
-        
-            strncpy (op, ops[i], op_size - 1);
-            op[op_size - 1] = '\0';
-            
-            return 1;
-        
-        }
-    
-    }
-    
-    return 0;
-
-}
-
-static int inline_eval_test_jump (const char *op, long value) {
-
-    long svalue = inline_s32 (value);
-    
-    if (strcmp (op, "jz") == 0 || strcmp (op, "je") == 0) {
-        return svalue == 0;
-    }
-    
-    if (strcmp (op, "jnz") == 0 || strcmp (op, "jne") == 0) {
-        return svalue != 0;
-    }
-    
-    if (strcmp (op, "js") == 0) {
-        return svalue < 0;
-    }
-    
-    if (strcmp (op, "jns") == 0) {
-        return svalue >= 0;
-    }
-    
-    return 0;
-
-}
-
-static int inline_eval_cmp_jump (const char *op, long lhs, long rhs) {
-
-    long slhs = inline_s32 (lhs);
-    long srhs = inline_s32 (rhs);
-    
-    unsigned long ulhs = inline_u32 (lhs);
-    unsigned long urhs = inline_u32 (rhs);
-    
-    if (strcmp (op, "jz") == 0 || strcmp (op, "je") == 0) {
-        return slhs == srhs;
-    }
-    
-    if (strcmp (op, "jnz") == 0 || strcmp (op, "jne") == 0) {
-        return slhs != srhs;
-    }
-    
-    if (strcmp (op, "jg") == 0) {
-        return slhs > srhs;
-    }
-    
-    if (strcmp (op, "jge") == 0) {
-        return slhs >= srhs;
-    }
-    
-    if (strcmp (op, "jl") == 0) {
-        return slhs < srhs;
-    }
-    
-    if (strcmp (op, "jle") == 0) {
-        return slhs <= srhs;
-    }
-    
-    if (strcmp (op, "ja") == 0) {
-        return ulhs > urhs;
-    }
-    
-    if (strcmp (op, "jae") == 0) {
-        return ulhs >= urhs;
-    }
-    
-    if (strcmp (op, "jb") == 0) {
-        return ulhs < urhs;
-    }
-    
-    if (strcmp (op, "jbe") == 0) {
-        return ulhs <= urhs;
-    }
-    
-    return 0;
-
-}
-
-static int inline_parse_jump_label (const char *line, const char *op, char *label, size_t label_size) {
-
-    const char *p = line;
-    size_t n = 0;
-    
-    if (!label || label_size == 0) {
-        return 0;
-    }
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (strncmp (p, op, strlen (op)) != 0) {
-        return 0;
-    }
-    
-    p += strlen (op);
-    
-    if (*p != ' ' && *p != '\t') {
-        return 0;
-    }
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_' || *p == '.')) {
-        return 0;
-    }
-    
-    while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') ||
-           (*p >= '0' && *p <= '9') || *p == '_' || *p == '.') {
-    
-        if (n + 1 < label_size) {
-            label[n++] = *p;
-        }
-        
-        p++;
-    }
-    
-    label[n] = '\0';
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    return *p == '\0';
-
-}
-
-
-
-static int inline_parse_any_jump_label (const char *line, char *label, size_t label_size) {
-
-    static const char *const ops[] = {
-        "jmp", "jz", "jnz", "je", "jne", "jc", "jnc",
-        "ja", "jae", "jb", "jbe", "jg", "jge", "jl", "jle",
-        "js", "jns", "jo", "jno", "jp", "jpe", "jnp", "jpo",
-        0
-    };
-    
-    int i;
-    
-    for (i = 0; ops[i]; i++) {
-    
-        if (inline_parse_jump_label (line, ops[i], label, label_size)) {
-            return 1;
-        }
-    
-    }
-    
-    return 0;
-
-}
-
-static int inline_parse_label_definition (const char *line, char *label, size_t label_size) {
-
-    const char *p = line;
-    size_t n = 0;
-    
-    if (!label || label_size == 0) {
-        return 0;
-    }
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_' || *p == '.')) {
-        return 0;
-    }
-    
-    while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') ||
-           (*p >= '0' && *p <= '9') || *p == '_' || *p == '.') {
-    
-        if (n + 1 < label_size) {
-            label[n++] = *p;
-        }
-        
-        p++;
-    }
-    
-    label[n] = '\0';
-    
-    if (*p != ':') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    return *p == '\0';
-
-}
-
-static const char *inline_find_chain_target (char **from, char **to, int count, const char *label) {
-
-    int i;
-    
-    if (!label) {
-        return 0;
-    }
-    
-    for (i = 0; i < count; i++) {
-    
-        if (from[i] && to[i] && strcmp (from[i], label) == 0) {
-            return to[i];
-        }
-    
-    }
-    
-    return 0;
-
-}
-
-static void inline_copy_string (char *dst, const char *src, size_t dst_size) {
-
-    size_t len;
-    
-    if (!dst || dst_size == 0) {
-        return;
-    }
-    
-    if (!src) {
-    
-        dst[0] = '\0';
-        return;
-    
-    }
-    
-    len = strlen (src);
-    
-    if (len >= dst_size) {
-        len = dst_size - 1;
-    }
-    
-    memcpy (dst, src, len);
-    dst[len] = '\0';
-
-}
-
-static int inline_resolve_jump_chain (char **from, char **to, int count, const char *label, char *out, size_t out_size) {
-
-    const char *cur = label;
-    const char *next;
-    
-    int changed = 0;
-    int depth = 0;
-    
-    if (!label || !out || out_size == 0) {
-        return 0;
-    }
-    
-    while (depth++ < count) {
-    
-        next = inline_find_chain_target (from, to, count, cur);
-        
-        if (!next || strcmp (next, cur) == 0) {
-            break;
-        }
-        
-        cur = next;
-        changed = 1;
-    
-    }
-    
-    if (!changed || strcmp (cur, label) == 0) {
-        return 0;
-    }
-    
-    if (out && cur && out_size > 0) {
-        inline_copy_string (out, cur, out_size);
-    }
-    
-    return 1;
-
-}
-
-static int inline_parse_esp_reference (const char *p, int *offset) {
-
-    const char *start = p;
-    
-    int off = 0;
-    int neg = 0;
-    
-    if (strncmp (p, "[esp]", 5) == 0) {
-    
-        *offset = 0;
-        return 5;
-    
-    }
-    
-    if (strncmp (p, "[esp + ", 7) == 0) {
-        p += 7;
-    } else if (strncmp (p, "[esp+", 5) == 0) {
-        p += 5;
-    } else if (strncmp (p, "[esp - ", 7) == 0) {
-        neg = 1;
-        p += 7;
-    } else if (strncmp (p, "[esp-", 5) == 0) {
-        neg = 1;
-        p += 5;
-    } else {
-        return 0;
-    }
-    
-    if (*p < '0' || *p > '9') {
-        return 0;
-    }
-    
-    while (*p >= '0' && *p <= '9') {
-    
-        off = (off * 10) + (*p - '0');
-        p++;
-    
-    }
-    
-    if (*p != ']') {
-        return 0;
-    }
-    
-    *offset = neg ? -off : off;
-    return (int) ((p + 1) - start);
-
-}
-
-static int inline_parse_store_eax_to_esp (const char *line, int *offset) {
-
-    const char *p = line;
-    int n;
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (strncmp (p, "mov dword ptr ", 14) != 0) {
-        return 0;
-    }
-    
-    p += 14;
-    n = inline_parse_esp_reference (p, offset);
-    
-    if (!n) {
-        return 0;
-    }
-    
-    p += n;
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (strncmp (p, ", eax", 5) != 0) {
-        return 0;
-    }
-    
-    p += 5;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    return *p == '\0';
-
-}
-
-static int inline_parse_load_eax_from_esp (const char *line, int *offset) {
-
-    const char *p = line;
-    int n;
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (strncmp (p, "mov eax, dword ptr ", 19) != 0) {
-        return 0;
-    }
-    
-    p += 19;
-    n = inline_parse_esp_reference (p, offset);
-    
-    if (!n) {
-        return 0;
-    }
-    
-    p += n;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    return *p == '\0';
-
-}
-
-static int inline_parse_load_edx_from_esp (const char *line, int *offset) {
-
-    const char *p = line;
-    int n;
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (strncmp (p, "mov edx, dword ptr ", 19) != 0) {
-        return 0;
-    }
-    
-    p += 19;
-    n = inline_parse_esp_reference (p, offset);
-    
-    if (!n) {
-        return 0;
-    }
-    
-    p += n;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    return *p == '\0';
-
-}
-
-static int inline_parse_addsub_esp_imm1 (const char *line, int *offset, long *delta) {
-
-    const char *p = line;
-    int n;
-    int is_sub = 0;
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (strncmp (p, "add dword ptr ", 14) == 0) {
-        p += 14;
-    } else if (strncmp (p, "sub dword ptr ", 14) == 0) {
-    
-        is_sub = 1;
-        p += 14;
-    
-    } else {
-        return 0;
-    }
-    
-    n = inline_parse_esp_reference (p, offset);
-    
-    if (!n) {
-        return 0;
-    }
-    
-    p += n;
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (strncmp (p, ", 1", 3) != 0) {
-        return 0;
-    }
-    
-    p += 3;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (*p != '\0') {
-        return 0;
-    }
-    
-    *delta = is_sub ? -1 : 1;
-    return 1;
-
-}
-
-static char *inline_dup_text_slice (const char *start, size_t len) {
-
-    char *out = (char *) malloc (len + 1);
-    
-    if (!out) {
-        return 0;
-    }
-    
-    memcpy (out, start, len);
-    out[len] = '\0';
-    
-    return out;
-
-}
-
-static void inline_clear_slots (int *slot_valid, long *slot_value) {
-
-    int i;
-    
-    for (i = 0; i < 64; i++) {
-    
-        slot_valid[i] = 0;
-        slot_value[i] = 0;
-    
-    }
-
-}
-
-static void emit_inline_optimized_text (const char *text, FILE *ofp) {
-
-    const char *p = text;
-    
-    char **lines;
-    char **repl;
-    
-    int *skip;
-    int *store_slot;
-    int count = 0;
-    int i;
-    
-    long slot_value[64];
-    
-    int slot_valid[64];
-    int slot_real_read[64];
-    
-    long eax_value = 0;
-    
-    int eax_valid = 0;
-    int alloc_line = -1;
-    int free_line = -1;
-    int alloc_bytes = 0;
-    int can_remove_area = 0;
-    
-    char **chain_from = 0;
-    char **chain_to = 0;
-    
-    int *label_refs = 0;
-    
-    if (!text || !ofp) {
-        return;
-    }
-    
-    for (p = text; *p; p++) {
-    
-        if (*p == '\n') {
-            count++;
-        }
-    
-    }
-    
-    if (p != text && p[-1] != '\n') {
-        count++;
-    }
-    
-    if (count <= 0) {
-        return;
-    }
-    
-    lines = (char **) calloc ((size_t) count, sizeof (*lines));
-    repl = (char **) calloc ((size_t) count, sizeof (*repl));
-    skip = (int *) calloc ((size_t) count, sizeof (*skip));
-    store_slot = (int *) malloc ((size_t) count * sizeof (*store_slot));
-    chain_from = (char **) calloc ((size_t) count, sizeof (*chain_from));
-    chain_to = (char **) calloc ((size_t) count, sizeof (*chain_to));
-    label_refs = (int *) calloc ((size_t) count, sizeof (*label_refs));
-    
-    if (!lines || !repl || !skip || !store_slot || !chain_from || !chain_to || !label_refs) {
-    
-        free (lines);
-        free (repl);
-        free (skip);
-        free (store_slot);
-        free (chain_from);
-        free (chain_to);
-        free (label_refs);
-        
-        fputs (text, ofp);
-        return;
-    
-    }
-    
-    for (i = 0; i < count; i++) {
-        store_slot[i] = -1;
-    }
-    
-    p = text;
-    i = 0;
-    
-    while (*p && i < count) {
-    
-        const char *line = p;
-        const char *eol = strchr (p, '\n');
-        const char *next = eol ? eol + 1 : p + strlen (p);
-        size_t len = (size_t) (next - line);
-        
-        lines[i++] = inline_dup_text_slice (line, len);
-        p = next;
-    
-    }
-    
-    count = i;
-    inline_clear_slots (slot_valid, slot_value);
-    
-    for (i = 0; i < 64; i++) {
-        slot_real_read[i] = 0;
-    }
-    
-    for (i = 0; i < count; i++) {
-    
-        char *buf = lines[i];
-        int offset;
-        int slot;
-        long value;
-        long mem_delta;
-        int delta;
-        
-        if (!buf) {
-            continue;
-        }
-        
-        delta = inline_line_stack_delta (buf, strlen (buf));
-        
-        if (delta > 0 && alloc_line < 0) {
-        
-            alloc_line = i;
-            alloc_bytes = delta;
-            
-            eax_valid = 0;
-            continue;
-        
-        }
-        
-        if (delta < 0 && alloc_line >= 0 && -delta == alloc_bytes) {
-        
-            free_line = i;
-            eax_valid = 0;
-            
-            continue;
-        
-        }
-        
-        if (inline_parse_mov_eax_imm (buf, &value)) {
-        
-            eax_value = value;
-            eax_valid = 1;
-            
-            continue;
-        
-        }
-        
-        if (inline_parse_store_eax_to_esp (buf, &offset)) {
-        
-            if (offset >= 0 && (offset % 4) == 0) {
-            
-                slot = offset / 4;
-                
-                if (slot >= 0 && slot < 64) {
-                
-                    store_slot[i] = slot;
-                    
-                    if (eax_valid) {
-                    
-                        slot_valid[slot] = 1;
-                        slot_value[slot] = eax_value;
-                    
-                    } else {
-                        slot_valid[slot] = 0;
-                    }
-                
-                }
-            
-            }
-            
-            continue;
-        
-        }
-        
-        if (inline_parse_load_eax_from_esp (buf, &offset)) {
-        
-            if (offset >= 0 && (offset % 4) == 0) {
-            
-                slot = offset / 4;
-                
-                if (slot >= 0 && slot < 64 && slot_valid[slot]) {
-                
-                    char tmp[128];
-                    sprintf (tmp, "    mov eax, %ld\n", slot_value[slot]);
-                    
-                    repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-                    
-                    eax_value = slot_value[slot];
-                    eax_valid = 1;
-                    
-                    continue;
-                
-                }
-                
-                if (slot >= 0 && slot < 64) {
-                    slot_real_read[slot] = 1;
-                }
-            
-            }
-            
-            eax_valid = 0;
-            continue;
-        }
-        
-        if (inline_parse_load_edx_from_esp (buf, &offset)) {
-        
-            if (offset >= 0 && (offset % 4) == 0) {
-            
-                slot = offset / 4;
-                
-                if (slot >= 0 && slot < 64 && slot_valid[slot]) {
-                
-                    char tmp[128];
-                    sprintf (tmp, "    mov edx, %ld\n", slot_value[slot]);
-                    
-                    repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-                    continue;
-                
-                }
-                
-                if (slot >= 0 && slot < 64) {
-                    slot_real_read[slot] = 1;
-                }
-            
-            }
-            
-            continue;
-        
-        }
-        
-        if (inline_parse_addsub_esp_imm1 (buf, &offset, &mem_delta)) {
-        
-            if (offset >= 0 && (offset % 4) == 0) {
-            
-                slot = offset / 4;
-                
-                if (slot >= 0 && slot < 64) {
-                
-                    if (slot_valid[slot]) {
-                        slot_value[slot] = inline_s32 (slot_value[slot] + mem_delta);
-                        skip[i] = 1;
-                    }
-                    
-                    continue;
-                }
-            }
-            
-            eax_valid = 0;
-            continue;
-        
-        }
-        
-        if (strstr (buf, "esp")) {
-        
-            inline_clear_slots (slot_valid, slot_value);
-            eax_valid = 0;
-        
-        } else if (strstr (buf, "eax")) {
-            eax_valid = 0;
-        }
-    
-    }
-    
-    if (alloc_line >= 0 && free_line > alloc_line && alloc_bytes > 0) {
-    
-        int any_remaining_esp = 0;
-        int slots = alloc_bytes / 4;
-        
-        for (i = 0; i < count; i++) {
-        
-            if (i == alloc_line || i == free_line) {
-                continue;
-            }
-            
-            if (store_slot[i] >= 0 && store_slot[i] < slots && !slot_real_read[store_slot[i]]) {
-                continue;
-            }
-            
-            if (repl[i]) {
-            
-                if (strstr (repl[i], "esp")) {
-                    any_remaining_esp = 1;
-                    break;
-                }
-            
-            } else if (lines[i] && strstr (lines[i], "esp")) {
-            
-                any_remaining_esp = 1;
-                break;
-            
-            }
-        
-        }
-        
-        if (!any_remaining_esp) {
-        
-            can_remove_area = 1;
-            skip[alloc_line] = 1;
-            skip[free_line] = 1;
-            
-            for (i = 0; i < count; i++) {
-            
-                if (store_slot[i] >= 0 && store_slot[i] < slots && !slot_real_read[store_slot[i]]) {
-                    skip[i] = 1;
-                }
-            
-            }
-            
-            /*
-             * If an argument copy was folded away, the immediately preceding
-             * constant load was only there to feed that copy.  Drop it too;
-             * otherwise multi-argument inline calls leave noise like:
-             *
-             *     mov eax, 1
-             *     mov eax, 2
-             *
-             * after both temporary argument stores have been removed.
-             */
-            for (i = 0; i < count; i++) {
-            
-                long ignored_value;
-                int j;
-                
-                if (!skip[i] || store_slot[i] < 0) {
-                    continue;
-                }
-                
-                for (j = i - 1; j >= 0; j--) {
-                
-                    if (skip[j]) {
-                        continue;
-                    }
-                    
-                    if (inline_parse_mov_eax_imm (lines[j], &ignored_value)) {
-                        skip[j] = 1;
-                    }
-                    
-                    break;
-                
-                }
-            
-            }
-        
-        }
-    
-    }
-    
-    (void) can_remove_area;
-    
-    for (i = 0; i < count; i++) {
-    
-        long first_value;
-        int j;
-        
-        if (skip[i] || !lines[i] || !inline_parse_mov_eax_imm (lines[i], &first_value)) {
-            continue;
-        }
-        
-        for (j = i + 1; j < count; j++) {
-        
-            long next_value;
-            const char *check;
-            
-            if (skip[j]) {
-                continue;
-            }
-            
-            check = repl[j] ? repl[j] : lines[j];
-            
-            if (!check) {
-                continue;
-            }
-            
-            if (!strstr (check, "eax")) {
-                continue;
-            }
-            
-            if (inline_parse_mov_eax_imm (check, &next_value) && next_value == first_value) {
-                skip[i] = 1;
-            }
-            
-            break;
-        
-        }
-    
-    }
-    
-    for (i = 0; i + 3 < count; i++) {
-    
-        long lhs;
-        long rhs;
-        
-        char cond_label[128];
-        char opbuf[16];
-        char tmp[192];
-        
-        const char *l0;
-        const char *l1;
-        const char *l2;
-        const char *l3;
-        
-        int taken;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        l0 = repl[i] ? repl[i] : lines[i];
-        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
-        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
-        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
-        
-        if (!l0 || !l1 || !l2 || !l3) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l2, "cmp eax, edx")) {
-            continue;
-        }
-        
-        if (!inline_parse_cond_jump_label (l3, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
-            continue;
-        }
-        
-        taken = inline_eval_cmp_jump (opbuf, lhs, rhs);
-        
-        if (taken) {
-        
-            sprintf (tmp, "    jmp %s\n", cond_label);
-            free (repl[i]);
-            
-            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-            
-            skip[i + 1] = 1;
-            skip[i + 2] = 1;
-            skip[i + 3] = 1;
-        
-        } else {
-        
-            skip[i] = 1;
-            skip[i + 1] = 1;
-            skip[i + 2] = 1;
-            skip[i + 3] = 1;
-        
-        }
-    
-    }
-    
-    for (i = 0; i + 4 < count; i++) {
-    
-        long lhs;
-        long rhs;
-        
-        char false_label[128];
-        char true_label[128];
-        char opbuf[16];
-        char tmp[192];
-        
-        const char *l0;
-        const char *l1;
-        const char *l2;
-        const char *l3;
-        const char *l4;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        l0 = repl[i] ? repl[i] : lines[i];
-        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
-        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
-        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
-        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
-        
-        if (!l0 || !l1 || !l2 || !l3 || !l4) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l2, "cmp eax, edx")) {
-            continue;
-        }
-        
-        if (!inline_parse_cond_jump_label (l3, opbuf, sizeof (opbuf), false_label, sizeof (false_label))) {
-            continue;
-        }
-        
-        if (!inline_parse_jump_label (l4, "jmp", true_label, sizeof (true_label))) {
-            continue;
-        }
-        
-        sprintf (tmp, "    jmp %s\n", inline_eval_cmp_jump (opbuf, lhs, rhs) ? false_label : true_label);
-        free (repl[i]);
-        
-        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-        
-        skip[i + 1] = 1;
-        skip[i + 2] = 1;
-        skip[i + 3] = 1;
-        skip[i + 4] = 1;
-    
-    }
-    
-    for (i = 0; i + 4 < count; i++) {
-
-        long lhs;
-        long rhs;
-        
-        char cond_label[128];
-        char opbuf[16];
-        char tmp[192];
-        
-        const char *l0;
-        const char *l1;
-        const char *l2;
-        const char *l3;
-        const char *l4;
-        
-        int taken;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        l0 = repl[i] ? repl[i] : lines[i];
-        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
-        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
-        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
-        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
-        
-        if (!l0 || !l1 || !l2 || !l3 || !l4) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
-            continue;
-        }
-        
-        if (!inline_fold_binary_eax_edx (l2, lhs, rhs, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l3, "test eax, eax")) {
-            continue;
-        }
-        
-        if (!inline_parse_cond_jump_label (l4, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
-            continue;
-        }
-        
-        taken = inline_eval_test_jump (opbuf, lhs);
-        
-        if (taken) {
-        
-            sprintf (tmp, "    jmp %s\n", cond_label);
-            free (repl[i]);
-            
-            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-            
-            skip[i + 1] = 1;
-            skip[i + 2] = 1;
-            skip[i + 3] = 1;
-            skip[i + 4] = 1;
-        
-        } else {
-        
-            skip[i] = 1;
-            skip[i + 1] = 1;
-            skip[i + 2] = 1;
-            skip[i + 3] = 1;
-            skip[i + 4] = 1;
-        
-        }
-    
-    }
-    
-    for (i = 0; i + 5 < count; i++) {
-    
-        long lhs;
-        long rhs;
-        long cmp_rhs;
-        long folded;
-        
-        char cond_label[128];
-        char opbuf[16];
-        char tmp[192];
-        
-        const char *l0;
-        const char *l1;
-        const char *l2;
-        const char *l3;
-        const char *l4;
-        const char *l5;
-        
-        int taken;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        l0 = repl[i] ? repl[i] : lines[i];
-        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
-        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
-        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
-        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
-        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
-        
-        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
-            continue;
-        }
-        
-        if (!inline_fold_binary_eax_edx (l2, lhs, rhs, &folded)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l3, &cmp_rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l4, "cmp eax, edx")) {
-            continue;
-        }
-        
-        if (!inline_parse_cond_jump_label (l5, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
-            continue;
-        }
-        
-        taken = inline_eval_cmp_jump (opbuf, folded, cmp_rhs);
-        
-        if (taken) {
-        
-            sprintf (tmp, "    jmp %s\n", cond_label);
-            free (repl[i]);
-            
-            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-            
-            skip[i + 1] = 1;
-            skip[i + 2] = 1;
-            skip[i + 3] = 1;
-            skip[i + 4] = 1;
-            skip[i + 5] = 1;
-        
-        } else {
-        
-            skip[i] = 1;
-            skip[i + 1] = 1;
-            skip[i + 2] = 1;
-            skip[i + 3] = 1;
-            skip[i + 4] = 1;
-            skip[i + 5] = 1;
-        
-        }
-    
-    }
-    
-    for (i = 0; i + 5 < count; i++) {
-    
-        long lhs;
-        long rhs;
-        
-        char false_label[128];
-        char true_label[128];
-        char opbuf[16];
-        char tmp[192];
-        
-        const char *l0;
-        const char *l1;
-        const char *l2;
-        const char *l3;
-        const char *l4;
-        const char *l5;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        l0 = repl[i] ? repl[i] : lines[i];
-        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
-        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
-        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
-        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
-        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
-        
-        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
-            continue;
-        }
-        
-        if (!inline_fold_binary_eax_edx (l2, lhs, rhs, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l3, "test eax, eax")) {
-            continue;
-        }
-        
-        if (!inline_parse_cond_jump_label (l4, opbuf, sizeof (opbuf), false_label, sizeof (false_label))) {
-            continue;
-        }
-        
-        if (!inline_parse_jump_label (l5, "jmp", true_label, sizeof (true_label))) {
-            continue;
-        }
-        
-        sprintf (tmp, "    jmp %s\n", inline_eval_test_jump (opbuf, lhs) ? false_label : true_label);
-        free (repl[i]);
-        
-        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-        
-        skip[i + 1] = 1;
-        skip[i + 2] = 1;
-        skip[i + 3] = 1;
-        skip[i + 4] = 1;
-        skip[i + 5] = 1;
-    
-    }
-    
-    for (i = 0; i + 6 < count; i++) {
-    
-        long lhs;
-        long rhs;
-        long cmp_rhs;
-        long folded;
-        
-        int jump_taken = 0;
-        
-        char cond_label[128];
-        char fall_label[128];
-        char opbuf[16];
-        char tmp[192];
-        
-        const char *l0;
-        const char *l1;
-        const char *l2;
-        const char *l3;
-        const char *l4;
-        const char *l5;
-        const char *l6;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        l0 = repl[i] ? repl[i] : lines[i];
-        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
-        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
-        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
-        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
-        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
-        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
-        
-        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
-            continue;
-        }
-        
-        if (!inline_fold_binary_eax_edx (l2, lhs, rhs, &folded)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l3, &cmp_rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l4, "cmp eax, edx")) {
-            continue;
-        }
-        
-        if (!inline_parse_cond_jump_label (l5, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
-            continue;
-        }
-        
-        jump_taken = inline_eval_cmp_jump (opbuf, folded, cmp_rhs);
-        
-        if (!inline_parse_jump_label (l6, "jmp", fall_label, sizeof (fall_label))) {
-            continue;
-        }
-        
-        sprintf (tmp, "    jmp %s\n", jump_taken ? cond_label : fall_label);
-        free (repl[i]);
-        
-        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-        
-        skip[i + 1] = 1;
-        skip[i + 2] = 1;
-        skip[i + 3] = 1;
-        skip[i + 4] = 1;
-        skip[i + 5] = 1;
-        skip[i + 6] = 1;
-    
-    }
-    
-    for (i = 0; i + 5 < count; i++) {
-
-        long lhs;
-        long rhs;
-        long folded;
-        
-        char cond_label[128];
-        char opbuf[16];
-        char tmp[192];
-        
-        const char *l0;
-        const char *l1;
-        const char *l2;
-        const char *l3;
-        const char *l4;
-        const char *l5;
-        
-        int taken;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        l0 = repl[i] ? repl[i] : lines[i];
-        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
-        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
-        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
-        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
-        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
-        
-        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l2, "mov ecx, edx")) {
-            continue;
-        }
-        
-        if (!inline_fold_shift_eax_edx (l3, lhs, rhs, &folded)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l4, "test eax, eax")) {
-            continue;
-        }
-        
-        if (!inline_parse_cond_jump_label (l5, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
-            continue;
-        }
-        
-        taken = inline_eval_test_jump (opbuf, folded);
-        
-        if (taken) {
-        
-            sprintf (tmp, "    jmp %s\n", cond_label);
-            free (repl[i]);
-            
-            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-            
-            skip[i + 1] = 1;
-            skip[i + 2] = 1;
-            skip[i + 3] = 1;
-            skip[i + 4] = 1;
-            skip[i + 5] = 1;
-        
-        } else {
-        
-            skip[i] = 1;
-            skip[i + 1] = 1;
-            skip[i + 2] = 1;
-            skip[i + 3] = 1;
-            skip[i + 4] = 1;
-            skip[i + 5] = 1;
-        
-        }
-    
-    }
-    
-    for (i = 0; i + 6 < count; i++) {
-    
-        long lhs;
-        long rhs;
-        long cmp_rhs;
-        long folded;
-        
-        char cond_label[128];
-        char opbuf[16];
-        char tmp[192];
-        
-        const char *l0;
-        const char *l1;
-        const char *l2;
-        const char *l3;
-        const char *l4;
-        const char *l5;
-        const char *l6;
-        
-        int taken;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        l0 = repl[i] ? repl[i] : lines[i];
-        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
-        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
-        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
-        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
-        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
-        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
-        
-        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l2, "mov ecx, edx")) {
-            continue;
-        }
-        
-        if (!inline_fold_shift_eax_edx (l3, lhs, rhs, &folded)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l4, &cmp_rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l5, "cmp eax, edx")) {
-            continue;
-        }
-        
-        if (!inline_parse_cond_jump_label (l6, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
-            continue;
-        }
-        
-        taken = inline_eval_cmp_jump (opbuf, folded, cmp_rhs);
-        
-        if (taken) {
-        
-            sprintf (tmp, "    jmp %s\n", cond_label);
-            free (repl[i]);
-            
-            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-            
-            skip[i + 1] = 1;
-            skip[i + 2] = 1;
-            skip[i + 3] = 1;
-            skip[i + 4] = 1;
-            skip[i + 5] = 1;
-            skip[i + 6] = 1;
-        
-        } else {
-        
-            skip[i] = 1;
-            skip[i + 1] = 1;
-            skip[i + 2] = 1;
-            skip[i + 3] = 1;
-            skip[i + 4] = 1;
-            skip[i + 5] = 1;
-            skip[i + 6] = 1;
-        
-        }
-    
-    }
-    
-    for (i = 0; i + 6 < count; i++) {
-    
-        long lhs;
-        long rhs;
-        long folded;
-        
-        char false_label[128];
-        char true_label[128];
-        char opbuf[16];
-        char tmp[192];
-        
-        const char *l0;
-        const char *l1;
-        const char *l2;
-        const char *l3;
-        const char *l4;
-        const char *l5;
-        const char *l6;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        l0 = repl[i] ? repl[i] : lines[i];
-        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
-        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
-        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
-        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
-        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
-        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
-        
-        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l2, "mov ecx, edx")) {
-            continue;
-        }
-        
-        if (!inline_fold_shift_eax_edx (l3, lhs, rhs, &folded)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l4, "test eax, eax")) {
-            continue;
-        }
-        
-        if (!inline_parse_cond_jump_label (l5, opbuf, sizeof (opbuf), false_label, sizeof (false_label))) {
-            continue;
-        }
-        
-        if (!inline_parse_jump_label (l6, "jmp", true_label, sizeof (true_label))) {
-            continue;
-        }
-        
-        sprintf (tmp, "    jmp %s\n", inline_eval_test_jump (opbuf, folded) ? false_label : true_label);
-        free (repl[i]);
-        
-        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-        
-        skip[i + 1] = 1;
-        skip[i + 2] = 1;
-        skip[i + 3] = 1;
-        skip[i + 4] = 1;
-        skip[i + 5] = 1;
-        skip[i + 6] = 1;
-    
-    }
-    
-    for (i = 0; i + 7 < count; i++) {
-    
-        long lhs;
-        long rhs;
-        long cmp_rhs;
-        long folded;
-        
-        int jump_taken = 0;
-        
-        char cond_label[128];
-        char fall_label[128];
-        char opbuf[16];
-        char tmp[192];
-        
-        const char *l0;
-        const char *l1;
-        const char *l2;
-        const char *l3;
-        const char *l4;
-        const char *l5;
-        const char *l6;
-        const char *l7;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        l0 = repl[i] ? repl[i] : lines[i];
-        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
-        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
-        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
-        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
-        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
-        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
-        l7 = repl[i + 7] ? repl[i + 7] : lines[i + 7];
-        
-        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6 || !l7) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l2, "mov ecx, edx")) {
-            continue;
-        }
-        
-        if (!inline_fold_shift_eax_edx (l3, lhs, rhs, &folded)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l4, &cmp_rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l5, "cmp eax, edx")) {
-            continue;
-        }
-        
-        if (!inline_parse_cond_jump_label (l6, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
-            continue;
-        }
-        
-        jump_taken = inline_eval_cmp_jump (opbuf, folded, cmp_rhs);
-        
-        if (!inline_parse_jump_label (l7, "jmp", fall_label, sizeof (fall_label))) {
-            continue;
-        }
-        
-        sprintf (tmp, "    jmp %s\n", jump_taken ? cond_label : fall_label);
-        free (repl[i]);
-        
-        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-        
-        skip[i + 1] = 1;
-        skip[i + 2] = 1;
-        skip[i + 3] = 1;
-        skip[i + 4] = 1;
-        skip[i + 5] = 1;
-        skip[i + 6] = 1;
-        skip[i + 7] = 1;
-    
-    }
-    
-    for (i = 0; i + 6 < count; i++) {
-    
-        long lhs;
-        long rhs;
-        long folded;
-        
-        char cond_label[128];
-        char opbuf[16];
-        char tmp[192];
-        
-        const char *l0;
-        const char *l1;
-        const char *l2;
-        const char *l3;
-        const char *l4;
-        const char *l5;
-        const char *l6;
-        
-        int taken;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        l0 = repl[i] ? repl[i] : lines[i];
-        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
-        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
-        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
-        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
-        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
-        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
-        
-        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l2, "mov ecx, edx") || !inline_line_is_exact (l3, "cdq") ||
-            !inline_line_is_exact (l4, "idiv ecx")) {
-            continue;
-        }
-        
-        if (!inline_fold_div_eax_edx (lhs, rhs, &folded)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l5, "test eax, eax")) {
-            continue;
-        }
-        
-        if (!inline_parse_cond_jump_label (l6, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
-            continue;
-        }
-        
-        taken = inline_eval_test_jump (opbuf, folded);
-        
-        if (taken) {
-        
-            sprintf (tmp, "    jmp %s\n", cond_label);
-            free (repl[i]);
-            
-            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-            
-            skip[i + 1] = 1;
-            skip[i + 2] = 1;
-            skip[i + 3] = 1;
-            skip[i + 4] = 1;
-            skip[i + 5] = 1;
-            skip[i + 6] = 1;
-        
-        } else {
-        
-            skip[i] = 1;
-            skip[i + 1] = 1;
-            skip[i + 2] = 1;
-            skip[i + 3] = 1;
-            skip[i + 4] = 1;
-            skip[i + 5] = 1;
-            skip[i + 6] = 1;
-        
-        }
-    
-    }
-    
-    for (i = 0; i + 7 < count; i++) {
-    
-        long lhs;
-        long rhs;
-        long cmp_rhs;
-        long folded;
-        
-        char cond_label[128];
-        char opbuf[16];
-        char tmp[192];
-        
-        const char *l0;
-        const char *l1;
-        const char *l2;
-        const char *l3;
-        const char *l4;
-        const char *l5;
-        const char *l6;
-        const char *l7;
-        
-        int taken;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        l0 = repl[i] ? repl[i] : lines[i];
-        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
-        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
-        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
-        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
-        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
-        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
-        l7 = repl[i + 7] ? repl[i + 7] : lines[i + 7];
-        
-        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6 || !l7) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l2, "mov ecx, edx") || !inline_line_is_exact (l3, "cdq") ||
-            !inline_line_is_exact (l4, "idiv ecx")) {
-            continue;
-        }
-        
-        if (!inline_fold_div_eax_edx (lhs, rhs, &folded)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l5, &cmp_rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l6, "cmp eax, edx")) {
-            continue;
-        }
-        
-        if (!inline_parse_cond_jump_label (l7, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
-            continue;
-        }
-        
-        taken = inline_eval_cmp_jump (opbuf, folded, cmp_rhs);
-        
-        if (taken) {
-        
-            sprintf (tmp, "    jmp %s\n", cond_label);
-            free (repl[i]);
-            
-            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-            
-            skip[i + 1] = 1;
-            skip[i + 2] = 1;
-            skip[i + 3] = 1;
-            skip[i + 4] = 1;
-            skip[i + 5] = 1;
-            skip[i + 6] = 1;
-            skip[i + 7] = 1;
-        
-        } else {
-        
-            skip[i] = 1;
-            skip[i + 1] = 1;
-            skip[i + 2] = 1;
-            skip[i + 3] = 1;
-            skip[i + 4] = 1;
-            skip[i + 5] = 1;
-            skip[i + 6] = 1;
-            skip[i + 7] = 1;
-        
-        }
-    
-    }
-    
-    for (i = 0; i + 7 < count; i++) {
-    
-        long lhs;
-        long rhs;
-        long folded;
-        
-        char cond_label[128];
-        char opbuf[16];
-        char tmp[192];
-        
-        const char *l0;
-        const char *l1;
-        const char *l2;
-        const char *l3;
-        const char *l4;
-        const char *l5;
-        const char *l6;
-        const char *l7;
-        
-        int taken;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        l0 = repl[i] ? repl[i] : lines[i];
-        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
-        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
-        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
-        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
-        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
-        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
-        l7 = repl[i + 7] ? repl[i + 7] : lines[i + 7];
-        
-        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6 || !l7) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l2, "mov ecx, edx") || !inline_line_is_exact (l3, "cdq") ||
-            !inline_line_is_exact (l4, "idiv ecx") || !inline_line_is_exact (l5, "mov eax, edx")) {
-            continue;
-        }
-        
-        if (!inline_fold_mod_eax_edx (lhs, rhs, &folded)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l6, "test eax, eax")) {
-            continue;
-        }
-        
-        if (!inline_parse_cond_jump_label (l7, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
-            continue;
-        }
-        
-        taken = inline_eval_test_jump (opbuf, folded);
-        
-        if (taken) {
-        
-            sprintf (tmp, "    jmp %s\n", cond_label);
-            free (repl[i]);
-            
-            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-            
-            skip[i + 1] = 1;
-            skip[i + 2] = 1;
-            skip[i + 3] = 1;
-            skip[i + 4] = 1;
-            skip[i + 5] = 1;
-            skip[i + 6] = 1;
-            skip[i + 7] = 1;
-        
-        } else {
-        
-            skip[i] = 1;
-            skip[i + 1] = 1;
-            skip[i + 2] = 1;
-            skip[i + 3] = 1;
-            skip[i + 4] = 1;
-            skip[i + 5] = 1;
-            skip[i + 6] = 1;
-            skip[i + 7] = 1;
-        
-        }
-    
-    }
-    
-    for (i = 0; i + 8 < count; i++) {
-    
-        long lhs;
-        long rhs;
-        long cmp_rhs;
-        long folded;
-        
-        char cond_label[128];
-        char opbuf[16];
-        char tmp[192];
-        
-        const char *l0;
-        const char *l1;
-        const char *l2;
-        const char *l3;
-        const char *l4;
-        const char *l5;
-        const char *l6;
-        const char *l7;
-        const char *l8;
-        
-        int taken;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        l0 = repl[i] ? repl[i] : lines[i];
-        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
-        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
-        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
-        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
-        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
-        l6 = repl[i + 6] ? repl[i + 6] : lines[i + 6];
-        l7 = repl[i + 7] ? repl[i + 7] : lines[i + 7];
-        l8 = repl[i + 8] ? repl[i + 8] : lines[i + 8];
-        
-        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5 || !l6 || !l7 || !l8) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l2, "mov ecx, edx") || !inline_line_is_exact (l3, "cdq") ||
-            !inline_line_is_exact (l4, "idiv ecx") || !inline_line_is_exact (l5, "mov eax, edx")) {
-            continue;
-        }
-        
-        if (!inline_fold_mod_eax_edx (lhs, rhs, &folded)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l6, &cmp_rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l7, "cmp eax, edx")) {
-            continue;
-        }
-        
-        if (!inline_parse_cond_jump_label (l8, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
-            continue;
-        }
-        
-        taken = inline_eval_cmp_jump (opbuf, folded, cmp_rhs);
-        
-        if (taken) {
-        
-            sprintf (tmp, "    jmp %s\n", cond_label);
-            free (repl[i]);
-            
-            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-            
-            skip[i + 1] = 1;
-            skip[i + 2] = 1;
-            skip[i + 3] = 1;
-            skip[i + 4] = 1;
-            skip[i + 5] = 1;
-            skip[i + 6] = 1;
-            skip[i + 7] = 1;
-            skip[i + 8] = 1;
-        
-        } else {
-        
-            skip[i] = 1;
-            skip[i + 1] = 1;
-            skip[i + 2] = 1;
-            skip[i + 3] = 1;
-            skip[i + 4] = 1;
-            skip[i + 5] = 1;
-            skip[i + 6] = 1;
-            skip[i + 7] = 1;
-            skip[i + 8] = 1;
-        
-        }
-    
-    }
-    
-    for (i = 0; i + 2 < count; i++) {
-    
-        long lhs;
-        long rhs;
-        long folded;
-        
-        char tmp[128];
-        
-        const char *l0;
-        const char *l1;
-        const char *l2;
-        
-        if (skip[i] || skip[i + 1] || skip[i + 2]) {
-            continue;
-        }
-        
-        l0 = repl[i] ? repl[i] : lines[i];
-        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
-        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
-        
-        if (!l0 || !l1 || !l2) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
-            continue;
-        }
-        
-        if (!inline_fold_binary_eax_edx (l2, lhs, rhs, &folded)) {
-            continue;
-        }
-        
-        sprintf (tmp, "    mov eax, %ld\n", folded);
-        free (repl[i]);
-        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-        
-        skip[i + 1] = 1;
-        skip[i + 2] = 1;
-    
-    }
-    
-    for (i = 0; i + 3 < count; i++) {
-    
-        long lhs;
-        long rhs;
-        long folded;
-        
-        char tmp[128];
-        
-        const char *l0;
-        const char *l1;
-        const char *l2;
-        const char *l3;
-        
-        if (skip[i] || skip[i + 1] || skip[i + 2] || skip[i + 3]) {
-            continue;
-        }
-        
-        l0 = repl[i] ? repl[i] : lines[i];
-        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
-        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
-        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
-        
-        if (!l0 || !l1 || !l2 || !l3) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l2, "mov ecx, edx")) {
-            continue;
-        }
-        
-        if (!inline_fold_shift_eax_edx (l3, lhs, rhs, &folded)) {
-            continue;
-        }
-        
-        sprintf (tmp, "    mov eax, %ld\n", folded);
-        free (repl[i]);
-        
-        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-        
-        skip[i + 1] = 1;
-        skip[i + 2] = 1;
-        skip[i + 3] = 1;
-    
-    }
-    
-    for (i = 0; i + 4 < count; i++) {
-    
-        long lhs;
-        long rhs;
-        long folded;
-        
-        char tmp[128];
-        
-        const char *l0;
-        const char *l1;
-        const char *l2;
-        const char *l3;
-        const char *l4;
-        
-        if (skip[i] || skip[i + 1] || skip[i + 2] || skip[i + 3] || skip[i + 4]) {
-            continue;
-        }
-        
-        l0 = repl[i] ? repl[i] : lines[i];
-        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
-        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
-        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
-        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
-        
-        if (!l0 || !l1 || !l2 || !l3 || !l4) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l2, "mov ecx, edx") || !inline_line_is_exact (l3, "cdq") ||
-            !inline_line_is_exact (l4, "idiv ecx")) {
-            continue;
-        }
-        
-        if (!inline_fold_div_eax_edx (lhs, rhs, &folded)) {
-            continue;
-        }
-        
-        sprintf (tmp, "    mov eax, %ld\n", folded);
-        free (repl[i]);
-        
-        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-        
-        skip[i + 1] = 1;
-        skip[i + 2] = 1;
-        skip[i + 3] = 1;
-        skip[i + 4] = 1;
-    
-    }
-    
-    for (i = 0; i + 5 < count; i++) {
-    
-        long lhs;
-        long rhs;
-        long folded;
-        
-        char tmp[128];
-        
-        const char *l0;
-        const char *l1;
-        const char *l2;
-        const char *l3;
-        const char *l4;
-        const char *l5;
-        
-        if (skip[i] || skip[i + 1] || skip[i + 2] || skip[i + 3] || skip[i + 4] || skip[i + 5]) {
-            continue;
-        }
-        
-        l0 = repl[i] ? repl[i] : lines[i];
-        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
-        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
-        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
-        l4 = repl[i + 4] ? repl[i + 4] : lines[i + 4];
-        l5 = repl[i + 5] ? repl[i + 5] : lines[i + 5];
-        
-        if (!l0 || !l1 || !l2 || !l3 || !l4 || !l5) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l2, "mov ecx, edx") || !inline_line_is_exact (l3, "cdq") ||
-            !inline_line_is_exact (l4, "idiv ecx") || !inline_line_is_exact (l5, "mov eax, edx")) {
-            continue;
-        }
-        
-        if (!inline_fold_mod_eax_edx (lhs, rhs, &folded)) {
-            continue;
-        }
-        
-        sprintf (tmp, "    mov eax, %ld\n", folded);
-        free (repl[i]);
-        
-        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-        
-        skip[i + 1] = 1;
-        skip[i + 2] = 1;
-        skip[i + 3] = 1;
-        skip[i + 4] = 1;
-        skip[i + 5] = 1;
-    
-    }
-    
-    /*
-     * Some compound-expression folds, such as x += 1, are reduced only by
-     * the late arithmetic pass above.  Run the constant compare/branch fold
-     * again here so newly-created sequences like:
-     *
-     *     mov eax, 9
-     *     mov edx, 9
-     *     cmp eax, edx
-     *     jne Lx
-     *
-     * are folded after the arithmetic result becomes visible.
-     */
-    for (i = 0; i + 3 < count; i++) {
-    
-        long lhs;
-        long rhs;
-        
-        char cond_label[128];
-        char opbuf[16];
-        char tmp[192];
-        
-        const char *l0;
-        const char *l1;
-        const char *l2;
-        const char *l3;
-        
-        int taken;
-        
-        if (skip[i] || skip[i + 1] || skip[i + 2] || skip[i + 3]) {
-            continue;
-        }
-        
-        l0 = repl[i] ? repl[i] : lines[i];
-        l1 = repl[i + 1] ? repl[i + 1] : lines[i + 1];
-        l2 = repl[i + 2] ? repl[i + 2] : lines[i + 2];
-        l3 = repl[i + 3] ? repl[i + 3] : lines[i + 3];
-        
-        if (!l0 || !l1 || !l2 || !l3) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l2, "cmp eax, edx")) {
-            continue;
-        }
-        
-        if (!inline_parse_cond_jump_label (l3, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
-            continue;
-        }
-        
-        taken = inline_eval_cmp_jump (opbuf, lhs, rhs);
-        
-        if (taken) {
-        
-            sprintf (tmp, "    jmp %s\n", cond_label);
-            free (repl[i]);
-            
-            repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-            
-            skip[i + 1] = 1;
-            skip[i + 2] = 1;
-            skip[i + 3] = 1;
-        
-        } else {
-        
-            skip[i] = 1;
-            skip[i + 1] = 1;
-            skip[i + 2] = 1;
-            skip[i + 3] = 1;
-        
-        }
-    
-    }
-    
-    /*
-     * A late fold can leave useful instructions separated by skipped source
-     * lines.  For example x += 1 followed by == may become:
-     *
-     *     mov eax, 9
-     *     ; skipped old rhs/op lines
-     *     mov edx, 9
-     *     cmp eax, edx
-     *     jne Lx
-     *
-     * The normal adjacent compare fold cannot see through the skipped lines,
-     * so do one compacting pass over the remaining live instructions.
-     */
-    for (i = 0; i < count; i++) {
-    
-        int j0;
-        int j1;
-        int j2;
-        int j3;
-        
-        long lhs;
-        long rhs;
-        
-        char cond_label[128];
-        char opbuf[16];
-        char tmp[192];
-        
-        const char *l0;
-        const char *l1;
-        const char *l2;
-        const char *l3;
-        
-        int taken;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        j0 = i;
-        j1 = j0 + 1;
-        
-        while (j1 < count && skip[j1]) {
-            j1++;
-        }
-        
-        j2 = j1 + 1;
-        
-        while (j2 < count && skip[j2]) {
-            j2++;
-        }
-        
-        j3 = j2 + 1;
-        
-        while (j3 < count && skip[j3]) {
-            j3++;
-        }
-        
-        if (j1 >= count || j2 >= count || j3 >= count) {
-            continue;
-        }
-        
-        l0 = repl[j0] ? repl[j0] : lines[j0];
-        l1 = repl[j1] ? repl[j1] : lines[j1];
-        l2 = repl[j2] ? repl[j2] : lines[j2];
-        l3 = repl[j3] ? repl[j3] : lines[j3];
-        
-        if (!l0 || !l1 || !l2 || !l3) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_eax_imm (l0, &lhs)) {
-            continue;
-        }
-        
-        if (!inline_parse_mov_edx_imm (l1, &rhs)) {
-            continue;
-        }
-        
-        if (!inline_line_is_exact (l2, "cmp eax, edx")) {
-            continue;
-        }
-        
-        if (!inline_parse_cond_jump_label (l3, opbuf, sizeof (opbuf), cond_label, sizeof (cond_label))) {
-            continue;
-        }
-        
-        taken = inline_eval_cmp_jump (opbuf, lhs, rhs);
-        
-        if (taken) {
-        
-            sprintf (tmp, "    jmp %s\n", cond_label);
-            free (repl[j0]);
-            
-            repl[j0] = inline_dup_text_slice (tmp, strlen (tmp));
-            
-            skip[j1] = 1;
-            skip[j2] = 1;
-            skip[j3] = 1;
-        
-        } else {
-        
-            skip[j0] = 1;
-            skip[j1] = 1;
-            skip[j2] = 1;
-            skip[j3] = 1;
-        
-        }
-    
-    }
-    
-    for (i = 0; i < count; i++) {
-    
-        char label[128];
-        char target[128];
-        const char *line;
-        int j;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        line = repl[i] ? repl[i] : lines[i];
-        
-        if (!line || !inline_parse_label_definition (line, label, sizeof (label))) {
-            continue;
-        }
-        
-        for (j = i + 1; j < count; j++) {
-        
-            const char *next_line;
-            
-            if (skip[j]) {
-                continue;
-            }
-            
-            next_line = repl[j] ? repl[j] : lines[j];
-            
-            if (!next_line) {
-                continue;
-            }
-            
-            if (inline_parse_jump_label (next_line, "jmp", target, sizeof (target))) {
-            
-                if (strcmp (label, target) != 0) {
-                
-                    chain_from[i] = inline_dup_text_slice (label, strlen (label));
-                    chain_to[i] = inline_dup_text_slice (target, strlen (target));
-                
-                }
-            
-            }
-            
-            break;
-        
-        }
-    
-    }
-    
-    for (i = 0; i < count; i++) {
-    
-        char target[128];
-        char resolved[128];
-        char tmp[192];
-        const char *line;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        line = repl[i] ? repl[i] : lines[i];
-        
-        if (!line || !inline_parse_jump_label (line, "jmp", target, sizeof (target))) {
-            continue;
-        }
-        
-        if (!inline_resolve_jump_chain (chain_from, chain_to, count, target, resolved, sizeof (resolved))) {
-            continue;
-        }
-        
-        sprintf (tmp, "    jmp %s\n", resolved);
-        free (repl[i]);
-        
-        repl[i] = inline_dup_text_slice (tmp, strlen (tmp));
-    
-    }
-    
-    for (i = 0; i < count; i++) {
-    
-        char target[128];
-        const char *line;
-        int j;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        line = repl[i] ? repl[i] : lines[i];
-        
-        if (!line || !inline_parse_any_jump_label (line, target, sizeof (target))) {
-            continue;
-        }
-        
-        for (j = 0; j < count; j++) {
-        
-            char label[128];
-            const char *def;
-            
-            if (skip[j]) {
-                continue;
-            }
-            
-            def = repl[j] ? repl[j] : lines[j];
-            
-            if (def && inline_parse_label_definition (def, label, sizeof (label)) && strcmp (label, target) == 0) {
-            
-                label_refs[j]++;
-                break;
-            
-            }
-        
-        }
-    
-    }
-    
-    for (i = 0; i < count; i++) {
-    
-        char target[128];
-        const char *line;
-        int j;
-        int target_line = -1;
-        int can_delete = 1;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        line = repl[i] ? repl[i] : lines[i];
-        
-        if (!line || !inline_parse_jump_label (line, "jmp", target, sizeof (target))) {
-            continue;
-        }
-        
-        for (j = i + 1; j < count; j++) {
-        
-            char label[128];
-            const char *check;
-            
-            if (skip[j]) {
-                continue;
-            }
-            
-            check = repl[j] ? repl[j] : lines[j];
-            
-            if (check && inline_parse_label_definition (check, label, sizeof (label)) && strcmp (label, target) == 0) {
-            
-                target_line = j;
-                break;
-            
-            }
-        
-        }
-        
-        if (target_line < 0) {
-            continue;
-        }
-        
-        for (j = i + 1; j < target_line; j++) {
-        
-            char label[128];
-            const char *check;
-            
-            if (skip[j]) {
-                continue;
-            }
-            
-            check = repl[j] ? repl[j] : lines[j];
-            
-            if (check && inline_parse_label_definition (check, label, sizeof (label)) && label_refs[j] > 0) {
-            
-                can_delete = 0;
-                break;
-            
-            }
-        
-        }
-        
-        if (!can_delete) {
-            continue;
-        }
-        
-        for (j = i + 1; j < target_line; j++) {
-            skip[j] = 1;
-        }
-    
-    }
-    
-    for (i = 0; i < count; i++) {
-    
-        char target[128];
-        const char *line;
-        int j;
-        int target_line = -1;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        line = repl[i] ? repl[i] : lines[i];
-        
-        if (!line || !inline_parse_jump_label (line, "jmp", target, sizeof (target))) {
-            continue;
-        }
-        
-        for (j = i + 1; j < count; j++) {
-        
-            char label[128];
-            const char *check;
-            
-            if (skip[j]) {
-                continue;
-            }
-            
-            check = repl[j] ? repl[j] : lines[j];
-            
-            if (!check) {
-                continue;
-            }
-            
-            if (inline_parse_label_definition (check, label, sizeof (label))) {
-            
-                if (strcmp (label, target) == 0) {
-                    target_line = j;
-                }
-                
-                break;
-            
-            }
-            
-            break;
-        
-        }
-        
-        if (target_line >= 0) {
-            skip[i] = 1;
-        }
-    
-    }
-    
-    /*
-     * Branch folding can create new unreachable ranges after the earlier
-     * jump cleanup has already run.  Recompute label references from the
-     * current non-skipped text and remove dead fall-through ranges between
-     * an unconditional jump and its later target.  This deliberately keeps
-     * referenced labels, so externally reachable or still-jumped-to blocks
-     * are not discarded.
-     */
-    {
-    
-        int changed;
-        int pass;
-        
-        for (pass = 0; pass < count; pass++) {
-        
-            changed = 0;
-            
-            for (i = 0; i < count; i++) {
-                label_refs[i] = 0;
-            }
-            
-            for (i = 0; i < count; i++) {
-            
-                char target[128];
-                const char *line;
-                int j;
-                
-                if (skip[i]) {
-                    continue;
-                }
-                
-                line = repl[i] ? repl[i] : lines[i];
-                
-                if (!line || !inline_parse_any_jump_label (line, target, sizeof (target))) {
-                    continue;
-                }
-                
-                for (j = 0; j < count; j++) {
-                
-                    char label[128];
-                    const char *def;
-                    
-                    if (skip[j]) {
-                        continue;
-                    }
-                    
-                    def = repl[j] ? repl[j] : lines[j];
-                    
-                    if (def && inline_parse_label_definition (def, label, sizeof (label)) && strcmp (label, target) == 0) {
-                    
-                        label_refs[j]++;
-                        break;
-                    
-                    }
-                
-                }
-            
-            }
-            
-            for (i = 0; i < count; i++) {
-            
-                char target[128];
-                const char *line;
-                int j;
-                int target_line = -1;
-                int can_delete = 1;
-                
-                if (skip[i]) {
-                    continue;
-                }
-                
-                line = repl[i] ? repl[i] : lines[i];
-                
-                if (!line || !inline_parse_jump_label (line, "jmp", target, sizeof (target))) {
-                    continue;
-                }
-                
-                for (j = i + 1; j < count; j++) {
-                
-                    char label[128];
-                    const char *check;
-                    
-                    if (skip[j]) {
-                        continue;
-                    }
-                    
-                    check = repl[j] ? repl[j] : lines[j];
-                    
-                    if (check && inline_parse_label_definition (check, label, sizeof (label)) && strcmp (label, target) == 0) {
-                    
-                        target_line = j;
-                        break;
-                    
-                    }
-                
-                }
-                
-                if (target_line < 0) {
-                    continue;
-                }
-                
-                for (j = i + 1; j < target_line; j++) {
-                
-                    char label[128];
-                    const char *check;
-                    
-                    if (skip[j]) {
-                        continue;
-                    }
-                    
-                    check = repl[j] ? repl[j] : lines[j];
-                    
-                    if (check && inline_parse_label_definition (check, label, sizeof (label)) && label_refs[j] > 0) {
-                    
-                        can_delete = 0;
-                        break;
-                    
-                    }
-                
-                }
-                
-                if (!can_delete) {
-                    continue;
-                }
-                
-                for (j = i + 1; j < target_line; j++) {
-                
-                    if (!skip[j]) {
-                    
-                        skip[j] = 1;
-                        changed = 1;
-                    
-                    }
-                
-                }
-            
-            }
-            
-            if (!changed) {
-                break;
-            }
-        
-        }
-    
-    }
-    
-    /*
-     * The second unreachable-code pass can expose a new fall-through jump,
-     * for example "jmp L9" immediately followed by "L9:".  Run this small
-     * cleanup again at the end so later branch/unreachable optimisations do
-     * not leave the already-handled form behind.
-     */
-    for (i = 0; i < count; i++) {
-    
-        char target[128];
-        const char *line;
-        int j;
-        int target_line = -1;
-        
-        if (skip[i]) {
-            continue;
-        }
-        
-        line = repl[i] ? repl[i] : lines[i];
-        
-        if (!line || !inline_parse_jump_label (line, "jmp", target, sizeof (target))) {
-            continue;
-        }
-        
-        for (j = i + 1; j < count; j++) {
-        
-            char label[128];
-            const char *check;
-            
-            if (skip[j]) {
-                continue;
-            }
-            
-            check = repl[j] ? repl[j] : lines[j];
-            
-            if (!check) {
-                continue;
-            }
-            
-            if (inline_parse_label_definition (check, label, sizeof (label))) {
-            
-                if (strcmp (label, target) == 0) {
-                    target_line = j;
-                }
-                
-                break;
-            
-            }
-            
-            break;
-        
-        }
-        
-        if (target_line >= 0) {
-            skip[i] = 1;
-        }
-    
-    }
-    
-    for (i = 0; i < count; i++) {
-    
-        if (!skip[i]) {
-            fputs (repl[i] ? repl[i] : (lines[i] ? lines[i] : ""), ofp);
-        }
-        
-        free (lines[i]);
-        free (repl[i]);
-    
-    }
-    
-    for (i = 0; i < count; i++) {
-    
-        free (chain_from[i]);
-        free (chain_to[i]);
-    
-    }
-    
-    free (lines);
-    free (repl);
-    free (skip);
-    free (store_slot);
-    free (chain_from);
-    free (chain_to);
-    free (label_refs);
-
-}
-
-static void finish_inline_buffer (FILE **tmp, FILE **saved, int optimize) {
-
-    FILE *out;
-    long size;
-    char *buf;
-    
-    if (!tmp || !saved || !*tmp || !*saved) {
-        return;
-    }
-    
-    out = *saved;
-    
-    fflush (*tmp);
-    fseek (*tmp, 0, SEEK_END);
-    
-    size = ftell (*tmp);
-    fseek (*tmp, 0, SEEK_SET);
-    
-    if (size > 0) {
-    
-        buf = (char *) malloc ((size_t) size + 1);
-        
-        if (buf) {
-        
-            if (fread (buf, 1, (size_t) size, *tmp) == (size_t) size) {
-            
-                buf[size] = '\0';
-                
-                if (optimize) {
-                    emit_inline_optimized_text (buf, out);
-                } else {
-                    fwrite (buf, 1, (size_t) size, out);
-                }
-            
-            }
-            
-            free (buf);
-        
-        }
-    
-    }
-    
-    scc_close (*tmp);
-    
-    *tmp = 0;
-    *saved = 0;
-    
-    state->ofp = out;
-
-}
-
-static void emit_inline_body_substituted (const char *body, int return_label, int argc) {
-
-    const char *p = body;
-    
-    int call_id = anon_label++;
-    int stack_bytes = 0;
-    
-    if (!body || !state->ofp) {
-        return;
-    }
-    
-    while (*p) {
-    
-        const char *line = p;
-        const char *eol = strchr (p, '\n');
-        const char *next = eol ? eol + 1 : p + strlen (p);
-        size_t len = (size_t) (next - line);
-        
-        emit_inline_line_substituted (line, len, return_label, call_id, argc, stack_bytes);
-        stack_bytes += inline_line_stack_delta (line, len);
-        p = next;
-    
-    }
-    
-    if (body[0] && body[strlen (body) - 1] != '\n') {
-        fputc ('\n', state->ofp);
-    }
-    
-    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
-        fprintf (state->ofp, "L%d:\n", call_id);
-    } else {
-        fprintf (state->ofp, ".L%d:\n", call_id);
-    }
-
-}
-
-static int emit_inline_call_if_possible (const char *name, int argc, const char *reg) {
-
-    int i = find_inline_function (name);
-    
-    if (i < 0 || !inline_functions[i].usable) {
-        return 0;
-    }
-    
-    if (argc != inline_functions[i].param_count) {
-        return 0;
-    }
-    
-    if (inline_functions[i].is_floating) {
-        return 0;
-    }
-    
-    if (inline_functions[i].expanding) {
-        return 0;
-    }
-    
-    if (!state->ofp) {
-        return 1;
-    }
-    
-    if (!inline_functions[i].body && !inline_functions[i].returns_void) {
-        return 0;
-    }
-    
-    if (inline_functions[i].body && inline_body_stack_delta (inline_functions[i].body) != 0) {
-        return 0;
-    }
-    
-    if (inline_functions[i].data && !inline_functions[i].data_emitted) {
-    
-        fputs (inline_functions[i].data, state->ofp);
-        
-        if (inline_functions[i].data[0] && inline_functions[i].data[strlen (inline_functions[i].data) - 1] != '\n') {
-            fputc ('\n', state->ofp);
-        }
-        
-        if (state->syntax & ASM_SYNTAX_MASM) {
-            fprintf (state->ofp, ".code\n");
-        } else if (state->syntax & ASM_SYNTAX_NASM) {
-            fprintf (state->ofp, "section .text\n");
-        } else {
-            fprintf (state->ofp, ".text\n");
-        }
-        
-        inline_functions[i].data_emitted = 1;
-    
-    }
-    
-    if (inline_functions[i].body) {
-    
-        inline_functions[i].expanding = 1;
-        emit_inline_body_substituted (inline_functions[i].body, inline_functions[i].return_label, argc);
-        inline_functions[i].expanding = 0;
-    
-    }
-    
-    if (!inline_functions[i].returns_void && strcmp (reg, "eax") != 0) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-            fprintf (state->ofp, "    mov %s, eax\n", reg);
-        } else {
-            fprintf (state->ofp, "    movl %%eax, %%%s\n", reg);
-        }
-    
-    }
-    
-    return 1;
-
-}
-
-#define     MAX_LOCAL_SYMBOLS           1024
-
-struct local_symbol {
-
-    char *name;
-    
-    int size;
-    int align;
-    
-    int is_floating;
-    long offset;
-    
-    char *static_label;
-    
-    int is_static, is_unsigned;
-    int is_array;
-    int array_element_size;
-    int array_dimensions;
-    
-    int pointer_depth;
-    int pointed_size;
-    int pointed_is_floating;
-    int pointed_is_unsigned;
-    
-    char *pointed_tag_name;
-    char *tag_name;
-
-};
-
-static struct local_symbol local_symbols[MAX_LOCAL_SYMBOLS];
-
-static int local_array_pointer_step_size (const struct local_symbol *sym);
-static int global_array_pointer_step_size (const char *name);
-
-static int aggregate_tag_size_or_zero (const char *tag_name) {
-
-    struct aggregate_tag_entry *entry;
-    
-    if (!tag_name || !tag_name[0]) {
-        return 0;
-    }
-    
-    entry = find_aggregate_tag (tag_name, 0);
-    
-    if (entry && entry->size > 0) {
-        return entry->size;
-    }
-    
-    return 0;
-
-}
-
-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;
-    
-    if (align <= 1) {
-        return value;
-    }
-    
-    mask = (long) align - 1;
-    return (value + mask) & ~mask;
-
-}
-
-static int type_alignment (int size) {
-
-    if (size <= 1) {
-        return 1;
-    }
-    
-    if (size == 2) {
-        return 2;
-    }
-    
-    return 4;
-
-}
-
-static void reset_local_symbols (void) {
-
-    int i;
-    
-    for (i = 0; i < local_symbol_count; i++) {
-    
-        if (local_symbols[i].name) {
-        
-            free (local_symbols[i].name);
-            local_symbols[i].name = 0;
-        
-        }
-        
-        if (local_symbols[i].static_label) {
-        
-            free (local_symbols[i].static_label);
-            local_symbols[i].static_label = 0;
-        
-        }
-        
-        if (local_symbols[i].pointed_tag_name) {
-        
-            free (local_symbols[i].pointed_tag_name);
-            local_symbols[i].pointed_tag_name = 0;
-        
-        }
-        
-        if (local_symbols[i].tag_name) {
-        
-            free (local_symbols[i].tag_name);
-            local_symbols[i].tag_name = 0;
-        
-        }
-    
-    }
-    
-    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;
-    current_function_preserve_assignment64_regs = 0;
-
-}
-
-static void truncate_local_symbols (int count, long stack_size) {
-
-    int i;
-    
-    if (count < 0) {
-        count = 0;
-    }
-    
-    for (i = count; i < local_symbol_count; i++) {
-    
-        if (local_symbols[i].name) {
-        
-            free (local_symbols[i].name);
-            local_symbols[i].name = 0;
-        
-        }
-        
-        if (local_symbols[i].static_label) {
-        
-            free (local_symbols[i].static_label);
-            local_symbols[i].static_label = 0;
-        
-        }
-        
-        if (local_symbols[i].pointed_tag_name) {
-        
-            free (local_symbols[i].pointed_tag_name);
-            local_symbols[i].pointed_tag_name = 0;
-        
-        }
-        
-        if (local_symbols[i].tag_name) {
-        
-            free (local_symbols[i].tag_name);
-            local_symbols[i].tag_name = 0;
-        
-        }
-    
-    }
-    
-    local_symbol_count = count;
-    current_local_stack_size = stack_size;
-
-}
-
-static int local_symbol_exists_in_current_scope (const char *name, int start_count) {
-
-    int i;
-    
-    if (!name) {
-        return 0;
-    }
-    
-    for (i = start_count; i < local_symbol_count; i++) {
-    
-        if (local_symbols[i].name && strcmp (local_symbols[i].name, name) == 0) {
-            return 1;
-        }
-    
-    }
-    
-    return 0;
-
-}
-
-static long add_local_symbol (const char *name, int size, int align, int is_unsigned, int scope_start_count, int line, const char *start, const char *caret) {
-
-    long new_size;
-    
-    if (!name) {
-        return 0;
-    }
-    
-    if (size < 1) {
-        size = 1;
-    }
-    
-    if (align < 1) {
-        align = 1;
-    }
-    
-    if (local_symbol_exists_in_current_scope (name, scope_start_count)) {
-    
-        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "duplicate local symbol '%s'", name);
-        return 0;
-    
-    }
-    
-    if (local_symbol_count >= MAX_LOCAL_SYMBOLS) {
-    
-        report_line_at (get_filename (), line, REPORT_ERROR, start, caret,  "too many local symbols");
-        return 0;
-    
-    }
-    
-    new_size = align_up_long (current_local_stack_size + size, align);
-    
-    /*
-     * EBP-relative locals must be backed by whole stack slots.  Without this,
-     * a byte-sized local following two pointer locals can be assigned offset
-     * -9(%ebp), while the emitted stack adjustment has only reserved 8 bytes.
-     * That is exactly what happened in cpplib/lex.c's _cpp_skip_block_comment:
-     *
-     *     cpp_mffc *mffc;   -> -4
-     *     const char *pos;  -> -8
-     *     char c;           -> -9, outside the reserved frame
-     *
-     * Keep the object's real size for loads/stores, but round the frame growth
-     * so subsequent stack allocation reserves enough bytes before the local is
-     * used.
-     */
-    new_size = align_up_long (new_size, 4);
-    
-    local_symbols[local_symbol_count].name = xstrdup (name);
-    local_symbols[local_symbol_count].size = size;
-    local_symbols[local_symbol_count].align = align;
-    local_symbols[local_symbol_count].offset = -(int) new_size;
-    local_symbols[local_symbol_count].is_static = 0;
-    local_symbols[local_symbol_count].static_label = 0;
-    local_symbols[local_symbol_count].is_unsigned = is_unsigned ? 1 : 0;
-    local_symbols[local_symbol_count].is_floating = 0;
-    local_symbols[local_symbol_count].is_array = 0;
-    local_symbols[local_symbol_count].array_element_size = 0;
-    local_symbols[local_symbol_count].array_dimensions = 0;
-    local_symbols[local_symbol_count].pointer_depth = 0;
-    local_symbols[local_symbol_count].pointed_size = 0;
-    local_symbols[local_symbol_count].pointed_is_floating = 0;
-    local_symbols[local_symbol_count].pointed_is_unsigned = 0;
-    local_symbols[local_symbol_count].pointed_tag_name = 0;
-    local_symbols[local_symbol_count].tag_name = 0;
-    
-    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;
-
-}
-
-static void add_static_local_symbol (const char *name, const char *label, int size, int align, int is_unsigned, int scope_start_count, int line, const char *start, const char *caret) {
-
-    if (!name || !label) {
-        return;
-    }
-    
-    if (size < 1) {
-        size = 1;
-    }
-    
-    if (align < 1) {
-        align = 1;
-    }
-    
-    if (local_symbol_exists_in_current_scope (name, scope_start_count)) {
-    
-        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "duplicate local symbol '%s'", name);
-        return;
-    
-    }
-    
-    if (local_symbol_count >= MAX_LOCAL_SYMBOLS) {
-    
-        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "too many local symbols");
-        return;
-    
-    }
-    
-    local_symbols[local_symbol_count].name = xstrdup (name);
-    local_symbols[local_symbol_count].static_label = xstrdup (label);
-    local_symbols[local_symbol_count].size = size;
-    local_symbols[local_symbol_count].align = align;
-    local_symbols[local_symbol_count].offset = 0;
-    local_symbols[local_symbol_count].is_static = 1;
-    local_symbols[local_symbol_count].is_unsigned = is_unsigned ? 1 : 0;
-    local_symbols[local_symbol_count].is_floating = 0;
-    local_symbols[local_symbol_count].is_array = 0;
-    local_symbols[local_symbol_count].array_element_size = 0;
-    local_symbols[local_symbol_count].array_dimensions = 0;
-    local_symbols[local_symbol_count].pointer_depth = 0;
-    local_symbols[local_symbol_count].pointed_size = 0;
-    local_symbols[local_symbol_count].pointed_is_floating = 0;
-    local_symbols[local_symbol_count].pointed_is_unsigned = 0;
-    local_symbols[local_symbol_count].pointed_tag_name = 0;
-    local_symbols[local_symbol_count].tag_name = 0;
-       
-    local_symbol_count++;
-
-}
-
-static struct local_symbol *find_local_symbol (const char *name);
-
-static void set_local_symbol_array (const char *name, int is_array) {
-
-    struct local_symbol *sym = find_local_symbol (name);
-    
-    if (sym) {
-        sym->is_array = is_array ? 1 : 0;
-    }
-
-}
-
-static void set_local_symbol_array_element_size (const char *name, int elem_size) {
-
-    struct local_symbol *sym = find_local_symbol (name);
-    
-    if (sym) {
-        sym->array_element_size = elem_size > 0 ? elem_size : 0;
-    }
-
-}
-
-static void set_local_symbol_array_dimensions (const char *name, int dims) {
-
-    struct local_symbol *sym = find_local_symbol (name);
-    
-    if (sym) {
-        sym->array_dimensions = dims > 0 ? dims : 0;
-    }
-
-}
-
-static void set_local_symbol_floating (const char *name, int is_floating) {
-
-    int i;
-    
-    if (!name) {
-        return;
-    }
-    
-    for (i = local_symbol_count - 1; i >= 0; i--) {
-    
-        if (local_symbols[i].name && strcmp (local_symbols[i].name, name) == 0) {
-        
-            local_symbols[i].is_floating = is_floating ? 1 : 0;
-            return;
-        
-        }
-    
-    }
-
-}
-
-#define     MAX_PENDING_PARAMS          128
-
-struct pending_param {
-
-    char *name;
-    int align, size;
-    
-    int is_unsigned;
-    int is_floating;
-    
-    int pointer_depth;
-    int pointed_size;
-    int pointed_is_floating;
-    int pointed_is_unsigned;
-    
-    char *pointed_tag_name;
-    int knr_declared;
-
-};
-
-static struct pending_param pending_params[MAX_PENDING_PARAMS];
-
-static int pending_param_count = 0;
-static int declarator_depth = 0;
-static int preserve_pending_params = 0;
-
-static int local_symbol_exists_in_current_scope (const char *name, int start_count);
-
-static void clear_pending_params (void) {
-
-    int i;
-    
-    for (i = 0; i < pending_param_count; i++) {
-    
-        if (pending_params[i].name) {
-        
-            free (pending_params[i].name);
-            pending_params[i].name = 0;
-        
-        }
-        
-        pending_params[i].size = 0;
-        pending_params[i].align = 0;
-        pending_params[i].is_unsigned = 0;
-        pending_params[i].is_floating = 0;
-        pending_params[i].pointer_depth = 0;
-        pending_params[i].pointed_size = 0;
-        pending_params[i].pointed_is_floating = 0;
-        pending_params[i].pointed_is_unsigned = 0;
-        pending_params[i].knr_declared = 0;
-        
-        if (pending_params[i].pointed_tag_name) {
-        
-            free (pending_params[i].pointed_tag_name);
-            pending_params[i].pointed_tag_name = 0;
-        
-        }
-    
-    }
-    
-    pending_param_count = 0;
-
-}
-
-static void add_pending_param (const char *name, int size, int align, int is_unsigned, int is_floating, int pointer_depth, int pointed_size, int pointed_is_unsigned) {
-
-    if (pointer_depth > 0 && parsed_type_is_aggregate && parsed_type_size > (DATA_PTR & 0x1f) && pointed_size <= (DATA_PTR & 0x1f)) {
-        pointed_size = parsed_type_size;
-    }
-    
-    if (pending_param_count >= MAX_PENDING_PARAMS) {
-    
-        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "too many function parameters");
-        return;
-    
-    }
-    
-    if (size < 1) {
-        size = DATA_INT & 0x1f;
-    }
-    
-    if (align < 1) {
-        align = type_alignment (size);
-    }
-    
-    pending_params[pending_param_count].name = (name && *name) ? xstrdup (name) : 0;
-    pending_params[pending_param_count].size = size;
-    pending_params[pending_param_count].align = align;
-    pending_params[pending_param_count].is_unsigned = is_unsigned ? 1 : 0;
-    pending_params[pending_param_count].is_floating = is_floating ? 1 : 0;
-    pending_params[pending_param_count].knr_declared = 0;
-    pending_params[pending_param_count].pointer_depth = pointer_depth;
-    pending_params[pending_param_count].pointed_size = pointed_size > 0 ? pointed_size : 0;
-    pending_params[pending_param_count].pointed_is_floating = pointer_depth > 0 ? (parsed_type_is_floating ? 1 : 0) : 0;
-    pending_params[pending_param_count].pointed_is_unsigned = pointer_depth > 0 ? (pointed_is_unsigned ? 1 : 0) : 0;
-    pending_params[pending_param_count].pointed_tag_name = (pointer_depth > 0 && parsed_type_tag_name[0]) ? xstrdup (parsed_type_tag_name) : 0;
-    
-    pending_param_count++;
-
-}
-
-static int find_pending_param_from (const char *name, int start) {
-
-    int i;
-    
-    if (!name) {
-        return -1;
-    }
-    
-    if (start < 0) {
-        start = 0;
-    }
-    
-    for (i = start; i < pending_param_count; i++) {
-    
-        if (pending_params[i].name && strcmp (pending_params[i].name, name) == 0) {
-            return i;
-        }
-    
-    }
-    
-    return -1;
-
-}
-
-static int find_pending_param (const char *name) {
-    return find_pending_param_from (name, 0);
-}
-
-static void update_pending_param (const char *name, int size, int align, int is_unsigned, int is_floating, int pointer_depth, int pointed_size, int pointed_is_unsigned) {
-
-    int i = find_pending_param (name);
-    
-    if (i < 0) {
-        return;
-    }
-    
-    if (pointer_depth > 0 && parsed_type_is_aggregate && parsed_type_size > (DATA_PTR & 0x1f) && pointed_size <= (DATA_PTR & 0x1f)) {
-        pointed_size = parsed_type_size;
-    }
-    
-    if (size < 1) {
-        size = DATA_INT & 0x1f;
-    }
-    
-    if (align < 1) {
-        align = type_alignment (size);
-    }
-    
-    pending_params[i].size = size;
-    pending_params[i].align = align;
-    pending_params[i].is_unsigned = is_unsigned ? 1 : 0;
-    pending_params[i].is_floating = is_floating ? 1 : 0;
-    pending_params[i].pointer_depth = pointer_depth;
-    pending_params[i].pointed_size = pointed_size > 0 ? pointed_size : 0;
-    pending_params[i].pointed_is_floating = pointer_depth > 0 ? (parsed_type_is_floating ? 1 : 0) : 0;
-    pending_params[i].pointed_is_unsigned = pointer_depth > 0 ? (pointed_is_unsigned ? 1 : 0) : 0;
-    
-    if (pending_params[i].pointed_tag_name) {
-    
-        free (pending_params[i].pointed_tag_name);
-        pending_params[i].pointed_tag_name = 0;
-    
-    }
-    
-    if (pointer_depth > 0 && parsed_type_tag_name[0]) {
-        pending_params[i].pointed_tag_name = xstrdup (parsed_type_tag_name);
-    }
-
-}
-
-static int mark_pending_param_knr_declared (const char *name, const char *name_start, const char *name_caret, unsigned long name_line) {
-
-    int i = find_pending_param (name);
-    
-    if (i < 0) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "K&R parameter '%s' is not in function parameter list", name);
-        return 0;
-    
-    }
-    
-    if (pending_params[i].knr_declared) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "duplicate K&R parameter declaration for '%s'", name);
-        return 0;
-    
-    }
-    
-    pending_params[i].knr_declared = 1;
-    return 1;
-
-}
-
-static void remove_duplicate_pending_params (void) {
-
-    int i;
-    
-    for (i = 0; i < pending_param_count; i++) {
-    
-        int j;
-        
-        if (!pending_params[i].name) {
-            continue;
-        }
-        
-        j = i + 1;
-        
-        while (j < pending_param_count) {
-        
-            if (pending_params[j].name && strcmp (pending_params[i].name, pending_params[j].name) == 0) {
-            
-                int k;
-                
-                if (pending_params[j].name) {
-                    free (pending_params[j].name);
-                }
-                
-                if (pending_params[j].pointed_tag_name) {
-                    free (pending_params[j].pointed_tag_name);
-                }
-                
-                for (k = j; k + 1 < pending_param_count; k++) {
-                    pending_params[k] = pending_params[k + 1];
-                }
-                
-                pending_param_count--;
-                
-                pending_params[pending_param_count].name = 0;
-                pending_params[pending_param_count].size = 0;
-                pending_params[pending_param_count].align = 0;
-                pending_params[pending_param_count].is_unsigned = 0;
-                pending_params[pending_param_count].is_floating = 0;
-                pending_params[pending_param_count].pointer_depth = 0;
-                pending_params[pending_param_count].pointed_size = 0;
-                pending_params[pending_param_count].pointed_tag_name = 0;
-                
-                continue;
-            
-            }
-            
-            j++;
-        
-        }
-    
-    }
-
-}
-
-static void copy_pending_params_to_global_symbol (const char *name) {
-
-    int i = find_global_symbol (name);
-    int pi;
-    
-    if (i < 0) {
-        return;
-    }
-    
-    for (pi = 0; pi < 128; pi++) {
-    
-        global_symbols[i].param_sizes[pi] = 0;
-        global_symbols[i].param_unsigneds[pi] = 0;
-        global_symbols[i].param_floatings[pi] = 0;
-    
-    }
-    
-    for (pi = 0; pi < pending_param_count && pi < 128; pi++) {
-    
-        global_symbols[i].param_sizes[pi] = pending_params[pi].size;
-        global_symbols[i].param_unsigneds[pi] = pending_params[pi].is_unsigned;
-        global_symbols[i].param_floatings[pi] = pending_params[pi].is_floating;
-    
-    }
-
-}
-
-static struct local_symbol *find_local_symbol (const char *name) {
-
-    int i;
-    
-    if (!name) {
-        return 0;
-    }
-    
-    for (i = local_symbol_count - 1; i >= 0; i--) {
-    
-        if (local_symbols[i].name && strcmp (local_symbols[i].name, name) == 0) {
-            return &local_symbols[i];
-        }
-    
-    }
-    
-    return 0;
-
-}
-
-static void set_local_symbol_pointer_info (const char *name, int pointer_depth, int pointed_size) {
-
-    struct local_symbol *sym = find_local_symbol (name);
-    
-    if (pointer_depth > 0 && parsed_type_is_aggregate && parsed_type_size > (DATA_PTR & 0x1f) && pointed_size <= (DATA_PTR & 0x1f)) {
-        pointed_size = parsed_type_size;
-    }
-    
-    if (sym) {
-    
-        sym->pointer_depth = pointer_depth;
-        sym->pointed_size = pointed_size;
-        
-        sym->pointed_is_floating = pointer_depth > 0 ? (parsed_type_is_floating ? 1 : 0) : 0;
-        sym->pointed_is_unsigned = pointer_depth > 0 ? (parsed_type_is_unsigned ? 1 : 0) : 0;
-        
-        if (sym->pointed_tag_name) {
-        
-            free (sym->pointed_tag_name);
-            sym->pointed_tag_name = 0;
-        
-        }
-        
-        if ((pointer_depth > 0 || sym->is_array) && parsed_type_tag_name[0]) {
-            sym->pointed_tag_name = xstrdup (parsed_type_tag_name);
-        }
-    
-    }
-
-}
-
-static void install_pending_params_as_locals (void) {
-
-    long offset = current_function_returns_aggregate ? 12 : 8;
-    int i;
-    
-    for (i = 0; i < pending_param_count; i++) {
-    
-        int slot_size;
-        
-        if (!pending_params[i].name) {
-            continue;
-        }
-        
-        if (local_symbol_count >= MAX_LOCAL_SYMBOLS) {
-        
-            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "too many local symbols");
-            break;
-        
-        }
-        
-        if (local_symbol_exists_in_current_scope (pending_params[i].name, 0)) {
-            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate parameter '%s'", pending_params[i].name);
-        }
-        
-        local_symbols[local_symbol_count].name = xstrdup (pending_params[i].name);
-        local_symbols[local_symbol_count].size = pending_params[i].size;
-        local_symbols[local_symbol_count].align = pending_params[i].align;
-        local_symbols[local_symbol_count].offset = (int) offset;
-        local_symbols[local_symbol_count].is_static = 0;
-        local_symbols[local_symbol_count].static_label = 0;
-        local_symbols[local_symbol_count].is_unsigned = pending_params[i].is_unsigned;
-        local_symbols[local_symbol_count].is_floating = pending_params[i].is_floating;
-        local_symbols[local_symbol_count].pointer_depth = pending_params[i].pointer_depth;
-        local_symbols[local_symbol_count].pointed_is_floating = pending_params[i].pointed_is_floating;
-        local_symbols[local_symbol_count].pointed_is_unsigned = pending_params[i].pointed_is_unsigned;
-        local_symbols[local_symbol_count].is_array = 0;
-        local_symbols[local_symbol_count].array_element_size = 0;
-        local_symbols[local_symbol_count].array_dimensions = 0;
-        local_symbols[local_symbol_count].pointed_size = pending_params[i].pointed_size;
-        local_symbols[local_symbol_count].pointed_tag_name = pending_params[i].pointed_tag_name ? xstrdup (pending_params[i].pointed_tag_name) : 0;
-        local_symbols[local_symbol_count].tag_name = 0;
-        
-        local_symbol_count++;
-        slot_size = pending_params[i].size;
-        
-        if (slot_size < DATA_PTR) {
-            slot_size = DATA_PTR;
-        }
-        
-        slot_size = (int) align_up_long (slot_size, DATA_PTR);
-        offset += slot_size;
-    
-    }
-
-}
-
-#define     MAX_LOCAL_INITS             1024
-
-#define     LOCAL_INIT_CONST            0
-#define     LOCAL_INIT_ADDRESS          1
-#define     LOCAL_INIT_STACK            2
-#define     LOCAL_INIT_GLOBAL           3
-
-struct local_init {
-
-    long offset;
-    
-    int size;
-    int kind;
-    
-    char *symbol;
-    int64_s value;
-    
-    long source_offset;
-    int source_size;
-
-};
-
-static void switch_section (int sec) {
-
-    if (!state->ofp || current_section == sec) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_MASM) {
-        masm_flush_data_line ();
-    }
-    
-    if (sec == SECTION_TEXT) {
-    
-        if (state->syntax & ASM_SYNTAX_NASM) {
-            fprintf (state->ofp, "section .text\n");
-        } else {
-            fprintf (state->ofp, "%s\n", (state->syntax & ASM_SYNTAX_MASM ? ".code" : ".text"));
-        }
-    
-    } else if (sec == SECTION_DATA) {
-    
-        if (state->syntax & ASM_SYNTAX_NASM) {
-            fprintf (state->ofp, "section .data\n");
-        } else {
-            fprintf (state->ofp, ".data\n");
-        }
-    
-    } else if (sec == SECTION_BSS) {
-    
-        if (state->syntax & ASM_SYNTAX_NASM) {
-            fprintf (state->ofp, "section .bss\n");
-        } else {
-            fprintf (state->ofp, "%s\n", (state->syntax & ASM_SYNTAX_MASM ? ".data?" : ".bss"));
-        }
-    
-    }
-    
-    current_section = sec;
-
-}
-
-static int token_is_ms_int_type_name (void) {
-
-    if (tok.kind != TOK_IDENT || !tok.ident) {
-        return 0;
-    }
-    
-    return  strcmp (tok.ident, "__int8") == 0 || strcmp (tok.ident, "__int16") == 0 ||
-                strcmp (tok.ident, "__int32") == 0 || strcmp (tok.ident, "__int64") == 0;
-
-}
-
-static int is_type_start (enum token_kind k) {
-
-    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_DLLIMPORT:
-        case TOK_EXTERN:        case TOK_TYPEDEF:       case TOK_INLINE:
-        case TOK_CONST:         case TOK_VOLATILE:      case TOK_RESTRICT:
-        case TOK_SIGNED:        case TOK_UNSIGNED:
-        case TOK_SHORT:         case TOK_LONG:
-        case TOK_CHAR:          case TOK_INT:           case TOK_VOID:
-        case TOK_FLOAT:         case TOK_DOUBLE:
-        case TOK_STRUCT:        case TOK_UNION:         case TOK_ENUM:
-        
-            return 1;
-        
-        default:
-        
-            break;
-    
-    }
-    
-    return 0;
-
-}
-
-/*static void next (void) {
-    get_token ();
-}*/
-
-static int expect (enum token_kind k, const char *what);
-
-static void parse_declarator (char **out_name);
-static void parse_type_spec (void);
-
-int token_starts_type_name (void) {
-    return is_type_start (tok.kind);
-}
-
-int parse_cast_type_name (int *out_size, int *out_is_unsigned, int *out_is_pointer) {
-
-    int saved_type_size = parsed_type_size;
-    int saved_storage_class = parsed_storage_class;
-    int saved_is_aggregate = parsed_type_is_aggregate;
-    int saved_is_void = parsed_type_is_void;
-    int saved_is_unsigned = parsed_type_is_unsigned;
-    int saved_is_floating = parsed_type_is_floating;
-    int saved_has_tag = parsed_type_has_tag;
-    int saved_is_inline = parsed_type_is_inline;
-    int saved_field_count = parsed_field_count;
-    int saved_fields[MAX_AGG_FIELDS];
-    
-    int saved_declarator_is_pointer = declarator_is_pointer;
-    int saved_declarator_has_array = declarator_has_array;
-    int saved_declarator_has_function = declarator_has_function;
-    int saved_declarator_array_unsized = declarator_array_unsized;
-    int saved_declarator_array_dimensions = declarator_array_dimensions;
-    
-    long saved_declarator_array_count = declarator_array_count;
-    long saved_declarator_first_array_count = declarator_first_array_count;
-    
-    char *name = 0;
-    int size = DATA_INT & 0x1f;
-    int is_unsigned = 0;
-    int is_pointer = 0;
-    int ok = 0;
-    int i;
-    
-    for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
-        saved_fields[i] = parsed_field_sizes[i];
-    }
-    
-    if (is_type_start (tok.kind)) {
-    
-        declarator_is_pointer = 0;
-        declarator_pointer_depth = 0;
-        declarator_has_array = 0;
-        declarator_has_function = 0;
-        declarator_array_unsized = 0;
-        declarator_array_count = 0;
-        
-        parse_type_spec ();
-        
-        size = parsed_type_size & 0x1f;
-        is_unsigned = parsed_type_is_unsigned;
-        
-        if (tok.kind != TOK_RPAREN) {
-            parse_declarator (&name);
-        }
-        
-        if (declarator_is_pointer) {
-        
-            size = DATA_PTR;
-            
-            is_unsigned = 1;
-            is_pointer = 1;
-        
-        }
-        
-        if (tok.kind == TOK_RPAREN) {
-        
-            get_token ();
-            ok = 1;
-        
-        } else {
-            expect (TOK_RPAREN, ")");
-        }
-        
-        if (name) {
-            free (name);
-        }
-    
-    }
-    
-    last_cast_type_tag_name[0] = '\0';
-    last_cast_type_object_size = parsed_type_size & 0x1f;
-    last_cast_type_is_floating = (is_pointer ? 0 : parsed_type_is_floating);
-    
-    if (parsed_type_tag_name[0]) {
-    
-        strncpy (last_cast_type_tag_name, parsed_type_tag_name, sizeof (last_cast_type_tag_name) - 1);
-        last_cast_type_tag_name[sizeof (last_cast_type_tag_name) - 1] = '\0';
-    
-    }
-    
-    if (parsed_type_is_aggregate && parsed_type_size > 0) {
-        last_cast_type_object_size = parsed_type_size;
-    }
-    
-    parsed_type_size = saved_type_size;
-    parsed_storage_class = saved_storage_class;
-    parsed_type_is_aggregate = saved_is_aggregate;
-    parsed_type_is_void = saved_is_void;
-    parsed_type_is_unsigned = saved_is_unsigned;
-    parsed_type_is_floating = saved_is_floating;
-    parsed_type_has_tag = saved_has_tag;
-    parsed_type_is_inline = saved_is_inline;
-    
-    clear_parsed_fields ();
-    
-    for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
-        parsed_field_sizes[i] = saved_fields[i];
-    }
-    
-    parsed_field_count = saved_field_count;
-    
-    declarator_is_pointer = saved_declarator_is_pointer;
-    declarator_has_array = saved_declarator_has_array;
-    declarator_has_function = saved_declarator_has_function;
-    declarator_array_unsized = saved_declarator_array_unsized;
-    declarator_array_count = saved_declarator_array_count;
-    declarator_first_array_count = saved_declarator_first_array_count;
-    declarator_array_dimensions = saved_declarator_array_dimensions;
-    
-    if (out_size) {
-        *out_size = size;
-    }
-    
-    if (out_is_unsigned) {
-        *out_is_unsigned = is_unsigned;
-    }
-    
-    if (out_is_pointer) {
-        *out_is_pointer = is_pointer;
-    }
-    
-    return ok;
-
-}
-
-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;
-    int saved_storage_class = parsed_storage_class;
-    int saved_is_aggregate = parsed_type_is_aggregate;
-    int saved_is_void = parsed_type_is_void;
-    int saved_is_unsigned = parsed_type_is_unsigned;
-    int saved_is_floating = parsed_type_is_floating;
-    int saved_has_tag = parsed_type_has_tag;
-    int saved_is_inline = parsed_type_is_inline;
-    int saved_field_count = parsed_field_count;
-    int saved_fields[MAX_AGG_FIELDS];
-    int saved_declarator_is_pointer = declarator_is_pointer;
-    int saved_declarator_pointer_depth = declarator_pointer_depth;
-    int saved_declarator_has_array = declarator_has_array;
-    int saved_declarator_has_function = declarator_has_function;
-    int saved_declarator_array_unsized = declarator_array_unsized;
-    int saved_declarator_array_dimensions = declarator_array_dimensions;
-    
-    long saved_declarator_array_count = declarator_array_count;
-    long saved_declarator_first_array_count = declarator_first_array_count;
-    
-    char *name = 0;
-    
-    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];
-    }
-    
-    if (is_type_start (tok.kind)) {
-    
-        declarator_is_pointer = 0;
-        declarator_pointer_depth = 0;
-        declarator_has_array = 0;
-        declarator_has_function = 0;
-        declarator_array_unsized = 0;
-        declarator_array_count = 0;
-        
-        parse_type_spec ();
-        
-        size = parsed_type_size & 0x1f;
-        cast_is_floating = parsed_type_is_floating;
-        
-        if (tok.kind != TOK_RPAREN) {
-        
-            parse_declarator (&name);
-            
-            /*
-             * This parser is called after a leading unary '*', for forms such
-             * as *(long long *)p.  The '*' outside the cast performs the
-             * dereference, so the size needed by the caller is the pointed-at
-             * object size, not DATA_PTR.  However, forms produced by va_arg()
-             * for pointer types are one level deeper, e.g. char * becomes
-             * *(char **).  In that case the dereferenced object is itself a
-             * pointer and must be loaded with pointer width.
-             */
-            if (declarator_is_pointer && declarator_pointer_depth > 1) {
-                size = DATA_PTR;
-            }
-        
-        }
-        
-        if (tok.kind == TOK_RPAREN) {
-        
-            get_token ();
-            ok = 1;
-            
-            last_deref_cast_type_is_floating = cast_is_floating;
-        
-        } else {
-            expect (TOK_RPAREN, ")");
-        }
-        
-        if (name) {
-            free (name);
-        }
-    
-    }
-    
-    parsed_type_size = saved_type_size;
-    parsed_storage_class = saved_storage_class;
-    parsed_type_is_aggregate = saved_is_aggregate;
-    parsed_type_is_void = saved_is_void;
-    parsed_type_is_unsigned = saved_is_unsigned;
-    parsed_type_is_floating = saved_is_floating;
-    parsed_type_has_tag = saved_has_tag;
-    parsed_type_is_inline = saved_is_inline;
-    
-    clear_parsed_fields ();
-    
-    for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
-        parsed_field_sizes[i] = saved_fields[i];
-    }
-    
-    parsed_field_count = saved_field_count;
-    
-    declarator_is_pointer = saved_declarator_is_pointer;
-    declarator_pointer_depth = saved_declarator_pointer_depth;
-    declarator_has_array = saved_declarator_has_array;
-    declarator_has_function = saved_declarator_has_function;
-    declarator_array_unsized = saved_declarator_array_unsized;
-    declarator_array_count = saved_declarator_array_count;
-    declarator_first_array_count = saved_declarator_first_array_count;
-    declarator_array_dimensions = saved_declarator_array_dimensions;
-    
-    if (out_size) {
-        *out_size = size;
-    }
-    
-    return ok;
-
-}
-
-static int _accept (enum token_kind k) {
-
-    if (tok.kind == k) {
-    
-        get_token ();
-        return 1;
-    
-    }
-    
-    return 0;
-
-}
-
-static int expect (enum token_kind k, const char *what) {
-
-    if (tok.kind == k) {
-    
-        get_token ();
-        return 1;
-    
-    }
-    
-    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected %s", what);
-    return 0;
-
-}
-
-static int token_is_ident (void) {
-    return tok.kind == TOK_IDENT;
-}
-
-static void skip_balanced_until (enum token_kind stop1, enum token_kind stop2, enum token_kind stop3);
-
-static void emit_load_assignment_rhs_expression_to_reg (const char *reg);
-static void emit_load_floating_rhs_expression_now (int result_size);
-static void emit_store_floating_to_local_now (long offset, int size);
-
-static void consume_comma_expression_tail_before_semi (void) {
-
-    while (tok.kind == TOK_COMMA) {
-    
-        get_token ();
-        emit_load_assignment_rhs_expression_to_reg ("eax");
-    
-    }
-
-}
-
-static void expect_semi_or_recover (void) {
-
-    consume_comma_expression_tail_before_semi ();
-    
-    if (expect (TOK_SEMI, ";")) {
-        return;
-    }
-    
-    skip_balanced_until (TOK_SEMI, TOK_RBRACE, TOK_EOF);
-    
-    if (tok.kind == TOK_SEMI) {
-        get_token ();
-    }
-
-}
-
-static int current_ident_is_known_value (void) {
-
-    int64_s ignored;
-    
-    if (tok.kind != TOK_IDENT) {
-        return 0;
-    }
-    
-    if (find_local_symbol (tok.ident)) {
-        return 1;
-    }
-    
-    if (find_global_symbol (tok.ident) >= 0) {
-        return 1;
-    }
-    
-    if (resolve_enum_constant (tok.ident, &ignored)) {
-        return 1;
-    }
-    
-    return 0;
-
-}
-
-static int recover_unknown_rhs_identifier (void) {
-
-    const char *name;
-    const char *start;
-    const char *caret;
-    
-    unsigned long line;
-    
-    if (tok.kind != TOK_IDENT || current_ident_is_known_value ()) {
-        return 0;
-    }
-    
-    name = tok.ident ? tok.ident : "";
-    start = tok.start;
-    caret = tok.caret;
-    line = get_line_number ();
-    
-    report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "unknown symbol '%s'", name);
-    get_token ();
-    
-    if (tok.kind == TOK_LPAREN) {
-    
-        get_token ();
-        skip_balanced_until (TOK_RPAREN, TOK_SEMI, TOK_EOF);
-        
-        if (tok.kind == TOK_RPAREN) {
-            get_token ();
-        }
-    
-    }
-    
-    return 1;
-
-}
-
-static char *take_ident (void) {
-
-    char *name;
-    
-    if (!token_is_ident ()) {
-        return 0;
-    }
-    
-    name = xstrdup (tok.ident);
-    
-    last_declarator_name_line = get_line_number ();
-    last_declarator_name_start = tok.start;
-    last_declarator_name_caret = tok.caret;
-    
-    if (capture_declarator_name_location && !captured_declarator_name_location) {
-    
-        captured_declarator_name_location = 1;
-        captured_declarator_name_line = last_declarator_name_line;
-        captured_declarator_name_start = last_declarator_name_start;
-        captured_declarator_name_caret = last_declarator_name_caret;
-    
-    }
-    
-    get_token ();
-    return name;
-
-}
-
-static void skip_balanced_until (enum token_kind stop1, enum token_kind stop2, enum token_kind stop3) {
-
-    int paren = 0, brace = 0, brack = 0;
-    
-    while (tok.kind != TOK_EOF) {
-    
-        if (paren == 0 && brace == 0 && brack == 0) {
-        
-            if (tok.kind == stop1 || tok.kind == stop2 || tok.kind == stop3) {
-                return;
-            }
-        
-        }
-        
-        if (tok.kind == TOK_LPAREN) {
-            paren++;
-        } else if (tok.kind == TOK_RPAREN) {
-        
-            if (paren > 0) {
-                paren--;
-            } else {
-            
-                if (stop1 == TOK_RPAREN || stop2 == TOK_RPAREN || stop3 == TOK_RPAREN) {
-                    return;
-                }
-            
-            }
-        
-        } else if (tok.kind == TOK_LBRACE) {
-            brace++;
-        } else if (tok.kind == TOK_RBRACE) {
-        
-            if (brace > 0) {
-                brace--;
-            } else {
-            
-                if (stop1 == TOK_RPAREN || stop2 == TOK_RPAREN || stop3 == TOK_RPAREN) {
-                    return;
-                }
-            
-            }
-        
-        } else if (tok.kind == TOK_LBRACK) {
-            brack++;
-        } else if (tok.kind == TOK_RBRACK) {
-        
-            if (brack > 0) {
-                brack--;
-            } else {
-            
-                if (stop1 == TOK_RPAREN || stop2 == TOK_RPAREN || stop3 == TOK_RPAREN) {
-                    return;
-                }
-            
-            }
-        
-        }
-        
-        get_token ();
-    
-    }
-
-}
-
-/*static void consume_redundant_rparens_before_statement (void) {
-
-    while (tok.kind == TOK_RPAREN) {
-        get_token ();
-    }
-
-}*/
-
-static void skip_initializer (void) {
-
-    if (tok.kind == TOK_LBRACE) {
-        skip_balanced_until (TOK_COMMA, TOK_SEMI, TOK_EOF);
-    } else {
-        skip_balanced_until (TOK_COMMA, TOK_SEMI, TOK_EOF);
-    }
-
-}
-
-static void parse_enum_body (void) {
-
-    int64_s value;
-    zext64 (&value, 0);
-    
-    expect (TOK_LBRACE, "{");
-    
-    while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
-    
-        if (!token_is_ident ()) {
-        
-            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected enum constant");
-            
-            get_token ();
-            continue;
-        
-        } else {
-        
-            char *name;
-            
-            const char *name_start;
-            const char *name_caret;
-            
-            name = xstrdup (tok.ident);
-            
-            name_start = tok.start;
-            name_caret = tok.caret;
-            
-            get_token ();
-            
-            if (_accept (TOK_ASSIGN)) {
-            
-                enum token_kind kill[4];
-                
-                kill[0] = TOK_COMMA;
-                kill[1] = TOK_RBRACE;
-                kill[2] = TOK_EOF;
-                kill[3] = 0;
-                
-                value = expr_const64 (kill);
-            
-            }
-            
-            save_enum_constant (name, value, name_start, name_caret);
-            free (name);
-            
-            inc64 (&value);
-        
-        }
-        
-        if (!_accept (TOK_COMMA)) {
-            break;
-        }
-    
-    }
-    
-    expect (TOK_RBRACE, "}");
-
-}
-
-static void parse_declarator_inner (char **out_name);
-static void parse_declarator (char **out_name);
-
-static void parse_decl_modifier (void) {
-
-    if (tok.kind == TOK_STDCALL) {
-    
-        if (parsed_calling_convention == TOK_EOF && declarator_calling_convention == TOK_EOF) {
-            parsed_calling_convention = TOK_STDCALL;
-        }
-    
-    } else if (tok.kind == TOK_DLLEXPORT) {
-    
-        if (parsed_dllexport) {
-            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate '__dllexport'");
-        } else if (parsed_dllimport) {
-            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "'__dllexport' and '__dllimport' cannot both be specified");
-        } else {
-        
-            declarator_dllexport = 1;
-            parsed_dllexport = 1;
-        
-        }
-    
-    } else if (tok.kind == TOK_DLLIMPORT) {
-    
-        if (parsed_dllimport) {
-            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate '__dllimport'");
-        } else if (parsed_dllexport) {
-            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "'__dllexport' and '__dllimport' cannot both be specified");
-        } else {
-        
-            declarator_dllimport = 1;
-            parsed_dllimport = 1;
-        
-        }
-    
-    }
-    
-    get_token ();
-
-}
-
-static void parse_type_spec (void) {
-
-    int saw = 0;
-    
-    int saw_float = 0;
-    int saw_double = 0;
-    int saw_void = 0;
-    
-    int saw_signed = 0;
-    int saw_unsigned = 0;
-    int saw_real_type = 0;
-    
-    parsed_storage_class = STORAGE_NONE;
-    parsed_type_is_aggregate = 0;
-    parsed_type_is_unsigned = 0;
-    parsed_type_has_tag = 0;
-    parsed_type_tag_name[0] = '\0';
-    parsed_type_is_array_typedef = 0;
-    parsed_type_array_count = 1;
-    parsed_type_array_element_size = DATA_NONE;
-    parsed_type_is_inline = 0;
-    parsed_type_is_void = 0;
-    parsed_type_only_qualifiers = 0;
-    parsed_type_size = DATA_NONE;
-    
-    parsed_calling_convention = TOK_EOF;
-    
-    if (declarator_depth == 0) {
-        declarator_calling_convention = TOK_EOF;
-    }
-    
-    parsed_dllexport = 0;
-    parsed_dllimport = 0;
-    
-    clear_parsed_fields ();
-    
-    while (tok.kind == TOK_AUTO || tok.kind == TOK_REGISTER || tok.kind == TOK_STATIC ||
-           tok.kind == TOK_EXTERN || tok.kind == TOK_TYPEDEF || tok.kind == TOK_CONST ||
-           tok.kind == TOK_VOLATILE || tok.kind == TOK_SIGNED || tok.kind == TOK_UNSIGNED ||
-           tok.kind == TOK_SHORT || tok.kind == TOK_LONG || tok.kind == TOK_CHAR ||
-           tok.kind == TOK_INT || tok.kind == TOK_VOID || tok.kind == TOK_FLOAT ||
-           tok.kind == TOK_DOUBLE || tok.kind == TOK_INLINE || tok.kind == TOK_RESTRICT ||
-           tok.kind == TOK_DLLEXPORT || tok.kind == TOK_DLLIMPORT || tok.kind == TOK_STDCALL || token_is_ms_int_type_name ()) {
-        
-        saw = 1;
-        
-        if (tok.kind == TOK_SIGNED || tok.kind == TOK_UNSIGNED ||
-            tok.kind == TOK_SHORT || tok.kind == TOK_LONG || tok.kind == TOK_CHAR ||
-            tok.kind == TOK_INT || tok.kind == TOK_VOID || tok.kind == TOK_FLOAT ||
-            tok.kind == TOK_DOUBLE || token_is_ms_int_type_name ()) {
-            saw_real_type = 1;
-        }
-        
-        if (tok.kind == TOK_STDCALL || tok.kind == TOK_DLLEXPORT || tok.kind == TOK_DLLIMPORT) {
-        
-            parse_decl_modifier ();
-            continue;
-        
-        } else if (tok.kind == TOK_EXTERN) {
-        
-            if (parsed_storage_class == STORAGE_EXTERN) {
-                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate 'extern'");
-            } else if (parsed_storage_class != STORAGE_NONE) {
-                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple storage classes in declaration specifiers");
-            } else {
-                parsed_storage_class = STORAGE_EXTERN;
-            }
-        
-        } else if (tok.kind == TOK_STATIC) {
-        
-            if (parsed_storage_class == STORAGE_STATIC) {
-                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate 'static'");
-            } else if (parsed_storage_class != STORAGE_NONE) {
-                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple storage classes in declaration specifiers");
-            } else {
-                parsed_storage_class = STORAGE_STATIC;
-            }
-        
-        } else if (tok.kind == TOK_TYPEDEF) {
-        
-            if (parsed_storage_class == STORAGE_TYPEDEF) {
-                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate 'typedef'");
-            } else if (parsed_storage_class != STORAGE_NONE) {
-                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple storage classes in declaration specifiers");
-            } else {
-                parsed_storage_class = STORAGE_TYPEDEF;
-            }
-        
-        } else if (tok.kind == TOK_INLINE) {
-            parsed_type_is_inline = 1;
-        } else if (tok.kind == TOK_CHAR) {
-        
-            if (parsed_type_size == DATA_CHAR) {
-                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate 'char'");
-            } else if (parsed_type_size != DATA_NONE) {
-                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");
-            } else {
-                parsed_type_size = DATA_CHAR;
-            }
-        
-        } else if (tok.kind == TOK_SHORT) {
-        
-            if (parsed_type_size == DATA_SHORT) {
-                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate 'short'");
-            } else if (parsed_type_size != DATA_NONE) {
-                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");
-            } else {
-                parsed_type_size = DATA_SHORT;
-            }
-        
-        } else if (tok.kind == TOK_INT) {
-        
-            if (parsed_type_size == DATA_INT) {
-                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate 'int'");
-            } else if (parsed_type_size != DATA_NONE) {
-                /*report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");*/
-            } else {
-                parsed_type_size = DATA_INT;
-            }
-        
-        } else if (tok.kind == TOK_LONG) {
-        
-            if (parsed_type_size == DATA_LONG) {
-                parsed_type_size = DATA_LLONG;
-            } else if (parsed_type_size == DATA_LLONG) {
-                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "too many 'long' keywords");
-            } else if (parsed_type_size != DATA_NONE) {
-                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");
-            } else {
-                parsed_type_size = DATA_LONG;
-            }
-        
-        } else if (tok.kind == TOK_SIGNED) {
-            saw_signed = 1;
-        } else if (tok.kind == TOK_UNSIGNED) {
-            saw_unsigned = 1;
-        } else if (tok.kind == TOK_FLOAT) {
-        
-            if (parsed_type_size == DATA_FLOAT) {
-                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate 'float'");
-            } else if (parsed_type_size != DATA_NONE) {
-                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");
-            } else {
-            
-                parsed_type_size = DATA_FLOAT;
-                saw_float = 1;
-            
-            }
-        
-        } else if (tok.kind == TOK_DOUBLE) {
-        
-            if (parsed_type_size == DATA_LONG) {
-            
-                parsed_type_size = DATA_DOUBLE;
-                saw_double = 1;
-            
-            } else if (parsed_type_size == DATA_DOUBLE) {
-                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate 'double'");
-            } else if (parsed_type_size != DATA_NONE) {
-                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");
-            } else {
-            
-                parsed_type_size = DATA_DOUBLE;
-                saw_double = 1;
-            
-            }
-        
-        } else if (tok.kind == TOK_VOID) {
-        
-            if (parsed_type_size == DATA_VOID) {
-                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate 'void'");
-            } else if (parsed_type_size != DATA_NONE) {
-                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");
-            } else {
-            
-                parsed_type_size = DATA_VOID;
-                parsed_type_is_void = 1;
-                
-                saw_void = 1;
-            
-            }
-        
-        } else if (token_is_ms_int_type_name ()) {
-        
-            if (strcmp (tok.ident, "__int8") == 0) {
-            
-                if (parsed_type_size != DATA_NONE) {
-                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");
-                } else {
-                    parsed_type_size = DATA_CHAR & 0x1f;
-                }
-            
-            } else if (strcmp (tok.ident, "__int16") == 0) {
-            
-                if (parsed_type_size != DATA_NONE) {
-                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");
-                } else {
-                    parsed_type_size = DATA_SHORT & 0x1f;
-                }
-            
-            } else if (strcmp (tok.ident, "__int32") == 0) {
-            
-                if (parsed_type_size != DATA_NONE) {
-                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");
-                } else {
-                    parsed_type_size = DATA_INT & 0x1f;
-                }
-            
-            } else {
-            
-                if (parsed_type_size != DATA_NONE) {
-                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");
-                } else {
-                    parsed_type_size = DATA_LLONG & 0x1f;
-                }
-            
-            }
-        
-        }
-        
-        get_token ();
-    
-    }
-    
-    /*
-     * Be tolerant of project typedef chains where the base typedef name is
-     * not already known to this parser.  In
-     *
-     *     typedef some_base new_name;
-     *     typedef some_base *new_ptr;
-     *
-     * the declarator name is new_name/new_ptr, not some_base.  Without
-     * consuming the unknown base identifier here, parse_declarator() records
-     * some_base as the typedef name and the real declarator is then parsed as
-     * junk.
-     */
-    if (parsed_storage_class == STORAGE_TYPEDEF && !saw_real_type &&
-        tok.kind == TOK_IDENT && !is_current_typedef_name ()) {
-    
-        get_token ();
-        
-        saw = 1;
-        saw_real_type = 1;
-        
-        parsed_type_size = DATA_INT;
-    
-    }
-    
-    if (parsed_type_size == DATA_NONE) {
-    
-        parsed_type_only_qualifiers = (saw && !saw_real_type) ? 1 : 0;
-        parsed_type_size = DATA_INT;
-    
-    } else if (parsed_type_size == DATA_LONG && state->long64) {
-        parsed_type_size = DATA_LLONG;
-    }
-    
-    parsed_type_size &= 0x1f;
-    
-    if (is_current_typedef_name ()) {
-
-        struct typedef_entry *entry;
-        
-        entry = find_typedef_name (tok.ident);
-        get_token ();
-        
-        load_typedef_name (entry);
-        
-        if (entry && entry->is_aggregate && entry->tag_name && entry->tag_name[0]) {
-        
-            strncpy (parsed_type_tag_name, entry->tag_name, sizeof (parsed_type_tag_name) - 1);
-            parsed_type_tag_name[sizeof (parsed_type_tag_name) - 1] = '\0';
-            
-            parsed_type_has_tag = 1;
-        
-        }
-        
-        parsed_type_only_qualifiers = 0;
-        return;
-    
-    }
-    
-    if (tok.kind == TOK_STRUCT || tok.kind == TOK_UNION) {
-    
-        int is_union = (tok.kind == TOK_UNION);
-        int has_tag = 0;
-        
-        int aggregate_size = 0;
-        int aggregate_align = 1;
-        
-        int aggregate_fields[MAX_AGG_FIELDS];
-        int aggregate_field_count = 0;
-        
-        int union_init_fields[MAX_AGG_FIELDS];
-        int union_init_field_count = 0;
-        int union_init_size = 0;
-        
-        struct aggregate_tag_entry *tag_entry = 0;
-        
-        int aggregate_storage_class = parsed_storage_class;
-        int aggregate_is_inline = parsed_type_is_inline;
-        
-        char *tag_name = 0;
-        int member_info_start = member_info_count;
-        
-        parsed_type_size = DATA_PTR;
-        parsed_type_is_void = 0;
-        
-        clear_parsed_fields ();
-        get_token ();
-        
-        if (token_is_ident ()) {
-        
-            tag_name = xstrdup (tok.ident);
-            strncpy (parsed_type_tag_name, tok.ident, sizeof (parsed_type_tag_name) - 1);
-            
-            parsed_type_tag_name[sizeof (parsed_type_tag_name) - 1] = '\0';
-            has_tag = 1;
-            
-            get_token ();
-        
-        }
-        
-        if (tok.kind == TOK_LBRACE) {
-        
-            get_token ();
-            
-            while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
-            
-                int member_type_size;
-                int member_type_is_floating;
-                int member_is_aggregate;
-                int member_has_tag;
-                
-                int member_fields[MAX_AGG_FIELDS];
-                int member_field_count;
-                
-                int i;
-                
-                if (!is_type_start (tok.kind)) {
-                
-                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected member declaration");
-                    
-                    skip_balanced_until (TOK_SEMI, TOK_RBRACE, TOK_EOF);
-                    _accept (TOK_SEMI);
-                    
-                    continue;
-                
-                }
-                
-                parse_type_spec ();
-                
-                member_type_size = parsed_type_size;
-                member_type_is_floating = parsed_type_is_floating;
-                member_is_aggregate = parsed_type_is_aggregate;
-                member_has_tag = parsed_type_has_tag;
-                member_field_count = parsed_field_count;
-                
-                for (i = 0; i < member_field_count; i++) {
-                    member_fields[i] = parsed_field_sizes[i];
-                }
-                
-                if (tok.kind == TOK_SEMI) {
-
-                    if (member_is_aggregate && !member_has_tag) {
-
-                        int member_init_size = fields_storage_size (member_fields, member_field_count);
-                        
-                        if (is_union) {
-                        
-                            if (member_type_size > aggregate_size) {
-                                aggregate_size = member_type_size;
-                            }
-                            
-                            if (union_init_field_count == 0) {
-                            
-                                union_init_field_count = member_field_count;
-                                
-                                for (i = 0; i < member_field_count; i++) {
-                                    union_init_fields[i] = member_fields[i];
-                                }
-                                
-                                union_init_size = member_init_size;
-                            
-                            }
-                        
-                        } else {
-                        
-                            aggregate_size += member_type_size;
-                            
-                            for (i = 0; i < member_field_count && aggregate_field_count < MAX_AGG_FIELDS; i++) {
-                                aggregate_fields[aggregate_field_count++] = member_fields[i];
-                            }
-                            
-                            if (member_type_size > member_init_size && aggregate_field_count < MAX_AGG_FIELDS) {
-                                aggregate_fields[aggregate_field_count++] = -(member_type_size - member_init_size);
-                            }
-                        
-                        }
-                    
-                    }
-
-                } else {
-                
-                    for (;;) {
-                    
-                        char *member = 0;
-                        
-                        int member_size, repeat;
-                        int init_size;
-                        
-                        int member_info_elem_size;
-                        int member_align;
-                        
-                        parse_declarator (&member);
-                        
-                        if (declarator_is_pointer) {
-                        
-                            member_size = DATA_PTR;
-                            member_field_count = 1;
-                            member_fields[0] = DATA_PTR;
-                        
-                        } else {
-                        
-                            member_size = member_type_size;
-                            
-                            if (member_field_count <= 0) {
-                            
-                                member_field_count = 1;
-                                member_fields[0] = member_type_size;
-                            
-                            }
-                        
-                        }
-                        
-                        member_align = declarator_is_pointer ? type_alignment (DATA_PTR) : type_alignment (member_type_size);
-                        
-                        if (member_align > aggregate_align) {
-                            aggregate_align = member_align;
-                        }
-                        
-                        repeat = 1;
-                        
-                        if (declarator_has_array) {
-                        
-                            repeat = (int) declarator_array_count;
-                            member_size *= declarator_array_count;
-                        
-                        }
-                        
-                        if (_accept (TOK_COLON)) {
-                            skip_balanced_until (TOK_COMMA, TOK_SEMI, TOK_RBRACE);
-                        }
-                        
-                        if (declarator_has_array && declarator_is_pointer) {
-                            member_info_elem_size = DATA_PTR;
-                        } else {
-                        
-                            member_info_elem_size = declarator_is_pointer ?
-                                (declarator_pointer_depth > 1 ? DATA_PTR : (parsed_type_is_aggregate ? parsed_type_size : (parsed_type_size & 0x1f))) :
-                                    (declarator_has_array ? member_type_size : member_size);
-                        
-                        }
-                        
-                        init_size = fields_storage_size (member_fields, member_field_count);
-                        
-                        if (is_union) {
-                        
-                            remember_member_info_ex (member, 0, member_size, member_info_elem_size, declarator_is_pointer ? declarator_pointer_depth : 0, declarator_has_array, declarator_is_pointer ? 0 : member_type_is_floating);
-                            
-                            if (member_size > aggregate_size) {
-                                aggregate_size = member_size;
-                            }
-                            
-                            if (union_init_field_count == 0) {
-                            
-                                union_init_field_count = member_field_count;
-                                
-                                for (i = 0; i < member_field_count; i++) {
-                                    union_init_fields[i] = member_fields[i];
-                                }
-                                
-                                union_init_size = init_size;
-                            
-                            }
-                        
-                        } else {
-                        
-                            int member_offset = (int) align_up_long (aggregate_size, member_align);
-                            int padding = member_offset - aggregate_size;
-                            
-                            int r;
-                            
-                            if (padding > 0 && aggregate_field_count < MAX_AGG_FIELDS) {
-                                aggregate_fields[aggregate_field_count++] = -padding;
-                            }
-                            
-                            aggregate_size = member_offset;
-                            
-                            remember_member_info_ex (member, member_offset, member_size, member_info_elem_size, declarator_is_pointer ? declarator_pointer_depth : 0, declarator_has_array, declarator_is_pointer ? 0 : member_type_is_floating);
-                            aggregate_size += member_size;
-                            
-                            for (r = 0; r < repeat; r++) {
-                            
-                                for (i = 0; i < member_field_count && aggregate_field_count < MAX_AGG_FIELDS; i++) {
-                                    aggregate_fields[aggregate_field_count++] = member_fields[i];
-                                }
-                            
-                            }
-                            
-                            if (member_size > init_size * repeat && aggregate_field_count < MAX_AGG_FIELDS) {
-                                aggregate_fields[aggregate_field_count++] = -(member_size - init_size * repeat);
-                            }
-                        
-                        }
-                        
-                        if (member) {
-                            free (member);
-                        }
-                        
-                        if (!_accept (TOK_COMMA)) {
-                            break;
-                        }
-                    
-                    }
-                
-                }
-                
-                expect (TOK_SEMI, ";");
-            
-            }
-            
-            expect (TOK_RBRACE, "}");
-            
-            if (aggregate_size <= 0) {
-                aggregate_size = DATA_CHAR & 0x1f;
-            }
-            
-            aggregate_size = (int) align_up_long (aggregate_size, aggregate_align);
-            
-            {
-            
-                const char *owner_name = 0;
-                char anon_owner_name[64];
-                
-                int mi;
-                
-                if (has_tag) {
-                    owner_name = tag_name;
-                } else {
-                
-                    sprintf (anon_owner_name, "<anon-aggregate-%d>", anonymous_aggregate_owner_id++);
-                    owner_name = anon_owner_name;
-                
-                }
-                
-                for (mi = member_info_start; mi < member_info_count; mi++) {
-                
-                    if (member_infos[mi].owner_size == 0) {
-                        member_infos[mi].owner_size = aggregate_size;
-                    }
-                    
-                    if (owner_name && member_infos[mi].owner_tag_name == 0) {
-                        member_infos[mi].owner_tag_name = xstrdup (owner_name);
-                    }
-                
-                }
-                
-                if (!has_tag && owner_name) {
-                
-                    strncpy (parsed_type_tag_name, owner_name, sizeof (parsed_type_tag_name) - 1);
-                    parsed_type_tag_name[sizeof (parsed_type_tag_name) - 1] = '\0';
-                
-                }
-            
-            }
-            
-            parsed_type_size = aggregate_size;
-            parsed_type_is_aggregate = 1;
-            parsed_type_is_void = 0;
-            parsed_type_has_tag = has_tag;
-            
-            clear_parsed_fields ();
-
-            if (is_union) {
-            
-                int i;
-                
-                for (i = 0; i < union_init_field_count; i++) {
-                    append_parsed_field (union_init_fields[i]);
-                }
-                
-                if (aggregate_size > union_init_size) {
-                    append_parsed_field (-(aggregate_size - union_init_size));
-                }
-            
-            } else {
-            
-                int i;
-                
-                for (i = 0; i < aggregate_field_count; i++) {
-                    append_parsed_field (aggregate_fields[i]);
-                }
-            
-            }
-            
-            if (tag_name) {
-            
-                save_aggregate_tag (tag_name, is_union, parsed_type_size, parsed_field_sizes, parsed_field_count);
-                update_typedef_name_from_aggregate_tag (tag_name, parsed_type_size, parsed_field_sizes, parsed_field_count);
-            
-            }
-        
-        } else {
-        
-            tag_entry = find_aggregate_tag (tag_name, is_union);
-
-            if (tag_entry) {
-                load_aggregate_tag_fields (tag_entry);
-            } else {
-            
-                parsed_type_size = DATA_PTR;
-                append_parsed_field (DATA_PTR);
-            
-            }
-        
-        }
-        
-        if (tag_name) {
-            free (tag_name);
-        }
-        
-        parsed_storage_class = aggregate_storage_class;
-        parsed_type_is_inline = aggregate_is_inline;
-        
-        return;
-    
-    }
-    
-    if (tok.kind == TOK_ENUM) {
-    
-        parsed_type_size = DATA_INT & 0x1f;
-        parsed_type_is_unsigned = 0;
-        
-        get_token ();
-        
-        if (token_is_ident ()) {
-            get_token ();
-        }
-        
-        if (tok.kind == TOK_LBRACE) {
-            parse_enum_body ();
-        }
-        
-        append_parsed_field (DATA_INT & 0x1f);
-        return;
-    
-    }
-    
-    /*if (saw_void) {
-        parsed_type_size = DATA_INT;
-    }*/
-    
-    parsed_type_is_floating = (saw_float || saw_double) ? 1 : 0;
-    
-    if (saw_signed && saw_unsigned) {
-        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "both signed and unsigned specified");
-    }
-
-    if ((saw_signed || saw_unsigned) && (saw_float || saw_double || saw_void)) {
-        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "signed/unsigned invalid for this type");
-    }
-
-    parsed_type_is_unsigned = saw_unsigned ? 1 : 0;
-    append_parsed_field (parsed_type_size);
-    
-    if (!saw) {
-    
-        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected type");
-        get_token ();
-    
-    }
-
-}
-
-static int declarator_object_size (int base_size);
-
-static void parse_direct_declarator (char **out_name) {
-
-    if (_accept (TOK_LPAREN)) {
-    
-        parse_declarator_inner (out_name);
-        expect (TOK_RPAREN, ")");
-        
-        if (declarator_is_pointer && !declarator_has_function) {
-            declarator_function_is_pointer = 1;
-        }
-    
-    } else if (token_is_ident ()) {
-    
-        if (out_name && !*out_name) {
-            *out_name = take_ident ();
-        } else {
-            get_token ();
-        }
-    
-    }
-    
-    for (;;) {
-    
-        if (_accept (TOK_LBRACK)) {
-        
-            int was_array = declarator_has_array;
-            long count = 1;
-            
-            if (tok.kind != TOK_RBRACK) {
-            
-                enum token_kind kill[3];
-                int v;
-                
-                kill[0] = TOK_RBRACK;
-                kill[1] = TOK_EOF;
-                kill[2] = 0;
-                
-                v = expr_const (kill);
-                
-                if (v > 0) {
-                    count = v;
-                }
-            
-            } else {
-                declarator_array_unsized = 1;
-            }
-            
-            if (!was_array) {
-                declarator_first_array_count = count;
-            }
-            
-            declarator_has_array = 1;
-            declarator_array_dimensions++;
-            
-            if (declarator_array_count <= 0) {
-                declarator_array_count = 1;
-            }
-            
-            declarator_array_count *= count;
-            declarator_last_array_count = count;
-            
-            expect (TOK_RBRACK, "]");
-            continue;
-        
-        }
-        
-        if (_accept (TOK_LPAREN)) {
-        
-            int old_style_param_start = pending_param_count;
-            declarator_has_function = 1;
-            
-            if (tok.kind != TOK_RPAREN) {
-            
-                for (;;) {
-                
-                    if (tok.kind == TOK_ELLIPSIS) {
-                    
-                        declarator_function_is_variadic = 1;
-                        get_token ();
-                    
-                    } else if (is_type_start (tok.kind)) {
-                    
-                        enum token_kind saved_calling_convention = declarator_calling_convention;
-                        enum token_kind saved_parsed_calling_convention = parsed_calling_convention;
-                        
-                        long saved_array_count = declarator_array_count;
-                        
-                        int saved_type_size = parsed_type_size;
-                        int saved_storage_class = parsed_storage_class;
-                        int saved_is_aggregate = parsed_type_is_aggregate;
-                        int saved_is_void = parsed_type_is_void;
-                        int saved_is_unsigned = parsed_type_is_unsigned;
-                        int saved_is_floating = parsed_type_is_floating;
-                        int saved_has_tag = parsed_type_has_tag;
-                        int saved_is_pointer = declarator_is_pointer;
-                        int saved_pointer_depth = declarator_pointer_depth;
-                        int saved_has_array = declarator_has_array;
-                        int saved_has_function = declarator_has_function;
-                        int saved_function_is_pointer = declarator_function_is_pointer;
-                        int saved_function_param_count = declarator_function_param_count;
-                        int saved_function_has_prototype = declarator_function_has_prototype;
-                        int saved_array_unsized = declarator_array_unsized;
-                        int saved_is_inline = parsed_type_is_inline;
-                        
-                        char *param_name = 0;
-                        int param_base_size, param_size;
-                        
-                        int count_this_param = 0;
-                        int saw_void_param_list = 0;
-                        
-                        parse_type_spec ();
-                        param_base_size = parsed_type_size;
-                        
-                        /*
-                         * Parameter declarators must not inherit the outer
-                         * declarator state.  In particular, in declarations
-                         * such as:
-                         *
-                         *     FILE **__gtin(void);
-                         *
-                         * the function return type leaves declarator_is_pointer
-                         * set before the parameter list is parsed.  If that flag
-                         * is still set while looking at the abstract void
-                         * parameter list, void is mistaken for a real pointer
-                         * parameter and the prototype is recorded as taking one
-                         * argument.
-                         */
-                        declarator_is_pointer = 0;
-                        declarator_pointer_depth = 0;
-                        declarator_has_array = 0;
-                        declarator_has_function = 0;
-                        declarator_function_is_pointer = 0;
-                        declarator_array_unsized = 0;
-                        declarator_array_count = 1;
-                        declarator_last_array_count = 1;
-                        
-                        if (parsed_type_only_qualifiers && token_is_ident ()) {
-                            get_token ();
-                        }
-                        
-                        if (tok.kind != TOK_COMMA && tok.kind != TOK_RPAREN) {
-                            parse_declarator (&param_name);
-                        }
-                        
-                        if (!parsed_type_is_void || declarator_is_pointer || declarator_has_array || declarator_has_function || param_name) {
-                        
-                            count_this_param = 1;
-                            param_size = (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef) ? DATA_PTR : declarator_object_size (param_base_size);
-                            
-                            if (declarator_depth == 1) {
-                            
-                                add_pending_param (param_name, param_size, type_alignment (param_size),
-                                    (declarator_is_pointer || parsed_type_is_array_typedef ? 0 : parsed_type_is_unsigned),
-                                        (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef) ? 0 : parsed_type_is_floating,
-                                            declarator_pointer_depth, parsed_type_is_aggregate ? parsed_type_size : (parsed_type_size & 0x1f), parsed_type_is_unsigned);
-                            
-                            }
-                        
-                        } else {
-                            saw_void_param_list = 1;
-                        }
-                        
-                        if (param_name) {
-                            free (param_name);
-                        }
-                        
-                        parsed_calling_convention = saved_parsed_calling_convention;
-                        parsed_type_size = saved_type_size;
-                        parsed_storage_class = saved_storage_class;
-                        parsed_type_is_aggregate = saved_is_aggregate;
-                        parsed_type_is_void = saved_is_void;
-                        parsed_type_is_unsigned = saved_is_unsigned;
-                        parsed_type_is_floating = saved_is_floating;
-                        parsed_type_has_tag = saved_has_tag;
-                        parsed_type_is_inline = saved_is_inline;
-                        
-                        declarator_calling_convention = saved_calling_convention;
-                        declarator_is_pointer = saved_is_pointer;
-                        declarator_pointer_depth = saved_pointer_depth;
-                        declarator_has_array = saved_has_array;
-                        declarator_has_function = saved_has_function;
-                        declarator_function_is_pointer = saved_function_is_pointer;
-                        declarator_function_param_count = saved_function_param_count + (count_this_param ? 1 : 0);
-                        declarator_function_has_prototype = saved_function_has_prototype || count_this_param || saw_void_param_list;
-                        declarator_array_count = saved_array_count;
-                        
-                        declarator_array_unsized = saved_array_unsized;
-                    
-                    } else if (token_is_ident ()) {
-                    
-                        char *maybe_type_name = xstrdup (tok.ident);
-                        int unknown_typedef_pointer = 0;
-                        int consumed_as_prototype_param = 0;
-                        
-                        get_token ();
-                        
-                        while (tok.kind == TOK_CONST || tok.kind == TOK_VOLATILE || tok.kind == TOK_RESTRICT) {
-                            get_token ();
-                        }
-                        
-                        while (tok.kind == TOK_STAR) {
-                        
-                            unknown_typedef_pointer = 1;
-                            get_token ();
-                            
-                            while (tok.kind == TOK_CONST || tok.kind == TOK_VOLATILE || tok.kind == TOK_RESTRICT) {
-                                get_token ();
-                            }
-                        
-                        }
-                        
-                        if (token_is_ident ()) {
-                        
-                            char *param_name = xstrdup (tok.ident);
-                            int param_size = unknown_typedef_pointer ? DATA_PTR : DATA_PTR;
-                            
-                            get_token ();
-                            
-                            if (declarator_depth == 1) {
-                            
-                                if (find_pending_param_from (param_name, old_style_param_start) >= 0) {
-                                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate parameter '%s'", param_name);
-                                } else {
-                                    add_pending_param (param_name, param_size, type_alignment (param_size), 0, 0, unknown_typedef_pointer ? 1 : 0, DATA_INT & 0x1f, 0);
-                                }
-                            
-                            }
-                            
-                            free (param_name);
-                            
-                            declarator_function_param_count++;
-                            declarator_function_has_prototype = 1;
-                            consumed_as_prototype_param = 1;
-                        
-                        }
-                        
-                        if (!consumed_as_prototype_param) {
-                        
-                            if (declarator_depth == 1) {
-                            
-                                if (find_pending_param_from (maybe_type_name, old_style_param_start) >= 0) {
-                                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate parameter '%s'", maybe_type_name);
-                                } else {
-                                    add_pending_param (maybe_type_name, DATA_INT & 0x1f, type_alignment (DATA_INT & 0x1f), 0, 0, 0, 0, 0);
-                                }
-                            
-                            }
-                            
-                            declarator_function_param_count++;
-                        
-                        }
-                        
-                        if (maybe_type_name) {
-                            free (maybe_type_name);
-                        }
-                    
-                    } else {
-                        skip_balanced_until (TOK_COMMA, TOK_RPAREN, TOK_EOF);
-                    }
-                    
-                    if (!_accept (TOK_COMMA)) {
-                        break;
-                    }
-                
-                }
-            
-            }
-            
-            expect (TOK_RPAREN, ")");
-            continue;
-        }
-        
-        break;
-    
-    }
-
-}
-
-static void parse_declarator_inner (char **out_name) {
-
-    while (tok.kind == TOK_STDCALL || tok.kind == TOK_DLLEXPORT || tok.kind == TOK_DLLIMPORT) {
-    
-        if (tok.kind == TOK_STDCALL) {
-        
-            if (declarator_calling_convention == TOK_EOF && parsed_calling_convention == TOK_EOF) {
-                declarator_calling_convention = tok.kind;
-            }
-            
-            get_token ();
-        
-        } else {
-            parse_decl_modifier ();
-        }
-    
-    }
-    
-    while (tok.kind == TOK_STAR) {
-    
-        declarator_is_pointer = 1;
-        declarator_pointer_depth++;
-        
-        get_token ();
-        
-        while (tok.kind == TOK_CONST || tok.kind == TOK_VOLATILE || tok.kind == TOK_RESTRICT || tok.kind == TOK_STDCALL || tok.kind == TOK_DLLEXPORT || tok.kind == TOK_DLLIMPORT) {
-        
-            if (tok.kind == TOK_STDCALL) {
-            
-                if (declarator_calling_convention == TOK_EOF && parsed_calling_convention == TOK_EOF) {
-                    declarator_calling_convention = tok.kind;
-                }
-                
-                get_token ();
-            
-            } else if (tok.kind == TOK_DLLEXPORT || tok.kind == TOK_DLLIMPORT) {
-                parse_decl_modifier ();
-            } else {
-                get_token ();
-            }
-        
-        }
-    
-    }
-    
-    parse_direct_declarator (out_name);
-
-}
-
-static void parse_declarator (char **out_name) {
-
-    int top_level = (declarator_depth == 0);
-    
-    int saved_capture_declarator_name_location = capture_declarator_name_location;
-    int saved_captured_declarator_name_location = captured_declarator_name_location;
-
-    const char *saved_captured_declarator_name_start = captured_declarator_name_start;
-    const char *saved_captured_declarator_name_caret = captured_declarator_name_caret;
-
-    enum token_kind saved_declarator_calling_convention = declarator_calling_convention;
-    
-    int saved_declarator_dllexport = declarator_dllexport;
-    int saved_declarator_dllimport = declarator_dllimport;
-    
-    unsigned long saved_captured_declarator_name_line = captured_declarator_name_line;
-    
-    if (top_level) {
-    
-        if (!preserve_pending_params) {
-            clear_pending_params ();
-        }
-        
-        declarator_calling_convention = TOK_EOF;
-        capture_declarator_name_location = 1;
-        
-        declarator_dllexport = 0;
-        declarator_dllimport = 0;
-        
-        captured_declarator_name_location = 0;
-        captured_declarator_name_start = 0;
-        captured_declarator_name_caret = 0;
-        captured_declarator_name_line = 0;
-    
-    }
-    
-    declarator_depth++;
-    
-    declarator_is_pointer = 0;
-    declarator_pointer_depth = 0;
-    declarator_has_array = 0;
-    declarator_has_function = 0;
-    declarator_function_is_pointer = 0;
-    declarator_function_param_count = 0;
-    declarator_function_has_prototype = 0;
-    declarator_function_is_variadic = 0;
-    declarator_array_unsized = 0;
-    declarator_array_count = 1;
-    declarator_first_array_count = 1;
-    declarator_last_array_count = 1;
-    declarator_array_dimensions = 0;
-    
-    parse_declarator_inner (out_name);
-    
-    if (top_level && parsed_type_is_array_typedef && !declarator_is_pointer && !declarator_has_array && !declarator_has_function) {
-    
-        declarator_has_array = 1;
-        
-        declarator_array_count = parsed_type_array_count > 0 ? parsed_type_array_count : 1;
-        declarator_first_array_count = declarator_array_count;
-        declarator_last_array_count = declarator_array_count;
-        declarator_array_dimensions = 1;
-        
-        if (parsed_type_array_element_size > 0) {
-            parsed_type_size = parsed_type_array_element_size;
-        }
-    
-    }
-    
-    declarator_depth--;
-    
-    if (top_level) {
-    
-        if (captured_declarator_name_location) {
-        
-            last_declarator_name_line = captured_declarator_name_line;
-            last_declarator_name_start = captured_declarator_name_start;
-            last_declarator_name_caret = captured_declarator_name_caret;
-        
-        }
-        
-        capture_declarator_name_location = saved_capture_declarator_name_location;
-        captured_declarator_name_location = saved_captured_declarator_name_location;
-        captured_declarator_name_start = saved_captured_declarator_name_start;
-        captured_declarator_name_caret = saved_captured_declarator_name_caret;
-        captured_declarator_name_line = saved_captured_declarator_name_line;
-    
-    } else {
-    
-        declarator_calling_convention = saved_declarator_calling_convention;
-        declarator_dllexport = saved_declarator_dllexport;
-        declarator_dllimport = saved_declarator_dllimport;
-    
-    }
-
-}
-
-static void apply_typedef_array_to_declarator (void) {
-
-    if (parsed_type_is_array_typedef && !declarator_is_pointer && !declarator_has_array && !declarator_has_function) {
-    
-        declarator_has_array = 1;
-        
-        declarator_array_count = parsed_type_array_count > 0 ? parsed_type_array_count : 1;
-        declarator_first_array_count = declarator_array_count;
-        declarator_last_array_count = declarator_array_count;
-        declarator_array_dimensions = 1;
-        
-        if (parsed_type_array_element_size > 0) {
-            parsed_type_size = parsed_type_array_element_size;
-        }
-    
-    }
-
-}
-
-static void parse_old_style_param_decls (void) {
-
-    while (is_type_start (tok.kind)) {
-    
-        int param_base_size;
-        
-        parse_type_spec ();
-        param_base_size = parsed_type_size;
-        
-        for (;;) {
-        
-            char *name = 0;
-            
-            int param_size;
-            int param_pointer_depth;
-            
-            preserve_pending_params++;
-            parse_declarator (&name);
-            preserve_pending_params--;
-            
-            if (name) {
-            
-                param_size = (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef) ? DATA_PTR : declarator_object_size (param_base_size);
-                param_pointer_depth = declarator_pointer_depth;
-                
-                if ((declarator_has_array || declarator_has_function || parsed_type_is_array_typedef) && param_pointer_depth < 1) {
-                    param_pointer_depth = 1;
-                }
-                
-                if (mark_pending_param_knr_declared (name, last_declarator_name_start, last_declarator_name_caret, last_declarator_name_line)) {
-                
-                    update_pending_param (name, param_size, type_alignment (param_size),
-                        (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef ? 0 : parsed_type_is_unsigned),
-                            (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef ? 0 : parsed_type_is_floating),
-                                param_pointer_depth, parsed_type_is_aggregate ? parsed_type_size : (parsed_type_size & 0x1f), parsed_type_is_unsigned);
-                
-                }
-                
-                free (name);
-            
-            }
-            
-            if (_accept (TOK_ASSIGN)) {
-                skip_initializer ();
-            }
-            
-            if (!_accept (TOK_COMMA)) {
-                break;
-            }
-        
-        }
-        
-        expect (TOK_SEMI, ";");
-    
-    }
-
-}
-
-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;
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    asm_name = asm_global_symbol_name (name);
-    switch_section (SECTION_TEXT);
-    
-    if (state->syntax & ASM_SYNTAX_MASM) {
-    
-        masm_flush_data_line ();
-        
-        if (!is_static) {
-            fprintf (state->ofp, "public %s\n", asm_name);
-        }
-    
-    } else if (state->syntax & ASM_SYNTAX_NASM) {
-    
-        if (!is_static) {
-            fprintf (state->ofp, "global %s\n", asm_name);
-        }
-    
-    } else {
-    
-        if (!is_static) {
-            fprintf (state->ofp, ".globl %s\n", asm_name);
-        }
-    
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        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 ();
-    
-    }
-
-}
-
-static void emit_pending_return_jump (void) {
-
-    if (!pending_return_jump) {
-        return;
-    }
-    
-    if (!state->ofp) {
-    
-        pending_return_jump = 0;
-        return;
-    
-    }
-    
-    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
-        fprintf (state->ofp, "    jmp L%d\n", current_return_label);
-    } else {
-        fprintf (state->ofp, "    jmp .L%d\n", current_return_label);
-    }
-    
-    pending_return_jump = 0;
-
-}
-
-static void emit_stack_adjust (long bytes, int allocate) {
-
-    if (!state->ofp || bytes <= 0) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-        fprintf (state->ofp, "    %s esp, %ld\n", allocate ? "sub" : "add", bytes);
-    } else {
-        fprintf (state->ofp, "    %s $%ld, %%esp\n", allocate ? "subl" : "addl", bytes);
-    }
-
-}
-
-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) {
-        return;
-    }
-    
-    if (offset < 0) {
-        sprintf (buf, "[ebp - %ld]", -offset);
-    } else if (offset > 0) {
-        sprintf (buf, "[ebp + %ld]", offset);
-    } else {
-        sprintf (buf, "[ebp]");
-    }
-
-}
-
-static const char *format_nasm_memory_operand (char *buf, size_t bufsz, const char *operand) {
-
-    if (!operand) {
-        return operand;
-    }
-    
-    if (!(state->syntax & ASM_SYNTAX_NASM)) {
-        return operand;
-    }
-    
-    if (operand[0] == '[') {
-        return operand;
-    }
-    
-    if (buf && bufsz > 0) {
-    
-        sprintf (buf, "[%s]", operand);
-        return buf;
-    
-    }
-    
-    return operand;
-
-}
-
-static void emit_local_store_const (long offset, int size, int64_s value) {
-
-    char memref_hi[64], memref[64];
-    unsigned long high, low;
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    low = value.low;
-    high = value.high;
-    
-    if (size > 8 && low == 0 && high == 0) {
-    
-        long pos;
-        
-        for (pos = 0; pos < size; pos += 4) {
-            emit_local_store_const (offset + pos, DATA_INT, value);
-        }
-        
-        return;
-    
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        format_intel_ebp_offset (memref, sizeof (memref), offset);
-        
-        if (size == (DATA_CHAR & 0x1f)) {
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov byte %s, %lu\n" : "    mov byte ptr %s, %lu\n"), memref, low & ((1 << 8) - 1));
-        } else if (size == (DATA_SHORT & 0x1f)) {
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov word %s, %lu\n" : "    mov word ptr %s, %lu\n"), memref, low & ((1 << 16) - 1));
-        } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
-        
-            format_intel_ebp_offset (memref_hi, sizeof (memref_hi), offset + 4);
-            
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword %s, %lu\n" : "    mov dword ptr %s, %lu\n"), memref, low & U32_MASK);
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword %s, %lu\n" : "    mov dword ptr %s, %lu\n"), memref_hi, high & U32_MASK);
-        
-        } else {
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword %s, %lu\n" : "    mov dword ptr %s, %lu\n"), memref, low & U32_MASK);
-        }
-    
-    } else {
-    
-        if (size == (DATA_CHAR & 0x1f)) {
-            fprintf (state->ofp, "    movb $%lu, %ld(%%ebp)\n", low & 0xffUL, offset);
-        } else if (size == (DATA_SHORT & 0x1f)) {
-            fprintf (state->ofp, "    movw $%lu, %ld(%%ebp)\n", low & 0xffffUL, offset);
-        } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
-        
-            fprintf (state->ofp, "    movl $%lu, %ld(%%ebp)\n", low & U32_MASK, offset);
-            fprintf (state->ofp, "    movl $%lu, %ld(%%ebp)\n", high & U32_MASK, offset + 4);
-        
-        } else {
-            fprintf (state->ofp, "    movl $%lu, %ld(%%ebp)\n", low & U32_MASK, offset);
-        }
-    
-    }
-
-}
-
-static void emit_store_floating_to_local_now (long offset, int size) {
-
-    char memref[64];
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        format_intel_ebp_offset (memref, sizeof (memref), offset);
-        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fstp %s %s\n" : "    fstp %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", memref);
-    
-    } else {
-        fprintf (state->ofp, "    fstp%s %ld(%%ebp)\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", offset);
-    }
-
-}
-
-static void emit_local_store_address (long offset, const char *symbol) {
-
-    const char *asm_symbol;
-    char memref[64];
-    
-    if (!state->ofp || !symbol) {
-        return;
-    }
-    
-    emit_extern_reference_symbol (symbol, DATA_PTR);
-    asm_symbol = asm_global_symbol_name (symbol);
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        format_intel_ebp_offset (memref, sizeof (memref), offset);
-        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword %s, %s\n" : "    mov dword ptr %s, offset %s\n"), memref, asm_symbol);
-    
-    } else {
-        fprintf (state->ofp, "    movl $%s, %ld(%%ebp)\n", asm_symbol, offset);
-    }
-
-}
-
-static void emit_local_store_stack (long dst_offset, int dst_size, long src_offset, int src_size) {
-
-    char dst[64];
-    char src[64];
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        format_intel_ebp_offset (dst, sizeof (dst), dst_offset);
-        format_intel_ebp_offset (src, sizeof (src), src_offset);
-
-        if (dst_size == (DATA_CHAR & 0x1f)) {
-        
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov al, byte %s\n" : "    mov al, byte ptr %s\n"), src);
-            fprintf (state->ofp, "    mov byte ptr %s, al\n", dst);
-        
-        } else if (dst_size == (DATA_SHORT & 0x1f)) {
-        
-            if (src_size == (DATA_CHAR & 0x1f)) {
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov ax, byte %s\n" : "    movzx ax, byte ptr %s\n"), src);
-            } else {
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov ax, word %s\n" : "    mov ax, word ptr %s\n"), src);
-            }
-            
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov word %s, ax\n" : "    mov word ptr %s, ax\n"), dst);
-        
-        } else {
-        
-            if (src_size == (DATA_CHAR & 0x1f)) {
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movzx eax, byte %s\n" : "    movzx eax, byte ptr %s\n"), src);
-            } else if (src_size == (DATA_SHORT & 0x1f)) {
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movzx eax, word %s\n" : "    movzx eax, word ptr %s\n"), src);
-            } else {
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov eax, dword %s\n" : "    mov eax, dword ptr %s\n"), src);
-            }
-            
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword %s, eax\n" : "    mov dword ptr %s, eax\n"), dst);
-        
-        }
-    
-    } else {
-    
-        if (dst_size == (DATA_CHAR & 0x1f)) {
-        
-            fprintf (state->ofp, "    movb %ld(%%ebp), %%al\n", src_offset);
-            fprintf (state->ofp, "    movb %%al, %ld(%%ebp)\n", dst_offset);
-        
-        } else if (dst_size == (DATA_SHORT & 0x1f)) {
-        
-            fprintf (state->ofp, "    movw %ld(%%ebp), %%ax\n", src_offset);
-            fprintf (state->ofp, "    movw %%ax, %ld(%%ebp)\n", dst_offset);
-        
-        } else {
-        
-            fprintf (state->ofp, "    movl %ld(%%ebp), %%eax\n", src_offset);
-            fprintf (state->ofp, "    movl %%eax, %ld(%%ebp)\n", dst_offset);
-        
-        }
-    
-    }
-
-}
-
-static void emit_local_store_global (long dst_offset, int dst_size, const char *symbol) {
-
-    const char *asm_symbol;
-    char dst[64];
-    
-    if (!state->ofp || !symbol) {
-        return;
-    }
-    
-    emit_extern_reference_symbol (symbol, get_global_symbol_size (symbol));
-    asm_symbol = asm_global_symbol_name (symbol);
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        format_intel_ebp_offset (dst, sizeof (dst), dst_offset);
-        
-        if (dst_size == (DATA_CHAR & 0x1f)) {
-        
-            if (state->syntax & ASM_SYNTAX_NASM) {
-            
-                fprintf (state->ofp, "    mov al, byte [%s]\n", asm_symbol);
-                fprintf (state->ofp, "    mov byte %s, al\n", dst);
-            
-            } else {
-            
-                fprintf (state->ofp, "    mov al, byte ptr %s\n", asm_symbol);
-                fprintf (state->ofp, "    mov byte ptr %s, al\n", dst);
-            
-            }
-        
-        } else if (dst_size == (DATA_SHORT & 0x1f)) {
-        
-            if (state->syntax & ASM_SYNTAX_NASM) {
-            
-                fprintf (state->ofp, "    mov ax, word [%s]\n", asm_symbol);
-                fprintf (state->ofp, "    mov word %s, ax\n", dst);
-            
-            } else {
-            
-                fprintf (state->ofp, "    mov ax, word ptr %s\n", asm_symbol);
-                fprintf (state->ofp, "    mov word ptr %s, ax\n", dst);
-            
-            }
-        
-        } else {
-        
-            if (state->syntax & ASM_SYNTAX_NASM) {
-            
-                fprintf (state->ofp, "    mov eax, dword [%s]\n", asm_symbol);
-                fprintf (state->ofp, "    mov dword %s, eax\n", dst);
-            
-            } else {
-            
-                fprintf (state->ofp, "    mov eax, dword ptr %s\n", asm_symbol);
-                fprintf (state->ofp, "    mov dword ptr %s, eax\n", dst);
-            
-            }
-        
-        }
-    
-    } else {
-    
-        if (dst_size == (DATA_CHAR & 0x1f)) {
-        
-            fprintf (state->ofp, "    movb %s, %%al\n", asm_symbol);
-            fprintf (state->ofp, "    movb %%al, %ld(%%ebp)\n", dst_offset);
-        
-        } else if (dst_size == (DATA_SHORT & 0x1f)) {
-        
-            fprintf (state->ofp, "    movw %s, %%ax\n", asm_symbol);
-            fprintf (state->ofp, "    movw %%ax, %ld(%%ebp)\n", dst_offset);
-        
-        } else {
-        
-            fprintf (state->ofp, "    movl %s, %%eax\n", asm_symbol);
-            fprintf (state->ofp, "    movl %%eax, %ld(%%ebp)\n", dst_offset);
-        
-        }
-    
-    }
-
-}
-
-static void emit_local_initializers (struct local_init *inits, int init_count) {
-
-    int i;
-    
-    for (i = 0; i < init_count; i++) {
-    
-        if (inits[i].kind == LOCAL_INIT_ADDRESS) {
-            emit_local_store_address (inits[i].offset, inits[i].symbol);
-        } else if (inits[i].kind == LOCAL_INIT_STACK) {
-            emit_local_store_stack (inits[i].offset, inits[i].size, inits[i].source_offset, inits[i].source_size);
-        } else if (inits[i].kind == LOCAL_INIT_GLOBAL) {
-            emit_local_store_global (inits[i].offset, inits[i].size, inits[i].symbol);
-        } else {
-            emit_local_store_const (inits[i].offset, inits[i].size, inits[i].value);
-        }
-        
-        if (inits[i].symbol) {
-        
-            free (inits[i].symbol);
-            inits[i].symbol = 0;
-        
-        }
-    
-    }
-
-}
-
-static void emit_function_end (void) {
-
-    patch_deferred_function_frame ();
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
-    
-        fprintf (state->ofp, "L%d:\n", current_return_label);
-        
-        if (current_function_returns_aggregate) {
-        
-            if (state->syntax & ASM_SYNTAX_NASM) {
-                fprintf (state->ofp, "    mov eax, dword [ebp + 8]\n");
-            } else {
-                fprintf (state->ofp, "    mov eax, dword ptr [ebp + 8]\n");
-            }
-        
-        }
-        
-        if (current_function_preserve_assignment64_regs) {
-            fprintf (state->ofp, "__SCC_RESTORE_ASSIGNMENT64_REGS__\n");
-        }
-        
-        fprintf (state->ofp, "    leave\n");
-        
-        if (current_function_calling_convention == TOK_STDCALL && current_function_param_stack_bytes > 0) {
-            fprintf (state->ofp, "    ret %d\n", current_function_param_stack_bytes);
-        } else {
-            fprintf (state->ofp, "    ret\n");
-        }
-    
-    } else {
-    
-        fprintf (state->ofp, ".L%d:\n", current_return_label);
-        
-        if (current_function_returns_aggregate) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                fprintf (state->ofp, "    mov eax, dword ptr [ebp + 8]\n");
-            } else {
-                fprintf (state->ofp, "    movl 8(%%ebp), %%eax\n");
-            }
-        
-        }
-        
-        if (current_function_preserve_assignment64_regs) {
-            fprintf (state->ofp, "__SCC_RESTORE_ASSIGNMENT64_REGS__\n");
-        }
-        
-        fprintf (state->ofp, "    leave\n");
-        
-        if (current_function_calling_convention == TOK_STDCALL && current_function_param_stack_bytes > 0) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                fprintf (state->ofp, "    ret %d\n", current_function_param_stack_bytes);
-            } else {
-                fprintf (state->ofp, "    ret $%d\n", current_function_param_stack_bytes);
-            }
-        
-        } else {
-            fprintf (state->ofp, "    ret\n");
-        }
-    
-    }
-
-}
-
-static void emit_preserve_assignment64_regs (enum token_kind op) {
-
-    if (current_function_frame_deferred) {
-    
-        current_function_preserve_assignment64_regs = 1;
-        return;
-    
-    }
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        fprintf (state->ofp, "    push ebx\n");
-        
-        if (op == TOK_STAREQ || op == TOK_STAR || op == TOK_SLASHEQ || op == TOK_BSLASH || op == TOK_MODEQ || op == TOK_MOD) {
-        
-            fprintf (state->ofp, "    push esi\n");
-            fprintf (state->ofp, "    push edi\n");
-        
-        }
-    
-    } else {
-    
-        fprintf (state->ofp, "    pushl %%ebx\n");
-        
-        if (op == TOK_STAREQ || op == TOK_STAR || op == TOK_SLASHEQ || op == TOK_BSLASH || op == TOK_MODEQ || op == TOK_MOD) {
-        
-            fprintf (state->ofp, "    pushl %%esi\n");
-            fprintf (state->ofp, "    pushl %%edi\n");
-        
-        }
-    
-    }
-
-}
-
-static void emit_restore_assignment64_regs (enum token_kind op) {
-
-    if (current_function_frame_deferred) {
-        return;
-    }
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (op == TOK_STAREQ || op == TOK_STAR || op == TOK_SLASHEQ || op == TOK_BSLASH || op == TOK_MODEQ || op == TOK_MOD) {
-        
-            fprintf (state->ofp, "    pop edi\n");
-            fprintf (state->ofp, "    pop esi\n");
-        
-        }
-        
-        fprintf (state->ofp, "    pop ebx\n");
-    
-    } else {
-    
-        if (op == TOK_STAREQ || op == TOK_STAR || op == TOK_SLASHEQ || op == TOK_BSLASH || op == TOK_MODEQ || op == TOK_MOD) {
-        
-            fprintf (state->ofp, "    popl %%edi\n");
-            fprintf (state->ofp, "    popl %%esi\n");
-        
-        }
-        
-        fprintf (state->ofp, "    popl %%ebx\n");
-    
-    }
-
-}
-
-static int is_string_token (void);
-static void parse_string_initializer_values (int64_s *values, int max_values, int *count);
-
-static int parse_constexpr_null_member_address_after_lparen (int64_s *out) {
-
-    char current_tag_name[128];
-    
-    int current_object_size;
-    unsigned long total_offset = 0;
-    
-    if (tok.kind != TOK_LPAREN) {
-        return 0;
-    }
-    
-    get_token ();
-    
-    if (tok.kind != TOK_LPAREN) {
-        return 0;
-    }
-    
-    get_token ();
-    
-    if (!parse_cast_type_name (0, 0, 0)) {
-        return 0;
-    }
-    
-    current_tag_name[0] = '\0';
-    
-    if (last_cast_type_tag_name[0]) {
-    
-        strncpy (current_tag_name, last_cast_type_tag_name, sizeof (current_tag_name) - 1);
-        current_tag_name[sizeof (current_tag_name) - 1] = '\0';
-    
-    }
-    
-    current_object_size = last_cast_type_object_size;
-    
-    if (!((tok.kind == TOK_CINT || tok.kind == TOK_CUINT || tok.kind == TOK_CLONG ||
-           tok.kind == TOK_CULONG || tok.kind == TOK_CLLONG || tok.kind == TOK_CULLONG) &&
-          tok.val.i.low == 0 && tok.val.i.high == 0)) {
-        return 0;
-    }
-    
-    get_token ();
-    expect (TOK_RPAREN, ")");
-    
-    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
-    
-        enum token_kind member_op = tok.kind;
-        char *member;
-        
-        const char *member_start;
-        const char *member_caret;
-        
-        unsigned long member_line;
-        
-        int offset = 0;
-        int size = DATA_INT & 0x1f;
-        int elem_size = DATA_INT & 0x1f;
-        int pointer_depth = 0;
-        int is_array = 0;
-        
-        get_token ();
-        
-        member_start = tok.start;
-        member_caret = tok.caret;
-        member_line = get_line_number ();
-        
-        if (tok.kind != TOK_IDENT) {
-        
-            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret,
-                            "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
-            return 1;
-        
-        }
-        
-        member = xstrdup (tok.ident);
-        get_token ();
-        
-        if (!find_member_info_ex_bounded (member, current_object_size,
-                                          current_tag_name[0] ? current_tag_name : 0,
-                                          &offset, &size, &elem_size, &pointer_depth, &is_array, 0)) {
-        
-            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret,
-                            "unknown member '%s'", member);
-            
-            free (member);
-            return 1;
-        
-        }
-        
-        free (member);
-        total_offset += (unsigned long) offset;
-        
-        if (last_found_member_tag_name && last_found_member_tag_name[0]) {
-        
-            strncpy (current_tag_name, last_found_member_tag_name, sizeof (current_tag_name) - 1);
-            current_tag_name[sizeof (current_tag_name) - 1] = '\0';
-        
-        } else {
-            current_tag_name[0] = '\0';
-        }
-        
-        while (tok.kind == TOK_LBRACK) {
-        
-            enum token_kind kill[2];
-            int64_s index;
-            
-            get_token ();
-            
-            kill[0] = TOK_RBRACK;
-            kill[1] = 0;
-            
-            index = expr_const64 (kill);
-            
-            expect (TOK_RBRACK, "]");
-            total_offset += index.low * (unsigned long) (elem_size > 0 ? elem_size : (DATA_INT & 0x1f));
-        
-        }
-        
-        if (pointer_depth > 0) {
-            current_object_size = elem_size > 0 ? elem_size : (DATA_PTR & 0x1f);
-        } else if (is_array && elem_size > 0) {
-            current_object_size = elem_size;
-        } else {
-            current_object_size = size;
-        }
-    
-    }
-    
-    expect (TOK_RPAREN, ")");
-    
-    if (out) {
-        zext64 (out, total_offset);
-    }
-    
-    return 1;
-
-}
-
-int parse_constexpr_address_of_null_member (int64_s *out) {
-
-    if (tok.kind != TOK_AMPER) {
-        return 0;
-    }
-    
-    get_token ();
-    
-    if (tok.kind != TOK_LPAREN) {
-        return 0;
-    }
-    
-    get_token ();
-    
-    if (parse_constexpr_null_member_address_after_lparen (out)) {
-        return 1;
-    }
-    
-    return 0;
-
-}
-
-int token_is_sizeof_keyword (void) {
-    return tok.kind == TOK_SIZEOF;
-}
-
-static int64_s sizeof_from_current_token (void) {
-
-    int64_s v;
-    int size;
-    
-    zext64 (&v, 0);
-    get_token ();
-    
-    size = parse_sizeof_value ();
-    zext64 (&v, (unsigned long) size);
-    
-    return v;
-
-}
-
-static int64_s const64_from_current_expr (void) {
-
-    enum token_kind kill[6];
-    int64_s v;
-    
-    kill[0] = TOK_SEMI;
-    kill[1] = TOK_COMMA;
-    kill[2] = TOK_RPAREN;
-    kill[3] = TOK_RBRACK;
-    kill[4] = TOK_RBRACE;
-    kill[5] = 0;
-    
-    v = expr_const64 (kill);
-    return v;
-
-}
-
-static int64_s const64_from_current_operand (void) {
-
-    enum token_kind kill[26];
-    
-    if (token_is_sizeof_keyword ()) {
-        return sizeof_from_current_token ();
-    }
-    
-    kill[0] = TOK_PLUS;
-    kill[1] = TOK_MINUS;
-    kill[2] = TOK_STAR;
-    kill[3] = TOK_BSLASH;
-    kill[4] = TOK_MOD;
-    kill[5] = TOK_LSH;
-    kill[6] = TOK_RSH;
-    kill[7] = TOK_AMPER;
-    kill[8] = TOK_PIPE;
-    kill[9] = TOK_CARET;
-    kill[10] = TOK_LESS;
-    kill[11] = TOK_LTEQ;
-    kill[12] = TOK_GREATER;
-    kill[13] = TOK_GTEQ;
-    kill[14] = TOK_EQEQ;
-    kill[15] = TOK_NOTEQ;
-    kill[16] = TOK_LOGAND;
-    kill[17] = TOK_LOGOR;
-    kill[18] = TOK_QMARK;
-    kill[19] = TOK_COLON;
-    kill[20] = TOK_SEMI;
-    kill[21] = TOK_COMMA;
-    kill[22] = TOK_RPAREN;
-    kill[23] = TOK_RBRACK;
-    kill[24] = TOK_RBRACE;
-    kill[25] = 0;
-    
-    return expr_const64 (kill);
-
-}
-
-static int64_s const64_from_current_foldable_expr (void) {
-
-    enum token_kind kill[17];
-    
-    if (token_is_sizeof_keyword ()) {
-        return sizeof_from_current_token ();
-    }
-    
-    kill[0] = TOK_LESS;
-    kill[1] = TOK_LTEQ;
-    kill[2] = TOK_GREATER;
-    kill[3] = TOK_GTEQ;
-    kill[4] = TOK_EQEQ;
-    kill[5] = TOK_NOTEQ;
-    kill[6] = TOK_LOGAND;
-    kill[7] = TOK_LOGOR;
-    kill[8] = TOK_QMARK;
-    kill[9] = TOK_COLON;
-    kill[10] = TOK_SEMI;
-    kill[11] = TOK_COMMA;
-    kill[12] = TOK_RPAREN;
-    kill[13] = TOK_RBRACK;
-    kill[14] = TOK_RBRACE;
-    kill[15] = 0;
-    kill[16] = 0;
-    
-    return expr_const64 (kill);
-
-}
-
-static long const_from_current_expr (void) {
-
-    int64_s v = const64_from_current_expr ();
-    return (long) v.low;
-
-}
-
-static long const_from_current_case_expr (void) {
-
-    enum token_kind kill[7];
-    int64_s v;
-    
-    if (token_is_sizeof_keyword ()) {
-    
-        v = sizeof_from_current_token ();
-        return (long) v.low;
-    
-    }
-    
-    kill[0] = TOK_COLON;
-    kill[1] = TOK_SEMI;
-    kill[2] = TOK_COMMA;
-    kill[3] = TOK_RPAREN;
-    kill[4] = TOK_RBRACK;
-    kill[5] = TOK_RBRACE;
-    kill[6] = 0;
-    
-    v = expr_const64 (kill);
-    return (long) v.low;
-
-}
-
-static int declarator_element_size_from_fields (int base_size, const int *field_sizes, int field_count);
-
-static int declarator_pointed_size_now (void) {
-
-    if (declarator_pointer_depth > 1) {
-        return DATA_PTR;
-    }
-    
-    if (parsed_type_is_aggregate) {
-        return parsed_type_size;
-    }
-    
-    return parsed_type_size & 0x1f;
-
-}
-
-static struct aggregate_tag_entry *hidden_typedef_pointer_entry_now (void) {
-
-    if (declarator_pointer_depth != 0 || declarator_is_pointer ||
-        declarator_has_array || declarator_has_function) {
-        return 0;
-    }
-    
-    if ((parsed_type_size & 0x1f) != (DATA_PTR & 0x1f) ||
-        !parsed_type_tag_name[0]) {
-        return 0;
-    }
-    
-    return find_aggregate_tag (parsed_type_tag_name, 0);
-
-}
-
-static int declarator_effective_pointer_depth_now (void) {
-
-    if (declarator_pointer_depth > 0) {
-        return declarator_pointer_depth;
-    }
-    
-    return hidden_typedef_pointer_entry_now () ? 1 : 0;
-
-}
-
-static int declarator_effective_pointed_size_now (int base_size, const int *field_sizes, int field_count) {
-
-    struct aggregate_tag_entry *entry;
-    
-    if (declarator_pointer_depth > 0 || declarator_is_pointer) {
-        return declarator_pointed_size_now ();
-    }
-    
-    entry = hidden_typedef_pointer_entry_now ();
-    
-    if (entry) {
-        return entry->size;
-    }
-    
-    return declarator_element_size_from_fields (base_size, field_sizes, field_count);
-
-}
-
-static int declarator_element_size_from_fields (int base_size, const int *field_sizes, int field_count) {
-
-    int total = 0;
-    int i;
-    
-    if (field_sizes && field_count > 0) {
-    
-        for (i = 0; i < field_count; i++) {
-            total += field_sizes[i] & 0x1f;
-        }
-        
-        if (total > 0) {
-            return total;
-        }
-    
-    }
-    
-    if (parsed_type_is_aggregate) {
-        return base_size;
-    }
-    
-    return base_size & 0x1f;
-
-}
-
-static int declarator_array_element_size_now (int base_size) {
-
-    int object_size;
-    
-    if (!declarator_has_array) {
-        return 0;
-    }
-    
-    if (declarator_is_pointer) {
-        return DATA_PTR;
-    }
-    
-    /*
-     * For an array object, the element reached by one subscript is the
-     * complete row after the first dimension, not always the scalar base
-     * type.  For example, with:
-     *
-     *     static const char wday_name[7][3];
-     *
-     * wday_name[i] has type char [3] and decays to the address of that
-     * three-byte row when passed to %.3s.  Recording element size as char
-     * made expression code emit a byte load from wday_name + i instead of
-     * the row address wday_name + i * 3.
-     */
-    if (declarator_array_dimensions > 1 && declarator_first_array_count > 0) {
-    
-        object_size = declarator_object_size (base_size);
-        
-        if (object_size > 0) {
-            return object_size / declarator_first_array_count;
-        }
-    
-    }
-    
-    /*
-     * For a one-dimensional array, the size of the element reached by one
-     * subscript is the declared base object size, not the total flattened
-     * initializer field size.  make_declarator_fields() expands objects like
-     *
-     *     char parmbuf[410];
-     *
-     * into 410 byte fields for initialization/copying purposes.  Feeding that
-     * field total back here made parmbuf[i] scale by 410 and store a dword far
-     * beyond the stack object.
-     */
-    if (parsed_type_is_aggregate) {
-        return base_size;
-    }
-    
-    return base_size & 0x1f;
-
-}
-
-static int declarator_object_size (int base_size) {
-
-    if (declarator_has_array) {
-    
-        int elem_size = declarator_is_pointer ? DATA_PTR : base_size;
-        
-        if (declarator_array_count <= 0) {
-            return elem_size;
-        }
-        
-        return elem_size * declarator_array_count;
-    
-    }
-    
-    if (declarator_is_pointer) {
-        return DATA_PTR;
-    }
-    
-    return base_size;
-
-}
-
-static int count_brace_initializer_elements_from_assign_now (void) {
-
-    const char *p;
-    
-    int brace_depth = 0;
-    int paren_depth = 0;
-    int bracket_depth = 0;
-    int count = 0;
-    int saw_element = 0;
-    
-    if (tok.kind != TOK_ASSIGN || !tok.start) {
-        return 0;
-    }
-    
-    p = tok.start;
-    
-    while (*p && *p != '=') {
-        p++;
-    }
-    
-    if (*p != '=') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (*p != '{') {
-        return 0;
-    }
-    
-    p++;
-    brace_depth = 1;
-    
-    while (*p && brace_depth > 0) {
-    
-        if (*p == '\'' || *p == '"') {
-        
-            int quote = *p++;
-            saw_element = 1;
-            
-            while (*p && *p != quote) {
-            
-                if (*p == '\\' && p[1]) {
-                    p += 2;
-                } else {
-                    p++;
-                }
-            
-            }
-            
-            if (*p == quote) {
-                p++;
-            }
-            
-            continue;
-        
-        }
-        
-        if (*p == '{') {
-        
-            brace_depth++;
-            saw_element = 1;
-        
-        } else if (*p == '}') {
-        
-            if (brace_depth == 1 && paren_depth == 0 && bracket_depth == 0) {
-                break;
-            }
-            
-            brace_depth--;
-        
-        } else if (*p == '(') {
-        
-            paren_depth++;
-            saw_element = 1;
-        
-        } else if (*p == ')') {
-        
-            if (paren_depth > 0) {
-                paren_depth--;
-            }
-        
-        } else if (*p == '[') {
-        
-            bracket_depth++;
-            saw_element = 1;
-        
-        } else if (*p == ']') {
-        
-            if (bracket_depth > 0) {
-                bracket_depth--;
-            }
-        
-        } else if (*p == ',' && brace_depth == 1 && paren_depth == 0 && bracket_depth == 0) {
-        
-            if (saw_element) {
-            
-                count++;
-                saw_element = 0;
-            
-            }
-        
-        } else if (!(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')) {
-            saw_element = 1;
-        }
-        
-        p++;
-    
-    }
-    
-    if (saw_element) {
-        count++;
-    }
-    
-    return count;
-
-}
-
-static int parse_sizeof_member_expr_size (int leading_stars, int *out_size) {
-
-    int size = DATA_INT & 0x1f;
-    int pointer_depth = 0;
-    int pointed_size = 0;
-    int is_array = 0;
-    int array_element_size = 0;
-    int final_pointer_depth = 0;
-    int final_pointed_size = 0;
-    int final_is_array = 0;
-    int final_array_element_size = 0;
-    
-    struct local_symbol *local;
-    
-    if (tok.kind != TOK_IDENT) {
-        return 0;
-    }
-    
-    local = find_local_symbol (tok.ident);
-    
-    if (local) {
-    
-        size = local->size;
-        
-        pointer_depth = local->pointer_depth;
-        pointed_size = local->pointed_size;
-        
-        is_array = local->is_array;
-        array_element_size = local->array_element_size;
-    
-    } else if (find_global_symbol (tok.ident) >= 0) {
-    
-        size = get_global_symbol_size (tok.ident);
-        
-        pointer_depth = get_global_symbol_pointer_depth (tok.ident);
-        pointed_size = get_global_symbol_pointed_size (tok.ident);
-        
-        is_array = get_global_symbol_array (tok.ident);
-        array_element_size = get_global_symbol_array_element_size (tok.ident);
-    
-    } else {
-        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "unknown symbol '%s'", tok.ident ? tok.ident : "");
-    }
-    
-    final_pointer_depth = pointer_depth;
-    final_pointed_size = pointed_size;
-    final_is_array = is_array;
-    final_array_element_size = array_element_size;
-    
-    get_token ();
-    
-    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
-    
-        int member_pointer_depth = 0;
-        int member_pointed_size = 0;
-        int member_offset = 0;
-        int member_size = 0;
-        int member_is_array = 0;
-        
-        const char *member_tag_name = 0;
-        enum token_kind member_op = tok.kind;
-        
-        get_token ();
-        
-        if (tok.kind != TOK_IDENT) {
-        
-            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret,
-                            "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
-            break;
-        
-        }
-        
-        if (find_member_info_ex (tok.ident, &member_offset, &member_size,
-                                 &member_pointed_size, &member_pointer_depth,
-                                 &member_is_array, 0)) {
-        
-            member_tag_name = last_found_member_tag_name ? last_found_member_tag_name : find_member_tag_name (tok.ident);
-            size = member_size;
-            
-            final_pointer_depth = member_pointer_depth;
-            final_pointed_size = member_pointed_size;
-            
-            final_is_array = member_is_array;
-            final_array_element_size = member_is_array ? member_size : 0;
-        
-            if (final_pointer_depth > 0 && member_tag_name) {
-            
-                struct aggregate_tag_entry *entry = find_aggregate_tag (member_tag_name, 0);
-                
-                if (entry) {
-                    final_pointed_size = entry->size;
-                }
-            
-            }
-        
-        } else {
-        
-            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret,
-                            "unknown member '%s'", tok.ident ? tok.ident : "");
-        
-        }
-        
-        get_token ();
-    
-    }
-    
-    while (tok.kind == TOK_LBRACK) {
-    
-        int depth = 1;
-        get_token ();
-        
-        while (tok.kind != TOK_EOF && depth > 0) {
-        
-            if (tok.kind == TOK_LBRACK) {
-                depth++;
-            } else if (tok.kind == TOK_RBRACK) {
-            
-                depth--;
-                
-                if (depth == 0) {
-                    break;
-                }
-            
-            }
-            
-            get_token ();
-        
-        }
-        
-        if (tok.kind == TOK_RBRACK) {
-            get_token ();
-        }
-        
-        if (final_is_array && leading_stars > 0) {
-        
-            int remaining_stars = leading_stars - 1;
-            int elem_size = final_array_element_size > 0 ? final_array_element_size :
-                (final_pointer_depth > 0 ? DATA_PTR : final_pointed_size);
-            
-            /*
-             * In expressions, an array object decays to a pointer to its first
-             * element before the leading '*' operators are applied.  For an
-             * array of pointers, sizeof(*array) is therefore pointer-sized,
-             * not the size of the pointed-to base type.
-             */
-            size = elem_size > 0 ? elem_size : size;
-            
-            if (remaining_stars > 0 && final_pointer_depth >= remaining_stars) {
-            
-                int remaining_depth = final_pointer_depth - remaining_stars;
-                size = remaining_depth > 0 ? DATA_PTR : final_pointed_size;
-            
-            }
-            
-            final_is_array = 0;
-            final_pointer_depth = 0;
-        
-        } else if (final_pointer_depth > 0) {
-         
-            size = final_pointer_depth > 1 ? DATA_PTR : final_pointed_size;
-            final_pointer_depth--;
-        
-        } else if (final_is_array && final_array_element_size > 0) {
-            size = final_array_element_size;
-        } else if (final_is_array && final_pointed_size > 0) {
-            size = final_pointed_size;
-        }
-        
-        final_is_array = 0;
-    
-    }
-    
-    if (leading_stars > 0 && final_is_array) {
-    
-        int remaining_stars = leading_stars - 1;
-        int elem_size = final_array_element_size > 0 ? final_array_element_size :
-            (final_pointer_depth > 0 ? DATA_PTR : final_pointed_size);
-        
-        /*
-         * In an expression, an array object decays to a pointer to its first
-         * element before unary '*' is applied.  This is needed for plain
-         * sizeof(*array) as well as for forms that later include subscripts.
-         * For example, with char *builtins[], sizeof(*builtins) is the size
-         * of one array element, i.e. pointer-sized, not sizeof(char).
-         */
-        size = elem_size > 0 ? elem_size : size;
-        
-        if (remaining_stars > 0 && final_pointer_depth >= remaining_stars) {
-        
-            int remaining_depth = final_pointer_depth - remaining_stars;
-            size = remaining_depth > 0 ? DATA_PTR : final_pointed_size;
-        
-        }
-        
-        final_is_array = 0;
-        final_pointer_depth = 0;
-    
-    } else if (leading_stars > 0 && final_pointer_depth >= leading_stars) {
-    
-        int remaining_depth = final_pointer_depth - leading_stars;
-        size = remaining_depth > 0 ? DATA_PTR : final_pointed_size;
-    
-    }
-    
-    if (size < 1) {
-        size = DATA_INT & 0x1f;
-    }
-    
-    *out_size = size;
-    return 1;
-
-}
-
-int parse_sizeof_value (void) {
-
-    int saved_type_size = parsed_type_size;
-    int saved_storage_class = parsed_storage_class;
-    int saved_is_aggregate = parsed_type_is_aggregate;
-    int saved_is_void = parsed_type_is_void;
-    int saved_is_unsigned = parsed_type_is_unsigned;
-    int saved_is_floating = parsed_type_is_floating;
-    int saved_has_tag = parsed_type_has_tag;
-    int saved_is_inline = parsed_type_is_inline;
-    int saved_field_count = parsed_field_count;
-    int saved_fields[MAX_AGG_FIELDS];
-    
-    int saved_declarator_is_pointer = declarator_is_pointer;
-    int saved_declarator_has_array = declarator_has_array;
-    int saved_declarator_has_function = declarator_has_function;
-    int saved_declarator_array_unsized = declarator_array_unsized;
-    int saved_declarator_array_dimensions = declarator_array_dimensions;
-    
-    long saved_declarator_array_count = declarator_array_count;
-    long saved_declarator_first_array_count = declarator_first_array_count;
-    
-    int size = DATA_INT & 0x1f, i;
-    
-    for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
-        saved_fields[i] = parsed_field_sizes[i];
-    }
-    
-    if (_accept (TOK_LPAREN)) {
-    
-        if (is_type_start (tok.kind)) {
-        
-            char *name = 0;
-            int base_size;
-            
-            parse_type_spec ();
-            base_size = parsed_type_size;
-            
-            /*
-             * sizeof(type-name) may not contain a declarator, for example
-             * sizeof(FILE).  parse_declarator() normally clears these flags,
-             * but when the next token is ')' it is not called.  Do not let a
-             * previous declaration such as FILE **__gtin(void) make this
-             * type-name look like a pointer and collapse the size to 4.
-             */
-            declarator_is_pointer = 0;
-            declarator_pointer_depth = 0;
-            declarator_has_array = 0;
-            declarator_has_function = 0;
-            declarator_function_is_pointer = 0;
-            declarator_function_param_count = 0;
-            declarator_function_has_prototype = 0;
-            declarator_function_is_variadic = 0;
-            declarator_array_unsized = 0;
-            declarator_array_count = 1;
-            declarator_first_array_count = 1;
-            declarator_last_array_count = 1;
-            
-            if (tok.kind != TOK_RPAREN) {
-                parse_declarator (&name);
-            }
-            
-            size = declarator_object_size (base_size);
-            
-            if (name) {
-                free (name);
-            }
-            
-            expect (TOK_RPAREN, ")");
-        
-        } else if (is_string_token ()) {
-        
-            int64_s values[MAX_STRING_INIT_BYTES];
-            int value_count = 0;
-            
-            parse_string_initializer_values (values, MAX_STRING_INIT_BYTES, &value_count);
-            size = value_count;
-            expect (TOK_RPAREN, ")");
-        
-        } else {
-        
-            int depth = 1;
-            int first = 1;
-            int leading_stars = 0;
-            
-            while (tok.kind != TOK_EOF && depth > 0) {
-            
-                if (first) {
-                
-                    while (tok.kind == TOK_STAR || tok.kind == TOK_AMPER || tok.kind == TOK_PLUS || tok.kind == TOK_MINUS) {
-                    
-                        if (tok.kind == TOK_STAR) {
-                            leading_stars++;
-                        }
-                        
-                        get_token ();
-                    
-                    }
-                
-                }
-                
-                if (first && tok.kind == TOK_IDENT) {
-                
-                    parse_sizeof_member_expr_size (leading_stars, &size);
-                    
-                    first = 0;
-                    continue;
-                
-                }
-                
-                if (first && tok.kind == TOK_LPAREN && leading_stars > 0) {
-                
-                    get_token ();
-                    
-                    if (tok.kind == TOK_IDENT) {
-                        parse_sizeof_member_expr_size (leading_stars, &size);
-                    }
-                    
-                    while (tok.kind != TOK_EOF && tok.kind != TOK_RPAREN) {
-                        get_token ();
-                    }
-                    
-                    if (tok.kind == TOK_RPAREN) {
-                        get_token ();
-                    }
-                    
-                    first = 0;
-                    continue;
-                
-                }
-                
-                first = 0;
-                
-                if (tok.kind == TOK_LPAREN) {
-                    depth++;
-                } else if (tok.kind == TOK_RPAREN) {
-                
-                    depth--;
-                    
-                    if (depth == 0) {
-                        break;
-                    }
-                
-                }
-                
-                get_token ();
-            
-            }
-            
-            expect (TOK_RPAREN, ")");
-        
-        }
-    
-    } else {
-    
-        int leading_stars = 0;
-        
-        while (tok.kind == TOK_STAR || tok.kind == TOK_AMPER || tok.kind == TOK_PLUS || tok.kind == TOK_MINUS) {
-        
-            if (tok.kind == TOK_STAR) {
-                leading_stars++;
-            }
-            
-            get_token ();
-        
-        }
-        
-        if (is_string_token ()) {
-        
-            int64_s values[MAX_STRING_INIT_BYTES];
-            int value_count = 0;
-            
-            parse_string_initializer_values (values, MAX_STRING_INIT_BYTES, &value_count);
-            size = value_count;
-        
-        } else if (tok.kind == TOK_IDENT) {
-            parse_sizeof_member_expr_size (leading_stars, &size);
-        } else if (tok.kind == TOK_LPAREN) {
-        
-            int depth = 1;
-            
-            get_token ();
-            
-            while (tok.kind != TOK_EOF && depth > 0) {
-            
-                if (tok.kind == TOK_LPAREN) {
-                    depth++;
-                } else if (tok.kind == TOK_RPAREN) {
-                
-                    depth--;
-                    
-                    if (depth == 0) {
-                        break;
-                    }
-                
-                }
-                
-                get_token ();
-            
-            }
-            
-            expect (TOK_RPAREN, ")");
-        
-        } else if (tok.kind != TOK_EOF) {
-            get_token ();
-        }
-        
-        while (tok.kind == TOK_LBRACK || tok.kind == TOK_LPAREN) {
-        
-            enum token_kind close = (tok.kind == TOK_LBRACK) ? TOK_RBRACK : TOK_RPAREN;
-            int depth = 1;
-            
-            get_token ();
-            
-            while (tok.kind != TOK_EOF && depth > 0) {
-            
-                if ((close == TOK_RBRACK && tok.kind == TOK_LBRACK) || (close == TOK_RPAREN && tok.kind == TOK_LPAREN)) {
-                    depth++;
-                } else if (tok.kind == close) {
-                
-                    depth--;
-                    
-                    if (depth == 0) {
-                        break;
-                    }
-                
-                }
-                
-                get_token ();
-            
-            }
-            
-            expect (close, (close == TOK_RBRACK) ? "]" : ")");
-        
-        }
-    
-    }
-    
-    parsed_type_size = saved_type_size;
-    parsed_storage_class = saved_storage_class;
-    parsed_type_is_aggregate = saved_is_aggregate;
-    parsed_type_is_void = saved_is_void;
-    parsed_type_is_unsigned = saved_is_unsigned;
-    parsed_type_is_floating = saved_is_floating;
-    parsed_type_has_tag = saved_has_tag;
-    parsed_type_is_inline = saved_is_inline;
-    
-    clear_parsed_fields ();
-    
-    for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
-        append_parsed_field (saved_fields[i]);
-    }
-    
-    declarator_is_pointer = saved_declarator_is_pointer;
-    declarator_has_array = saved_declarator_has_array;
-    declarator_has_function = saved_declarator_has_function;
-    declarator_array_unsized = saved_declarator_array_unsized;
-    declarator_array_count = saved_declarator_array_count;
-    declarator_first_array_count = saved_declarator_first_array_count;
-    declarator_array_dimensions = saved_declarator_array_dimensions;
-    
-    if (size < 1) {
-        size = DATA_INT & 0x1f;
-    }
-    
-    return size;
-
-}
-
-static void make_declarator_fields (int *out_fields, int *out_count, const int *base_fields, int base_count, int base_size, int base_is_aggregate) {
-
-    int i;
-    long r;
-    
-    *out_count = 0;
-    
-    if (declarator_is_pointer) {
-    
-        out_fields[(*out_count)++] = DATA_PTR;
-        return;
-    
-    }
-    
-    if (declarator_has_array) {
-    
-        if (base_is_aggregate && base_count > 0) {
-        
-            for (r = 0; r < declarator_array_count && *out_count < MAX_AGG_FIELDS; r++) {
-            
-                for (i = 0; i < base_count && *out_count < MAX_AGG_FIELDS; i++) {
-                    out_fields[(*out_count)++] = base_fields[i];
-                }
-            
-            }
-        
-        } else {
-        
-            for (r = 0; r < declarator_array_count && *out_count < MAX_AGG_FIELDS; r++) {
-                out_fields[(*out_count)++] = (base_size & 0x1f);
-            }
-        
-        }
-        
-        return;
-
-    }
-    
-    for (i = 0; i < base_count && *out_count < MAX_AGG_FIELDS; i++) {
-        out_fields[(*out_count)++] = base_fields[i];
-    }
-    
-    if (*out_count == 0) {
-        out_fields[(*out_count)++] = (base_size & 0x1f);
-    }
-
-}
-
-static void parse_statement (void);
-
-static void emit_load_assignment_rhs_expression_to_pair (const char *lo, const char *hi, int is_unsigned);
-static void emit_load_assignment_rhs_expression_to_reg (const char *reg);
-
-static void emit_incdec_symbol_now (struct local_symbol *sym, const char *name, enum token_kind op, int line, const char *start, const char *caret);
-
-static int current_expression_mentions_64bit_symbol_now (void);
-static int rhs_current_operand_is_unsigned_now (void);
-
-static int64_s parse_floating_const_expr_bits_now (int size);
-
-static int initializer_contains_runtime_call_now (void) {
-
-    const char *p = tok.start;
-    
-    int paren_depth = 0;
-    int bracket_depth = 0;
-    int brace_depth = 0;
-    
-    while (*p) {
-    
-        if (paren_depth == 0 && bracket_depth == 0 && brace_depth == 0 && (*p == ';' || *p == ',' || *p == '}')) {
-            break;
-        }
-        
-        if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_') {
-        
-            const char *q = p + 1;
-            
-            while ((*q >= 'A' && *q <= 'Z') || (*q >= 'a' && *q <= 'z') || (*q >= '0' && *q <= '9') || *q == '_') {
-                q++;
-            }
-            
-            while (*q == ' ' || *q == '\t' || *q == '\r' || *q == '\n') {
-                q++;
-            }
-            
-            if (*q == '(') {
-                return 1;
-            }
-            
-            p = q;
-            continue;
-        
-        }
-        
-        if (*p == '\'' || *p == '"') {
-        
-            int quote = *p++;
-            
-            while (*p && *p != quote) {
-            
-                if (*p == '\\' && p[1]) {
-                    p += 2;
-                } else {
-                    p++;
-                }
-            
-            }
-            
-            if (*p == quote) {
-                p++;
-            }
-            
-            continue;
-        
-        }
-        
-        if (*p == '(') {
-            paren_depth++;
-        } else if (*p == ')') {
-        
-            if (paren_depth > 0) {
-                paren_depth--;
-            }
-        
-        } else if (*p == '[') {
-            bracket_depth++;
-        } else if (*p == ']') {
-        
-            if (bracket_depth > 0) {
-                bracket_depth--;
-            }
-        
-        } else if (*p == '{') {
-            brace_depth++;
-        } else if (*p == '}') {
-        
-            if (brace_depth > 0) {
-                brace_depth--;
-            }
-        
-        }
-        
-        p++;
-    
-    }
-    
-    return 0;
-
-}
-
-static int auto_init_ident_char_now (int ch) {
-    return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '_';
-}
-
-static int auto_init_expr_continues_after_ident_now (void) {
-
-    const char *p;
-    const char *q;
-    
-    if (tok.kind != TOK_IDENT) {
-        return 1;
-    }
-    
-    p = tok.start;
-    q = p;
-    
-    while (auto_init_ident_char_now ((unsigned char) *q)) {
-        q++;
-    }
-    
-    while (*q == ' ' || *q == '\t' || *q == '\r' || *q == '\n') {
-        q++;
-    }
-    
-    return !(*q == ';' || *q == ',' || *q == '}');
-
-}
-
-static int auto_initializer_needs_runtime_now (void) {
-
-    const char *p = tok.start;
-    int paren_depth = 0;
-    int bracket_depth = 0;
-    int brace_depth = 0;
-    
-    if (initializer_contains_runtime_call_now () || tok.kind == TOK_LPAREN) {
-        return 1;
-    }
-    
-    if (tok.kind == TOK_IDENT) {
-        return auto_init_expr_continues_after_ident_now ();
-    }
-    
-    if (tok.kind == TOK_AMPER) {
-    
-        p++;
-        
-        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-            p++;
-        }
-        
-        if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
-            return 1;
-        }
-        
-        while (auto_init_ident_char_now ((unsigned char) *p)) {
-            p++;
-        }
-        
-        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-            p++;
-        }
-        
-        return !(*p == ';' || *p == ',' || *p == '}');
-    
-    }
-    
-    p = tok.start;
-    
-    while (*p) {
-    
-        if (paren_depth == 0 && bracket_depth == 0 && brace_depth == 0 && (*p == ';' || *p == ',' || *p == '}')) {
-            break;
-        }
-        
-        if (*p == '[' || *p == ']' || *p == '*') {
-            return 1;
-        }
-        
-        if (*p == '(') {
-            paren_depth++;
-        } else if (*p == ')') {
-            if (paren_depth > 0) paren_depth--;
-        } else if (*p == '[') {
-            bracket_depth++;
-        } else if (*p == ']') {
-            if (bracket_depth > 0) bracket_depth--;
-        } else if (*p == '{') {
-            brace_depth++;
-        } else if (*p == '}') {
-            if (brace_depth > 0) brace_depth--;
-        }
-        
-        if (((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_') && p[0] != 'L') {
-            return 1;
-        }
-        
-        p++;
-    
-    }
-    
-    return 0;
-
-}
-
-static void parse_local_initializer_value (struct local_init *init, int object_size, int object_is_floating) {
-
-    init->kind = LOCAL_INIT_CONST;
-    init->symbol = 0;
-    init->value.low = 0;
-    init->value.high = 0;
-    init->source_offset = 0;
-    init->source_size = 0;
-    
-    if (tok.kind == TOK_LBRACE) {
-    
-        get_token ();
-        parse_local_initializer_value (init, object_size, object_is_floating);
-        
-        while (_accept (TOK_COMMA)) {
-            skip_initializer ();
-        }
-        
-        expect (TOK_RBRACE, "}");
-        return;
-    
-    }
-    
-    if (tok.kind == TOK_AMPER) {
-    
-        get_token ();
-        
-        if (tok.kind != TOK_IDENT) {
-        
-            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after '&'");
-            return;
-        
-        }
-        
-        init->kind = LOCAL_INIT_ADDRESS;
-        init->symbol = xstrdup (tok.ident);
-        
-        get_token ();
-        return;
-    
-    }
-    
-    if (tok.kind == TOK_IDENT) {
-    
-        struct local_symbol *src = find_local_symbol (tok.ident);
-        
-        if (src) {
-        
-            if (src->is_static && src->static_label) {
-            
-                init->kind = LOCAL_INIT_GLOBAL;
-                init->symbol = xstrdup (src->static_label);
-            
-            } else {
-            
-                init->kind = LOCAL_INIT_STACK;
-                
-                init->source_offset = src->offset;
-                init->source_size = src->size;
-            
-            }
-            
-            get_token ();
-            return;
-        
-        }
-        
-        if (find_global_symbol (tok.ident) >= 0) {
-        
-            init->kind = LOCAL_INIT_GLOBAL;
-            init->symbol = xstrdup (tok.ident);
-            
-            get_token ();
-            return;
-        
-        }
-    
-    }
-    
-    if (object_is_floating) {
-        init->value = parse_floating_const_expr_bits_now (object_size);
-    } else {
-        init->value = const64_from_current_expr ();
-    }
-
-}
-
-static void parse_local_string_field_initializer (struct local_init *inits, int *init_count, int max_inits, long base_offset, int field_size) {
-
-    int64_s values[MAX_STRING_INIT_BYTES];
-    int value_count = 0, i;
-    
-    parse_string_initializer_values (values, MAX_STRING_INIT_BYTES, &value_count);
-    
-    for (i = 0; i < field_size; i++) {
-    
-        if (*init_count >= max_inits) {
-            continue;
-        }
-        
-        inits[*init_count].offset = base_offset + i;
-        inits[*init_count].size = 1;
-        inits[*init_count].kind = LOCAL_INIT_CONST;
-        inits[*init_count].symbol = 0;
-        inits[*init_count].value.low = (i < value_count) ? (values[i].low & 0xffUL) : 0;
-        inits[*init_count].value.high = 0;
-        inits[*init_count].source_offset = 0;
-        inits[*init_count].source_size = 0;
-        
-        (*init_count)++;
-    
-    }
-
-}
-
-static void parse_local_aggregate_initializer_values (struct local_init *inits, int *init_count, int max_inits, long base_offset, const int *fields, int field_count) {
-
-    int field_index = 0;
-    long field_offset = 0;
-    int braced = 0;
-    
-    if (tok.kind == TOK_LBRACE) {
-        braced = 1;
-        get_token ();
-    }
-    
-    while (field_index < field_count) {
-    
-        int field_size = fields[field_index];
-        
-        if (field_size < 0) {
-        
-            field_offset += -field_size;
-            
-            field_index++;
-            continue;
-        
-        }
-        
-        if (braced && tok.kind == TOK_RBRACE) {
-        
-            if (*init_count < max_inits) {
-            
-                inits[*init_count].offset = base_offset + field_offset;
-                inits[*init_count].size = field_size;
-                inits[*init_count].kind = LOCAL_INIT_CONST;
-                inits[*init_count].symbol = 0;
-                inits[*init_count].value.low = 0;
-                inits[*init_count].value.high = 0;
-                inits[*init_count].source_offset = 0;
-                inits[*init_count].source_size = 0;
-                
-                (*init_count)++;
-            
-            }
-            
-            field_offset += field_size;
-            field_index++;
-            
-            continue;
-        
-        }
-        
-        if (*init_count < max_inits) {
-        
-            if (is_string_token ()) {
-                parse_local_string_field_initializer (inits, init_count, max_inits, base_offset + field_offset, field_size);
-            } else {
-            
-                inits[*init_count].offset = base_offset + field_offset;
-                inits[*init_count].size = field_size;
-                
-                parse_local_initializer_value (&inits[*init_count], 0, 0);
-                (*init_count)++;
-            
-            }
-        
-        } else {
-            skip_initializer ();
-        }
-        
-        field_offset += field_size;
-        field_index++;
-        
-        if (braced) {
-        
-            if (!_accept (TOK_COMMA)) {
-                break;
-            }
-            
-            if (tok.kind == TOK_RBRACE) {
-                break;
-            }
-        
-        } else {
-            break;
-        }
-    
-    }
-    
-    if (braced) {
-    
-        while (field_index < field_count) {
-        
-            int field_size = fields[field_index];
-            
-            if (field_size < 0) {
-            
-                field_offset += -field_size;
-                
-                field_index++;
-                continue;
-            
-            }
-            
-            if (*init_count < max_inits) {
-            
-                inits[*init_count].offset = base_offset + field_offset;
-                inits[*init_count].size = field_size;
-                inits[*init_count].kind = LOCAL_INIT_CONST;
-                inits[*init_count].symbol = 0;
-                inits[*init_count].value.low = 0;
-                inits[*init_count].value.high = 0;
-                inits[*init_count].source_offset = 0;
-                inits[*init_count].source_size = 0;
-                
-                (*init_count)++;
-            
-            }
-            
-            field_offset += field_size;
-            field_index++;
-        
-        }
-        
-        while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
-        
-            skip_initializer ();
-            
-            if (!_accept (TOK_COMMA)) {
-                break;
-            }
-        }
-        
-        expect (TOK_RBRACE, "}");
-    
-    }
-
-}
-
-static void make_local_static_label (char *buf, size_t bufsz, const char *name) {
-
-    if (!buf || bufsz == 0) {
-        return;
-    }
-    
-    if (!name) {
-        name = "anon";
-    }
-    
-    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
-        sprintf (buf, "LC%d_%s", local_static_id++, name);
-    } else {
-        sprintf (buf, ".LC%d_%s", local_static_id++, name);
-    }
-
-}
-
-static void emit_global_object (const char *name, int size, int is_array, long array_count, const int *field_sizes, int field_count, const int64_s *values, char **symbols, int value_count, int is_aggregate, int is_static);
-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_block_static_object (const char *label, int size, int is_array, long array_count, const int *field_sizes, int field_count, const int64_s *values, char **symbols, int value_count, int is_aggregate) {
-    
-    emit_global_object (label, size, is_array, array_count, field_sizes, field_count, values, symbols, value_count, is_aggregate, 1);
-    
-    /**
-     * We may have switched to .data/.data? to emit the static object while
-     * parsing a function body.  The following statements still belong in
-     * .code/.text.
-     */
-    switch_section (SECTION_TEXT);
-
-}
-
-static char *emit_string_literal_global (void);
-static int is_string_token (void);
-
-static void ensure_block_stack_allocated (long block_stack_start, long *block_stack_bytes, int *block_stack_emitted) {
-
-    long needed_stack_bytes = align_up_long (current_local_stack_size - block_stack_start, 4);
-    
-    /*
-     * The parser can emit code while it is still inside a declaration list
-     * containing comma-separated declarators and runtime initializers.  Keep
-     * one word of conservative headroom once a block frame exists, so a
-     * subsequently-discovered automatic slot in the same declaration phase is
-     * not allowed to overlap the caller frame before the next adjustment is
-     * emitted.  This fixes cases like:
-     *
-     *     cpp_mffc *old = reader->mffc;
-     *     struct if_stack *ifs, *next_ifs;
-     *     ... next_ifs = ifs->next;
-     *
-     * where generated code used -12(%ebp) after reserving only 8 bytes.
-     */
-    if (needed_stack_bytes > 0) {
-        needed_stack_bytes = align_up_long (needed_stack_bytes + 4, 4);
-    }
-    
-    if (!block_stack_bytes || !block_stack_emitted) {
-        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;
-        emit_stack_adjust (*block_stack_bytes, 1);
-        
-        if (current_parse_block_depth > 1) {
-            current_block_cleanup_bytes += *block_stack_bytes;
-        }
-        
-        *block_stack_emitted = (*block_stack_bytes > 0);
-    
-    } 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 (current_parse_block_depth > 1) {
-            current_block_cleanup_bytes += extra_stack_bytes;
-        }
-        
-        *block_stack_bytes = needed_stack_bytes;
-    
-    }
-
-}
-
-static void parse_global_initializer_values (int64_s *values, char **symbols, int max_values, int *count);
-static void parse_string_initializer_values (int64_s *values, int max_values, int *count);
-
-static int aggregate_initializer_value_field_count (const int *field_sizes, int field_count);
-static void parse_global_initializer_values_padded_elements (int64_s *values, char **symbols, int max_values, int *count, int element_field_count);
-
-static void parse_char_array_initializer_values (int64_s *values, int max_values, int *count, long row_width);
-static int64_s parse_floating_const_expr_bits_now (int size);
-
-static void emit_store_pair_to_local64 (long offset, const char *lo, const char *hi);
-static void emit_store_reg_to_local (long offset, int size, const char *reg);
-
-static void emit_load_local_address_to_reg_now (const char *reg, long offset);
-static int emit_aggregate_copy_from_current_rhs_to_addr_reg_now (const char *addr_reg, int offset, int size);
-
-static void parse_block (void) {
-
-    int declaration_phase = 1, is_function_body = (current_parse_block_depth == 0);
-    
-    int block_local_start = local_symbol_count;
-    int block_stack_emitted = 0;
-    
-    long block_stack_start = current_local_stack_size;
-    long block_stack_bytes = 0;
-    
-    struct local_init inits[MAX_LOCAL_INITS];
-    int block_scope_start, init_count = 0;
-    
-    block_scope_start = is_function_body ? 0 : block_local_start;
-    current_parse_block_depth++;;
-    
-    expect (TOK_LBRACE, "{");
-    
-    while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
-    
-        if (is_type_start (tok.kind)) {
-        
-            if (!declaration_phase) {
-            
-                if (state->std == 90) {
-                    report_line_at (get_filename (), get_line_number (), (state->pedantic ? REPORT_ERROR : REPORT_WARNING), tok.start, tok.caret, "ISO C90 forbids mixed declarations and code");
-                }
-            
-            }
-            
-            parse_type_spec ();
-            
-            for (;;) {
-            
-                long object_offset = 0;
-                
-                int object_init_size = 0;
-                int object_is_auto = 0;
-                
-                char *name = 0;
-                unsigned long name_line;
-                
-                const char *name_start, *name_caret;
-                int object_align, object_size = 0;
-                
-                int object_fields[MAX_AGG_FIELDS];
-                int object_field_count = 0;
-                int init_value_count = 0;
-                
-                int64_s init_values[MAX_AGG_FIELDS];
-                int i;
-                
-                char *init_symbols[MAX_AGG_FIELDS];
-                char static_label[128];
-                
-                int declaration_dllimport = parsed_dllimport;
-                
-                for (i = 0; i < MAX_AGG_FIELDS; i++) {
-                    init_symbols[i] = 0;
-                }
-                
-                parse_declarator (&name);
-                
-                declaration_dllimport = declaration_dllimport || parsed_dllimport || declarator_dllimport;
-                apply_typedef_array_to_declarator ();
-                
-                if (declarator_has_array && declarator_array_unsized && tok.kind == TOK_ASSIGN) {
-                
-                    int inferred_count = count_brace_initializer_elements_from_assign_now ();
-                    
-                    if (inferred_count > 0) {
-                        declarator_array_count = inferred_count;
-                    }
-                
-                }
-                
-                name_line = last_declarator_name_line;
-                name_start = last_declarator_name_start;
-                name_caret = last_declarator_name_caret;
-                
-                make_declarator_fields (object_fields, &object_field_count, parsed_field_sizes, parsed_field_count, parsed_type_size, parsed_type_is_aggregate);
-                
-                if (parsed_type_is_void && !declarator_is_pointer && !declarator_has_function) {
-                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "variable '%s' declared void", name ? name : "");
-                }
-                
-                if (declarator_is_pointer) {
-                
-                    object_field_count = 1;
-                    object_fields[0] = DATA_PTR;
-                
-                }
-                
-                if (parsed_storage_class == STORAGE_TYPEDEF && name) {
-                
-                    save_typedef_name (name, declarator_object_size (parsed_type_size),
-                        (declarator_is_pointer ? 0 : parsed_type_is_unsigned),
-                            (declarator_is_pointer ? 0 : parsed_type_is_void),
-                                (!declarator_is_pointer && (parsed_type_is_aggregate || declarator_has_array)),
-                                    (!declarator_is_pointer && declarator_has_array),
-                                        declarator_array_count, parsed_type_size,
-                                            (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention,
-                                                object_fields, object_field_count);
-                
-                } else if (name && (parsed_storage_class == STORAGE_EXTERN || declaration_dllimport)) {
-                
-                    add_global_symbol (name, (declarator_has_function && !declarator_function_is_pointer) ? GLOBAL_SYMBOL_FUNCTION : GLOBAL_SYMBOL_OBJECT, 1, name_start, name_caret, name_line);
-                    
-                    if (find_global_symbol (name) >= 0) {
-                    
-                        set_global_symbol_size (name, (declarator_has_function && !declarator_is_pointer && !declarator_function_is_pointer) ? parsed_type_size : ((declarator_has_function || declarator_is_pointer) ? DATA_PTR : declarator_object_size (parsed_type_size)));
-                        set_global_symbol_pointer_info (name, declarator_effective_pointer_depth_now (),
-                            declarator_effective_pointed_size_now (parsed_type_size, object_fields, object_field_count));
-                        set_global_symbol_tag_name (name, parsed_type_tag_name);
-                        set_global_symbol_unsigned (name, (declarator_is_pointer || declarator_has_function) ? 0 : parsed_type_is_unsigned);
-                        set_global_symbol_floating (name, (declarator_is_pointer || (declarator_has_function && declarator_function_is_pointer)) ? 0 : parsed_type_is_floating);
-                        set_global_symbol_returns_void (name, declarator_has_function && parsed_type_is_void && !declarator_is_pointer && !declarator_function_is_pointer);
-                        
-                        if (declarator_has_function) {
-                        
-                            set_global_symbol_param_count (name, declarator_function_param_count, declarator_function_has_prototype || declarator_function_param_count > 0, declarator_function_is_variadic);
-                            
-                            set_global_symbol_calling_convention (name, (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention);
-                            set_global_symbol_dllimport (name, declaration_dllimport);
-                            
-                            copy_pending_params_to_global_symbol (name);
-                        
-                        }
-                        
-                        set_global_symbol_dllimport (name, declaration_dllimport);
-                        switch_section (SECTION_TEXT);
-                    
-                    }
-                
-                } else if (name && parsed_storage_class != STORAGE_STATIC) {
-                
-                    object_size = declarator_object_size (parsed_type_size);
-                    object_align = declarator_is_pointer ? type_alignment (DATA_PTR) : type_alignment (parsed_type_is_aggregate ? DATA_PTR : parsed_type_size);
-                    
-                    object_offset = add_local_symbol (name, object_size, object_align,
-                        (declarator_is_pointer ? 0 : parsed_type_is_unsigned),
-                            block_scope_start, name_line, name_start, name_caret);
-                    
-                    /*
-                     * Reserve stack space as soon as an automatic local receives
-                     * an EBP-relative slot.  Some blocks start with declarations
-                     * and then immediately execute statements that write those
-                     * locals, for example:
-                     *
-                     *     if (...) { location_t loc; unsigned int i; loc.file = ...; }
-                     *
-                     * Waiting until the declaration phase is exited proved too
-                     * fragile after runtime initializer handling was added: code
-                     * could use -4/-8/-12(%ebp) before any sub esp had been
-                     * emitted.  Keep block_stack_bytes in sync here so the later
-                     * declaration-phase transition is a no-op unless a later
-                     * unsized aggregate expands the frame.
-                     */
-                    ensure_block_stack_allocated (block_stack_start, &block_stack_bytes, &block_stack_emitted);
-                    
-                    set_local_symbol_floating (name, declarator_is_pointer ? 0 : parsed_type_is_floating);
-                    set_local_symbol_array (name, declarator_has_array);
-                    set_local_symbol_array_dimensions (name, declarator_has_array ? declarator_array_dimensions : 0);
-                    set_local_symbol_array_element_size (name, declarator_array_element_size_now (parsed_type_size));
-                    set_local_symbol_pointer_info (name, declarator_effective_pointer_depth_now (),
-                        declarator_effective_pointed_size_now (parsed_type_size, object_fields, object_field_count));
-                    
-                    if (!declarator_is_pointer && parsed_type_tag_name[0]) {
-                    
-                        struct local_symbol *lsym = find_local_symbol (name);
-                        
-                        if (lsym) {
-                            lsym->tag_name = xstrdup (parsed_type_tag_name);
-                        }
-                    
-                    }
-                    
-                    object_init_size = declarator_is_pointer ? DATA_PTR : (parsed_type_size & 0x1f);
-                    object_is_auto = 1;
-                    
-                    /*
-                     * If an earlier automatic declaration in this block had a
-                     * runtime initializer, stack space has already been emitted.
-                     * Any later automatic declaration extends current_local_stack_size,
-                     * and its initializer may immediately store to the new slot.
-                     * Reserve the extra bytes before parsing/emitting that initializer;
-                     * otherwise code can write to -8(%ebp), -12(%ebp), etc. after
-                     * only the first 4 bytes were allocated.
-                     */
-                    if (block_stack_emitted) {
-                        ensure_block_stack_allocated (block_stack_start, &block_stack_bytes, &block_stack_emitted);
-                    }
-                
-                }
-                
-                if (_accept (TOK_ASSIGN)) {
-                
-                    /*
-                     * Reserve the stack slot before parsing an automatic initializer.
-                     *
-                     * Some initializer forms which are not compile-time constants
-                     * can still reach code emission through parse_local_initializer_value().
-                     * If the stack adjustment is delayed until the first following
-                     * statement, those stores use offsets that have not yet been
-                     * reserved.  In create_definition(), this affected:
-                     *
-                     *     cpp_token *saved_cur_token = reader->cur_token;
-                     *
-                     * The generated code stored to -64(%ebp) while only -60 bytes
-                     * had been allocated, so the following call overwrote the saved
-                     * value and reader->cur_token was restored with garbage.
-                     */
-                    if (object_is_auto) {
-                        ensure_block_stack_allocated (block_stack_start, &block_stack_bytes, &block_stack_emitted);
-                    }
-                    
-                    if ((parsed_storage_class == STORAGE_EXTERN || parsed_dllimport)) {
-                    
-                        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "extern declaration '%s' is initialized", name ? name : "");
-                        skip_initializer ();
-                    
-                    } else if (parsed_storage_class == STORAGE_STATIC && name) {
-                    
-                        if (declarator_has_array && !declarator_is_pointer && (parsed_type_size & 0x1f) == (DATA_CHAR & 0x1f) && (is_string_token () || tok.kind == TOK_LBRACE)) {
-                        
-                            if (is_string_token ()) {
-                                parse_string_initializer_values (init_values, MAX_AGG_FIELDS, &init_value_count);
-                            } else {
-                                parse_char_array_initializer_values (init_values, MAX_AGG_FIELDS, &init_value_count, declarator_last_array_count);
-                            }
-                            
-                            if (declarator_array_unsized) {
-                                declarator_array_count = init_value_count;
-                            }
-                        
-                        } else if (declarator_is_pointer && is_string_token ()) {
-                        
-                            init_values[0].low = 0;
-                            init_values[0].high = 0;
-                            
-                            init_symbols[0] = emit_string_literal_global ();
-                            init_value_count = 1;
-                        
-                        } else if (!declarator_is_pointer && parsed_type_is_floating) {
-                        
-                            init_values[0] = parse_floating_const_expr_bits_now (parsed_type_size);
-                            init_symbols[0] = 0;
-                            init_value_count = 1;
-                        
-                        } else {
-                        
-                            {
-                            
-                                int saved_accept_symbol_addresses = global_initializer_accept_symbol_addresses;
-                                global_initializer_accept_symbol_addresses = declarator_is_pointer || parsed_type_is_aggregate || declarator_has_array;
-                                
-                                if (declarator_has_array && !declarator_is_pointer && parsed_type_is_aggregate && parsed_field_count > 0 && tok.kind == TOK_LBRACE) {
-                                    parse_global_initializer_values_padded_elements (init_values, init_symbols, MAX_AGG_FIELDS, &init_value_count, aggregate_initializer_value_field_count (parsed_field_sizes, parsed_field_count));
-                                } else {
-                                    parse_global_initializer_values (init_values, init_symbols, MAX_AGG_FIELDS, &init_value_count);
-                                }
-                                
-                                global_initializer_accept_symbol_addresses = saved_accept_symbol_addresses;
-                            
-                            }
-                            
-                            if (declarator_has_array && declarator_array_unsized) {
-                            
-                                if (parsed_type_is_aggregate && object_field_count > 0) {
-                                    declarator_array_count = (init_value_count + object_field_count - 1) / object_field_count;
-                                } else {
-                                    declarator_array_count = init_value_count;
-                                }
-                            
-                            }
-                        
-                        }
-                    
-                    } else if (object_is_auto && declarator_has_array && declarator_is_pointer && tok.kind == TOK_LBRACE) {
-                    
-                        int elem_index = 0;
-                        int elem_size = DATA_PTR;
-                        int first_init_index = init_count;
-                        
-                        get_token ();
-                        
-                        while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
-                        
-                            if (init_count < MAX_LOCAL_INITS) {
-                            
-                                inits[init_count].offset = object_offset + (elem_index * elem_size);
-                                inits[init_count].size = elem_size;
-                                
-                                if (is_string_token ()) {
-                                
-                                    inits[init_count].kind = LOCAL_INIT_ADDRESS;
-                                    inits[init_count].symbol = emit_string_literal_global ();
-                                    inits[init_count].value.low = 0;
-                                    inits[init_count].value.high = 0;
-                                    inits[init_count].source_offset = 0;
-                                    inits[init_count].source_size = 0;
-                                    
-                                    switch_section (SECTION_TEXT);
-                                
-                                } else {
-                                    parse_local_initializer_value (&inits[init_count], elem_size, 0);
-                                }
-                                
-                                init_count++;
-                            
-                            } else {
-                                skip_initializer ();
-                            }
-                            
-                            elem_index++;
-                            
-                            if (!_accept (TOK_COMMA)) {
-                                break;
-                            }
-                            
-                            if (tok.kind == TOK_RBRACE) {
-                                break;
-                            }
-                        
-                        }
-                        
-                        if (declarator_array_unsized && elem_index > 0 && (elem_index * elem_size) > object_size) {
-                        
-                            long old_offset = object_offset;
-                            long new_offset;
-                            long delta;
-                            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;
-                            object_size = elem_index * elem_size;
-                            
-                            if (local_symbol_count > 0 && name && local_symbols[local_symbol_count - 1].name
-                                && strcmp (local_symbols[local_symbol_count - 1].name, name) == 0) {
-                            
-                                local_symbols[local_symbol_count - 1].offset = object_offset;
-                                local_symbols[local_symbol_count - 1].size = object_size;
-                            
-                            }
-                            
-                            for (adj_i = first_init_index; adj_i < init_count; adj_i++) {
-                                inits[adj_i].offset += delta;
-                            }
-                        
-                        }
-                        
-                        expect (TOK_RBRACE, "}");
-                    
-                    } else if (object_is_auto && declarator_has_array && !declarator_is_pointer && (parsed_type_size & 0x1f) == (DATA_CHAR & 0x1f) && is_string_token ()) {
-                    
-                        int first_init_index = init_count;
-                        int value_count = 0;
-                        
-                        int64_s values[MAX_STRING_INIT_BYTES];
-                        int i;
-                        
-                        parse_string_initializer_values (values, MAX_STRING_INIT_BYTES, &value_count);
-                        
-                        if (declarator_array_unsized && value_count > 0 && value_count > object_size) {
-                        
-                            long old_offset = object_offset;
-                            long new_offset;
-                            long delta;
-                            
-                            int adj_i;
-                            current_local_stack_size += value_count - 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;
-                            declarator_array_count = value_count;
-                            
-                            if (local_symbol_count > 0 && name && local_symbols[local_symbol_count - 1].name && strcmp (local_symbols[local_symbol_count - 1].name, name) == 0) {
-                            
-                                local_symbols[local_symbol_count - 1].offset = object_offset;
-                                local_symbols[local_symbol_count - 1].size = object_size;
-                            
-                            }
-                            
-                            for (adj_i = first_init_index; adj_i < init_count; adj_i++) {
-                                inits[adj_i].offset += delta;
-                            }
-                        
-                        }
-                        
-                        for (i = 0; i < object_size; i++) {
-                        
-                            if (init_count >= MAX_LOCAL_INITS) {
-                                continue;
-                            }
-                            
-                            inits[init_count].offset = object_offset + i;
-                            inits[init_count].size = 1;
-                            inits[init_count].kind = LOCAL_INIT_CONST;
-                            inits[init_count].symbol = 0;
-                            inits[init_count].value.low = (i < value_count) ? (values[i].low & 0xffUL) : 0;
-                            inits[init_count].value.high = 0;
-                            inits[init_count].source_offset = 0;
-                            inits[init_count].source_size = 0;
-                            
-                            init_count++;
-                        
-                        }
-                    
-                    } else if (object_is_auto && !declarator_is_pointer && (parsed_type_is_aggregate || declarator_has_array) && tok.kind == TOK_LBRACE) {
-                        parse_local_aggregate_initializer_values (inits, &init_count, MAX_LOCAL_INITS, object_offset, object_fields, object_field_count);
-                    } else if (object_is_auto && auto_initializer_needs_runtime_now ()) {
-                    
-                        long needed_stack_bytes = align_up_long (current_local_stack_size - block_stack_start, 4);
-                        
-                        if (!block_stack_emitted) {
-                        
-                            block_stack_bytes = needed_stack_bytes;
-                            emit_stack_adjust (block_stack_bytes, 1);
-                            
-                            if (!is_function_body) {
-                                current_block_cleanup_bytes += block_stack_bytes;
-                            }
-                            
-                            block_stack_emitted = (block_stack_bytes > 0);
-                        
-                        } 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) {
-                                current_block_cleanup_bytes += extra_stack_bytes;
-                            }
-                            
-                            block_stack_bytes = needed_stack_bytes;
-                        
-                        }
-                        
-                        emit_local_initializers (inits, init_count);
-                        init_count = 0;
-                        
-                        if (!declarator_is_pointer && (parsed_type_is_aggregate || declarator_has_array)) {
-                        
-                            emit_load_local_address_to_reg_now ("edx", object_offset);
-                            
-                            if (!emit_aggregate_copy_from_current_rhs_to_addr_reg_now ("edx", 0, object_size)) {
-                            
-                                if (tok.kind == TOK_IDENT && token_identifier_is_function_call_rhs_now () &&
-                                    get_global_symbol_kind (tok.ident) == GLOBAL_SYMBOL_FUNCTION &&
-                                    get_global_symbol_size (tok.ident) > (DATA_LLONG & 0x1f)) {
-                                
-                                    pending_struct_return_lhs = find_local_symbol (name);
-                                    pending_struct_return_global_name = 0;
-                                    
-                                    emit_load_assignment_rhs_expression_to_reg ("eax");
-                                
-                                } else if (object_init_size == (DATA_LLONG & 0x1f) && !parsed_type_is_floating && !declarator_has_array) {
-                                
-                                    emit_load_assignment_rhs_expression_to_pair ("eax", "edx", parsed_type_is_unsigned);
-                                    emit_store_pair_to_local64 (object_offset, "eax", "edx");
-                                
-                                } else {
-                                
-                                    emit_load_assignment_rhs_expression_to_reg ("eax");
-                                    emit_store_reg_to_local (object_offset, object_init_size, "eax");
-                                
-                                }
-                            
-                            }
-                        
-                        } else if (!declarator_is_pointer && parsed_type_is_floating) {
-                        
-                            emit_load_floating_rhs_expression_now (object_init_size);
-                            emit_store_floating_to_local_now (object_offset, object_init_size);
-                        
-                        } else if (object_init_size == (DATA_LLONG & 0x1f) && !parsed_type_is_floating && !declarator_is_pointer) {
-                        
-                            emit_load_assignment_rhs_expression_to_pair ("eax", "edx", parsed_type_is_unsigned);
-                            emit_store_pair_to_local64 (object_offset, "eax", "edx");
-                        
-                        } else {
-                        
-                            emit_load_assignment_rhs_expression_to_reg ("eax");
-                            emit_store_reg_to_local (object_offset, object_init_size, "eax");
-                        
-                        }
-                    
-                    } else if (object_is_auto && init_count < MAX_LOCAL_INITS) {
-                    
-                        inits[init_count].offset = object_offset;
-                        inits[init_count].size = object_init_size;
-                        
-                        if (declarator_is_pointer && is_string_token ()) {
-                        
-                            inits[init_count].kind = LOCAL_INIT_ADDRESS;
-                            inits[init_count].symbol = emit_string_literal_global ();
-                            inits[init_count].value.low = 0;
-                            inits[init_count].value.high = 0;
-                            inits[init_count].source_offset = 0;
-                            inits[init_count].source_size = 0;
-                            
-                            switch_section (SECTION_TEXT);
-                        
-                        } else {
-                            parse_local_initializer_value (&inits[init_count], object_init_size, (!declarator_is_pointer && parsed_type_is_floating));
-                        }
-                        
-                        init_count++;
-                    
-                    } else {
-                        skip_initializer ();
-                    }
-                
-                }
-                
-                if (name && parsed_storage_class == STORAGE_STATIC) {
-                
-                    make_local_static_label (static_label, sizeof (static_label), name);
-                    
-                    if (add_global_symbol (static_label, GLOBAL_SYMBOL_OBJECT, 0, name_start, name_caret, name_line)) {
-                    
-                        set_global_symbol_size (static_label, declarator_is_pointer ? DATA_PTR : declarator_object_size (parsed_type_size));
-                        set_global_symbol_pointer_info (static_label, declarator_pointer_depth,
-                            declarator_is_pointer ? declarator_pointed_size_now () :
-                                declarator_element_size_from_fields (parsed_type_size, object_fields, object_field_count));
-                        set_global_symbol_unsigned (static_label, (declarator_is_pointer || declarator_has_function) ? 0 : parsed_type_is_unsigned);
-                        set_global_symbol_floating (static_label, (declarator_is_pointer || declarator_has_function) ? 0 : parsed_type_is_floating);
-                        set_global_symbol_array (static_label, declarator_has_array);
-                        set_global_symbol_array_count (static_label, declarator_has_array ? declarator_array_count : 0);
-                        set_global_symbol_array_dimensions (static_label, declarator_has_array ? declarator_array_dimensions : 0);
-                        set_global_symbol_array_element_size (static_label, declarator_array_element_size_now (parsed_type_size));
-                        
-                        emit_block_static_object (static_label,
-                            declarator_is_pointer ? DATA_PTR : (parsed_type_is_aggregate ? parsed_type_size : (parsed_type_size & 0x1f)),
-                                declarator_has_array, declarator_array_count,
-                                    object_fields, object_field_count,
-                                        init_values, init_symbols, init_value_count,
-                                            (!declarator_is_pointer && parsed_type_is_aggregate));
-                    
-                    }
-                    
-                    add_static_local_symbol (name, static_label,
-                        declarator_object_size (parsed_type_size),
-                            type_alignment (declarator_is_pointer ? DATA_PTR : parsed_type_size),
-                                (declarator_is_pointer ? 0 : parsed_type_is_unsigned),
-                                    block_scope_start, name_line, name_start, name_caret);
-                    
-                    set_local_symbol_floating (name, declarator_is_pointer ? 0 : parsed_type_is_floating);
-                    set_local_symbol_array (name, declarator_has_array);
-                    set_local_symbol_array_dimensions (name, declarator_has_array ? declarator_array_dimensions : 0);
-                    set_local_symbol_array_element_size (name, declarator_array_element_size_now (parsed_type_size));
-                    set_local_symbol_pointer_info (name, declarator_effective_pointer_depth_now (),
-                        declarator_effective_pointed_size_now (parsed_type_size, object_fields, object_field_count));
-                    
-                    if (!declarator_is_pointer && parsed_type_tag_name[0]) {
-                    
-                        struct local_symbol *lsym = find_local_symbol (name);
-                        
-                        if (lsym) {
-                            lsym->tag_name = xstrdup (parsed_type_tag_name);
-                        }
-                    
-                    }
-                
-                }
-                
-                for (i = 0; i < MAX_AGG_FIELDS; i++) {
-                
-                    if (init_symbols[i]) {
-                    
-                        free (init_symbols[i]);
-                        init_symbols[i] = 0;
-                    
-                    }
-                
-                }
-                
-                if (name) {
-                    free (name);
-                }
-                
-                if (!_accept (TOK_COMMA)) {
-                    break;
-                }
-            
-            }
-            
-            expect (TOK_SEMI, ";");
-            
-            if (block_stack_emitted) {
-                ensure_block_stack_allocated (block_stack_start, &block_stack_bytes, &block_stack_emitted);
-            }
-            
-            continue;
-        
-        }
-        
-        if (declaration_phase) {
-        
-            declaration_phase = 0;
-            
-            {
-            
-                long needed_stack_bytes = align_up_long (current_local_stack_size - block_stack_start, 4);
-                
-                if (!block_stack_emitted) {
-                
-                    block_stack_bytes = needed_stack_bytes;
-                    
-                    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;
-                    }
-                    
-                    block_stack_emitted = (block_stack_bytes > 0);
-                
-                } else if (needed_stack_bytes > block_stack_bytes) {
-                
-                    long extra_stack_bytes = needed_stack_bytes - block_stack_bytes;
-                    
-                    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;
-                    }
-                    
-                    block_stack_bytes = needed_stack_bytes;
-                
-                }
-            
-            }
-            
-            emit_local_initializers (inits, init_count);
-            init_count = 0;
-        
-        }
-        
-        parse_statement ();
-    
-    }
-    
-    if (declaration_phase) {
-    
-        /**
-         * The block contained declarations only.  We still need to reserve
-         * stack space for those automatic objects, otherwise a function like
-         *
-         *     void f(void) { int a; }
-         *
-         * would produce no `sub esp, ...` at all.
-         */
-        declaration_phase = 0;
-        
-        {
-        
-            long needed_stack_bytes = align_up_long (current_local_stack_size - block_stack_start, 4);
-            
-            if (!block_stack_emitted) {
-            
-                block_stack_bytes = needed_stack_bytes;
-                
-                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) {
-            
-                if (!current_function_frame_deferred) {
-                    emit_stack_adjust (needed_stack_bytes - block_stack_bytes, 1);
-                }
-                
-                block_stack_bytes = needed_stack_bytes;
-            
-            }
-        
-        }
-        
-        emit_local_initializers (inits, init_count);
-        init_count = 0;
-    
-    }
-    
-    expect (TOK_RBRACE, "}");
-    
-    if (!is_function_body && !current_function_frame_deferred && block_stack_emitted && block_stack_bytes > 0) {
-    
-        emit_stack_adjust (block_stack_bytes, 0);
-        
-        if (current_block_cleanup_bytes >= block_stack_bytes) {
-            current_block_cleanup_bytes -= block_stack_bytes;
-        } else {
-            current_block_cleanup_bytes = 0;
-        }
-    
-    }
-    
-    current_parse_block_depth--;
-    truncate_local_symbols (block_local_start, block_stack_start);
-
-}
-
-static int is_assignment_operator (enum token_kind k) {
-
-    switch (k) {
-    
-        case TOK_ASSIGN:
-        case TOK_PLUSEQ:
-        case TOK_MINUSEQ:
-        case TOK_STAREQ:
-        case TOK_SLASHEQ:
-        case TOK_MODEQ:
-        case TOK_ANDEQ:
-        case TOK_OREQ:
-        case TOK_XOREQ:
-        case TOK_LSHEQ:
-        case TOK_RSHEQ:
-        
-            return 1;
-        
-        default:
-        
-            return 0;
-    
-    }
-
-}
-
-static void emit_load_local_to_reg_ex (const char *reg, long offset, int size, int is_unsigned) {
-
-    char memref[64];
-    size &= 0x1f;
-    
-    if (!state->ofp || !reg) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        format_intel_ebp_offset (memref, sizeof (memref), offset);
-        
-        if (size == (DATA_CHAR & 0x1f)) {
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s %s, byte %s\n" : "    %s %s, byte ptr %s\n"), is_unsigned ? "movzx" : "movsx", reg, memref);
-        } else if (size == (DATA_SHORT & 0x1f)) {
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s %s, word %s\n" : "    %s %s, word ptr %s\n"), is_unsigned ? "movzx" : "movsx", reg, memref);
-        } else {
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword %s\n" : "    mov %s, dword ptr %s\n"), reg, memref);
-        }
-    
-    } else {
-    
-        if (size == (DATA_CHAR & 0x1f)) {
-            fprintf (state->ofp, "    %s %ld(%%ebp), %%%s\n", is_unsigned ? "movzbl" : "movsbl", offset, reg);
-        } else if (size == (DATA_SHORT & 0x1f)) {
-            fprintf (state->ofp, "    %s %ld(%%ebp), %%%s\n", is_unsigned ? "movzwl" : "movswl", offset, reg);
-        } else {
-            fprintf (state->ofp, "    movl %ld(%%ebp), %%%s\n", offset, reg);
-        }
-    
-    }
-
-}
-
-static void emit_load_local_to_reg (const char *reg, long offset, int size) {
-    emit_load_local_to_reg_ex (reg, offset, size, 0);
-}
-
-static void emit_load_global_to_reg_ex (const char *reg, const char *symbol, int size, int is_unsigned) {
-
-    const char *asm_symbol;
-    size &= 0x1f;
-    
-    if (!state->ofp || !reg || !symbol) {
-        return;
-    }
-    
-    emit_extern_reference_symbol (symbol, size);
-    
-    if (get_global_symbol_dllimport (symbol) && get_global_symbol_kind (symbol) == GLOBAL_SYMBOL_OBJECT) {
-    
-        asm_symbol = asm_global_import_symbol_name (symbol);
-        
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-        
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [%s]\n" : "    mov %s, dword ptr %s\n"), reg, asm_symbol);
-            
-            if (size == (DATA_CHAR & 0x1f)) {
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s %s, byte [%s]\n" : "    %s %s, byte ptr [%s]\n"), is_unsigned ? "movzx" : "movsx", reg, reg);
-            } else if (size == (DATA_SHORT & 0x1f)) {
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s %s, word [%s]\n" : "    %s %s, word ptr [%s]\n"), is_unsigned ? "movzx" : "movsx", reg, reg);
-            } else {
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [%s]\n" : "    mov %s, dword ptr [%s]\n"), reg, reg);
-            }
-        
-        } else {
-        
-            fprintf (state->ofp, "    movl %s, %%%s\n", asm_symbol, reg);
-            
-            if (size == (DATA_CHAR & 0x1f)) {
-                fprintf (state->ofp, "    %s (%%%s), %%%s\n", is_unsigned ? "movzbl" : "movsbl", reg, reg);
-            } else if (size == (DATA_SHORT & 0x1f)) {
-                fprintf (state->ofp, "    %s (%%%s), %%%s\n", is_unsigned ? "movzwl" : "movswl", reg, reg);
-            } else {
-                fprintf (state->ofp, "    movl (%%%s), %%%s\n", reg, reg);
-            }
-        
-        }
-        
-        return;
-    
-    }
-    
-    asm_symbol = asm_global_symbol_name (symbol);
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (size == (DATA_CHAR & 0x1f)) {
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s %s, byte [%s]\n" : "    %s %s, byte ptr %s\n"), is_unsigned ? "movzx" : "movsx", reg, asm_symbol);
-        } else if (size == (DATA_SHORT & 0x1f)) {
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s %s, word [%s]\n" : "    %s %s, word ptr %s\n"), is_unsigned ? "movzx" : "movsx", reg, asm_symbol);
-        } else {
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [%s]\n" : "    mov %s, dword ptr %s\n"), reg, asm_symbol);
-        }
-    
-    } else {
-    
-        if (size == (DATA_CHAR & 0x1f)) {
-            fprintf (state->ofp, "    %s %s, %%%s\n", is_unsigned ? "movzbl" : "movsbl", asm_symbol, reg);
-        } else if (size == (DATA_SHORT & 0x1f)) {
-            fprintf (state->ofp, "    %s %s, %%%s\n", is_unsigned ? "movzwl" : "movswl", asm_symbol, reg);
-        } else {
-            fprintf (state->ofp, "    movl %s, %%%s\n", asm_symbol, reg);
-        }
-    
-    }
-
-}
-
-static void emit_load_global_to_reg (const char *reg, const char *symbol, int size) {
-    emit_load_global_to_reg_ex (reg, symbol, size, 0);
-}
-
-static void emit_store_reg_to_local (long offset, int size, const char *reg) {
-
-    char memref[64];
-    
-    if (!state->ofp || !reg) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        format_intel_ebp_offset (memref, sizeof (memref), offset);
-
-        if (size == (DATA_CHAR & 0x1f)) {
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov byte %s, %cl\n" : "    mov byte ptr %s, %cl\n"), memref, reg[1]);
-        } else if (size == (DATA_SHORT & 0x1f)) {
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov word %s, %cx\n" : "    mov word ptr %s, %cx\n"), memref, reg[1]);
-        } else {
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword %s, %s\n" : "    mov dword ptr %s, %s\n"), memref, reg);
-        }
-    
-    } else {
-    
-        if (size == (DATA_CHAR & 0x1f)) {
-            fprintf (state->ofp, "    movb %%%cl, %ld(%%ebp)\n", reg[1], offset);
-        } else if (size == (DATA_SHORT & 0x1f)) {
-            fprintf (state->ofp, "    movw %%%cx, %ld(%%ebp)\n", reg[1], offset);
-        } else {
-            fprintf (state->ofp, "    movl %%%s, %ld(%%ebp)\n", reg, offset);
-        }
-    
-    }
-
-}
-
-static void emit_store_reg_to_global (const char *symbol, int size, const char *reg) {
-
-    const char *asm_symbol;
-    
-    if (!state->ofp || !symbol || !reg) {
-        return;
-    }
-    
-    if (get_global_symbol_dllimport (symbol) && get_global_symbol_kind (symbol) == GLOBAL_SYMBOL_OBJECT) {
-    
-        const char *addr_reg = (strcmp (reg, "ecx") == 0) ? "edx" : "ecx";
-        
-        asm_symbol = asm_global_import_symbol_name (symbol);
-        emit_extern_reference_symbol (symbol, size);
-        
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-        
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [%s]\n" : "    mov %s, dword ptr %s\n"), addr_reg, asm_symbol);
-            
-            if (size == (DATA_CHAR & 0x1f)) {
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov byte [%s], %cl\n" : "    mov byte ptr [%s], %cl\n"), addr_reg, reg[1]);
-            } else if (size == (DATA_SHORT & 0x1f)) {
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov word [%s], %cx\n" : "    mov word ptr [%s], %cx\n"), addr_reg, reg[1]);
-            } else {
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword [%s], %s\n" : "    mov dword ptr [%s], %s\n"), addr_reg, reg);
-            }
-        
-        } else {
-        
-            fprintf (state->ofp, "    movl %s, %%%s\n", asm_symbol, addr_reg);
-            
-            if (size == (DATA_CHAR & 0x1f)) {
-                fprintf (state->ofp, "    movb %%%cl, (%%%s)\n", reg[1], addr_reg);
-            } else if (size == (DATA_SHORT & 0x1f)) {
-                fprintf (state->ofp, "    movw %%%cx, (%%%s)\n", reg[1], addr_reg);
-            } else {
-                fprintf (state->ofp, "    movl %%%s, (%%%s)\n", reg, addr_reg);
-            }
-        
-        }
-        
-        return;
-    
-    }
-    
-    asm_symbol = asm_global_symbol_name (symbol);
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (size == (DATA_CHAR & 0x1f)) {
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov byte [%s], %cl\n" : "    mov byte ptr %s, %cl\n"), asm_symbol, reg[1]);
-        } else if (size == (DATA_SHORT & 0x1f)) {
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov word [%s], %cx\n" : "    mov word ptr %s, %cx\n"), asm_symbol, reg[1]);
-        } else {
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword [%s], %s\n" : "    mov dword ptr %s, %s\n"), asm_symbol, reg);
-        }
-    
-    } else {
-    
-        if (size == (DATA_CHAR & 0x1f)) {
-            fprintf (state->ofp, "    movb %%%cl, %s\n", reg[1], asm_symbol);
-        } else if (size == (DATA_SHORT & 0x1f)) {
-            fprintf (state->ofp, "    movw %%%cx, %s\n", reg[1], asm_symbol);
-        } else {
-            fprintf (state->ofp, "    movl %%%s, %s\n", reg, asm_symbol);
-        }
-    
-    }
-
-}
-
-static void emit_load_local64_to_pair (long offset, const char *lo, const char *hi) {
-
-    char memref_lo[64], memref_hi[64];
-    
-    if (!state->ofp || !lo || !hi) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        format_intel_ebp_offset (memref_lo, sizeof (memref_lo), offset);
-        format_intel_ebp_offset (memref_hi, sizeof (memref_hi), offset + 4);
-        
-        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword %s\n" : "    mov %s, dword ptr %s\n"), lo, memref_lo);
-        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword %s\n" : "    mov %s, dword ptr %s\n"), hi, memref_hi);
-    
-    } else {
-    
-        fprintf (state->ofp, "    movl %ld(%%ebp), %%%s\n", offset, lo);
-        fprintf (state->ofp, "    movl %ld(%%ebp), %%%s\n", offset + 4, hi);
-    
-    }
-
-}
-
-static void emit_store_pair_to_local64 (long offset, const char *lo, const char *hi) {
-
-    char memref_lo[64], memref_hi[64];
-    
-    if (!state->ofp || !lo || !hi) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        format_intel_ebp_offset (memref_lo, sizeof (memref_lo), offset);
-        format_intel_ebp_offset (memref_hi, sizeof (memref_hi), offset + 4);
-        
-        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword %s, %s\n" : "    mov dword ptr %s, %s\n"), memref_lo, lo);
-        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword %s, %s\n" : "    mov dword ptr %s, %s\n"), memref_hi, hi);
-    
-    } else {
-    
-        fprintf (state->ofp, "    movl %%%s, %ld(%%ebp)\n", lo, offset);
-        fprintf (state->ofp, "    movl %%%s, %ld(%%ebp)\n", hi, offset + 4);
-    
-    }
-
-}
-
-static void emit_load_global64_to_pair (const char *lo, const char *hi, const char *symbol) {
-
-    const char *asm_symbol;
-    
-    if (!state->ofp || !lo || !hi || !symbol) {
-        return;
-    }
-    
-    emit_extern_reference_symbol (symbol, DATA_LLONG & 0x1f);
-    asm_symbol = asm_global_symbol_name (symbol);
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [%s]\n" : "    mov %s, dword ptr %s\n"), lo, asm_symbol);
-        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [%s + 4]\n" : "    mov %s, dword ptr %s + 4\n"), hi, asm_symbol);
-    
-    } else {
-    
-        fprintf (state->ofp, "    movl %s, %%%s\n", asm_symbol, lo);
-        fprintf (state->ofp, "    movl %s+4, %%%s\n", asm_symbol, hi);
-    
-    }
-
-}
-
-static void emit_store_pair_to_global64 (const char *symbol, const char *lo, const char *hi) {
-
-    const char *asm_symbol;
-    
-    if (!state->ofp || !symbol || !lo || !hi) {
-        return;
-    }
-    
-    emit_extern_reference_symbol (symbol, DATA_LLONG & 0x1f);
-    asm_symbol = asm_global_symbol_name (symbol);
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword [%s], %s\n" : "    mov dword ptr %s, %s\n"), asm_symbol, lo);
-        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword [%s + 4], %s\n" : "    mov dword ptr %s + 4, %s\n"), asm_symbol, hi);
-    
-    } else {
-    
-        fprintf (state->ofp, "    movl %%%s, %s\n", lo, asm_symbol);
-        fprintf (state->ofp, "    movl %%%s, %s+4\n", hi, asm_symbol);
-    
-    }
-
-}
-
-static void emit_call_identifier_to_reg_now (const char *name, const char *reg, const char *name_start, const char *name_caret, unsigned long name_line);
-static void emit_push_pending_struct_return_address_now (int stack_arg_bytes);
-
-static int emit_push_aggregate_from_addr_reg_now (const char *reg, int size) {
-
-    int offset;
-    int chunk;
-    
-    if (!reg || size <= (DATA_PTR & 0x1f)) {
-        return 0;
-    }
-    
-    if (!state->ofp) {
-        return 1;
-    }
-    
-    for (offset = size; offset > 0; ) {
-    
-        if (offset >= 4) {
-        
-            chunk = 4;
-            offset -= 4;
-        
-        } else if (offset >= 2) {
-        
-            chunk = 2;
-            offset -= 2;
-        
-        } else {
-        
-            chunk = 1;
-            offset -= 1;
-        
-        }
-        
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-        
-            if (state->syntax & ASM_SYNTAX_NASM) {
-            
-                if (chunk == 4) {
-                    fprintf (state->ofp, "    push dword [%s + %d]\n", reg, offset);
-                } else if (chunk == 2) {
-                
-                    fprintf (state->ofp, "    movzx edx, word [%s + %d]\n", reg, offset);
-                    fprintf (state->ofp, "    push edx\n");
-                
-                } else {
-                
-                    fprintf (state->ofp, "    movzx edx, byte [%s + %d]\n", reg, offset);
-                    fprintf (state->ofp, "    push edx\n");
-                
-                }
-            
-            } else {
-            
-                if (chunk == 4) {
-                    fprintf (state->ofp, "    push dword ptr [%s + %d]\n", reg, offset);
-                } else if (chunk == 2) {
-                
-                    fprintf (state->ofp, "    movzx edx, word ptr [%s + %d]\n", reg, offset);
-                    fprintf (state->ofp, "    push edx\n");
-                
-                } else {
-                
-                    fprintf (state->ofp, "    movzx edx, byte ptr [%s + %d]\n", reg, offset);
-                    fprintf (state->ofp, "    push edx\n");
-                
-                }
-            
-            }
-        
-        } else {
-        
-            if (chunk == 4) {
-                fprintf (state->ofp, "    pushl %d(%%%s)\n", offset, reg);
-            } else if (chunk == 2) {
-            
-                fprintf (state->ofp, "    movzwl %d(%%%s), %%edx\n", offset, reg);
-                fprintf (state->ofp, "    pushl %%edx\n");
-            
-            } else {
-            
-                fprintf (state->ofp, "    movzbl %d(%%%s), %%edx\n", offset, reg);
-                fprintf (state->ofp, "    pushl %%edx\n");
-            
-            }
-        
-        }
-    
-    }
-    
-    return 1;
-
-}
-
-static void emit_call_pointer_in_reg_now (const char *fn_reg, const char *result_reg);
-
-static int is_arithmetic_binary_operator (enum token_kind k) {
-
-    return  k == TOK_PLUS || k == TOK_MINUS || k == TOK_STAR || k == TOK_BSLASH ||
-                k == TOK_MOD || k == TOK_AMPER || k == TOK_PIPE || k == TOK_CARET ||
-                    k == TOK_LSH || k == TOK_RSH;
-
-}
-
-static void emit_push_reg_now (const char *reg) {
-
-    if (!state->ofp || !reg) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-        fprintf (state->ofp, "    push %s\n", reg);
-    } else {
-        fprintf (state->ofp, "    pushl %%%s\n", reg);
-    }
-
-}
-
-static void emit_pop_reg_now (const char *reg) {
-
-    if (!state->ofp || !reg) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-        fprintf (state->ofp, "    pop %s\n", reg);
-    } else {
-        fprintf (state->ofp, "    popl %%%s\n", reg);
-    }
-
-}
-
-static void emit_mov_reg_to_reg_now (const char *dst, const char *src) {
-
-    if (!state->ofp || !dst || !src || strcmp (dst, src) == 0) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-        fprintf (state->ofp, "    mov %s, %s\n", dst, src);
-    } else {
-        fprintf (state->ofp, "    movl %%%s, %%%s\n", src, dst);
-    }
-
-}
-
-static void emit_load_indexed_pointer_to_reg_now (const char *base_reg, const char *index_reg) {
-
-    if (!state->ofp || !base_reg || !index_reg) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (state->syntax & ASM_SYNTAX_NASM) {
-            fprintf (state->ofp, "    mov %s, dword [%s + %s * 4]\n", base_reg, base_reg, index_reg);
-        } else {
-            fprintf (state->ofp, "    mov %s, dword ptr [%s + %s * 4]\n", base_reg, base_reg, index_reg);
-        }
-    
-    } else {
-        fprintf (state->ofp, "    movl (%%%s,%%%s,4), %%%s\n", base_reg, index_reg, base_reg);
-    }
-
-}
-
-static void emit_load_indexed_char_to_reg_now (const char *base_reg, const char *index_reg, const char *dst_reg, int is_unsigned) {
-
-    if (!state->ofp || !base_reg || !index_reg || !dst_reg) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (state->syntax & ASM_SYNTAX_NASM) {
-            fprintf (state->ofp, "    %s %s, byte [%s + %s]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg);
-        } else {
-            fprintf (state->ofp, "    %s %s, byte ptr [%s + %s]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg);
-        }
-    
-    } else {
-        fprintf (state->ofp, "    %s (%%%s,%%%s), %%%s\n", is_unsigned ? "movzbl" : "movsbl", base_reg, index_reg, dst_reg);
-    }
-
-}
-
-static void emit_load_indexed_sized_to_reg_ex_now (const char *base_reg, const char *index_reg, const char *dst_reg, int elem_size, int is_unsigned) {
-
-    int scale = 1;
-    
-    const char *gasop = is_unsigned ? "movzbl" : "movsbl";
-    const char *atype = "byte";
-    
-    if (!state->ofp || !base_reg || !index_reg || !dst_reg) {
-        return;
-    }
-    
-    elem_size &= 0x1f;
-    
-    if (elem_size == (DATA_SHORT & 0x1f)) {
-    
-        scale = 2;
-        
-        atype = "word";
-        gasop = "movswl";
-    
-    } else if (elem_size == (DATA_INT & 0x1f) || elem_size == (DATA_LONG & 0x1f) || elem_size == DATA_PTR) {
-    
-        scale = 4;
-        
-        atype = "dword";
-        gasop = "movl";
-    
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (elem_size == (DATA_CHAR & 0x1f)) {
-            emit_load_indexed_char_to_reg_now (base_reg, index_reg, dst_reg, is_unsigned);
-        } else if (scale == 1) {
-        
-            if (strcmp (atype, "byte") == 0) {
-            
-                if (state->syntax & ASM_SYNTAX_NASM) {
-                    fprintf (state->ofp, "    %s %s, byte [%s + %s]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg);
-                } else {
-                    fprintf (state->ofp, "    %s %s, byte ptr [%s + %s]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg);
-                }
-            
-            } else if (elem_size == (DATA_SHORT & 0x1f)) {
-            
-                if (state->syntax & ASM_SYNTAX_NASM) {
-                    fprintf (state->ofp, "    %s %s, word [%s + %s]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg);
-                } else {
-                    fprintf (state->ofp, "    %s %s, word ptr [%s + %s]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg);
-                }
-            
-            } else if (state->syntax & ASM_SYNTAX_NASM) {
-                fprintf (state->ofp, "    mov %s, %s [%s + %s]\n", dst_reg, atype, base_reg, index_reg);
-            } else {
-                fprintf (state->ofp, "    mov %s, %s ptr [%s + %s]\n", dst_reg, atype, base_reg, index_reg);
-            }
-        
-        } else {
-        
-            if (strcmp (atype, "byte") == 0) {
-            
-                if (state->syntax & ASM_SYNTAX_NASM) {
-                    fprintf (state->ofp, "    %s %s, byte [%s + %s * %d]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg, scale);
-                } else {
-                    fprintf (state->ofp, "    %s %s, byte ptr [%s + %s * %d]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg, scale);
-                }
-            
-            } else if (elem_size == (DATA_SHORT & 0x1f)) {
-
-                if (state->syntax & ASM_SYNTAX_NASM) {
-                    fprintf (state->ofp, "    %s %s, word [%s + %s * %d]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg, scale);
-                } else {
-                    fprintf (state->ofp, "    %s %s, word ptr [%s + %s * %d]\n", is_unsigned ? "movzx" : "movsx", dst_reg, base_reg, index_reg, scale);
-                }
-
-            } else if (state->syntax & ASM_SYNTAX_NASM) {
-                fprintf (state->ofp, "    mov %s, %s [%s + %s * %d]\n", dst_reg, atype, base_reg, index_reg, scale);
-            } else {
-                fprintf (state->ofp, "    mov %s, %s ptr [%s + %s * %d]\n", dst_reg, atype, base_reg, index_reg, scale);
-            }
-        
-        }
-    
-    } else {
-    
-        if (scale == 1) {
-            fprintf (state->ofp, "    %s (%%%s,%%%s), %%%s\n", gasop, base_reg, index_reg, dst_reg);
-        } else {
-            fprintf (state->ofp, "    %s (%%%s,%%%s,%d), %%%s\n", gasop, base_reg, index_reg, scale, dst_reg);
-        }
-    
-    }
-
-}
-
-static void emit_load_indexed_sized_to_reg_now (const char *base_reg, const char *index_reg, const char *dst_reg, int elem_size) {
-    emit_load_indexed_sized_to_reg_ex_now (base_reg, index_reg, dst_reg, elem_size, 0);
-}
-
-static void emit_load_indexed_unsigned_sized_to_reg_now (const char *base_reg, const char *index_reg, const char *dst_reg, int elem_size) {
-    emit_load_indexed_sized_to_reg_ex_now (base_reg, index_reg, dst_reg, elem_size, 1);
-}
-
-static void emit_load_symbol_address_to_reg_now (const char *reg, const char *symbol, long offset, int is_local) {
-
-    const char *asm_symbol;
-    
-    if (!state->ofp || !reg) {
-        return;
-    }
-    
-    if (is_local) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-            fprintf (state->ofp, "    lea %s, [ebp%+ld]\n", reg, offset);
-        } else {
-            fprintf (state->ofp, "    leal %ld(%%ebp), %%%s\n", offset, reg);
-        }
-        
-        return;
-    
-    }
-    
-    if (!symbol) {
-        return;
-    }
-    
-    emit_extern_reference_symbol (symbol, DATA_PTR);
-    asm_symbol = asm_global_symbol_name (symbol);
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (state->syntax & ASM_SYNTAX_NASM) {
-            fprintf (state->ofp, "    mov %s, %s\n", reg, asm_symbol);
-        } else {
-            fprintf (state->ofp, "    mov %s, offset %s\n", reg, asm_symbol);
-        }
-    
-    } else {
-        fprintf (state->ofp, "    movl $%s, %%%s\n", asm_symbol, reg);
-    }
-
-}
-
-static void emit_add_indexed_scaled_address_to_reg_now (const char *base_reg, const char *index_reg, int elem_size) {
-
-    int raw_elem_size = elem_size;
-    int scale = 1;
-    
-    if (!state->ofp || !base_reg || !index_reg) {
-        return;
-    }
-    
-    if (raw_elem_size == DATA_SHORT || raw_elem_size == (DATA_SHORT & 0x1f)) {
-    
-        elem_size = DATA_SHORT & 0x1f;
-        scale = 2;
-    
-    } else if (raw_elem_size == DATA_INT || raw_elem_size == DATA_LONG || raw_elem_size == DATA_PTR || raw_elem_size == (DATA_INT & 0x1f)) {
-    
-        elem_size = DATA_INT & 0x1f;
-        scale = 4;
-    
-    } else if (elem_size > 1) {
-        scale = 0;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (scale == 0) {
-        
-            fprintf (state->ofp, "    imul %s, %d\n", index_reg, elem_size);
-            fprintf (state->ofp, "    lea %s, [%s + %s]\n", base_reg, base_reg, index_reg);
-        
-        } else if (scale == 1) {
-            fprintf (state->ofp, "    lea %s, [%s + %s]\n", base_reg, base_reg, index_reg);
-        } else {
-            fprintf (state->ofp, "    lea %s, [%s + %s * %d]\n", base_reg, base_reg, index_reg, scale);
-        }
-    
-    } else {
-    
-        if (scale == 0) {
-        
-            fprintf (state->ofp, "    imull $%d, %%%s, %%%s\n", elem_size, index_reg, index_reg);
-            fprintf (state->ofp, "    leal (%%%s,%%%s), %%%s\n", base_reg, index_reg, base_reg);
-        
-        } else if (scale == 1) {
-            fprintf (state->ofp, "    leal (%%%s,%%%s), %%%s\n", base_reg, index_reg, base_reg);
-        } else {
-            fprintf (state->ofp, "    leal (%%%s,%%%s,%d), %%%s\n", base_reg, index_reg, scale, base_reg);
-        }
-    
-    }
-
-}
-
-static void emit_load_subscript_index_to_reg_now (const char *index_reg) {
-
-    if (current_expression_mentions_64bit_symbol_now ()) {
-    
-        int is_unsigned = rhs_current_operand_is_unsigned_now ();
-        emit_load_assignment_rhs_expression_to_pair ("eax", "edx", is_unsigned);
-        
-        if (index_reg && strcmp (index_reg, "eax") != 0) {
-            emit_mov_reg_to_reg_now (index_reg, "eax");
-        }
-        
-        return;
-    
-    }
-    
-    emit_load_assignment_rhs_expression_to_reg (index_reg);
-
-}
-
-static int emit_parse_postfix_subscript_scaled_address_to_reg_now (const char *reg, int elem_size) {
-
-    const char *index_reg;
-    int saw_subscript = 0;
-    
-    if (!reg) {
-        reg = "eax";
-    }
-    
-    index_reg = (strcmp (reg, "ecx") == 0) ? "edx" : "ecx";
-    
-    while (tok.kind == TOK_LBRACK) {
-    
-        saw_subscript = 1;
-        get_token ();
-        
-        emit_push_reg_now (reg);
-        emit_load_subscript_index_to_reg_now (index_reg);
-        expect (TOK_RBRACK, "]");
-        emit_pop_reg_now (reg);
-        
-        if (tok.kind == TOK_LBRACK) {
-            emit_load_indexed_pointer_to_reg_now (reg, index_reg);
-        } else {
-            emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
-        }
-    
-    }
-    
-    return saw_subscript;
-
-}
-
-static int emit_parse_postfix_subscripts_to_reg_now (const char *reg, int elem_size, int pointer_depth, int pointed_size) {
-
-    const char *index_reg;
-    int saw_subscript = 0;
-    
-    if (!reg) {
-        reg = "eax";
-    }
-    
-    index_reg = (strcmp (reg, "ecx") == 0) ? "edx" : "ecx";
-    
-    while (tok.kind == TOK_LBRACK) {
-    
-        saw_subscript = 1;
-        get_token ();
-        
-        emit_push_reg_now (reg);
-        emit_load_subscript_index_to_reg_now (index_reg);
-        
-        expect (TOK_RBRACK, "]");
-        emit_pop_reg_now (reg);
-        
-        if (tok.kind == TOK_LBRACK) {
-        
-            if (pointer_depth == 0 && pointed_size > 0 && elem_size > pointed_size) {
-            
-                /*
-                 * This is a real multidimensional array row, not an array of
-                 * pointers.  For char a[7][3], a[i] is the address of the
-                 * three-byte row.  The old code treated every further subscript
-                 * as pointer traversal and loaded *(a + i), which turns the
-                 * first bytes of the row into a bogus pointer.
-                 */
-                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
-                elem_size = index_step_size (pointed_size);
-            
-            } else {
-            
-                emit_load_indexed_pointer_to_reg_now (reg, index_reg);
-                
-                if (pointer_depth > 0) {
-                    pointer_depth--;
-                }
-                
-                if (pointed_size > 0) {
-                    elem_size = (pointer_depth > 1) ? (DATA_PTR & 0x1f) : index_step_size (pointed_size);
-                }
-            
-            }
-        
-        } else {
-        
-            if (pointer_depth == 0 && pointed_size > 0 && elem_size > pointed_size) {
-                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
-            } else if (index_step_size (elem_size) > (DATA_PTR & 0x1f)) {
-                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
-            } else {
-                emit_load_indexed_sized_to_reg_now (reg, index_reg, reg, elem_size);
-            }
-        
-        }
-    
-    }
-
-    return saw_subscript;
-
-}
-
-static int emit_parse_postfix_subscripts_to_reg_dims_now (const char *reg, int elem_size, int pointer_depth, int pointed_size, int array_dimensions, int is_unsigned) {
-
-    const char *index_reg;
-    int saw_subscript = 0;
-    
-    if (!reg) {
-        reg = "eax";
-    }
-    
-    index_reg = (strcmp (reg, "ecx") == 0) ? "edx" : "ecx";
-    
-    while (tok.kind == TOK_LBRACK) {
-    
-        int dims_before = array_dimensions;
-        
-        saw_subscript = 1;
-        get_token ();
-        
-        emit_push_reg_now (reg);
-        emit_load_subscript_index_to_reg_now (index_reg);
-        
-        expect (TOK_RBRACK, "]");
-        emit_pop_reg_now (reg);
-        
-        if (array_dimensions > 0) {
-            array_dimensions--;
-        }
-        
-        if (tok.kind == TOK_LBRACK) {
-        
-            if (pointer_depth == 0 && pointed_size > 0 && elem_size > pointed_size) {
-            
-                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
-                elem_size = index_step_size (pointed_size);
-            
-            } else {
-            
-                emit_load_indexed_pointer_to_reg_now (reg, index_reg);
-                
-                if (pointer_depth > 0) {
-                    pointer_depth--;
-                }
-                
-                if (pointed_size > 0) {
-                    elem_size = (pointer_depth > 1) ? (DATA_PTR & 0x1f) : index_step_size (pointed_size);
-                }
-            
-            }
-        
-        } else {
-        
-            if (pointer_depth == 0 && dims_before > 1) {
-                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
-            } else if (pointer_depth == 0 && pointed_size > 0 && elem_size > pointed_size) {
-                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
-            } else if (index_step_size (elem_size) > (DATA_PTR & 0x1f)) {
-                emit_add_indexed_scaled_address_to_reg_now (reg, index_reg, elem_size);
-            } else {
-            
-                if (is_unsigned) {
-                    emit_load_indexed_unsigned_sized_to_reg_now (reg, index_reg, reg, elem_size);
-                } else {
-                    emit_load_indexed_sized_to_reg_now (reg, index_reg, reg, elem_size);
-                }
-            
-            }
-        
-        }
-    
-    }
-
-    return saw_subscript;
-
-}
-
-static int parse_incdec_identifier_now (enum token_kind *op, char **name, const char **name_start, const char **name_caret, unsigned long *name_line) {
-
-    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
-        return 0;
-    }
-    
-    *op = tok.kind;
-    get_token ();
-    
-    if (tok.kind != TOK_IDENT) {
-    
-        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after %s", *op == TOK_INCR ? "++" : "--");
-        
-        *name = 0;
-        return 1;
-    }
-    
-    *name = xstrdup (tok.ident);
-    *name_start = tok.start;
-    *name_caret = tok.caret;
-    *name_line = get_line_number ();
-    
-    get_token ();
-    return 1;
-
-}
-
-static void emit_apply_postfix_member_access_to_reg_now (const char *reg);
-static void emit_apply_postfix_member_incdec_now (const char *reg, enum token_kind op);
-static void emit_load_member_from_addr_reg_now (const char *dst_reg, const char *addr_reg, int offset, int size);
-
-static struct token *clone_current_token_now (void);
-static void emit_store_reg_to_deref_reg_now (const char *addr_reg, const char *value_reg, int size);
-
-static int source_starts_prefix_incdec_parenthesized_deref_at (const char *p) {
-
-    if (!p) {
-        return 0;
-    }
-    
-    if (!((p[0] == '+' && p[1] == '+') || (p[0] == '-' && p[1] == '-'))) {
-        return 0;
-    }
-    
-    p += 2;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (*p != '(') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (*p != '*') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
-        return 0;
-    }
-    
-    p++;
-    
-    while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
-        p++;
-    }
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    return *p == ')';
-
-}
-
-static int emit_load_prefix_incdec_parenthesized_deref_to_reg_now (const char *reg) {
-
-    enum token_kind op;
-    char *name;
-    
-    const char *name_start;
-    const char *name_caret;
-    
-    unsigned long name_line;
-    struct local_symbol *sym;
-    
-    int global_index;
-    int pointer_depth = 0;
-    int pointed_size = DATA_INT & 0x1f;
-    int lvalue_size = DATA_INT & 0x1f;
-    int step = 1;
-    
-    const char *addr_reg;
-    
-    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
-        return 0;
-    }
-    
-    if (!source_starts_prefix_incdec_parenthesized_deref_at (tok.caret)) {
-        return 0;
-    }
-    
-    op = tok.kind;
-    get_token ();
-    
-    expect (TOK_LPAREN, "(");
-    expect (TOK_STAR, "*");
-    
-    name_start = tok.start;
-    name_caret = tok.caret;
-    name_line = get_line_number ();
-    
-    if (tok.kind != TOK_IDENT || !tok.ident) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
-        return 1;
-    
-    }
-    
-    name = xstrdup (tok.ident);
-    get_token ();
-    
-    expect (TOK_RPAREN, ")");
-    
-    sym = find_local_symbol (name);
-    global_index = find_global_symbol (name);
-    
-    if (sym) {
-    
-        pointer_depth = sym->pointer_depth;
-        pointed_size = sym->pointed_size;
-    
-    } else if (global_index >= 0) {
-    
-        pointer_depth = get_global_symbol_pointer_depth (name);
-        pointed_size = get_global_symbol_pointed_size (name);
-    
-    } else {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    if (pointer_depth <= 0) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid indirection of non-pointer '%s'", name);
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    if (pointed_size <= 0) {
-        pointed_size = DATA_INT & 0x1f;
-    }
-    
-    if (pointer_depth > 1) {
-    
-        lvalue_size = DATA_PTR & 0x1f;
-        step = pointer_depth > 2 ? (DATA_PTR & 0x1f) : index_step_size (pointed_size);
-    
-    } else {
-    
-        lvalue_size = pointed_size & 0x1f;
-        step = 1;
-    
-    }
-    
-    if (!reg) {
-        reg = "eax";
-    }
-    
-    addr_reg = (strcmp (reg, "edx") == 0) ? "ecx" : "edx";
-    
-    if (sym) {
-    
-        if (sym->is_static && sym->static_label) {
-            emit_load_global_to_reg (addr_reg, sym->static_label, DATA_PTR);
-        } else {
-            emit_load_local_to_reg (addr_reg, sym->offset, DATA_PTR);
-        }
-    
-    } else {
-        emit_load_global_to_reg (addr_reg, name, DATA_PTR);
-    }
-    
-    emit_load_member_from_addr_reg_now (reg, addr_reg, 0, lvalue_size);
-    
-    if (state->ofp) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-            fprintf (state->ofp, op == TOK_INCR ? "    add %s, %d\n" : "    sub %s, %d\n", reg, step);
-        } else {
-            fprintf (state->ofp, op == TOK_INCR ? "    addl $%d, %%%s\n" : "    subl $%d, %%%s\n", step, reg);
-        }
-    
-    }
-    
-    emit_store_reg_to_deref_reg_now (addr_reg, reg, lvalue_size);
-    
-    if (pointer_depth > 1) {
-        set_rhs_last_pointer_info (pointer_depth - 1, pointed_size);
-    } else {
-        clear_rhs_last_pointer_info ();
-    }
-    
-    free (name);
-    return 1;
-
-}
-
-static int emit_load_prefix_incdec_deref_to_reg_now (const char *reg) {
-
-    enum token_kind op;
-    
-    struct token *saved_tok;
-    char *name;
-    
-    const char *name_start;
-    const char *name_caret;
-    
-    unsigned long name_line;
-    
-    struct local_symbol *sym;
-    
-    int global_index;
-    int deref_size = DATA_INT & 0x1f;
-    
-    const char *addr_reg;
-    
-    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
-        return 0;
-    }
-    
-    saved_tok = clone_current_token_now ();
-    op = tok.kind;
-    
-    get_token ();
-    
-    if (tok.kind != TOK_STAR) {
-    
-        unget_token (saved_tok);
-        return 0;
-    
-    }
-    
-    get_token ();
-    
-    if (tok.kind != TOK_IDENT) {
-    
-        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after *");
-        
-        free (saved_tok->ident);
-        free ((char *) saved_tok->start);
-        free (saved_tok);
-        
-        return 1;
-    
-    }
-    
-    name = xstrdup (tok.ident);
-    name_start = tok.start;
-    name_caret = tok.caret;
-    name_line = get_line_number ();
-    
-    get_token ();
-    
-    sym = find_local_symbol (name);
-    global_index = find_global_symbol (name);
-    
-    if (sym) {
-    
-        if (sym->pointer_depth > 1) {
-            deref_size = DATA_PTR & 0x1f;
-        } else if (sym->pointer_depth == 1 && sym->pointed_size > 0) {
-            deref_size = sym->pointed_size & 0x1f;
-        }
-    
-    } else if (global_index >= 0) {
-    
-        if (get_global_symbol_pointer_depth (name) > 1) {
-            deref_size = DATA_PTR & 0x1f;
-        } else if (get_global_symbol_pointer_depth (name) == 1 && get_global_symbol_pointed_size (name) > 0) {
-            deref_size = get_global_symbol_pointed_size (name) & 0x1f;
-        }
-    
-    } else {
-
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-        
-        free (name);
-        free (saved_tok->ident);
-        
-        free ((char *) saved_tok->start);
-        free (saved_tok);
-        
-        return 1;
-    
-    }
-    
-    if (!reg) {
-        reg = "eax";
-    }
-    
-    addr_reg = (strcmp (reg, "edx") == 0) ? "ecx" : "edx";
-    
-    if (sym) {
-    
-        if (sym->is_static && sym->static_label) {
-            emit_load_global_to_reg (addr_reg, sym->static_label, DATA_PTR);
-        } else {
-            emit_load_local_to_reg (addr_reg, sym->offset, DATA_PTR);
-        }
-    
-    } else {
-        emit_load_global_to_reg (addr_reg, name, DATA_PTR);
-    }
-    
-    emit_load_member_from_addr_reg_now (reg, addr_reg, 0, deref_size);
-    
-    if (state->ofp) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-            fprintf (state->ofp, op == TOK_INCR ? "    add %s, 1\n" : "    sub %s, 1\n", reg);
-        } else {
-            fprintf (state->ofp, op == TOK_INCR ? "    addl $1, %%%s\n" : "    subl $1, %%%s\n", reg);
-        }
-    
-    }
-    
-    emit_store_reg_to_deref_reg_now (addr_reg, reg, deref_size);
-    
-    free (name);
-    
-    free (saved_tok->ident);
-    free ((char *) saved_tok->start);
-    
-    free (saved_tok);
-    return 1;
-
-}
-
-static int emit_load_prefix_incdec_to_reg_now (const char *reg) {
-
-    enum token_kind op;
-    char *name;
-    
-    const char *name_start, *name_caret;
-    unsigned long name_line;
-    
-    struct local_symbol *sym;
-    
-    if (emit_load_prefix_incdec_parenthesized_deref_to_reg_now (reg)) {
-        return 1;
-    }
-    
-    if (emit_load_prefix_incdec_deref_to_reg_now (reg)) {
-        return 1;
-    }
-    
-    if (!parse_incdec_identifier_now (&op, &name, &name_start, &name_caret, &name_line)) {
-        return 0;
-    }
-    
-    if (!name) {
-        return 1;
-    }
-    
-    sym = find_local_symbol (name);
-    emit_incdec_symbol_now (sym, name, op, name_line, name_start, name_caret);
-    
-    if (sym) {
-    
-        if (sym->is_static && sym->static_label) {
-            emit_load_global_to_reg_ex (reg, sym->static_label, sym->size, sym->is_unsigned);
-        } else {
-            emit_load_local_to_reg_ex (reg, sym->offset, sym->size, sym->is_unsigned);
-        }
-    
-    } else if (find_global_symbol (name) >= 0) {
-        emit_load_global_to_reg_ex (reg, name, get_global_symbol_size (name), get_global_symbol_unsigned (name));
-    }
-    
-    free (name);
-    return 1;
-
-}
-
-static int emit_load_prefix_incdec_member_to_reg_now (const char *reg) {
-
-    struct token *saved_tok;
-    
-    enum token_kind op;
-    enum token_kind member_op = TOK_EOF;
-    
-    char *member;
-    
-    const char *member_start;
-    const char *member_caret;
-    
-    unsigned long member_line;
-    
-    int offset = 0;
-    int size = DATA_INT & 0x1f;
-    
-    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
-        return 0;
-    }
-    
-    saved_tok = clone_current_token_now ();
-    get_token ();
-    
-    if (tok.kind == TOK_STAR) {
-    
-        unget_token (saved_tok);
-        return 0;
-    
-    }
-    
-    unget_token (saved_tok);
-    
-    if (emit_load_prefix_incdec_parenthesized_deref_to_reg_now (reg)) {
-        return 1;
-    }
-    
-    op = tok.kind;
-    get_token ();
-    
-    if (tok.kind != TOK_LPAREN) {
-    
-        char *name;
-        
-        const char *name_start;
-        const char *name_caret;
-        
-        unsigned long name_line;
-        struct local_symbol *sym;
-        
-        int global_index;
-        
-        if (tok.kind != TOK_IDENT) {
-        
-            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after %s", op == TOK_INCR ? "++" : "--");
-            return 1;
-        
-        }
-        
-        name = xstrdup (tok.ident);
-        name_start = tok.start;
-        name_caret = tok.caret;
-        name_line = get_line_number ();
-        
-        get_token ();
-        
-        sym = find_local_symbol (name);
-        global_index = find_global_symbol (name);
-        
-        if (tok.kind == TOK_ARROW) {
-        
-            member_op = tok.kind;
-            get_token ();
-            
-            member_start = tok.start;
-            member_caret = tok.caret;
-            member_line = get_line_number ();
-            
-            if (tok.kind != TOK_IDENT) {
-            
-                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
-                
-                free (name);
-                return 1;
-            
-            }
-            
-            member = xstrdup (tok.ident);
-            get_token ();
-            
-            if (!find_member_info (member, &offset, &size)) {
-            
-                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
-                
-                free (member);
-                free (name);
-                
-                return 1;
-            
-            }
-            
-            free (member);
-            
-            if (sym) {
-            
-                if (sym->is_static && sym->static_label) {
-                    emit_load_global_to_reg (reg, sym->static_label, DATA_PTR);
-                } else {
-                    emit_load_local_to_reg (reg, sym->offset, DATA_PTR);
-                }
-            
-            } else if (global_index >= 0) {
-                emit_load_global_to_reg (reg, name, DATA_PTR);
-            } else {
-                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-            }
-            
-            free (name);
-            goto emit_member_incdec;
-        
-        }
-        
-        emit_incdec_symbol_now (sym, name, op, name_line, name_start, name_caret);
-        
-        if (sym) {
-        
-            if (sym->is_static && sym->static_label) {
-                emit_load_global_to_reg_ex (reg, sym->static_label, sym->size, sym->is_unsigned);
-            } else {
-                emit_load_local_to_reg_ex (reg, sym->offset, sym->size, sym->is_unsigned);
-            }
-        
-        } else if (find_global_symbol (name) >= 0) {
-            emit_load_global_to_reg_ex (reg, name, get_global_symbol_size (name), get_global_symbol_unsigned (name));
-        }
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    get_token ();
-    
-    emit_load_assignment_rhs_expression_to_reg (reg);
-    expect (TOK_RPAREN, ")");
-    
-    if (postfix_member_seen && tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
-    
-        emit_apply_postfix_member_incdec_now (reg, op);
-        emit_load_member_from_addr_reg_now (reg, "edx", postfix_member_offset, postfix_member_size);
-        
-        return 1;
-    
-    }
-    
-    if (tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
-    
-        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected member after %s", op == TOK_INCR ? "++" : "--");
-        return 1;
-    
-    }
-    
-    member_op = tok.kind;
-    get_token ();
-    
-    member_start = tok.start;
-    member_caret = tok.caret;
-    member_line = get_line_number ();
-    
-    if (tok.kind != TOK_IDENT) {
-    
-        report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
-        return 1;
-    
-    }
-    
-    member = xstrdup (tok.ident);
-    get_token ();
-    
-    if (!find_member_info (member, &offset, &size)) {
-    
-        report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
-        
-        free (member);
-        return 1;
-    
-    }
-    
-    free (member);
-    
-emit_member_incdec:
-    
-    if (!state->ofp) {
-        return 1;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        const char *insn = op == TOK_INCR ? "inc" : "dec";
-        const char *opsize = "dword";
-        
-        if (size == (DATA_CHAR & 0x1f)) {
-            opsize = "byte";
-        } else if (size == (DATA_SHORT & 0x1f)) {
-            opsize = "word";
-        }
-        
-        if (state->syntax & ASM_SYNTAX_NASM) {
-        
-            fprintf (state->ofp, "    %s %s [%s + %d]\n", insn, opsize, reg, offset);
-            
-            if (size == (DATA_CHAR & 0x1f)) {
-                fprintf (state->ofp, "    movzx %s, byte [%s + %d]\n", reg, reg, offset);
-            } else if (size == (DATA_SHORT & 0x1f)) {
-                fprintf (state->ofp, "    movzx %s, word [%s + %d]\n", reg, reg, offset);
-            } else {
-                fprintf (state->ofp, "    mov %s, dword [%s + %d]\n", reg, reg, offset);
-            }
-        
-        } else {
-        
-            fprintf (state->ofp, "    %s %s ptr [%s + %d]\n", insn, opsize, reg, offset);
-            
-            if (size == (DATA_CHAR & 0x1f)) {
-                fprintf (state->ofp, "    movzx %s, byte ptr [%s + %d]\n", reg, reg, offset);
-            } else if (size == (DATA_SHORT & 0x1f)) {
-                fprintf (state->ofp, "    movzx %s, word ptr [%s + %d]\n", reg, reg, offset);
-            } else {
-                fprintf (state->ofp, "    mov %s, dword ptr [%s + %d]\n", reg, reg, offset);
-            }
-        
-        }
-    
-    } else {
-    
-        const char *suffix = "l";
-        
-        if (size == (DATA_CHAR & 0x1f)) {
-            suffix = "b";
-        } else if (size == (DATA_SHORT & 0x1f)) {
-            suffix = "w";
-        }
-        
-        fprintf (state->ofp, "    %s%s %d(%%%s)\n", op == TOK_INCR ? "inc" : "dec", suffix, offset, reg);
-        
-        if (size == (DATA_CHAR & 0x1f)) {
-            fprintf (state->ofp, "    movzbl %d(%%%s), %%%s\n", offset, reg, reg);
-        } else if (size == (DATA_SHORT & 0x1f)) {
-            fprintf (state->ofp, "    movzwl %d(%%%s), %%%s\n", offset, reg, reg);
-        } else {
-            fprintf (state->ofp, "    movl %d(%%%s), %%%s\n", offset, reg, reg);
-        }
-    
-    }
-    
-    return 1;
-
-}
-
-static int emit_load_prefix_incdec_to_pair_now (const char *lo, const char *hi) {
-
-    enum token_kind op;
-    char *name;
-    
-    const char *name_start, *name_caret;
-    unsigned long name_line;
-    
-    struct local_symbol *sym;
-    
-    if (!parse_incdec_identifier_now (&op, &name, &name_start, &name_caret, &name_line)) {
-        return 0;
-    }
-    
-    if (!name) {
-        return 1;
-    }
-    
-    sym = find_local_symbol (name);
-    emit_incdec_symbol_now (sym, name, op, name_line, name_start, name_caret);
-    
-    if (sym) {
-    
-        if (sym->size == (DATA_LLONG & 0x1f) && !sym->is_floating) {
-        
-            if (sym->is_static && sym->static_label) {
-                emit_load_global64_to_pair (lo, hi, sym->static_label);
-            } else {
-                emit_load_local64_to_pair (sym->offset, lo, hi);
-            }
-        
-        } else {
-        
-            if (sym->is_static && sym->static_label) {
-                emit_load_global_to_reg_ex (lo, sym->static_label, sym->size, sym->is_unsigned);
-            } else {
-                emit_load_local_to_reg_ex (lo, sym->offset, sym->size, sym->is_unsigned);
-            }
-            
-            if (state->ofp) {
-            
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                    fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
-                } else {
-                    fprintf (state->ofp, "    xorl %%%s, %%%s\n", hi, hi);
-                }
-            
-            }
-        
-        }
-    
-    } else if (find_global_symbol (name) >= 0) {
-    
-        if (get_global_symbol_size (name) == (DATA_LLONG & 0x1f) && !get_global_symbol_floating (name)) {
-            emit_load_global64_to_pair (lo, hi, name);
-        } else {
-        
-            emit_load_global_to_reg_ex (lo, name, get_global_symbol_size (name), get_global_symbol_unsigned (name));
-            
-            if (state->ofp) {
-            
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                    fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
-                } else {
-                    fprintf (state->ofp, "    xorl %%%s, %%%s\n", hi, hi);
-                }
-            
-            }
-        
-        }
-    
-    }
-    
-    free (name);
-    return 1;
-
-}
-
-static int expression_text_mentions_64bit_symbol (const char *p) {
-
-    char name[256];
-    int depth = 0;
-    int i;
-    
-    if (!p) {
-        return 0;
-    }
-    
-    while (*p) {
-    
-        if (*p == '(') {
-        
-            depth++;
-            p++;
-            
-            continue;
-        
-        }
-        
-        if (*p == ')') {
-        
-            if (depth <= 0) {
-                return 0;
-            }
-            
-            depth--;
-            p++;
-            
-            continue;
-        
-        }
-        
-        if (*p == ';' || *p == '{' || *p == '}') {
-            return 0;
-        }
-        
-        if ((unsigned char) *p == '_' || ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z'))) {
-        
-            i = 0;
-            
-            while ((unsigned char) *p == '_' || ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z')) || (*p >= '0' && *p <= '9')) {
-            
-                if (i + 1 < (int) sizeof (name)) {
-                    name[i++] = *p;
-                }
-                
-                p++;
-            
-            }
-            
-            name[i] = 0;
-            
-            while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-                p++;
-            }
-            
-            if (*p == '.' || (p[0] == '-' && p[1] == '>')) {
-                continue;
-            }
-            
-            {
-            
-                struct local_symbol *sym = find_local_symbol (name);
-                
-                if (sym && sym->size == (DATA_LLONG & 0x1f) && !sym->is_floating) {
-                    return 1;
-                }
-            
-            }
-            
-            if (find_global_symbol (name) >= 0 && get_global_symbol_size (name) == (DATA_LLONG & 0x1f) && !get_global_symbol_floating (name)) {
-                return 1;
-            }
-            
-            continue;
-        
-        }
-        
-        p++;
-    
-    }
-    
-    return 0;
-
-}
-
-static int current_expression_mentions_64bit_symbol_now (void) {
-
-    if (expression_text_mentions_64bit_symbol (tok.start)) {
-        return 1;
-    }
-    
-    if (expression_text_mentions_64bit_symbol (tok.caret)) {
-        return 1;
-    }
-    
-    return 0;
-
-}
-
-static const char *reg8_name_for_32 (const char *reg) {
-
-    if (strcmp (reg, "eax") == 0) {
-        return "al";
-    }
-    
-    if (strcmp (reg, "ebx") == 0) {
-        return "bl";
-    }
-    
-    if (strcmp (reg, "ecx") == 0) {
-        return "cl";
-    }
-    
-    if (strcmp (reg, "edx") == 0) {
-        return "dl";
-    }
-    
-    return "al";
-
-}
-
-static const char *reg16_name_for_32 (const char *reg) {
-
-    if (strcmp (reg, "eax") == 0) {
-        return "ax";
-    }
-    
-    if (strcmp (reg, "ebx") == 0) {
-        return "bx";
-    }
-    
-    if (strcmp (reg, "ecx") == 0) {
-        return "cx";
-    }
-    
-    if (strcmp (reg, "edx") == 0) {
-        return "dx";
-    }
-    
-    return "ax";
-
-}
-
-static void emit_extend_pair_high_from_low (const char *lo, const char *hi, int size, int is_unsigned) {
-
-    if (!state->ofp) {
-        return;
-    }
-
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-
-        if (is_unsigned) {
-        
-            if (size == (DATA_CHAR & 0x1f)) {
-                fprintf (state->ofp, "    movzx %s, %s\n", lo, reg8_name_for_32 (lo));
-            } else if (size == (DATA_SHORT & 0x1f)) {
-                fprintf (state->ofp, "    movzx %s, %s\n", lo, reg16_name_for_32 (lo));
-            }
-            
-            fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
-        
-        } else {
-
-            if (size == (DATA_CHAR & 0x1f)) {
-                fprintf (state->ofp, "    movsx %s, %s\n", lo, reg8_name_for_32 (lo));
-            } else if (size == (DATA_SHORT & 0x1f)) {
-                fprintf (state->ofp, "    movsx %s, %s\n", lo, reg16_name_for_32 (lo));
-            }
-
-            fprintf (state->ofp, "    mov %s, %s\n", hi, lo);
-            fprintf (state->ofp, "    sar %s, 31\n", hi);
-
-        }
-
-    } else {
-
-        if (is_unsigned) {
-        
-            if (size == (DATA_CHAR & 0x1f)) {
-                fprintf (state->ofp, "    movzbl %%%s, %%%s\n", reg8_name_for_32 (lo), lo);
-            } else if (size == (DATA_SHORT & 0x1f)) {
-                fprintf (state->ofp, "    movzwl %%%s, %%%s\n", reg16_name_for_32 (lo), lo);
-            }
-            
-            fprintf (state->ofp, "    xorl %%%s, %%%s\n", hi, hi);
-        
-        } else {
-
-            if (size == (DATA_CHAR & 0x1f)) {
-                fprintf (state->ofp, "    movsbl %%%s, %%%s\n", reg8_name_for_32 (lo), lo);
-            } else if (size == (DATA_SHORT & 0x1f)) {
-                fprintf (state->ofp, "    movswl %%%s, %%%s\n", reg16_name_for_32 (lo), lo);
-            }
-
-            fprintf (state->ofp, "    movl %%%s, %%%s\n", lo, hi);
-            fprintf (state->ofp, "    sarl $31, %%%s\n", hi);
-
-        }
-
-    }
-
-}
-
-static void emit_apply_integer_cast_to_reg_now (const char *reg, int size, int is_unsigned) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (size != (DATA_CHAR & 0x1f) && size != (DATA_SHORT & 0x1f)) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (size == (DATA_CHAR & 0x1f)) {
-            fprintf (state->ofp, is_unsigned ? "    movzx %s, %s\n" : "    movsx %s, %s\n", reg, reg8_name_for_32 (reg));
-        } else {
-            fprintf (state->ofp, is_unsigned ? "    movzx %s, %s\n" : "    movsx %s, %s\n", reg, reg16_name_for_32 (reg));
-        }
-    
-    } else {
-    
-        if (size == (DATA_CHAR & 0x1f)) {
-            fprintf (state->ofp, is_unsigned ? "    movzbl %%%s, %%%s\n" : "    movsbl %%%s, %%%s\n", reg8_name_for_32 (reg), reg);
-        } else {
-            fprintf (state->ofp, is_unsigned ? "    movzwl %%%s, %%%s\n" : "    movswl %%%s, %%%s\n", reg16_name_for_32 (reg), reg);
-        }
-    
-    }
-
-}
-
-static int fold_text_starts_with_type_name_only_before_rparen (const char *p) {
-
-    int saw_type = 0;
-    char word[64];
-    int i;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    for (;;) {
-    
-        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-            p++;
-        }
-        
-        if (*p == '*') {
-        
-            saw_type = 1;
-            
-            p++;
-            continue;
-        
-        }
-        
-        if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
-            break;
-        }
-        
-        i = 0;
-        
-        while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
-        
-            if (i + 1 < (int) sizeof (word)) {
-                word[i++] = *p;
-            }
-            
-            p++;
-        
-        }
-        
-        word[i] = 0;
-        
-        if (strcmp (word, "char") != 0 &&
-            strcmp (word, "short") != 0 &&
-            strcmp (word, "int") != 0 &&
-            strcmp (word, "long") != 0 &&
-            strcmp (word, "signed") != 0 &&
-            strcmp (word, "unsigned") != 0 &&
-            strcmp (word, "void") != 0) {
-            return 0;
-        }
-        
-        saw_type = 1;
-    
-    }
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    return saw_type && *p == ')';
-
-}
-
-static int const_integer_expr_text_is_foldable_now (const char *p) {
-
-    int saw_value_token = 0;
-    int saw_token = 0;
-    
-    char word[64];
-    int depth = 0, ch, i;
-    
-    if (!p) {
-        return 0;
-    }
-    
-    {
-    
-        const char *q = p;
-        int parens = 0;
-        
-        while (*q == ' ' || *q == '\t' || *q == '\r' || *q == '\n') {
-            q++;
-        }
-        
-        while (*q == '(') {
-        
-            parens = 1;
-            q++;
-            
-            while (*q == ' ' || *q == '\t' || *q == '\r' || *q == '\n') {
-                q++;
-            }
-        
-        }
-        
-        if (fold_text_starts_with_type_name_only_before_rparen (p) || (parens && fold_text_starts_with_type_name_only_before_rparen (q))) {
-            return 0;
-        }
-    
-    }
-    
-    while (*p) {
-    
-        ch = (unsigned char) *p;
-        
-        if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') {
-        
-            p++;
-            continue;
-        
-        }
-        
-        if (depth == 0) {
-        
-            if (*p == ';' || *p == ',' || *p == '}' || *p == ']') {
-                break;
-            }
-            
-            /*
-             * This helper is only for folding a complete integer expression
-             * operand.  Do not claim that a leading parenthesized constant is
-             * foldable when it is followed by a lower-precedence operator such
-             * as the '<' in:
-             *
-             *     ((3) < (1 + n)) ? ...
-             *
-             * Returning true there makes the caller consume only '(3)' and then
-             * expect a closing parenthesis while the current token is '<'.
-             */
-            if (*p == ':' || *p == '?') {
-                return 0;
-            }
-            
-            if (*p == '<' || *p == '>' || *p == '=' || (*p == '!' && p[1] == '=')) {
-            
-                if ((p[0] == '<' && p[1] == '<') || (p[0] == '>' && p[1] == '>')) {
-                
-                    saw_token = 1;
-                    
-                    p += 2;
-                    continue;
-                
-                } else {
-                    return 0;
-                }
-            }
-            
-            if ((p[0] == '&' && p[1] == '&') || (p[0] == '|' && p[1] == '|')) {
-                return 0;
-            }
-        
-        }
-        
-        if (*p == '(') {
-        
-            depth++;
-            
-            saw_token = 1;
-            p++;
-            
-            continue;
-        
-        }
-        
-        if (*p == ')') {
-        
-            if (depth == 0) {
-            
-                /*
-                 * If the caller asks about text that starts inside a cast, the
-                 * scanner can see only the type-name prefix, for example:
-                 *
-                 *     unsigned char) ch
-                 *
-                 * That is not an integer constant expression.  Returning true
-                 * here sends the parser down expr_const64(), which then reports
-                 * "integer constant expression expected" at the cast.
-                 */
-                if (!saw_value_token) {
-                    return 0;
-                }
-                
-                break;
-            
-            }
-            
-            depth--;
-            p++;
-            
-            continue;
-        
-        }
-        
-        if (*p >= '0' && *p <= '9') {
-        
-            saw_value_token = 1;
-            saw_token = 1;
-            
-            p++;
-            
-            while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
-                p++;
-            }
-            
-            continue;
-        
-        }
-        
-        if (*p == '\'') {
-        
-            saw_value_token = 1;
-            saw_token = 1;
-            
-            p++;
-            
-            while (*p && *p != '\'') {
-            
-                if (*p == '\\' && p[1]) {
-                    p += 2;
-                } else {
-                    p++;
-                }
-            
-            }
-            
-            if (*p == '\'') {
-                p++;
-            }
-            
-            continue;
-        
-        }
-        
-        if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_') {
-        
-            i = 0;
-            
-            while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
-            
-                if (i + 1 < (int) sizeof (word)) {
-                    word[i++] = *p;
-                }
-                
-                p++;
-            
-            }
-            
-            word[i] = 0;
-            
-            if (strcmp (word, "sizeof") == 0) {
-                saw_value_token = 1;
-            }
-            
-            if (strcmp (word, "sizeof") != 0 &&
-                strcmp (word, "char") != 0 &&
-                strcmp (word, "short") != 0 &&
-                strcmp (word, "int") != 0 &&
-                strcmp (word, "long") != 0 &&
-                strcmp (word, "signed") != 0 &&
-                strcmp (word, "unsigned") != 0 &&
-                strcmp (word, "void") != 0) {
-                return 0;
-            }
-            
-            saw_token = 1;
-            continue;
-        
-        }
-        
-        if (*p == '+' || *p == '-' || *p == '*' || *p == '/' || *p == '%' || *p == '&' || *p == '|' || *p == '^' || *p == '~' || *p == '!' || *p == '<' || *p == '>') {
-        
-            saw_token = 1;
-            p++;
-            
-            continue;
-        
-        }
-        
-        return 0;
-    
-    }
-    
-    return saw_token;
-
-}
-
-static int token_kind_is_integer_constant_now (enum token_kind kind) {
-
-    return kind == TOK_CCHAR || kind == TOK_LCHAR ||
-           kind == TOK_CINT || kind == TOK_CUINT ||
-           kind == TOK_CLONG || kind == TOK_CULONG ||
-           kind == TOK_CLLONG || kind == TOK_CULLONG;
-
-}
-
-static int token_kind_is_binary_expression_operator_now (enum token_kind kind) {
-
-    return kind == TOK_PLUS || kind == TOK_MINUS || kind == TOK_STAR ||
-           kind == TOK_FSLASH || kind == TOK_MOD ||
-           kind == TOK_AMPER || kind == TOK_PIPE || kind == TOK_CARET ||
-           kind == TOK_LSH || kind == TOK_RSH ||
-           kind == TOK_LESS || kind == TOK_LTEQ ||
-           kind == TOK_GREATER || kind == TOK_GTEQ ||
-           kind == TOK_EQEQ || kind == TOK_NOTEQ ||
-           kind == TOK_LOGAND || kind == TOK_LOGOR;
-
-}
-
-static int current_integer_expr_is_foldable_now (void) {
-
-    struct token *saved_tok;
-    
-    enum token_kind first_kind;
-    enum token_kind next_kind;
-    
-    if (!const_integer_expr_text_is_foldable_now (tok.start)) {
-        return 0;
-    }
-    
-    /*
-     * Macro-expanded integer tokens can have tok.start/tok.caret pointing at
-     * only the replacement text (for example "16") rather than the complete
-     * source expression that follows it.  Do not hand such a prefix to
-     * expr_const64() as though it described the whole expression when the real
-     * token stream continues with a binary operator:
-     *
-     *     MEMMGR_ALIGN - (size_t)buffer % MEMMGR_ALIGN
-     *
-     * The normal expression parser can still handle this; this guard only
-     * disables the whole-expression constant-folder for that unsafe prefix.
-     */
-    if (!token_kind_is_integer_constant_now (tok.kind)) {
-        return 1;
-    }
-    
-    first_kind = tok.kind;
-    
-    saved_tok = clone_current_token_now ();
-    get_token ();
-    
-    next_kind = tok.kind;
-    unget_token (saved_tok);
-    
-    if (token_kind_is_integer_constant_now (first_kind) && token_kind_is_binary_expression_operator_now (next_kind)) {
-        return 0;
-    }
-    
-    return 1;
-
-}
-
-static void emit_load_const64_to_pair_now (const char *lo, const char *hi, int64_s v) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        fprintf (state->ofp, "    mov %s, %lu\n", lo, v.low & U32_MASK);
-        fprintf (state->ofp, "    mov %s, %lu\n", hi, v.high & U32_MASK);
-    
-    } else {
-    
-        fprintf (state->ofp, "    movl $%lu, %%%s\n", v.low & U32_MASK, lo);
-        fprintf (state->ofp, "    movl $%lu, %%%s\n", v.high & U32_MASK, hi);
-    
-    }
-
-}
-
-static void emit_load_const32_to_reg_now (const char *reg, int64_s v) {
-
-    flush_pending_statement_labels ();
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-        fprintf (state->ofp, "    mov %s, %lu\n", reg, v.low & U32_MASK);
-    } else {
-        fprintf (state->ofp, "    movl $%lu, %%%s\n", v.low & U32_MASK, reg);
-    }
-
-}
-
-static void emit_load_address_to_reg_now (const char *reg, const char *symbol) {
-
-    const char *asm_symbol;
-    flush_pending_statement_labels ();
-    
-    if (!state->ofp || !symbol || !*symbol) {
-        return;
-    }
-    
-    emit_extern_reference_symbol (symbol, DATA_PTR);
-    asm_symbol = asm_global_symbol_name (symbol);
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (state->syntax & ASM_SYNTAX_NASM) {
-            fprintf (state->ofp, "    mov %s, %s\n", reg, asm_symbol);
-        } else {
-            fprintf (state->ofp, "    mov %s, offset %s\n", reg, asm_symbol);
-        }
-    
-    } else {
-        fprintf (state->ofp, "    movl $%s, %%%s\n", asm_symbol, reg);
-    }
-
-}
-
-static void emit_load_deref_reg_ex_now (const char *reg, int size, int is_unsigned);
-static void emit_load_deref_reg_now (const char *reg, int size);
-
-static int emit_load_parenthesized_indirect_member_to_reg_now (const char *reg);
-static int emit_parse_postfix_copy_source_address_now (const char *reg, struct local_symbol *src, const char *src_name, const char *name_start, const char *name_caret, unsigned long name_line);
-
-static void emit_load_postfix_lvalue_address_to_pair_ex_now (const char *lo, const char *hi, int size, int is_unsigned) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (size > (DATA_PTR & 0x1f)) {
-    
-        emit_push_reg_now (lo);
-        
-        emit_load_deref_reg_now (lo, DATA_PTR & 0x1f);
-        emit_pop_reg_now (hi);
-        
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-        
-            if (state->syntax & ASM_SYNTAX_NASM) {
-                fprintf (state->ofp, "    mov %s, dword [%s + 4]\n", hi, hi);
-            } else {
-                fprintf (state->ofp, "    mov %s, dword ptr [%s + 4]\n", hi, hi);
-            }
-        
-        } else {
-            fprintf (state->ofp, "    movl 4(%%%s), %%%s\n", hi, hi);
-        }
-    
-    } else {
-    
-        emit_load_deref_reg_ex_now (lo, size, is_unsigned);
-        
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-            fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
-        } else {
-            fprintf (state->ofp, "    xorl %%%s, %%%s\n", hi, hi);
-        }
-    
-    }
-
-}
-
-static void emit_store_pair_to_deref_reg_now (const char *addr_reg, const char *lo, const char *hi) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (state->syntax & ASM_SYNTAX_NASM) {
-        
-            fprintf (state->ofp, "    mov dword [%s], %s\n", addr_reg, lo);
-            fprintf (state->ofp, "    mov dword [%s + 4], %s\n", addr_reg, hi);
-        
-        } else {
-        
-            fprintf (state->ofp, "    mov dword ptr [%s], %s\n", addr_reg, lo);
-            fprintf (state->ofp, "    mov dword ptr [%s + 4], %s\n", addr_reg, hi);
-        
-        }
-    
-    } else {
-    
-        fprintf (state->ofp, "    movl %%%s, (%%%s)\n", lo, addr_reg);
-        fprintf (state->ofp, "    movl %%%s, 4(%%%s)\n", hi, addr_reg);
-    
-    }
-
-}
-
-static void emit_load_pair_from_deref_reg_now (const char *lo, const char *hi, const char *addr_reg) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (state->syntax & ASM_SYNTAX_NASM) {
-        
-            fprintf (state->ofp, "    mov %s, dword [%s]\n", lo, addr_reg);
-            fprintf (state->ofp, "    mov %s, dword [%s + 4]\n", hi, addr_reg);
-        
-        } else {
-        
-            fprintf (state->ofp, "    mov %s, dword ptr [%s]\n", lo, addr_reg);
-            fprintf (state->ofp, "    mov %s, dword ptr [%s + 4]\n", hi, addr_reg);
-        
-        }
-    
-    } else {
-    
-        fprintf (state->ofp, "    movl (%%%s), %%%s\n", addr_reg, lo);
-        fprintf (state->ofp, "    movl 4(%%%s), %%%s\n", addr_reg, hi);
-    
-    }
-
-}
-
-static void emit_copy_reg_now (const char *dst, const char *src) {
-
-    if (!state->ofp || !dst || !src || strcmp (dst, src) == 0) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-        fprintf (state->ofp, "    mov %s, %s\n", dst, src);
-    } else {
-        fprintf (state->ofp, "    movl %%%s, %%%s\n", src, dst);
-    }
-
-}
-
-static int emit_parse_builtin_va_arg_address_to_reg_now (const char *reg, int *out_size, int *out_unsigned, int *out_pointer, int *out_floating);
-static int rhs_current_operand_is_floating_now (void);
-static int token_is_floating_constant_now (void);
-
-static void emit_store_floating_member_to_addr_reg_now (const char *addr_reg, int offset, int size);
-static void emit_load_floating_rhs_expression_now (int result_size);
-static void emit_load_assignment_rhs_to_reg (const char *reg);
-static void emit_floating_stack_to_int_pair_now (const char *lo, const char *hi);
-static void emit_integer_pair_to_floating_stack_now (const char *lo, const char *hi, int size);
-
-static void emit_load_assignment_rhs_to_pair (const char *lo, const char *hi) {
-
-    if (_accept (TOK_LPAREN)) {
-    
-        if (token_starts_type_name ()) {
-        
-            int cast_size = 0;
-            int cast_is_unsigned = 0;
-            int cast_is_pointer = 0;
-            
-            if (parse_cast_type_name (&cast_size, &cast_is_unsigned, &cast_is_pointer)) {
-            
-                if (!cast_is_pointer && !last_cast_type_is_floating && rhs_current_operand_is_floating_now ()) {
-                
-                    emit_load_floating_rhs_expression_now (DATA_DOUBLE & 0x1f);
-                    
-                    if (floating_rhs_result_in_eax_bool) {
-                    
-                        if (strcmp (lo, "eax") != 0 && state->ofp) {
-                        
-                            if (state->syntax & ASM_SYNTAX_INTEL) {
-                                fprintf (state->ofp, "    mov %s, eax\n", lo);
-                            } else {
-                                fprintf (state->ofp, "    movl %%eax, %%%s\n", lo);
-                            }
-                        
-                        }
-                        
-                        emit_extend_pair_high_from_low (lo, hi, cast_size, cast_is_unsigned);
-                        floating_rhs_result_in_eax_bool = 0;
-                    
-                    } else {
-                    
-                        emit_floating_stack_to_int_pair_now (lo, hi);
-                        
-                        if ((cast_size & 0x1f) != (DATA_LLONG & 0x1f)) {
-                            emit_extend_pair_high_from_low (lo, hi, cast_size, cast_is_unsigned);
-                        }
-                    
-                    }
-                    
-                    return;
-                
-                }
-                
-                emit_load_assignment_rhs_to_pair (lo, hi);
-                
-                {
-                
-                    int applied_postfix = 0;
-                    
-                    if (cast_is_pointer) {
-                        set_rhs_last_pointer_info (1, cast_size > 0 ? cast_size : (DATA_INT & 0x1f));
-                    } else {
-                        emit_extend_pair_high_from_low (lo, hi, cast_size, cast_is_unsigned);
-                    }
-                    
-                    postfix_member_seen = 0;
-                    
-                    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
-                    
-                        applied_postfix = 1;
-                        emit_apply_postfix_member_access_to_reg_now (lo);
-                    
-                    }
-                    
-                    if (applied_postfix && postfix_member_seen) {
-                    
-                        if (postfix_member_size == (DATA_LLONG & 0x1f) && !postfix_member_is_floating) {
-                        
-                            const char *addr_reg = (strcmp (lo, "ecx") != 0 && strcmp (hi, "ecx") != 0) ? "ecx" : "esi";
-                            
-                            emit_copy_reg_now (addr_reg, lo);
-                            emit_load_pair_from_deref_reg_now (lo, hi, addr_reg);
-                        
-                        } else {
-                            emit_extend_pair_high_from_low (lo, hi, postfix_member_size, postfix_member_is_unsigned);
-                        }
-                    
-                    }
-                
-                }
-                
-                return;
-            
-            }
-        
-        }
-        
-        if (tok.kind != TOK_LPAREN && current_integer_expr_is_foldable_now ()) {
-        
-            int64_s v = const64_from_current_foldable_expr ();
-            expect (TOK_RPAREN, ")");
-            
-            emit_load_const64_to_pair_now (lo, hi, v);
-            return;
-        
-        }
-        
-        if (emit_load_parenthesized_indirect_member_to_reg_now (lo)) {
-        
-            emit_extend_pair_high_from_low (lo, hi, DATA_INT & 0x1f, 1);
-            return;
-        
-        }
-        
-        emit_load_assignment_rhs_expression_to_pair (lo, hi, 1);
-        expect (TOK_RPAREN, ")");
-        
-        {
-        
-            int applied_postfix = 0;
-            postfix_member_seen = 0;
-            
-            while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
-            
-                applied_postfix = 1;
-                emit_apply_postfix_member_access_to_reg_now (lo);
-            
-            }
-            
-            if (applied_postfix && postfix_member_seen) {
-            
-                if (postfix_member_size == (DATA_LLONG & 0x1f) && !postfix_member_is_floating) {
-                
-                    const char *addr_reg = (strcmp (lo, "ecx") != 0 && strcmp (hi, "ecx") != 0) ? "ecx" : "esi";
-                    
-                    emit_copy_reg_now (addr_reg, lo);
-                    emit_load_pair_from_deref_reg_now (lo, hi, addr_reg);
-                
-                } else {
-                    emit_extend_pair_high_from_low (lo, hi, postfix_member_size, postfix_member_is_unsigned);
-                }
-            
-            }
-        
-        }
-            
-        return;
-    
-    }
-    
-    if (tok.kind == TOK_PLUS || tok.kind == TOK_MINUS || tok.kind == TOK_TILDE || tok.kind == TOK_XMARK) {
-    
-        enum token_kind unary_op = tok.kind;
-        get_token ();
-        
-        emit_load_assignment_rhs_to_pair (lo, hi);
-        
-        if (state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-            
-                if (unary_op == TOK_MINUS) {
-                
-                    fprintf (state->ofp, "    not %s\n", lo);
-                    fprintf (state->ofp, "    not %s\n", hi);
-                    
-                    fprintf (state->ofp, "    add %s, 1\n", lo);
-                    fprintf (state->ofp, "    adc %s, 0\n", hi);
-                
-                } else if (unary_op == TOK_TILDE) {
-                
-                    fprintf (state->ofp, "    not %s\n", lo);
-                    fprintf (state->ofp, "    not %s\n", hi);
-                
-                } else if (unary_op == TOK_XMARK) {
-                
-                    fprintf (state->ofp, "    or %s, %s\n", lo, hi);
-                    fprintf (state->ofp, "    setz al\n");
-                    fprintf (state->ofp, "    movzx eax, al\n");
-                    
-                    if (strcmp (lo, "eax") != 0) {
-                        fprintf (state->ofp, "    mov %s, eax\n", lo);
-                    }
-                    
-                    fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
-                
-                }
-            
-            } else {
-            
-                if (unary_op == TOK_MINUS) {
-                
-                    fprintf (state->ofp, "    notl %%%s\n", lo);
-                    fprintf (state->ofp, "    notl %%%s\n", hi);
-                    
-                    fprintf (state->ofp, "    addl $1, %%%s\n", lo);
-                    fprintf (state->ofp, "    adcl $0, %%%s\n", hi);
-                
-                } else if (unary_op == TOK_TILDE) {
-                
-                    fprintf (state->ofp, "    notl %%%s\n", lo);
-                    fprintf (state->ofp, "    notl %%%s\n", hi);
-                
-                } else if (unary_op == TOK_XMARK) {
-                
-                    fprintf (state->ofp, "    orl %%%s, %%%s\n", hi, lo);
-                    fprintf (state->ofp, "    setz %%al\n");
-                    fprintf (state->ofp, "    movzbl %%al, %%eax\n");
-                    
-                    if (strcmp (lo, "eax") != 0) {
-                        fprintf (state->ofp, "    movl %%eax, %%%s\n", lo);
-                    }
-                    
-                    fprintf (state->ofp, "    xorl %%%s, %%%s\n", hi, hi);
-                
-                }
-            
-            }
-        
-        }
-        
-        return;
-    
-    }
-    
-    if (emit_load_prefix_incdec_to_pair_now (lo, hi)) {
-        return;
-    }
-    
-    if (tok.kind == TOK_STAR) {
-    
-        char *name;
-        
-        const char *name_start;
-        const char *name_caret;
-        
-        unsigned long name_line;
-        struct local_symbol *src;
-        
-        int global_index;
-        
-        int deref_size = DATA_INT & 0x1f;
-        int deref_unsigned = 1;
-        
-        int postfix_incdec = 0;
-        
-        enum token_kind postfix_op = TOK_EOF;
-        get_token ();
-        
-        name_start = tok.start;
-        name_caret = tok.caret;
-        name_line = get_line_number ();
-        
-        if (tok.kind == TOK_LPAREN) {
-        
-            const char *addr_reg = (strcmp (lo, "ecx") != 0 && strcmp (hi, "ecx") != 0) ? "ecx" : "esi";
-            int cast_deref_size = DATA_INT & 0x1f;
-            
-            get_token ();
-            
-            if (is_type_start (tok.kind) && parse_deref_cast_type_name (&cast_deref_size)) {
-            
-                emit_load_assignment_rhs_to_reg (lo);
-                
-                if ((cast_deref_size & 0x1f) == (DATA_LLONG & 0x1f)) {
-                
-                    emit_copy_reg_now (addr_reg, lo);
-                    emit_load_pair_from_deref_reg_now (lo, hi, addr_reg);
-                
-                } else {
-                
-                    emit_load_deref_reg_now (lo, cast_deref_size);
-                    emit_extend_pair_high_from_low (lo, hi, cast_deref_size, 1);
-                
-                }
-                
-                return;
-            
-            }
-            
-            emit_load_assignment_rhs_expression_to_reg (lo);
-            expect (TOK_RPAREN, ")");
-            
-            emit_load_deref_reg_now (lo, DATA_INT & 0x1f);
-            emit_extend_pair_high_from_low (lo, hi, DATA_INT & 0x1f, 1);
-            
-            return;
-        
-        }
-        
-        if (tok.kind != TOK_IDENT || !tok.ident) {
-        
-            int64_s zero;
-            
-            zero.low = 0;
-            zero.high = 0;
-            
-            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
-            
-            emit_load_const64_to_pair_now (lo, hi, zero);
-            return;
-        
-        }
-        
-        name = xstrdup (tok.ident);
-        get_token ();
-        
-        src = find_local_symbol (name);
-        global_index = find_global_symbol (name);
-        
-        if (!src && global_index >= 0 && tok.kind == TOK_LPAREN &&
-            get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION) {
-        
-            const char *addr_reg = (strcmp (lo, "ecx") != 0 && strcmp (hi, "ecx") != 0) ? "ecx" : "esi";
-            int fptr_depth = get_global_symbol_pointer_depth (name);
-            int fpointed_size = get_global_symbol_pointed_size (name);
-            
-            if (get_global_symbol_returns_void (name)) {
-                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "void function '%s' used as a value", name);
-            }
-            
-            emit_call_identifier_to_reg_now (name, lo, name_start, name_caret, name_line);
-            
-            if (fptr_depth > 1) {
-                deref_size = DATA_PTR & 0x1f;
-            } else if (fptr_depth == 1 && fpointed_size > 0) {
-                deref_size = fpointed_size & 0x1f;
-            }
-            
-            if (deref_size == (DATA_LLONG & 0x1f)) {
-            
-                emit_copy_reg_now (addr_reg, lo);
-                emit_load_pair_from_deref_reg_now (lo, hi, addr_reg);
-            
-            } else {
-            
-                emit_load_deref_reg_now (lo, deref_size);
-                emit_extend_pair_high_from_low (lo, hi, deref_size, 1);
-            
-            }
-            
-            free (name);
-            return;
-        
-        }
-        
-        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-        
-            postfix_incdec = 1;
-            postfix_op = tok.kind;
-            
-            get_token ();
-        
-        }
-        
-        if (src) {
-        
-            if (src->pointer_depth > 1) {
-                deref_size = DATA_PTR & 0x1f;
-            } else if (src->pointer_depth == 1 && src->pointed_size > 0) {
-                deref_size = src->pointed_size & 0x1f;
-            }
-            
-            if (src->is_static && src->static_label) {
-                emit_load_global_to_reg (lo, src->static_label, DATA_PTR);
-            } else {
-                emit_load_local_to_reg (lo, src->offset, DATA_PTR);
-            }
-        
-        } else if (global_index >= 0) {
-        
-            if (get_global_symbol_pointer_depth (name) > 1) {
-                deref_size = DATA_PTR & 0x1f;
-            } else if (get_global_symbol_pointer_depth (name) == 1 && get_global_symbol_pointed_size (name) > 0) {
-                deref_size = get_global_symbol_pointed_size (name) & 0x1f;
-            }
-            
-            emit_load_global_to_reg (lo, name, DATA_PTR);
-        
-        } else {
-        
-            int64_s zero;
-            
-            zero.low = 0;
-            zero.high = 0;
-            
-            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-            
-            emit_load_const64_to_pair_now (lo, hi, zero);
-            free (name);
-            
-            return;
-        
-        }
-        
-        if (deref_size == (DATA_LLONG & 0x1f)) {
-        
-            emit_push_reg_now (lo);
-            
-            emit_load_deref_reg_now (lo, DATA_INT & 0x1f);
-            emit_pop_reg_now (hi);
-            
-            if (state->ofp) {
-            
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                
-                    if (state->syntax & ASM_SYNTAX_NASM) {
-                        fprintf (state->ofp, "    mov %s, dword [%s + 4]\n", hi, hi);
-                    } else {
-                        fprintf (state->ofp, "    mov %s, dword ptr [%s + 4]\n", hi, hi);
-                    }
-                
-                } else {
-                    fprintf (state->ofp, "    movl 4(%%%s), %%%s\n", hi, hi);
-                }
-            
-            }
-        
-        } else {
-        
-            emit_load_deref_reg_now (lo, deref_size);
-            emit_extend_pair_high_from_low (lo, hi, deref_size, deref_unsigned);
-        
-        }
-        
-        if (postfix_incdec) {
-        
-            emit_push_reg_now (lo);
-            emit_push_reg_now (hi);
-            
-            emit_incdec_symbol_now (src, name, postfix_op, name_line, name_start, name_caret);
-            
-            emit_pop_reg_now (hi);
-            emit_pop_reg_now (lo);
-        
-        }
-        
-        free (name);
-        return;
-    
-    }
-    
-    if (token_is_sizeof_keyword ()) {
-    
-        int64_s v = sizeof_from_current_token ();
-        
-        if (state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-            
-                fprintf (state->ofp, "    mov %s, %lu\n", lo, v.low & U32_MASK);
-                fprintf (state->ofp, "    mov %s, %lu\n", hi, v.high & U32_MASK);
-            
-            } else {
-            
-                fprintf (state->ofp, "    movl $%lu, %%%s\n", v.low & U32_MASK, lo);
-                fprintf (state->ofp, "    movl $%lu, %%%s\n", v.high & U32_MASK, hi);
-            
-            }
-        
-        }
-        
-        return;
-    
-    }
-    
-    if (tok.kind == TOK_SCC_BUILTIN_VA_ARG) {
-    
-        int va_size = DATA_INT & 0x1f;
-        int va_unsigned = 1;
-        int va_pointer = 0;
-        int va_floating = 0;
-        
-        const char *addr_reg = (strcmp (lo, "ecx") != 0 && strcmp (hi, "ecx") != 0) ? "ecx" : "esi";
-        
-        get_token ();
-        emit_parse_builtin_va_arg_address_to_reg_now (addr_reg, &va_size, &va_unsigned, &va_pointer, &va_floating);
-        
-        if (va_size == (DATA_LLONG & 0x1f) && va_pointer == 0) {
-            emit_load_pair_from_deref_reg_now (lo, hi, addr_reg);
-        } else {
-        
-            emit_copy_reg_now (lo, addr_reg);
-            emit_load_deref_reg_now (lo, va_size);
-            
-            emit_extend_pair_high_from_low (lo, hi, va_size, va_unsigned);
-        
-        }
-        
-        return;
-    
-    }
-
-    if (tok.kind == TOK_IDENT) {
-    
-        enum token_kind postfix_op = TOK_EOF;
-        char *name = xstrdup (tok.ident);
-        
-        const char *name_start = tok.start, *name_caret = tok.caret;
-        unsigned long name_line = get_line_number ();
-        
-        int postfix_incdec = 0;
-        
-        struct local_symbol *src;
-        int64_s enum_value;
-        
-        get_token ();
-        
-        if (strcmp (name, "__scc_builtin_va_arg") == 0 && tok.kind == TOK_LPAREN) {
-        
-            int va_size = DATA_INT & 0x1f;
-            int va_unsigned = 1;
-            int va_pointer = 0;
-            int va_floating = 0;
-            
-            const char *addr_reg = (strcmp (lo, "ecx") != 0 && strcmp (hi, "ecx") != 0) ? "ecx" : "esi";
-            emit_parse_builtin_va_arg_address_to_reg_now (addr_reg, &va_size, &va_unsigned, &va_pointer, &va_floating);
-            
-            if (va_size == (DATA_LLONG & 0x1f) && !va_floating && va_pointer == 0) {
-                emit_load_pair_from_deref_reg_now (lo, hi, addr_reg);
-            } else {
-            
-                emit_copy_reg_now (lo, addr_reg);
-                emit_load_deref_reg_now (lo, va_size);
-                emit_extend_pair_high_from_low (lo, hi, va_size, va_unsigned);
-            
-            }
-            
-            free (name);
-            return;
-        
-        }
-        
-        if (!find_local_symbol (name) && find_global_symbol (name) < 0 && resolve_enum_constant (name, &enum_value)) {
-        
-            emit_load_const64_to_pair_now (lo, hi, enum_value);
-            
-            free (name);
-            return;
-        
-        }
-
-        if (tok.kind == TOK_LPAREN) {
-        
-            if (!find_local_symbol (name)) {
-                ensure_global_function_symbol (name, name_start, name_caret, name_line);
-            }
-            
-            if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION && get_global_symbol_returns_void (name)) {
-                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "void function '%s' used as a value", name);
-            }
-            
-            emit_call_identifier_to_reg_now (name, "eax", name_start, name_caret, name_line);
-            
-            if (get_global_function_returns_floating (name)) {
-            
-                if (state->ofp) {
-                
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                    
-                        fprintf (state->ofp, "    sub esp, 8\n");
-                        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fstp qword [esp]\n" : "    fstp qword ptr [esp]\n");
-                        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [esp]\n" : "    mov %s, dword ptr [esp]\n", lo);
-                        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [esp + 4]\n" : "    mov %s, dword ptr [esp + 4]\n", hi);
-                        fprintf (state->ofp, "    add esp, 8\n");
-                    
-                    } else {
-                    
-                        fprintf (state->ofp, "    subl $8, %%esp\n");
-                        fprintf (state->ofp, "    fstpl (%%esp)\n");
-                        fprintf (state->ofp, "    movl (%%esp), %%%s\n", lo);
-                        fprintf (state->ofp, "    movl 4(%%esp), %%%s\n", hi);
-                        fprintf (state->ofp, "    addl $8, %%esp\n");
-                    
-                    }
-                
-                }
-                
-                free (name);
-                return;
-            }
-            
-            if (state->ofp) {
-            
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                
-                    if (strcmp (lo, "eax") != 0) {
-                        fprintf (state->ofp, "    mov %s, eax\n", lo);
-                    }
-                    
-                    if (strcmp (hi, "edx") != 0) {
-                        fprintf (state->ofp, "    mov %s, edx\n", hi);
-                    }
-                
-                } else {
-                
-                    if (strcmp (lo, "eax") != 0) {
-                        fprintf (state->ofp, "    movl %%eax, %%%s\n", lo);
-                    }
-                    
-                    if (strcmp (hi, "edx") != 0) {
-                        fprintf (state->ofp, "    movl %%edx, %%%s\n", hi);
-                    }
-                
-                }
-            
-            }
-            
-            free (name);
-            return;
-        
-        }
-        
-        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-        
-            postfix_incdec = 1;
-            postfix_op = tok.kind;
-            
-            get_token ();
-        
-        }
-
-        src = find_local_symbol (name);
-        
-        if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT || tok.kind == TOK_LBRACK) {
-        
-            int source_size;
-            
-            if (src || find_global_symbol (name) >= 0) {
-            
-                if (tok.kind == TOK_ARROW || tok.kind == TOK_LBRACK) {
-                
-                    if (src) {
-                    
-                        postfix_copy_lvalue_size = src->pointer_depth > 0 ? src->pointed_size : src->size;
-                        postfix_copy_lvalue_tag_name = src->pointer_depth > 0 ? src->pointed_tag_name : src->tag_name;
-                    
-                    } else {
-                    
-                        postfix_copy_lvalue_size = get_global_symbol_pointer_depth (name) > 0 ? get_global_symbol_pointed_size (name) : get_global_symbol_size (name);
-                        postfix_copy_lvalue_tag_name = 0;
-                    
-                    }
-                
-                } else if (src) {
-                
-                    postfix_copy_lvalue_size = src->size;
-                    postfix_copy_lvalue_tag_name = src->tag_name;
-                
-                } else {
-                
-                    postfix_copy_lvalue_size = get_global_symbol_size (name);
-                    postfix_copy_lvalue_tag_name = get_global_symbol_tag_name (name);
-                
-                }
-                
-                if (!emit_parse_postfix_copy_source_address_now (lo, src, name, name_start, name_caret, name_line)) {
-                
-                    free (name);
-                    return;
-                
-                }
-                
-                source_size = postfix_copy_lvalue_size;
-                
-                if (source_size <= 0) {
-                    source_size = DATA_INT & 0x1f;
-                }
-                
-                if (is_assignment_operator (tok.kind)) {
-                
-                    enum token_kind assign_op = tok.kind;
-                    
-                    const char *addr_reg = (strcmp (lo, "ecx") != 0 && strcmp (hi, "ecx") != 0) ? "ecx" : "edx";
-                    int lvalue_size = index_step_size (source_size);
-                    
-                    get_token ();
-                    
-                    if (assign_op == TOK_ASSIGN && (postfix_member_is_floating || token_is_floating_constant_now () || rhs_current_operand_is_floating_now ())) {
-                    
-                        emit_push_reg_now (lo);
-                        emit_load_floating_rhs_expression_now (lvalue_size);
-                        
-                        emit_pop_reg_now (addr_reg);
-                        emit_store_floating_member_to_addr_reg_now (addr_reg, 0, lvalue_size);
-                        
-                        free (name);
-                        return;
-                    }
-                    
-                    if (assign_op == TOK_ASSIGN && lvalue_size == (DATA_LLONG & 0x1f)) {
-                    
-                        emit_push_reg_now (lo);
-                        
-                        emit_load_assignment_rhs_expression_to_pair (lo, hi, 1);
-                        emit_pop_reg_now (addr_reg);
-                        
-                        emit_store_pair_to_deref_reg_now (addr_reg, lo, hi);
-                        
-                        free (name);
-                        return;
-                    
-                    }
-                    
-                    if (assign_op == TOK_ASSIGN) {
-                    
-                        emit_push_reg_now (lo);
-                        
-                        emit_load_assignment_rhs_expression_to_reg (lo);
-                        emit_extend_pair_high_from_low (lo, hi, lvalue_size, 1);
-                        
-                        emit_pop_reg_now (addr_reg);
-                        emit_store_reg_to_deref_reg_now (addr_reg, lo, lvalue_size);
-                        
-                        free (name);
-                        return;
-                    
-                    }
-                    
-                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "compound member assignment expression not implemented in 64-bit context");
-                    
-                    free (name);
-                    return;
-                
-                }
-                
-                emit_load_postfix_lvalue_address_to_pair_ex_now (lo, hi, source_size, src ? (src->pointer_depth > 0 ? src->pointed_is_unsigned : src->is_unsigned) : (get_global_symbol_pointer_depth (name) > 0 ? get_global_symbol_pointed_is_unsigned (name) : get_global_symbol_unsigned (name)));
-                
-                free (name);
-                return;
-            
-            }
-        
-        }
-        
-        if (src) {
-        
-            if (src->size == (DATA_LLONG & 0x1f) && !src->is_floating) {
-            
-                if (src->is_static && src->static_label) {
-                    emit_load_global64_to_pair (lo, hi, src->static_label);
-                } else {
-                    emit_load_local64_to_pair (src->offset, lo, hi);
-                }
-            
-            } else {
-            
-                if (src->is_static && src->static_label) {
-                    emit_load_global_to_reg_ex (lo, src->static_label, src->size, src->is_unsigned);
-                } else {
-                    emit_load_local_to_reg_ex (lo, src->offset, src->size, src->is_unsigned);
-                }
-                
-                emit_extend_pair_high_from_low (lo, hi, src->size, src->is_unsigned);
-            
-            }
-            
-            if (postfix_incdec) {
-            
-                emit_push_reg_now (lo);
-                emit_push_reg_now (hi);
-                
-                emit_incdec_symbol_now (src, name, postfix_op, name_line, name_start, name_caret);
-                
-                emit_pop_reg_now (hi);
-                emit_pop_reg_now (lo);
-            
-            }
-            
-            free (name);
-            return;
-        
-        }
-        
-        if (find_global_symbol (name) >= 0) {
-        
-            if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION ||
-                get_global_symbol_array (name) ||
-                (!get_global_symbol_pointer_depth (name) &&
-                    get_global_symbol_size (name) > (DATA_PTR & 0x1f))) {
-            
-                /*
-                 * In a 64-bit/pair context, an array/function/aggregate
-                 * expression still decays to its address.  The 32-bit RHS
-                 * path already handled this, but this path was used when
-                 * the caller requested eax:edx (for example a mis-sized
-                 * pointer return).  Loading the first word of the global
-                 * table produced bogus pseudo-op table pointers such as the
-                 * first string pointer instead of &table.
-                 */
-                emit_load_address_to_reg_now (lo, name);
-                if (state->ofp) {
-                
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                        fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
-                    } else {
-                        fprintf (state->ofp, "    xorl %%%s, %%%s\n", hi, hi);
-                    }
-                
-                }
-            
-            } else if (get_global_symbol_size (name) == (DATA_LLONG & 0x1f) && !get_global_symbol_floating (name)) {
-                emit_load_global64_to_pair (lo, hi, name);
-            } else {
-            
-                emit_load_global_to_reg_ex (lo, name, get_global_symbol_size (name), get_global_symbol_unsigned (name));
-                emit_extend_pair_high_from_low (lo, hi, get_global_symbol_size (name), get_global_symbol_unsigned (name));
-            
-            }
-            
-            if (postfix_incdec) {
-            
-                emit_push_reg_now (lo);
-                emit_push_reg_now (hi);
-                
-                emit_incdec_symbol_now (0, name, postfix_op, name_line, name_start, name_caret);
-                
-                emit_pop_reg_now (hi);
-                emit_pop_reg_now (lo);
-            
-            }
-            
-            free (name);
-            return;
-        
-        }
-        
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-        free (name);
-        
-        if (state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-            
-                fprintf (state->ofp, "    xor %s, %s\n", lo, lo);
-                fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
-            
-            } else {
-            
-                fprintf (state->ofp, "    xorl %%%s, %%%s\n", lo, lo);
-                fprintf (state->ofp, "    xorl %%%s, %%%s\n", hi, hi);
-            
-            }
-        
-        }
-        
-        return;
-    
-    }
-    
-    if (recover_unknown_rhs_identifier ()) {
-    
-        if (state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-            
-                fprintf (state->ofp, "    xor %s, %s\n", lo, lo);
-                fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
-            
-            } else {
-            
-                fprintf (state->ofp, "    xorl %%%s, %%%s\n", lo, lo);
-                fprintf (state->ofp, "    xorl %%%s, %%%s\n", hi, hi);
-            
-            }
-        
-        }
-        
-        return;
-    
-    }
-    
-    {
-    
-        int64_s v = const64_from_current_operand ();
-        
-        if (state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-            
-                fprintf (state->ofp, "    mov %s, %lu\n", lo, v.low & U32_MASK);
-                fprintf (state->ofp, "    mov %s, %lu\n", hi, v.high & U32_MASK);
-            
-            } else {
-            
-                fprintf (state->ofp, "    movl $%lu, %%%s\n", v.low & U32_MASK, lo);
-                fprintf (state->ofp, "    movl $%lu, %%%s\n", v.high & U32_MASK, hi);
-            
-            }
-        
-        }
-    
-    }
-
-}
-
-static void emit_assignment_divmod64_intel (int is_unsigned, int want_mod) {
-
-    int loop_label, sub_label, nosub_label;
-    int lhs_pos_label, rhs_pos_label;
-    int qpos_label, rpos_label;
-    
-    loop_label = anon_label++;
-    sub_label = anon_label++;
-    nosub_label = anon_label++;
-    lhs_pos_label = anon_label++;
-    rhs_pos_label = anon_label++;
-    qpos_label = anon_label++;
-    rpos_label = anon_label++;
-    
-    if (state->syntax & ASM_SYNTAX_MASM) {
-    
-        fprintf (state->ofp, "    sub esp, 40\n");
-        fprintf (state->ofp, "    mov dword ptr [esp], eax\n");
-        fprintf (state->ofp, "    mov dword ptr [esp + 4], edx\n");
-        fprintf (state->ofp, "    mov dword ptr [esp + 8], ebx\n");
-        fprintf (state->ofp, "    mov dword ptr [esp + 12], ecx\n");
-        fprintf (state->ofp, "    xor eax, eax\n");
-        fprintf (state->ofp, "    mov dword ptr [esp + 16], eax\n");
-        fprintf (state->ofp, "    mov dword ptr [esp + 20], eax\n");
-        fprintf (state->ofp, "    mov dword ptr [esp + 24], eax\n");
-        fprintf (state->ofp, "    mov dword ptr [esp + 28], eax\n");
-        fprintf (state->ofp, "    mov dword ptr [esp + 32], eax\n");
-        fprintf (state->ofp, "    mov dword ptr [esp + 36], eax\n");
-        
-        if (!is_unsigned) {
-        
-            fprintf (state->ofp, "    test dword ptr [esp + 4], 80000000h\n");
-            fprintf (state->ofp, "    jz L%d\n", lhs_pos_label);
-            fprintf (state->ofp, "    not dword ptr [esp]\n");
-            fprintf (state->ofp, "    not dword ptr [esp + 4]\n");
-            fprintf (state->ofp, "    add dword ptr [esp], 1\n");
-            fprintf (state->ofp, "    adc dword ptr [esp + 4], 0\n");
-            fprintf (state->ofp, "    mov dword ptr [esp + 32], 1\n");
-            fprintf (state->ofp, "    xor dword ptr [esp + 36], 1\n");
-            fprintf (state->ofp, "L%d:\n", lhs_pos_label);
-            fprintf (state->ofp, "    test dword ptr [esp + 12], 80000000h\n");
-            fprintf (state->ofp, "    jz L%d\n", rhs_pos_label);
-            fprintf (state->ofp, "    not dword ptr [esp + 8]\n");
-            fprintf (state->ofp, "    not dword ptr [esp + 12]\n");
-            fprintf (state->ofp, "    add dword ptr [esp + 8], 1\n");
-            fprintf (state->ofp, "    adc dword ptr [esp + 12], 0\n");
-            fprintf (state->ofp, "    xor dword ptr [esp + 36], 1\n");
-            fprintf (state->ofp, "L%d:\n", rhs_pos_label);
-        
-        }
-        
-        fprintf (state->ofp, "    mov esi, 64\n");
-        fprintf (state->ofp, "L%d:\n", loop_label);
-        fprintf (state->ofp, "    shl dword ptr [esp], 1\n");
-        fprintf (state->ofp, "    rcl dword ptr [esp + 4], 1\n");
-        fprintf (state->ofp, "    rcl dword ptr [esp + 24], 1\n");
-        fprintf (state->ofp, "    rcl dword ptr [esp + 28], 1\n");
-        fprintf (state->ofp, "    shl dword ptr [esp + 16], 1\n");
-        fprintf (state->ofp, "    rcl dword ptr [esp + 20], 1\n");
-        fprintf (state->ofp, "    mov eax, dword ptr [esp + 28]\n");
-        fprintf (state->ofp, "    cmp eax, dword ptr [esp + 12]\n");
-        fprintf (state->ofp, "    ja L%d\n", sub_label);
-        fprintf (state->ofp, "    jb L%d\n", nosub_label);
-        fprintf (state->ofp, "    mov eax, dword ptr [esp + 24]\n");
-        fprintf (state->ofp, "    cmp eax, dword ptr [esp + 8]\n");
-        fprintf (state->ofp, "    jb L%d\n", nosub_label);
-        fprintf (state->ofp, "L%d:\n", sub_label);
-        fprintf (state->ofp, "    mov eax, dword ptr [esp + 8]\n");
-        fprintf (state->ofp, "    sub dword ptr [esp + 24], eax\n");
-        fprintf (state->ofp, "    mov eax, dword ptr [esp + 12]\n");
-        fprintf (state->ofp, "    sbb dword ptr [esp + 28], eax\n");
-        fprintf (state->ofp, "    or dword ptr [esp + 16], 1\n");
-        fprintf (state->ofp, "L%d:\n", nosub_label);
-        fprintf (state->ofp, "    dec esi\n");
-        fprintf (state->ofp, "    jnz L%d\n", loop_label);
-        
-        if (!is_unsigned) {
-        
-            fprintf (state->ofp, "    cmp dword ptr [esp + 36], 0\n");
-            fprintf (state->ofp, "    je L%d\n", qpos_label);
-            fprintf (state->ofp, "    not dword ptr [esp + 16]\n");
-            fprintf (state->ofp, "    not dword ptr [esp + 20]\n");
-            fprintf (state->ofp, "    add dword ptr [esp + 16], 1\n");
-            fprintf (state->ofp, "    adc dword ptr [esp + 20], 0\n");
-            fprintf (state->ofp, "L%d:\n", qpos_label);
-            fprintf (state->ofp, "    cmp dword ptr [esp + 32], 0\n");
-            fprintf (state->ofp, "    je L%d\n", rpos_label);
-            fprintf (state->ofp, "    not dword ptr [esp + 24]\n");
-            fprintf (state->ofp, "    not dword ptr [esp + 28]\n");
-            fprintf (state->ofp, "    add dword ptr [esp + 24], 1\n");
-            fprintf (state->ofp, "    adc dword ptr [esp + 28], 0\n");
-            fprintf (state->ofp, "L%d:\n", rpos_label);
-        
-        }
-        
-        if (want_mod) {
-        
-            fprintf (state->ofp, "    mov eax, dword ptr [esp + 24]\n");
-            fprintf (state->ofp, "    mov edx, dword ptr [esp + 28]\n");
-        
-        } else {
-        
-            fprintf (state->ofp, "    mov eax, dword ptr [esp + 16]\n");
-            fprintf (state->ofp, "    mov edx, dword ptr [esp + 20]\n");
-        
-        }
-    
-    } else if (state->syntax & ASM_SYNTAX_NASM) {
-    
-        fprintf (state->ofp, "    sub esp, 40\n");
-        fprintf (state->ofp, "    mov dword [esp], eax\n");
-        fprintf (state->ofp, "    mov dword [esp + 4], edx\n");
-        fprintf (state->ofp, "    mov dword [esp + 8], ebx\n");
-        fprintf (state->ofp, "    mov dword [esp + 12], ecx\n");
-        fprintf (state->ofp, "    xor eax, eax\n");
-        fprintf (state->ofp, "    mov dword [esp + 16], eax\n");
-        fprintf (state->ofp, "    mov dword [esp + 20], eax\n");
-        fprintf (state->ofp, "    mov dword [esp + 24], eax\n");
-        fprintf (state->ofp, "    mov dword [esp + 28], eax\n");
-        fprintf (state->ofp, "    mov dword [esp + 32], eax\n");
-        fprintf (state->ofp, "    mov dword [esp + 36], eax\n");
-        
-        if (!is_unsigned) {
-        
-            fprintf (state->ofp, "    test dword [esp + 4], 80000000h\n");
-            fprintf (state->ofp, "    jz L%d\n", lhs_pos_label);
-            fprintf (state->ofp, "    not dword [esp]\n");
-            fprintf (state->ofp, "    not dword [esp + 4]\n");
-            fprintf (state->ofp, "    add dword [esp], 1\n");
-            fprintf (state->ofp, "    adc dword [esp + 4], 0\n");
-            fprintf (state->ofp, "    mov dword [esp + 32], 1\n");
-            fprintf (state->ofp, "    xor dword [esp + 36], 1\n");
-            fprintf (state->ofp, "L%d:\n", lhs_pos_label);
-            fprintf (state->ofp, "    test dword [esp + 12], 80000000h\n");
-            fprintf (state->ofp, "    jz L%d\n", rhs_pos_label);
-            fprintf (state->ofp, "    not dword [esp + 8]\n");
-            fprintf (state->ofp, "    not dword [esp + 12]\n");
-            fprintf (state->ofp, "    add dword [esp + 8], 1\n");
-            fprintf (state->ofp, "    adc dword [esp + 12], 0\n");
-            fprintf (state->ofp, "    xor dword [esp + 36], 1\n");
-            fprintf (state->ofp, "L%d:\n", rhs_pos_label);
-        
-        }
-        
-        fprintf (state->ofp, "    mov esi, 64\n");
-        fprintf (state->ofp, "L%d:\n", loop_label);
-        fprintf (state->ofp, "    shl dword [esp], 1\n");
-        fprintf (state->ofp, "    rcl dword [esp + 4], 1\n");
-        fprintf (state->ofp, "    rcl dword [esp + 24], 1\n");
-        fprintf (state->ofp, "    rcl dword [esp + 28], 1\n");
-        fprintf (state->ofp, "    shl dword [esp + 16], 1\n");
-        fprintf (state->ofp, "    rcl dword [esp + 20], 1\n");
-        fprintf (state->ofp, "    mov eax, dword [esp + 28]\n");
-        fprintf (state->ofp, "    cmp eax, dword [esp + 12]\n");
-        fprintf (state->ofp, "    ja L%d\n", sub_label);
-        fprintf (state->ofp, "    jb L%d\n", nosub_label);
-        fprintf (state->ofp, "    mov eax, dword [esp + 24]\n");
-        fprintf (state->ofp, "    cmp eax, dword [esp + 8]\n");
-        fprintf (state->ofp, "    jb L%d\n", nosub_label);
-        fprintf (state->ofp, "L%d:\n", sub_label);
-        fprintf (state->ofp, "    mov eax, dword [esp + 8]\n");
-        fprintf (state->ofp, "    sub dword [esp + 24], eax\n");
-        fprintf (state->ofp, "    mov eax, dword [esp + 12]\n");
-        fprintf (state->ofp, "    sbb dword [esp + 28], eax\n");
-        fprintf (state->ofp, "    or dword [esp + 16], 1\n");
-        fprintf (state->ofp, "L%d:\n", nosub_label);
-        fprintf (state->ofp, "    dec esi\n");
-        fprintf (state->ofp, "    jnz L%d\n", loop_label);
-        
-        if (!is_unsigned) {
-        
-            fprintf (state->ofp, "    cmp dword [esp + 36], 0\n");
-            fprintf (state->ofp, "    je L%d\n", qpos_label);
-            fprintf (state->ofp, "    not dword [esp + 16]\n");
-            fprintf (state->ofp, "    not dword [esp + 20]\n");
-            fprintf (state->ofp, "    add dword [esp + 16], 1\n");
-            fprintf (state->ofp, "    adc dword [esp + 20], 0\n");
-            fprintf (state->ofp, "L%d:\n", qpos_label);
-            fprintf (state->ofp, "    cmp dword [esp + 32], 0\n");
-            fprintf (state->ofp, "    je L%d\n", rpos_label);
-            fprintf (state->ofp, "    not dword [esp + 24]\n");
-            fprintf (state->ofp, "    not dword [esp + 28]\n");
-            fprintf (state->ofp, "    add dword [esp + 24], 1\n");
-            fprintf (state->ofp, "    adc dword [esp + 28], 0\n");
-            fprintf (state->ofp, "L%d:\n", rpos_label);
-        
-        }
-        
-        if (want_mod) {
-        
-            fprintf (state->ofp, "    mov eax, dword [esp + 24]\n");
-            fprintf (state->ofp, "    mov edx, dword [esp + 28]\n");
-        
-        } else {
-        
-            fprintf (state->ofp, "    mov eax, dword [esp + 16]\n");
-            fprintf (state->ofp, "    mov edx, dword [esp + 20]\n");
-        
-        }
-    
-    } else {
-    
-        fprintf (state->ofp, "    sub esp, 40\n");
-        fprintf (state->ofp, "    mov dword ptr [esp], eax\n");
-        fprintf (state->ofp, "    mov dword ptr [esp + 4], edx\n");
-        fprintf (state->ofp, "    mov dword ptr [esp + 8], ebx\n");
-        fprintf (state->ofp, "    mov dword ptr [esp + 12], ecx\n");
-        fprintf (state->ofp, "    xor eax, eax\n");
-        fprintf (state->ofp, "    mov dword ptr [esp + 16], eax\n");
-        fprintf (state->ofp, "    mov dword ptr [esp + 20], eax\n");
-        fprintf (state->ofp, "    mov dword ptr [esp + 24], eax\n");
-        fprintf (state->ofp, "    mov dword ptr [esp + 28], eax\n");
-        fprintf (state->ofp, "    mov dword ptr [esp + 32], eax\n");
-        fprintf (state->ofp, "    mov dword ptr [esp + 36], eax\n");
-        
-        if (!is_unsigned) {
-        
-            fprintf (state->ofp, "    test dword ptr [esp + 4], 80000000h\n");
-            fprintf (state->ofp, "    jz .L%d\n", lhs_pos_label);
-            fprintf (state->ofp, "    not dword ptr [esp]\n");
-            fprintf (state->ofp, "    not dword ptr [esp + 4]\n");
-            fprintf (state->ofp, "    add dword ptr [esp], 1\n");
-            fprintf (state->ofp, "    adc dword ptr [esp + 4], 0\n");
-            fprintf (state->ofp, "    mov dword ptr [esp + 32], 1\n");
-            fprintf (state->ofp, "    xor dword ptr [esp + 36], 1\n");
-            fprintf (state->ofp, ".L%d:\n", lhs_pos_label);
-            fprintf (state->ofp, "    test dword ptr [esp + 12], 80000000h\n");
-            fprintf (state->ofp, "    jz .L%d\n", rhs_pos_label);
-            fprintf (state->ofp, "    not dword ptr [esp + 8]\n");
-            fprintf (state->ofp, "    not dword ptr [esp + 12]\n");
-            fprintf (state->ofp, "    add dword ptr [esp + 8], 1\n");
-            fprintf (state->ofp, "    adc dword ptr [esp + 12], 0\n");
-            fprintf (state->ofp, "    xor dword ptr [esp + 36], 1\n");
-            fprintf (state->ofp, ".L%d:\n", rhs_pos_label);
-        
-        }
-        
-        fprintf (state->ofp, "    mov esi, 64\n");
-        fprintf (state->ofp, ".L%d:\n", loop_label);
-        fprintf (state->ofp, "    shl dword ptr [esp], 1\n");
-        fprintf (state->ofp, "    rcl dword ptr [esp + 4], 1\n");
-        fprintf (state->ofp, "    rcl dword ptr [esp + 24], 1\n");
-        fprintf (state->ofp, "    rcl dword ptr [esp + 28], 1\n");
-        fprintf (state->ofp, "    shl dword ptr [esp + 16], 1\n");
-        fprintf (state->ofp, "    rcl dword ptr [esp + 20], 1\n");
-        fprintf (state->ofp, "    mov eax, dword ptr [esp + 28]\n");
-        fprintf (state->ofp, "    cmp eax, dword ptr [esp + 12]\n");
-        fprintf (state->ofp, "    ja .L%d\n", sub_label);
-        fprintf (state->ofp, "    jb .L%d\n", nosub_label);
-        fprintf (state->ofp, "    mov eax, dword ptr [esp + 24]\n");
-        fprintf (state->ofp, "    cmp eax, dword ptr [esp + 8]\n");
-        fprintf (state->ofp, "    jb .L%d\n", nosub_label);
-        fprintf (state->ofp, ".L%d:\n", sub_label);
-        fprintf (state->ofp, "    mov eax, dword ptr [esp + 8]\n");
-        fprintf (state->ofp, "    sub dword ptr [esp + 24], eax\n");
-        fprintf (state->ofp, "    mov eax, dword ptr [esp + 12]\n");
-        fprintf (state->ofp, "    sbb dword ptr [esp + 28], eax\n");
-        fprintf (state->ofp, "    or dword ptr [esp + 16], 1\n");
-        fprintf (state->ofp, ".L%d:\n", nosub_label);
-        fprintf (state->ofp, "    dec esi\n");
-        fprintf (state->ofp, "    jnz .L%d\n", loop_label);
-        
-        if (!is_unsigned) {
-        
-            fprintf (state->ofp, "    cmp dword ptr [esp + 36], 0\n");
-            fprintf (state->ofp, "    je .L%d\n", qpos_label);
-            fprintf (state->ofp, "    not dword ptr [esp + 16]\n");
-            fprintf (state->ofp, "    not dword ptr [esp + 20]\n");
-            fprintf (state->ofp, "    add dword ptr [esp + 16], 1\n");
-            fprintf (state->ofp, "    adc dword ptr [esp + 20], 0\n");
-            fprintf (state->ofp, ".L%d:\n", qpos_label);
-            fprintf (state->ofp, "    cmp dword ptr [esp + 32], 0\n");
-            fprintf (state->ofp, "    je .L%d\n", rpos_label);
-            fprintf (state->ofp, "    not dword ptr [esp + 24]\n");
-            fprintf (state->ofp, "    not dword ptr [esp + 28]\n");
-            fprintf (state->ofp, "    add dword ptr [esp + 24], 1\n");
-            fprintf (state->ofp, "    adc dword ptr [esp + 28], 0\n");
-            fprintf (state->ofp, ".L%d:\n", rpos_label);
-        
-        }
-        
-        if (want_mod) {
-        
-            fprintf (state->ofp, "    mov eax, dword ptr [esp + 24]\n");
-            fprintf (state->ofp, "    mov edx, dword ptr [esp + 28]\n");
-        
-        } else {
-        
-            fprintf (state->ofp, "    mov eax, dword ptr [esp + 16]\n");
-            fprintf (state->ofp, "    mov edx, dword ptr [esp + 20]\n");
-        
-        }
-    
-    }
-    
-    fprintf (state->ofp, "    add esp, 40\n");
-
-}
-
-static void emit_assignment_divmod64_att (int is_unsigned, int want_mod) {
-
-    int loop_label, sub_label, nosub_label;
-    int lhs_pos_label, rhs_pos_label;
-    int qpos_label, rpos_label;
-    
-    loop_label = anon_label++;
-    sub_label = anon_label++;
-    nosub_label = anon_label++;
-    lhs_pos_label = anon_label++;
-    rhs_pos_label = anon_label++;
-    qpos_label = anon_label++;
-    rpos_label = anon_label++;
-    
-    fprintf (state->ofp, "    subl $40, %%esp\n");
-    fprintf (state->ofp, "    movl %%eax, (%%esp)\n");
-    fprintf (state->ofp, "    movl %%edx, 4(%%esp)\n");
-    fprintf (state->ofp, "    movl %%ebx, 8(%%esp)\n");
-    fprintf (state->ofp, "    movl %%ecx, 12(%%esp)\n");
-    fprintf (state->ofp, "    xorl %%eax, %%eax\n");
-    fprintf (state->ofp, "    movl %%eax, 16(%%esp)\n");
-    fprintf (state->ofp, "    movl %%eax, 20(%%esp)\n");
-    fprintf (state->ofp, "    movl %%eax, 24(%%esp)\n");
-    fprintf (state->ofp, "    movl %%eax, 28(%%esp)\n");
-    fprintf (state->ofp, "    movl %%eax, 32(%%esp)\n");
-    fprintf (state->ofp, "    movl %%eax, 36(%%esp)\n");
-    
-    if (!is_unsigned) {
-    
-        fprintf (state->ofp, "    testl $0x80000000, 4(%%esp)\n");
-        fprintf (state->ofp, "    jz .L%d\n", lhs_pos_label);
-        fprintf (state->ofp, "    notl (%%esp)\n");
-        fprintf (state->ofp, "    notl 4(%%esp)\n");
-        fprintf (state->ofp, "    addl $1, (%%esp)\n");
-        fprintf (state->ofp, "    adcl $0, 4(%%esp)\n");
-        fprintf (state->ofp, "    movl $1, 32(%%esp)\n");
-        fprintf (state->ofp, "    xorl $1, 36(%%esp)\n");
-        fprintf (state->ofp, ".L%d:\n", lhs_pos_label);
-        fprintf (state->ofp, "    testl $0x80000000, 12(%%esp)\n");
-        fprintf (state->ofp, "    jz .L%d\n", rhs_pos_label);
-        fprintf (state->ofp, "    notl 8(%%esp)\n");
-        fprintf (state->ofp, "    notl 12(%%esp)\n");
-        fprintf (state->ofp, "    addl $1, 8(%%esp)\n");
-        fprintf (state->ofp, "    adcl $0, 12(%%esp)\n");
-        fprintf (state->ofp, "    xorl $1, 36(%%esp)\n");
-        fprintf (state->ofp, ".L%d:\n", rhs_pos_label);
-    
-    }
-    
-    fprintf (state->ofp, "    movl $64, %%esi\n");
-    fprintf (state->ofp, ".L%d:\n", loop_label);
-    fprintf (state->ofp, "    shll $1, (%%esp)\n");
-    fprintf (state->ofp, "    rcll $1, 4(%%esp)\n");
-    fprintf (state->ofp, "    rcll $1, 24(%%esp)\n");
-    fprintf (state->ofp, "    rcll $1, 28(%%esp)\n");
-    fprintf (state->ofp, "    shll $1, 16(%%esp)\n");
-    fprintf (state->ofp, "    rcll $1, 20(%%esp)\n");
-    fprintf (state->ofp, "    movl 28(%%esp), %%eax\n");
-    fprintf (state->ofp, "    cmpl 12(%%esp), %%eax\n");
-    fprintf (state->ofp, "    ja .L%d\n", sub_label);
-    fprintf (state->ofp, "    jb .L%d\n", nosub_label);
-    fprintf (state->ofp, "    movl 24(%%esp), %%eax\n");
-    fprintf (state->ofp, "    cmpl 8(%%esp), %%eax\n");
-    fprintf (state->ofp, "    jb .L%d\n", nosub_label);
-    fprintf (state->ofp, ".L%d:\n", sub_label);
-    fprintf (state->ofp, "    movl 8(%%esp), %%eax\n");
-    fprintf (state->ofp, "    subl %%eax, 24(%%esp)\n");
-    fprintf (state->ofp, "    movl 12(%%esp), %%eax\n");
-    fprintf (state->ofp, "    sbbl %%eax, 28(%%esp)\n");
-    fprintf (state->ofp, "    orl $1, 16(%%esp)\n");
-    fprintf (state->ofp, ".L%d:\n", nosub_label);
-    fprintf (state->ofp, "    decl %%esi\n");
-    fprintf (state->ofp, "    jnz .L%d\n", loop_label);
-    
-    if (!is_unsigned) {
-    
-        fprintf (state->ofp, "    cmpl $0, 36(%%esp)\n");
-        fprintf (state->ofp, "    je .L%d\n", qpos_label);
-        fprintf (state->ofp, "    notl 16(%%esp)\n");
-        fprintf (state->ofp, "    notl 20(%%esp)\n");
-        fprintf (state->ofp, "    addl $1, 16(%%esp)\n");
-        fprintf (state->ofp, "    adcl $0, 20(%%esp)\n");
-        fprintf (state->ofp, ".L%d:\n", qpos_label);
-        fprintf (state->ofp, "    cmpl $0, 32(%%esp)\n");
-        fprintf (state->ofp, "    je .L%d\n", rpos_label);
-        fprintf (state->ofp, "    notl 24(%%esp)\n");
-        fprintf (state->ofp, "    notl 28(%%esp)\n");
-        fprintf (state->ofp, "    addl $1, 24(%%esp)\n");
-        fprintf (state->ofp, "    adcl $0, 28(%%esp)\n");
-        fprintf (state->ofp, ".L%d:\n", rpos_label);
-    
-    }
-    
-    if (want_mod) {
-    
-        fprintf (state->ofp, "    movl 24(%%esp), %%eax\n");
-        fprintf (state->ofp, "    movl 28(%%esp), %%edx\n");
-    
-    } else {
-    
-        fprintf (state->ofp, "    movl 16(%%esp), %%eax\n");
-        fprintf (state->ofp, "    movl 20(%%esp), %%edx\n");
-    
-    }
-    
-    fprintf (state->ofp, "    addl $40, %%esp\n");
-
-}
-
-static void emit_assignment_divmod64 (int is_unsigned, int want_mod) {
-
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-        emit_assignment_divmod64_intel (is_unsigned, want_mod);
-    } else {
-        emit_assignment_divmod64_att (is_unsigned, want_mod);
-    }
-
-}
-
-static void emit_assignment_binary_op64 (enum token_kind op, int is_unsigned) {
-
-    int l1, l2;
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        switch (op) {
-        
-            case TOK_PLUS:      case TOK_PLUSEQ:
-            
-                fprintf (state->ofp, "    add eax, ebx\n");
-                fprintf (state->ofp, "    adc edx, ecx\n");
-                break;
-            
-            case TOK_MINUS:     case TOK_MINUSEQ:
-            
-                fprintf (state->ofp, "    sub eax, ebx\n");
-                fprintf (state->ofp, "    sbb edx, ecx\n");
-                break;
-            
-            case TOK_STAR:      case TOK_STAREQ:
-            
-                /**
-                 * Low 64 bits of (EDX:EAX * EBX).  The high half of the RHS
-                 * is ignored for now; this is enough for constants/small ints.
-                 */
-                fprintf (state->ofp, "    mov esi, eax\n");
-                fprintf (state->ofp, "    mov edi, edx\n");
-                fprintf (state->ofp, "    mul ebx\n");
-                fprintf (state->ofp, "    mov esi, edx\n");
-                fprintf (state->ofp, "    mov edx, edi\n");
-                fprintf (state->ofp, "    imul edx, ebx\n");
-                fprintf (state->ofp, "    add edx, esi\n");
-                break;
-            
-            case TOK_BSLASH:    case TOK_SLASHEQ:
-            
-                emit_assignment_divmod64 (is_unsigned, 0);
-                break;
-            
-            case TOK_MOD:       case TOK_MODEQ:
-            
-                emit_assignment_divmod64 (is_unsigned, 1);
-                break;
-            
-            case TOK_AMPER:     case TOK_ANDEQ:
-            
-                fprintf (state->ofp, "    and eax, ebx\n");
-                fprintf (state->ofp, "    and edx, ecx\n");
-                break;
-            
-            case TOK_PIPE:      case TOK_OREQ:
-            
-                fprintf (state->ofp, "    or eax, ebx\n");
-                fprintf (state->ofp, "    or edx, ecx\n");
-                break;
-            
-            case TOK_CARET:     case TOK_XOREQ:
-            
-                fprintf (state->ofp, "    xor eax, ebx\n");
-                fprintf (state->ofp, "    xor edx, ecx\n");
-                break;
-            
-            case TOK_LSH:       case TOK_LSHEQ:
-            
-                l1 = anon_label++;
-                l2 = anon_label++;
-                
-                fprintf (state->ofp, "    test ecx, ecx\n");
-                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), l2);
-                fprintf (state->ofp, "    mov ecx, ebx\n");
-                fprintf (state->ofp, "    cmp ecx, 64\n");
-                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jae L%d\n" : "    jae .L%d\n"), l2);
-                fprintf (state->ofp, "    cmp ecx, 32\n");
-                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jb L%d\n" : "    jb .L%d\n"), l1);
-                fprintf (state->ofp, "    mov edx, eax\n");
-                fprintf (state->ofp, "    xor eax, eax\n");
-                fprintf (state->ofp, "    sub ecx, 32\n");
-                fprintf (state->ofp, "    shl edx, cl\n");
-                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jmp L%d\n" : "    jmp .L%d\n"), l2 + 1);
-                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), l1);
-                fprintf (state->ofp, "    shld edx, eax, cl\n");
-                fprintf (state->ofp, "    shl eax, cl\n");
-                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jmp L%d\n" : "    jmp .L%d\n"), l2 + 1);
-                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), l2);
-                fprintf (state->ofp, "    xor eax, eax\n");
-                fprintf (state->ofp, "    xor edx, edx\n");
-                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), l2 + 1);
-                
-                anon_label++;
-                break;
-            
-            case TOK_RSH:       case TOK_RSHEQ:
-            
-                l1 = anon_label++;
-                l2 = anon_label++;
-                
-                fprintf (state->ofp, "    test ecx, ecx\n");
-                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), l2);
-                fprintf (state->ofp, "    mov ecx, ebx\n");
-                fprintf (state->ofp, "    cmp ecx, 64\n");
-                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jae L%d\n" : "    jae .L%d\n"), l2);
-                fprintf (state->ofp, "    cmp ecx, 32\n");
-                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jb L%d\n" : "    jb .L%d\n"), l1);
-                fprintf (state->ofp, "    mov eax, edx\n");
-                fprintf (state->ofp, is_unsigned ? "    xor edx, edx\n" : "    sar edx, 31\n");
-                fprintf (state->ofp, "    sub ecx, 32\n");
-                fprintf (state->ofp, is_unsigned ? "    shr eax, cl\n" : "    sar eax, cl\n");
-                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jmp L%d\n" : "    jmp .L%d\n"), l2 + 1);
-                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), l1);
-                fprintf (state->ofp, "    shrd eax, edx, cl\n");
-                fprintf (state->ofp, is_unsigned ? "    shr edx, cl\n" : "    sar edx, cl\n");
-                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jmp L%d\n" : "    jmp .L%d\n"), l2 + 1);
-                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), l2);
-                fprintf (state->ofp, is_unsigned ? "    xor eax, eax\n" : "    mov eax, edx\n");
-                fprintf (state->ofp, is_unsigned ? "    xor edx, edx\n" : "    sar edx, 31\n");
-                fprintf (state->ofp, is_unsigned ? "" : "    mov eax, edx\n");
-                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), l2 + 1);
-                
-                anon_label++;
-                break;
-            
-            default:
-            
-                break;
-        
-        }
-    
-    } else {
-    
-        switch (op) {
-        
-            case TOK_PLUS:      case TOK_PLUSEQ:
-            
-                fprintf (state->ofp, "    addl %%ebx, %%eax\n");
-                fprintf (state->ofp, "    adcl %%ecx, %%edx\n");
-                break;
-            
-            case TOK_MINUS:     case TOK_MINUSEQ:
-            
-                fprintf (state->ofp, "    subl %%ebx, %%eax\n");
-                fprintf (state->ofp, "    sbbl %%ecx, %%edx\n");
-                break;
-            
-            case TOK_STAR:      case TOK_STAREQ:
-            
-                fprintf (state->ofp, "    movl %%eax, %%esi\n");
-                fprintf (state->ofp, "    movl %%edx, %%edi\n");
-                fprintf (state->ofp, "    mull %%ebx\n");
-                fprintf (state->ofp, "    movl %%edx, %%esi\n");
-                fprintf (state->ofp, "    movl %%edi, %%edx\n");
-                fprintf (state->ofp, "    imull %%ebx, %%edx\n");
-                fprintf (state->ofp, "    addl %%esi, %%edx\n");
-                break;
-            
-            case TOK_BSLASH:    case TOK_SLASHEQ:
-            
-                emit_assignment_divmod64 (is_unsigned, 0);
-                break;
-            
-            case TOK_MOD:       case TOK_MODEQ:
-            
-                emit_assignment_divmod64 (is_unsigned, 1);
-                break;
-            
-            case TOK_AMPER:     case TOK_ANDEQ:
-            
-                fprintf (state->ofp, "    andl %%ebx, %%eax\n");
-                fprintf (state->ofp, "    andl %%ecx, %%edx\n");
-                break;
-            
-            case TOK_PIPE:      case TOK_OREQ:
-            
-                fprintf (state->ofp, "    orl %%ebx, %%eax\n");
-                fprintf (state->ofp, "    orl %%ecx, %%edx\n");
-                break;
-            
-            case TOK_CARET:     case TOK_XOREQ:
-            
-                fprintf (state->ofp, "    xorl %%ebx, %%eax\n");
-                fprintf (state->ofp, "    xorl %%ecx, %%edx\n");
-                break;
-            
-            case TOK_LSH:       case TOK_LSHEQ:
-            
-                l1 = anon_label++;
-                l2 = anon_label++;
-                
-                fprintf (state->ofp, "    testl %%ecx, %%ecx\n");
-                fprintf (state->ofp, "    jnz .L%d\n", l2);
-                fprintf (state->ofp, "    movl %%ebx, %%ecx\n");
-                fprintf (state->ofp, "    cmpl $64, %%ecx\n");
-                fprintf (state->ofp, "    jae .L%d\n", l2);
-                fprintf (state->ofp, "    cmpl $32, %%ecx\n");
-                fprintf (state->ofp, "    jb .L%d\n", l1);
-                fprintf (state->ofp, "    movl %%eax, %%edx\n");
-                fprintf (state->ofp, "    xorl %%eax, %%eax\n");
-                fprintf (state->ofp, "    subl $32, %%ecx\n");
-                fprintf (state->ofp, "    shll %%cl, %%edx\n");
-                fprintf (state->ofp, "    jmp .L%d\n", l2 + 1);
-                fprintf (state->ofp, ".L%d:\n", l1);
-                fprintf (state->ofp, "    shldl %%cl, %%eax, %%edx\n");
-                fprintf (state->ofp, "    shll %%cl, %%eax\n");
-                fprintf (state->ofp, "    jmp .L%d\n", l2 + 1);
-                fprintf (state->ofp, ".L%d:\n", l2);
-                fprintf (state->ofp, "    xorl %%eax, %%eax\n");
-                fprintf (state->ofp, "    xorl %%edx, %%edx\n");
-                fprintf (state->ofp, ".L%d:\n", l2 + 1);
-                
-                anon_label++;
-                break;
-            
-            case TOK_RSH:       case TOK_RSHEQ:
-            
-                l1 = anon_label++;
-                l2 = anon_label++;
-                
-                fprintf (state->ofp, "    testl %%ecx, %%ecx\n");
-                fprintf (state->ofp, "    jnz .L%d\n", l2);
-                fprintf (state->ofp, "    movl %%ebx, %%ecx\n");
-                fprintf (state->ofp, "    cmpl $64, %%ecx\n");
-                fprintf (state->ofp, "    jae .L%d\n", l2);
-                fprintf (state->ofp, "    cmpl $32, %%ecx\n");
-                fprintf (state->ofp, "    jb .L%d\n", l1);
-                fprintf (state->ofp, "    movl %%edx, %%eax\n");
-                fprintf (state->ofp, is_unsigned ? "    xorl %%edx, %%edx\n" : "    sarl $31, %%edx\n");
-                fprintf (state->ofp, "    subl $32, %%ecx\n");
-                fprintf (state->ofp, is_unsigned ? "    shrl %%cl, %%eax\n" : "    sarl %%cl, %%eax\n");
-                fprintf (state->ofp, "    jmp .L%d\n", l2 + 1);
-                fprintf (state->ofp, ".L%d:\n", l1);
-                fprintf (state->ofp, "    shrdl %%cl, %%edx, %%eax\n");
-                fprintf (state->ofp, is_unsigned ? "    shrl %%cl, %%edx\n" : "    sarl %%cl, %%edx\n");
-                fprintf (state->ofp, "    jmp .L%d\n", l2 + 1);
-                fprintf (state->ofp, ".L%d:\n", l2);
-                fprintf (state->ofp, is_unsigned ? "    xorl %%eax, %%eax\n" : "    movl %%edx, %%eax\n");
-                fprintf (state->ofp, is_unsigned ? "    xorl %%edx, %%edx\n" : "    sarl $31, %%edx\n");
-                fprintf (state->ofp, is_unsigned ? "" : "    movl %%edx, %%eax\n");
-                fprintf (state->ofp, ".L%d:\n", l2 + 1);
-                
-                anon_label++;
-                break;
-            
-            default:
-            
-                break;
-        
-        }
-    
-    }
-
-}
-
-static void emit_call_identifier_to_reg_now (const char *name, const char *reg, const char *name_start, const char *name_caret, unsigned long name_line);
-static void emit_assignment_binary_op (enum token_kind op, int is_unsigned);
-static void emit_store_member_to_addr_reg_now (const char *addr_reg, int offset, const char *value_reg, int size);
-static void emit_store_reg_to_deref_reg_now (const char *addr_reg, const char *value_reg, int size);
-static void emit_load_deref_reg_now (const char *reg, int size);
-
-static void emit_store_floating_member_to_addr_reg_now (const char *addr_reg, int offset, int size);
-static void emit_load_floating_rhs_expression_now (int result_size);
-
-static int emit_load_parenthesized_assignment_expression_to_reg_now (const char *reg, int *out_is_unsigned);
-static int token_is_floating_constant_now (void);
-
-static void emit_load_local_address_to_reg_now (const char *reg, long offset) {
-
-    char memref[64];
-    
-    if (!state->ofp || !reg) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        format_intel_ebp_offset (memref, sizeof (memref), offset);
-        fprintf (state->ofp, "    lea %s, %s\n", reg, memref);
-    
-    } else {
-        fprintf (state->ofp, "    leal %ld(%%ebp), %%%s\n", offset, reg);
-    }
-
-}
-
-static void emit_apply_postfix_member_access_to_reg_now (const char *reg) {
-
-    postfix_member_pointer_depth = 0;
-    postfix_member_pointed_size = 0;
-    postfix_member_seen = 0;
-    postfix_member_offset = 0;
-    postfix_member_size = 0;
-    postfix_member_is_floating = 0;
-    postfix_member_is_unsigned = 0;
-    
-    postfix_member_calling_convention = TOK_EOF;
-
-    {
-    
-        const char *current_object_tag_name = postfix_copy_lvalue_tag_name;
-        int current_object_size = postfix_copy_lvalue_size;
-        
-        if (current_object_size <= 0 && rhs_last_pointed_size > 0) {
-            current_object_size = rhs_last_pointed_size;
-        }
-        
-        while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
-        
-            enum token_kind op = tok.kind;
-            char *member;
-            
-            const char *member_start;
-            const char *member_caret;
-            
-            unsigned long member_line;
-            
-            int offset = 0;
-            int size = DATA_INT & 0x1f;
-            int elem_size = DATA_INT & 0x1f;
-            int pointer_depth = 0;
-            int is_array = 0;
-            int is_floating = 0;
-            int is_unsigned = 0;
-            
-            get_token ();
-            
-            member_start = tok.start;
-            member_caret = tok.caret;
-            member_line = get_line_number ();
-            
-            if (tok.kind != TOK_IDENT) {
-            
-                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", op == TOK_ARROW ? "->" : ".");
-                return;
-            
-            }
-            
-            member = xstrdup (tok.ident);
-            get_token ();
-            
-            if (!find_member_info_ex_bounded (member, current_object_size, current_object_tag_name, &offset, &size, &elem_size, &pointer_depth, &is_array, &is_floating)) {
-            
-                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
-                
-                free (member);
-                return;
-            
-            }
-            
-            is_unsigned = last_found_member_is_unsigned;
-            
-            {
-            
-                const char *member_tag_name = last_found_member_tag_name;
-                
-                /*
-                 * For an array member whose element type is a pointer, the
-                 * subscript step is always one pointer.  Keep this independent
-                 * of the pointed aggregate size; otherwise expressions like
-                 * ic->heads[i] scale by sizeof(*heads[i]) and are later passed
-                 * as an aggregate instead of one pointer.
-                 */
-                if (is_array && pointer_depth > 0) {
-                    elem_size = DATA_PTR;
-                } else if (pointer_depth > 1) {
-                    elem_size = DATA_PTR;
-                } else if (pointer_depth == 1 && member_tag_name) {
-                
-                    struct aggregate_tag_entry *entry = find_aggregate_tag (member_tag_name, 0);
-                    
-                    if (entry) {
-                        elem_size = entry->size;
-                    }
-                
-                }
-                
-                current_object_tag_name = member_tag_name;
-            
-            }
-            
-            free (member);
-            
-            postfix_member_seen = 1;
-            postfix_member_pointer_depth = is_array ? 1 : pointer_depth;
-            postfix_member_pointed_size = elem_size;
-            postfix_member_offset = offset;
-            postfix_member_size = size;
-            postfix_member_is_floating = is_floating;
-            postfix_member_is_unsigned = is_unsigned;
-            postfix_member_calling_convention = last_found_member_calling_convention;
-            
-            if (pointer_depth > 0 || is_array) {
-                current_object_size = elem_size;
-            } else {
-                current_object_size = size;
-            }
-            
-            if (tok.kind == TOK_LBRACK) {
-            
-                enum token_kind assign_op;
-                int subscript_elem_size;
-                
-                if (!is_array && pointer_depth > 0) {
-                    emit_load_member_from_addr_reg_now (reg, reg, offset, DATA_PTR & 0x1f);
-                } else if (state->ofp && offset != 0) {
-                
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
-                    } else {
-                        fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
-                    }
-                
-                }
-                
-                subscript_elem_size = index_step_size (elem_size);
-                
-                if (subscript_elem_size <= 0) {
-                    subscript_elem_size = DATA_INT & 0x1f;
-                }
-                
-                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, subscript_elem_size);
-                
-                if (tok.kind == TOK_ARROW && subscript_elem_size <= (DATA_PTR & 0x1f)) {
-                
-                    emit_load_deref_reg_now (reg, DATA_PTR & 0x1f);
-                    
-                    postfix_member_pointer_depth = 0;
-                    postfix_member_size = DATA_PTR & 0x1f;
-                    
-                    continue;
-                
-                }
-                
-                if (is_assignment_operator (tok.kind)) {
-                
-                    assign_op = tok.kind;
-                    get_token ();
-                    
-                    if (assign_op == TOK_ASSIGN && subscript_elem_size > (DATA_LLONG & 0x1f)
-                        && tok.kind == TOK_IDENT && tok.ident
-                        && get_global_symbol_kind (tok.ident) == GLOBAL_SYMBOL_FUNCTION) {
-                    
-                        char *rhs_name = xstrdup (tok.ident);
-                        
-                        const char *rhs_start = tok.start;
-                        const char *rhs_caret = tok.caret;
-                        
-                        unsigned long rhs_line = get_line_number ();
-                        emit_push_reg_now (reg);
-                        
-                        pending_struct_return_lhs = 0;
-                        pending_struct_return_global_name = 0;
-                        pending_struct_return_stack_address = 1;
-                        pending_struct_return_stack_offset = 0;
-                        
-                        get_token ();
-                        emit_call_identifier_to_reg_now (rhs_name, reg, rhs_start, rhs_caret, rhs_line);
-                        
-                        pending_struct_return_stack_address = 0;
-                        pending_struct_return_stack_offset = 0;
-                        
-                        emit_pop_reg_now ("edx");
-                        free (rhs_name);
-                        
-                        postfix_member_seen = 0;
-                        return;
-                    
-                    }
-                    
-                    emit_push_reg_now (reg);
-                    
-                    if (assign_op == TOK_ASSIGN) {
-                    
-                        if (subscript_elem_size > (DATA_LLONG & 0x1f)) {
-                        
-                            pending_struct_return_lhs = 0;
-                            pending_struct_return_global_name = 0;
-                            pending_struct_return_stack_address = 1;
-                            pending_struct_return_stack_offset = 0;
-                            
-                            emit_load_assignment_rhs_expression_to_reg (reg);
-                            
-                            pending_struct_return_stack_address = 0;
-                            pending_struct_return_stack_offset = 0;
-                            
-                            emit_pop_reg_now ("edx");
-                            
-                            postfix_member_seen = 0;
-                            return;
-                        
-                        }
-                        
-                        emit_load_assignment_rhs_expression_to_reg (reg);
-                    
-                    } else {
-                    
-                        emit_load_deref_reg_now (reg, subscript_elem_size);
-                        emit_push_reg_now (reg);
-                        emit_load_assignment_rhs_expression_to_reg ("edx");
-                        emit_pop_reg_now (reg);
-                        emit_assignment_binary_op (assign_op, 0);
-                    
-                    }
-                    
-                    emit_pop_reg_now ("edx");
-                    emit_store_reg_to_deref_reg_now ("edx", reg, subscript_elem_size);
-                    
-                    postfix_member_seen = 0;
-                    return;
-                
-                }
-                
-                if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
-                
-                    current_object_size = elem_size;
-                    continue;
-                
-                }
-                
-                /**
-                 * The expression now denotes the subscripted element, not the
-                 * whole member array.  Keep the postfix-member metadata in
-                 * step with the value in REG so argument passing does not
-                 * mistake e.g. ic->heads[i] for the entire heads[] aggregate
-                 * and push multiple words.
-                 *
-                 * If the element itself is an aggregate, REG must remain the
-                 * address of that element.  Loading *(REG) would fetch the
-                 * first word of the struct and later aggregate argument
-                 * passing would treat that word as a pointer, as happened for
-                 * instruction.types[instruction.operands].
-                 */
-                postfix_member_size = subscript_elem_size;
-                
-                /*
-                 * Subscript of an array member whose element type is a pointer
-                 * yields the pointer stored in that array slot.  The generic
-                 * aggregate-subscript path deliberately keeps struct elements as
-                 * addresses, but pointer elements must still be loaded before a
-                 * following -> member access.  Otherwise expressions such as
-                 * instruction.regs[operand]->type.reg_rex treat the address of
-                 * the regs[] slot as if it were a struct reg_entry *.
-                 */
-                if (is_array && (pointer_depth > 0 || (tok.kind == TOK_ARROW && subscript_elem_size == (DATA_PTR & 0x1f)))) {
-                
-                    emit_load_deref_reg_now (reg, DATA_PTR & 0x1f);
-                    
-                    postfix_member_pointer_depth = pointer_depth > 0 ? pointer_depth - 1 : 0;
-                    postfix_member_size = DATA_PTR & 0x1f;
-                    
-                    if (postfix_member_pointer_depth == 0 && current_object_tag_name) {
-                    
-                        struct aggregate_tag_entry *entry = find_aggregate_tag (current_object_tag_name, 0);
-                        
-                        if (entry) {
-                            current_object_size = entry->size;
-                        }
-                    
-                    }
-                    
-                    continue;
-                
-                }
-                
-                if (postfix_member_pointer_depth > 0) {
-                    postfix_member_pointer_depth--;
-                }
-                
-                if (postfix_member_pointer_depth != 0
-                    || postfix_member_size <= (DATA_PTR & 0x1f)) {
-                    emit_load_deref_reg_now (reg, subscript_elem_size);
-                }
-                
-                continue;
-            
-            }
-            
-            if (is_array && tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
-            
-                if (state->ofp && offset != 0) {
-                
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
-                    } else {
-                        fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
-                    }
-                
-                }
-                
-                /*
-                 * A bare array member expression decays to a pointer when used
-                 * as an rvalue/function argument.  Keep REG as the element
-                 * address, but do not leave aggregate element metadata behind or
-                 * the call argument path will push the first element by value.
-                 * This broke calls such as _cpp_add_unknown2_direct(...,
-                 * macro->tokens, token_count), where tokens[0] is a struct.
-                 */
-                postfix_member_size = DATA_PTR & 0x1f;
-                postfix_member_pointer_depth = 1;
-                postfix_member_pointed_size = elem_size;
-                
-                continue;
-            
-            }
-            
-            if ((tok.kind == TOK_ARROW || tok.kind == TOK_DOT) && pointer_depth == 0) {
-            
-                if (state->ofp && offset != 0) {
-                
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
-                    } else {
-                        fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
-                    }
-                
-                }
-                
-                continue;
-            
-            }
-            
-            if (size > (DATA_PTR & 0x1f) && tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
-            
-                if (state->ofp && offset != 0) {
-                
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
-                    } else {
-                        fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
-                    }
-                
-                }
-                
-                continue;
-            
-            }
-            
-            if (state->ofp) {
-            
-                if (strcmp (reg, "edx") != 0) {
-                
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                        fprintf (state->ofp, "    mov edx, %s\n", reg);
-                    } else {
-                        fprintf (state->ofp, "    movl %%%s, %%edx\n", reg);
-                    }
-                
-                }
-                
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                
-                    const char *opsize = "dword";
-                    
-                    if (size == 1) {
-                        opsize = "byte";
-                    } else if (size == 2) {
-                        opsize = "word";
-                    }
-                    
-                    if (state->syntax & ASM_SYNTAX_NASM) {
-                    
-                        if (size == 1) {
-                            fprintf (state->ofp, "    movzx %s, byte [%s + %d]\n", reg, reg, offset);
-                        } else if (size == 2) {
-                            fprintf (state->ofp, "    movzx %s, word [%s + %d]\n", reg, reg, offset);
-                        } else {
-                            fprintf (state->ofp, "    mov %s, %s [%s + %d]\n", reg, opsize, reg, offset);
-                        }
-                    
-                    } else {
-                    
-                        if (size == 1) {
-                            fprintf (state->ofp, "    movzx %s, byte ptr [%s + %d]\n", reg, reg, offset);
-                        } else if (size == 2) {
-                            fprintf (state->ofp, "    movzx %s, word ptr [%s + %d]\n", reg, reg, offset);
-                        } else {
-                            fprintf (state->ofp, "    mov %s, %s ptr [%s + %d]\n", reg, opsize, reg, offset);
-                        }
-                    
-                    }
-                
-                } else {
-                
-                    if (size == 1) {
-                        fprintf (state->ofp, "    movzbl %d(%%%s), %%%s\n", offset, reg, reg);
-                    } else if (size == 2) {
-                        fprintf (state->ofp, "    movzwl %d(%%%s), %%%s\n", offset, reg, reg);
-                    } else {
-                        fprintf (state->ofp, "    movl %d(%%%s), %%%s\n", offset, reg, reg);
-                    }
-                
-                }
-            
-            }
-        
-        }
-    
-    }
-
-}
-
-static void emit_apply_postfix_member_incdec_now (const char *reg, enum token_kind op) {
-
-    if (!postfix_member_seen) {
-        return;
-    }
-    
-    if (state->ofp) {
-    
-        const char *insn = op == TOK_INCR ? "inc" : "dec";
-        (void) reg;
-        
-        if (postfix_member_pointer_depth > 0) {
-        
-            int step = postfix_member_pointed_size;
-            const char *arith = op == TOK_INCR ? "add" : "sub";
-            
-            if (step <= 0) {
-                step = 1;
-            }
-            
-            if (step == 1) {
-                /* Falling through keeps the compact inc/dec form for char *. */
-            } else if (state->syntax & ASM_SYNTAX_INTEL) {
-            
-                if (state->syntax & ASM_SYNTAX_NASM) {
-                    fprintf (state->ofp, "    %s dword [edx + %d], %d\n", arith, postfix_member_offset, step);
-                } else {
-                    fprintf (state->ofp, "    %s dword ptr [edx + %d], %d\n", arith, postfix_member_offset, step);
-                }
-                
-                return;
-            
-            } else {
-            
-                fprintf (state->ofp, "    %sl $%d, %d(%%edx)\n", arith, step, postfix_member_offset);
-                return;
-            }
-        
-        }
-        
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-        
-            const char *opsize = "dword";
-            
-            if (postfix_member_size == 1) {
-                opsize = "byte";
-            } else if (postfix_member_size == 2) {
-                opsize = "word";
-            }
-            
-            if (state->syntax & ASM_SYNTAX_NASM) {
-                fprintf (state->ofp, "    %s %s [edx + %d]\n", insn, opsize, postfix_member_offset);
-            } else {
-                fprintf (state->ofp, "    %s %s ptr [edx + %d]\n", insn, opsize, postfix_member_offset);
-            }
-        
-        } else {
-        
-            if (postfix_member_size == 1) {
-                fprintf (state->ofp, "    %sb %d(%%edx)\n", insn, postfix_member_offset);
-            } else if (postfix_member_size == 2) {
-                fprintf (state->ofp, "    %sw %d(%%edx)\n", insn, postfix_member_offset);
-            } else {
-                fprintf (state->ofp, "    %sl %d(%%edx)\n", insn, postfix_member_offset);
-            }
-        
-        }
-    
-    }
-
-}
-
-static int rhs_text_is_plain_aggregate_lvalue_now (const char *p) {
-
-    int paren_depth = 0;
-    int bracket_depth = 0;
-    int saw_ident = 0;
-    
-    if (!p) {
-        return 1;
-    }
-    
-    while (*p) {
-    
-        unsigned char ch = (unsigned char) *p;
-        
-        if (ch == '\'' || ch == '"') {
-        
-            int quote = ch;
-            p++;
-            
-            while (*p && *p != quote) {
-            
-                if (*p == '\\' && p[1]) {
-                    p += 2;
-                } else {
-                    p++;
-                }
-            
-            }
-            
-            if (*p == quote) {
-                p++;
-            }
-            
-            continue;
-        
-        }
-        
-        if (ch == '(') {
-        
-            paren_depth++;
-            p++;
-            
-            continue;
-        
-        }
-        
-        if (ch == ')') {
-        
-            if (paren_depth == 0 && bracket_depth == 0) {
-                break;
-            }
-            
-            if (paren_depth > 0) {
-                paren_depth--;
-            }
-            
-            p++;
-            continue;
-        
-        }
-        
-        if (ch == '[') {
-        
-            bracket_depth++;
-            p++;
-            
-            continue;
-        
-        }
-        
-        if (ch == ']') {
-        
-            if (bracket_depth > 0) {
-                bracket_depth--;
-            }
-            
-            p++;
-            continue;
-        
-        }
-        
-        if (paren_depth == 0 && bracket_depth == 0) {
-        
-            if (ch == ';' || ch == ',') {
-                break;
-            }
-            
-            if (ch == '-' && p[1] == '>') {
-            
-                p += 2;
-                continue;
-            
-            }
-            
-            if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%' ||
-                ch == '&' || ch == '|' || ch == '^' || ch == '?' || ch == ':') {
-                return 0;
-            }
-        
-        }
-        
-        if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '_') {
-            saw_ident = 1;
-        }
-        
-        p++;
-    
-    }
-
-    return saw_ident;
-
-}
-
-static int emit_aggregate_copy_from_current_rhs_to_addr_reg_now (const char *addr_reg, int offset, int size);
-static int emit_parse_postfix_copy_source_address_now (const char *reg, struct local_symbol *src, const char *src_name, const char *name_start, const char *name_caret, unsigned long name_line);
-
-static int emit_store_assignment_to_aggregate_address_now (const char *addr_reg, int size, const char *name_start, const char *name_caret, unsigned long name_line) {
-
-    enum token_kind op;
-    
-    if (!is_assignment_operator (tok.kind) || size <= (DATA_LLONG & 0x1f)) {
-        return 0;
-    }
-    
-    op = tok.kind;
-    get_token ();
-    
-    if (op == TOK_ASSIGN && tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now ()) {
-    
-        char *rhs_name = xstrdup (tok.ident);
-        
-        const char *rhs_start = tok.start ? tok.start : name_start;
-        const char *rhs_caret = tok.caret ? tok.caret : name_caret;
-        
-        unsigned long rhs_line = get_line_number ();
-        emit_push_reg_now (addr_reg);
-        
-        pending_struct_return_lhs = 0;
-        pending_struct_return_global_name = 0;
-        pending_struct_return_stack_address = 1;
-        pending_struct_return_stack_offset = 0;
-        
-        get_token ();
-        emit_call_identifier_to_reg_now (rhs_name, "eax", rhs_start, rhs_caret, rhs_line);
-        
-        pending_struct_return_stack_address = 0;
-        pending_struct_return_stack_offset = 0;
-        
-        emit_pop_reg_now ("edx");
-        free (rhs_name);
-        
-        return 1;
-    
-    }
-    
-    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "aggregate assignment expression not implemented");
-    
-    skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-    return 1;
-
-}
-
-static int rhs_current_operand_is_floating_now (void);
-
-static int emit_store_assignment_to_postfix_member_now (const char *reg) {
-
-    enum token_kind op;
-    int assign_member_offset;
-    int assign_member_size;
-    
-    if (!postfix_member_seen || !is_assignment_operator (tok.kind)) {
-        return 0;
-    }
-    
-    op = tok.kind;
-    assign_member_offset = postfix_member_offset;
-    assign_member_size = postfix_member_size;
-    
-    get_token ();
-    
-    if (state->ofp) {
-    
-        if (op == TOK_ASSIGN) {
-        
-            if (postfix_member_is_floating || token_is_floating_constant_now () || rhs_current_operand_is_floating_now ()) {
-            
-                emit_push_reg_now ("edx");
-                emit_load_floating_rhs_expression_now (assign_member_size);
-                
-                emit_pop_reg_now ("edx");
-                emit_store_floating_member_to_addr_reg_now ("edx", assign_member_offset, assign_member_size);
-                
-                return 1;
-            
-            }
-            
-            if (assign_member_size > (DATA_LLONG & 0x1f) &&
-                tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now ()) {
-            
-                char *rhs_name = xstrdup (tok.ident);
-                
-                const char *rhs_start = tok.start;
-                const char *rhs_caret = tok.caret;
-                
-                unsigned long rhs_line = get_line_number ();
-                emit_push_reg_now ("edx");
-                
-                pending_struct_return_lhs = 0;
-                pending_struct_return_global_name = 0;
-                pending_struct_return_stack_address = 1;
-                pending_struct_return_stack_offset = assign_member_offset;
-                
-                get_token ();
-                emit_call_identifier_to_reg_now (rhs_name, reg, rhs_start, rhs_caret, rhs_line);
-                
-                pending_struct_return_stack_address = 0;
-                pending_struct_return_stack_offset = 0;
-                
-                emit_pop_reg_now ("edx");
-                free (rhs_name);
-                
-                return 1;
-            
-            }
-            
-            if (emit_aggregate_copy_from_current_rhs_to_addr_reg_now ("edx", assign_member_offset, assign_member_size)) {
-                return 1;
-            }
-            
-            emit_push_reg_now ("edx");
-            
-            emit_load_assignment_rhs_expression_to_reg (reg);
-            emit_pop_reg_now ("edx");
-        
-        } else {
-        
-            emit_push_reg_now ("edx");
-            emit_push_reg_now (reg);
-            
-            emit_load_assignment_rhs_expression_to_reg ("edx");
-            emit_pop_reg_now (reg);
-            
-            emit_assignment_binary_op (op, 0);
-            emit_pop_reg_now ("edx");
-        
-        }
-        
-        emit_store_member_to_addr_reg_now ("edx", assign_member_offset, reg, assign_member_size);
-    
-    } else {
-        emit_load_assignment_rhs_expression_to_reg (reg);
-    }
-    
-    return 1;
-
-}
-
-static int parenthesized_function_designator_call_now (void) {
-
-    const char *p;
-    
-    if (tok.kind != TOK_IDENT || !tok.caret || !tok.ident) {
-        return 0;
-    }
-    
-    p = tok.caret + strlen (tok.ident);
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (*p != ')') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    return *p == '(';
-
-}
-
-static void emit_load_deref_reg_ex_now (const char *reg, int size, int is_unsigned) {
-
-    const char *op8;
-    const char *op16;
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    op8 = is_unsigned ? "movzx" : "movsx";
-    op16 = is_unsigned ? "movzx" : "movsx";
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (state->syntax & ASM_SYNTAX_NASM) {
-        
-            if (size == (DATA_CHAR & 0x1f)) {
-                fprintf (state->ofp, "    %s %s, byte [%s]\n", op8, reg, reg);
-            } else if (size == (DATA_SHORT & 0x1f)) {
-                fprintf (state->ofp, "    %s %s, word [%s]\n", op16, reg, reg);
-            } else {
-                fprintf (state->ofp, "    mov %s, dword [%s]\n", reg, reg);
-            }
-        
-        } else {
-        
-            if (size == (DATA_CHAR & 0x1f)) {
-                fprintf (state->ofp, "    %s %s, byte ptr [%s]\n", op8, reg, reg);
-            } else if (size == (DATA_SHORT & 0x1f)) {
-                fprintf (state->ofp, "    %s %s, word ptr [%s]\n", op16, reg, reg);
-            } else {
-                fprintf (state->ofp, "    mov %s, dword ptr [%s]\n", reg, reg);
-            }
-        
-        }
-    
-    } else {
-    
-        if (size == (DATA_CHAR & 0x1f)) {
-            fprintf (state->ofp, "    %s (%%%s), %%%s\n", is_unsigned ? "movzbl" : "movsbl", reg, reg);
-        } else if (size == (DATA_SHORT & 0x1f)) {
-            fprintf (state->ofp, "    %s (%%%s), %%%s\n", is_unsigned ? "movzwl" : "movswl", reg, reg);
-        } else {
-            fprintf (state->ofp, "    movl (%%%s), %%%s\n", reg, reg);
-        }
-    
-    }
-
-}
-
-static void emit_load_deref_reg_now (const char *reg, int size) {
-    emit_load_deref_reg_ex_now (reg, size, 0);
-}
-
-static void emit_store_reg_to_deref_reg_now (const char *addr_reg, const char *value_reg, int size) {
-
-    if (suppress_next_struct_return_scalar_store) {
-    
-        suppress_next_struct_return_scalar_store = 0;
-        return;
-    
-    }
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (state->syntax & ASM_SYNTAX_NASM) {
-        
-            if (size == (DATA_CHAR & 0x1f)) {
-                fprintf (state->ofp, "    mov byte [%s], %cl\n", addr_reg, value_reg[1]);
-            } else if (size == (DATA_SHORT & 0x1f)) {
-                fprintf (state->ofp, "    mov word [%s], %cx\n", addr_reg, value_reg[1]);
-            } else {
-                fprintf (state->ofp, "    mov dword [%s], %s\n", addr_reg, value_reg);
-            }
-        
-        } else {
-        
-            if (size == (DATA_CHAR & 0x1f)) {
-                fprintf (state->ofp, "    mov byte ptr [%s], %cl\n", addr_reg, value_reg[1]);
-            } else if (size == (DATA_SHORT & 0x1f)) {
-                fprintf (state->ofp, "    mov word ptr [%s], %cx\n", addr_reg, value_reg[1]);
-            } else {
-                fprintf (state->ofp, "    mov dword ptr [%s], %s\n", addr_reg, value_reg);
-            }
-        
-        }
-    
-    } else {
-    
-        if (size == (DATA_CHAR & 0x1f)) {
-            fprintf (state->ofp, "    movb %%%cl, (%%%s)\n", value_reg[1], addr_reg);
-        } else if (size == (DATA_SHORT & 0x1f)) {
-            fprintf (state->ofp, "    movw %%%cx, (%%%s)\n", value_reg[1], addr_reg);
-        } else {
-            fprintf (state->ofp, "    movl %%%s, (%%%s)\n", value_reg, addr_reg);
-        }
-    
-    }
-
-}
-
-static int emit_handle_subscript_after_loaded_pointer_to_reg_now (const char *reg, int pointer_depth, int pointed_size, int pointed_is_unsigned) {
-
-    int subscript_elem_size;
-    
-    if (tok.kind != TOK_LBRACK) {
-        return 0;
-    }
-    
-    subscript_elem_size = pointer_depth > 1 ? (DATA_PTR & 0x1f) : pointed_size;
-    
-    if (subscript_elem_size <= 0) {
-        subscript_elem_size = DATA_INT & 0x1f;
-    }
-    
-    emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, subscript_elem_size);
-    
-    if (is_assignment_operator (tok.kind)) {
-    
-        enum token_kind assign_op = tok.kind;
-        
-        get_token ();
-        emit_push_reg_now (reg);
-        
-        if (assign_op == TOK_ASSIGN) {
-            emit_load_assignment_rhs_expression_to_reg (reg);
-        } else {
-        
-            emit_load_deref_reg_now (reg, subscript_elem_size);
-            emit_push_reg_now (reg);
-            
-            emit_load_assignment_rhs_expression_to_reg ("edx");
-            emit_pop_reg_now (reg);
-            
-            emit_assignment_binary_op (assign_op, 0);
-        
-        }
-        
-        emit_pop_reg_now ("edx");
-        
-        emit_store_reg_to_deref_reg_now ("edx", reg, subscript_elem_size);
-        clear_rhs_last_pointer_info ();
-        
-        return 1;
-    
-    }
-    
-    emit_load_deref_reg_ex_now (reg, subscript_elem_size, pointer_depth <= 1 ? pointed_is_unsigned : 0);
-    
-    if (pointer_depth > 1) {
-        set_rhs_last_pointer_info (pointer_depth - 1, pointed_size);
-    } else {
-        clear_rhs_last_pointer_info ();
-    }
-    
-    return 1;
-
-}
-
-static void emit_load_member_from_addr_reg_now (const char *dst_reg, const char *addr_reg, int offset, int size) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (state->syntax & ASM_SYNTAX_NASM) {
-        
-            if (size == (DATA_CHAR & 0x1f)) {
-                fprintf (state->ofp, "    movsx %s, byte [%s + %d]\n", dst_reg, addr_reg, offset);
-            } else if (size == (DATA_SHORT & 0x1f)) {
-                fprintf (state->ofp, "    movsx %s, word [%s + %d]\n", dst_reg, addr_reg, offset);
-            } else {
-                fprintf (state->ofp, "    mov %s, dword [%s + %d]\n", dst_reg, addr_reg, offset);
-            }
-        
-        } else {
-        
-            if (size == (DATA_CHAR & 0x1f)) {
-                fprintf (state->ofp, "    movsx %s, byte ptr [%s + %d]\n", dst_reg, addr_reg, offset);
-            } else if (size == (DATA_SHORT & 0x1f)) {
-                fprintf (state->ofp, "    movsx %s, word ptr [%s + %d]\n", dst_reg, addr_reg, offset);
-            } else {
-                fprintf (state->ofp, "    mov %s, dword ptr [%s + %d]\n", dst_reg, addr_reg, offset);
-            }
-        
-        }
-    
-    } else {
-    
-        if (size == (DATA_CHAR & 0x1f)) {
-            fprintf (state->ofp, "    movsbl %d(%%%s), %%%s\n", offset, addr_reg, dst_reg);
-        } else if (size == (DATA_SHORT & 0x1f)) {
-            fprintf (state->ofp, "    movswl %d(%%%s), %%%s\n", offset, addr_reg, dst_reg);
-        } else {
-            fprintf (state->ofp, "    movl %d(%%%s), %%%s\n", offset, addr_reg, dst_reg);
-        }
-    
-    }
-
-}
-
-static int emit_load_address_of_parenthesized_postfix_to_reg_now (const char *reg) {
-
-    char *name;
-    
-    enum token_kind member_op;
-    struct local_symbol *src;
-    
-    int global_index;
-    
-    const char *current_object_tag_name = 0;
-    int current_object_size = 0;
-    
-    if (tok.kind != TOK_LPAREN) {
-        return 0;
-    }
-    
-    get_token ();
-    
-    if (tok.kind == TOK_LPAREN) {
-    
-        int64_s offset_value;
-        
-        if (parse_constexpr_null_member_address_after_lparen (&offset_value)) {
-        
-            emit_load_const32_to_reg_now (reg, offset_value);
-            return 1;
-        
-        }
-    
-    }
-    
-    if (tok.kind != TOK_IDENT) {
-    
-        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after '&('");
-        
-        expect (TOK_RPAREN, ")");
-        return 1;
-    
-    }
-    
-    name = xstrdup (tok.ident);
-    get_token ();
-    
-    src = find_local_symbol (name);
-    global_index = find_global_symbol (name);
-    
-    if (src) {
-    
-        if (src->is_array) {
-        
-            current_object_size = src->pointed_size > 0 ? src->pointed_size : src->size;
-            current_object_tag_name = src->pointed_tag_name;
-            
-            if (src->is_static && src->static_label) {
-                emit_load_symbol_address_to_reg_now (reg, src->static_label, 0, 0);
-            } else {
-                emit_load_symbol_address_to_reg_now (reg, 0, src->offset, 1);
-            }
-        
-        } else if (src->pointer_depth > 0) {
-        
-            current_object_size = src->pointed_size > 0 ? src->pointed_size : DATA_PTR;
-            current_object_tag_name = src->pointed_tag_name;
-            
-            if (src->is_static && src->static_label) {
-                emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
-            
-            } else {
-                emit_load_local_to_reg (reg, src->offset, DATA_PTR);
-            }
-        
-        } else if (src->is_static && src->static_label) {
-        
-            current_object_size = src->size;
-            emit_load_address_to_reg_now (reg, src->static_label);
-        
-        } else {
-        
-            current_object_size = src->size;
-            
-            /**
-             * A typedef such as section_t can hide the pointer depth from this
-             * older parser.  For &(p->member), the base must be the pointer
-             * value stored in the local, not the address of the local slot.
-             *
-             * Keep the pointed aggregate tag as well.  Without that, address-of
-             * member expressions such as &symbol->next can fall back to an
-             * unqualified member-name lookup and pick another struct's "next"
-             * field.  That emitted symbol + 24 instead of symbol + 36 for
-             * struct symbol::next, corrupting symbol->section in pdas.
-             */
-            if (tok.kind == TOK_ARROW && src->size == (DATA_PTR & 0x1f)) {
-            
-                if (src->pointed_tag_name) {
-                
-                    struct aggregate_tag_entry *entry = find_aggregate_tag (src->pointed_tag_name, 0);
-                    current_object_tag_name = src->pointed_tag_name;
-                    
-                    if (entry) {
-                        current_object_size = entry->size;
-                    }
-                
-                }
-                
-                emit_load_local_to_reg (reg, src->offset, DATA_PTR);
-            
-            } else {
-                emit_load_local_address_to_reg_now (reg, src->offset);
-            }
-        
-        }
-    
-    } else if (global_index >= 0) {
-    
-        if (get_global_symbol_array (name)) {
-        
-            current_object_size = get_global_symbol_pointed_size (name);
-            emit_load_symbol_address_to_reg_now (reg, name, 0, 0);
-        
-        } else if (get_global_symbol_pointer_depth (name) > 0 || (tok.kind == TOK_ARROW && get_global_symbol_size (name) == (DATA_PTR & 0x1f))) {
-        
-            current_object_size = get_global_symbol_pointed_size (name);
-            
-            if (current_object_size <= 0) {
-                current_object_size = DATA_PTR & 0x1f;
-            }
-            
-            emit_load_global_to_reg (reg, name, DATA_PTR);
-        
-        } else {
-        
-            current_object_size = get_global_symbol_size (name);
-            emit_load_address_to_reg_now (reg, name);
-        
-        }
-    
-    } else {
-    
-        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "unknown symbol '%s'", name);
-        free (name);
-        
-        expect (TOK_RPAREN, ")");
-        return 1;
-    
-    }
-    
-    if (tok.kind == TOK_LBRACK) {
-    
-        int elem_size = DATA_INT & 0x1f;
-        
-        if (src) {
-        
-            elem_size = src->is_array ? (src->pointer_depth ? DATA_PTR : (src->array_element_size > 0 ? src->array_element_size : src->pointed_size)) :
-                (src->pointer_depth > 1 ? DATA_PTR : src->pointed_size);
-        
-        } else if (global_index >= 0) {
-        
-            elem_size = get_global_symbol_array (name) ?
-                (get_global_symbol_pointer_depth (name) ? DATA_PTR : (get_global_symbol_array_element_size (name) > 0 ? get_global_symbol_array_element_size (name) : get_global_symbol_pointed_size (name))) :
-                    (get_global_symbol_pointer_depth (name) > 1 ? DATA_PTR : get_global_symbol_pointed_size (name));
-        
-        }
-        
-        if (elem_size <= 0) {
-            elem_size = DATA_INT & 0x1f;
-        }
-        
-        emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
-    
-    }
-    
-    free (name);
-    
-    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
-    
-        char *member;
-        
-        const char *member_start;
-        const char *member_caret;
-        
-        unsigned long member_line;
-        
-        int offset;
-        int size;
-        int elem_size;
-        int pointer_depth;
-        
-        member_op = tok.kind;
-        get_token ();
-        
-        member_start = tok.start;
-        member_caret = tok.caret;
-        member_line = get_line_number ();
-        
-        if (tok.kind != TOK_IDENT) {
-        
-            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
-            
-            expect (TOK_RPAREN, ")");
-            return 1;
-        
-        }
-        
-        member = xstrdup (tok.ident);
-        get_token ();
-        
-        offset = 0;
-        size = DATA_INT & 0x1f;
-        elem_size = DATA_INT & 0x1f;
-        pointer_depth = 0;
-        
-        if (!find_member_info_ex_bounded (member, current_object_size, current_object_tag_name, &offset, &size, &elem_size, &pointer_depth, 0, 0)) {
-        
-            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
-            
-            free (member);
-            expect (TOK_RPAREN, ")");
-            
-            return 1;
-        
-        }
-        
-        current_object_tag_name = last_found_member_tag_name;
-        free (member);
-        
-        if (tok.kind == TOK_LBRACK) {
-        
-            if (pointer_depth > 0) {
-            
-                emit_load_member_from_addr_reg_now (reg, reg, offset, DATA_PTR & 0x1f);
-                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
-            
-            } else {
-            
-                if (state->ofp && offset != 0) {
-                
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
-                    } else {
-                        fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
-                    }
-                
-                }
-                
-                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
-            
-            }
-        
-        } else {
-        
-            if (state->ofp && offset != 0) {
-            
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                    fprintf (state->ofp, "    add %s, %d\n", reg, offset);
-                } else {
-                    fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
-                }
-            
-            }
-        
-        }
-        
-        if (pointer_depth > 0) {
-            current_object_size = elem_size > 0 ? elem_size : DATA_PTR;
-        } else {
-            current_object_size = size;
-        }
-    
-    }
-    
-    expect (TOK_RPAREN, ")");
-    return 1;
-
-}
-
-static void emit_store_member_to_addr_reg_now (const char *addr_reg, int offset, const char *value_reg, int size) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (offset != 0) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-            fprintf (state->ofp, "    add %s, %d\n", addr_reg, offset);
-        } else {
-            fprintf (state->ofp, "    addl $%d, %%%s\n", offset, addr_reg);
-        }
-    
-    }
-    
-    emit_store_reg_to_deref_reg_now (addr_reg, value_reg, size);
-
-}
-
-static void emit_store_floating_member_to_addr_reg_now (const char *addr_reg, int offset, int size) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (offset != 0) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-            fprintf (state->ofp, "    add %s, %d\n", addr_reg, offset);
-        } else {
-            fprintf (state->ofp, "    addl $%d, %%%s\n", offset, addr_reg);
-        }
-    
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fstp %s [%s]\n" : "    fstp %s ptr [%s]\n", size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", addr_reg);
-    } else {
-        fprintf (state->ofp, "    fstp%s (%%%s)\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", addr_reg);
-    }
-
-}
-
-static void emit_load_symbol_address_for_copy_now (const char *reg, struct local_symbol *sym, const char *name) {
-
-    if (sym) {
-    
-        if (sym->is_static && sym->static_label) {
-            emit_load_address_to_reg_now (reg, sym->static_label);
-        } else {
-            emit_load_local_address_to_reg_now (reg, sym->offset);
-        }
-    
-    } else {
-        emit_load_address_to_reg_now (reg, name);
-    }
-
-}
-
-static void emit_copy_fixed_size_now (int size) {
-
-    int offset = 0;
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    while (size - offset >= 4) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-        
-            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov ecx, dword [eax + %d]\n" : "    mov ecx, dword ptr [eax + %d]\n", offset);
-            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov dword [edx + %d], ecx\n" : "    mov dword ptr [edx + %d], ecx\n", offset);
-        
-        } else {
-        
-            fprintf (state->ofp, "    movl %d(%%eax), %%ecx\n", offset);
-            fprintf (state->ofp, "    movl %%ecx, %d(%%edx)\n", offset);
-        
-        }
-        
-        offset += 4;
-    
-    }
-    
-    while (size - offset >= 2) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-        
-            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov cx, word [eax + %d]\n" : "    mov cx, word ptr [eax + %d]\n", offset);
-            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov word [edx + %d], cx\n" : "    mov word ptr [edx + %d], cx\n", offset);
-        
-        } else {
-        
-            fprintf (state->ofp, "    movw %d(%%eax), %%cx\n", offset);
-            fprintf (state->ofp, "    movw %%cx, %d(%%edx)\n", offset);
-        
-        }
-        
-        offset += 2;
-    
-    }
-    
-    while (size - offset >= 1) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-        
-            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov cl, byte [eax + %d]\n" : "    mov cl, byte ptr [eax + %d]\n", offset);
-            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov byte [edx + %d], cl\n" : "    mov byte ptr [edx + %d], cl\n", offset);
-        
-        } else {
-        
-            fprintf (state->ofp, "    movb %d(%%eax), %%cl\n", offset);
-            fprintf (state->ofp, "    movb %%cl, %d(%%edx)\n", offset);
-        
-        }
-        
-        offset++;
-    
-    }
-
-}
-
-static void emit_memcpy_symbol_to_symbol_now (struct local_symbol *dst, const char *dst_name, struct local_symbol *src, const char *src_name, int size) {
-
-    emit_load_symbol_address_for_copy_now ("eax", src, src_name);
-    emit_load_symbol_address_for_copy_now ("edx", dst, dst_name);
-    emit_copy_fixed_size_now (size);
-
-}
-
-static int token_identifier_is_function_call_rhs_now (void) {
-
-    struct token *saved_tok;
-    int is_call;
-    
-    if (tok.kind != TOK_IDENT || !tok.ident) {
-        return 0;
-    }
-    
-    /**
-     * Do not inspect tok.start/tok.caret to decide whether this identifier is
-     * followed by a call.  After macro substitution the spelling in the source
-     * can be a different length from tok.ident, e.g.
-     *
-     *     #define cc_parse_type ccpartype
-     *     member.type = cc_parse_type(reader);
-     *
-     * tok.ident is "ccpartype" but tok.caret still points into the original
-     * text "cc_parse_type(reader)".  The old spelling-based test missed the
-     * '(' and the aggregate-copy fast path treated the function symbol as an
-     * object, leaving the argument list unconsumed and producing "expected ;".
-     */
-    saved_tok = xmalloc (sizeof (*saved_tok));
-    *saved_tok = tok;
-    
-    if (tok.ident) {
-        saved_tok->ident = xstrdup (tok.ident);
-    }
-    
-    if (tok.start) {
-    
-        const char *old_start = tok.start;
-        const char *old_caret = tok.caret;
-        
-        saved_tok->start = xstrdup (old_start);
-        
-        if (old_caret && old_caret >= old_start) {
-            saved_tok->caret = saved_tok->start + (old_caret - old_start);
-        } else {
-            saved_tok->caret = saved_tok->start;
-        }
-    
-    }
-    
-    get_token ();
-    
-    is_call = (tok.kind == TOK_LPAREN);
-    unget_token (saved_tok);
-    
-    return is_call;
-
-}
-
-static struct token *clone_current_token_now (void) {
-
-    struct token *saved_tok = xmalloc (sizeof (*saved_tok));
-    *saved_tok = tok;
-    
-    if (tok.ident) {
-        saved_tok->ident = xstrdup (tok.ident);
-    }
-    
-    if (tok.start) {
-    
-        const char *old_start = tok.start;
-        const char *old_caret = tok.caret;
-        
-        saved_tok->start = xstrdup (old_start);
-        
-        if (old_caret && old_caret >= old_start) {
-            saved_tok->caret = saved_tok->start + (old_caret - old_start);
-        } else {
-            saved_tok->caret = saved_tok->start;
-        }
-    
-    }
-    
-    return saved_tok;
-
-}
-
-static int emit_aggregate_copy_from_current_rhs_to_addr_reg_now (const char *addr_reg, int offset, int size) {
-
-    struct local_symbol *rhs_sym;
-    char *rhs_name;
-    
-    const char *rhs_start;
-    const char *rhs_caret;
-    
-    unsigned long rhs_line;
-    
-    int rhs_global_index;
-    int rhs_size;
-    
-    int source_size;
-    int source_ready;
-    
-    /*
-     * Only use the aggregate-copy fast path when the destination is
-     * itself an aggregate object.  Pointer members can legally be assigned
-     * an array object, e.g. fp->intBuffer = buffer1; in pdpclib.  The RHS
-     * symbol then has a large array size, but the LHS is only a pointer, so
-     * emitting a fixed-size aggregate copy corrupts the FILE object.
-     */
-    if (size < (DATA_LLONG & 0x1f)) {
-        return 0;
-    }
-    
-    if (tok.kind == TOK_STAR) {
-    
-        struct token *saved_tok = clone_current_token_now ();
-        struct local_symbol *ptr_sym;
-        
-        char *ptr_name;
-        
-        int ptr_global_index;
-        int ptr_depth;
-        int ptr_pointed_size;
-        
-        get_token ();
-        
-        if (tok.kind != TOK_IDENT || !tok.ident) {
-        
-            unget_token (saved_tok);
-            return 0;
-        
-        }
-        
-        ptr_name = xstrdup (tok.ident);
-        ptr_sym = find_local_symbol (ptr_name);
-        ptr_global_index = find_global_symbol (ptr_name);
-        
-        if (!ptr_sym && ptr_global_index < 0) {
-        
-            free (ptr_name);
-            
-            unget_token (saved_tok);
-            return 0;
-        
-        }
-        
-        ptr_depth = ptr_sym ? ptr_sym->pointer_depth : get_global_symbol_pointer_depth (ptr_name);
-        ptr_pointed_size = ptr_sym ? ptr_sym->pointed_size : get_global_symbol_pointed_size (ptr_name);
-        
-        if (!ptr_sym && ptr_global_index >= 0
-            && get_global_symbol_kind (ptr_name) == GLOBAL_SYMBOL_FUNCTION) {
-        
-            const char *call_start = tok.start;
-            const char *call_caret = tok.caret;
-            unsigned long call_line = get_line_number ();
-            
-            get_token ();
-            
-            if (tok.kind != TOK_LPAREN || ptr_depth <= 0
-                || (ptr_depth == 1 && ptr_pointed_size > 0 && ptr_pointed_size < size)) {
-            
-                free (ptr_name);
-                
-                unget_token (saved_tok);
-                return 0;
-            
-            }
-            
-            emit_push_reg_now (addr_reg);
-            emit_call_identifier_to_reg_now (ptr_name, "eax", call_start, call_caret, call_line);
-            emit_pop_reg_now ("edx");
-            
-            if (offset != 0 && state->ofp) {
-            
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                    fprintf (state->ofp, "    add edx, %d\n", offset);
-                } else {
-                    fprintf (state->ofp, "    addl $%d, %%edx\n", offset);
-                }
-            
-            }
-            
-            emit_copy_fixed_size_now (size);
-            
-            free (ptr_name);
-            return 1;
-        
-        }
-        
-        /*
-         * For aggregate initialization from a dereferenced pointer, keep the
-         * full pointed-to object size.  The old code masked pointed_size with
-         * 0x1f as if it were a DATA_* scalar type.  That turns e.g.
-         *
-         *     struct hashtab old_hashtab = *hashtab;
-         *
-         * from a 44-byte copy into a rejected aggregate fast path because
-         * 44 & 0x1f == 12.  The initializer then falls back to scalar code
-         * and copies only the first word, leaving old_hashtab mostly
-         * uninitialized and crashing in rehash().
-         */
-        source_size = ptr_depth > 1 ? (DATA_PTR & 0x1f) : ptr_pointed_size;
-        
-        if (ptr_depth <= 0 || source_size < size) {
-        
-            free (ptr_name);
-            
-            unget_token (saved_tok);
-            return 0;
-        
-        }
-        
-        emit_push_reg_now (addr_reg);
-        
-        if (ptr_sym) {
-        
-            if (ptr_sym->is_static && ptr_sym->static_label) {
-                emit_load_global_to_reg ("eax", ptr_sym->static_label, DATA_PTR);
-            } else {
-                emit_load_local_to_reg ("eax", ptr_sym->offset, DATA_PTR);
-            }
-        
-        } else {
-            emit_load_global_to_reg ("eax", ptr_name, DATA_PTR);
-        }
-        
-        get_token ();
-        
-        if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
-        
-            enum token_kind member_op = tok.kind;
-            char *member;
-            
-            int member_offset = 0;
-            int member_size = DATA_INT & 0x1f;
-            int member_elem_size = DATA_INT & 0x1f;
-            int member_pointer_depth = 0;
-            int member_is_array = 0;
-            int member_incdec = 0;
-            
-            enum token_kind member_incdec_op = TOK_EOF;
-            const char *object_tag_name = ptr_sym ? ptr_sym->pointed_tag_name : 0;
-            
-            int object_size = ptr_sym ? ptr_sym->pointed_size : get_global_symbol_pointed_size (ptr_name);
-            get_token ();
-            
-            if (tok.kind != TOK_IDENT || !tok.ident) {
-            
-                free (ptr_name);
-                
-                unget_token (saved_tok);
-                return 0;
-            
-            }
-            
-            member = xstrdup (tok.ident);
-            get_token ();
-            
-            if (!find_member_info_ex_bounded (member, object_size, object_tag_name,
-                                              &member_offset, &member_size, &member_elem_size,
-                                              &member_pointer_depth, &member_is_array, 0)) {
-            
-                free (member);
-                free (ptr_name);
-                
-                unget_token (saved_tok);
-                return 0;
-            
-            }
-            
-            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-            
-                member_incdec = 1;
-                member_incdec_op = tok.kind;
-                
-                get_token ();
-            
-            }
-            
-            if (member_op != TOK_ARROW || member_pointer_depth <= 0 || member_elem_size < size) {
-            
-                free (member);
-                free (ptr_name);
-                
-                unget_token (saved_tok);
-                return 0;
-            
-            }
-            
-            emit_push_reg_now (addr_reg);
-            
-            if (ptr_sym) {
-            
-                if (ptr_sym->is_static && ptr_sym->static_label) {
-                    emit_load_global_to_reg ("ecx", ptr_sym->static_label, DATA_PTR);
-                } else {
-                    emit_load_local_to_reg ("ecx", ptr_sym->offset, DATA_PTR);
-                }
-            
-            } else {
-                emit_load_global_to_reg ("ecx", ptr_name, DATA_PTR);
-            }
-            
-            if (state->ofp) {
-            
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                
-                    fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ?
-                        "    mov eax, dword [ecx + %d]\n" :
-                        "    mov eax, dword ptr [ecx + %d]\n", member_offset);
-                    
-                    if (member_incdec) {
-                    
-                        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ?
-                            "    %s dword [ecx + %d], %d\n" :
-                            "    %s dword ptr [ecx + %d], %d\n",
-                            member_incdec_op == TOK_INCR ? "add" : "sub",
-                            member_offset, member_elem_size);
-                    
-                    }
-                
-                } else {
-                
-                    fprintf (state->ofp, "    movl %d(%%ecx), %%eax\n", member_offset);
-                    
-                    if (member_incdec) {
-                    
-                        fprintf (state->ofp, "    %sl $%d, %d(%%ecx)\n",
-                            member_incdec_op == TOK_INCR ? "add" : "sub",
-                            member_elem_size, member_offset);
-                    
-                    }
-                
-                }
-            
-            }
-            
-            emit_pop_reg_now ("edx");
-            
-            if (offset != 0 && state->ofp) {
-            
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                    fprintf (state->ofp, "    add edx, %d\n", offset);
-                } else {
-                    fprintf (state->ofp, "    addl $%d, %%edx\n", offset);
-                }
-            
-            }
-            
-            emit_copy_fixed_size_now (size);
-            
-            free (member);
-            free (ptr_name);
-            
-            return 1;
-        
-        }
-        
-        emit_pop_reg_now ("edx");
-        
-        if (offset != 0 && state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                fprintf (state->ofp, "    add edx, %d\n", offset);
-            } else {
-                fprintf (state->ofp, "    addl $%d, %%edx\n", offset);
-            }
-        
-        }
-        
-        emit_copy_fixed_size_now (size);
-        
-        free (ptr_name);
-        return 1;
-    
-    }
-    
-    if (tok.kind == TOK_LPAREN) {
-    
-        struct token *saved_tok = clone_current_token_now ();
-        struct local_symbol *ptr_sym;
-        
-        char *ptr_name;
-        
-        const char *ptr_start;
-        const char *ptr_caret;
-        
-        unsigned long ptr_line;
-        
-        int ptr_global_index;
-        int ptr_depth;
-        
-        const char *ptr_tag_name;
-        
-        int current_object_size;
-        int have_direct_object_pointer;
-        
-        get_token ();
-        
-        if (tok.kind != TOK_STAR) {
-        
-            unget_token (saved_tok);
-            return 0;
-        
-        }
-        
-        get_token ();
-        
-        if (tok.kind != TOK_IDENT || !tok.ident) {
-        
-            unget_token (saved_tok);
-            return 0;
-        
-        }
-        
-        ptr_name = xstrdup (tok.ident);
-        ptr_start = tok.start;
-        ptr_caret = tok.caret;
-        ptr_line = get_line_number ();
-        ptr_sym = find_local_symbol (ptr_name);
-        ptr_global_index = find_global_symbol (ptr_name);
-        
-        if (!ptr_sym && ptr_global_index < 0) {
-        
-            free (ptr_name);
-            
-            unget_token (saved_tok);
-            return 0;
-        
-        }
-        
-        ptr_depth = ptr_sym ? ptr_sym->pointer_depth : get_global_symbol_pointer_depth (ptr_name);
-        ptr_tag_name = ptr_sym ? ptr_sym->pointed_tag_name : 0;
-        
-        current_object_size = ptr_sym ? ptr_sym->pointed_size : get_global_symbol_pointed_size (ptr_name);
-        source_size = current_object_size;
-        
-        if (ptr_tag_name) {
-        
-            struct aggregate_tag_entry *entry = find_aggregate_tag (ptr_tag_name, 0);
-            
-            if (entry) {
-            
-                current_object_size = entry->size;
-                source_size = current_object_size;
-            
-            }
-        
-        }
-        
-        get_token ();
-        
-        if (tok.kind != TOK_RPAREN || ptr_depth <= 0) {
-        
-            free (ptr_name);
-            
-            unget_token (saved_tok);
-            return 0;
-        
-        }
-        
-        get_token ();
-        
-        if (tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
-        
-            free (ptr_name);
-            
-            unget_token (saved_tok);
-            return 0;
-        
-        }
-        
-        emit_push_reg_now (addr_reg);
-        
-        if (ptr_sym) {
-        
-            if (ptr_sym->is_static && ptr_sym->static_label) {
-                emit_load_global_to_reg ("eax", ptr_sym->static_label, DATA_PTR);
-            } else {
-                emit_load_local_to_reg ("eax", ptr_sym->offset, DATA_PTR);
-            }
-        
-        } else {
-            emit_load_global_to_reg ("eax", ptr_name, DATA_PTR);
-        }
-        
-        emit_load_deref_reg_now ("eax", DATA_PTR);
-        have_direct_object_pointer = 1;
-        
-        while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT || tok.kind == TOK_LBRACK) {
-        
-            if (tok.kind == TOK_LBRACK) {
-            
-                emit_parse_postfix_subscript_scaled_address_to_reg_now ("eax", DATA_PTR);
-                
-                current_object_size = DATA_PTR;
-                continue;
-            
-            }
-            
-            {
-            
-                enum token_kind member_op = tok.kind;
-                char *member;
-                
-                int member_offset = 0;
-                int member_size = DATA_INT & 0x1f;
-                int member_elem_size = DATA_INT & 0x1f;
-                int member_pointer_depth = 0;
-                int member_is_array = 0;
-                
-                get_token ();
-                
-                if (tok.kind != TOK_IDENT || !tok.ident) {
-                
-                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret,
-                        "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
-                    
-                    free (ptr_name);
-                    return 0;
-                
-                }
-                
-                member = xstrdup (tok.ident);
-                get_token ();
-                
-                if (!find_member_info_ex_bounded (member, current_object_size, ptr_tag_name,
-                                                  &member_offset, &member_size, &member_elem_size,
-                                                  &member_pointer_depth, &member_is_array, 0)) {
-                
-                    report_line_at (get_filename (), ptr_line, REPORT_ERROR, ptr_start, ptr_caret,
-                        "unknown member '%s'", member);
-                    
-                    free (member);
-                    free (ptr_name);
-                    
-                    return 0;
-                
-                }
-                
-                ptr_tag_name = last_found_member_tag_name;
-                
-                if (member_op == TOK_ARROW) {
-                
-                    if (have_direct_object_pointer) {
-                        have_direct_object_pointer = 0;
-                    } else {
-                        emit_load_deref_reg_now ("eax", DATA_PTR);
-                    }
-                
-                } else {
-                    have_direct_object_pointer = 0;
-                }
-                
-                if (member_offset != 0 && state->ofp) {
-                
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                        fprintf (state->ofp, "    add eax, %d\n", member_offset);
-                    } else {
-                        fprintf (state->ofp, "    addl $%d, %%eax\n", member_offset);
-                    }
-                
-                }
-                
-                current_object_size = member_size;
-                source_size = member_size;
-                
-                free (member);
-            
-            }
-        
-        }
-        
-        if (source_size < size) {
-        
-            free (ptr_name);
-            return 0;
-        
-        }
-        
-        emit_pop_reg_now ("edx");
-        
-        if (offset != 0 && state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                fprintf (state->ofp, "    add edx, %d\n", offset);
-            } else {
-                fprintf (state->ofp, "    addl $%d, %%edx\n", offset);
-            }
-        
-        }
-        
-        emit_copy_fixed_size_now (size);
-        
-        free (ptr_name);
-        return 1;
-    
-    }
-    
-    if (tok.kind != TOK_IDENT) {
-        return 0;
-    }
-    
-    /*
-     * A function-call RHS that returns a struct/union must be parsed by
-     * the normal expression code.  The aggregate-copy fast path is only
-     * for copying an already-existing aggregate object by address.
-     */
-    if (token_identifier_is_function_call_rhs_now ()) {
-        return 0;
-    }
-    
-    if (!rhs_text_is_plain_aggregate_lvalue_now (tok.caret ? tok.caret : tok.start)) {
-        return 0;
-    }
-    
-    rhs_name = xstrdup (tok.ident);
-    rhs_start = tok.start;
-    rhs_caret = tok.caret;
-    rhs_line = get_line_number ();
-
-    rhs_sym = find_local_symbol (rhs_name);
-    rhs_global_index = find_global_symbol (rhs_name);
-    
-    if (!rhs_sym && rhs_global_index < 0) {
-    
-        free (rhs_name);
-        return 0;
-    
-    }
-    
-    rhs_size = rhs_sym ? rhs_sym->size : get_global_symbol_size (rhs_name);
-    
-    {
-    
-        struct token *saved_rhs_tok = clone_current_token_now ();
-        get_token ();
-        
-        if (rhs_size <= (DATA_LLONG & 0x1f) && tok.kind != TOK_DOT && tok.kind != TOK_ARROW && tok.kind != TOK_LBRACK) {
-        
-            free (rhs_name);
-            
-            unget_token (saved_rhs_tok);
-            return 0;
-        
-        }
-        
-        unget_token (saved_rhs_tok);
-    
-    }
-    
-    emit_push_reg_now (addr_reg);
-    get_token ();
-    
-    source_ready = 0;
-    source_size = rhs_size;
-    
-    if (tok.kind == TOK_DOT || tok.kind == TOK_ARROW || tok.kind == TOK_LBRACK) {
-    
-        if (!emit_parse_postfix_copy_source_address_now ("eax", rhs_sym, rhs_name, rhs_start, rhs_caret, rhs_line)) {
-        
-            free (rhs_name);
-            return 0;
-        
-        }
-        
-        source_size = postfix_copy_lvalue_size;
-        source_ready = 1;
-    
-    }
-    
-    if (source_size < size) {
-    
-        free (rhs_name);
-        return 0;
-    
-    }
-    
-    if (!source_ready) {
-        emit_load_symbol_address_for_copy_now ("eax", rhs_sym, rhs_name);
-    }
-    
-    emit_pop_reg_now ("edx");
-    
-    if (offset != 0 && state->ofp) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-            fprintf (state->ofp, "    add edx, %d\n", offset);
-        } else {
-            fprintf (state->ofp, "    addl $%d, %%edx\n", offset);
-        }
-    
-    }
-    
-    emit_copy_fixed_size_now (size);
-    
-    free (rhs_name);
-    return 1;
-
-}
-
-static void emit_load_member_address_for_copy_now (const char *reg, struct local_symbol *sym, const char *name, enum token_kind member_op, int offset) {
-
-    if (sym) {
-    
-        if (member_op == TOK_DOT || sym->is_array) {
-        
-            if (sym->is_static && sym->static_label) {
-                emit_load_address_to_reg_now (reg, sym->static_label);
-            } else {
-                emit_load_local_address_to_reg_now (reg, sym->offset);
-            }
-        
-        } else if (sym->is_static && sym->static_label) {
-            emit_load_global_to_reg (reg, sym->static_label, DATA_PTR);
-        } else {
-            emit_load_local_to_reg (reg, sym->offset, DATA_PTR);
-        }
-    
-    } else {
-    
-        if (member_op == TOK_DOT || get_global_symbol_array (name)) {
-            emit_load_address_to_reg_now (reg, name);
-        } else {
-            emit_load_global_to_reg (reg, name, DATA_PTR);
-        }
-    
-    }
-    
-    if (offset != 0 && state->ofp) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-            fprintf (state->ofp, "    add %s, %d\n", reg, offset);
-        } else {
-            fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
-        }
-    
-    }
-
-}
-
-static int emit_parse_postfix_copy_source_address_now (const char *reg, struct local_symbol *src, const char *src_name, const char *name_start, const char *name_caret, unsigned long name_line) {
-
-    int have_address = 0;
-    int have_direct_object_pointer = 0;
-    int last_elem_size = DATA_INT & 0x1f;
-    int last_lvalue_size = DATA_INT & 0x1f;
-    
-    const char *current_object_tag_name = 0;
-    int current_object_size = 0;
-    
-    postfix_copy_lvalue_size = DATA_INT & 0x1f;
-    
-    if (!reg) {
-        reg = "eax";
-    }
-    
-    if (tok.kind == TOK_LPAREN) {
-    
-        if (src) {
-            return 0;
-        }
-        
-        ensure_global_function_symbol (src_name, name_start, name_caret, name_line);
-        emit_call_identifier_to_reg_now (src_name, reg, name_start, name_caret, name_line);
-        
-        have_address = 1;
-        have_direct_object_pointer = 1;
-    
-    }
-    
-    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-    
-        enum token_kind postfix_op = tok.kind;
-        
-        int pointer_depth;
-        int pointed_size;
-        
-        get_token ();
-        
-        if (tok.kind != TOK_LBRACK) {
-            return 0;
-        }
-        
-        if (src) {
-        
-            pointer_depth = src->pointer_depth;
-            pointed_size = src->pointed_size;
-            
-            if (src->is_static && src->static_label) {
-                emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
-            } else {
-                emit_load_local_to_reg (reg, src->offset, DATA_PTR);
-            }
-        
-        } else if (find_global_symbol (src_name) >= 0) {
-        
-            pointer_depth = get_global_symbol_pointer_depth (src_name);
-            pointed_size = get_global_symbol_pointed_size (src_name);
-            
-            emit_load_global_to_reg (reg, src_name, DATA_PTR);
-        
-        } else {
-        
-            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", src_name);
-            return 0;
-        
-        }
-        
-        if (pointer_depth <= 0) {
-        
-            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "subscripted value is not a pointer");
-            return 0;
-        }
-        
-        last_elem_size = pointer_depth > 1 ? (DATA_PTR & 0x1f) : (pointed_size > 0 ? (pointed_size & 0x1f) : (DATA_INT & 0x1f));
-        last_lvalue_size = last_elem_size;
-        
-        have_address = 1;
-        have_direct_object_pointer = 0;
-        
-        emit_incdec_symbol_now (src, src_name, postfix_op, name_line, name_start, name_caret);
-    
-    }
-    
-    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT || tok.kind == TOK_LBRACK) {
-    
-        if (tok.kind == TOK_LBRACK) {
-        
-            int elem_size = last_elem_size;
-            
-            if (!have_address) {
-            
-                if (src) {
-                
-                    if (src->is_array) {
-                        emit_load_symbol_address_for_copy_now (reg, src, src_name);
-                    } else if (src->is_static && src->static_label) {
-                        emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
-                    } else {
-                        emit_load_local_to_reg (reg, src->offset, DATA_PTR);
-                    }
-                
-                    elem_size = src->is_array ? (src->pointer_depth ? DATA_PTR : (src->array_element_size > 0 ? src->array_element_size : src->pointed_size)) :
-                        (src->pointer_depth > 1 ? DATA_PTR : src->pointed_size);
-                    
-                    if (src->is_array && !src->pointer_depth) {
-                        current_object_tag_name = src->tag_name;
-                    } else if (!src->is_array && src->pointer_depth > 0) {
-                        current_object_tag_name = src->pointed_tag_name;
-                    }
-                
-                } else {
-                
-                    if (get_global_symbol_array (src_name)) {
-                        emit_load_address_to_reg_now (reg, src_name);
-                    } else {
-                        emit_load_global_to_reg (reg, src_name, DATA_PTR);
-                    }
-                    
-                    elem_size = get_global_symbol_array (src_name) ?
-                        (get_global_symbol_pointer_depth (src_name) ? DATA_PTR : (get_global_symbol_array_element_size (src_name) > 0 ? get_global_symbol_array_element_size (src_name) : get_global_symbol_pointed_size (src_name))) :
-                            (get_global_symbol_pointer_depth (src_name) > 1 ? DATA_PTR : get_global_symbol_pointed_size (src_name));
-                    
-                    if (get_global_symbol_array (src_name) && !get_global_symbol_pointer_depth (src_name)) {
-                        current_object_tag_name = get_global_symbol_tag_name (src_name);
-                    } else if (!get_global_symbol_array (src_name) && get_global_symbol_pointer_depth (src_name) > 0) {
-                        current_object_tag_name = get_global_symbol_tag_name (src_name);
-                    }
-                
-                }
-                
-                if (elem_size <= 0) {
-                    elem_size = DATA_INT & 0x1f;
-                }
-                
-                have_address = 1;
-            
-            }
-            
-            emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
-            
-            last_elem_size = elem_size;
-            last_lvalue_size = elem_size;
-            
-            current_object_size = elem_size;
-            continue;
-        
-        }
-        
-        {
-        
-            enum token_kind member_op = tok.kind;
-            char *member;
-            
-            const char *member_start;
-            const char *member_caret;
-            
-            unsigned long member_line;
-            
-            int member_offset = 0;
-            int member_size = DATA_INT & 0x1f;
-            int member_elem_size = DATA_INT & 0x1f;
-            int member_pointer_depth = 0;
-            int member_is_array = 0;
-            
-            get_token ();
-            
-            member_start = tok.start;
-            member_caret = tok.caret;
-            member_line = get_line_number ();
-            
-            if (tok.kind != TOK_IDENT) {
-            
-                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret,
-                    "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
-                
-                return 0;
-            
-            }
-            
-            member = xstrdup (tok.ident);
-            get_token ();
-            
-            if (current_object_size <= 0) {
-            
-                if (src) {
-                
-                    if (member_op == TOK_ARROW && src->pointer_depth > 0) {
-                    
-                        current_object_size = src->pointed_size;
-                        current_object_tag_name = src->pointed_tag_name;
-                    
-                    } else {
-                    
-                        current_object_size = src->size;
-                        current_object_tag_name = src->tag_name;
-                    
-                    }
-                
-                } else {
-                
-                    if (member_op == TOK_ARROW && get_global_symbol_pointer_depth (src_name) > 0) {
-                    
-                        current_object_size = get_global_symbol_pointed_size (src_name);
-                        current_object_tag_name = get_global_symbol_tag_name (src_name);
-                    
-                    } else {
-                    
-                        current_object_size = get_global_symbol_size (src_name);
-                        current_object_tag_name = get_global_symbol_tag_name (src_name);
-                    
-                    }
-                
-                }
-            
-            }
-            
-            if (!find_member_info_ex_bounded (member, current_object_size, current_object_tag_name, &member_offset, &member_size, &member_elem_size, &member_pointer_depth, &member_is_array, 0)) {
-            
-                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret,
-                    "unknown member '%s'", member);
-                
-                free (member);
-                return 0;
-            
-            }
-            
-            {
-            
-                const char *member_tag_name = last_found_member_tag_name;
-                
-                if (member_is_array && member_pointer_depth > 0) {
-                
-                    /*
-                     * For an array member whose element type is a pointer,
-                     * the subscript step is one pointer.  Do not replace it
-                     * with the pointed aggregate size from the member tag.
-                     */
-                    member_elem_size = DATA_PTR;
-                
-                } else if (member_pointer_depth > 1) {
-                    member_elem_size = DATA_PTR;
-                } else if (member_pointer_depth == 1 && member_tag_name) {
-                
-                    struct aggregate_tag_entry *entry = find_aggregate_tag (member_tag_name, 0);
-                    
-                    if (entry) {
-                        member_elem_size = entry->size;
-                    }
-                
-                }
-                
-                current_object_tag_name = member_tag_name;
-            
-            }
-            
-            free (member);
-            
-            if (!have_address) {
-            
-                emit_load_member_address_for_copy_now (reg, src, src_name, member_op, 0);
-                have_address = 1;
-            
-            } else if (member_op == TOK_ARROW) {
-            
-                if (have_direct_object_pointer) {
-                    have_direct_object_pointer = 0;
-                } else {
-                    emit_load_deref_reg_now (reg, DATA_PTR);
-                }
-            
-            } else {
-                have_direct_object_pointer = 0;
-            }
-            
-            if (tok.kind == TOK_LBRACK && member_pointer_depth > 0 && !member_is_array) {
-                emit_load_member_from_addr_reg_now (reg, reg, member_offset, DATA_PTR & 0x1f);
-            } else if (state->ofp && member_offset != 0) {
-            
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                    fprintf (state->ofp, "    add %s, %d\n", reg, member_offset);
-                } else {
-                    fprintf (state->ofp, "    addl $%d, %%%s\n", member_offset, reg);
-                }
-            
-            }
-            
-            last_elem_size = member_elem_size;
-            last_lvalue_size = member_size;
-            
-            if (member_pointer_depth > 0 || member_is_array) {
-                current_object_size = member_elem_size;
-            } else {
-                current_object_size = member_size;
-            }
-        
-        }
-    
-    }
-    
-    postfix_copy_lvalue_size = last_lvalue_size;
-    return have_address;
-
-}
-
-static void emit_load_floating_deref_reg_now (const char *reg, int size) {
-
-    if (!state->ofp) {
-        return;
-    }
-
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-
-        if (size == (DATA_FLOAT & 0x1f)) {
-            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fld dword [%s]\n" : "    fld dword ptr [%s]\n", reg);
-        } else {
-            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fld qword [%s]\n" : "    fld qword ptr [%s]\n", reg);
-        }
-
-    } else {
-
-        if (size == (DATA_FLOAT & 0x1f)) {
-            fprintf (state->ofp, "    flds (%%%s)\n", reg);
-        } else {
-            fprintf (state->ofp, "    fldl (%%%s)\n", reg);
-        }
-
-    }
-
-}
-
-static void emit_add_const_to_reg_now (const char *reg, int offset) {
-
-    if (!state->ofp || !reg || offset == 0) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
-    } else {
-        fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
-    }
-
-}
-
-static void emit_load_floating_member_from_addr_reg_now (const char *reg, int offset, int size) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (size == (DATA_FLOAT & 0x1f)) {
-            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fld dword [%s + %d]\n" : "    fld dword ptr [%s + %d]\n", reg, offset);
-        } else {
-            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fld qword [%s + %d]\n" : "    fld qword ptr [%s + %d]\n", reg, offset);
-        }
-    
-    } else {
-    
-        if (size == (DATA_FLOAT & 0x1f)) {
-            fprintf (state->ofp, "    flds %d(%%%s)\n", offset, reg);
-        } else {
-            fprintf (state->ofp, "    fldl %d(%%%s)\n", offset, reg);
-        }
-    
-    }
-
-}
-
-static void save_parse_type_state_now (
-
-    int *saved_type_size,
-    int *saved_storage_class,
-    int *saved_is_aggregate,
-    int *saved_is_void,
-    int *saved_is_unsigned,
-    int *saved_is_floating,
-    int *saved_has_tag,
-    int *saved_is_inline,
-    int *saved_field_count,
-    int saved_fields[MAX_AGG_FIELDS],
-    int *saved_declarator_is_pointer,
-    int *saved_declarator_pointer_depth,
-    int *saved_declarator_has_array,
-    int *saved_declarator_has_function,
-    int *saved_declarator_array_unsized,
-    int *saved_declarator_array_dimensions,
-    long *saved_declarator_array_count,
-    long *saved_declarator_first_array_count) {
-
-    int i;
-    
-    *saved_type_size = parsed_type_size;
-    *saved_storage_class = parsed_storage_class;
-    *saved_is_aggregate = parsed_type_is_aggregate;
-    *saved_is_void = parsed_type_is_void;
-    *saved_is_unsigned = parsed_type_is_unsigned;
-    *saved_is_floating = parsed_type_is_floating;
-    *saved_has_tag = parsed_type_has_tag;
-    *saved_is_inline = parsed_type_is_inline;
-    *saved_field_count = parsed_field_count;
-    
-    for (i = 0; i < *saved_field_count && i < MAX_AGG_FIELDS; i++) {
-        saved_fields[i] = parsed_field_sizes[i];
-    }
-    
-    *saved_declarator_is_pointer = declarator_is_pointer;
-    *saved_declarator_pointer_depth = declarator_pointer_depth;
-    *saved_declarator_has_array = declarator_has_array;
-    *saved_declarator_has_function = declarator_has_function;
-    *saved_declarator_array_unsized = declarator_array_unsized;
-    *saved_declarator_array_dimensions = declarator_array_dimensions;
-    *saved_declarator_array_count = declarator_array_count;
-    *saved_declarator_first_array_count = declarator_first_array_count;
-
-}
-
-static void restore_parse_type_state_now (
-    int saved_type_size,
-    int saved_storage_class,
-    int saved_is_aggregate,
-    int saved_is_void,
-    int saved_is_unsigned,
-    int saved_is_floating,
-    int saved_has_tag,
-    int saved_is_inline,
-    int saved_field_count,
-    int saved_fields[MAX_AGG_FIELDS],
-    int saved_declarator_is_pointer,
-    int saved_declarator_pointer_depth,
-    int saved_declarator_has_array,
-    int saved_declarator_has_function,
-    int saved_declarator_array_unsized,
-    int saved_declarator_array_dimensions,
-    long saved_declarator_array_count,
-    long saved_declarator_first_array_count) {
-
-    int i;
-    
-    parsed_type_size = saved_type_size;
-    parsed_storage_class = saved_storage_class;
-    parsed_type_is_aggregate = saved_is_aggregate;
-    parsed_type_is_void = saved_is_void;
-    parsed_type_is_unsigned = saved_is_unsigned;
-    parsed_type_is_floating = saved_is_floating;
-    parsed_type_has_tag = saved_has_tag;
-    parsed_type_is_inline = saved_is_inline;
-    
-    clear_parsed_fields ();
-    
-    for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
-        parsed_field_sizes[i] = saved_fields[i];
-    }
-    
-    parsed_field_count = saved_field_count;
-    declarator_is_pointer = saved_declarator_is_pointer;
-    declarator_pointer_depth = saved_declarator_pointer_depth;
-    declarator_has_array = saved_declarator_has_array;
-    declarator_has_function = saved_declarator_has_function;
-    declarator_array_unsized = saved_declarator_array_unsized;
-    declarator_array_dimensions = saved_declarator_array_dimensions;
-    declarator_array_count = saved_declarator_array_count;
-    declarator_first_array_count = saved_declarator_first_array_count;
-
-}
-
-static int parse_builtin_va_arg_type_now (int *out_size, int *out_unsigned, int *out_pointer, int *out_floating) {
-
-    int saved_type_size;
-    int saved_storage_class;
-    int saved_is_aggregate;
-    int saved_is_void;
-    int saved_is_unsigned;
-    int saved_is_floating;
-    int saved_has_tag;
-    int saved_is_inline;
-    int saved_field_count;
-    int saved_fields[MAX_AGG_FIELDS];
-    int saved_declarator_is_pointer;
-    int saved_declarator_pointer_depth;
-    int saved_declarator_has_array;
-    int saved_declarator_has_function;
-    int saved_declarator_array_unsized;
-    int saved_declarator_array_dimensions;
-    
-    long saved_declarator_array_count;
-    long saved_declarator_first_array_count;
-    
-    char *type_name = 0;
-    
-    int base_size;
-    int pointer_depth;
-    int is_unsigned;
-    int is_floating;
-    
-    save_parse_type_state_now (&saved_type_size, &saved_storage_class,
-        &saved_is_aggregate, &saved_is_void, &saved_is_unsigned,
-        &saved_is_floating, &saved_has_tag, &saved_is_inline,
-        &saved_field_count, saved_fields, &saved_declarator_is_pointer,
-        &saved_declarator_pointer_depth, &saved_declarator_has_array,
-        &saved_declarator_has_function, &saved_declarator_array_unsized,
-        &saved_declarator_array_dimensions, &saved_declarator_array_count,
-        &saved_declarator_first_array_count);
-    
-    declarator_is_pointer = 0;
-    declarator_pointer_depth = 0;
-    declarator_has_array = 0;
-    declarator_has_function = 0;
-    declarator_array_unsized = 0;
-    declarator_array_count = 0;
-    declarator_first_array_count = 1;
-    declarator_array_dimensions = 0;
-    
-    parse_type_spec ();
-    base_size = parsed_type_size & 0x1f;
-    
-    is_unsigned = parsed_type_is_unsigned;
-    is_floating = parsed_type_is_floating;
-    
-    if (tok.kind != TOK_RPAREN) {
-        parse_declarator (&type_name);
-    }
-    
-    pointer_depth = declarator_is_pointer ? (declarator_pointer_depth > 0 ? declarator_pointer_depth : 1) : 0;
-    
-    if (type_name) {
-        free (type_name);
-    }
-    
-    if (out_pointer) {
-        *out_pointer = pointer_depth;
-    }
-    
-    if (out_unsigned) {
-        *out_unsigned = is_unsigned;
-    }
-    
-    if (out_floating) {
-        *out_floating = is_floating;
-    }
-    
-    if (out_size) {
-        *out_size = pointer_depth > 0 ? (DATA_PTR & 0x1f) : base_size;
-    }
-    
-    restore_parse_type_state_now (saved_type_size, saved_storage_class,
-        saved_is_aggregate, saved_is_void, saved_is_unsigned,
-        saved_is_floating, saved_has_tag, saved_is_inline,
-        saved_field_count, saved_fields, saved_declarator_is_pointer,
-        saved_declarator_pointer_depth, saved_declarator_has_array,
-        saved_declarator_has_function, saved_declarator_array_unsized,
-        saved_declarator_array_dimensions, saved_declarator_array_count,
-        saved_declarator_first_array_count);
-    
-    return 1;
-
-}
-
-static int emit_parse_builtin_va_arg_address_to_reg_now (const char *reg, int *out_size, int *out_unsigned, int *out_pointer, int *out_floating) {
-
-    char *name;
-    
-    const char *name_start;
-    const char *name_caret;
-    const char *scratch_reg;
-    
-    unsigned long name_line;
-    unsigned long inc;
-    
-    struct local_symbol *src;
-    
-    int global_index;
-    int size = DATA_INT & 0x1f;
-    int is_unsigned = 1;
-    int pointer_depth = 0;
-    int is_floating = 0;
-    int deref_lvalue = 0;
-    int paren_lvalue = 0;
-    
-    if (tok.kind != TOK_LPAREN) {
-        return 0;
-    }
-    
-    get_token ();
-    
-    if (tok.kind == TOK_LPAREN) {
-    
-        paren_lvalue = 1;
-        get_token ();
-    
-    }
-    
-    if (tok.kind == TOK_STAR) {
-    
-        deref_lvalue = 1;
-        get_token ();
-    
-    }
-    
-    name_start = tok.start;
-    name_caret = tok.caret;
-    name_line = get_line_number ();
-    
-    if (tok.kind != TOK_IDENT || !tok.ident) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected va_list object in __scc_builtin_va_arg");
-        return 1;
-    
-    }
-    
-    name = xstrdup (tok.ident);
-    get_token ();
-    
-    if (paren_lvalue) {
-        expect (TOK_RPAREN, ")");
-    }
-    
-    expect (TOK_COMMA, ",");
-    
-    if (!is_type_start (tok.kind)) {
-    
-        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected type name in __scc_builtin_va_arg");
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    parse_builtin_va_arg_type_now (&size, &is_unsigned, &pointer_depth, &is_floating);
-    expect (TOK_RPAREN, ")");
-    
-    if (size <= 0) {
-        size = DATA_INT & 0x1f;
-    }
-    
-    inc = (unsigned long) size;
-    
-    src = find_local_symbol (name);
-    global_index = find_global_symbol (name);
-    
-    if (!src && global_index < 0) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    if (deref_lvalue) {
-    
-        scratch_reg = strcmp (reg, "edx") == 0 ? "ecx" : "edx";
-        
-        if (src) {
-        
-            if (src->is_static && src->static_label) {
-                emit_load_global_to_reg (scratch_reg, src->static_label, DATA_PTR);
-            } else {
-                emit_load_local_to_reg (scratch_reg, src->offset, DATA_PTR);
-            }
-        
-        } else {
-            emit_load_global_to_reg (scratch_reg, name, DATA_PTR);
-        }
-        
-        if (state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-            
-                fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [%s]\n" : "    mov %s, dword ptr [%s]\n", reg, scratch_reg);
-                fprintf (state->ofp, "    push %s\n", reg);
-                fprintf (state->ofp, "    add %s, %lu\n", reg, inc);
-                fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov dword [%s], %s\n" : "    mov dword ptr [%s], %s\n", scratch_reg, reg);
-                fprintf (state->ofp, "    pop %s\n", reg);
-            
-            } else {
-            
-                fprintf (state->ofp, "    movl (%%%s), %%%s\n", scratch_reg, reg);
-                fprintf (state->ofp, "    pushl %%%s\n", reg);
-                fprintf (state->ofp, "    addl $%lu, %%%s\n", inc, reg);
-                fprintf (state->ofp, "    movl %%%s, (%%%s)\n", reg, scratch_reg);
-                fprintf (state->ofp, "    subl $%lu, %%%s\n", inc, reg);
-                fprintf (state->ofp, "    popl %%%s\n", reg);
-            
-            }
-        
-        }
-    
-    } else {
-    
-        if (src) {
-        
-            if (src->is_static && src->static_label) {
-                emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
-            } else {
-                emit_load_local_to_reg (reg, src->offset, DATA_PTR);
-            }
-        
-        } else {
-            emit_load_global_to_reg (reg, name, DATA_PTR);
-        }
-        
-        if (state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-            
-                fprintf (state->ofp, "    push %s\n", reg);
-                fprintf (state->ofp, "    add %s, %lu\n", reg, inc);
-            
-            } else {
-            
-                fprintf (state->ofp, "    pushl %%%s\n", reg);
-                fprintf (state->ofp, "    addl $%lu, %%%s\n", inc, reg);
-            
-            }
-        
-        }
-        
-        if (src) {
-        
-            if (src->is_static && src->static_label) {
-                emit_store_reg_to_global (src->static_label, DATA_PTR, reg);
-            } else {
-                emit_store_reg_to_local (src->offset, DATA_PTR, reg);
-            }
-        
-        } else {
-            emit_store_reg_to_global (name, DATA_PTR, reg);
-        }
-        
-        if (state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                fprintf (state->ofp, "    pop %s\n", reg);
-            } else {
-                fprintf (state->ofp, "    popl %%%s\n", reg);
-            }
-        
-        }
-    
-    }
-    
-    if (out_size) {
-        *out_size = size;
-    }
-    
-    if (out_unsigned) {
-        *out_unsigned = is_unsigned;
-    }
-    
-    if (out_pointer) {
-        *out_pointer = pointer_depth;
-    }
-    
-    if (out_floating) {
-        *out_floating = is_floating;
-    }
-    
-    free (name);
-    return 1;
-
-}
-
-static int emit_load_parenthesized_indirect_member_to_reg_now (const char *reg) {
-
-    const char *p;
-    char *name;
-    
-    const char *name_start;
-    const char *name_caret;
-    
-    unsigned long name_line;
-    struct local_symbol *src;
-    
-    int global_index;
-    int current_object_size;
-    
-    const char *current_tag_name;
-    
-    int first_member;
-    int last_member_size;
-    int last_member_pointer_depth;
-    int last_member_elem_size;
-    
-    if (tok.kind != TOK_STAR || !tok.caret) {
-        return 0;
-    }
-    
-    p = tok.caret + 1;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
-        return 0;
-    }
-    
-    p++;
-    
-    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;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (*p != '.' && !(*p == '-' && p[1] == '>')) {
-        return 0;
-    }
-    
-    get_token ();
-    
-    name_start = tok.start;
-    name_caret = tok.caret;
-    name_line = get_line_number ();
-    
-    if (tok.kind != TOK_IDENT || !tok.ident) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
-        return 1;
-    
-    }
-    
-    name = xstrdup (tok.ident);
-    get_token ();
-    
-    expect (TOK_RPAREN, ")");
-    
-    src = find_local_symbol (name);
-    global_index = find_global_symbol (name);
-    
-    if (src) {
-    
-        if (src->is_static && src->static_label) {
-            emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
-        } else {
-            emit_load_local_to_reg (reg, src->offset, DATA_PTR);
-        }
-        
-        current_object_size = src->pointed_size;
-        current_tag_name = src->pointed_tag_name;
-    
-    } else if (global_index >= 0) {
-    
-        emit_load_global_to_reg (reg, name, DATA_PTR);
-        
-        current_object_size = get_global_symbol_pointed_size (name);
-        current_tag_name = 0;
-    
-    } else {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    free (name);
-    
-    emit_load_deref_reg_now (reg, DATA_PTR);
-    first_member = 1;
-    
-    last_member_size = DATA_INT & 0x1f;
-    last_member_pointer_depth = 0;
-    last_member_elem_size = DATA_INT & 0x1f;
-    
-    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
-    
-        enum token_kind member_op = tok.kind;
-        char *member;
-        
-        const char *member_start;
-        const char *member_caret;
-        
-        unsigned long member_line;
-        
-        int member_offset = 0;
-        int member_size = DATA_INT & 0x1f;
-        int member_elem_size = DATA_INT & 0x1f;
-        int member_pointer_depth = 0;
-        int member_is_array = 0;
-        
-        get_token ();
-        
-        member_start = tok.start;
-        member_caret = tok.caret;
-        member_line = get_line_number ();
-        
-        if (tok.kind != TOK_IDENT || !tok.ident) {
-        
-            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
-            return 1;
-        
-        }
-        
-        member = xstrdup (tok.ident);
-        get_token ();
-        
-        if (!find_member_info_ex_bounded (member, current_object_size, current_tag_name, &member_offset, &member_size, &member_elem_size, &member_pointer_depth, &member_is_array, 0)) {
-        
-            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
-            
-            free (member);
-            return 1;
-        
-        }
-        
-        free (member);
-        
-        if (!first_member && member_op == TOK_ARROW) {
-            emit_load_deref_reg_now (reg, DATA_PTR);
-        }
-        
-        if (member_offset != 0 && state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                fprintf (state->ofp, "    add %s, %d\n", reg, member_offset);
-            } else {
-                fprintf (state->ofp, "    addl $%d, %%%s\n", member_offset, reg);
-            }
-        
-        }
-        
-        current_object_size = member_size;
-        current_tag_name = last_found_member_tag_name;
-        
-        last_member_size = member_size;
-        last_member_pointer_depth = member_pointer_depth;
-        last_member_elem_size = member_elem_size;
-        
-        first_member = 0;
-    
-    }
-    
-    emit_load_deref_reg_now (reg, last_member_size);
-    
-    if (last_member_pointer_depth > 0) {
-        set_rhs_last_pointer_info (last_member_pointer_depth, last_member_elem_size);
-    } else {
-        clear_rhs_last_pointer_info ();
-    }
-    
-    return 1;
-
-}
-
-static int source_starts_parenthesized_deref_postfix_incdec_subscript_at (const char *p) {
-
-    if (!p || *p != '*') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
-        return 0;
-    }
-    
-    p++;
-    
-    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;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (!((p[0] == '+' && p[1] == '+') || (p[0] == '-' && p[1] == '-'))) {
-        return 0;
-    }
-    
-    p += 2;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    return 1;
-
-}
-
-static int source_starts_lparen_deref_subscript_at (const char *p) {
-
-    if (!p || *p != '(') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (*p != '*') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
-        return 0;
-    }
-    
-    p++;
-    
-    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;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    return *p == '[';
-
-}
-
-static int source_starts_lparen_deref_postfix_incdec_at (const char *p) {
-
-    if (!p) {
-        return 0;
-    }
-    
-    /*
-     * Most callers pass the caret at the opening parenthesis, but some
-     * token paths leave it just after the '('.  Accept both positions so
-     * a statement such as:
-     *
-     *     (*parameter_count)++;
-     *
-     * is always routed through the dereferenced-object inc/dec emitter, not
-     * the ordinary pointer-variable inc/dec path.  The latter scales by the
-     * pointed-to size and would emit addl $4 for int *, corrupting counts.
-     */
-    if (*p == '(') {
-        p++;
-    }
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (*p != '*') {
-        return 0;
-    }
-    
-    return source_starts_parenthesized_deref_postfix_incdec_subscript_at (p);
-
-}
-
-static int emit_load_parenthesized_deref_postfix_incdec_subscript_to_reg_now (const char *reg) {
-
-    enum token_kind op;
-    char *name;
-    
-    const char *name_start;
-    const char *name_caret;
-    
-    unsigned long name_line;
-    struct local_symbol *src;
-    
-    int global_index;
-    int pointer_depth = 0;
-    int pointed_size = DATA_INT & 0x1f;
-    int elem_size = DATA_INT & 0x1f;
-    int lvalue_size = DATA_INT & 0x1f;
-    int step = 1;
-    
-    const char *addr_reg;
-    
-    if (tok.kind != TOK_STAR) {
-        return 0;
-    }
-    
-    if (!source_starts_parenthesized_deref_postfix_incdec_subscript_at (tok.caret)) {
-        return 0;
-    }
-    
-    get_token ();
-    
-    name_start = tok.start;
-    name_caret = tok.caret;
-    name_line = get_line_number ();
-    
-    if (tok.kind != TOK_IDENT || !tok.ident) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
-        return 1;
-    
-    }
-    
-    name = xstrdup (tok.ident);
-    get_token ();
-    
-    if (tok.kind != TOK_RPAREN) {
-    
-        free (name);
-        return 0;
-    
-    }
-    
-    get_token ();
-    
-    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
-    
-        free (name);
-        return 0;
-    
-    }
-    
-    op = tok.kind;
-    get_token ();
-    
-    src = find_local_symbol (name);
-    global_index = find_global_symbol (name);
-    
-    if (src) {
-    
-        pointer_depth = src->pointer_depth;
-        pointed_size = src->pointed_size;
-    
-    } else if (global_index >= 0) {
-    
-        pointer_depth = get_global_symbol_pointer_depth (name);
-        pointed_size = get_global_symbol_pointed_size (name);
-    
-    } else {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    if (pointer_depth <= 0) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid indirection of non-pointer '%s'", name);
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    if (pointed_size <= 0) {
-        pointed_size = DATA_INT & 0x1f;
-    }
-    
-    if (pointer_depth > 1) {
-    
-        lvalue_size = DATA_PTR & 0x1f;
-        
-        elem_size = (pointer_depth > 2) ? (DATA_PTR & 0x1f) : index_step_size (pointed_size);
-        step = elem_size;
-    
-    } else {
-    
-        lvalue_size = pointed_size & 0x1f;
-        
-        elem_size = pointed_size & 0x1f;
-        step = 1;
-    
-    }
-    
-    if (!reg) {
-        reg = "eax";
-    }
-    
-    addr_reg = (strcmp (reg, "edx") == 0) ? "ecx" : "edx";
-    
-    if (src) {
-    
-        if (src->is_static && src->static_label) {
-            emit_load_global_to_reg (addr_reg, src->static_label, DATA_PTR);
-        } else {
-            emit_load_local_to_reg (addr_reg, src->offset, DATA_PTR);
-        }
-    
-    } else {
-        emit_load_global_to_reg (addr_reg, name, DATA_PTR);
-    }
-    
-    emit_load_member_from_addr_reg_now (reg, addr_reg, 0, lvalue_size);
-    emit_push_reg_now (reg);
-    
-    if (state->ofp) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-            fprintf (state->ofp, op == TOK_INCR ? "    add %s, %d\n" : "    sub %s, %d\n", reg, step);
-        } else {
-            fprintf (state->ofp, op == TOK_INCR ? "    addl $%d, %%%s\n" : "    subl $%d, %%%s\n", step, reg);
-        }
-    
-    }
-    
-    emit_store_reg_to_deref_reg_now (addr_reg, reg, lvalue_size);
-    emit_pop_reg_now (reg);
-    
-    if (tok.kind == TOK_LBRACK) {
-        emit_parse_postfix_subscripts_to_reg_now (reg, elem_size, pointer_depth - 1, pointed_size);
-    }
-    
-    if (pointer_depth > 1) {
-        set_rhs_last_pointer_info (pointer_depth - 1, pointed_size);
-    } else {
-        clear_rhs_last_pointer_info ();
-    }
-    
-    free (name);
-    return 1;
-
-}
-
-static int source_starts_deref_parenthesized_deref_postfix_incdec_assignment_at (const char *p) {
-
-    if (!p) {
-        return 0;
-    }
-    
-    if (*p == '*') {
-        p++;
-    }
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (*p != '(') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (*p != '*') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
-        return 0;
-    }
-    
-    p++;
-    
-    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;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (!((p[0] == '+' && p[1] == '+') || (p[0] == '-' && p[1] == '-'))) {
-        return 0;
-    }
-    
-    p += 2;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    return *p == '=';
-
-}
-
-static int source_starts_deref_parenthesized_deref_postfix_incdec_value_at (const char *p) {
-
-    if (!p || *p != '*') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (*p != '(') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (*p != '(') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (*p != '*') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
-        return 0;
-    }
-    
-    p++;
-    
-    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;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (!((p[0] == '+' && p[1] == '+') || (p[0] == '-' && p[1] == '-'))) {
-        return 0;
-    }
-    
-    p += 2;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    return *p == ')';
-
-}
-
-static int emit_load_deref_parenthesized_deref_postfix_incdec_to_reg_now (const char *reg) {
-
-    enum token_kind op;
-    char *name;
-    
-    const char *name_start;
-    const char *name_caret;
-    
-    unsigned long name_line;
-    struct local_symbol *src;
-    
-    int global_index;
-    int pointer_depth = 0;
-    int pointed_size = DATA_INT & 0x1f;
-    int deref_size = DATA_INT & 0x1f;
-    int step = DATA_PTR & 0x1f;
-    
-    if (tok.kind != TOK_STAR) {
-        return 0;
-    }
-    
-    if (!source_starts_deref_parenthesized_deref_postfix_incdec_value_at (tok.caret)) {
-        return 0;
-    }
-    
-    expect (TOK_STAR, "*");
-    expect (TOK_LPAREN, "(");
-    expect (TOK_LPAREN, "(");
-    expect (TOK_STAR, "*");
-    
-    name_start = tok.start;
-    name_caret = tok.caret;
-    name_line = get_line_number ();
-    
-    if (tok.kind != TOK_IDENT || !tok.ident) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
-        return 1;
-    
-    }
-    
-    name = xstrdup (tok.ident);
-    get_token ();
-    
-    expect (TOK_RPAREN, ")");
-    
-    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
-    
-        free (name);
-        return 0;
-    
-    }
-    
-    op = tok.kind;
-    get_token ();
-    
-    expect (TOK_RPAREN, ")");
-    
-    src = find_local_symbol (name);
-    global_index = find_global_symbol (name);
-    
-    if (src) {
-    
-        pointer_depth = src->pointer_depth;
-        pointed_size = src->pointed_size;
-    
-    } else if (global_index >= 0) {
-    
-        pointer_depth = get_global_symbol_pointer_depth (name);
-        pointed_size = get_global_symbol_pointed_size (name);
-    
-    } else {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    if (pointer_depth <= 0) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid indirection of non-pointer '%s'", name);
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    if (pointed_size <= 0) {
-        pointed_size = DATA_INT & 0x1f;
-    }
-    
-    deref_size = pointer_depth > 1 ? (pointed_size & 0x1f) : (DATA_INT & 0x1f);
-    step = pointer_depth > 2 ? (DATA_PTR & 0x1f) : index_step_size (pointed_size);
-    
-    if (deref_size <= 0) {
-        deref_size = DATA_INT & 0x1f;
-    }
-    
-    if (step <= 0) {
-        step = DATA_PTR & 0x1f;
-    }
-    
-    if (!reg) {
-        reg = "eax";
-    }
-    
-    if (src) {
-    
-        if (src->is_static && src->static_label) {
-            emit_load_global_to_reg ("ecx", src->static_label, DATA_PTR);
-        } else {
-            emit_load_local_to_reg ("ecx", src->offset, DATA_PTR);
-        }
-    
-    } else {
-        emit_load_global_to_reg ("ecx", name, DATA_PTR);
-    }
-    
-    emit_load_member_from_addr_reg_now (reg, "ecx", 0, DATA_PTR & 0x1f);
-    emit_push_reg_now (reg);
-    
-    if (state->ofp) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-            fprintf (state->ofp, op == TOK_INCR ? "    add %s, %d\n" : "    sub %s, %d\n", reg, step);
-        } else {
-            fprintf (state->ofp, op == TOK_INCR ? "    addl $%d, %%%s\n" : "    subl $%d, %%%s\n", step, reg);
-        }
-    
-    }
-    
-    emit_store_reg_to_deref_reg_now ("ecx", reg, DATA_PTR & 0x1f);
-    emit_pop_reg_now (reg);
-    emit_load_deref_reg_now (reg, deref_size);
-    
-    if (pointer_depth > 2) {
-        set_rhs_last_pointer_info (pointer_depth - 2, pointed_size);
-    } else {
-        clear_rhs_last_pointer_info ();
-    }
-    
-    free (name);
-    return 1;
-
-}
-
-static int emit_store_to_deref_parenthesized_deref_postfix_incdec_now (const char *reg) {
-
-    enum token_kind op;
-    char *name;
-    
-    const char *name_start;
-    const char *name_caret;
-    
-    unsigned long name_line;
-    struct local_symbol *src;
-    
-    int global_index;
-    int pointer_depth = 0;
-    int pointed_size = DATA_INT & 0x1f;
-    int store_size = DATA_INT & 0x1f;
-    int step = DATA_PTR & 0x1f;
-    
-    if (tok.kind != TOK_STAR) {
-        return 0;
-    }
-    
-    if (!source_starts_deref_parenthesized_deref_postfix_incdec_assignment_at (tok.caret)) {
-        return 0;
-    }
-    
-    get_token ();
-    
-    expect (TOK_LPAREN, "(");
-    expect (TOK_STAR, "*");
-    
-    name_start = tok.start;
-    name_caret = tok.caret;
-    name_line = get_line_number ();
-    
-    if (tok.kind != TOK_IDENT || !tok.ident) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
-        return 1;
-    
-    }
-    
-    name = xstrdup (tok.ident);
-    get_token ();
-    
-    expect (TOK_RPAREN, ")");
-    
-    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
-    
-        free (name);
-        return 0;
-    
-    }
-    
-    op = tok.kind;
-    get_token ();
-    
-    expect (TOK_ASSIGN, "=");
-    
-    src = find_local_symbol (name);
-    global_index = find_global_symbol (name);
-    
-    if (src) {
-    
-        pointer_depth = src->pointer_depth;
-        pointed_size = src->pointed_size;
-    
-    } else if (global_index >= 0) {
-    
-        pointer_depth = get_global_symbol_pointer_depth (name);
-        pointed_size = get_global_symbol_pointed_size (name);
-    
-    } else {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    if (pointer_depth <= 0) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid indirection of non-pointer '%s'", name);
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    if (pointed_size <= 0) {
-        pointed_size = DATA_INT & 0x1f;
-    }
-    
-    store_size = pointed_size & 0x1f;
-    step = pointed_size & 0x1f;
-    
-    if (step <= 0) {
-        step = DATA_PTR & 0x1f;
-    }
-    
-    if (!reg) {
-        reg = "eax";
-    }
-    
-    if (src) {
-    
-        if (src->is_static && src->static_label) {
-            emit_load_global_to_reg ("ecx", src->static_label, DATA_PTR);
-        } else {
-            emit_load_local_to_reg ("ecx", src->offset, DATA_PTR);
-        }
-    
-    } else {
-        emit_load_global_to_reg ("ecx", name, DATA_PTR);
-    }
-    
-    emit_load_member_from_addr_reg_now ("edx", "ecx", 0, DATA_PTR & 0x1f);
-    emit_push_reg_now ("edx");
-    
-    if (state->ofp) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-            fprintf (state->ofp, op == TOK_INCR ? "    add edx, %d\n" : "    sub edx, %d\n", step);
-        } else {
-            fprintf (state->ofp, op == TOK_INCR ? "    addl $%d, %%edx\n" : "    subl $%d, %%edx\n", step);
-        }
-    
-    }
-    
-    emit_store_reg_to_deref_reg_now ("ecx", "edx", DATA_PTR & 0x1f);
-    
-    emit_load_assignment_rhs_expression_to_reg (reg);
-    emit_pop_reg_now ("edx");
-    emit_store_reg_to_deref_reg_now ("edx", reg, store_size);
-    
-    free (name);
-    return 1;
-
-}
-
-static void emit_scale_reg_by_const_now (const char *reg, int scale);
-
-static int source_starts_deref_assignment_at_now (const char *p) {
-
-    if (!p || *p != '*') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
-        return 0;
-    }
-    
-    p++;
-    
-    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[1] != '=') {
-        return 1;
-    }
-    
-    if ((p[0] == '+' || p[0] == '-' || p[0] == '*' || p[0] == '/' ||
-         p[0] == '%' || p[0] == '&' || p[0] == '^' || p[0] == '|') &&
-        p[1] == '=') {
-        return 1;
-    }
-    
-    if ((p[0] == '<' && p[1] == '<' && p[2] == '=') ||
-        (p[0] == '>' && p[1] == '>' && p[2] == '=')) {
-        return 1;
-    }
-    
-    return 0;
-
-}
-
-static int emit_load_deref_assignment_expression_to_reg_now (const char *reg) {
-
-    char *name;
-    
-    const char *name_start;
-    const char *name_caret;
-    
-    unsigned long name_line;
-    
-    struct local_symbol *sym;
-    int global_index;
-    
-    enum token_kind op;
-    
-    int pointer_depth = 0;
-    int pointed_size = DATA_INT & 0x1f;
-    int value_pointer_depth = 0;
-    int store_size = DATA_INT & 0x1f;
-    
-    if (tok.kind != TOK_STAR) {
-        return 0;
-    }
-    
-    if (!source_starts_deref_assignment_at_now (tok.caret)) {
-        return 0;
-    }
-    
-    get_token ();
-    
-    name_start = tok.start;
-    name_caret = tok.caret;
-    name_line = get_line_number ();
-    
-    if (tok.kind != TOK_IDENT || !tok.ident) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
-        return 1;
-    
-    }
-    
-    name = xstrdup (tok.ident);
-    get_token ();
-    
-    if (!is_assignment_operator (tok.kind)) {
-    
-        free (name);
-        return 0;
-    
-    }
-    
-    op = tok.kind;
-    get_token ();
-    
-    sym = find_local_symbol (name);
-    global_index = find_global_symbol (name);
-    
-    if (sym) {
-    
-        pointer_depth = sym->pointer_depth;
-        pointed_size = sym->pointed_size;
-        
-        if (sym->is_static && sym->static_label) {
-            emit_load_global_to_reg ("ecx", sym->static_label, DATA_PTR);
-        } else {
-            emit_load_local_to_reg ("ecx", sym->offset, DATA_PTR);
-        }
-    
-    } else if (global_index >= 0) {
-    
-        pointer_depth = get_global_symbol_pointer_depth (name);
-        pointed_size = get_global_symbol_pointed_size (name);
-        
-        emit_load_global_to_reg ("ecx", name, DATA_PTR);
-    
-    } else {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    if (pointer_depth <= 0) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid indirection of non-pointer '%s'", name);
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    value_pointer_depth = pointer_depth - 1;
-    
-    if (value_pointer_depth > 0) {
-        store_size = DATA_PTR & 0x1f;
-    } else if (pointed_size > 0) {
-        store_size = pointed_size & 0x1f;
-    }
-    
-    if (store_size <= 0) {
-        store_size = DATA_INT & 0x1f;
-    }
-    
-    emit_push_reg_now ("ecx");
-    
-    if (op == TOK_ASSIGN) {
-        emit_load_assignment_rhs_expression_to_reg ("eax");
-    } else {
-    
-        emit_load_deref_reg_now ("ecx", store_size);
-        
-        emit_push_reg_now ("ecx");
-        emit_load_assignment_rhs_expression_to_reg ("edx");
-        
-        emit_pop_reg_now ("eax");
-        
-        if ((op == TOK_PLUSEQ || op == TOK_MINUSEQ) && value_pointer_depth > 0 &&
-            index_step_size (pointed_size) > 1) {
-            emit_scale_reg_by_const_now ("edx", index_step_size (pointed_size));
-        }
-        
-        emit_assignment_binary_op (op, 0);
-    
-    }
-    
-    emit_pop_reg_now ("ecx");
-    emit_store_reg_to_deref_reg_now ("ecx", "eax", store_size);
-    
-    if (reg && strcmp (reg, "eax") != 0 && state->ofp) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-            fprintf (state->ofp, "    mov %s, eax\n", reg);
-        } else {
-            fprintf (state->ofp, "    movl %%eax, %%%s\n", reg);
-        }
-    
-    }
-    
-    expect (TOK_RPAREN, ")");
-    
-    if (value_pointer_depth > 0) {
-        set_rhs_last_pointer_info (value_pointer_depth, pointed_size);
-    } else {
-        clear_rhs_last_pointer_info ();
-    }
-    
-    free (name);
-    return 1;
-
-}
-
-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 ();
-        
-        if (emit_load_parenthesized_deref_postfix_incdec_subscript_to_reg_now (reg)) {
-            return;
-        }
-    
-    }
-    
-    /*
-     * Do not special-case parenthesized assignment expressions here.
-     *
-     * The normal parenthesized-expression path below already recurses back
-     * into emit_load_assignment_rhs_expression_to_reg(), and the identifier
-     * operand parser below already _accepts assignment operators.  Using the
-     * old source-text detector here was wrong for nested grouping such as:
-     *
-     *     ((((reta <<= 1)) & 0x10))
-     *
-     * because it greedily treated all leading '(' tokens as belonging to the
-     * assignment expression, including parentheses that actually enclose the
-     * later binary '&' expression.
-     */
-    if (_accept (TOK_LPAREN)) {
-    
-        char *paren_call_name = 0;
-        
-        const char *paren_call_start = 0;
-        const char *paren_call_caret = 0;
-        
-        unsigned long paren_call_line = 0;
-        
-        if (emit_load_deref_assignment_expression_to_reg_now (reg)) {
-            return;
-        }
-        
-        /*
-         * Function pointer call designator: (*fp)(args).
-         *
-         * If this is left to the normal parenthesized-expression path, the
-         * inner unary * path treats *fp as a data dereference and emits:
-         *
-         *     movl off(%ebp), %eax
-         *     movl (%eax), %eax
-         *
-         * That is correct for reading *p as an object, but wrong for a
-         * function designator.  In a call, the value of fp is already the
-         * target address, so load fp and call through it without the extra
-         * data load.  Keep this narrow: only handle the exact token form
-         * (*identifier)(...), and let every other parenthesized expression use
-         * the existing parser.
-         */
-        if (tok.kind == TOK_STAR && tok.caret) {
-        
-            const char *p = tok.caret + 1;
-            const char *name_start;
-            const char *name_caret;
-            
-            unsigned long name_line;
-            char *name;
-            
-            struct local_symbol *src;
-            
-            int global_index;
-            int looks_like_call = 0;
-            
-            if (emit_load_parenthesized_deref_postfix_incdec_subscript_to_reg_now (reg)) {
-                return;
-            }
-            
-            while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-                p++;
-            }
-            
-            if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_') {
-            
-                p++;
-                
-                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++;
-                    
-                    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-                        p++;
-                    }
-                    
-                    looks_like_call = (*p == '(');
-                
-                }
-            
-            }
-            
-            if (looks_like_call) {
-            
-                get_token ();
-                
-                name_start = tok.start;
-                name_caret = tok.caret;
-                name_line = get_line_number ();
-                
-                if (tok.kind != TOK_IDENT || !tok.ident) {
-                
-                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
-                    return;
-                
-                }
-                
-                name = xstrdup (tok.ident);
-                get_token ();
-                
-                expect (TOK_RPAREN, ")");
-                
-                src = find_local_symbol (name);
-                global_index = find_global_symbol (name);
-                
-                if (src) {
-                
-                    if (src->is_static && src->static_label) {
-                        emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
-                    } else {
-                        emit_load_local_to_reg (reg, src->offset, DATA_PTR);
-                    }
-                
-                } else if (global_index >= 0) {
-                    emit_load_global_to_reg (reg, name, DATA_PTR);
-                } else {
-                
-                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-                    
-                    free (name);
-                    return;
-                
-                }
-                
-                free (name);
-                
-                emit_call_pointer_in_reg_now (reg, reg);
-                clear_rhs_last_pointer_info ();
-                
-                return;
-            
-            }
-        
-        }
-        
-        if (emit_load_parenthesized_indirect_member_to_reg_now (reg)) {
-            return;
-        }
-        
-        if (tok.kind == TOK_IDENT && tok.ident &&
-        
-            find_global_symbol (tok.ident) >= 0 &&
-            get_global_symbol_kind (tok.ident) == GLOBAL_SYMBOL_FUNCTION) {
-        
-            paren_call_name = xstrdup (tok.ident);
-            paren_call_start = tok.start;
-            paren_call_caret = tok.caret;
-            paren_call_line = get_line_number ();
-        
-        }
-        
-        if (!is_type_start (tok.kind) && parenthesized_function_designator_call_now ()) {
-        
-            char *call_name = xstrdup (tok.ident);
-            
-            const char *call_start = tok.start;
-            const char *call_caret = tok.caret;
-            
-            unsigned long call_line = get_line_number ();
-            get_token ();
-            
-            expect (TOK_RPAREN, ")");
-            
-            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, reg, call_start, call_caret, call_line);
-            free (call_name);
-            
-            return;
-        
-        }
-        
-        if (is_type_start (tok.kind)) {
-        
-            int saved_type_size = parsed_type_size;
-            int saved_storage_class = parsed_storage_class;
-            int saved_is_aggregate = parsed_type_is_aggregate;
-            int saved_is_void = parsed_type_is_void;
-            int saved_is_unsigned = parsed_type_is_unsigned;
-            int saved_is_floating = parsed_type_is_floating;
-            int saved_has_tag = parsed_type_has_tag;
-            int saved_is_inline = parsed_type_is_inline;
-            int saved_field_count = parsed_field_count;
-            int saved_fields[MAX_AGG_FIELDS];
-            int saved_declarator_is_pointer = declarator_is_pointer;
-            int saved_declarator_pointer_depth = declarator_pointer_depth;
-            int saved_declarator_has_array = declarator_has_array;
-            int saved_declarator_has_function = declarator_has_function;
-            int saved_declarator_array_unsized = declarator_array_unsized;
-            int saved_declarator_array_dimensions = declarator_array_dimensions;
-            
-            long saved_declarator_array_count = declarator_array_count;
-            long saved_declarator_first_array_count = declarator_first_array_count;
-            
-            char *cast_name = 0;
-            
-            int cast_base_size;
-            int cast_is_unsigned = 0;
-            int cast_pointer_depth = 0;
-            int cast_pointed_size = 0;
-            
-            int i;
-            
-            for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
-                saved_fields[i] = parsed_field_sizes[i];
-            }
-            
-            declarator_is_pointer = 0;
-            declarator_pointer_depth = 0;
-            declarator_has_array = 0;
-            declarator_has_function = 0;
-            declarator_array_unsized = 0;
-            declarator_array_count = 0;
-            declarator_first_array_count = 1;
-            
-            parse_type_spec ();
-            
-            cast_base_size = parsed_type_size & 0x1f;
-            cast_is_unsigned = parsed_type_is_unsigned;
-            
-            if (tok.kind != TOK_RPAREN) {
-                parse_declarator (&cast_name);
-            }
-            
-            if (declarator_is_pointer) {
-            
-                cast_pointer_depth = declarator_pointer_depth > 0 ? declarator_pointer_depth : 1;
-                cast_pointed_size = cast_pointer_depth > 1 ? (DATA_PTR & 0x1f) : cast_base_size;
-                
-                if (cast_pointed_size <= 0) {
-                    cast_pointed_size = DATA_INT & 0x1f;
-                }
-            
-            }
-            
-            if (cast_name) {
-                free (cast_name);
-            }
-            
-            expect (TOK_RPAREN, ")");
-            
-            parsed_type_size = saved_type_size;
-            parsed_storage_class = saved_storage_class;
-            parsed_type_is_aggregate = saved_is_aggregate;
-            parsed_type_is_void = saved_is_void;
-            parsed_type_is_unsigned = saved_is_unsigned;
-            parsed_type_is_floating = saved_is_floating;
-            parsed_type_has_tag = saved_has_tag;
-            parsed_type_is_inline = saved_is_inline;
-            
-            clear_parsed_fields ();
-            
-            for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
-                parsed_field_sizes[i] = saved_fields[i];
-            }
-            
-            parsed_field_count = saved_field_count;
-            
-            declarator_is_pointer = saved_declarator_is_pointer;
-            declarator_pointer_depth = saved_declarator_pointer_depth;
-            declarator_has_array = saved_declarator_has_array;
-            declarator_has_function = saved_declarator_has_function;
-            declarator_array_unsized = saved_declarator_array_unsized;
-            declarator_array_count = saved_declarator_array_count;
-            declarator_first_array_count = saved_declarator_first_array_count;
-            declarator_array_dimensions = saved_declarator_array_dimensions;
-            
-            emit_load_assignment_rhs_to_reg (reg);
-            
-            while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
-                emit_apply_postfix_member_access_to_reg_now (reg);
-            }
-            
-            if (tok.kind == TOK_LBRACK) {
-            
-                int cast_subscript_elem_size = cast_pointer_depth > 1 ? (DATA_PTR & 0x1f) : cast_pointed_size;
-                
-                if (cast_subscript_elem_size <= 0) {
-                    cast_subscript_elem_size = DATA_INT & 0x1f;
-                }
-                
-                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, cast_subscript_elem_size);
-                emit_load_deref_reg_now (reg, cast_subscript_elem_size);
-            
-            }
-            
-            if (cast_pointer_depth > 0) {
-                set_rhs_last_pointer_info (cast_pointer_depth, cast_pointed_size);
-            } else {
-            
-                emit_apply_integer_cast_to_reg_now (reg, cast_base_size, cast_is_unsigned);
-                clear_rhs_last_pointer_info ();
-            
-            }
-            
-            return;
-        
-        }
-        
-        if (tok.kind != TOK_LPAREN && current_integer_expr_is_foldable_now ()) {
-        
-            int64_s v = const64_from_current_foldable_expr ();
-            expect (TOK_RPAREN, ")");
-            
-            emit_load_const32_to_reg_now (reg, v);
-            return;
-        
-        }
-        
-        emit_load_assignment_rhs_expression_to_reg (reg);
-        
-        if (postfix_member_seen && (tok.kind == TOK_INCR || tok.kind == TOK_DECR)) {
-        
-            enum token_kind postfix_op = tok.kind;
-            get_token ();
-            emit_apply_postfix_member_incdec_now (reg, postfix_op);
-        
-        }
-        
-        while (tok.kind == TOK_COMMA) {
-        
-            get_token ();
-            emit_load_assignment_rhs_expression_to_reg (reg);
-        
-        }
-        
-        if (is_assignment_operator (tok.kind)) {
-        
-            get_token ();
-            emit_load_assignment_rhs_expression_to_reg (reg);
-        
-        }
-        
-        if (paren_call_name && tok.kind == TOK_RPAREN) {
-        
-            get_token ();
-            
-            if (tok.kind == TOK_LPAREN) {
-            
-                if (!find_local_symbol (paren_call_name)) {
-                    ensure_global_function_symbol (paren_call_name, paren_call_start, paren_call_caret, paren_call_line);
-                }
-                
-                emit_call_identifier_to_reg_now (paren_call_name, reg, paren_call_start, paren_call_caret, paren_call_line);
-                free (paren_call_name);
-                
-                return;
-            
-            }
-        
-        } else {
-            expect (TOK_RPAREN, ")");
-        }
-        
-        if (paren_call_name) {
-            free (paren_call_name);
-        }
-        
-        if (tok.kind == TOK_LBRACK) {
-        
-            int subscript_pointer_depth = rhs_last_pointer_depth;
-            int subscript_elem_size = rhs_last_pointed_size;
-            
-            if (subscript_elem_size <= 0) {
-                subscript_elem_size = DATA_INT & 0x1f;
-            }
-            
-            emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, subscript_elem_size);
-            
-            if (is_assignment_operator (tok.kind)) {
-            
-                enum token_kind assign_op = tok.kind;
-                
-                get_token ();
-                emit_push_reg_now (reg);
-                
-                if (assign_op == TOK_ASSIGN && subscript_elem_size > (DATA_LLONG & 0x1f) &&
-                    tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now ()) {
-                
-                    char *rhs_name = xstrdup (tok.ident);
-                    
-                    const char *rhs_start = tok.start;
-                    const char *rhs_caret = tok.caret;
-                    
-                    unsigned long rhs_line = get_line_number ();
-                    
-                    pending_struct_return_lhs = 0;
-                    pending_struct_return_global_name = 0;
-                    pending_struct_return_stack_address = 1;
-                    pending_struct_return_stack_offset = 0;
-                    
-                    get_token ();
-                    emit_call_identifier_to_reg_now (rhs_name, reg, rhs_start, rhs_caret, rhs_line);
-                    
-                    pending_struct_return_stack_address = 0;
-                    pending_struct_return_stack_offset = 0;
-                    
-                    emit_pop_reg_now ("edx");
-                    free (rhs_name);
-                    
-                    set_rhs_last_pointer_info (0, 0);
-                    return;
-                
-                } else if (assign_op == TOK_ASSIGN) {
-                
-                    if (subscript_elem_size > (DATA_LLONG & 0x1f)) {
-                    
-                        pending_struct_return_lhs = 0;
-                        pending_struct_return_global_name = 0;
-                        pending_struct_return_stack_address = 1;
-                        pending_struct_return_stack_offset = 0;
-                        
-                        emit_load_assignment_rhs_expression_to_reg (reg);
-                        
-                        pending_struct_return_stack_address = 0;
-                        pending_struct_return_stack_offset = 0;
-                        
-                        emit_pop_reg_now ("edx");
-                        set_rhs_last_pointer_info (0, 0);
-                        
-                        return;
-                    
-                    }
-                    
-                    emit_load_assignment_rhs_expression_to_reg (reg);
-                
-                } else {
-                
-                    emit_load_deref_reg_now (reg, subscript_elem_size);
-                    emit_push_reg_now (reg);
-                    
-                    emit_load_assignment_rhs_expression_to_reg ("edx");
-                    emit_pop_reg_now (reg);
-                    
-                    emit_assignment_binary_op (assign_op, 0);
-                
-                }
-                
-                emit_pop_reg_now ("edx");
-                
-                emit_store_reg_to_deref_reg_now ("edx", reg, subscript_elem_size);
-                set_rhs_last_pointer_info (0, 0);
-                
-                return;
-            
-            }
-            
-            emit_load_deref_reg_now (reg, subscript_elem_size);
-            
-            if (subscript_pointer_depth > 0) {
-                subscript_pointer_depth--;
-            }
-            
-            if (subscript_pointer_depth > 0) {
-                set_rhs_last_pointer_info (subscript_pointer_depth, subscript_elem_size);
-            } else {
-                set_rhs_last_pointer_info (0, 0);
-            }
-        
-        }
-        
-        if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
-            emit_apply_postfix_member_access_to_reg_now (reg);
-        }
-        
-        if (postfix_member_seen && tok.kind == TOK_LPAREN) {
-        
-            emit_call_pointer_in_reg_now (reg, reg);
-            
-            set_rhs_last_pointer_info (0, 0);
-            return;
-        
-        }
-        
-        if (postfix_member_seen) {
-        
-            set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
-            
-            if (is_assignment_operator (tok.kind)) {
-            
-                enum token_kind op = tok.kind;
-                
-                int assign_member_offset = postfix_member_offset;
-                int assign_member_size = postfix_member_size;
-                
-                get_token ();
-                
-                if (state->ofp) {
-                
-                    if (op == TOK_ASSIGN) {
-                    
-                        if (postfix_member_is_floating || token_is_floating_constant_now () || rhs_current_operand_is_floating_now ()) {
-                        
-                            emit_push_reg_now ("edx");
-                            emit_load_floating_rhs_expression_now (assign_member_size);
-                            
-                            emit_pop_reg_now ("edx");
-                            emit_store_floating_member_to_addr_reg_now ("edx", assign_member_offset, assign_member_size);
-                            
-                            return;
-                        
-                        }
-                        
-                        if (assign_member_size > (DATA_LLONG & 0x1f) &&
-                            tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now ()) {
-                        
-                            char *rhs_name = xstrdup (tok.ident);
-                            
-                            const char *rhs_start = tok.start;
-                            const char *rhs_caret = tok.caret;
-                            
-                            unsigned long rhs_line = get_line_number ();
-                            emit_push_reg_now ("edx");
-                            
-                            pending_struct_return_lhs = 0;
-                            pending_struct_return_global_name = 0;
-                            pending_struct_return_stack_address = 1;
-                            pending_struct_return_stack_offset = assign_member_offset;
-                            
-                            get_token ();
-                            emit_call_identifier_to_reg_now (rhs_name, reg, rhs_start, rhs_caret, rhs_line);
-                            
-                            pending_struct_return_stack_address = 0;
-                            pending_struct_return_stack_offset = 0;
-                            
-                            emit_pop_reg_now ("edx");
-                            free (rhs_name);
-                            
-                            return;
-                        
-                        }
-                        
-                        if (emit_aggregate_copy_from_current_rhs_to_addr_reg_now ("edx", assign_member_offset, assign_member_size)) {
-                            return;
-                        }
-                        
-                        emit_push_reg_now ("edx");
-                        
-                        emit_load_assignment_rhs_expression_to_reg (reg);
-                        emit_pop_reg_now ("edx");
-                    
-                    } else {
-                    
-                        /*
-                         * emit_apply_postfix_member_access_to_reg_now() has already
-                         * loaded the member value into reg and left the containing
-                         * object address in edx.  Do not load the member again from
-                         * reg: for p->m |= x that treats the old value of m as a
-                         * pointer and dereferences it, which corrupts/segfaults code
-                         * such as section->symbol->flags |= SYMBOL_FLAG_SECTION_SYMBOL.
-                         */
-                        emit_push_reg_now ("edx");
-                        emit_push_reg_now (reg);
-                        
-                        emit_load_assignment_rhs_expression_to_reg ("edx");
-                        emit_pop_reg_now (reg);
-                        
-                        emit_assignment_binary_op (op, 0);
-                        emit_pop_reg_now ("edx");
-                    
-                    }
-                    
-                    emit_store_member_to_addr_reg_now ("edx", assign_member_offset, reg, assign_member_size);
-                
-                } else {
-                    emit_load_assignment_rhs_expression_to_reg (reg);
-                }
-            
-            }
-        
-        }
-        
-        /*
-         * This routine parses one primary operand for the outer binary
-         * expression parser.  After returning, the caller can still consume
-         * any trailing operator, e.g. the / b in:
-         *
-         *     (a + b - 1) / b
-         */
-        return;
-    
-    } else if (tok.kind == TOK_AMPER) {
-    
-        char *name;
-        
-        const char *name_start;
-        const char *name_caret;
-        
-        unsigned long name_line;
-        struct local_symbol *src;
-        
-        get_token ();
-        
-        if (tok.kind == TOK_LPAREN) {
-        
-            if (emit_load_address_of_parenthesized_postfix_to_reg_now (reg)) {
-                return;
-            }
-        
-        }
-        
-        name_start = tok.start;
-        name_caret = tok.caret;
-        name_line = get_line_number ();
-        
-        if (tok.kind != TOK_IDENT) {
-        
-            int64_s zero;
-            
-            zero.low = 0;
-            zero.high = 0;
-            
-            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after '&'");
-            
-            emit_load_const32_to_reg_now (reg, zero);
-            return;
-        
-        }
-        
-        name = xstrdup (tok.ident);
-        get_token ();
-        
-        src = find_local_symbol (name);
-        
-        if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
-        
-            int global_index = find_global_symbol (name);
-            
-            const char *current_object_tag_name = 0;
-            int current_object_size = 0;
-            
-            if (src) {
-            
-                if (tok.kind == TOK_DOT || src->is_array) {
-                
-                    current_object_size = src->is_array && src->pointed_size > 0 ? src->pointed_size : src->size;
-                    current_object_tag_name = src->is_array ? (src->pointed_tag_name ? src->pointed_tag_name : src->tag_name) : 0;
-                    
-                    if (src->is_static && src->static_label) {
-                        emit_load_address_to_reg_now (reg, src->static_label);
-                    } else {
-                        emit_load_local_address_to_reg_now (reg, src->offset);
-                    }
-                
-                } else if (src->is_static && src->static_label) {
-                
-                    current_object_size = src->pointed_size > 0 ? src->pointed_size : DATA_PTR;
-                    current_object_tag_name = src->pointed_tag_name;
-                    
-                    emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
-                
-                } else {
-                
-                    current_object_size = src->pointed_size > 0 ? src->pointed_size : DATA_PTR;
-                    current_object_tag_name = src->pointed_tag_name;
-                    
-                    emit_load_local_to_reg (reg, src->offset, DATA_PTR);
-                
-                }
-            
-            } else if (global_index >= 0) {
-            
-                if (tok.kind == TOK_DOT || get_global_symbol_array (name)) {
-                
-                    current_object_size = get_global_symbol_array (name) && get_global_symbol_pointed_size (name) > 0 ? get_global_symbol_pointed_size (name) : get_global_symbol_size (name);
-                    current_object_tag_name = get_global_symbol_tag_name (name);
-                    
-                    emit_load_address_to_reg_now (reg, name);
-                
-                } else {
-                
-                    current_object_size = get_global_symbol_pointed_size (name) > 0 ? get_global_symbol_pointed_size (name) : DATA_PTR;
-                    current_object_tag_name = get_global_symbol_tag_name (name);
-                    
-                    emit_load_global_to_reg (reg, name, DATA_PTR);
-                
-                }
-            
-            } else {
-            
-                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-                
-                free (name);
-                return;
-            
-            }
-            
-            while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
-            
-                enum token_kind member_op = tok.kind;
-                char *member;
-                
-                const char *member_start;
-                const char *member_caret;
-                
-                unsigned long member_line;
-                
-                int offset = 0;
-                int member_size = DATA_INT & 0x1f;
-                int elem_size = DATA_INT & 0x1f;
-                int pointer_depth = 0;
-                
-                get_token ();
-                
-                member_start = tok.start;
-                member_caret = tok.caret;
-                member_line = get_line_number ();
-                
-                if (tok.kind != TOK_IDENT) {
-                
-                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
-                    
-                    free (name);
-                    return;
-                
-                }
-                
-                member = xstrdup (tok.ident);
-                get_token ();
-                
-                if (!find_member_info_ex_bounded (member, current_object_size, current_object_tag_name, &offset, &member_size, &elem_size, &pointer_depth, 0, 0)) {
-                
-                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
-                    
-                    free (member);
-                    free (name);
-                    
-                    return;
-                
-                }
-                
-                current_object_tag_name = last_found_member_tag_name;
-                free (member);
-                
-                if (state->ofp && offset != 0) {
-                
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                        fprintf (state->ofp, "    add %s, %d\n", reg, offset);
-                    } else {
-                        fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
-                    }
-                
-                }
-                
-                if (tok.kind == TOK_LBRACK) {
-                
-                    if (pointer_depth > 0) {
-                    
-                        emit_load_member_from_addr_reg_now (reg, reg, 0, DATA_PTR & 0x1f);
-                        emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
-                    
-                    } else {
-                        emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
-                    }
-                
-                } else if (pointer_depth > 0 && (tok.kind == TOK_ARROW || tok.kind == TOK_DOT)) {
-                    emit_load_member_from_addr_reg_now (reg, reg, 0, DATA_PTR & 0x1f);
-                }
-                
-                if (pointer_depth > 0) {
-                    current_object_size = elem_size > 0 ? elem_size : DATA_PTR;
-                } else {
-                    current_object_size = member_size;
-                }
-            
-            }
-            
-            free (name);
-            return;
-        
-        }
-        
-        if (tok.kind == TOK_LBRACK) {
-        
-            if (src) {
-            
-                int elem_size = src->is_array ? (src->pointer_depth ? DATA_PTR : (src->array_element_size > 0 ? src->array_element_size : src->pointed_size)) :
-                    (src->pointer_depth > 1 ? DATA_PTR : src->pointed_size);
-                
-                if (elem_size <= 0) {
-                    elem_size = DATA_INT & 0x1f;
-                }
-                
-                if (src->is_array) {
-                
-                    if (src->is_static && src->static_label) {
-                        emit_load_address_to_reg_now (reg, src->static_label);
-                    } else {
-                        emit_load_local_address_to_reg_now (reg, src->offset);
-                    }
-                
-                } else if (src->is_static && src->static_label) {
-                    emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
-                } else {
-                    emit_load_local_to_reg (reg, src->offset, DATA_PTR);
-                }
-                
-                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
-                
-                if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
-                
-                    const char *current_object_tag_name = src->is_array ? (src->tag_name ? src->tag_name : src->pointed_tag_name) : src->pointed_tag_name;
-                    int current_object_size = elem_size;
-                    
-                    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
-                    
-                        enum token_kind member_op = tok.kind;
-                        char *member;
-                        
-                        const char *member_start;
-                        const char *member_caret;
-                        
-                        unsigned long member_line;
-                        
-                        int offset = 0;
-                        int member_size = DATA_INT & 0x1f;
-                        int member_elem_size = DATA_INT & 0x1f;
-                        int member_pointer_depth = 0;
-                        
-                        get_token ();
-                        
-                        member_start = tok.start;
-                        member_caret = tok.caret;
-                        member_line = get_line_number ();
-                        
-                        if (tok.kind != TOK_IDENT) {
-                        
-                            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
-                            
-                            free (name);
-                            return;
-                        
-                        }
-                        
-                        member = xstrdup (tok.ident);
-                        get_token ();
-                        
-                        if (!find_member_info_ex_bounded (member, current_object_size, current_object_tag_name, &offset, &member_size, &member_elem_size, &member_pointer_depth, 0, 0)) {
-                        
-                            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
-                            
-                            free (member);
-                            free (name);
-                            
-                            return;
-                        
-                        }
-                        
-                        current_object_tag_name = last_found_member_tag_name;
-                        free (member);
-                        
-                        if (state->ofp && offset != 0) {
-                        
-                            if (state->syntax & ASM_SYNTAX_INTEL) {
-                                fprintf (state->ofp, "    add %s, %d\n", reg, offset);
-                            } else {
-                                fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
-                            }
-                        
-                        }
-                        
-                        if (tok.kind == TOK_LBRACK) {
-                        
-                            if (member_pointer_depth > 0) {
-                                emit_load_member_from_addr_reg_now (reg, reg, 0, DATA_PTR & 0x1f);
-                            }
-                            
-                            emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, member_elem_size > 0 ? member_elem_size : DATA_INT & 0x1f);
-                        
-                        } else if (member_pointer_depth > 0 && (tok.kind == TOK_ARROW || tok.kind == TOK_DOT)) {
-                            emit_load_member_from_addr_reg_now (reg, reg, 0, DATA_PTR & 0x1f);
-                        }
-                        
-                        if (member_pointer_depth > 0) {
-                            current_object_size = member_elem_size > 0 ? member_elem_size : DATA_PTR;
-                        } else {
-                            current_object_size = member_size;
-                        }
-                    
-                    }
-                
-                }
-                
-                free (name);
-                return;
-            
-            }
-            
-            if (find_global_symbol (name) >= 0) {
-            
-                int elem_size = get_global_symbol_array (name) ?
-                    (get_global_symbol_pointer_depth (name) ? DATA_PTR : (get_global_symbol_array_element_size (name) > 0 ? get_global_symbol_array_element_size (name) : get_global_symbol_pointed_size (name))) :
-                        (get_global_symbol_pointer_depth (name) > 1 ? DATA_PTR : get_global_symbol_pointed_size (name));
-                
-                if (elem_size <= 0) {
-                    elem_size = DATA_INT & 0x1f;
-                }
-                
-                if (get_global_symbol_array (name)) {
-                    emit_load_address_to_reg_now (reg, name);
-                } else {
-                    emit_load_global_to_reg (reg, name, DATA_PTR);
-                }
-                
-                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
-                
-                free (name);
-                return;
-            
-            }
-        
-        }
-        
-        if (src) {
-        
-            if (src->is_static && src->static_label) {
-                emit_load_address_to_reg_now (reg, src->static_label);
-            } else {
-                emit_load_local_address_to_reg_now (reg, src->offset);
-            }
-            
-            free (name);
-            return;
-        
-        }
-        
-        if (find_global_symbol (name) >= 0) {
-        
-            emit_load_address_to_reg_now (reg, name);
-            
-            free (name);
-            return;
-        
-        }
-        
-        {
-        
-            int64_s zero;
-            
-            zero.low = 0;
-            zero.high = 0;
-            
-            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-            
-            free (name);
-            emit_load_const32_to_reg_now (reg, zero);
-        
-        }
-        
-        return;
-    
-    } else if (tok.kind == TOK_STAR) {
-    
-        int deref_had_parens = 0;
-        int deref_size = DATA_CHAR & 0x1f;
-        int deref_pointer_depth = 0;
-        int deref_pointed_size = 0;
-        
-        if (emit_load_deref_parenthesized_deref_postfix_incdec_to_reg_now (reg)) {
-            return;
-        }
-        
-        if (emit_store_to_deref_parenthesized_deref_postfix_incdec_now (reg)) {
-            return;
-        }
-        
-        get_token ();
-        
-        if (tok.kind == TOK_IDENT) {
-        
-            char *lhs_name = xstrdup (tok.ident);
-            
-            const char *lhs_start = tok.start;
-            const char *lhs_caret = tok.caret;
-            
-            unsigned long lhs_line = get_line_number ();
-            struct local_symbol *lhs_sym;
-            
-            enum token_kind lhs_postfix_op = TOK_EOF;
-            enum token_kind member_op = TOK_EOF;
-            
-            char *member;
-            
-            const char *member_start;
-            const char *member_caret;
-            
-            unsigned long member_line;
-            
-            int lhs_has_postfix = 0;
-            int offset = 0;
-            
-            int member_size = DATA_PTR & 0x1f;
-            int member_elem_size = DATA_INT & 0x1f;
-            int member_pointer_depth = 0;
-            int member_load_size = DATA_PTR & 0x1f;
-            
-            get_token ();
-            
-            if (tok.kind == TOK_LPAREN &&
-                find_global_symbol (lhs_name) >= 0 &&
-                get_global_symbol_kind (lhs_name) == GLOBAL_SYMBOL_FUNCTION) {
-            
-                int fptr_depth = get_global_symbol_pointer_depth (lhs_name);
-                int fpointed_size = get_global_symbol_pointed_size (lhs_name);
-                
-                emit_call_identifier_to_reg_now (lhs_name, reg, lhs_start, lhs_caret, lhs_line);
-                
-                if (fptr_depth > 1) {
-                    deref_size = DATA_PTR;
-                } else if (fptr_depth == 1 && fpointed_size > 0) {
-                    deref_size = fpointed_size;
-                }
-                
-                emit_load_deref_reg_now (reg, deref_size);
-                
-                free (lhs_name);
-                return;
-            
-            }
-            
-            if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
-            
-                member_op = tok.kind;
-                get_token ();
-                
-                member_start = tok.start;
-                member_caret = tok.caret;
-                member_line = get_line_number ();
-                
-                if (tok.kind != TOK_IDENT) {
-                
-                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
-                    
-                    free (lhs_name);
-                    return;
-                
-                }
-                
-                member = xstrdup (tok.ident);
-                get_token ();
-                
-                if (!find_member_info_ex (member, &offset, &member_size, &member_elem_size, &member_pointer_depth, 0, 0)) {
-                
-                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
-                    
-                    free (member);
-                    free (lhs_name);
-                    
-                    return;
-                
-                }
-                
-                free (member);
-                
-                if (member_pointer_depth > 0) {
-                    member_load_size = DATA_PTR & 0x1f;
-                } else {
-                    member_load_size = member_size;
-                }
-                
-                if (member_pointer_depth > 1) {
-                    deref_size = DATA_PTR;
-                } else if (member_pointer_depth == 1 && member_elem_size > 0) {
-                    deref_size = member_elem_size;
-                }
-                
-                if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-                
-                    lhs_has_postfix = 1;
-                    lhs_postfix_op = tok.kind;
-                    
-                    get_token ();
-                
-                }
-                
-                if (tok.kind == TOK_ASSIGN) {
-                
-                    lhs_sym = find_local_symbol (lhs_name);
-                    
-                    if (lhs_sym) {
-                    
-                        if (lhs_sym->is_static && lhs_sym->static_label) {
-                            emit_load_global_to_reg ("edx", lhs_sym->static_label, DATA_PTR);
-                        } else {
-                            emit_load_local_to_reg ("edx", lhs_sym->offset, DATA_PTR);
-                        }
-                    
-                    } else if (find_global_symbol (lhs_name) >= 0) {
-                        emit_load_global_to_reg ("edx", lhs_name, DATA_PTR);
-                    } else {
-                        report_line_at (get_filename (), lhs_line, REPORT_ERROR, lhs_start, lhs_caret, "unknown symbol '%s'", lhs_name);
-                    }
-                    
-                    if (state->ofp && offset != 0) {
-                    
-                        if (state->syntax & ASM_SYNTAX_INTEL) {
-                            fprintf (state->ofp, "    add edx, %d\n", offset);
-                        } else {
-                            fprintf (state->ofp, "    addl $%d, %%edx\n", offset);
-                        }
-                    
-                    }
-                    
-                    emit_push_reg_now ("edx");
-                    get_token ();
-                    
-                    emit_load_assignment_rhs_expression_to_reg (reg);
-                    
-                    emit_pop_reg_now ("edx");
-                    emit_store_reg_to_deref_reg_now ("edx", reg, member_load_size);
-                    
-                    free (lhs_name);
-                    return;
-                
-                }
-                
-                lhs_sym = find_local_symbol (lhs_name);
-                
-                if (lhs_sym) {
-                
-                    if (member_op == TOK_DOT) {
-                    
-                        if (lhs_sym->is_static && lhs_sym->static_label) {
-                            emit_load_address_to_reg_now (reg, lhs_sym->static_label);
-                        } else {
-                            emit_load_local_address_to_reg_now (reg, lhs_sym->offset);
-                        }
-                    
-                    } else if (lhs_sym->is_static && lhs_sym->static_label) {
-                        emit_load_global_to_reg (reg, lhs_sym->static_label, DATA_PTR);
-                    } else {
-                        emit_load_local_to_reg (reg, lhs_sym->offset, DATA_PTR);
-                    }
-                
-                } else if (find_global_symbol (lhs_name) >= 0) {
-                
-                    if (member_op == TOK_DOT) {
-                        emit_load_address_to_reg_now (reg, lhs_name);
-                    } else {
-                        emit_load_global_to_reg (reg, lhs_name, DATA_PTR);
-                    }
-                
-                } else {
-                    report_line_at (get_filename (), lhs_line, REPORT_ERROR, lhs_start, lhs_caret, "unknown symbol '%s'", lhs_name);
-                }
-                
-                if (member_size > (DATA_PTR & 0x1f) && member_pointer_depth == 0) {
-                
-                    if (state->ofp && offset != 0) {
-                    
-                        if (state->syntax & ASM_SYNTAX_INTEL) {
-                            fprintf (state->ofp, "    add %s, %d\n", reg, offset);
-                        } else {
-                            fprintf (state->ofp, "    addl $%d, %%%s\n", offset, reg);
-                        }
-                    
-                    }
-                
-                } else {
-                    emit_load_member_from_addr_reg_now (reg, reg, offset, member_load_size);
-                }
-                
-                if (lhs_has_postfix) {
-                    /* Already applied above only for assignment forms. */
-                }
-                
-                if (member_pointer_depth > 0) {
-                    set_rhs_last_pointer_info (member_pointer_depth, member_elem_size);
-                } else {
-                    clear_rhs_last_pointer_info ();
-                }
-                
-                free (lhs_name);
-                return;
-            
-            }
-            
-            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-            
-                lhs_has_postfix = 1;
-                lhs_postfix_op = tok.kind;
-                
-                get_token ();
-            
-            }
-            
-            if (tok.kind == TOK_ASSIGN) {
-            
-                int lhs_deref_is_unsigned = 1;
-                lhs_sym = find_local_symbol (lhs_name);
-                
-                if (lhs_sym) {
-                
-                    if (lhs_sym->pointer_depth > 1) {
-                        deref_size = DATA_PTR & 0x1f;
-                    } else if (lhs_sym->pointer_depth == 1 && lhs_sym->pointed_size > 0) {
-                    
-                        /**
-                         * Keep the full pointed-to object size here.  This
-                         * assignment path also handles aggregate lvalues such
-                         * as *hashtab = old_hashtab;  Masking with 0x1f turns
-                         * a 44-byte struct hashtab into 12 and emits a partial
-                         * copy, corrupting pdas hashtab state during rehash().
-                         */
-                        deref_size = lhs_sym->pointed_size;
-                    
-                    }
-                    
-                    if (member_op == TOK_DOT) {
-                    
-                        if (lhs_sym->is_static && lhs_sym->static_label) {
-                            emit_load_address_to_reg_now ("edx", lhs_sym->static_label);
-                        } else {
-                            emit_load_local_address_to_reg_now ("edx", lhs_sym->offset);
-                        }
-                    
-                    } else if (lhs_sym->is_static && lhs_sym->static_label) {
-                        emit_load_global_to_reg ("edx", lhs_sym->static_label, DATA_PTR);
-                    } else {
-                        emit_load_local_to_reg ("edx", lhs_sym->offset, DATA_PTR);
-                    }
-                
-                } else if (find_global_symbol (lhs_name) >= 0) {
-                
-                    if (get_global_symbol_pointer_depth (lhs_name) > 1) {
-                        deref_size = DATA_PTR & 0x1f;
-                    } else if (get_global_symbol_pointer_depth (lhs_name) == 1 && get_global_symbol_pointed_size (lhs_name) > 0) {
-                        deref_size = get_global_symbol_pointed_size (lhs_name);
-                    }
-                    
-                    if (member_op == TOK_DOT) {
-                        emit_load_address_to_reg_now ("edx", lhs_name);
-                    } else {
-                        emit_load_global_to_reg ("edx", lhs_name, DATA_PTR);
-                    }
-                
-                } else {
-                    report_line_at (get_filename (), lhs_line, REPORT_ERROR, lhs_start, lhs_caret, "unknown symbol '%s'", lhs_name);
-                }
-                
-                emit_push_reg_now ("edx");
-                
-                if (lhs_has_postfix) {
-                    emit_incdec_symbol_now (lhs_sym, lhs_name, lhs_postfix_op, lhs_line, lhs_start, lhs_caret);
-                }
-                
-                get_token ();
-                
-                if (deref_size > (DATA_LLONG & 0x1f)) {
-                
-                    emit_pop_reg_now ("edx");
-                    
-                    if (!emit_store_assignment_to_aggregate_address_now ("edx", deref_size, lhs_start, lhs_caret, lhs_line)) {
-                        report_line_at (get_filename (), lhs_line, REPORT_ERROR, lhs_start, lhs_caret, "aggregate assignment expression not implemented");
-                    }
-                
-                } else if (deref_size == (DATA_LLONG & 0x1f)) {
-                
-                    emit_load_assignment_rhs_expression_to_pair ("eax", "edx", lhs_deref_is_unsigned);
-                    emit_pop_reg_now ("ecx");
-                    
-                    emit_store_pair_to_deref_reg_now ("ecx", "eax", "edx");
-                
-                } else {
-                
-                    emit_load_assignment_rhs_expression_to_reg (reg);
-                    emit_pop_reg_now ("edx");
-                    
-                    emit_store_reg_to_deref_reg_now ("edx", reg, deref_size);
-                
-                }
-                
-                free (lhs_name);
-                return;
-            
-            }
-            
-            lhs_sym = find_local_symbol (lhs_name);
-            
-            if (lhs_sym) {
-            
-                if (lhs_sym->is_static && lhs_sym->static_label) {
-                    emit_load_global_to_reg (reg, lhs_sym->static_label, DATA_PTR);
-                } else {
-                    emit_load_local_to_reg (reg, lhs_sym->offset, DATA_PTR);
-                }
-                
-                if (lhs_has_postfix) {
-                
-                    emit_push_reg_now (reg);
-                    emit_incdec_symbol_now (lhs_sym, lhs_name, lhs_postfix_op, lhs_line, lhs_start, lhs_caret);
-                    emit_pop_reg_now (reg);
-                
-                }
-                
-                if (lhs_sym->pointer_depth > 1) {
-                    deref_size = DATA_PTR;
-                } else if (lhs_sym->pointer_depth == 1) {
-                    deref_size = lhs_sym->pointed_size;
-                }
-                
-                emit_load_deref_reg_now (reg, deref_size);
-                
-                if (lhs_sym->pointer_depth > 1) {
-                    set_rhs_last_pointer_info (lhs_sym->pointer_depth - 1, lhs_sym->pointed_size);
-                } else {
-                    clear_rhs_last_pointer_info ();
-                }
-                
-                if (emit_handle_subscript_after_loaded_pointer_to_reg_now (reg, lhs_sym->pointer_depth > 0 ? lhs_sym->pointer_depth - 1 : 0, lhs_sym->pointed_size, lhs_sym->pointed_is_unsigned)) {
-                
-                    free (lhs_name);
-                    return;
-                
-                }
-                
-                free (lhs_name);
-                return;
-            
-            }
-            
-            if (find_global_symbol (lhs_name) >= 0) {
-            
-                emit_load_global_to_reg (reg, lhs_name, DATA_PTR);
-                
-                if (lhs_has_postfix) {
-                
-                    emit_push_reg_now (reg);
-                    
-                    emit_incdec_symbol_now (0, lhs_name, lhs_postfix_op, lhs_line, lhs_start, lhs_caret);
-                    emit_pop_reg_now (reg);
-                
-                }
-                
-                if (get_global_symbol_pointer_depth (lhs_name) > 1) {
-                    deref_size = DATA_PTR;
-                } else if (get_global_symbol_pointer_depth (lhs_name) == 1) {
-                    deref_size = get_global_symbol_pointed_size (lhs_name);
-                }
-                
-                emit_load_deref_reg_now (reg, deref_size);
-                
-                if (get_global_symbol_pointer_depth (lhs_name) > 1) {
-                    set_rhs_last_pointer_info (get_global_symbol_pointer_depth (lhs_name) - 1, get_global_symbol_pointed_size (lhs_name));
-                } else {
-                    clear_rhs_last_pointer_info ();
-                }
-                
-                if (emit_handle_subscript_after_loaded_pointer_to_reg_now (reg, get_global_symbol_pointer_depth (lhs_name) > 0 ? get_global_symbol_pointer_depth (lhs_name) - 1 : 0, get_global_symbol_pointed_size (lhs_name), get_global_symbol_pointed_is_unsigned (lhs_name))) {
-                
-                    free (lhs_name);
-                    return;
-                
-                }
-                
-                free (lhs_name);
-                return;
-            
-            }
-            
-            report_line_at (get_filename (), lhs_line, REPORT_ERROR, lhs_start, lhs_caret, "unknown symbol '%s'", lhs_name);
-            free (lhs_name);
-            
-            return;
-        
-        }
-        
-        if (tok.kind == TOK_LPAREN) {
-        
-            deref_had_parens = 1;
-            get_token ();
-            
-            if (is_type_start (tok.kind)) {
-            
-                if (parse_deref_cast_type_name (&deref_size)) {
-                
-                    /*
-                     * parse_deref_cast_type_name() consumes the cast parentheses
-                     * only.  Do not consume a following ')' here: in expressions
-                     * such as:
-                     *
-                     *     __munmap(ptr, *(size_t *)ptr + sizeof(size_t))
-                     *
-                     * that ')' belongs to the surrounding call.  Consuming it
-                     * here makes the caller report a false "expected )".
-                     */
-                    
-                    if (tok.kind == TOK_ASSIGN) {
-                    
-                        get_token ();
-                        
-                        emit_push_reg_now (reg);
-                        emit_load_assignment_rhs_expression_to_reg (reg);
-                        
-                        emit_pop_reg_now ("edx");
-                        emit_store_reg_to_deref_reg_now ("edx", reg, deref_size);
-                        
-                        return;
-                    
-                    }
-                    
-                    /*
-                     * parse_deref_cast_type_name() consumes only the cast type
-                     * parentheses.  The operand being cast is still the current
-                     * token, e.g. the ptr in:
-                     *
-                     *     *(size_t *)ptr + sizeof(size_t)
-                     *
-                     * Load that address expression before applying the outer
-                     * unary '*'.  Otherwise the caller sees the unconsumed
-                     * identifier/operator and reports a false "expected )".
-                     */
-                    emit_load_assignment_rhs_to_reg (reg);
-                    goto dereference_loaded_address;
-                
-                }
-            
-            }
-            
-            if (tok.kind == TOK_AMPER) {
-            
-                char *name;
-                
-                const char *name_start;
-                const char *name_caret;
-                
-                unsigned long name_line;
-                struct local_symbol *dst;
-                
-                int global_index;
-                int dst_size;
-                
-                get_token ();
-                
-                name_start = tok.start;
-                name_caret = tok.caret;
-                name_line = get_line_number ();
-                
-                if (tok.kind == TOK_IDENT) {
-                
-                    name = xstrdup (tok.ident);
-                    
-                    get_token ();
-                    expect (TOK_RPAREN, ")");
-                    
-                    if (is_assignment_operator (tok.kind)) {
-                    
-                        get_token ();
-                        emit_load_assignment_rhs_expression_to_reg (reg);
-                        
-                        dst = find_local_symbol (name);
-                        global_index = find_global_symbol (name);
-                        
-                        if (dst) {
-                        
-                            dst_size = dst->size;
-                            
-                            if (dst->is_static && dst->static_label) {
-                                emit_store_reg_to_global (dst->static_label, dst_size, reg);
-                            } else {
-                                emit_store_reg_to_local (dst->offset, dst_size, reg);
-                            }
-                        
-                        } else if (global_index >= 0) {
-                        
-                            dst_size = get_global_symbol_size (name);
-                            emit_store_reg_to_global (name, dst_size, reg);
-                        
-                        } else {
-                            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-                        }
-                        
-                        free (name);
-                        return;
-                    
-                    }
-                    
-                    if (find_local_symbol (name) || find_global_symbol (name) >= 0) {
-                    
-                        dst = find_local_symbol (name);
-                        
-                        if (dst) {
-                        
-                            if (dst->is_static && dst->static_label) {
-                                emit_load_address_to_reg_now (reg, dst->static_label);
-                            } else {
-                                emit_load_local_address_to_reg_now (reg, dst->offset);
-                            }
-                        
-                        } else {
-                            emit_load_address_to_reg_now (reg, name);
-                        }
-                        
-                        free (name);
-                        goto dereference_loaded_address;
-                    
-                    }
-                    
-                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-                    free (name);
-                    
-                    return;
-                
-                }
-            
-            }
-        
-        }
-        
-        if (deref_had_parens) {
-        
-            emit_load_assignment_rhs_expression_to_reg (reg);
-            
-            if (rhs_last_pointer_depth > 1) {
-                deref_size = DATA_PTR;
-            } else if (rhs_last_pointer_depth == 1) {
-                deref_size = rhs_last_pointed_size;
-            }
-            
-            expect (TOK_RPAREN, ")");
-            
-            /*
-             * A parenthesized dereferenced function pointer is still a function
-             * designator when it is followed by an argument list.  For example:
-             *
-             *     (*generate_func)(outfile, pos)
-             *
-             * The inner expression already loaded the function pointer value into
-             * reg.  Do not dereference that value as data before the call; call
-             * through it directly.
-             */
-            if (tok.kind == TOK_LPAREN) {
-            
-                emit_call_pointer_in_reg_now (reg, reg);
-                
-                clear_rhs_last_pointer_info ();
-                return;
-            
-            }
-            
-            if (is_assignment_operator (tok.kind)) {
-            
-                enum token_kind assign_op = tok.kind;
-                
-                emit_push_reg_now (reg);
-                get_token ();
-                
-                if (assign_op == TOK_ASSIGN) {
-                    emit_load_assignment_rhs_expression_to_reg (reg);
-                } else {
-                
-                    emit_load_deref_reg_now (reg, deref_size);
-                    
-                    emit_push_reg_now (reg);
-                    emit_load_assignment_rhs_expression_to_reg ("edx");
-                    
-                    emit_pop_reg_now (reg);
-                    emit_assignment_binary_op (assign_op, 0);
-                
-                }
-                
-                emit_pop_reg_now ("edx");
-                emit_store_reg_to_deref_reg_now ("edx", reg, deref_size);
-                
-                return;
-            
-            }
-            
-            if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
-            
-                enum token_kind member_op = tok.kind;
-                enum token_kind postfix_op = TOK_EOF;
-                
-                char *member;
-                
-                const char *member_start;
-                const char *member_caret;
-                
-                unsigned long member_line;
-                
-                int offset = 0;
-                int member_size = DATA_PTR & 0x1f;
-                int member_elem_size = DATA_INT & 0x1f;
-                int member_pointer_depth = 0;
-                
-                get_token ();
-                
-                member_start = tok.start;
-                member_caret = tok.caret;
-                member_line = get_line_number ();
-                
-                if (tok.kind != TOK_IDENT) {
-                
-                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
-                    return;
-                
-                }
-                
-                member = xstrdup (tok.ident);
-                get_token ();
-                
-                if (!find_member_info_ex (member, &offset, &member_size, &member_elem_size, &member_pointer_depth, 0, 0)) {
-                
-                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
-                    
-                    free (member);
-                    return;
-                
-                }
-                
-                free (member);
-                
-                if (member_pointer_depth > 1) {
-                    deref_size = DATA_PTR;
-                } else if (member_pointer_depth == 1 && member_elem_size > 0) {
-                    deref_size = member_elem_size;
-                }
-                
-                if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-                
-                    postfix_op = tok.kind;
-                    get_token ();
-                
-                }
-                
-                if (state->ofp) {
-                
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                    
-                        if (state->syntax & ASM_SYNTAX_NASM) {
-                            fprintf (state->ofp, "    mov edx, dword [%s + %d]\n", reg, offset);
-                        } else {
-                            fprintf (state->ofp, "    mov edx, dword ptr [%s + %d]\n", reg, offset);
-                        }
-                        
-                        if (postfix_op == TOK_INCR || postfix_op == TOK_DECR) {
-                        
-                            if (state->syntax & ASM_SYNTAX_NASM) {
-                                fprintf (state->ofp, "    %s dword [%s + %d]\n", postfix_op == TOK_INCR ? "inc" : "dec", reg, offset);
-                            } else {
-                                fprintf (state->ofp, "    %s dword ptr [%s + %d]\n", postfix_op == TOK_INCR ? "inc" : "dec", reg, offset);
-                            }
-                        
-                        }
-                    
-                    } else {
-                    
-                        fprintf (state->ofp, "    movl %d(%%%s), %%edx\n", offset, reg);
-                        
-                        if (postfix_op == TOK_INCR || postfix_op == TOK_DECR) {
-                            fprintf (state->ofp, "    %sl %d(%%%s)\n", postfix_op == TOK_INCR ? "inc" : "dec", offset, reg);
-                        }
-                    
-                    }
-                
-                }
-                
-                if (tok.kind == TOK_ASSIGN) {
-                
-                    emit_push_reg_now ("edx");
-                    get_token ();
-                    
-                    emit_load_assignment_rhs_expression_to_reg (reg);
-                    emit_pop_reg_now ("edx");
-                    emit_store_reg_to_deref_reg_now ("edx", reg, deref_size);
-                    
-                    return;
-                
-                }
-                
-                if (state->ofp && strcmp (reg, "edx") != 0) {
-                
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                        fprintf (state->ofp, "    mov %s, edx\n", reg);
-                    } else {
-                        fprintf (state->ofp, "    movl %%edx, %%%s\n", reg);
-                    }
-                
-                }
-                
-                goto dereference_loaded_address;
-            
-            }
-        
-        } else {
-            emit_load_assignment_rhs_to_reg (reg);
-        }
-        
-    dereference_loaded_address:
-        
-        deref_pointer_depth = rhs_last_pointer_depth;
-        deref_pointed_size = rhs_last_pointed_size;
-        
-        emit_load_deref_reg_now (reg, deref_size);
-        
-        if (deref_pointer_depth > 1) {
-            set_rhs_last_pointer_info (deref_pointer_depth - 1, deref_pointed_size);
-        } else {
-            clear_rhs_last_pointer_info ();
-        }
-        
-        if (tok.kind == TOK_LBRACK) {
-        
-            int subscript_pointer_depth = deref_pointer_depth > 0 ? deref_pointer_depth - 1 : 0;
-            int subscript_elem_size = subscript_pointer_depth > 1 ? (DATA_PTR & 0x1f) : deref_pointed_size;
-            
-            if (subscript_elem_size <= 0) {
-                subscript_elem_size = DATA_INT & 0x1f;
-            }
-            
-            emit_parse_postfix_subscripts_to_reg_now (reg, subscript_elem_size, subscript_pointer_depth, deref_pointed_size);
-            
-            if (is_assignment_operator (tok.kind)) {
-            
-                enum token_kind assign_op = tok.kind;
-                
-                get_token ();
-                emit_push_reg_now (reg);
-                
-                if (assign_op == TOK_ASSIGN && subscript_elem_size > (DATA_LLONG & 0x1f) &&
-                    tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now ()) {
-                
-                    char *rhs_name = xstrdup (tok.ident);
-                    
-                    const char *rhs_start = tok.start;
-                    const char *rhs_caret = tok.caret;
-                    
-                    unsigned long rhs_line = get_line_number ();
-                    
-                    pending_struct_return_lhs = 0;
-                    pending_struct_return_global_name = 0;
-                    pending_struct_return_stack_address = 1;
-                    pending_struct_return_stack_offset = 0;
-                    
-                    get_token ();
-                    emit_call_identifier_to_reg_now (rhs_name, reg, rhs_start, rhs_caret, rhs_line);
-                    
-                    pending_struct_return_stack_address = 0;
-                    pending_struct_return_stack_offset = 0;
-                    
-                    emit_pop_reg_now ("edx");
-                    free (rhs_name);
-                    
-                    set_rhs_last_pointer_info (0, 0);
-                    return;
-                
-                } else if (assign_op == TOK_ASSIGN) {
-                
-                    if (subscript_elem_size > (DATA_LLONG & 0x1f)) {
-                    
-                        pending_struct_return_lhs = 0;
-                        pending_struct_return_global_name = 0;
-                        pending_struct_return_stack_address = 1;
-                        pending_struct_return_stack_offset = 0;
-                        
-                        emit_load_assignment_rhs_expression_to_reg (reg);
-                        
-                        pending_struct_return_stack_address = 0;
-                        pending_struct_return_stack_offset = 0;
-                        
-                        emit_pop_reg_now ("edx");
-                        set_rhs_last_pointer_info (0, 0);
-                        return;
-                    
-                    }
-                    
-                    emit_load_assignment_rhs_expression_to_reg (reg);
-                
-                } else {
-                
-                    emit_load_deref_reg_now (reg, subscript_elem_size);
-                    emit_push_reg_now (reg);
-                    
-                    emit_load_assignment_rhs_expression_to_reg ("edx");
-                    emit_pop_reg_now (reg);
-                    
-                    emit_assignment_binary_op (assign_op, 0);
-                
-                }
-                
-                emit_pop_reg_now ("edx");
-                
-                emit_store_reg_to_deref_reg_now ("edx", reg, subscript_elem_size);
-                clear_rhs_last_pointer_info ();
-                
-                return;
-            
-            }
-            
-            emit_load_deref_reg_now (reg, subscript_elem_size);
-            
-            if (subscript_pointer_depth > 1) {
-                set_rhs_last_pointer_info (subscript_pointer_depth - 1, deref_pointed_size);
-            } else {
-                clear_rhs_last_pointer_info ();
-            }
-        
-        }
-        
-        return;
-    
-    } else if (tok.kind == TOK_TILDE) {
-    
-        get_token ();
-        emit_load_assignment_rhs_to_reg (reg);
-        
-        if (state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                fprintf (state->ofp, "    not %s\n", reg);
-            } else {
-                fprintf (state->ofp, "    notl %%%s\n", reg);
-            }
-        
-        }
-        
-        return;
-    
-    } else if (tok.kind == TOK_XMARK) {
-    
-        get_token ();
-        emit_load_assignment_rhs_to_reg (reg);
-        
-        if (state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-            
-                fprintf (state->ofp, "    test %s, %s\n", reg, reg);
-                
-                if (strcmp (reg, "eax") != 0) {
-                
-                    fprintf (state->ofp, "    setz al\n");
-                    fprintf (state->ofp, "    movzx eax, al\n");
-                    fprintf (state->ofp, "    mov %s, eax\n", reg);
-                
-                } else {
-                
-                    fprintf (state->ofp, "    setz al\n");
-                    fprintf (state->ofp, "    movzx eax, al\n");
-                
-                }
-            
-            } else {
-            
-                fprintf (state->ofp, "    testl %%%s, %%%s\n", reg, reg);
-                fprintf (state->ofp, "    setz %%al\n");
-                fprintf (state->ofp, "    movzbl %%al, %%eax\n");
-                
-                if (strcmp (reg, "eax") != 0) {
-                    fprintf (state->ofp, "    movl %%eax, %%%s\n", reg);
-                }
-            
-            }
-        
-        }
-        
-        return;
-    
-    } else if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-    
-        if (emit_load_prefix_incdec_member_to_reg_now (reg)) {
-            return;
-        }
-        
-        if (emit_load_prefix_incdec_to_reg_now (reg)) {
-            return;
-        }
-    
-    }
-    
-    if (tok.kind == TOK_PLUS || tok.kind == TOK_MINUS) {
-    
-        int negate = 0;
-        
-        while (tok.kind == TOK_PLUS || tok.kind == TOK_MINUS) {
-        
-            if (tok.kind == TOK_MINUS) {
-                negate = !negate;
-            }
-            
-            get_token ();
-        
-        }
-        
-        emit_load_assignment_rhs_to_reg (reg);
-        
-        if (negate && state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                fprintf (state->ofp, "    neg %s\n", reg);
-            } else {
-                fprintf (state->ofp, "    negl %%%s\n", reg);
-            }
-        
-        }
-        
-        return;
-    
-    }
-    
-    if (token_is_sizeof_keyword ()) {
-    
-        int64_s v = sizeof_from_current_token ();
-        
-        if (state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                fprintf (state->ofp, "    mov %s, %lu\n", reg, v.low & U32_MASK);
-            } else {
-                fprintf (state->ofp, "    movl $%lu, %%%s\n", v.low & U32_MASK, reg);
-            }
-        
-        }
-        
-        return;
-    
-    }
-    
-    if (is_string_token ()) {
-    
-        char *label = emit_string_literal_global ();
-        
-        switch_section (SECTION_TEXT);
-        emit_load_address_to_reg_now (reg, label);
-        
-        free (label);
-        
-        /*
-         * A string literal is a primary expression and may still have
-         * postfix operators applied to it.  In particular, macro-expanded
-         * string constants are commonly subscripted in calls, e.g.
-         *
-         *     tebc (LINKAGE_EDITOR_PROGRAM_NAME[i])
-         *
-         * where LINKAGE_EDITOR_PROGRAM_NAME expands to a string literal.
-         * The old path returned immediately after loading the literal
-         * address, leaving the '[' token for the caller and causing a false
-         * "expected )".  Treat the literal as a char array here and consume
-         * any following subscripts.
-         */
-        if (tok.kind == TOK_LBRACK) {
-        
-            emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, DATA_CHAR & 0x1f);
-            emit_load_deref_reg_now (reg, DATA_CHAR & 0x1f);
-            
-            set_rhs_last_pointer_info (0, 0);
-        
-        } else {
-            set_rhs_last_pointer_info (1, DATA_CHAR & 0x1f);
-        }
-        
-        return;
-    
-    }
-    
-    switch (tok.kind) {
-    
-        case TOK_CCHAR:     case TOK_CINT:      case TOK_CUINT:     case TOK_CULONG:
-        case TOK_CLONG:     case TOK_CLLONG:    case TOK_CULLONG:   case TOK_LCHAR:
-        {
-        
-            int64_s v;
-            
-            int trailing_op = 0;
-            size_t len = tok.ident ? strlen (tok.ident) : 0;
-            
-            v.high = tok.val.i.high;
-            v.low = tok.val.i.low;
-            
-            if (len > 1 && tok.ident[len - 1] == '+') {
-                trailing_op = TOK_PLUS;
-            } else if (len > 1 && tok.ident[len - 1] == '-') {
-                trailing_op = TOK_MINUS;
-            }
-            
-            if (trailing_op) {
-            
-                free (tok.ident);
-                
-                tok.ident = xstrdup (trailing_op == TOK_PLUS ? "+" : "-");
-                tok.kind = (enum token_kind) trailing_op;
-                
-                if (tok.caret) {
-                    tok.caret--;
-                }
-            
-            } else {
-                get_token ();
-            }
-            
-            emit_load_const32_to_reg_now (reg, v);
-            return;
-        
-        }
-        
-        case TOK_CFLOAT:    case TOK_CDOUBLE:    case TOK_CLDOUBLE:
-        {
-        
-            int trailing_op = 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;
-            
-            if (len > 1 && tok.ident[len - 1] == '+') {
-                trailing_op = TOK_PLUS;
-            } else if (len > 1 && tok.ident[len - 1] == '-') {
-                trailing_op = TOK_MINUS;
-            }
-            
-            if (trailing_op) {
-            
-                free (tok.ident);
-                
-                tok.ident = xstrdup (trailing_op == TOK_PLUS ? "+" : "-");
-                tok.kind = (enum token_kind) trailing_op;
-                
-                if (tok.caret) {
-                    tok.caret--;
-                }
-            
-            } else {
-                get_token ();
-            }
-            
-            emit_load_const32_to_reg_now (reg, v);
-            return;
-        
-        }
-        
-        default:
-        
-            break;
-    
-    }
-    
-    if (tok.kind == TOK_SCC_BUILTIN_VA_ARG) {
-    
-        int va_size = DATA_INT & 0x1f;
-        int va_unsigned = 1;
-        int va_pointer = 0;
-        int va_floating = 0;
-        
-        get_token ();
-        
-        emit_parse_builtin_va_arg_address_to_reg_now (reg, &va_size, &va_unsigned, &va_pointer, &va_floating);
-        emit_load_deref_reg_now (reg, va_size);
-        
-        if (va_pointer > 0) {
-            set_rhs_last_pointer_info (va_pointer, DATA_INT & 0x1f);
-        } else {
-        
-            emit_apply_integer_cast_to_reg_now (reg, va_size, va_unsigned);
-            clear_rhs_last_pointer_info ();
-        
-        }
-        
-        return;
-    
-    }
-    
-    if (tok.kind == TOK_IDENT) {
-    
-        enum token_kind postfix_op = TOK_EOF;
-        char *name = xstrdup (tok.ident);
-        
-        const char *name_start = tok.start, *name_caret = tok.caret;
-        unsigned long name_line = get_line_number ();
-        
-        struct local_symbol *src;
-        int postfix_incdec = 0;
-        
-        get_token ();
-        
-        if (strcmp (name, "__scc_builtin_va_arg") == 0 && tok.kind == TOK_LPAREN) {
-        
-            int va_size = DATA_INT & 0x1f;
-            int va_unsigned = 1;
-            int va_pointer = 0;
-            int va_floating = 0;
-            
-            emit_parse_builtin_va_arg_address_to_reg_now (reg, &va_size, &va_unsigned, &va_pointer, &va_floating);
-            emit_load_deref_reg_now (reg, va_size);
-            
-            if (va_pointer > 0) {
-                set_rhs_last_pointer_info (va_pointer, DATA_INT & 0x1f);
-            } else {
-            
-                emit_apply_integer_cast_to_reg_now (reg, va_size, va_unsigned);
-                clear_rhs_last_pointer_info ();
-            
-            }
-            
-            free (name);
-            return;
-        
-        }
-        
-        {
-        
-            int64_s enum_value;
-            
-            if (!find_local_symbol (name) && find_global_symbol (name) < 0 && resolve_enum_constant (name, &enum_value)) {
-            
-                emit_load_const32_to_reg_now (reg, enum_value);
-                
-                set_rhs_last_pointer_info (0, DATA_INT & 0x1f);
-                free (name);
-                
-                return;
-            
-            }
-        
-        }
-        
-        if (tok.kind == TOK_LBRACK) {
-        
-            src = find_local_symbol (name);
-            
-            if (src) {
-            
-                int saw_subscript;
-                int elem_size;
-                
-                {
-                
-                    elem_size = src->is_array ? (src->pointer_depth ? DATA_PTR : (src->array_element_size > 0 ? src->array_element_size : src->pointed_size)) :
-                        (src->pointer_depth > 1 ? DATA_PTR : src->pointed_size);
-                    
-                    if (src->is_array && src->pointer_depth == 0 && elem_size <= (DATA_PTR & 0x1f)) {
-                    
-                        int aggregate_elem_size = aggregate_tag_size_or_zero (src->tag_name ? src->tag_name : src->pointed_tag_name);
-                        
-                        if (aggregate_elem_size > (DATA_PTR & 0x1f)) {
-                            elem_size = aggregate_elem_size;
-                        }
-                    
-                    }
-                    
-                    if (src->is_array) {
-                    
-                        if (src->is_static && src->static_label) {
-                            emit_load_symbol_address_to_reg_now (reg, src->static_label, 0, 0);
-                        } else {
-                            emit_load_symbol_address_to_reg_now (reg, 0, src->offset, 1);
-                        }
-                    
-                    } else if (src->is_static && src->static_label) {
-                        emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
-                    } else {
-                        emit_load_local_to_reg (reg, src->offset, DATA_PTR);
-                    }
-                    
-                    saw_subscript = emit_parse_postfix_subscripts_to_reg_dims_now (reg, elem_size, src->pointer_depth, src->pointed_size, src->array_dimensions, src->pointer_depth > 0 ? src->pointed_is_unsigned : src->is_unsigned);
-                    
-                    postfix_copy_lvalue_size = index_step_size (elem_size);
-                    postfix_copy_lvalue_tag_name = src->is_array ? (src->tag_name ? src->tag_name : src->pointed_tag_name) : src->pointed_tag_name;
-                
-                }
-                
-                emit_apply_postfix_member_access_to_reg_now (reg);
-                postfix_copy_lvalue_tag_name = 0;
-                
-                if (!postfix_member_seen && emit_store_assignment_to_aggregate_address_now (reg, elem_size, name_start, name_caret, name_line)) {
-                
-                    free (name);
-                    return;
-                
-                }
-                
-                if (!postfix_member_seen && saw_subscript && elem_size > (DATA_PTR & 0x1f)) {
-                
-                    postfix_member_seen = 1;
-                    postfix_member_pointer_depth = 0;
-                    postfix_member_pointed_size = elem_size;
-                    postfix_member_size = elem_size;
-                    postfix_member_is_floating = src->is_floating;
-                    postfix_member_is_unsigned = src->is_unsigned;
-                
-                }
-                
-                if (postfix_member_seen) {
-                    set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
-                } else {
-                    set_rhs_last_pointer_info (src->pointer_depth > 0 ? src->pointer_depth - 1 : 0, src->pointed_size);
-                }
-                
-                free (name);
-                return;
-            
-            }
-            
-            if (find_global_symbol (name) >= 0) {
-            
-                int saw_subscript;
-                int elem_size;
-                
-                {
-                
-                    elem_size = get_global_symbol_array (name) ?
-                        (get_global_symbol_pointer_depth (name) ? DATA_PTR :
-                            (get_global_symbol_array_element_size (name) > 0 ? get_global_symbol_array_element_size (name) : get_global_symbol_pointed_size (name))) :
-                                (get_global_symbol_pointer_depth (name) > 1 ? DATA_PTR : get_global_symbol_pointed_size (name));
-                    
-                    if (get_global_symbol_array (name) && get_global_symbol_pointer_depth (name) == 0 && elem_size <= (DATA_PTR & 0x1f)) {
-                    
-                        int aggregate_elem_size = aggregate_tag_size_or_zero (get_global_symbol_tag_name (name));
-                        
-                        if (aggregate_elem_size > (DATA_PTR & 0x1f)) {
-                            elem_size = aggregate_elem_size;
-                        }
-                    
-                    }
-                    
-                    if (get_global_symbol_array (name)) {
-                        emit_load_symbol_address_to_reg_now (reg, name, 0, 0);
-                    } else {
-                        emit_load_global_to_reg (reg, name, DATA_PTR);
-                    }
-                    
-                    saw_subscript = emit_parse_postfix_subscripts_to_reg_dims_now (reg, elem_size, get_global_symbol_pointer_depth (name), get_global_symbol_pointed_size (name), get_global_symbol_array_dimensions (name), get_global_symbol_pointer_depth (name) > 0 ? get_global_symbol_pointed_is_unsigned (name) : get_global_symbol_unsigned (name));
-                    
-                    postfix_copy_lvalue_size = index_step_size (elem_size);
-                    postfix_copy_lvalue_tag_name = get_global_symbol_array (name) ? get_global_symbol_tag_name (name) : 0;
-                
-                }
-                
-                emit_apply_postfix_member_access_to_reg_now (reg);
-                postfix_copy_lvalue_tag_name = 0;
-                
-                if (!postfix_member_seen && emit_store_assignment_to_aggregate_address_now (reg, elem_size, name_start, name_caret, name_line)) {
-                
-                    free (name);
-                    return;
-                
-                }
-                
-                if (!postfix_member_seen && saw_subscript && elem_size > (DATA_PTR & 0x1f)) {
-                
-                    postfix_member_seen = 1;
-                    postfix_member_pointer_depth = 0;
-                    postfix_member_pointed_size = elem_size;
-                    postfix_member_size = elem_size;
-                    postfix_member_is_floating = get_global_symbol_floating (name);
-                    postfix_member_is_unsigned = get_global_symbol_unsigned (name);
-                
-                }
-                
-                free (name);
-                return;
-            
-            }
-        
-        }
-        
-        if (tok.kind == TOK_LPAREN) {
-        
-            if (!find_local_symbol (name)) {
-                ensure_global_function_symbol (name, name_start, name_caret, name_line);
-            }
-            
-            if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION && get_global_symbol_returns_void (name)) {
-                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "void function '%s' used as a value", name);
-            }
-            
-            emit_call_identifier_to_reg_now (name, reg, name_start, name_caret, name_line);
-            
-            if (tok.kind == TOK_LBRACK) {
-            
-                int subscript_pointer_depth = get_global_symbol_pointer_depth (name);
-                int subscript_elem_size = get_global_symbol_pointed_size (name);
-                
-                if (subscript_elem_size <= 0) {
-                    subscript_elem_size = DATA_INT & 0x1f;
-                }
-                
-                emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, subscript_elem_size);
-                
-                if (is_assignment_operator (tok.kind)) {
-                
-                    enum token_kind assign_op = tok.kind;
-                    
-                    get_token ();
-                    emit_push_reg_now (reg);
-                    
-                    if (assign_op == TOK_ASSIGN) {
-                    
-                        if (subscript_elem_size > (DATA_LLONG & 0x1f)) {
-                        
-                            pending_struct_return_lhs = 0;
-                            pending_struct_return_global_name = 0;
-                            pending_struct_return_stack_address = 1;
-                            pending_struct_return_stack_offset = 0;
-                            
-                            emit_load_assignment_rhs_expression_to_reg (reg);
-                            
-                            pending_struct_return_stack_address = 0;
-                            pending_struct_return_stack_offset = 0;
-                            
-                            emit_pop_reg_now ("edx");
-                            postfix_member_seen = 0;
-                            
-                            return;
-                        
-                        }
-                        
-                        emit_load_assignment_rhs_expression_to_reg (reg);
-                    
-                    } else {
-                    
-                        emit_load_deref_reg_now (reg, subscript_elem_size);
-                        emit_push_reg_now (reg);
-                        
-                        emit_load_assignment_rhs_expression_to_reg ("edx");
-                        emit_pop_reg_now (reg);
-                        
-                        emit_assignment_binary_op (assign_op, 0);
-                    
-                    }
-                    
-                    emit_pop_reg_now ("edx");
-                    emit_store_member_to_addr_reg_now ("edx", 0, reg, subscript_elem_size);
-                    set_rhs_last_pointer_info (0, 0);
-                    
-                    free (name);
-                    return;
-                
-                }
-                
-                emit_load_deref_reg_now (reg, subscript_elem_size);
-                
-                if (subscript_pointer_depth > 0) {
-                    subscript_pointer_depth--;
-                }
-                
-                if (subscript_pointer_depth > 0) {
-                    set_rhs_last_pointer_info (subscript_pointer_depth, subscript_elem_size);
-                } else {
-                    set_rhs_last_pointer_info (0, 0);
-                }
-            
-            }
-            
-            emit_apply_postfix_member_access_to_reg_now (reg);
-            
-            if (postfix_member_seen && tok.kind == TOK_LPAREN) {
-            
-                emit_call_pointer_in_reg_now (reg, reg);
-                
-                set_rhs_last_pointer_info (0, 0);
-                free (name);
-                
-                return;
-            
-            }
-            
-            if (postfix_member_seen) {
-                set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
-            }
-            
-            free (name);
-            return;
-        
-        }
-        
-        if (is_assignment_operator (tok.kind)) {
-        
-            enum token_kind assign_op = tok.kind;
-            struct local_symbol *dst;
-            int global_index;
-            int dst_size;
-            int dst_is_floating;
-            
-            get_token ();
-            
-            dst = find_local_symbol (name);
-            global_index = find_global_symbol (name);
-            
-            if (!dst && global_index < 0) {
-            
-                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-                
-                if (state->ofp) {
-                
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                        fprintf (state->ofp, "    xor %s, %s\n", reg, reg);
-                    } else {
-                        fprintf (state->ofp, "    xorl %%%s, %%%s\n", reg, reg);
-                    }
-                
-                }
-                
-                free (name);
-                return;
-            
-            }
-            
-            dst_size = dst ? dst->size : get_global_symbol_size (name);
-            dst_is_floating = dst ? dst->is_floating : get_global_symbol_floating (name);
-            
-            if (dst_is_floating) {
-            
-                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "floating assignment expression not implemented");
-                skip_balanced_until (TOK_RPAREN, TOK_SEMI, TOK_EOF);
-                
-                free (name);
-                return;
-            
-            }
-            
-            if (dst_size == (DATA_LLONG & 0x1f)) {
-            
-                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "64-bit assignment expression not implemented");
-                skip_balanced_until (TOK_RPAREN, TOK_SEMI, TOK_EOF);
-                
-                free (name);
-                return;
-            
-            }
-            
-            if (assign_op == TOK_ASSIGN) {
-                emit_load_assignment_rhs_expression_to_reg (reg);
-            } else {
-            
-                if (dst) {
-                
-                    if (dst->is_static && dst->static_label) {
-                        emit_load_global_to_reg_ex (reg, dst->static_label, dst->size, dst->is_unsigned);
-                    } else {
-                        emit_load_local_to_reg_ex (reg, dst->offset, dst->size, dst->is_unsigned);
-                    }
-                
-                } else {
-                    emit_load_global_to_reg_ex (reg, name, dst_size, get_global_symbol_unsigned (name));
-                }
-                
-                emit_load_assignment_rhs_expression_to_reg ("edx");
-                
-                if (strcmp (reg, "eax") != 0 && state->ofp) {
-                
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                        fprintf (state->ofp, "    mov eax, %s\n", reg);
-                    } else {
-                        fprintf (state->ofp, "    movl %%%s, %%eax\n", reg);
-                    }
-                
-                }
-                
-                emit_assignment_binary_op (assign_op, dst ? dst->is_unsigned : get_global_symbol_unsigned (name));
-                
-                if (strcmp (reg, "eax") != 0 && state->ofp) {
-                
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                        fprintf (state->ofp, "    mov %s, eax\n", reg);
-                    } else {
-                        fprintf (state->ofp, "    movl %%eax, %%%s\n", reg);
-                    }
-                
-                }
-            
-            }
-            
-            if (dst) {
-            
-                if (dst->is_static && dst->static_label) {
-                    emit_store_reg_to_global (dst->static_label, dst->size, reg);
-                } else {
-                    emit_store_reg_to_local (dst->offset, dst->size, reg);
-                }
-                
-                if (dst->is_array || dst->pointer_depth > 0) {
-                    set_rhs_last_pointer_info (dst->is_array ? 1 : dst->pointer_depth, dst->is_array ? local_array_pointer_step_size (dst) : dst->pointed_size);
-                } else {
-                    clear_rhs_last_pointer_info ();
-                }
-            
-            } else {
-            
-                emit_store_reg_to_global (name, dst_size, reg);
-                
-                if (get_global_symbol_array (name) || get_global_symbol_pointer_depth (name) > 0) {
-                    set_rhs_last_pointer_info (get_global_symbol_array (name) ? 1 : get_global_symbol_pointer_depth (name), get_global_symbol_array (name) ? global_array_pointer_step_size (name) : get_global_symbol_pointed_size (name));
-                } else {
-                    clear_rhs_last_pointer_info ();
-                }
-            
-            }
-            
-            free (name);
-            return;
-        
-        }
-        
-        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-        
-            postfix_incdec = 1;
-            postfix_op = tok.kind;
-            
-            get_token ();
-        
-        }
-        
-        src = find_local_symbol (name);
-        
-        if (postfix_incdec && tok.kind == TOK_LBRACK) {
-        
-            int pointer_depth = 0;
-            int pointed_size = 0;
-            int elem_size = DATA_INT & 0x1f;
-            int is_unsigned = 1;
-            int known = 0;
-            
-            if (src) {
-            
-                known = 1;
-                
-                pointer_depth = src->pointer_depth;
-                pointed_size = src->pointed_size;
-                
-                is_unsigned = src->is_unsigned;
-                
-                if (src->is_static && src->static_label) {
-                    emit_load_global_to_reg (reg, src->static_label, DATA_PTR);
-                } else {
-                    emit_load_local_to_reg (reg, src->offset, DATA_PTR);
-                }
-            
-            } else if (find_global_symbol (name) >= 0) {
-            
-                known = 1;
-                
-                pointer_depth = get_global_symbol_pointer_depth (name);
-                pointed_size = get_global_symbol_pointed_size (name);
-                
-                is_unsigned = get_global_symbol_unsigned (name);
-                emit_load_global_to_reg (reg, name, DATA_PTR);
-            
-            }
-            
-            if (!known) {
-            
-                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-                
-                free (name);
-                return;
-            
-            }
-            
-            if (pointer_depth <= 0) {
-            
-                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "subscripted value is not a pointer");
-                
-                free (name);
-                return;
-            
-            }
-            
-            if (pointer_depth > 1) {
-                elem_size = DATA_PTR & 0x1f;
-            } else if (pointed_size > 0) {
-                elem_size = pointed_size & 0x1f;
-            }
-            
-            emit_push_reg_now (reg);
-            
-            emit_incdec_symbol_now (src, name, postfix_op, name_line, name_start, name_caret);
-            emit_pop_reg_now (reg);
-            
-            emit_parse_postfix_subscript_scaled_address_to_reg_now (reg, elem_size);
-            
-            if (is_assignment_operator (tok.kind)) {
-            
-                enum token_kind assign_op = tok.kind;
-                get_token ();
-                
-                emit_push_reg_now (reg);
-                
-                if (assign_op == TOK_ASSIGN) {
-                    emit_load_assignment_rhs_expression_to_reg (reg);
-                } else {
-                
-                    emit_load_deref_reg_now (reg, elem_size);
-                    emit_push_reg_now (reg);
-                    
-                    emit_load_assignment_rhs_expression_to_reg ("edx");
-                    emit_pop_reg_now (reg);
-                    
-                    emit_assignment_binary_op (assign_op, is_unsigned);
-                
-                }
-                
-                emit_pop_reg_now ("edx");
-                emit_store_reg_to_deref_reg_now ("edx", reg, elem_size);
-                
-                clear_rhs_last_pointer_info ();
-                free (name);
-                
-                return;
-            
-            }
-            
-            emit_load_deref_reg_now (reg, elem_size);
-            
-            if (pointer_depth > 1) {
-                set_rhs_last_pointer_info (pointer_depth - 1, pointed_size);
-            } else {
-                clear_rhs_last_pointer_info ();
-            }
-            
-            free (name);
-            return;
-        
-        }
-        
-        if (src) {
-        
-            if (src->is_array) {
-            
-                if (src->is_static && src->static_label) {
-                    emit_load_address_to_reg_now (reg, src->static_label);
-                } else {
-                    emit_load_local_address_to_reg_now (reg, src->offset);
-                }
-            
-            } else if (tok.kind == TOK_DOT) {
-            
-                if (src->is_static && src->static_label) {
-                    emit_load_address_to_reg_now (reg, src->static_label);
-                } else {
-                    emit_load_local_address_to_reg_now (reg, src->offset);
-                }
-            
-            } else if (src->is_static && src->static_label) {
-                emit_load_global_to_reg_ex (reg, src->static_label, src->size, src->is_unsigned);
-            } else {
-                emit_load_local_to_reg_ex (reg, src->offset, src->size, src->is_unsigned);
-            }
-            
-            if (src->pointer_depth > 0) {
-            
-                /*
-                 * Keep the pointed-to aggregate information even when the
-                 * arrow is not immediately visible.  Macro expansions commonly
-                 * parenthesize pointer operands, e.g. ((unknown)->type).
-                 * The inner expression sees ')' after 'unknown', and the
-                 * outer parenthesized path sees the later '->'.  If we clear
-                 * the tag here, that later member lookup falls back to an
-                 * unrelated member named 'type' and emits offset 0 instead of
-                 * the struct cpp_unknown offset.
-                 */
-                postfix_copy_lvalue_size = src->pointed_size;
-                postfix_copy_lvalue_tag_name = src->pointed_tag_name;
-            
-            } else {
-            
-                postfix_copy_lvalue_size = src->size;
-                postfix_copy_lvalue_tag_name = src->tag_name;
-            
-            }
-            
-            emit_apply_postfix_member_access_to_reg_now (reg);
-            
-            if (postfix_member_seen && tok.kind == TOK_LPAREN) {
-            
-                emit_call_pointer_in_reg_now (reg, reg);
-                
-                set_rhs_last_pointer_info (0, 0);
-                free (name);
-                
-                return;
-            
-            }
-            
-            if (emit_store_assignment_to_postfix_member_now (reg)) {
-            
-                set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
-                
-                free (name);
-                return;
-            
-            }
-            
-            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-            
-                postfix_incdec = 1;
-                postfix_op = tok.kind;
-                
-                get_token ();
-            
-            }
-            
-            if (postfix_incdec) {
-            
-                if (postfix_member_seen) {
-                    emit_apply_postfix_member_incdec_now (reg, postfix_op);
-                } else {
-                
-                    emit_push_reg_now (reg);
-                    emit_incdec_symbol_now (src, name, postfix_op, name_line, name_start, name_caret);
-                    emit_pop_reg_now (reg);
-                
-                }
-            
-            }
-            
-            if (postfix_member_seen) {
-                set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
-            } else {
-                set_rhs_last_pointer_info (src->is_array ? 1 : src->pointer_depth, src->is_array ? local_array_pointer_step_size (src) : src->pointed_size);
-            }
-            
-            free (name);
-            return;
-        
-        }
-        
-        if (find_global_symbol (name) >= 0) {
-        
-            if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION ||
-                get_global_symbol_array (name) ||
-                (!get_global_symbol_pointer_depth (name) &&
-                    get_global_symbol_size (name) > (DATA_PTR & 0x1f)) ||
-                tok.kind == TOK_DOT) {
-                emit_load_address_to_reg_now (reg, name);
-            } else {
-                emit_load_global_to_reg_ex (reg, name, get_global_symbol_size (name), get_global_symbol_unsigned (name));
-            }
-            
-            if (tok.kind == TOK_ARROW && get_global_symbol_pointer_depth (name) > 0) {
-            
-                postfix_copy_lvalue_size = get_global_symbol_pointed_size (name);
-                postfix_copy_lvalue_tag_name = get_global_symbol_tag_name (name);
-            
-            } else {
-            
-                postfix_copy_lvalue_size = get_global_symbol_size (name);
-                postfix_copy_lvalue_tag_name = get_global_symbol_tag_name (name);
-            
-            }
-            
-            emit_apply_postfix_member_access_to_reg_now (reg);
-            
-            if (postfix_member_seen && tok.kind == TOK_LPAREN) {
-            
-                emit_call_pointer_in_reg_now (reg, reg);
-                
-                set_rhs_last_pointer_info (0, 0);
-                free (name);
-                
-                return;
-            
-            }
-            
-            if (emit_store_assignment_to_postfix_member_now (reg)) {
-            
-                set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
-                
-                free (name);
-                return;
-            
-            }
-            
-            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-            
-                postfix_incdec = 1;
-                postfix_op = tok.kind;
-                
-                get_token ();
-            
-            }
-            
-            if (postfix_incdec) {
-            
-                if (postfix_member_seen) {
-                    emit_apply_postfix_member_incdec_now (reg, postfix_op);
-                } else {
-                
-                    emit_push_reg_now (reg);
-                    emit_incdec_symbol_now (0, name, postfix_op, name_line, name_start, name_caret);
-                    emit_pop_reg_now (reg);
-                
-                }
-            
-            }
-            
-            if (postfix_member_seen) {
-                set_rhs_last_pointer_info (postfix_member_pointer_depth, postfix_member_pointed_size);
-            } else {
-                set_rhs_last_pointer_info (get_global_symbol_array (name) ? 1 : get_global_symbol_pointer_depth (name), get_global_symbol_array (name) ? global_array_pointer_step_size (name) : get_global_symbol_pointed_size (name));
-            }
-            
-            free (name);
-            return;
-        
-        }
-        
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-        free (name);
-        
-        if (state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                fprintf (state->ofp, "    xor %s, %s\n", reg, reg);
-            } else {
-                fprintf (state->ofp, "    xorl %%%s, %%%s\n", reg, reg);
-            }
-        
-        }
-        
-        return;
-    
-    }
-    
-    if (recover_unknown_rhs_identifier ()) {
-    
-        if (state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                fprintf (state->ofp, "    xor %s, %s\n", reg, reg);
-            } else {
-                fprintf (state->ofp, "    xorl %%%s, %%%s\n", reg, reg);
-            }
-        
-        }
-        
-        return;
-    
-    }
-    
-    {
-    
-        int64_s v = const64_from_current_operand ();
-        
-        if (state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                fprintf (state->ofp, "    mov %s, %lu\n", reg, v.low & U32_MASK);
-            } else {
-                fprintf (state->ofp, "    movl $%lu, %%%s\n", v.low & U32_MASK, reg);
-            }
-        
-        }
-    
-    }
-
-}
-
-static int local_array_pointer_step_size (const struct local_symbol *sym) {
-
-    if (!sym || !sym->is_array) {
-        return 0;
-    }
-    
-    if (sym->array_element_size > 0) {
-        return index_step_size (sym->array_element_size);
-    }
-    
-    if (sym->pointed_size > 0 && sym->pointed_size < sym->size) {
-        return index_step_size (sym->pointed_size);
-    }
-    
-    return index_step_size (sym->size);
-
-}
-
-static int global_array_pointer_step_size (const char *name) {
-
-    long count;
-    int pointed_size;
-    
-    if (!name || !get_global_symbol_array (name)) {
-        return 0;
-    }
-    
-    if (get_global_symbol_array_element_size (name) > 0) {
-        return get_global_symbol_array_element_size (name);
-    }
-    
-    count = get_global_symbol_array_count (name);
-    
-    if (count > 0) {
-        return (int) (get_global_symbol_size (name) / count);
-    }
-    
-    pointed_size = get_global_symbol_pointed_size (name);
-    
-    if (pointed_size > 0 && pointed_size < get_global_symbol_size (name)) {
-        return index_step_size (pointed_size);
-    }
-    
-    return index_step_size (get_global_symbol_size (name));
-
-}
-
-static void emit_scale_reg_by_const_now (const char *reg, int scale) {
-
-    if (!state->ofp || scale <= 1) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-        fprintf (state->ofp, "    imul %s, %d\n", reg, scale);
-    } else {
-        fprintf (state->ofp, "    imull $%d, %%%s, %%%s\n", scale, reg, reg);
-    }
-
-}
-
-static void emit_divide_eax_by_const_now (int divisor) {
-
-    if (!state->ofp || divisor <= 1) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        fprintf (state->ofp, "    mov ecx, %d\n", divisor);
-        fprintf (state->ofp, "    cdq\n");
-        fprintf (state->ofp, "    idiv ecx\n");
-    
-    } else {
-    
-        fprintf (state->ofp, "    movl $%d, %%ecx\n", divisor);
-        fprintf (state->ofp, "    cdq\n");
-        fprintf (state->ofp, "    idivl %%ecx\n");
-    
-    }
-
-}
-
-static void emit_assignment_binary_op (enum token_kind op, int is_unsigned) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        switch (op) {
-        
-            case TOK_PLUS:      case TOK_PLUSEQ:
-            
-                fprintf (state->ofp, "    add eax, edx\n");
-                break;
-            
-            case TOK_MINUS:     case TOK_MINUSEQ:
-            
-                fprintf (state->ofp, "    sub eax, edx\n");
-                break;
-            
-            case TOK_STAR:      case TOK_STAREQ:
-            
-                fprintf (state->ofp, "    imul eax, edx\n");
-                break;
-            
-            case TOK_BSLASH:    case TOK_SLASHEQ:
-            
-                fprintf (state->ofp, "    mov ecx, edx\n");
-                
-                if (is_unsigned) {
-                
-                    fprintf (state->ofp, "    xor edx, edx\n");
-                    fprintf (state->ofp, "    div ecx\n");
-                
-                } else {
-                
-                    fprintf (state->ofp, "    cdq\n");
-                    fprintf (state->ofp, "    idiv ecx\n");
-                
-                }
-                
-                break;
-            
-            case TOK_MOD:
-            
-                fprintf (state->ofp, "    mov ecx, edx\n");
-                
-                if (is_unsigned) {
-                
-                    fprintf (state->ofp, "    xor edx, edx\n");
-                    fprintf (state->ofp, "    div ecx\n");
-                
-                } else {
-                
-                    fprintf (state->ofp, "    cdq\n");
-                    fprintf (state->ofp, "    idiv ecx\n");
-                
-                }
-                
-                fprintf (state->ofp, "    mov eax, edx\n");
-                break;
-            
-            case TOK_MODEQ:
-            
-                fprintf (state->ofp, "    mov ecx, edx\n");
-                
-                if (is_unsigned) {
-                
-                    fprintf (state->ofp, "    xor edx, edx\n");
-                    fprintf (state->ofp, "    div ecx\n");
-                
-                } else {
-                
-                    fprintf (state->ofp, "    cdq\n");
-                    fprintf (state->ofp, "    idiv ecx\n");
-                
-                }
-                
-                fprintf (state->ofp, "    mov eax, edx\n");
-                break;
-            
-            case TOK_AMPER:     case TOK_ANDEQ:
-            
-                fprintf (state->ofp, "    and eax, edx\n");
-                break;
-            
-            case TOK_PIPE:      case TOK_OREQ:
-            
-                fprintf (state->ofp, "    or eax, edx\n");
-                break;
-            
-            case TOK_CARET:     case TOK_XOREQ:
-            
-                fprintf (state->ofp, "    xor eax, edx\n");
-                break;
-            
-            case TOK_LSH:       case TOK_LSHEQ:
-            
-                fprintf (state->ofp, "    mov ecx, edx\n");
-                fprintf (state->ofp, "    shl eax, cl\n");
-                
-                break;
-            
-            case TOK_RSH:       case TOK_RSHEQ:
-            
-                fprintf (state->ofp, "    mov ecx, edx\n");
-                fprintf (state->ofp, is_unsigned ? "    shr eax, cl\n" : "    sar eax, cl\n");
-                
-                break;
-            
-            default:
-            
-                break;
-        
-        }
-    
-    } else {
-    
-        switch (op) {
-        
-            case TOK_PLUS:      case TOK_PLUSEQ:
-            
-                fprintf (state->ofp, "    addl %%edx, %%eax\n");
-                break;
-            
-            case TOK_MINUS:     case TOK_MINUSEQ:
-            
-                fprintf (state->ofp, "    subl %%edx, %%eax\n");
-                break;
-            
-            case TOK_STAR:      case TOK_STAREQ:
-            
-                fprintf (state->ofp, "    imull %%edx, %%eax\n");
-                break;
-            
-            case TOK_BSLASH:    case TOK_SLASHEQ:
-            
-                fprintf (state->ofp, "    movl %%edx, %%ecx\n");
-                
-                if (is_unsigned) {
-                
-                    fprintf (state->ofp, "    xorl %%edx, %%edx\n");
-                    fprintf (state->ofp, "    divl %%ecx\n");
-                
-                } else {
-                
-                    fprintf (state->ofp, "    cdq\n");
-                    fprintf (state->ofp, "    idivl %%ecx\n");
-                
-                }
-                
-                break;
-            
-            case TOK_MOD:
-            
-                fprintf (state->ofp, "    movl %%edx, %%ecx\n");
-                
-                if (is_unsigned) {
-                
-                    fprintf (state->ofp, "    xorl %%edx, %%edx\n");
-                    fprintf (state->ofp, "    divl %%ecx\n");
-                
-                } else {
-                
-                    fprintf (state->ofp, "    cdq\n");
-                    fprintf (state->ofp, "    idivl %%ecx\n");
-                
-                }
-                
-                fprintf (state->ofp, "    movl %%edx, %%eax\n");
-                break;
-            
-            case TOK_MODEQ:
-            
-                fprintf (state->ofp, "    movl %%edx, %%ecx\n");
-                
-                if (is_unsigned) {
-                
-                    fprintf (state->ofp, "    xorl %%edx, %%edx\n");
-                    fprintf (state->ofp, "    divl %%ecx\n");
-                
-                } else {
-                
-                    fprintf (state->ofp, "    cdq\n");
-                    fprintf (state->ofp, "    idivl %%ecx\n");
-                
-                }
-                
-                fprintf (state->ofp, "    movl %%edx, %%eax\n");
-                break;
-            
-            case TOK_AMPER:     case TOK_ANDEQ:
-            
-                fprintf (state->ofp, "    andl %%edx, %%eax\n");
-                break;
-            
-            case TOK_PIPE:      case TOK_OREQ:
-            
-                fprintf (state->ofp, "    orl %%edx, %%eax\n");
-                break;
-            
-            case TOK_CARET:     case TOK_XOREQ:
-            
-                fprintf (state->ofp, "    xorl %%edx, %%eax\n");
-                break;
-            
-            case TOK_LSH:       case TOK_LSHEQ:
-            
-                fprintf (state->ofp, "    movl %%edx, %%ecx\n");
-                fprintf (state->ofp, "    sall %%cl, %%eax\n");
-                
-                break;
-            
-            case TOK_RSH:       case TOK_RSHEQ:
-            
-                fprintf (state->ofp, "    movl %%edx, %%ecx\n");
-                fprintf (state->ofp, is_unsigned ? "    shrl %%cl, %%eax\n" : "    sarl %%cl, %%eax\n");
-                
-                break;
-            
-            default:
-            
-                break;
-        
-        }
-    
-    }
-
-}
-
-static int token_is_floating_constant_now (void) {
-    return tok.kind == TOK_CFLOAT || tok.kind == TOK_CDOUBLE || tok.kind == TOK_CLDOUBLE;
-}
-
-static int64_s floating_constant_to_bits_now (int size) {
-
-    int64_s r;
-    
-    unsigned long bits32;
-    unsigned char bytes[8];
-    
-    int i;
-    
-    r.low = 0;
-    r.high = 0;
-    
-    if (size == (DATA_FLOAT & 0x1f)) {
-    
-        float f;
-        
-        if (tok.kind == TOK_CFLOAT) {
-            f = tok.val.f;
-        } else if (tok.kind == TOK_CLDOUBLE) {
-            f = (double) tok.val.ld;
-        } else {
-            f = tok.val.d;
-        }
-        
-        memcpy (&bits32, &f, sizeof (f));
-        
-        r.low = bits32;
-        get_token ();
-        
-        return r;
-    
-    }
-    
-    {
-    
-        double d;
-        
-        if (tok.kind == TOK_CFLOAT) {
-            d = (double) tok.val.f;
-        } else if (tok.kind == TOK_CLDOUBLE) {
-            d = (double) tok.val.ld;
-        } else {
-            d = tok.val.d;
-        }
-        
-        memset (bytes, 0, sizeof (bytes));
-        memcpy (bytes, &d, sizeof (d));
-        
-        for (i = 0; i < 4; i++) {
-            r.low |= ((unsigned long) bytes[i]) << (i * 8);
-        }
-        
-        for (i = 0; i < 4; i++) {
-            r.high |= ((unsigned long) bytes[i + 4]) << (i * 8);
-        }
-        
-        get_token ();
-        return r;
-    
-    }
-
-}
-
-static double floating_constant_to_ld_now (void) {
-
-    double v;
-    
-    if (tok.kind == TOK_CFLOAT) {
-        v = (float) tok.val.f;
-    } else if (tok.kind == TOK_CLDOUBLE) {
-        v = (double) tok.val.ld;
-    } else {
-        v = tok.val.d;
-    }
-    
-    get_token ();
-    return v;
-
-}
-
-static double int64_u32_base_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;
-
-}
-
-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)) {
-        return parse_floating_const_primary_now ();
-    }
-    
-    if (_accept (TOK_MINUS)) {
-        return -parse_floating_const_primary_now ();
-    }
-    
-    if (token_is_floating_constant_now ()) {
-        return floating_constant_to_ld_now ();
-    }
-    
-    iv = const64_from_current_operand ();
-    return int64_to_double_now (iv);
-
-}
-
-static double parse_floating_const_term_now (void) {
-
-    double rhs, v;
-    enum token_kind op;
-    
-    v = parse_floating_const_primary_now ();
-    
-    while (tok.kind == TOK_STAR || tok.kind == TOK_BSLASH) {
-    
-        op = tok.kind;
-        get_token ();
-        
-        rhs = parse_floating_const_primary_now ();
-        
-        if (op == TOK_STAR) {
-            v *= rhs;
-        } else {
-            v /= rhs;
-        }
-    
-    }
-    
-    return v;
-
-}
-
-static double parse_floating_const_expr_value_now (void) {
-
-    double rhs, v;
-    enum token_kind op;
-    
-    v = parse_floating_const_term_now ();
-    
-    while (tok.kind == TOK_PLUS || tok.kind == TOK_MINUS) {
-    
-        op = tok.kind;
-        get_token ();
-        
-        rhs = parse_floating_const_term_now ();
-        
-        if (op == TOK_PLUS) {
-            v += rhs;
-        } else {
-            v -= rhs;
-        }
-    
-    }
-    
-    return v;
-
-}
-
-static int64_s parse_floating_const_expr_bits_now (int size) {
-
-    double acc;
-    int64_s r;
-    
-    acc = parse_floating_const_expr_value_now ();
-    r.low = 0;
-    r.high = 0;
-    
-    if (size == (DATA_FLOAT & 0x1f)) {
-    
-        float f;
-        unsigned long bits32;
-        
-        f = (float) acc;
-        bits32 = 0;
-        memcpy (&bits32, &f, sizeof (f));
-        r.low = bits32;
-        return r;
-    
-    }
-    
-    {
-    
-        unsigned char bytes[8];
-        
-        double d = (double) acc;
-        int i;
-        
-        memset (bytes, 0, sizeof (bytes));
-        memcpy (bytes, &d, sizeof (d));
-        
-        for (i = 0; i < 4; i++) {
-            r.low |= ((unsigned long) bytes[i]) << (i * 8);
-        }
-        
-        for (i = 0; i < 4; i++) {
-            r.high |= ((unsigned long) bytes[i + 4]) << (i * 8);
-        }
-        
-        return r;
-    
-    }
-
-}
-
-static void emit_load_floating_const_bits_now (int size, int64_s v) {
-
-    int lab;
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    lab = anon_label++;
-    
-    if (state->syntax & ASM_SYNTAX_MASM) {
-    
-        switch_section (SECTION_DATA);
-        
-        if (size == (DATA_DOUBLE & 0x1f)) {
-        
-            /*
-             * 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 0%08lXh\n", lab, v.low & U32_MASK);
-        }
-        
-        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) {
-        
-            switch_section (SECTION_DATA);
-            
-            fprintf (state->ofp, "LC%d_flt:\n", lab);
-            fprintf (state->ofp, "    dd %lu\n", v.low & U32_MASK);
-            
-            if (size == (DATA_DOUBLE & 0x1f)) {
-                fprintf (state->ofp, "    dd %lu\n", v.high & U32_MASK);
-            }
-            
-            switch_section (SECTION_TEXT);
-            fprintf (state->ofp, "    fld %s [LC%d_flt]\n", size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", lab);
-        
-        } else {
-        
-            switch_section (SECTION_DATA);
-            
-            fprintf (state->ofp, ".LC%d_flt:\n", lab);
-            fprintf (state->ofp, "    .long %lu\n", v.low & U32_MASK);
-            
-            if (size == (DATA_DOUBLE & 0x1f)) {
-                fprintf (state->ofp, "    .long %lu\n", v.high & U32_MASK);
-            }
-            
-            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);
-            } else {
-                fprintf (state->ofp, "    fld%s .LC%d_flt\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", lab);
-            }
-        
-        }
-    
-    }
-
-}
-
-static void emit_load_floating_symbol_now (struct local_symbol *sym, const char *name, int size) {
-
-    char memref[64];
-    const char *label;
-    const char *asm_name;
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    asm_name = asm_global_symbol_name (name);
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (sym) {
-        
-            if (sym->is_static && sym->static_label) {
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fld %s [%s]\n" : "    fld %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", sym->static_label);
-            } else {
-            
-                format_intel_ebp_offset (memref, sizeof (memref), sym->offset);
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fld %s %s\n" : "    fld %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", memref);
-            
-            }
-        
-        } else {
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fld %s [%s]\n" : "    fld %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", asm_name);
-        }
-    
-    } else {
-    
-        if (sym) {
-        
-            label = (sym->is_static && sym->static_label) ? sym->static_label : 0;
-            
-            if (label) {
-                fprintf (state->ofp, "    fld%s %s\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", label);
-            } else {
-                fprintf (state->ofp, "    fld%s %ld(%%ebp)\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", sym->offset);
-            }
-        
-        } else {
-            fprintf (state->ofp, "    fld%s %s\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", asm_name);
-        }
-    
-    }
-
-}
-
-static void emit_load_floating_member_symbol_now (struct local_symbol *sym, const char *name, int offset, int size) {
-
-    char memref[64];
-    char labelref[256];
-    
-    const char *label;
-    const char *asm_name;
-    const char *opsize;
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    opsize = size == (DATA_FLOAT & 0x1f) ? "dword" : "qword";
-    asm_name = asm_global_symbol_name (name);
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (sym) {
-        
-            if (sym->is_static && sym->static_label) {
-            
-                if (offset) {
-                
-                    sprintf (labelref, "%s + %d", sym->static_label, offset);
-                    label = labelref;
-                
-                } else {
-                    label = sym->static_label;
-                }
-                
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fld %s %s\n" : "    fld %s ptr %s\n"), opsize, label);
-            
-            } else {
-            
-                format_intel_ebp_offset (memref, sizeof (memref), sym->offset + offset);
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fld %s %s\n" : "    fld %s ptr %s\n"), opsize, memref);
-            
-            }
-        
-        } else {
-        
-            if (offset) {
-            
-                sprintf (labelref, "%s + %d", asm_name, offset);
-                label = labelref;
-            
-            } else {
-                label = asm_name;
-            }
-            
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fld %s %s\n" : "    fld %s ptr %s\n"), opsize, label);
-        
-        }
-    
-    } else {
-    
-        if (sym) {
-        
-            label = (sym->is_static && sym->static_label) ? sym->static_label : 0;
-            
-            if (label) {
-            
-                if (offset) {
-                
-                    sprintf (labelref, "%s+%d", label, offset);
-                    label = labelref;
-                
-                }
-                
-                fprintf (state->ofp, "    fld%s %s\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", label);
-            
-            } else {
-                fprintf (state->ofp, "    fld%s %ld(%%ebp)\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", sym->offset + offset);
-            }
-        
-        } else {
-        
-            if (offset) {
-            
-                sprintf (labelref, "%s+%d", asm_name, offset);
-                asm_name = labelref;
-            
-            }
-            
-            fprintf (state->ofp, "    fld%s %s\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", asm_name);
-        
-        }
-    
-    }
-
-}
-
-static void emit_duplicate_floating_stack_top_now (void) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_NASM) {
-        fprintf (state->ofp, "    fld st0\n");
-    } else if (state->syntax & ASM_SYNTAX_INTEL) {
-        fprintf (state->ofp, "    fld st(0)\n");
-    } else {
-        fprintf (state->ofp, "    fld %%st(0)\n");
-    }
-
-}
-
-static void emit_store_floating_symbol_now (struct local_symbol *sym, const char *name, int size) {
-
-    char memref[64];
-    const char *label;
-    const char *asm_name;
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    asm_name = asm_global_symbol_name (name);
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (sym) {
-        
-            if (sym->is_static && sym->static_label) {
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fstp %s %s\n" : "    fstp %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", sym->static_label);
-            } else {
-            
-                format_intel_ebp_offset (memref, sizeof (memref), sym->offset);
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fstp %s %s\n" : "    fstp %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", memref);
-            
-            }
-        
-        } else {
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fstp %s %s\n" : "    fstp %s ptr %s\n"), size == (DATA_DOUBLE & 0x1f) ? "qword" : "dword", asm_name);
-        }
-    
-    } else {
-    
-        if (sym) {
-        
-            label = (sym->is_static && sym->static_label) ? sym->static_label : 0;
-            
-            if (label) {
-                fprintf (state->ofp, "    fstp%s %s\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", label);
-            } else {
-                fprintf (state->ofp, "    fstp%s %ld(%%ebp)\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", sym->offset);
-            }
-        
-        } else {
-            fprintf (state->ofp, "    fstp%s %s\n", size == (DATA_DOUBLE & 0x1f) ? "l" : "s", asm_name);
-        }
-    
-    }
-
-}
-
-static void emit_load_any_symbol_as_floating_now (struct local_symbol *src, const char *name, int size, int is_floating) {
-
-    if (is_floating) {
-    
-        emit_load_floating_symbol_now (src, name, size);
-        return;
-    
-    }
-    
-    if (src) {
-    
-        if (src->is_static && src->static_label) {
-            emit_load_global_to_reg_ex ("eax", src->static_label, src->size, src->is_unsigned);
-        } else {
-            emit_load_local_to_reg_ex ("eax", src->offset, src->size, src->is_unsigned);
-        }
-    
-    } else {
-        emit_load_global_to_reg_ex ("eax", name, size, get_global_symbol_unsigned (name));
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        fprintf (state->ofp, "    sub esp, 4\n");
-        
-        if (state->syntax & ASM_SYNTAX_NASM) {
-        
-            fprintf (state->ofp, "    mov dword [esp], eax\n");
-            fprintf (state->ofp, "    fild dword [esp]\n");
-        
-        } else {
-        
-            fprintf (state->ofp, "    mov dword ptr [esp], eax\n");
-            fprintf (state->ofp, "    fild dword ptr [esp]\n");
-        
-        }
-        
-        fprintf (state->ofp, "    add esp, 4\n");
-    
-    } else {
-    
-        fprintf (state->ofp, "    subl $4, %%esp\n");
-        fprintf (state->ofp, "    movl %%eax, (%%esp)\n");
-        fprintf (state->ofp, "    fildl (%%esp)\n");
-        fprintf (state->ofp, "    addl $4, %%esp\n");
-    
-    }
-
-}
-
-static int emit_load_floating_prefix_incdec_now (void) {
-
-    enum token_kind op;
-    char *name;
-    
-    const char *name_start, *name_caret;
-    unsigned long name_line;
-    
-    struct local_symbol *sym;
-    int size;
-    int is_floating;
-    
-    if (!parse_incdec_identifier_now (&op, &name, &name_start, &name_caret, &name_line)) {
-        return 0;
-    }
-    
-    if (!name) {
-        return 1;
-    }
-    
-    sym = find_local_symbol (name);
-    emit_incdec_symbol_now (sym, name, op, name_line, name_start, name_caret);
-    
-    if (sym) {
-    
-        size = sym->size;
-        is_floating = sym->is_floating;
-        
-        emit_load_any_symbol_as_floating_now (sym, name, size, is_floating);
-    
-    } else if (find_global_symbol (name) >= 0) {
-    
-        size = get_global_symbol_size (name);
-        is_floating = get_global_symbol_floating (name);
-        
-        emit_load_any_symbol_as_floating_now (0, name, size, is_floating);
-    
-    }
-    
-    free (name);
-    return 1;
-
-}
-
-static void emit_load_floating_rhs_expression_now (int result_size);
-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);
-static void emit_statement_jump (int label);
-
-static void emit_eax_bool_to_floating_stack_now (void) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        fprintf (state->ofp, "    sub esp, 4\n");
-        
-        if (state->syntax & ASM_SYNTAX_NASM) {
-        
-            fprintf (state->ofp, "    mov dword [esp], eax\n");
-            fprintf (state->ofp, "    fild dword [esp]\n");
-        
-        } else {
-        
-            fprintf (state->ofp, "    mov dword ptr [esp], eax\n");
-            fprintf (state->ofp, "    fild dword ptr [esp]\n");
-        
-        }
-        
-        fprintf (state->ofp, "    add esp, 4\n");
-    
-    } else {
-    
-        fprintf (state->ofp, "    subl $4, %%esp\n");
-        fprintf (state->ofp, "    movl %%eax, (%%esp)\n");
-        fprintf (state->ofp, "    fildl (%%esp)\n");
-        fprintf (state->ofp, "    addl $4, %%esp\n");
-    
-    }
-    
-    floating_rhs_result_in_eax_bool = 0;
-
-}
-
-static const char *floating_compare_true_setcc_now (enum token_kind op) {
-
-    switch (op) {
-    
-        case TOK_LESS:
-        
-            return "setb";
-        
-        case TOK_LTEQ:
-        
-            return "setbe";
-        
-        case TOK_GREATER:
-        
-            return "seta";
-        
-        case TOK_GTEQ:
-        
-            return "setae";
-        
-        case TOK_EQEQ:
-        
-            return "sete";
-        
-        case TOK_NOTEQ:
-        
-            return "setne";
-        
-        default:
-        
-            return "setz";
-    
-    }
-
-}
-
-static void emit_floating_compare_to_eax_now (enum token_kind op) {
-
-    const char *setcc;
-    
-    if (!state->ofp) {
-    
-        floating_rhs_result_in_eax_bool = 1;
-        return;
-    
-    }
-    
-    setcc = floating_compare_true_setcc_now (op);
-    
-    if (state->syntax & ASM_SYNTAX_NASM) {
-    
-        fprintf (state->ofp, "    fxch st1\n");
-        fprintf (state->ofp, "    fcompp\n");
-        fprintf (state->ofp, "    fnstsw ax\n");
-        fprintf (state->ofp, "    sahf\n");
-        fprintf (state->ofp, "    %s al\n", setcc);
-        fprintf (state->ofp, "    movzx eax, al\n");
-    
-    } else if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        fprintf (state->ofp, "    fxch st(1)\n");
-        fprintf (state->ofp, "    fcompp\n");
-        fprintf (state->ofp, "    fnstsw ax\n");
-        fprintf (state->ofp, "    sahf\n");
-        fprintf (state->ofp, "    %s al\n", setcc);
-        fprintf (state->ofp, "    movzx eax, al\n");
-    
-    } else {
-    
-        fprintf (state->ofp, "    fxch %%st(1)\n");
-        fprintf (state->ofp, "    fcompp\n");
-        fprintf (state->ofp, "    fnstsw %%ax\n");
-        fprintf (state->ofp, "    sahf\n");
-        fprintf (state->ofp, "    %s %%al\n", setcc);
-        fprintf (state->ofp, "    movzbl %%al, %%eax\n");
-    
-    }
-    
-    floating_rhs_result_in_eax_bool = 1;
-
-}
-
-static void emit_fild_eax_now (void) {
-
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        fprintf (state->ofp, "    sub esp, 4\n");
-        
-        if (state->syntax & ASM_SYNTAX_NASM) {
-        
-            fprintf (state->ofp, "    mov dword [esp], eax\n");
-            fprintf (state->ofp, "    fild dword [esp]\n");
-        
-        } else {
-        
-            fprintf (state->ofp, "    mov dword ptr [esp], eax\n");
-            fprintf (state->ofp, "    fild dword ptr [esp]\n");
-        
-        }
-        
-        fprintf (state->ofp, "    add esp, 4\n");
-    
-    } else {
-    
-        fprintf (state->ofp, "    subl $4, %%esp\n");
-        fprintf (state->ofp, "    movl %%eax, (%%esp)\n");
-        fprintf (state->ofp, "    fildl (%%esp)\n");
-        fprintf (state->ofp, "    addl $4, %%esp\n");
-    
-    }
-
-}
-
-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) {
-    
-        enum token_kind unary_op = tok.kind;
-        get_token ();
-        
-        emit_load_floating_rhs_operand_now (result_size);
-        
-        if (unary_op == TOK_MINUS) {
-            fprintf (state->ofp, "    fchs\n");
-        }
-        
-        return;
-    
-    }
-    
-    if (tok.kind == TOK_STAR) {
-    
-        int deref_size = result_size;
-        int deref_is_floating = 1;
-        
-        get_token ();
-        
-        if (tok.kind == TOK_LPAREN) {
-        
-            get_token ();
-            
-            if (is_type_start (tok.kind) && parse_deref_cast_type_name (&deref_size)) {
-            
-                emit_load_any_deref_as_floating_now ("eax", deref_size, last_deref_cast_type_is_floating);
-                return;
-            
-            }
-            
-            emit_load_assignment_rhs_expression_to_reg ("eax");
-            expect (TOK_RPAREN, ")");
-            
-            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");
-        
-        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;
-    
-    }
-    
-    if (_accept (TOK_LPAREN)) {
-    
-        if (token_starts_type_name ()) {
-        
-            int cast_size = 0;
-            int cast_is_unsigned = 0;
-            int cast_is_pointer = 0;
-            
-            if (parse_cast_type_name (&cast_size, &cast_is_unsigned, &cast_is_pointer)) {
-            
-                if (!cast_is_pointer && !last_cast_type_is_floating) {
-                
-                    if (rhs_current_operand_is_floating_now ()) {
-                    
-                        emit_load_floating_rhs_operand_now (result_size);
-                        
-                        if (floating_rhs_result_in_eax_bool) {
-                        
-                            emit_extend_pair_high_from_low ("eax", "edx", cast_size, cast_is_unsigned);
-                            floating_rhs_result_in_eax_bool = 0;
-                        
-                        } else {
-                            emit_floating_stack_to_int_pair_now ("eax", "edx");
-                        }
-                        
-                        if ((cast_size & 0x1f) != (DATA_LLONG & 0x1f)) {
-                            emit_extend_pair_high_from_low ("eax", "edx", cast_size, cast_is_unsigned);
-                        }
-                    
-                    } else {
-                        emit_load_assignment_rhs_to_pair ("eax", "edx");
-                    }
-                    
-                    emit_integer_pair_to_floating_stack_now ("eax", "edx", cast_size);
-                    return;
-                
-                }
-                
-                emit_load_floating_rhs_operand_now (result_size);
-                return;
-            
-            }
-        
-        }
-        
-        emit_load_floating_rhs_expression_now (result_size);
-        expect (TOK_RPAREN, ")");
-        
-        if (floating_rhs_result_in_eax_bool && tok.kind != TOK_QMARK) {
-            emit_eax_bool_to_floating_stack_now ();
-        }
-        
-        return;
-    
-    }
-    
-    if (emit_load_floating_prefix_incdec_now ()) {
-        return;
-    }
-    
-    if (token_is_sizeof_keyword ()) {
-    
-        int64_s v = sizeof_from_current_token ();
-        
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-        
-            fprintf (state->ofp, "    sub esp, 4\n");
-            
-            if (state->syntax & ASM_SYNTAX_NASM) {
-                
-                fprintf (state->ofp, "    mov dword [esp], %lu\n", v.low & U32_MASK);
-                fprintf (state->ofp, "    fild dword [esp]\n");
-            
-            } else {
-            
-                fprintf (state->ofp, "    mov dword ptr [esp], %lu\n", v.low & U32_MASK);
-                fprintf (state->ofp, "    fild dword ptr [esp]\n");
-            
-            }
-            
-            fprintf (state->ofp, "    add esp, 4\n");
-        
-        } else {
-        
-            fprintf (state->ofp, "    subl $4, %%esp\n");
-            fprintf (state->ofp, "    movl $%lu, (%%esp)\n", v.low & U32_MASK);
-            fprintf (state->ofp, "    fildl (%%esp)\n");
-            fprintf (state->ofp, "    addl $4, %%esp\n");
-        
-        }
-        
-        return;
-    
-    }
-    
-    if (tok.kind == TOK_SCC_BUILTIN_VA_ARG) {
-    
-        int va_size = DATA_DOUBLE & 0x1f;
-        int va_unsigned = 0;
-        int va_pointer = 0;
-        int va_floating = 0;
-        
-        get_token ();
-        
-        emit_parse_builtin_va_arg_address_to_reg_now ("eax", &va_size, &va_unsigned, &va_pointer, &va_floating);
-        emit_load_floating_deref_reg_now ("eax", va_size);
-        
-        return;
-    
-    }
-    
-    if (tok.kind == TOK_IDENT) {
-    
-        char *name = xstrdup (tok.ident);
-        
-        const char *name_start = tok.start, *name_caret = tok.caret;
-        unsigned long name_line = get_line_number ();
-        
-        struct local_symbol *src = find_local_symbol (name);
-        get_token ();
-        
-        if (strcmp (name, "__scc_builtin_va_arg") == 0 && tok.kind == TOK_LPAREN) {
-        
-            int va_size = DATA_DOUBLE & 0x1f;
-            int va_unsigned = 0;
-            int va_pointer = 0;
-            int va_floating = 0;
-            
-            emit_parse_builtin_va_arg_address_to_reg_now ("eax", &va_size, &va_unsigned, &va_pointer, &va_floating);
-            emit_load_floating_deref_reg_now ("eax", va_size);
-            
-            free (name);
-            return;
-        
-        }
-        
-        if (is_assignment_operator (tok.kind)) {
-        
-            enum token_kind assign_op = tok.kind;
-            
-            int dst_size = 0;
-            int dst_is_floating = 0;
-            int have_dst = 0;
-            
-            if (src) {
-            
-                dst_size = src->size;
-                
-                dst_is_floating = src->is_floating;
-                have_dst = 1;
-            
-            } else if (find_global_symbol (name) >= 0) {
-            
-                dst_size = get_global_symbol_size (name);
-                
-                dst_is_floating = get_global_symbol_floating (name);
-                have_dst = 1;
-            
-            }
-            
-            if (have_dst && dst_is_floating && floating_assignment_operator_supported_now (assign_op)) {
-            
-                get_token ();
-                
-                if (assign_op == TOK_ASSIGN) {
-                    emit_load_floating_rhs_expression_now (dst_size);
-                } else {
-                
-                    emit_load_floating_symbol_now (src, name, dst_size);
-                    emit_load_floating_rhs_expression_now (dst_size);
-                    
-                    emit_floating_binary_now (assign_op);
-                
-                }
-                
-                emit_duplicate_floating_stack_top_now ();
-                emit_store_floating_symbol_now (src, name, dst_size);
-                
-                free (name);
-                return;
-            
-            }
-        
-        }
-        
-        if (tok.kind == TOK_LPAREN) {
-        
-            if (!find_local_symbol (name)) {
-                ensure_global_function_symbol (name, name_start, name_caret, name_line);
-            }
-            
-            if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION && get_global_symbol_returns_void (name)) {
-                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "void function '%s' used as a value", name);
-            }
-            
-            emit_call_identifier_to_reg_now (name, "eax", name_start, name_caret, name_line);
-            
-            if (!get_global_function_returns_floating (name)) {
-            
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                
-                    fprintf (state->ofp, "    sub esp, 4\n");
-                    
-                    if (state->syntax & ASM_SYNTAX_NASM) {
-                    
-                        fprintf (state->ofp, "    mov dword [esp], eax\n");
-                        fprintf (state->ofp, "    fild dword [esp]\n");
-                    
-                    } else {
-                    
-                        fprintf (state->ofp, "    mov dword ptr [esp], eax\n");
-                        fprintf (state->ofp, "    fild dword ptr [esp]\n");
-                    
-                    }
-                    
-                    fprintf (state->ofp, "    add esp, 4\n");
-                
-                } else {
-                
-                    fprintf (state->ofp, "    subl $4, %%esp\n");
-                    fprintf (state->ofp, "    movl %%eax, (%%esp)\n");
-                    fprintf (state->ofp, "    fildl (%%esp)\n");
-                    fprintf (state->ofp, "    addl $4, %%esp\n");
-                
-                }
-            
-            }
-            
-            free (name);
-            return;
-        
-        }
-        
-        if (tok.kind == TOK_LBRACK && (src || find_global_symbol (name) >= 0)) {
-        
-            int elem_size;
-            int pointer_depth;
-            int pointed_size;
-            
-            if (src) {
-            
-                elem_size = src->is_array ?
-                    (src->pointer_depth ? DATA_PTR : (src->array_element_size > 0 ? src->array_element_size : src->pointed_size)) :
-                    (src->pointer_depth > 1 ? DATA_PTR : src->pointed_size);
-                
-                pointer_depth = src->pointer_depth;
-                pointed_size = src->pointed_size;
-                
-                if (src->is_array) {
-                
-                    if (src->is_static && src->static_label) {
-                        emit_load_symbol_address_to_reg_now ("eax", src->static_label, 0, 0);
-                    } else {
-                        emit_load_symbol_address_to_reg_now ("eax", 0, src->offset, 1);
-                    }
-                
-                } else if (src->is_static && src->static_label) {
-                    emit_load_global_to_reg ("eax", src->static_label, DATA_PTR);
-                } else {
-                    emit_load_local_to_reg ("eax", src->offset, DATA_PTR);
-                }
-            
-            } else {
-            
-                elem_size = get_global_symbol_array (name) ?
-                    (get_global_symbol_pointer_depth (name) ? DATA_PTR :
-                        (get_global_symbol_array_element_size (name) > 0 ? get_global_symbol_array_element_size (name) : get_global_symbol_pointed_size (name))) :
-                    (get_global_symbol_pointer_depth (name) > 1 ? DATA_PTR : get_global_symbol_pointed_size (name));
-                
-                pointer_depth = get_global_symbol_pointer_depth (name);
-                pointed_size = get_global_symbol_pointed_size (name);
-                
-                if (get_global_symbol_array (name)) {
-                    emit_load_symbol_address_to_reg_now ("eax", name, 0, 0);
-                } else {
-                    emit_load_global_to_reg ("eax", name, DATA_PTR);
-                }
-            
-            }
-            
-            if (elem_size <= 0) {
-                elem_size = DATA_INT & 0x1f;
-            }
-            
-            emit_parse_postfix_subscripts_to_reg_now ("eax", elem_size, pointer_depth, pointed_size);
-            
-            if ((elem_size & 0x1f) > DATA_PTR) {
-                emit_load_floating_deref_reg_now ("eax", elem_size);
-            } else {
-                emit_fild_eax_now ();
-            }
-            
-            free (name);
-            return;
-        
-        }
-        
-        if (tok.kind == TOK_ARROW && (src || find_global_symbol (name) >= 0)) {
-        
-            char *member;
-            
-            const char *member_start;
-            const char *member_caret;
-            
-            unsigned long member_line;
-            
-            int member_offset = 0;
-            int member_size = result_size;
-            int member_elem_size = result_size;
-            int member_pointer_depth = 0;
-            int member_is_array = 0;
-            int member_is_floating = 0;
-            int base_size;
-            
-            const char *base_tag_name;
-            
-            if (src) {
-            
-                base_size = src->pointed_size;
-                base_tag_name = src->pointed_tag_name;
-            
-            } else {
-            
-                base_size = get_global_symbol_pointed_size (name);
-                base_tag_name = get_global_symbol_tag_name (name);
-            
-            }
-            
-            get_token ();
-            
-            member_start = tok.start;
-            member_caret = tok.caret;
-            member_line = get_line_number ();
-            
-            if (tok.kind != TOK_IDENT) {
-            
-                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after ->");
-                
-                free (name);
-                return;
-            
-            }
-            
-            member = xstrdup (tok.ident);
-            get_token ();
-            
-            if (!find_member_info_ex_bounded (member, base_size, base_tag_name, &member_offset, &member_size, &member_elem_size, &member_pointer_depth, &member_is_array, &member_is_floating)) {
-            
-                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
-                
-                free (member);
-                free (name);
-                
-                return;
-            
-            }
-            
-            free (member);
-            
-            if (src) {
-            
-                if (src->is_static && src->static_label) {
-                    emit_load_global_to_reg ("eax", src->static_label, DATA_PTR & 0x1f);
-                } else {
-                    emit_load_local_to_reg ("eax", src->offset, DATA_PTR & 0x1f);
-                }
-            
-            } else {
-                emit_load_global_to_reg ("eax", name, DATA_PTR & 0x1f);
-            }
-            
-            if (member_is_floating) {
-                emit_load_floating_member_from_addr_reg_now ("eax", member_offset, member_size);
-            } else {
-            
-                emit_load_member_from_addr_reg_now ("eax", "eax", member_offset, member_size);
-                emit_eax_bool_to_floating_stack_now ();
-            
-            }
-            
-            free (name);
-            return;
-        
-        }
-        
-        if (tok.kind == TOK_DOT && (src || find_global_symbol (name) >= 0)) {
-        
-            char *member;
-            
-            const char *member_start;
-            const char *member_caret;
-            const char *current_tag_name;
-            
-            unsigned long member_line;
-            
-            int member_offset = 0;
-            int member_size = result_size;
-            int member_elem_size = result_size;
-            int member_pointer_depth = 0;
-            int member_is_array = 0;
-            int member_is_floating = 0;
-            int current_size;
-            
-            if (src) {
-            
-                current_size = src->size;
-                current_tag_name = src->tag_name;
-            
-            } else {
-            
-                current_size = get_global_symbol_size (name);
-                current_tag_name = get_global_symbol_tag_name (name);
-            
-            }
-            
-            get_token ();
-            
-            member_start = tok.start;
-            member_caret = tok.caret;
-            member_line = get_line_number ();
-            
-            if (tok.kind != TOK_IDENT) {
-            
-                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after .");
-                
-                free (name);
-                return;
-            
-            }
-            
-            member = xstrdup (tok.ident);
-            get_token ();
-            
-            if (!find_member_info_ex_bounded (member, current_size, current_tag_name, &member_offset, &member_size, &member_elem_size, &member_pointer_depth, &member_is_array, &member_is_floating)) {
-            
-                report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
-                
-                free (member);
-                free (name);
-                
-                return;
-            
-            }
-            
-            free (member);
-            
-            if (tok.kind != TOK_DOT && tok.kind != TOK_ARROW && member_is_floating) {
-            
-                emit_load_floating_member_symbol_now (src, name, member_offset, member_size);
-                
-                free (name);
-                return;
-            
-            }
-            
-            emit_load_symbol_address_for_copy_now ("eax", src, name);
-            emit_add_const_to_reg_now ("eax", member_offset);
-            
-            current_tag_name = last_found_member_tag_name;
-            
-            if (member_pointer_depth > 0 || member_is_array) {
-                current_size = member_elem_size;
-            } else {
-                current_size = member_size;
-            }
-            
-            while (tok.kind == TOK_DOT || tok.kind == TOK_ARROW) {
-            
-                enum token_kind member_op = tok.kind;
-                
-                get_token ();
-                
-                member_start = tok.start;
-                member_caret = tok.caret;
-                member_line = get_line_number ();
-                
-                if (tok.kind != TOK_IDENT) {
-                
-                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
-                    
-                    free (name);
-                    return;
-                
-                }
-                
-                member = xstrdup (tok.ident);
-                get_token ();
-                
-                if (!find_member_info_ex_bounded (member, current_size, current_tag_name, &member_offset, &member_size, &member_elem_size, &member_pointer_depth, &member_is_array, &member_is_floating)) {
-                
-                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
-                    
-                    free (member);
-                    free (name);
-                    
-                    return;
-                
-                }
-                
-                free (member);
-                
-                if (member_op == TOK_ARROW) {
-                    emit_load_deref_reg_now ("eax", DATA_PTR & 0x1f);
-                }
-                
-                emit_add_const_to_reg_now ("eax", member_offset);
-                
-                current_tag_name = last_found_member_tag_name;
-                
-                if (member_pointer_depth > 0 || member_is_array) {
-                    current_size = member_elem_size;
-                } else {
-                    current_size = member_size;
-                }
-            
-            }
-            
-            if (member_is_floating) {
-                emit_load_floating_member_from_addr_reg_now ("eax", 0, member_size);
-            } else {
-            
-                emit_load_deref_reg_now ("eax", member_size);
-                emit_eax_bool_to_floating_stack_now ();
-            
-            }
-            
-            free (name);
-            return;
-        
-        }
-        
-        if (src) {
-        
-            if (src->is_floating) {
-                emit_load_floating_symbol_now (src, name, src->size);
-            } else {
-            
-                if (src->is_static && src->static_label) {
-                    emit_load_global_to_reg_ex ("eax", src->static_label, src->size, src->is_unsigned);
-                } else {
-                    emit_load_local_to_reg_ex ("eax", src->offset, src->size, src->is_unsigned);
-                }
-                
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                
-                    fprintf (state->ofp, "    sub esp, 4\n");
-                    
-                    if (state->syntax & ASM_SYNTAX_NASM) {
-                    
-                        fprintf (state->ofp, "    mov dword [esp], eax\n");
-                        fprintf (state->ofp, "    fild dword [esp]\n");
-                    
-                    } else {
-                    
-                        fprintf (state->ofp, "    mov dword ptr [esp], eax\n");
-                        fprintf (state->ofp, "    fild dword ptr [esp]\n");
-                    
-                    }
-                    
-                    fprintf (state->ofp, "    add esp, 4\n");
-                
-                } else {
-                
-                    fprintf (state->ofp, "    subl $4, %%esp\n");
-                    fprintf (state->ofp, "    movl %%eax, (%%esp)\n");
-                    fprintf (state->ofp, "    fildl (%%esp)\n");
-                    fprintf (state->ofp, "    addl $4, %%esp\n");
-                
-                }
-            
-            }
-            
-            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-            
-                enum token_kind postfix_op = tok.kind;
-                get_token ();
-                
-                emit_incdec_symbol_now (src, name, postfix_op, name_line, name_start, name_caret);
-            
-            }
-            
-            free (name);
-            return;
-        
-        }
-        
-        if (find_global_symbol (name) >= 0) {
-        
-            if (get_global_symbol_floating (name)) {
-                emit_load_floating_symbol_now (0, name, get_global_symbol_size (name));
-            } else {
-            
-                emit_load_global_to_reg_ex ("eax", name, get_global_symbol_size (name), get_global_symbol_unsigned (name));
-                
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                
-                    fprintf (state->ofp, "    sub esp, 4\n");
-                    
-                    if (state->syntax & ASM_SYNTAX_NASM) {
-                    
-                        fprintf (state->ofp, "    mov dword [esp], eax\n");
-                        fprintf (state->ofp, "    fild dword [esp]\n");
-                    
-                    } else {
-                    
-                        fprintf (state->ofp, "    mov dword ptr [esp], eax\n");
-                        fprintf (state->ofp, "    fild dword ptr [esp]\n");
-                    
-                    }
-                    
-                    fprintf (state->ofp, "    add esp, 4\n");
-                
-                } else {
-                
-                    fprintf (state->ofp, "    subl $4, %%esp\n");
-                    fprintf (state->ofp, "    movl %%eax, (%%esp)\n");
-                    fprintf (state->ofp, "    fildl (%%esp)\n");
-                    fprintf (state->ofp, "    addl $4, %%esp\n");
-                
-                }
-            
-            }
-            
-            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-            
-                enum token_kind postfix_op = tok.kind;
-                get_token ();
-                
-                emit_incdec_symbol_now (0, name, postfix_op, name_line, name_start, name_caret);
-            
-            }
-            
-            free (name);
-            return;
-        
-        }
-        
-        free (name);
-    
-    }
-    
-    if (token_is_floating_constant_now ()) {
-    
-        emit_load_floating_const_bits_now (result_size, floating_constant_to_bits_now (result_size));
-        return;
-    
-    }
-    
-    if (recover_unknown_rhs_identifier ()) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-            fprintf (state->ofp, "    fldz\n");
-        } else {
-            fprintf (state->ofp, "    fldz\n");
-        }
-        return;
-    
-    }
-    
-    {
-    
-        int64_s v = const64_from_current_operand ();
-        
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-        
-            fprintf (state->ofp, "    sub esp, 4\n");
-            
-            if (state->syntax & ASM_SYNTAX_NASM) {
-            
-                fprintf (state->ofp, "    mov dword [esp], %lu\n", v.low & U32_MASK);
-                fprintf (state->ofp, "    fild dword [esp]\n");
-            
-            } else {
-            
-                fprintf (state->ofp, "    mov dword ptr [esp], %lu\n", v.low & U32_MASK);
-                fprintf (state->ofp, "    fild dword ptr [esp]\n");
-            
-            }
-            
-            fprintf (state->ofp, "    add esp, 4\n");
-        
-        } else {
-        
-            fprintf (state->ofp, "    subl $4, %%esp\n");
-            fprintf (state->ofp, "    movl $%lu, (%%esp)\n", v.low & U32_MASK);
-            fprintf (state->ofp, "    fildl (%%esp)\n");
-            fprintf (state->ofp, "    addl $4, %%esp\n");
-        
-        }
-    
-    }
-
-}
-
-static int token_is_floating_binary_now (enum token_kind k) {
-    return k == TOK_PLUS || k == TOK_MINUS || k == TOK_STAR || k == TOK_BSLASH;
-}
-
-static void emit_floating_binary_now (enum token_kind k) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    switch (k) {
-    
-        case TOK_PLUS:      case TOK_PLUSEQ:
-        
-            fprintf (state->ofp, "    faddp\n");
-            break;
-        
-        case TOK_MINUS:     case TOK_MINUSEQ:
-        
-            fprintf (state->ofp, "    fsubrp\n");
-            break;
-        
-        case TOK_STAR:      case TOK_STAREQ:
-        
-            fprintf (state->ofp, "    fmulp\n");
-            break;
-        
-        case TOK_BSLASH:    case TOK_SLASHEQ:
-        
-            fprintf (state->ofp, "    fdivrp\n");
-            break;
-        
-        default:
-        
-            break;
-    
-    }
-
-}
-
-static void emit_scale_reg_for_pointer_compound_assignment_now (const char *reg, struct local_symbol *lhs, const char *name, enum token_kind op) {
-
-    int pointer_depth;
-    int pointed_size;
-    int elem_size;
-    
-    if (op != TOK_PLUSEQ && op != TOK_MINUSEQ) {
-        return;
-    }
-    
-    pointer_depth = lhs ? lhs->pointer_depth : get_global_symbol_pointer_depth (name);
-    pointed_size = lhs ? lhs->pointed_size : get_global_symbol_pointed_size (name);
-    
-    if (pointer_depth <= 0) {
-        return;
-    }
-    
-    elem_size = pointer_depth > 1 ? DATA_PTR : pointed_size;
-    
-    if (elem_size > 1) {
-        emit_scale_reg_by_const_now (reg, elem_size);
-    }
-
-}
-
-static int floating_assignment_operator_supported_now (enum token_kind op) {
-    return op == TOK_ASSIGN || op == TOK_PLUSEQ || op == TOK_MINUSEQ || op == TOK_STAREQ || op == TOK_SLASHEQ;
-}
-
-static void emit_load_floating_rhs_expression_now (int result_size) {
-
-    enum token_kind op;
-    
-    int false_label;
-    int end_label;
-    
-    floating_rhs_result_in_eax_bool = 0;
-    emit_load_floating_rhs_operand_now (result_size);
-    
-    while (token_is_floating_binary_now (tok.kind)) {
-    
-        if (floating_rhs_result_in_eax_bool) {
-            emit_eax_bool_to_floating_stack_now ();
-        }
-        
-        op = tok.kind;
-        get_token ();
-        
-        emit_load_floating_rhs_operand_now (result_size);
-        
-        if (floating_rhs_result_in_eax_bool) {
-            emit_eax_bool_to_floating_stack_now ();
-        }
-        
-        emit_floating_binary_now (op);
-    
-    }
-    
-    if (is_value_compare_operator (tok.kind)) {
-    
-        op = tok.kind;
-        get_token ();
-        
-        emit_load_floating_rhs_operand_now (result_size);
-        
-        while (token_is_floating_binary_now (tok.kind)) {
-        
-            enum token_kind rhs_op = tok.kind;
-            get_token ();
-            
-            emit_load_floating_rhs_operand_now (result_size);
-            emit_floating_binary_now (rhs_op);
-        
-        }
-        
-        emit_floating_compare_to_eax_now (op);
-    
-    }
-    
-    if (tok.kind == TOK_QMARK) {
-    
-        false_label = anon_label++;
-        end_label = anon_label++;
-        
-        if (!floating_rhs_result_in_eax_bool) {
-        
-            if (state->ofp) {
-            
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                
-                    fprintf (state->ofp, "    sub esp, 4\n");
-                    
-                    if (state->syntax & ASM_SYNTAX_NASM) {
-                    
-                        fprintf (state->ofp, "    fstp dword [esp]\n");
-                        fprintf (state->ofp, "    mov eax, dword [esp]\n");
-                    
-                    } else {
-                    
-                        fprintf (state->ofp, "    fstp dword ptr [esp]\n");
-                        fprintf (state->ofp, "    mov eax, dword ptr [esp]\n");
-                    
-                    }
-                    
-                    fprintf (state->ofp, "    add esp, 4\n");
-                    fprintf (state->ofp, "    test eax, eax\n");
-                
-                } else {
-                
-                    fprintf (state->ofp, "    subl $4, %%esp\n");
-                    fprintf (state->ofp, "    fstps (%%esp)\n");
-                    fprintf (state->ofp, "    movl (%%esp), %%eax\n");
-                    fprintf (state->ofp, "    addl $4, %%esp\n");
-                    fprintf (state->ofp, "    testl %%eax, %%eax\n");
-                
-                }
-            
-            }
-        
-        } else if (state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                fprintf (state->ofp, "    test eax, eax\n");
-            } else {
-                fprintf (state->ofp, "    testl %%eax, %%eax\n");
-            }
-        
-        }
-        
-        if (state->ofp) {
-        
-            if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
-                fprintf (state->ofp, "    jz L%d\n", false_label);
-            } else {
-                fprintf (state->ofp, "    jz .L%d\n", false_label);
-            }
-        
-        }
-        
-        floating_rhs_result_in_eax_bool = 0;
-        get_token ();
-        
-        emit_load_floating_rhs_expression_now (result_size);
-        expect (TOK_COLON, ":");
-        
-        emit_statement_jump (end_label);
-        emit_statement_label (false_label);
-        
-        emit_load_floating_rhs_expression_now (result_size);
-        emit_statement_label (end_label);
-        
-        floating_rhs_result_in_eax_bool = 0;
-    
-    }
-
-}
-
-static void emit_load_assignment_rhs_expression_to_reg (const char *reg);
-
-static int current_argument_is_bare_identifier_now (void) {
-
-    const char *p;
-    
-    if (tok.kind != TOK_IDENT || !tok.caret) {
-        return 0;
-    }
-    
-    p = tok.caret + tok.len;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    return *p == ',' || *p == ')';
-
-}
-
-static int emit_push_aggregate_argument_now (const char *name, struct local_symbol *sym) {
-
-    int size;
-    int offset;
-    int chunk;
-    
-    char memref[64];
-    
-    if (!name || !sym || sym->is_array || sym->pointer_depth > 0 || sym->is_floating) {
-        return 0;
-    }
-    
-    /**
-     * Struct/union locals keep their real byte size here.  Masking with
-     * 0x1f is only valid for scalar DATA_* encodings; it turns e.g. a
-     * 72-byte struct cpu_flags argument into an 8-byte argument.
-     */
-    size = sym->size;
-    
-    /*
-     * Do not treat plain 64-bit scalar locals as aggregate arguments.
-     * The old test used only size > 4, so a call such as:
-     *
-     *     bytearray_write_4_bytes (..., result, endianess)
-     *
-     * where result is uint_fast64_t/address_type pushed both halves of
-     * result.  The callee expects an unsigned long here, so the extra high
-     * word shifted the following arguments and pdld wrote broken relocation
-     * bytes.  Real structs/unions either carry an aggregate tag here, or are
-     * larger than the built-in long long scalar size.
-     */
-    if (size <= (DATA_PTR & 0x1f) || (size <= (DATA_LLONG & 0x1f) && !sym->tag_name)) {
-        return 0;
-    }
-    
-    if (!state->ofp) {
-        return 1;
-    }
-    
-    for (offset = size; offset > 0; ) {
-    
-        if (offset >= 4) {
-        
-            chunk = 4;
-            offset -= 4;
-        
-        } else if (offset >= 2) {
-        
-            chunk = 2;
-            offset -= 2;
-        
-        } else {
-        
-            chunk = 1;
-            offset -= 1;
-        
-        }
-        
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-        
-            if (sym->is_static && sym->static_label) {
-            
-                if (chunk == 4) {
-                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    push dword [%s + %d]\n" : "    push dword ptr %s + %d\n"), asm_global_symbol_name (sym->static_label), offset);
-                } else if (chunk == 2) {
-                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movzx eax, word [%s + %d]\n" : "    movzx eax, word ptr %s + %d\n"), asm_global_symbol_name (sym->static_label), offset); fprintf (state->ofp, "    push eax\n");
-                } else {
-                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movzx eax, byte [%s + %d]\n" : "    movzx eax, byte ptr %s + %d\n"), asm_global_symbol_name (sym->static_label), offset); fprintf (state->ofp, "    push eax\n");
-                }
-            
-            } else {
-            
-                format_intel_ebp_offset (memref, sizeof (memref), sym->offset + offset);
-                
-                if (chunk == 4) {
-                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    push dword %s\n" : "    push dword ptr %s\n"), memref);
-                } else if (chunk == 2) {
-                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movzx eax, word %s\n" : "    movzx eax, word ptr %s\n"), memref); fprintf (state->ofp, "    push eax\n");
-                } else {
-                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    movzx eax, byte %s\n" : "    movzx eax, byte ptr %s\n"), memref); fprintf (state->ofp, "    push eax\n");
-                }
-            
-            }
-        
-        } else {
-        
-            if (sym->is_static && sym->static_label) {
-            
-                if (chunk == 4) {
-                    fprintf (state->ofp, "    pushl %s+%d\n", asm_global_symbol_name (sym->static_label), offset);
-                } else if (chunk == 2) {
-                    fprintf (state->ofp, "    movzwl %s+%d, %%eax\n", asm_global_symbol_name (sym->static_label), offset); fprintf (state->ofp, "    pushl %%eax\n");
-                } else {
-                    fprintf (state->ofp, "    movzbl %s+%d, %%eax\n", asm_global_symbol_name (sym->static_label), offset); fprintf (state->ofp, "    pushl %%eax\n");
-                }
-            
-            } else {
-            
-                if (chunk == 4) {
-                    fprintf (state->ofp, "    pushl %ld(%%ebp)\n", sym->offset + offset);
-                } else if (chunk == 2) {
-                    fprintf (state->ofp, "    movzwl %ld(%%ebp), %%eax\n", sym->offset + offset); fprintf (state->ofp, "    pushl %%eax\n");
-                } else {
-                    fprintf (state->ofp, "    movzbl %ld(%%ebp), %%eax\n", sym->offset + offset); fprintf (state->ofp, "    pushl %%eax\n");
-                }
-            
-            }
-        
-        }
-    
-    }
-    
-    return 1;
-
-}
-
-static int emit_push_global_aggregate_argument_now (const char *name) {
-
-    int size;
-    int offset;
-    int chunk;
-
-    if (!name || get_global_symbol_kind (name) != GLOBAL_SYMBOL_OBJECT ||
-        get_global_symbol_array (name) || get_global_symbol_pointer_depth (name) > 0 ||
-        get_global_symbol_floating (name)) {
-        return 0;
-    }
-    
-    size = get_global_symbol_size (name);
-    
-    if (size <= (DATA_PTR & 0x1f)) {
-        return 0;
-    }
-    
-    if (!state->ofp) {
-        return 1;
-    }
-    
-    for (offset = size; offset > 0; ) {
-    
-        if (offset >= 4) {
-        
-            chunk = 4;
-            offset -= 4;
-        
-        } else if (offset >= 2) {
-        
-            chunk = 2;
-            offset -= 2;
-        
-        } else {
-        
-            chunk = 1;
-            offset -= 1;
-        
-        }
-        
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-        
-            if (chunk == 4) {
-            
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ?
-                    "    push dword [%s + %d]\n" :
-                    "    push dword ptr %s + %d\n"), asm_global_symbol_name (name), offset);
-            
-            } else if (chunk == 2) {
-            
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ?
-                    "    movzx eax, word [%s + %d]\n" :
-                    "    movzx eax, word ptr %s + %d\n"), asm_global_symbol_name (name), offset);
-                fprintf (state->ofp, "    push eax\n");
-            
-            } else {
-            
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ?
-                    "    movzx eax, byte [%s + %d]\n" :
-                    "    movzx eax, byte ptr %s + %d\n"), asm_global_symbol_name (name), offset);
-                fprintf (state->ofp, "    push eax\n");
-            
-            }
-        
-        } else {
-        
-            if (chunk == 4) {
-                fprintf (state->ofp, "    pushl %s+%d\n", asm_global_symbol_name (name), offset);
-            } else if (chunk == 2) {
-            
-                fprintf (state->ofp, "    movzwl %s+%d, %%eax\n", asm_global_symbol_name (name), offset);
-                fprintf (state->ofp, "    pushl %%eax\n");
-            
-            } else {
-            
-                fprintf (state->ofp, "    movzbl %s+%d, %%eax\n", asm_global_symbol_name (name), offset);
-                fprintf (state->ofp, "    pushl %%eax\n");
-            
-            }
-        
-        }
-    
-    }
-    
-    return 1;
-
-}
-
-static void emit_call_pointer_in_reg_now (const char *fn_reg, const char *result_reg) {
-
-    enum token_kind saved_calling_convention = postfix_member_calling_convention;
-    
-    int argc = 0;
-    int total_arg_bytes = 0;
-    int arg_bytes;
-    int arg_is_floating;
-    int i;
-    int ch;
-    
-    FILE **arg_tmp_ofps = 0;
-    FILE **new_arg_tmp_ofps = 0;
-    FILE *arg_saved_ofp = 0;
-    FILE *arg_tmp_ofp = 0;
-    
-    if (tok.kind != TOK_LPAREN) {
-        return;
-    }
-    
-    if (state->ofp) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-            fprintf (state->ofp, "    push %s\n", fn_reg);
-        } else {
-            fprintf (state->ofp, "    pushl %%%s\n", fn_reg);
-        }
-    
-    }
-    
-    get_token ();
-    
-    if (tok.kind != TOK_RPAREN) {
-    
-        for (;;) {
-        
-            arg_saved_ofp = 0;
-            arg_tmp_ofp = 0;
-            
-            if (state->ofp) {
-            
-                arg_tmp_ofp = scc_tmpfile ();
-                
-                if (arg_tmp_ofp) {
-                
-                    arg_saved_ofp = state->ofp;
-                    state->ofp = arg_tmp_ofp;
-                
-                }
-            
-            }
-            
-            postfix_member_seen = 0;
-            postfix_member_size = 0;
-            postfix_member_pointer_depth = 0;
-            postfix_member_pointed_size = 0;
-            
-            if (tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && find_local_symbol (tok.ident) && emit_push_aggregate_argument_now (tok.ident, find_local_symbol (tok.ident))) {
-            
-                struct local_symbol *arg_sym = find_local_symbol (tok.ident);
-                
-                arg_bytes = arg_sym ? (arg_sym->size & 0x1f) : DATA_PTR;
-                arg_is_floating = 0;
-                
-                get_token ();
-            
-            } else {
-            
-                arg_is_floating = rhs_current_operand_is_floating_now ();
-                arg_bytes = arg_is_floating ? (DATA_DOUBLE & 0x1f) : DATA_PTR;
-                
-                if (arg_is_floating) {
-                    emit_load_floating_rhs_expression_now (DATA_DOUBLE & 0x1f);
-                } else {
-                    emit_load_assignment_rhs_expression_to_reg ("eax");
-                }
-                
-                if (state->ofp) {
-                
-                    if (!arg_is_floating && postfix_member_seen && postfix_member_pointer_depth == 0 && postfix_member_size > (DATA_PTR & 0x1f)) {
-                    
-                        arg_bytes = postfix_member_size;
-                        emit_push_aggregate_from_addr_reg_now ("eax", arg_bytes);
-                    
-                    } else if (!arg_is_floating && postfix_member_size > (DATA_PTR & 0x1f)) {
-                    
-                        arg_bytes = postfix_member_size;
-                        emit_push_aggregate_from_addr_reg_now ("eax", arg_bytes);
-                    
-                    } else if (arg_is_floating) {
-                    
-                        if (state->syntax & ASM_SYNTAX_INTEL) {
-                        
-                            fprintf (state->ofp, "    sub esp, 8\n");
-                            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fstp qword [esp]\n" : "    fstp qword ptr [esp]\n"));
-                        
-                        } else {
-                        
-                            fprintf (state->ofp, "    subl $8, %%esp\n");
-                            fprintf (state->ofp, "    fstpl (%%esp)\n");
-                        
-                        }
-                    
-                    } else {
-                    
-                        if (state->syntax & ASM_SYNTAX_INTEL) {
-                            fprintf (state->ofp, "    push eax\n");
-                        } else {
-                            fprintf (state->ofp, "    pushl %%eax\n");
-                        }
-                    
-                    }
-                
-                }
-            
-            }
-            
-            total_arg_bytes += arg_bytes;
-            
-            if (arg_saved_ofp) {
-            
-                fflush (arg_tmp_ofp);
-                
-                state->ofp = arg_saved_ofp;
-                new_arg_tmp_ofps = (FILE **) xrealloc (arg_tmp_ofps, sizeof (*arg_tmp_ofps) * (argc + 1));
-                
-                if (new_arg_tmp_ofps) {
-                
-                    arg_tmp_ofps = new_arg_tmp_ofps;
-                    arg_tmp_ofps[argc] = arg_tmp_ofp;
-                    arg_tmp_ofp = 0;
-                
-                }
-            
-            }
-            
-            if (arg_tmp_ofp) {
-            
-                scc_close (arg_tmp_ofp);
-                arg_tmp_ofp = 0;
-            
-            }
-            
-            argc++;
-            
-            if (!_accept (TOK_COMMA)) {
-                break;
-            }
-        
-        }
-    
-    }
-    
-    expect (TOK_RPAREN, ")");
-    
-    if (state->ofp) {
-    
-        for (i = argc - 1; i >= 0; i--) {
-        
-            if (arg_tmp_ofps && arg_tmp_ofps[i]) {
-            
-                fseek (arg_tmp_ofps[i], 0, SEEK_SET);
-                
-                while ((ch = fgetc (arg_tmp_ofps[i])) != EOF) {
-                    fputc (ch, state->ofp);
-                }
-                
-                scc_close (arg_tmp_ofps[i]);
-                arg_tmp_ofps[i] = 0;
-            
-            }
-        
-        }
-        
-        if (arg_tmp_ofps) {
-        
-            free (arg_tmp_ofps);
-            arg_tmp_ofps = 0;
-        
-        }
-        
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-        
-            if (state->syntax & ASM_SYNTAX_NASM) {
-                fprintf (state->ofp, "    mov ecx, dword [esp + %d]\n", total_arg_bytes);
-            } else {
-                fprintf (state->ofp, "    mov ecx, dword ptr [esp + %d]\n", total_arg_bytes);
-            }
-            
-            fprintf (state->ofp, "    call ecx\n");
-            
-            if (saved_calling_convention == TOK_STDCALL) {
-                fprintf (state->ofp, "    add esp, %d\n", (DATA_PTR & 0x1f));
-            } else {
-                fprintf (state->ofp, "    add esp, %d\n", total_arg_bytes + (DATA_PTR & 0x1f));
-            }
-            
-            if (strcmp (result_reg, "eax") != 0) {
-                fprintf (state->ofp, "    mov %s, eax\n", result_reg);
-            }
-        
-        } else {
-        
-            fprintf (state->ofp, "    movl %d(%%esp), %%ecx\n", total_arg_bytes);
-            fprintf (state->ofp, "    call *%%ecx\n");
-            
-            if (saved_calling_convention == TOK_STDCALL) {
-                fprintf (state->ofp, "    addl $%d, %%esp\n", (DATA_PTR & 0x1f));
-            } else {
-                fprintf (state->ofp, "    addl $%d, %%esp\n", total_arg_bytes + (DATA_PTR & 0x1f));
-            }
-            
-            if (strcmp (result_reg, "eax") != 0) {
-                fprintf (state->ofp, "    movl %%eax, %%%s\n", result_reg);
-            }
-        
-        }
-    
-    }
-    
-    if (arg_tmp_ofps) {
-    
-        for (i = 0; i < argc; i++) {
-        
-            if (arg_tmp_ofps[i]) {
-                scc_close (arg_tmp_ofps[i]);
-            }
-        
-        }
-        
-        free (arg_tmp_ofps);
-    
-    }
-
-}
-
-static void emit_sub_esp_now (int bytes) {
-
-    if (!state->ofp || bytes <= 0) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-        fprintf (state->ofp, "    sub esp, %d\n", bytes);
-    } else {
-        fprintf (state->ofp, "    subl $%d, %%esp\n", bytes);
-    }
-
-}
-
-static void emit_push_pending_struct_return_address_now (int stack_arg_bytes) {
-
-    if (!state->ofp || (!pending_struct_return_lhs && !pending_struct_return_global_name && !pending_struct_return_stack_address && !pending_struct_return_stack_top)) {
-        return;
-    }
-    
-    if (pending_struct_return_stack_top) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-        
-            if (state->syntax & ASM_SYNTAX_NASM) {
-                fprintf (state->ofp, "    lea eax, [esp + %d]\n", stack_arg_bytes);
-            } else {
-                fprintf (state->ofp, "    lea eax, dword ptr [esp + %d]\n", stack_arg_bytes);
-            }
-        
-        } else {
-            fprintf (state->ofp, "    leal %d(%%esp), %%eax\n", stack_arg_bytes);
-        }
-    
-    } else if (pending_struct_return_stack_address) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-        
-            if (state->syntax & ASM_SYNTAX_NASM) {
-                fprintf (state->ofp, "    mov eax, dword [esp + %d]\n", stack_arg_bytes);
-            } else {
-                fprintf (state->ofp, "    mov eax, dword ptr [esp + %d]\n", stack_arg_bytes);
-            }
-            
-            if (pending_struct_return_stack_offset) {
-                fprintf (state->ofp, "    add eax, %d\n", pending_struct_return_stack_offset);
-            }
-        
-        } else {
-        
-            fprintf (state->ofp, "    movl %d(%%esp), %%eax\n", stack_arg_bytes);
-            
-            if (pending_struct_return_stack_offset) {
-                fprintf (state->ofp, "    addl $%d, %%eax\n", pending_struct_return_stack_offset);
-            }
-        
-        }
-    
-    } else if (pending_struct_return_lhs) {
-    
-        if (pending_struct_return_lhs->is_static && pending_struct_return_lhs->static_label) {
-            emit_load_address_to_reg_now ("eax", pending_struct_return_lhs->static_label);
-        } else {
-            emit_load_local_address_to_reg_now ("eax", pending_struct_return_lhs->offset);
-        }
-    
-    } else {
-        emit_load_address_to_reg_now ("eax", pending_struct_return_global_name);
-    }
-    
-    emit_push_reg_now ("eax");
-
-}
-
-static int current_argument_is_bare_64bit_identifier_now (void) {
-
-    struct local_symbol *sym;
-    
-    if (tok.kind != TOK_IDENT || !tok.ident || !current_argument_is_bare_identifier_now ()) {
-        return 0;
-    }
-    
-    sym = find_local_symbol (tok.ident);
-    
-    if (sym) {
-        return sym->size == (DATA_LLONG & 0x1f) && !sym->is_floating;
-    }
-    
-    if (find_global_symbol (tok.ident) >= 0) {
-        return get_global_symbol_size (tok.ident) == (DATA_LLONG & 0x1f) && !get_global_symbol_floating (tok.ident);
-    }
-    
-    return 0;
-
-}
-
-static void emit_call_identifier_to_reg_now (const char *name, const char *reg, const char *name_start, const char *name_caret, unsigned long name_line) {
-
-    int argc = 0;
-    int inline_index;
-    int use_inline = 0;
-    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 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;
-    
-    const char *saved_pending_struct_return_global_name = pending_struct_return_global_name;
-    const char *asm_name;
-    
-    int saved_pending_struct_return_stack_address = pending_struct_return_stack_address;
-    int saved_pending_struct_return_stack_offset = pending_struct_return_stack_offset;
-    int saved_pending_struct_return_stack_top = pending_struct_return_stack_top;
-    
-    FILE *inline_saved_ofp = 0;
-    FILE *inline_tmp_ofp = 0;
-    FILE *arg_saved_ofp = 0;
-    FILE *arg_tmp_ofp = 0;
-    FILE **arg_tmp_ofps = 0;
-    FILE **new_arg_tmp_ofps = 0;
-    
-    if (tok.kind != TOK_LPAREN) {
-        return;
-    }
-    
-    inline_index = find_inline_function (name);
-    
-    if (inline_index >= 0 &&
-        inline_functions[inline_index].usable &&
-        !inline_functions[inline_index].is_floating &&
-        !inline_functions[inline_index].expanding &&
-        (inline_functions[inline_index].body || inline_functions[inline_index].returns_void) &&
-        (!inline_functions[inline_index].body || inline_body_stack_delta (inline_functions[inline_index].body) == 0)) {
-    
-        use_inline = 1;
-        expected_inline_args = inline_functions[inline_index].param_count;
-        inline_arg_bytes = expected_inline_args * 4;
-        
-        if (state->ofp) {
-        
-            inline_tmp_ofp = scc_tmpfile ();
-            
-            if (inline_tmp_ofp) {
-            
-                inline_saved_ofp = state->ofp;
-                state->ofp = inline_tmp_ofp;
-            
-            }
-            
-            if (inline_arg_bytes > 0) {
-            
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                    fprintf (state->ofp, "    sub esp, %d\n", inline_arg_bytes);
-                } else {
-                    fprintf (state->ofp, "    subl $%d, %%esp\n", inline_arg_bytes);
-                }
-            
-            }
-        
-        }
-    
-    }
-    
-    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) {
-    
-        for (;;) {
-        
-            arg_saved_ofp = 0;
-            arg_tmp_ofp = 0;
-            
-            /*
-             * cdecl wants the right-most argument nearest the call site and
-             * the left-most argument at [ebp + 8] in the callee.  The old
-             * code emitted each push immediately while parsing left-to-right,
-             * which reversed the parameter slots for normal calls.  Capture
-             * each non-inline argument's evaluation/push code and replay the
-             * completed argument blocks right-to-left just before CALL.
-             *
-             * Inline calls keep using the temporary argument frame below: that
-             * frame intentionally stores argument 0 at [esp], argument 1 at
-             * [esp + 4], etc., so do not reverse inline argument copies here.
-             */
-            if (!use_inline && state->ofp) {
-            
-                arg_tmp_ofp = scc_tmpfile ();
-                
-                if (arg_tmp_ofp) {
-                
-                    arg_saved_ofp = state->ofp;
-                    state->ofp = arg_tmp_ofp;
-                
-                }
-            
-            }
-            
-            postfix_member_seen = 0;
-            postfix_member_size = 0;
-            postfix_member_pointer_depth = 0;
-            postfix_member_pointed_size = 0;
-            
-            if (!use_inline && tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && find_local_symbol (tok.ident) && emit_push_aggregate_argument_now (tok.ident, find_local_symbol (tok.ident))) {
-            
-                struct local_symbol *arg_sym = find_local_symbol (tok.ident);
-                
-                arg_bytes = arg_sym ? arg_sym->size : DATA_PTR;
-                arg_is_floating = 0;
-                
-                get_token ();
-            
-            } else if (!use_inline && tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && !find_local_symbol (tok.ident) && emit_push_global_aggregate_argument_now (tok.ident)) {
-            
-                arg_bytes = get_global_symbol_size (tok.ident);
-                arg_is_floating = 0;
-                
-                get_token ();
-            
-            } else if (!use_inline && tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now () &&
-                       get_global_symbol_kind (tok.ident) == GLOBAL_SYMBOL_FUNCTION &&
-                       get_global_symbol_size (tok.ident) > (DATA_LLONG & 0x1f)) {
-            
-                char *arg_call_name = xstrdup (tok.ident);
-                
-                const char *arg_call_start = tok.start;
-                const char *arg_call_caret = tok.caret;
-                
-                unsigned long arg_call_line = get_line_number ();
-                
-                arg_bytes = get_global_symbol_size (arg_call_name);
-                arg_is_floating = 0;
-                
-                emit_sub_esp_now (arg_bytes);
-                
-                pending_struct_return_lhs = 0;
-                pending_struct_return_global_name = 0;
-                pending_struct_return_stack_address = 0;
-                pending_struct_return_stack_offset = 0;
-                pending_struct_return_stack_top = 1;
-                
-                get_token ();
-                emit_call_identifier_to_reg_now (arg_call_name, "eax", arg_call_start, arg_call_caret, arg_call_line);
-                
-                pending_struct_return_stack_top = 0;
-                free (arg_call_name);
-            
-            } else {
-            
-                arg_is_floating = rhs_current_operand_is_floating_now ();
-                arg_bytes = arg_is_floating ? (DATA_DOUBLE & 0x1f) : DATA_PTR;
-                
-                if (!use_inline && get_global_symbol_has_prototype (name) &&
-                    argc < get_global_symbol_param_count (name) &&
-                    get_global_symbol_param_size (name, argc) == (DATA_LLONG & 0x1f) &&
-                    !get_global_symbol_param_floating (name, argc)) {
-                
-                    arg_is_floating = 0;
-                    arg_bytes = DATA_LLONG & 0x1f;
-                    
-                    emit_load_assignment_rhs_expression_to_pair ("eax", "edx", get_global_symbol_param_unsigned (name, argc));
-
-                } else if (!use_inline && get_global_symbol_has_prototype (name) && get_global_symbol_is_variadic (name) && argc >= get_global_symbol_param_count (name) && current_argument_is_bare_64bit_identifier_now ()) {
-                
-                    arg_is_floating = 0;
-                    arg_bytes = DATA_LLONG & 0x1f;
-                        
-                    emit_load_assignment_rhs_expression_to_pair ("eax", "edx", rhs_current_operand_is_unsigned_now ());
-                
-                } else if (arg_is_floating) {
-                    emit_load_floating_rhs_expression_now (DATA_DOUBLE & 0x1f);
-                } else {
-                    emit_load_assignment_rhs_expression_to_reg ("eax");
-                }
-                
-                if (state->ofp) {
-                
-                    if (!use_inline && !arg_is_floating && arg_bytes == (DATA_LLONG & 0x1f)) {
-                    
-                        emit_push_reg_now ("edx");
-                        emit_push_reg_now ("eax");
-                    
-                    } else if (!use_inline && !arg_is_floating && postfix_member_seen && postfix_member_pointer_depth == 0 && postfix_member_size > (DATA_PTR & 0x1f)) {
-                    
-                        arg_bytes = postfix_member_size;
-                        emit_push_aggregate_from_addr_reg_now ("eax", arg_bytes);
-                    
-                    } else if (!use_inline && !arg_is_floating && postfix_member_size > (DATA_PTR & 0x1f)) {
-                    
-                        arg_bytes = postfix_member_size;
-                        emit_push_aggregate_from_addr_reg_now ("eax", arg_bytes);
-                    
-                    } else if (use_inline) {
-                    
-                        if (argc < expected_inline_args) {
-                        
-                            if (state->syntax & ASM_SYNTAX_INTEL) {
-                                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov dword [esp + %d], eax\n" : "    mov dword ptr [esp + %d], eax\n"), argc * 4);
-                            } else {
-                                fprintf (state->ofp, "    movl %%eax, %d(%%esp)\n", argc * 4);
-                            }
-                        
-                        }
-                    
-                    } else if (arg_is_floating) {
-                    
-                        if (state->syntax & ASM_SYNTAX_INTEL) {
-                        
-                            fprintf (state->ofp, "    sub esp, 8\n");
-                            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    fstp qword [esp]\n" : "    fstp qword ptr [esp]\n"));
-                        
-                        } else {
-                        
-                            fprintf (state->ofp, "    subl $8, %%esp\n");
-                            fprintf (state->ofp, "    fstpl (%%esp)\n");
-                        
-                        }
-                    
-                    } else {
-                    
-                        if (state->syntax & ASM_SYNTAX_INTEL) {
-                            fprintf (state->ofp, "    push eax\n");
-                        } else {
-                            fprintf (state->ofp, "    pushl %%eax\n");
-                        }
-                    
-                    }
-                
-                }
-            
-            }
-            
-            if (!use_inline) {
-                total_arg_bytes += arg_bytes;
-            }
-            
-            if (arg_saved_ofp) {
-            
-                fflush (arg_tmp_ofp);
-                state->ofp = arg_saved_ofp;
-                
-                new_arg_tmp_ofps = (FILE **) xrealloc (arg_tmp_ofps, sizeof (*arg_tmp_ofps) * (argc + 1));
-                
-                if (new_arg_tmp_ofps) {
-                
-                    arg_tmp_ofps = new_arg_tmp_ofps;
-                    
-                    arg_tmp_ofps[argc] = arg_tmp_ofp;
-                    arg_tmp_ofp = 0;
-                
-                }
-
-            }
-            
-            if (arg_tmp_ofp) {
-            
-                scc_close (arg_tmp_ofp);
-                arg_tmp_ofp = 0;
-            
-            }
-            
-            argc++;
-            
-            if (!_accept (TOK_COMMA)) {
-                break;
-            }
-        
-        }
-    
-    }
-    
-    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);
-    }
-    
-    if (use_inline) {
-    
-        if (argc == expected_inline_args && emit_inline_call_if_possible (name, argc, reg)) {
-        
-            if (state->ofp && inline_arg_bytes > 0) {
-            
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                    fprintf (state->ofp, "    add esp, %d\n", inline_arg_bytes);
-                } else {
-                    fprintf (state->ofp, "    addl $%d, %%esp\n", inline_arg_bytes);
-                }
-            
-            }
-            
-            /*
-             * The peephole inline optimiser currently understands the
-             * single-argument case well, but its stack-slot liveness pass is
-             * too aggressive for multi-argument inline calls.  It can fold
-             * constants correctly in simple examples, but it may also remove
-             * the temporary argument frame and leave confusing label-only
-             * fragments.  Keep multi-argument inline expansion conservative:
-             * emit the substituted inline body exactly as generated, with the
-             * argument copies still present.
-             */
-            finish_inline_buffer (&inline_tmp_ofp, &inline_saved_ofp, expected_inline_args <= 1);
-            return;
-        
-        }
-        
-        if (state->ofp && inline_arg_bytes > 0) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                fprintf (state->ofp, "    add esp, %d\n", inline_arg_bytes);
-            } else {
-                fprintf (state->ofp, "    addl $%d, %%esp\n", inline_arg_bytes);
-            }
-        
-        }
-        
-        finish_inline_buffer (&inline_tmp_ofp, &inline_saved_ofp, 0);
-        return;
-    
-    }
-    
-    if (emit_inline_call_if_possible (name, argc, reg)) {
-    
-        if (arg_tmp_ofps) {
-        
-            for (i = 0; i < argc; i++) {
-            
-                if (arg_tmp_ofps[i]) {
-                    scc_close (arg_tmp_ofps[i]);
-                }
-            
-            }
-            
-            free (arg_tmp_ofps);
-            arg_tmp_ofps = 0;
-        
-        }
-        
-        return;
-    
-    }
-    
-    call_sym = find_local_symbol (name);
-    
-    if (!call_sym) {
-    
-        if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_OBJECT) {
-            emit_extern_reference_symbol (name, DATA_PTR);
-        } else {
-            emit_extern_symbol (name, DATA_PTR, 1);
-        }
-        
-        asm_name = asm_global_symbol_name (name);
-    
-    } else {
-        asm_name = 0;
-    }
-    
-    if (state->ofp) {
-    
-        if (arg_tmp_ofps) {
-        
-            for (i = argc - 1; i >= 0; i--) {
-            
-                if (arg_tmp_ofps[i]) {
-                
-                    fseek (arg_tmp_ofps[i], 0, SEEK_SET);
-                    
-                    while ((ch = fgetc (arg_tmp_ofps[i])) != EOF) {
-                        fputc (ch, state->ofp);
-                    }
-                    
-                    scc_close (arg_tmp_ofps[i]);
-                    arg_tmp_ofps[i] = 0;
-                
-                }
-            
-            }
-            
-            free (arg_tmp_ofps);
-            arg_tmp_ofps = 0;
-        
-        }
-        
-        if (saved_pending_struct_return_lhs || saved_pending_struct_return_global_name ||
-            saved_pending_struct_return_stack_address || saved_pending_struct_return_stack_top) {
-        
-            pending_struct_return_lhs = saved_pending_struct_return_lhs;
-            pending_struct_return_global_name = saved_pending_struct_return_global_name;
-            pending_struct_return_stack_address = saved_pending_struct_return_stack_address;
-            pending_struct_return_stack_offset = saved_pending_struct_return_stack_offset;
-            pending_struct_return_stack_top = saved_pending_struct_return_stack_top;
-            
-            emit_push_pending_struct_return_address_now (total_arg_bytes);
-            total_arg_bytes += DATA_PTR & 0x1f;
-        
-        }
-        
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-        
-            if (call_sym) {
-            
-                emit_load_local_to_reg ("ecx", call_sym->offset, DATA_PTR);
-                fprintf (state->ofp, "    call ecx\n");
-            
-            } else if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_OBJECT) {
-            
-                emit_load_global_to_reg ("ecx", name, DATA_PTR);
-                fprintf (state->ofp, "    call ecx\n");
-            
-            } else if (get_global_symbol_dllimport (name)) {
-            
-                remember_global_symbol_import_call_stack_bytes (name, total_arg_bytes);
-                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    call dword [%s]\n" : "    call dword ptr %s\n"), asm_global_import_symbol_name (name));
-            
-            } else {
-                fprintf (state->ofp, "    call %s\n", asm_name);
-            }
-            
-            if (total_arg_bytes > 0 && get_global_symbol_calling_convention (name) != TOK_STDCALL) {
-                fprintf (state->ofp, "    add esp, %d\n", total_arg_bytes);
-            }
-            
-            if (strcmp (reg, "eax") != 0) {
-                fprintf (state->ofp, "    mov %s, eax\n", reg);
-            }
-        
-        } else {
-        
-            if (call_sym) {
-            
-                emit_load_local_to_reg ("ecx", call_sym->offset, DATA_PTR);
-                fprintf (state->ofp, "    call *%%ecx\n");
-            
-            } else if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_OBJECT) {
-            
-                emit_load_global_to_reg ("ecx", name, DATA_PTR);
-                fprintf (state->ofp, "    call *%%ecx\n");
-            
-            } else if (get_global_symbol_dllimport (name)) {
-            
-                remember_global_symbol_import_call_stack_bytes (name, total_arg_bytes);
-                fprintf (state->ofp, "    call *%s\n", asm_global_import_symbol_name (name));
-            
-            } else {
-                fprintf (state->ofp, "    call %s\n", asm_name);
-            }
-            
-            if (total_arg_bytes > 0 && get_global_symbol_calling_convention (name) != TOK_STDCALL) {
-                fprintf (state->ofp, "    addl $%d, %%esp\n", total_arg_bytes);
-            }
-            
-            if (strcmp (reg, "eax") != 0) {
-                fprintf (state->ofp, "    movl %%eax, %%%s\n", reg);
-            }
-        
-        }
-    
-    }
-    
-    set_rhs_last_pointer_info (get_global_symbol_pointer_depth (name), get_global_symbol_pointed_size (name));
-    
-    pending_struct_return_lhs = 0;
-    pending_struct_return_global_name = 0;
-    pending_struct_return_stack_address = 0;
-    pending_struct_return_stack_offset = 0;
-    pending_struct_return_stack_top = 0;
-    
-    if (arg_tmp_ofps) {
-    
-        for (i = 0; i < argc; i++) {
-        
-            if (arg_tmp_ofps[i]) {
-                scc_close (arg_tmp_ofps[i]);
-            }
-        
-        }
-        
-        free (arg_tmp_ofps);
-        arg_tmp_ofps = 0;
-    
-    }
-
-}
-
-static void emit_statement_label (int label);
-static void emit_statement_jump (int label);
-
-#define     MAX_GOTO_LABELS        256
-#define     MAX_GOTO_REFS          512
-
-struct goto_label_entry {
-
-    char *name;
-    
-    int label;
-    int defined;
-    int referenced;
-
-    long defined_stack_size;
-    unsigned long line;
-    
-    const char *start;
-    const char *caret;
-
-};
-
-static struct goto_label_entry goto_labels[MAX_GOTO_LABELS];
-static int goto_label_count = 0;
-
-struct goto_ref_entry {
-
-    int label_index;
-    int ref_label;
-    
-    long stack_size;
-
-};
-
-static struct goto_ref_entry goto_refs[MAX_GOTO_REFS];
-static int goto_ref_count = 0;
-
-static int current_break_label = -1;
-static int current_continue_label = -1;
-
-static long current_break_cleanup_base = 0;
-static long current_continue_cleanup_base = 0;
-
-#define     MAX_SWITCH_CASES        256
-
-struct switch_case_entry {
-
-    long value;
-    int label;
-
-};
-
-struct switch_context {
-
-    struct switch_case_entry cases[MAX_SWITCH_CASES];
-    int case_count;
-    int default_label;
-    int break_label;
-
-};
-
-static struct switch_context *current_switch_context = 0;
-static int statement_ends_control_flow = 0;
-
-static void reset_goto_labels (void) {
-
-    int i;
-    
-    for (i = 0; i < goto_label_count; i++) {
-    
-        if (goto_labels[i].name) {
-            free (goto_labels[i].name);
-        }
-        
-        goto_labels[i].name = 0;
-        goto_labels[i].label = 0;
-        goto_labels[i].defined = 0;
-        goto_labels[i].referenced = 0;
-        goto_labels[i].defined_stack_size = 0;
-        goto_labels[i].line = 0;
-        goto_labels[i].start = 0;
-        goto_labels[i].caret = 0;
-    
-    }
-    
-    goto_label_count = 0;
-    goto_ref_count = 0;
-
-}
-
-static int find_goto_label (const char *name) {
-
-    int i;
-    
-    for (i = 0; i < goto_label_count; i++) {
-    
-        if (goto_labels[i].name && strcmp (goto_labels[i].name, name) == 0) {
-            return i;
-        }
-    
-    }
-    
-    return -1;
-
-}
-
-static int get_goto_label (const char *name, unsigned long line, const char *start, const char *caret) {
-
-    int i = find_goto_label (name);
-    
-    if (i >= 0) {
-        return i;
-    }
-    
-    if (goto_label_count >= MAX_GOTO_LABELS) {
-    
-        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "too many goto labels");
-        return -1;
-    
-    }
-    
-    i = goto_label_count++;
-    
-    goto_labels[i].name = xstrdup (name);
-    goto_labels[i].label = anon_label++;
-    goto_labels[i].defined = 0;
-    goto_labels[i].referenced = 0;
-    goto_labels[i].defined_stack_size = 0;
-    goto_labels[i].line = line;
-    goto_labels[i].start = start;
-    goto_labels[i].caret = caret;
-    
-    return i;
-
-}
-
-static void define_goto_label (const char *name, unsigned long line, const char *start, const char *caret) {
-
-    int i = get_goto_label (name, line, start, caret);
-    
-    if (i < 0) {
-        return;
-    }
-    
-    if (goto_labels[i].defined) {
-    
-        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "duplicate label '%s'", name);
-        return;
-    
-    }
-    
-    goto_labels[i].defined = 1;
-    goto_labels[i].defined_stack_size = current_local_stack_size;
-    
-    /**
-     * A C label marks the next statement.  If the previous statement was a
-     * return, the compiler may have deferred the jump to the common return
-     * label so it can avoid redundant jumps.  Flush it before emitting the
-     * user label, otherwise the user label will point at the deferred return
-     * jump instead of the labelled statement.
-     */
-    if (pending_return_jump) {
-        emit_pending_return_jump ();
-    }
-    
-    emit_statement_label (goto_labels[i].label);
-
-}
-
-static void reference_goto_label (const char *name, unsigned long line, const char *start, const char *caret) {
-
-    int i = get_goto_label (name, line, start, caret);
-    
-    if (i < 0) {
-        return;
-    }
-    
-    goto_labels[i].referenced = 1;
-    
-    /*
-     * If this is a forward goto, do not jump directly to the final C
-     * label.  The target may be after automatic declarations in an inner
-     * block.  Because SCC emits stack allocation when those declarations are
-     * parsed, a direct branch can bypass the allocation and then use invalid
-     * EBP-relative locals.  Emit a per-reference trampoline after the function
-     * epilogue once the target stack depth is known.
-     */
-    if (!goto_labels[i].defined) {
-    
-        if (goto_ref_count < MAX_GOTO_REFS) {
-        
-            int ref_label = anon_label++;
-            
-            goto_refs[goto_ref_count].label_index = i;
-            goto_refs[goto_ref_count].ref_label = ref_label;
-            goto_refs[goto_ref_count].stack_size = current_local_stack_size;
-            goto_ref_count++;
-            
-            emit_statement_jump (ref_label);
-            return;
-        
-        }
-    
-    }
-    
-    emit_statement_jump (goto_labels[i].label);
-
-}
-
-static void check_goto_labels (void) {
-
-    int i;
-    
-    for (i = 0; i < goto_label_count; i++) {
-    
-        if (goto_labels[i].referenced && !goto_labels[i].defined) {
-            report_line_at (get_filename (), goto_labels[i].line, REPORT_ERROR, goto_labels[i].start, goto_labels[i].caret, "undefined label '%s'", goto_labels[i].name);
-        }
-    
-    }
-
-}
-
-static void emit_goto_trampolines (void) {
-
-    int i;
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    for (i = 0; i < goto_ref_count; i++) {
-    
-        int label_index = goto_refs[i].label_index;
-        long delta;
-        
-        if (label_index < 0 || label_index >= goto_label_count) {
-            continue;
-        }
-        
-        if (!goto_labels[label_index].defined) {
-            continue;
-        }
-        
-        emit_statement_label_raw (goto_refs[i].ref_label);
-        delta = goto_labels[label_index].defined_stack_size - goto_refs[i].stack_size;
-        
-        /*
-         * 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);
-    
-    }
-
-}
-
-static void queue_pending_statement_label (int label) {
-
-    if (label < 0) {
-        return;
-    }
-    
-    if (pending_statement_label_count >= MAX_PENDING_STATEMENT_LABELS) {
-        flush_pending_statement_labels ();
-    }
-    
-    if (pending_statement_label_count < MAX_PENDING_STATEMENT_LABELS) {
-        pending_statement_labels[pending_statement_label_count++] = label;
-    } else {
-        emit_statement_label (label);
-    }
-
-}
-
-static void add_switch_case_label (long value, unsigned long line, const char *start, const char *caret) {
-
-    int i;
-    
-    if (!current_switch_context) {
-    
-        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "case label not within a switch statement");
-        return;
-    
-    }
-    
-    for (i = 0; i < current_switch_context->case_count; i++) {
-    
-        if (current_switch_context->cases[i].value == value) {
-        
-            report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "duplicate case value");
-            return;
-        
-        }
-    
-    }
-    
-    if (current_switch_context->case_count >= MAX_SWITCH_CASES) {
-    
-        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "too many case labels in switch statement");
-        return;
-    
-    }
-    
-    current_switch_context->cases[current_switch_context->case_count].value = value;
-    current_switch_context->cases[current_switch_context->case_count].label = anon_label++;
-    
-    queue_pending_statement_label (current_switch_context->cases[current_switch_context->case_count].label);
-    current_switch_context->case_count++;
-
-}
-
-static void set_switch_default_label (unsigned long line, const char *start, const char *caret) {
-
-    if (!current_switch_context) {
-    
-        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "default label not within a switch statement");
-        return;
-    
-    }
-    
-    if (current_switch_context->default_label >= 0) {
-    
-        report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "duplicate default label");
-        return;
-    
-    }
-    
-    current_switch_context->default_label = anon_label++;
-    queue_pending_statement_label (current_switch_context->default_label);
-
-}
-
-static void emit_switch_dispatch (struct switch_context *sw) {
-
-    int i;
-    int target;
-    
-    if (!state->ofp || !sw) {
-        return;
-    }
-    
-    for (i = 0; i < sw->case_count; i++) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-        
-            fprintf (state->ofp, "    cmp eax, %ld\n", sw->cases[i].value);
-            
-            if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
-                fprintf (state->ofp, "    je L%d\n", sw->cases[i].label);
-            } else {
-                fprintf (state->ofp, "    je .L%d\n", sw->cases[i].label);
-            }
-        
-        } else {
-        
-            fprintf (state->ofp, "    cmpl $%ld, %%eax\n", sw->cases[i].value);
-            fprintf (state->ofp, "    je .L%d\n", sw->cases[i].label);
-        
-        }
-    
-    }
-    
-    target = (sw->default_label >= 0) ? sw->default_label : sw->break_label;
-    emit_statement_jump (target);
-
-}
-
-static void parse_switch_statement (void) {
-
-    struct switch_context sw;
-    struct switch_context *old_switch_context;
-    
-    int old_break_label;
-    int old_continue_label;
-    
-    long old_break_cleanup_base;
-    long old_continue_cleanup_base;
-    
-    int saved_ends_control_flow;
-    
-    FILE *saved_ofp;
-    FILE *body_tmp = 0;
-    
-    char *body_text = 0;
-    int body_pending_return_jump = 0;
-    
-    sw.case_count = 0;
-    sw.default_label = -1;
-    sw.break_label = anon_label++;
-    
-    get_token ();
-    expect (TOK_LPAREN, "(");
-    
-    emit_load_assignment_rhs_expression_to_reg ("eax");
-    
-    if (tok.kind != TOK_RPAREN) {
-        skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
-    }
-    
-    expect (TOK_RPAREN, ")");
-    
-    old_switch_context = current_switch_context;
-    old_break_label = current_break_label;
-    old_continue_label = current_continue_label;
-    old_break_cleanup_base = current_break_cleanup_base;
-    old_continue_cleanup_base = current_continue_cleanup_base;
-    
-    current_switch_context = &sw;
-    current_break_label = sw.break_label;
-    current_break_cleanup_base = current_block_cleanup_bytes;
-    
-    saved_ofp = state->ofp;
-    
-    if (saved_ofp) {
-    
-        body_tmp = scc_tmpfile ();
-        
-        if (body_tmp) {
-            state->ofp = body_tmp;
-        }
-    
-    }
-    
-    parse_statement ();
-    saved_ends_control_flow = statement_ends_control_flow;
-    
-    if (body_tmp) {
-    
-        body_text = read_tmp_file_text (body_tmp);
-        
-        scc_close (body_tmp);
-        body_tmp = 0;
-        
-        state->ofp = saved_ofp;
-        
-        body_pending_return_jump = pending_return_jump;
-        pending_return_jump = 0;
-        
-        emit_switch_dispatch (&sw);
-        
-        if (body_text) {
-        
-            fputs (body_text, state->ofp);
-            free (body_text);
-        
-        }
-        
-        pending_return_jump = body_pending_return_jump;
-    
-    } else {
-        state->ofp = saved_ofp;
-    }
-    
-    emit_statement_label (sw.break_label);
-    
-    current_switch_context = old_switch_context;
-    current_break_label = old_break_label;
-    current_continue_label = old_continue_label;
-    current_break_cleanup_base = old_break_cleanup_base;
-    current_continue_cleanup_base = old_continue_cleanup_base;
-    
-    /*
-     * A break inside the switch only leaves the switch.  Do not propagate the
-     * break statement's statement_ends_control_flow flag to the enclosing
-     * statement, otherwise code like:
-     *
-     *     if (x) { switch (y) { case 1: break; } } else { ... }
-     *
-     * is compiled without the jump over the else block and the true branch
-     * falls through into the else body.
-     */
-    (void)saved_ends_control_flow;
-    statement_ends_control_flow = 0;
-
-}
-
-static int is_value_compare_operator (enum token_kind k) {
-
-    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 const char *value_compare_set_mnemonic (enum token_kind op, int is_unsigned) {
-
-    switch (op) {
-    
-        case TOK_LESS:
-        
-            return is_unsigned ? "setb"  : "setl";
-        
-        case TOK_LTEQ:
-        
-            return is_unsigned ? "setbe" : "setle";
-        
-        case TOK_GREATER:
-        
-            return is_unsigned ? "seta"  : "setg";
-        
-        case TOK_GTEQ:
-        
-            return is_unsigned ? "setae" : "setge";
-        
-        case TOK_EQEQ:
-        
-            return "sete";
-        
-        case TOK_NOTEQ:
-        
-            return "setne";
-        
-        default:
-        
-            return "setne";
-    
-    }
-
-}
-
-static void emit_compare_eax_edx_to_reg (enum token_kind op, const char *reg, int is_unsigned) {
-
-    const char *setcc;
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    setcc = value_compare_set_mnemonic (op, is_unsigned);
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        fprintf (state->ofp, "    cmp eax, edx\n");
-        fprintf (state->ofp, "    %s al\n", setcc);
-        fprintf (state->ofp, "    movzx eax, al\n");
-        
-        if (strcmp (reg, "eax") != 0) {
-            fprintf (state->ofp, "    mov %s, eax\n", reg);
-        }
-    
-    } else {
-    
-        fprintf (state->ofp, "    cmpl %%edx, %%eax\n");
-        fprintf (state->ofp, "    %s %%al\n", setcc);
-        fprintf (state->ofp, "    movzbl %%al, %%eax\n");
-        
-        if (strcmp (reg, "eax") != 0) {
-            fprintf (state->ofp, "    movl %%eax, %%%s\n", reg);
-        }
-    
-    }
-
-}
-
-static int rhs_current_operand_is_unsigned_now (void);
-
-static int source_lhs_has_char_pointer_cast_before_now (const char *p) {
-
-    const char *q;
-    int limit = 160;
-    
-    if (!p) {
-        return 0;
-    }
-    
-    q = p;
-    
-    while (limit-- > 0 && q > tok.start) {
-    
-        q--;
-        
-        if (*q != '(') {
-            continue;
-        }
-        
-        if ((strncmp (q, "(char", 5) == 0 || strncmp (q, "(unsigned char", 14) == 0 || strncmp (q, "(signed char", 12) == 0)
-            && strchr (q, '*') && strchr (q, ')') && strchr (q, '*') < p && strchr (q, ')') < p) {
-            return 1;
-        }
-        
-        if (*q == ';' || *q == ',' || *q == '\n') {
-            break;
-        }
-    
-    }
-    
-    return 0;
-
-}
-
-static int arithmetic_operator_precedence_now (enum token_kind op) {
-
-    if (op == TOK_PIPE) {
-        return 1;
-    }
-    
-    if (op == TOK_CARET) {
-        return 2;
-    }
-    
-    if (op == TOK_AMPER) {
-        return 3;
-    }
-    
-    if (op == TOK_LSH || op == TOK_RSH) {
-        return 4;
-    }
-    
-    if (op == TOK_PLUS || op == TOK_MINUS) {
-        return 5;
-    }
-    
-    if (op == TOK_STAR || op == TOK_BSLASH || op == TOK_MOD) {
-        return 6;
-    }
-    
-    return 0;
-
-}
-
-static int emit_load_assignment_binary_expression_prec_to_reg (const char *reg, int min_prec) {
-
-    int is_unsigned;
-    int expr_pointer_depth;
-    int expr_pointed_size;
-    
-    is_unsigned = rhs_current_operand_is_unsigned_now ();
-    emit_load_assignment_rhs_to_reg (reg);
-    
-    /*
-     * Some statement-condition paths can leave a postfix member chain after
-     * the primary operand, e.g. inside parenthesized logical RHS terms such as
-     *     && (reg->type.dword || reg->type.debug)
-     * Consume that postfix here before the binary/logical expression parser
-     * decides whether the operand is complete.  Otherwise the enclosing
-     * parenthesized-expression code sees the still-pending "->"/"." token and
-     * reports a false "expected )".
-     */
-    while (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
-        emit_apply_postfix_member_access_to_reg_now (reg);
-    }
-    
-    /*
-     * The postfix member helper deliberately leaves aggregates and 64-bit
-     * scalar members as an address because the pair/aggregate paths may need
-     * the full object.  This single-register expression path, however, only
-     * has EAX/EDX-style 32-bit arithmetic available.  When such a member is
-     * used inside ordinary arithmetic/comparison code (for example the
-     * CHECK_READ macro in pdld with address_type fields), load the low word
-     * from the member address instead of adding the member address itself.
-     */
-    if (postfix_member_seen
-        && postfix_member_pointer_depth == 0
-        && postfix_member_size == (DATA_LLONG & 0x1f)
-        && !postfix_member_is_floating) {
-    
-        emit_load_deref_reg_now (reg, DATA_INT & 0x1f);
-        postfix_member_size = DATA_INT & 0x1f;
-    
-    }
-    
-    if (postfix_member_seen && postfix_member_is_unsigned) {
-        is_unsigned = 1;
-    }
-    
-    expr_pointer_depth = rhs_last_pointer_depth;
-    expr_pointed_size = rhs_last_pointed_size;
-    
-    while (is_arithmetic_binary_operator (tok.kind) && arithmetic_operator_precedence_now (tok.kind) >= min_prec) {
-        
-        enum token_kind op;
-        
-        int prec;
-        int rhs_is_unsigned;
-        int lhs_pointer_depth;
-        int lhs_pointed_size;
-        int rhs_pointer_depth;
-        int rhs_pointed_size;
-        int scale_rhs = 0;
-        int scale_lhs = 0;
-        
-        op = tok.kind;
-        prec = arithmetic_operator_precedence_now (op);
-        
-        lhs_pointer_depth = expr_pointer_depth;
-        lhs_pointed_size = expr_pointed_size;
-        
-        if ((op == TOK_PLUS || op == TOK_MINUS) && lhs_pointer_depth > 0 &&
-            source_lhs_has_char_pointer_cast_before_now (tok.caret)) {
-            lhs_pointed_size = DATA_CHAR & 0x1f;
-        }
-        
-        get_token ();
-        rhs_is_unsigned = rhs_current_operand_is_unsigned_now ();
-        
-        if (rhs_is_unsigned) {
-            is_unsigned = 1;
-        }
-        
-        if (strcmp (reg, "eax") != 0 && state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                fprintf (state->ofp, "    mov eax, %s\n", reg);
-            } else {
-                fprintf (state->ofp, "    movl %%%s, %%eax\n", reg);
-            }
-        
-        }
-        
-        emit_push_reg_now ("eax");
-        rhs_is_unsigned = emit_load_assignment_binary_expression_prec_to_reg ("edx", prec + 1);
-        
-        if (rhs_is_unsigned) {
-            is_unsigned = 1;
-        }
-        
-        rhs_pointer_depth = rhs_last_pointer_depth;
-        rhs_pointed_size = rhs_last_pointed_size;
-        
-        if ((op == TOK_PLUS || op == TOK_MINUS) && lhs_pointer_depth > 0 && rhs_pointer_depth == 0) {
-            scale_rhs = index_step_size (lhs_pointed_size);
-        } else if (op == TOK_PLUS && lhs_pointer_depth == 0 && rhs_pointer_depth > 0) {
-            scale_lhs = index_step_size (rhs_pointed_size);
-        }
-        
-        if (scale_rhs > 1) {
-            emit_scale_reg_by_const_now ("edx", scale_rhs);
-        }
-        
-        emit_pop_reg_now ("eax");
-        
-        if (scale_lhs > 1) {
-            emit_scale_reg_by_const_now ("eax", scale_lhs);
-        }
-        
-        emit_assignment_binary_op (op, is_unsigned);
-        
-        if (op == TOK_MINUS && lhs_pointer_depth > 0 && rhs_pointer_depth > 0 && index_step_size (lhs_pointed_size) > 1) {
-            emit_divide_eax_by_const_now (index_step_size (lhs_pointed_size));
-        }
-        
-        if (op == TOK_PLUS && lhs_pointer_depth == 0 && rhs_pointer_depth > 0) {
-        
-            expr_pointer_depth = rhs_pointer_depth;
-            expr_pointed_size = rhs_pointed_size;
-        
-        } else if (op == TOK_MINUS && lhs_pointer_depth > 0 && rhs_pointer_depth > 0) {
-        
-            expr_pointer_depth = 0;
-            expr_pointed_size = 0;
-        
-        } else if (op != TOK_PLUS && op != TOK_MINUS) {
-        
-            expr_pointer_depth = 0;
-            expr_pointed_size = 0;
-        
-        }
-        
-        if (strcmp (reg, "eax") != 0 && state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                fprintf (state->ofp, "    mov %s, eax\n", reg);
-            } else {
-                fprintf (state->ofp, "    movl %%eax, %%%s\n", reg);
-            }
-        
-        }
-    
-    }
-    
-    set_rhs_last_pointer_info (expr_pointer_depth, expr_pointed_size);
-    return is_unsigned;
-
-}
-
-static void emit_load_assignment_binary_expression_to_reg (const char *reg) {
-
-    if (current_integer_expr_is_foldable_now ()) {
-    
-        int64_s v = const64_from_current_foldable_expr ();
-        emit_load_const32_to_reg_now (reg, v);
-        
-        return;
-    
-    }
-    
-    emit_load_assignment_binary_expression_prec_to_reg (reg, 1);
-
-}
-
-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 ();
-    
-    if (emit_load_assignment_binary_expression_prec_to_reg (reg, 1)) {
-        is_unsigned = 1;
-    }
-    
-    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) {
-                fprintf (state->ofp, "    mov eax, %s\n", reg);
-            } else {
-                fprintf (state->ofp, "    movl %%%s, %%eax\n", 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;
-        }
-        
-        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;
-        }
-        
-        emit_pop_reg_now ("eax");
-        emit_compare_eax_edx_to_reg (op, reg, is_unsigned);
-    
-    }
-
-}
-
-static void emit_test_reg_jump_zero_now (const char *reg, int label) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        fprintf (state->ofp, "    test %s, %s\n", reg, reg);
-        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jz L%d\n" : "    jz .L%d\n"), label);
-    
-    } else {
-    
-        fprintf (state->ofp, "    testl %%%s, %%%s\n", reg, reg);
-        fprintf (state->ofp, "    jz .L%d\n", label);
-    
-    }
-
-}
-
-static void emit_test_reg_jump_nonzero_now (const char *reg, int label) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        fprintf (state->ofp, "    test %s, %s\n", reg, reg);
-        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), label);
-    
-    } else {
-    
-        fprintf (state->ofp, "    testl %%%s, %%%s\n", reg, reg);
-        fprintf (state->ofp, "    jnz .L%d\n", label);
-    
-    }
-
-}
-
-static void emit_mov_imm_to_reg_now (const char *reg, long value) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-        fprintf (state->ofp, "    mov %s, %ld\n", reg, value);
-    } else {
-        fprintf (state->ofp, "    movl $%ld, %%%s\n", value, reg);
-    }
-
-}
-
-static void emit_floating_stack_to_int_reg_now (const char *reg) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    /*
-     * C requires floating-to-integer conversion to discard the fractional
-     * part.  x87 fistp uses the current FPU rounding mode, which is normally
-     * round-to-nearest, so values such as 0.5000000001 become 1 instead of 0.
-     * Temporarily switch the x87 control word to truncate for this conversion.
-     */
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        fprintf (state->ofp, "    sub esp, 8\n");
-        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fnstcw word [esp + 4]\n" : "    fnstcw word ptr [esp + 4]\n");
-        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov ax, word [esp + 4]\n" : "    mov ax, word ptr [esp + 4]\n");
-        fprintf (state->ofp, "    or ah, 12\n");
-        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov word [esp + 6], ax\n" : "    mov word ptr [esp + 6], ax\n");
-        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fldcw word [esp + 6]\n" : "    fldcw word ptr [esp + 6]\n");
-        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fistp dword [esp]\n" : "    fistp dword ptr [esp]\n");
-        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fldcw word [esp + 4]\n" : "    fldcw word ptr [esp + 4]\n");
-        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [esp]\n" : "    mov %s, dword ptr [esp]\n", reg);
-        fprintf (state->ofp, "    add esp, 8\n");
-    
-    } else {
-    
-        fprintf (state->ofp, "    subl $8, %%esp\n");
-        fprintf (state->ofp, "    fnstcw 4(%%esp)\n");
-        fprintf (state->ofp, "    movw 4(%%esp), %%ax\n");
-        fprintf (state->ofp, "    orb $12, %%ah\n");
-        fprintf (state->ofp, "    movw %%ax, 6(%%esp)\n");
-        fprintf (state->ofp, "    fldcw 6(%%esp)\n");
-        fprintf (state->ofp, "    fistpl (%%esp)\n");
-        fprintf (state->ofp, "    fldcw 4(%%esp)\n");
-        fprintf (state->ofp, "    movl (%%esp), %%%s\n", reg);
-        fprintf (state->ofp, "    addl $8, %%esp\n");
-    
-    }
-
-}
-
-static void emit_floating_stack_to_int_pair_now (const char *lo, const char *hi) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        fprintf (state->ofp, "    sub esp, 12\n");
-        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fnstcw word [esp + 8]\n" : "    fnstcw word ptr [esp + 8]\n");
-        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov ax, word [esp + 8]\n" : "    mov ax, word ptr [esp + 8]\n");
-        fprintf (state->ofp, "    or ah, 12\n");
-        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov word [esp + 10], ax\n" : "    mov word ptr [esp + 10], ax\n");
-        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fldcw word [esp + 10]\n" : "    fldcw word ptr [esp + 10]\n");
-        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fistp qword [esp]\n" : "    fistp qword ptr [esp]\n");
-        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fldcw word [esp + 8]\n" : "    fldcw word ptr [esp + 8]\n");
-        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [esp]\n" : "    mov %s, dword ptr [esp]\n", lo);
-        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov %s, dword [esp + 4]\n" : "    mov %s, dword ptr [esp + 4]\n", hi);
-        fprintf (state->ofp, "    add esp, 12\n");
-    
-    } else {
-    
-        fprintf (state->ofp, "    subl $12, %%esp\n");
-        fprintf (state->ofp, "    fnstcw 8(%%esp)\n");
-        fprintf (state->ofp, "    movw 8(%%esp), %%ax\n");
-        fprintf (state->ofp, "    orb $12, %%ah\n");
-        fprintf (state->ofp, "    movw %%ax, 10(%%esp)\n");
-        fprintf (state->ofp, "    fldcw 10(%%esp)\n");
-        fprintf (state->ofp, "    fistpll (%%esp)\n");
-        fprintf (state->ofp, "    fldcw 8(%%esp)\n");
-        fprintf (state->ofp, "    movl (%%esp), %%%s\n", lo);
-        fprintf (state->ofp, "    movl 4(%%esp), %%%s\n", hi);
-        fprintf (state->ofp, "    addl $12, %%esp\n");
-    
-    }
-
-}
-
-static void emit_integer_pair_to_floating_stack_now (const char *lo, const char *hi, int size) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if ((size & 0x1f) == (DATA_LLONG & 0x1f)) {
-    
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-        
-            fprintf (state->ofp, "    sub esp, 8\n");
-            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov dword [esp], %s\n" : "    mov dword ptr [esp], %s\n", lo);
-            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov dword [esp + 4], %s\n" : "    mov dword ptr [esp + 4], %s\n", hi);
-            fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fild qword [esp]\n" : "    fild qword ptr [esp]\n");
-            fprintf (state->ofp, "    add esp, 8\n");
-        
-        } else {
-        
-            fprintf (state->ofp, "    subl $8, %%esp\n");
-            fprintf (state->ofp, "    movl %%%s, (%%esp)\n", lo);
-            fprintf (state->ofp, "    movl %%%s, 4(%%esp)\n", hi);
-            fprintf (state->ofp, "    fildll (%%esp)\n");
-            fprintf (state->ofp, "    addl $8, %%esp\n");
-        
-        }
-        
-        return;
-    
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        fprintf (state->ofp, "    sub esp, 4\n");
-        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    mov dword [esp], %s\n" : "    mov dword ptr [esp], %s\n", lo);
-        fprintf (state->ofp, state->syntax & ASM_SYNTAX_NASM ? "    fild dword [esp]\n" : "    fild dword ptr [esp]\n");
-        fprintf (state->ofp, "    add esp, 4\n");
-    
-    } else {
-    
-        fprintf (state->ofp, "    subl $4, %%esp\n");
-        fprintf (state->ofp, "    movl %%%s, (%%esp)\n", lo);
-        fprintf (state->ofp, "    fildl (%%esp)\n");
-        fprintf (state->ofp, "    addl $4, %%esp\n");
-    
-    }
-
-}
-
-static void emit_load_assignment_rhs_expression_to_reg (const char *reg) {
-
-    int false_label;
-    int true_label;
-    int end_label;
-    
-    if (rhs_current_operand_is_floating_now ()) {
-    
-        emit_load_floating_rhs_expression_now (DATA_DOUBLE & 0x1f);
-        
-        /*
-         * Floating comparisons leave their boolean result in eax.
-         * Do not run that through fistp: emit_floating_compare_to_eax_now()
-         * has already consumed both x87 operands with fcompp, so the x87
-         * stack no longer contains a value to convert.
-         */
-        if (floating_rhs_result_in_eax_bool) {
-        
-            if (state->ofp && strcmp (reg, "eax") != 0) {
-            
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                    fprintf (state->ofp, "    mov %s, eax\n", reg);
-                } else {
-                    fprintf (state->ofp, "    movl %%eax, %%%s\n", reg);
-                }
-            
-            }
-            
-            floating_rhs_result_in_eax_bool = 0;
-            return;
-        
-        }
-        
-        emit_floating_stack_to_int_reg_now (reg);
-        return;
-    
-    }
-    
-    emit_load_assignment_compare_expression_to_reg (reg);
-    
-    for (;;) {
-    
-        if (assignment32_stop_before_condition_operator && is_assignment32_condition_stop_operator (tok.kind)) {
-            break;
-        }
-        
-        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);
-            emit_mov_imm_to_reg_now (reg, 1);
-            emit_statement_jump (end_label);
-            emit_statement_label (false_label);
-            emit_mov_imm_to_reg_now (reg, 0);
-            emit_statement_label (end_label);
-            
-            continue;
-        
-        }
-        
-        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);
-            emit_mov_imm_to_reg_now (reg, 0);
-            emit_statement_jump (end_label);
-            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) {
-    
-        false_label = anon_label++;
-        end_label = anon_label++;
-        
-        get_token ();
-        
-        if (state->ofp) {
-        
-            if (strcmp (reg, "eax") != 0) {
-            
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                    fprintf (state->ofp, "    mov eax, %s\n", reg);
-                } else {
-                    fprintf (state->ofp, "    movl %%%s, %%eax\n", reg);
-                }
-            
-            }
-            
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-            
-                fprintf (state->ofp, "    test eax, eax\n");
-                
-                if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
-                    fprintf (state->ofp, "    jz L%d\n", false_label);
-                } else {
-                    fprintf (state->ofp, "    jz .L%d\n", false_label);
-                }
-            
-            } else {
-            
-                fprintf (state->ofp, "    testl %%eax, %%eax\n");
-                fprintf (state->ofp, "    jz .L%d\n", false_label);
-            
-            }
-        
-        }
-        
-        emit_load_assignment_rhs_expression_to_reg (reg);
-        expect (TOK_COLON, ":");
-        emit_statement_jump (end_label);
-        emit_statement_label (false_label);
-        emit_load_assignment_rhs_expression_to_reg (reg);
-        emit_statement_label (end_label);
-    
-    }
-
-}
-
-static void emit_statement_cmp64_to_eax (enum token_kind op, int is_unsigned);
-
-static int is_assignment64_condition_stop_operator (enum token_kind k) {
-
-    return  k == TOK_LESS || k == TOK_LTEQ || k == TOK_GREATER ||
-                k == TOK_GTEQ || k == TOK_EQEQ || k == TOK_NOTEQ ||
-                    k == TOK_LOGAND || k == TOK_LOGOR;
-
-}
-
-static int is_assignment64_binary_operator (enum token_kind k) {
-
-    return  is_arithmetic_binary_operator (k) ||
-                k == TOK_LESS || k == TOK_LTEQ || k == TOK_GREATER ||
-                    k == TOK_GTEQ || k == TOK_EQEQ || k == TOK_NOTEQ ||
-                        k == TOK_LOGAND || k == TOK_LOGOR;
-
-}
-
-static void emit_assignment64_bool_result_to_pair_now (const char *lo, const char *hi) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (strcmp (lo, "eax") != 0) {
-            fprintf (state->ofp, "    mov %s, eax\n", lo);
-        }
-        
-        fprintf (state->ofp, "    xor %s, %s\n", hi, hi);
-    
-    } else {
-    
-        if (strcmp (lo, "eax") != 0) {
-            fprintf (state->ofp, "    movl %%eax, %%%s\n", lo);
-        }
-        
-        fprintf (state->ofp, "    xorl %%%s, %%%s\n", hi, hi);
-    
-    }
-
-}
-
-static void emit_assignment64_logical_op_to_pair_now (enum token_kind op, const char *lo, const char *hi) {
-
-    int true_label;
-    int false_label;
-    int end_label;
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    true_label = anon_label++;
-    false_label = anon_label++;
-    end_label = anon_label++;
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        fprintf (state->ofp, "    test edx, edx\n");
-        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), op == TOK_LOGOR ? true_label : end_label);
-        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"), op == TOK_LOGOR ? true_label : end_label);
-        
-        if (op == TOK_LOGAND) {
-        
-            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jmp L%d\n" : "    jmp .L%d\n"), false_label);
-            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), end_label);
-            fprintf (state->ofp, "    test ecx, ecx\n");
-            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), true_label);
-            fprintf (state->ofp, "    test ebx, ebx\n");
-            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), true_label);
-            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), false_label);
-            fprintf (state->ofp, "    xor eax, eax\n");
-            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jmp L%d\n" : "    jmp .L%d\n"), end_label + 1);
-            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), true_label);
-            fprintf (state->ofp, "    mov eax, 1\n");
-            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), end_label + 1);
-        
-        } else {
-        
-            fprintf (state->ofp, "    test ecx, ecx\n");
-            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), true_label);
-            fprintf (state->ofp, "    test ebx, ebx\n");
-            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), true_label);
-            fprintf (state->ofp, "    xor eax, eax\n");
-            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jmp L%d\n" : "    jmp .L%d\n"), end_label);
-            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), true_label);
-            fprintf (state->ofp, "    mov eax, 1\n");
-            fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), end_label);
-        
-        }
-    
-    } else {
-    
-        fprintf (state->ofp, "    testl %%edx, %%edx\n");
-        fprintf (state->ofp, op == TOK_LOGOR ? "    jnz .L%d\n" : "    jnz .L%d\n", op == TOK_LOGOR ? true_label : end_label);
-        fprintf (state->ofp, "    testl %%eax, %%eax\n");
-        fprintf (state->ofp, op == TOK_LOGOR ? "    jnz .L%d\n" : "    jnz .L%d\n", op == TOK_LOGOR ? true_label : end_label);
-        
-        if (op == TOK_LOGAND) {
-        
-            fprintf (state->ofp, "    jmp .L%d\n", false_label);
-            fprintf (state->ofp, ".L%d:\n", end_label);
-            fprintf (state->ofp, "    testl %%ecx, %%ecx\n");
-            fprintf (state->ofp, "    jnz .L%d\n", true_label);
-            fprintf (state->ofp, "    testl %%ebx, %%ebx\n");
-            fprintf (state->ofp, "    jnz .L%d\n", true_label);
-            fprintf (state->ofp, ".L%d:\n", false_label);
-            fprintf (state->ofp, "    xorl %%eax, %%eax\n");
-            fprintf (state->ofp, "    jmp .L%d\n", end_label + 1);
-            fprintf (state->ofp, ".L%d:\n", true_label);
-            fprintf (state->ofp, "    movl $1, %%eax\n");
-            fprintf (state->ofp, ".L%d:\n", end_label + 1);
-        
-        } else {
-        
-            fprintf (state->ofp, "    testl %%ecx, %%ecx\n");
-            fprintf (state->ofp, "    jnz .L%d\n", true_label);
-            fprintf (state->ofp, "    testl %%ebx, %%ebx\n");
-            fprintf (state->ofp, "    jnz .L%d\n", true_label);
-            fprintf (state->ofp, "    xorl %%eax, %%eax\n");
-            fprintf (state->ofp, "    jmp .L%d\n", end_label);
-            fprintf (state->ofp, ".L%d:\n", true_label);
-            fprintf (state->ofp, "    movl $1, %%eax\n");
-            fprintf (state->ofp, ".L%d:\n", end_label);
-        
-        }
-    
-    }
-    
-    anon_label++;
-    emit_assignment64_bool_result_to_pair_now (lo, hi);
-
-}
-
-static void emit_assignment64_compare_op_to_pair_now (enum token_kind op, const char *lo, const char *hi, int is_unsigned) {
-
-    emit_statement_cmp64_to_eax (op, is_unsigned);
-    emit_assignment64_bool_result_to_pair_now (lo, hi);
-
-}
-
-static void emit_load_assignment_rhs_expression_to_pair (const char *lo, const char *hi, int is_unsigned) {
-
-    enum token_kind op;
-    
-    int result_pair_is_eax_edx = (strcmp (lo, "eax") == 0 && strcmp (hi, "edx") == 0);
-    int current_pair_is_eax_edx = result_pair_is_eax_edx;
-    
-    if (current_integer_expr_is_foldable_now ()) {
-    
-        int64_s v = const64_from_current_foldable_expr ();
-        emit_load_const64_to_pair_now (lo, hi, v);
-        
-        return;
-    
-    }
-    
-    emit_load_assignment_rhs_to_pair (lo, hi);
-    
-    while (is_assignment64_binary_operator (tok.kind) && !(assignment64_stop_before_condition_operator && is_assignment64_condition_stop_operator (tok.kind))) {
-    
-        op = tok.kind;
-        get_token ();
-        
-        if (!current_pair_is_eax_edx) {
-        
-            emit_mov_reg_to_reg_now ("eax", lo);
-            emit_mov_reg_to_reg_now ("edx", hi);
-            
-            current_pair_is_eax_edx = 1;
-        
-        }
-        
-        emit_preserve_assignment64_regs (op);
-        
-        /*
-         * The right operand of a 64-bit shift is a plain integer shift
-         * count, not a 64-bit value.  Loading it through the 64-bit primary
-         * path loses precedence for cases such as:
-         *
-         *     ((address_type)1) << (CHAR_BIT * rel->howto->size)
-         *
-         * Worse, the RHS loader uses EAX internally for nested expressions;
-         * preserve the 64-bit LHS in EDX:EAX while the count is evaluated
-         * into EBX.
-         */
-        if (op == TOK_LSH || op == TOK_RSH || op == TOK_LSHEQ || op == TOK_RSHEQ) {
-        
-            emit_push_reg_now ("eax");
-            emit_push_reg_now ("edx");
-            
-            emit_load_assignment_binary_expression_to_reg ("ebx");
-            
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                fprintf (state->ofp, "    xor ecx, ecx\n");
-            } else {
-                fprintf (state->ofp, "    xorl %%ecx, %%ecx\n");
-            }
-            
-            emit_pop_reg_now ("edx");
-            emit_pop_reg_now ("eax");
-        
-        } else {
-        
-            /*
-             * The generic 64-bit RHS loader uses EAX:EDX as scratch even
-             * when asked to leave the final value in EBX:ECX.  Preserve the
-             * left operand around RHS evaluation; otherwise expressions such
-             * as:
-             *
-             *     result &= (((address_type)1) << n) - 1
-             *
-             * end up applying the operator to the RHS twice, because the
-             * computed mask clobbers the original result in EAX:EDX.
-             */
-            emit_push_reg_now ("eax");
-            emit_push_reg_now ("edx");
-            
-            emit_load_assignment_rhs_to_pair ("ebx", "ecx");
-            
-            emit_pop_reg_now ("edx");
-            emit_pop_reg_now ("eax");
-        
-        }
-        
-        if (op == TOK_LOGAND || op == TOK_LOGOR) {
-        
-            emit_assignment64_logical_op_to_pair_now (op, lo, hi);
-            current_pair_is_eax_edx = result_pair_is_eax_edx;
-        
-        } else if (is_value_compare_operator (op)) {
-        
-            emit_assignment64_compare_op_to_pair_now (op, lo, hi, is_unsigned);
-            current_pair_is_eax_edx = result_pair_is_eax_edx;
-        
-        } else {
-        
-            emit_assignment_binary_op64 (op, is_unsigned);
-            current_pair_is_eax_edx = 1;
-        
-        }
-        
-        emit_restore_assignment64_regs (op);
-    
-    }
-    
-    if (current_pair_is_eax_edx && !result_pair_is_eax_edx) {
-    
-        emit_mov_reg_to_reg_now (lo, "eax");
-        emit_mov_reg_to_reg_now (hi, "edx");
-        
-        current_pair_is_eax_edx = 0;
-    
-    }
-    
-    if (tok.kind == TOK_QMARK) {
-    
-        int false_label = anon_label++;
-        int end_label = anon_label++;
-        
-        get_token ();
-        
-        if (state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-            
-                fprintf (state->ofp, "    test %s, %s\n", hi, hi);
-                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), false_label + 2);
-                fprintf (state->ofp, "    test %s, %s\n", lo, lo);
-                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jz L%d\n" : "    jz .L%d\n"), false_label);
-                fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), false_label + 2);
-            
-            } else {
-            
-                fprintf (state->ofp, "    testl %%%s, %%%s\n", hi, hi);
-                fprintf (state->ofp, "    jnz .L%d\n", false_label + 2);
-                fprintf (state->ofp, "    testl %%%s, %%%s\n", lo, lo);
-                fprintf (state->ofp, "    jz .L%d\n", false_label);
-                fprintf (state->ofp, ".L%d:\n", false_label + 2);
-            
-            }
-        
-        }
-        
-        anon_label++;
-        
-        emit_load_assignment_rhs_expression_to_pair (lo, hi, is_unsigned);
-        expect (TOK_COLON, ":");
-        
-        emit_statement_jump (end_label);
-        emit_statement_label (false_label);
-        emit_load_assignment_rhs_expression_to_pair (lo, hi, is_unsigned);
-        emit_statement_label (end_label);
-    
-    }
-
-}
-
-static void emit_incdec_integral_symbol_now (struct local_symbol *sym, const char *name, int size, enum token_kind op) {
-
-    char memref[64];
-    char nasm_memref[256];
-    
-    const char *symbol;
-    const char *mnemonic;
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (size == (DATA_LLONG & 0x1f)) {
-    
-        if (sym) {
-        
-            if (sym->is_static && sym->static_label) {
-                emit_load_global64_to_pair ("eax", "edx", sym->static_label);
-            } else {
-                emit_load_local64_to_pair (sym->offset, "eax", "edx");
-            }
-        
-        } else {
-            emit_load_global64_to_pair ("eax", "edx", name);
-        }
-        
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-        
-            if (op == TOK_INCR) {
-            
-                fprintf (state->ofp, "    add eax, 1\n");
-                fprintf (state->ofp, "    adc edx, 0\n");
-            
-            } else {
-            
-                fprintf (state->ofp, "    sub eax, 1\n");
-                fprintf (state->ofp, "    sbb edx, 0\n");
-            
-            }
-        
-        } else {
-        
-            if (op == TOK_INCR) {
-            
-                fprintf (state->ofp, "    addl $1, %%eax\n");
-                fprintf (state->ofp, "    adcl $0, %%edx\n");
-            
-            } else {
-            
-                fprintf (state->ofp, "    subl $1, %%eax\n");
-                fprintf (state->ofp, "    sbbl $0, %%edx\n");
-            
-            }
-        
-        }
-        
-        if (sym) {
-        
-            if (sym->is_static && sym->static_label) {
-                emit_store_pair_to_global64 (sym->static_label, "eax", "edx");
-            } else {
-                emit_store_pair_to_local64 (sym->offset, "eax", "edx");
-            }
-        
-        } else {
-            emit_store_pair_to_global64 (name, "eax", "edx");
-        }
-        
-        return;
-    
-    }
-    
-    if (size != (DATA_CHAR & 0x1f) && size != (DATA_SHORT & 0x1f) && size != (DATA_INT & 0x1f) && size != DATA_PTR) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        mnemonic = op == TOK_INCR ? "add" : "sub";
-        
-        if (sym && !sym->is_static) {
-        
-            format_intel_ebp_offset (memref, sizeof (memref), sym->offset);
-            symbol = memref;
-        
-        } else if (sym && sym->static_label) {
-            symbol = asm_global_symbol_name (sym->static_label);
-        } else {
-            symbol = asm_global_symbol_name (name);
-        }
-        
-        if (state->syntax & ASM_SYNTAX_NASM) {
-            symbol = format_nasm_memory_operand (nasm_memref, sizeof (nasm_memref), symbol);
-        }
-        
-        if (size == (DATA_CHAR & 0x1f)) {
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s byte %s, 1\n" : "    %s byte ptr %s, 1\n"), mnemonic, symbol);
-        } else if (size == (DATA_SHORT & 0x1f)) {
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s word %s, 1\n" : "    %s word ptr %s, 1\n"), mnemonic, symbol);
-        } else {
-            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s dword %s, 1\n" : "    %s dword ptr %s, 1\n"), mnemonic, symbol);
-        }
-    
-    } else {
-    
-        if (sym && !sym->is_static) {
-        
-            if (size == (DATA_CHAR & 0x1f)) {
-                fprintf (state->ofp, op == TOK_INCR ? "    incb %ld(%%ebp)\n" : "    decb %ld(%%ebp)\n", sym->offset);
-            } else if (size == (DATA_SHORT & 0x1f)) {
-                fprintf (state->ofp, op == TOK_INCR ? "    incw %ld(%%ebp)\n" : "    decw %ld(%%ebp)\n", sym->offset);
-            } else {
-                fprintf (state->ofp, op == TOK_INCR ? "    incl %ld(%%ebp)\n" : "    decl %ld(%%ebp)\n", sym->offset);
-            }
-        
-        } else {
-        
-            symbol = asm_global_symbol_name ((sym && sym->static_label) ? sym->static_label : name);
-            
-            if (size == (DATA_CHAR & 0x1f)) {
-                fprintf (state->ofp, op == TOK_INCR ? "    incb %s\n" : "    decb %s\n", symbol);
-            } else if (size == (DATA_SHORT & 0x1f)) {
-                fprintf (state->ofp, op == TOK_INCR ? "    incw %s\n" : "    decw %s\n", symbol);
-            } else {
-                fprintf (state->ofp, op == TOK_INCR ? "    incl %s\n" : "    decl %s\n", symbol);
-            }
-        
-        }
-    
-    }
-
-}
-
-static void emit_incdec_pointer_symbol_now (struct local_symbol *sym, const char *name, enum token_kind op, int step) {
-
-    const char *mnemonic = op == TOK_INCR ? "add" : "sub";
-    const char *symbol;
-    
-    char memref[64];
-    char nasm_memref[128];
-    
-    if (step <= 0) {
-        step = 1;
-    }
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (step == 1) {
-    
-        emit_incdec_integral_symbol_now (sym, name, DATA_PTR, op);
-        return;
-    
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        if (sym && !sym->is_static) {
-        
-            format_intel_ebp_offset (memref, sizeof (memref), sym->offset);
-            symbol = memref;
-        
-        } else if (sym && sym->static_label) {
-            symbol = asm_global_symbol_name (sym->static_label);
-        } else {
-            symbol = asm_global_symbol_name (name);
-        }
-        
-        if (state->syntax & ASM_SYNTAX_NASM) {
-        
-            symbol = format_nasm_memory_operand (nasm_memref, sizeof (nasm_memref), symbol);
-            fprintf (state->ofp, "    %s dword %s, %d\n", mnemonic, symbol, step);
-        
-        } else {
-            fprintf (state->ofp, "    %s dword ptr %s, %d\n", mnemonic, symbol, step);
-        }
-    
-    } else {
-    
-        if (sym && !sym->is_static) {
-            fprintf (state->ofp, "    %sl $%d, %ld(%%ebp)\n", mnemonic, step, sym->offset);
-        } else {
-        
-            symbol = asm_global_symbol_name ((sym && sym->static_label) ? sym->static_label : name);
-            fprintf (state->ofp, "    %sl $%d, %s\n", mnemonic, step, symbol);
-        
-        }
-    
-    }
-
-}
-
-static void emit_incdec_symbol_now (struct local_symbol *sym, const char *name, enum token_kind op, int line, const char *start, const char *caret) {
-
-    int global_index;
-    int is_floating;
-    int pointer_depth;
-    int pointed_size;
-    
-    int size;
-    
-    if (!sym) {
-    
-        global_index = find_global_symbol (name);
-        
-        if (global_index < 0) {
-        
-            report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "unknown symbol '%s'", name);
-            return;
-        
-        }
-        
-        if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION) {
-        
-            report_line_at (get_filename (), line, REPORT_ERROR, start, caret, "function '%s' cannot be incremented or decremented", name);
-            return;
-        
-        }
-    
-    }
-    
-    size = sym ? sym->size : get_global_symbol_size (name);
-    is_floating = sym ? sym->is_floating : get_global_symbol_floating (name);
-    
-    pointer_depth = sym ? sym->pointer_depth : get_global_symbol_pointer_depth (name);
-    pointed_size = sym ? sym->pointed_size : get_global_symbol_pointed_size (name);
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (is_floating) {
-    
-        emit_load_floating_symbol_now (sym, name, size);
-        fprintf (state->ofp, "    fld1\n");
-        
-        if (op == TOK_INCR) {
-            emit_floating_binary_now (TOK_PLUS);
-        } else {
-            emit_floating_binary_now (TOK_MINUS);
-        }
-        
-        emit_store_floating_symbol_now (sym, name, size);
-        return;
-    
-    }
-    
-    if (pointer_depth > 0) {
-    
-        emit_incdec_pointer_symbol_now (sym, name, op, pointed_size);
-        return;
-    
-    }
-    
-    emit_incdec_integral_symbol_now (sym, name, size, op);
-
-}
-
-static int parse_prefix_incdec_statement (void) {
-
-    enum token_kind op;
-    char *name;
-    
-    const char *name_start, *name_caret;
-    unsigned long name_line;
-    
-    struct local_symbol *sym;
-    
-    int deref_size = DATA_INT & 0x1f;
-    int indirect = 0;
-    
-    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-    
-        if (emit_load_prefix_incdec_member_to_reg_now ("eax")) {
-        
-            expect_semi_or_recover ();
-            return 1;
-        
-        }
-    
-    }
-    
-    if (emit_load_prefix_incdec_parenthesized_deref_to_reg_now ("eax")) {
-    
-        expect_semi_or_recover ();
-        return 1;
-    
-    }
-    
-    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
-        return 0;
-    }
-    
-    op = tok.kind;
-    get_token ();
-    
-    if (tok.kind == TOK_STAR) {
-    
-        indirect = 1;
-        get_token ();
-    
-    }
-    
-    if (tok.kind != TOK_IDENT) {
-    
-        if (indirect) {
-            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after *");
-        } else {
-            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after %s", op == TOK_INCR ? "++" : "--");
-        }
-        
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        expect_semi_or_recover ();
-        
-        return 1;
-    
-    }
-    
-    name = xstrdup (tok.ident);
-    name_start = tok.start;
-    name_caret = tok.caret;
-    name_line = get_line_number ();
-    
-    get_token ();
-
-    sym = find_local_symbol (name);
-    
-    if (indirect) {
-    
-        if (sym) {
-        
-            if (sym->pointer_depth > 1) {
-                deref_size = DATA_PTR & 0x1f;
-            } else if (sym->pointer_depth == 1 && sym->pointed_size > 0) {
-                deref_size = sym->pointed_size & 0x1f;
-            }
-            
-            if (sym->is_static && sym->static_label) {
-                emit_load_global_to_reg ("edx", sym->static_label, DATA_PTR);
-            } else {
-                emit_load_local_to_reg ("edx", sym->offset, DATA_PTR);
-            }
-        
-        } else if (find_global_symbol (name) >= 0) {
-        
-            if (get_global_symbol_pointer_depth (name) > 1) {
-                deref_size = DATA_PTR & 0x1f;
-            } else if (get_global_symbol_pointer_depth (name) == 1 && get_global_symbol_pointed_size (name) > 0) {
-                deref_size = get_global_symbol_pointed_size (name) & 0x1f;
-            }
-            
-            emit_load_global_to_reg ("edx", name, DATA_PTR);
-        
-        } else {
-        
-            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-            
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-            expect_semi_or_recover ();
-            
-            free (name);
-            return 1;
-        
-        }
-        
-        emit_push_reg_now ("edx");
-        emit_load_member_from_addr_reg_now ("eax", "edx", 0, deref_size);
-        
-        if (state->ofp) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                fprintf (state->ofp, op == TOK_INCR ? "    add eax, 1\n" : "    sub eax, 1\n");
-            } else {
-                fprintf (state->ofp, op == TOK_INCR ? "    addl $1, %%eax\n" : "    subl $1, %%eax\n");
-            }
-        
-        }
-        
-        emit_pop_reg_now ("edx");
-        emit_store_reg_to_deref_reg_now ("edx", "eax", deref_size);
-        
-        expect_semi_or_recover ();
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    emit_incdec_symbol_now (sym, name, op, name_line, name_start, name_caret);
-    
-    expect_semi_or_recover ();
-    free (name);
-    
-    return 1;
-
-}
-
-static int parse_parenthesized_pointer_member_indirect_assignment_statement (void) {
-
-    char *name = 0;
-    char *member = 0;
-    
-    struct local_symbol *sym;
-    
-    int global_index;
-    int parens = 0;
-    int offset = 0;
-    int member_size = DATA_PTR & 0x1f;
-    int member_elem_size = DATA_INT & 0x1f;
-    int member_pointer_depth = 0;
-    int deref_size = DATA_INT & 0x1f;
-    int step = 1;
-    
-    enum token_kind postfix_op = TOK_EOF;
-    enum token_kind op;
-    
-    const char *name_start;
-    const char *name_caret;
-    const char *member_start;
-    const char *member_caret;
-    
-    unsigned long name_line;
-    unsigned long member_line;
-    
-    if (tok.kind != TOK_LPAREN) {
-        return 0;
-    }
-    
-    while (tok.kind == TOK_LPAREN) {
-        ++parens;
-        get_token ();
-    }
-    
-    if (tok.kind != TOK_STAR) {
-    
-        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-        
-            enum token_kind prefix_op = tok.kind;
-            char *prefix_name;
-            
-            const char *prefix_start;
-            const char *prefix_caret;
-            
-            unsigned long prefix_line;
-            
-            struct local_symbol *prefix_sym;
-            
-            int prefix_global_index;
-            int prefix_deref_size = DATA_INT & 0x1f;
-            
-            enum token_kind prefix_assign_op;
-            get_token ();
-            
-            if (tok.kind != TOK_IDENT) {
-            
-                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-                
-                expect_semi_or_recover ();
-                return 1;
-            
-            }
-            
-            prefix_name = xstrdup (tok.ident);
-            prefix_start = tok.start;
-            prefix_caret = tok.caret;
-            prefix_line = get_line_number ();
-            
-            get_token ();
-            
-            while (tok.kind == TOK_RPAREN && parens > 0) {
-            
-                --parens;
-                get_token ();
-            
-            }
-            
-            if (parens != 0 || !is_assignment_operator (tok.kind)) {
-            
-                free (prefix_name);
-                
-                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-                expect_semi_or_recover ();
-                
-                return 1;
-            
-            }
-            
-            prefix_assign_op = tok.kind;
-            get_token ();
-            
-            prefix_sym = find_local_symbol (prefix_name);
-            prefix_global_index = find_global_symbol (prefix_name);
-            
-            if (!prefix_sym && prefix_global_index < 0) {
-            
-                report_line_at (get_filename (), prefix_line, REPORT_ERROR, prefix_start, prefix_caret, "unknown symbol '%s'", prefix_name);
-                
-                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-                expect_semi_or_recover ();
-                
-                free (prefix_name);
-                return 1;
-            
-            }
-            
-            if (prefix_sym) {
-            
-                if (prefix_sym->pointer_depth > 1) {
-                    prefix_deref_size = DATA_PTR & 0x1f;
-                } else if (prefix_sym->pointer_depth == 1 && prefix_sym->pointed_size > 0) {
-                    prefix_deref_size = prefix_sym->pointed_size & 0x1f;
-                }
-            
-            } else {
-            
-                if (get_global_symbol_pointer_depth (prefix_name) > 1) {
-                    prefix_deref_size = DATA_PTR & 0x1f;
-                } else if (get_global_symbol_pointer_depth (prefix_name) == 1 && get_global_symbol_pointed_size (prefix_name) > 0) {
-                    prefix_deref_size = get_global_symbol_pointed_size (prefix_name) & 0x1f;
-                }
-            
-            }
-            
-            if (prefix_deref_size == 0) {
-                prefix_deref_size = DATA_INT & 0x1f;
-            }
-            
-            emit_incdec_symbol_now (prefix_sym, prefix_name, prefix_op, prefix_line, prefix_start, prefix_caret);
-            
-            if (state->ofp) {
-            
-                if (prefix_sym) {
-                
-                    if (prefix_sym->is_static && prefix_sym->static_label) {
-                        emit_load_global_to_reg ("ecx", prefix_sym->static_label, DATA_PTR);
-                    } else {
-                        emit_load_local_to_reg ("ecx", prefix_sym->offset, DATA_PTR);
-                    }
-                
-                } else {
-                    emit_load_global_to_reg ("ecx", prefix_name, DATA_PTR);
-                }
-                
-                emit_push_reg_now ("ecx");
-                
-                if (prefix_assign_op == TOK_ASSIGN) {
-                    emit_load_assignment_rhs_expression_to_reg ("eax");
-                } else {
-                
-                    emit_pop_reg_now ("edx");
-                    emit_push_reg_now ("edx");
-                    
-                    emit_load_member_from_addr_reg_now ("eax", "edx", 0, prefix_deref_size);
-                    emit_push_reg_now ("eax");
-                    
-                    emit_load_assignment_rhs_expression_to_reg ("edx");
-                    emit_pop_reg_now ("eax");
-                    
-                    emit_assignment_binary_op (prefix_assign_op, 0);
-                
-                }
-                
-                emit_pop_reg_now ("edx");
-                emit_store_reg_to_deref_reg_now ("edx", "eax", prefix_deref_size);
-            
-            } else {
-                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-            }
-            
-            expect_semi_or_recover ();
-            
-            free (prefix_name);
-            return 1;
-        
-        }
-        
-        if (tok.kind == TOK_IDENT) {
-        
-            name = xstrdup (tok.ident);
-            name_start = tok.start;
-            name_caret = tok.caret;
-            name_line = get_line_number ();
-            
-            get_token ();
-            
-            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-            
-                postfix_op = tok.kind;
-                get_token ();
-            
-            }
-            
-            while (tok.kind == TOK_RPAREN && parens > 0) {
-            
-                --parens;
-                get_token ();
-            
-            }
-            
-            if (parens != 0 || !is_assignment_operator (tok.kind)) {
-            
-                free (name);
-                
-                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-                expect_semi_or_recover ();
-                
-                return 1;
-            
-            }
-            
-            op = tok.kind;
-            get_token ();
-            
-            sym = find_local_symbol (name);
-            global_index = find_global_symbol (name);
-            
-            if (!sym && global_index < 0) {
-            
-                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-                
-                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-                expect_semi_or_recover ();
-                
-                free (name);
-                return 1;
-            
-            }
-            
-            if (sym) {
-            
-                if (sym->pointer_depth > 1) {
-                
-                    deref_size = DATA_PTR & 0x1f;
-                    step = DATA_PTR & 0x1f;
-                
-                } else if (sym->pointer_depth == 1) {
-                
-                    deref_size = sym->pointed_size & 0x1f;
-                    step = sym->pointed_size > 0 ? sym->pointed_size : 1;
-                
-                }
-            
-            } else {
-            
-                if (get_global_symbol_pointer_depth (name) > 1) {
-                
-                    deref_size = DATA_PTR & 0x1f;
-                    step = DATA_PTR & 0x1f;
-                
-                } else if (get_global_symbol_pointer_depth (name) == 1) {
-                
-                    deref_size = get_global_symbol_pointed_size (name) & 0x1f;
-                    step = get_global_symbol_pointed_size (name) > 0 ? get_global_symbol_pointed_size (name) : 1;
-                
-                }
-            
-            }
-            
-            if (deref_size == 0) {
-                deref_size = DATA_INT & 0x1f;
-            }
-            
-            if (state->ofp) {
-            
-                if (sym) {
-                
-                    if (sym->is_static && sym->static_label) {
-                        emit_load_global_to_reg ("ecx", sym->static_label, DATA_PTR);
-                    } else {
-                        emit_load_local_to_reg ("ecx", sym->offset, DATA_PTR);
-                    }
-                
-                } else {
-                    emit_load_global_to_reg ("ecx", name, DATA_PTR);
-                }
-                
-                emit_push_reg_now ("ecx");
-                
-                if (postfix_op == TOK_INCR || postfix_op == TOK_DECR) {
-                
-                    if (sym) {
-                    
-                        if (sym->is_static && sym->static_label) {
-                        
-                            if (state->syntax & ASM_SYNTAX_INTEL) {
-                                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s dword [%s], %d\n" : "    %s dword ptr [%s], %d\n"), postfix_op == TOK_INCR ? "add" : "sub", sym->static_label, step);
-                            } else {
-                                fprintf (state->ofp, "    %sl $%d, %s\n", postfix_op == TOK_INCR ? "add" : "sub", step, sym->static_label);
-                            }
-                        
-                        } else {
-                        
-                            if (state->syntax & ASM_SYNTAX_INTEL) {
-                            
-                                char memref[64];
-                                
-                                format_intel_ebp_offset (memref, sizeof (memref), sym->offset);
-                                fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s dword %s, %d\n" : "    %s dword ptr %s, %d\n"), postfix_op == TOK_INCR ? "add" : "sub", memref, step);
-                                
-                            } else {
-                                fprintf (state->ofp, "    %sl $%d, %ld(%%ebp)\n", postfix_op == TOK_INCR ? "add" : "sub", step, sym->offset);
-                            }
-                        
-                        }
-                    
-                    } else {
-                    
-                        if (state->syntax & ASM_SYNTAX_INTEL) {
-                            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s dword [%s], %d\n" : "    %s dword ptr [%s], %d\n"), postfix_op == TOK_INCR ? "add" : "sub", name, step);
-                        } else {
-                            fprintf (state->ofp, "    %sl $%d, %s\n", postfix_op == TOK_INCR ? "add" : "sub", step, name);
-                        }
-                    
-                    }
-                
-                }
-                
-                if (op == TOK_ASSIGN) {
-                    emit_load_assignment_rhs_expression_to_reg ("eax");
-                } else {
-                
-                    emit_pop_reg_now ("edx");
-                    emit_push_reg_now ("edx");
-                    emit_load_member_from_addr_reg_now ("eax", "edx", 0, deref_size);
-                    emit_push_reg_now ("eax");
-                    emit_load_assignment_rhs_expression_to_reg ("edx");
-                    emit_pop_reg_now ("eax");
-                    emit_assignment_binary_op (op, 0);
-                
-                }
-                
-                emit_pop_reg_now ("edx");
-                emit_store_reg_to_deref_reg_now ("edx", "eax", deref_size);
-            
-            } else {
-                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-            }
-            
-            expect_semi_or_recover ();
-            
-            free (name);
-            return 1;
-        
-        }
-        
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        
-        expect_semi_or_recover ();
-        return 1;
-    
-    }
-    
-    get_token ();
-    
-    while (tok.kind == TOK_LPAREN) {
-    
-        ++parens;
-        get_token ();
-    
-    }
-    
-    if (tok.kind != TOK_IDENT) {
-    
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        
-        expect_semi_or_recover ();
-        return 1;
-    
-    }
-    
-    name = xstrdup (tok.ident);
-    name_start = tok.start;
-    name_caret = tok.caret;
-    name_line = get_line_number ();
-    
-    get_token ();
-    
-    if (state->ofp) {
-    
-        if (tok.kind == TOK_LPAREN) {
-            emit_call_identifier_to_reg_now (name, "eax", name_start, name_caret, name_line);
-        } else {
-        
-            sym = find_local_symbol (name);
-            global_index = find_global_symbol (name);
-            
-            if (sym) {
-            
-                if (sym->is_static && sym->static_label) {
-                    emit_load_global_to_reg ("eax", sym->static_label, DATA_PTR);
-                } else {
-                    emit_load_local_to_reg ("eax", sym->offset, DATA_PTR);
-                }
-            
-            } else if (global_index >= 0) {
-                emit_load_global_to_reg ("eax", name, DATA_PTR);
-            } else {
-                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-            }
-        
-        }
-        
-        emit_load_deref_reg_now ("eax", DATA_PTR);
-        
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-            fprintf (state->ofp, "    mov edx, eax\n");
-        } else {
-            fprintf (state->ofp, "    movl %%eax, %%edx\n");
-        }
-    
-    } else if (tok.kind == TOK_LPAREN) {
-        emit_call_identifier_to_reg_now (name, "eax", name_start, name_caret, name_line);
-    }
-    
-    while (tok.kind == TOK_RPAREN && parens > 0) {
-    
-        --parens;
-        get_token ();
-    
-    }
-    
-    if (tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
-    
-        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-        
-            postfix_op = tok.kind;
-            get_token ();
-            
-            sym = find_local_symbol (name);
-            global_index = find_global_symbol (name);
-            
-            if (sym) {
-            
-                if (sym->pointer_depth > 1) {
-                
-                    deref_size = DATA_PTR & 0x1f;
-                    step = DATA_PTR & 0x1f;
-                
-                } else if (sym->pointer_depth == 1) {
-                
-                    deref_size = sym->pointed_size & 0x1f;
-                    step = 1;
-                
-                }
-                
-                if (deref_size == 0) {
-                    deref_size = DATA_INT & 0x1f;
-                }
-                
-                if (sym->is_static && sym->static_label) {
-                    emit_load_global_to_reg ("edx", sym->static_label, DATA_PTR);
-                } else {
-                    emit_load_local_to_reg ("edx", sym->offset, DATA_PTR);
-                }
-            
-            } else if (global_index >= 0) {
-            
-                if (get_global_symbol_pointer_depth (name) > 1) {
-                
-                    deref_size = DATA_PTR & 0x1f;
-                    step = DATA_PTR & 0x1f;
-                
-                } else if (get_global_symbol_pointer_depth (name) == 1) {
-                
-                    deref_size = get_global_symbol_pointed_size (name) & 0x1f;
-                    step = 1;
-                
-                }
-                
-                if (deref_size == 0) {
-                    deref_size = DATA_INT & 0x1f;
-                }
-                
-                emit_load_global_to_reg ("edx", name, DATA_PTR);
-            
-            } else {
-                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-            }
-            
-            if (state->ofp) {
-            
-                emit_load_deref_reg_now ("edx", deref_size);
-
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                    fprintf (state->ofp, "    %s edx, %d\n", postfix_op == TOK_INCR ? "add" : "sub", step);
-                } else {
-                    fprintf (state->ofp, "    %sl $%d, %%edx\n", postfix_op == TOK_INCR ? "add" : "sub", step);
-                }
-                
-                if (sym) {
-                
-                    if (sym->is_static && sym->static_label) {
-                        emit_load_global_to_reg ("eax", sym->static_label, DATA_PTR);
-                    } else {
-                        emit_load_local_to_reg ("eax", sym->offset, DATA_PTR);
-                    }
-                
-                } else if (global_index >= 0) {
-                    emit_load_global_to_reg ("eax", name, DATA_PTR);
-                }
-                
-                emit_store_reg_to_deref_reg_now ("eax", "edx", deref_size);
-            
-            }
-            
-            expect_semi_or_recover ();
-            
-            free (name);
-            return 1;
-        
-        }
-        
-        free (name);
-        
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        expect_semi_or_recover ();
-        
-        return 1;
-    
-    }
-    
-    get_token ();
-    
-    member_start = tok.start;
-    member_caret = tok.caret;
-    member_line = get_line_number ();
-    
-    if (tok.kind != TOK_IDENT) {
-    
-        report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name");
-        free (name);
-        
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        
-        expect_semi_or_recover ();
-        return 1;
-    
-    }
-    
-    member = xstrdup (tok.ident);
-    get_token ();
-    
-    if (!find_member_info_ex (member, &offset, &member_size, &member_elem_size, &member_pointer_depth, 0, 0)) {
-    
-        report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
-        
-        free (member);
-        free (name);
-        
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        expect_semi_or_recover ();
-        
-        return 1;
-    
-    }
-    
-    free (member);
-    
-    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-    
-        postfix_op = tok.kind;
-        get_token ();
-    
-    }
-    
-    if (!is_assignment_operator (tok.kind)) {
-    
-        free (name);
-        
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        expect_semi_or_recover ();
-        
-        return 1;
-    
-    }
-    
-    op = tok.kind;
-    get_token ();
-    
-    if (member_pointer_depth > 1) {
-        deref_size = DATA_PTR & 0x1f;
-    } else if (member_pointer_depth == 1 && member_elem_size > 0) {
-        deref_size = member_elem_size & 0x1f;
-    } else if (member_size > 0) {
-        deref_size = member_size & 0x1f;
-    }
-    
-    if (deref_size == 0) {
-        deref_size = DATA_INT & 0x1f;
-    }
-    
-    step = member_elem_size > 0 ? member_elem_size : 1;
-    
-    if (state->ofp) {
-    
-        emit_load_member_from_addr_reg_now ("ecx", "edx", offset, DATA_PTR & 0x1f);
-        
-        if (postfix_op == TOK_INCR || postfix_op == TOK_DECR) {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-            
-                if (state->syntax & ASM_SYNTAX_NASM) {
-                    fprintf (state->ofp, "    %s dword [edx + %d], %d\n", postfix_op == TOK_INCR ? "add" : "sub", offset, step);
-                } else {
-                    fprintf (state->ofp, "    %s dword ptr [edx + %d], %d\n", postfix_op == TOK_INCR ? "add" : "sub", offset, step);
-                }
-            
-            } else {
-                fprintf (state->ofp, "    %sl $%d, %d(%%edx)\n", postfix_op == TOK_INCR ? "add" : "sub", step, offset);
-            }
-        
-        }
-        
-        emit_push_reg_now ("ecx");
-        
-        if (op == TOK_ASSIGN) {
-            emit_load_assignment_rhs_expression_to_reg ("eax");
-        } else {
-        
-            emit_load_member_from_addr_reg_now ("eax", "edx", 0, deref_size);
-            emit_push_reg_now ("eax");
-            emit_load_assignment_rhs_expression_to_reg ("edx");
-            emit_pop_reg_now ("eax");
-            emit_assignment_binary_op (op, 0);
-        
-        }
-        
-        emit_pop_reg_now ("edx");
-        emit_store_reg_to_deref_reg_now ("edx", "eax", deref_size);
-    
-    } else {
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-    }
-    
-    expect_semi_or_recover ();
-    
-    free (name);
-    return 1;
-
-}
-
-static int paren_text_starts_type_name_now (void) {
-
-    const char *p;
-    
-    char name[128];
-    int n = 0;
-    
-    if (tok.caret) {
-        p = tok.caret;
-    } else if (tok.start) {
-        p = tok.start;
-    } else {
-        return 0;
-    }
-    
-    if (*p != '(') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (*p == '(') {
-    
-        p++;
-        
-        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 == '_') && n < (int) sizeof (name) - 1) {
-        name[n++] = *p++;
-    }
-    
-    name[n] = '\0';
-    
-    if (strcmp (name, "char") == 0 || strcmp (name, "short") == 0 ||
-        strcmp (name, "int") == 0 || strcmp (name, "long") == 0 ||
-        strcmp (name, "signed") == 0 || strcmp (name, "unsigned") == 0 ||
-        strcmp (name, "void") == 0 || strcmp (name, "struct") == 0 ||
-        strcmp (name, "union") == 0 || strcmp (name, "enum") == 0) {
-        return 1;
-    }
-    
-    return find_typedef_name (name) != 0;
-
-}
-
-static int parse_cast_indirect_assignment_statement (void) {
-
-    int saved_type_size = parsed_type_size;
-    int saved_storage_class = parsed_storage_class;
-    int saved_is_aggregate = parsed_type_is_aggregate;
-    int saved_is_void = parsed_type_is_void;
-    int saved_is_unsigned = parsed_type_is_unsigned;
-    int saved_is_floating = parsed_type_is_floating;
-    int saved_has_tag = parsed_type_has_tag;
-    int saved_is_inline = parsed_type_is_inline;
-    int saved_field_count = parsed_field_count;
-    int saved_fields[MAX_AGG_FIELDS];
-    int saved_declarator_is_pointer = declarator_is_pointer;
-    int saved_declarator_pointer_depth = declarator_pointer_depth;
-    int saved_declarator_has_array = declarator_has_array;
-    int saved_declarator_has_function = declarator_has_function;
-    int saved_declarator_array_unsized = declarator_array_unsized;
-    int saved_declarator_array_dimensions = declarator_array_dimensions;
-    
-    long saved_declarator_first_array_count = declarator_first_array_count;
-    long saved_declarator_array_count = declarator_array_count;
-    
-    char *cast_name = 0;
-    int base_size;
-    int deref_size;
-    int pointer_depth;
-    int i;
-    
-    enum token_kind op;
-    int has_outer_paren = 0;
-    
-    if (tok.kind != TOK_LPAREN) {
-        return 0;
-    }
-    
-    get_token ();
-    
-    /*
-     * Accept the common casted-dereference lvalue spelling:
-     *
-     *     *((char *)ptr + n) = v;
-     *
-     * parse_indirect_assignment_statement() enters here at the outer '(';
-     * the actual cast type begins after the inner '('.
-     */
-    if (tok.kind == TOK_LPAREN) {
-    
-        has_outer_paren = 1;
-        get_token ();
-    
-    }
-    
-    if (!is_type_start (tok.kind)) {
-        return 0;
-    }
-    
-    for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
-        saved_fields[i] = parsed_field_sizes[i];
-    }
-    
-    parse_type_spec ();
-    base_size = parsed_type_size & 0x1f;
-    
-    if (tok.kind != TOK_RPAREN) {
-        parse_declarator (&cast_name);
-    }
-    
-    pointer_depth = declarator_is_pointer ? (declarator_pointer_depth > 0 ? declarator_pointer_depth : 1) : 0;
-    deref_size = pointer_depth > 1 ? (DATA_PTR & 0x1f) : base_size;
-    
-    if (deref_size <= 0) {
-        deref_size = DATA_INT & 0x1f;
-    }
-    
-    if (cast_name) {
-        free (cast_name);
-    }
-    
-    expect (TOK_RPAREN, ")");
-    
-    parsed_type_size = saved_type_size;
-    parsed_storage_class = saved_storage_class;
-    parsed_type_is_aggregate = saved_is_aggregate;
-    parsed_type_is_void = saved_is_void;
-    parsed_type_is_unsigned = saved_is_unsigned;
-    parsed_type_is_floating = saved_is_floating;
-    parsed_type_has_tag = saved_has_tag;
-    parsed_type_is_inline = saved_is_inline;
-    
-    clear_parsed_fields ();
-    
-    for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
-        parsed_field_sizes[i] = saved_fields[i];
-    }
-    
-    parsed_field_count = saved_field_count;
-    
-    declarator_is_pointer = saved_declarator_is_pointer;
-    declarator_pointer_depth = saved_declarator_pointer_depth;
-    declarator_has_array = saved_declarator_has_array;
-    declarator_has_function = saved_declarator_has_function;
-    declarator_array_unsized = saved_declarator_array_unsized;
-    declarator_array_count = saved_declarator_array_count;
-    declarator_first_array_count = saved_declarator_first_array_count;
-    declarator_array_dimensions = saved_declarator_array_dimensions;
-    
-    if (state->ofp) {
-    
-        /*
-         * Parse the address expression inside the outer dereference without
-         * allowing the first operand parser to consume the assignment operator.
-         *
-         * For:
-         *
-         *     *(size_t *)ptr = size;
-         *
-         * emit_load_assignment_rhs_to_reg() sees the identifier "ptr" followed
-         * by '=' and treats it as an assignment expression, generating
-         * "ptr = size" instead of using ptr as the destination address.  Load a
-         * plain identifier operand directly, then let the explicit '+'/'-' loop
-         * below handle the casted pointer arithmetic case:
-         *
-         *     *((char *)ptr + *actualRead) = '\n';
-         */
-        if (tok.kind == TOK_IDENT) {
-        
-            char *addr_name = xstrdup (tok.ident);
-            
-            const char *addr_start = tok.start;
-            const char *addr_caret = tok.caret;
-            
-            unsigned long addr_line = get_line_number ();
-            
-            struct local_symbol *addr_sym;
-            int addr_global_index;
-            
-            get_token ();
-            
-            addr_sym = find_local_symbol (addr_name);
-            addr_global_index = find_global_symbol (addr_name);
-            
-            if (addr_sym) {
-            
-                if (addr_sym->is_static && addr_sym->static_label) {
-                    emit_load_global_to_reg ("edx", addr_sym->static_label, DATA_PTR);
-                } else {
-                    emit_load_local_to_reg ("edx", addr_sym->offset, DATA_PTR);
-                }
-            
-            } else if (addr_global_index >= 0) {
-                emit_load_global_to_reg ("edx", addr_name, DATA_PTR);
-            } else {
-                report_line_at (get_filename (), addr_line, REPORT_ERROR, addr_start, addr_caret, "unknown symbol '%s'", addr_name);
-            }
-            
-            free (addr_name);
-        
-        } else {
-            emit_load_assignment_rhs_to_reg ("edx");
-        }
-        
-        while (tok.kind == TOK_PLUS || tok.kind == TOK_MINUS) {
-        
-            enum token_kind addr_op = tok.kind;
-            get_token ();
-            
-            emit_push_reg_now ("edx");
-            emit_load_assignment_rhs_to_reg ("eax");
-            
-            if (deref_size > 1) {
-                emit_scale_reg_by_const_now ("eax", deref_size);
-            }
-            
-            emit_pop_reg_now ("edx");
-            
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                fprintf (state->ofp, "    %s edx, eax\n", addr_op == TOK_PLUS ? "add" : "sub");
-            } else {
-                fprintf (state->ofp, "    %sl %%eax, %%edx\n", addr_op == TOK_PLUS ? "add" : "sub");
-            }
-        
-        }
-    
-    } else {
-        skip_balanced_until (TOK_RPAREN, TOK_SEMI, TOK_EOF);
-    }
-    
-    if (has_outer_paren) {
-        expect (TOK_RPAREN, ")");
-    }
-    
-    if (!is_assignment_operator (tok.kind)) {
-    
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        
-        expect_semi_or_recover ();
-        return 1;
-    
-    }
-    
-    op = tok.kind;
-    get_token ();
-    
-    if (op == TOK_ASSIGN) {
-    
-        emit_push_reg_now ("edx");
-        emit_load_assignment_rhs_expression_to_reg ("eax");
-        emit_pop_reg_now ("edx");
-    
-    } else {
-    
-        emit_push_reg_now ("edx");
-        emit_load_deref_reg_now ("eax", deref_size);
-        emit_push_reg_now ("eax");
-        emit_load_assignment_rhs_expression_to_reg ("edx");
-        emit_pop_reg_now ("eax");
-        emit_assignment_binary_op (op, 0);
-        emit_pop_reg_now ("edx");
-    
-    }
-    
-    emit_store_reg_to_deref_reg_now ("edx", "eax", deref_size);
-    expect_semi_or_recover ();
-    
-    return 1;
-
-}
-
-static int lparen_expression_starts_with_star_now (void) {
-
-    const char *p;
-    
-    if (tok.kind != TOK_LPAREN || !tok.caret) {
-        return 0;
-    }
-    
-    p = tok.caret + 1;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    return *p == '*';
-
-}
-
-static int parse_parenthesized_indirect_assignment_statement (void) {
-
-    enum token_kind op;
-    
-    int pointer_depth;
-    int pointed_size;
-    int deref_size = DATA_INT & 0x1f;
-    
-    if (tok.kind != TOK_LPAREN) {
-        return 0;
-    }
-    
-    get_token ();
-    emit_load_assignment_rhs_expression_to_reg ("edx");
-    
-    pointer_depth = rhs_last_pointer_depth;
-    pointed_size = rhs_last_pointed_size;
-    
-    if (pointer_depth > 1) {
-        deref_size = DATA_PTR & 0x1f;
-    } else if (pointer_depth == 1 && pointed_size > 0) {
-        deref_size = pointed_size & 0x1f;
-    }
-    
-    if (deref_size <= 0) {
-        deref_size = DATA_INT & 0x1f;
-    }
-    
-    expect (TOK_RPAREN, ")");
-    
-    if (!is_assignment_operator (tok.kind)) {
-    
-        expect_semi_or_recover ();
-        return 1;
-    
-    }
-    
-    op = tok.kind;
-    get_token ();
-    
-    if (op == TOK_ASSIGN) {
-    
-        emit_push_reg_now ("edx");
-        
-        emit_load_assignment_rhs_expression_to_reg ("eax");
-        emit_pop_reg_now ("edx");
-    
-    } else {
-    
-        emit_push_reg_now ("edx");
-        
-        emit_load_deref_reg_now ("eax", deref_size);
-        emit_push_reg_now ("eax");
-        
-        emit_load_assignment_rhs_expression_to_reg ("edx");
-        emit_pop_reg_now ("eax");
-        
-        emit_assignment_binary_op (op, 0);
-        emit_pop_reg_now ("edx");
-    
-    }
-    
-    emit_store_reg_to_deref_reg_now ("edx", "eax", deref_size);
-    expect_semi_or_recover ();
-    
-    return 1;
-
-}
-
-static int parse_indirect_assignment_statement (void) {
-
-    char *name;
-    
-    const char *name_start;
-    const char *name_caret;
-    
-    unsigned long name_line;
-    struct local_symbol *lhs;
-    
-    int deref_size = DATA_INT & 0x1f;
-    int deref_is_floating = 0;
-    
-    enum token_kind op;
-    int global_index;
-    
-    if (tok.kind != TOK_STAR) {
-        return 0;
-    }
-    
-    if (emit_store_to_deref_parenthesized_deref_postfix_incdec_now ("eax")) {
-    
-        expect_semi_or_recover ();
-        return 1;
-    
-    }
-    
-    get_token ();
-    
-    if (tok.kind == TOK_STAR) {
-    
-        get_token ();
-        
-        if (tok.kind == TOK_IDENT) {
-        
-            name = xstrdup (tok.ident);
-            
-            name_start = tok.start;
-            name_caret = tok.caret;
-            
-            name_line = get_line_number ();
-            get_token ();
-            
-            if (is_assignment_operator (tok.kind)) {
-            
-                op = tok.kind;
-                get_token ();
-                
-                lhs = find_local_symbol (name);
-                global_index = find_global_symbol (name);
-                
-                if (!lhs && global_index < 0) {
-                
-                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-                    
-                    skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-                    expect_semi_or_recover ();
-                    
-                    free (name);
-                    return 1;
-                
-                }
-                
-                if (lhs) {
-                
-                    if (lhs->pointer_depth > 2) {
-                        deref_size = DATA_PTR & 0x1f;
-                    } else if (lhs->pointer_depth == 2) {
-                        deref_size = lhs->pointed_size & 0x1f;
-                    }
-                
-                } else {
-                
-                    if (get_global_symbol_pointer_depth (name) > 2) {
-                        deref_size = DATA_PTR & 0x1f;
-                    } else if (get_global_symbol_pointer_depth (name) == 2) {
-                        deref_size = get_global_symbol_pointed_size (name) & 0x1f;
-                    }
-                
-                }
-                
-                if (deref_size <= 0) {
-                    deref_size = DATA_INT & 0x1f;
-                }
-                
-                if (state->ofp) {
-                
-                    if (lhs) {
-                    
-                        if (lhs->is_static && lhs->static_label) {
-                            emit_load_global_to_reg ("ecx", lhs->static_label, DATA_PTR);
-                        } else {
-                            emit_load_local_to_reg ("ecx", lhs->offset, DATA_PTR);
-                        }
-                    
-                    } else {
-                        emit_load_global_to_reg ("ecx", name, DATA_PTR);
-                    }
-                    
-                    emit_load_deref_reg_now ("ecx", DATA_PTR & 0x1f);
-                    
-                    if (op == TOK_ASSIGN) {
-                    
-                        emit_push_reg_now ("ecx");
-                        
-                        emit_load_assignment_rhs_expression_to_reg ("eax");
-                        emit_pop_reg_now ("ecx");
-                    
-                    } else {
-                    
-                        emit_push_reg_now ("ecx");
-                        
-                        emit_load_member_from_addr_reg_now ("eax", "ecx", 0, deref_size);
-                        emit_push_reg_now ("eax");
-                        
-                        emit_load_assignment_rhs_expression_to_reg ("edx");
-                        emit_pop_reg_now ("eax");
-                        
-                        emit_assignment_binary_op (op, 0);
-                        emit_pop_reg_now ("ecx");
-                    
-                    }
-                    
-                    emit_store_reg_to_deref_reg_now ("ecx", "eax", deref_size);
-                
-                } else {
-                    skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-                }
-                
-                expect_semi_or_recover ();
-                
-                free (name);
-                return 1;
-            
-            }
-            
-            free (name);
-        
-        }
-        
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        
-        expect_semi_or_recover ();
-        return 1;
-    
-    }
-    
-    if (tok.kind != TOK_IDENT) {
-    
-        if (tok.kind == TOK_LPAREN) {
-        
-            if (paren_text_starts_type_name_now () ||
-                (tok.start && tok.start[0] == '(' && tok.start[1] == '(')) {
-                return parse_cast_indirect_assignment_statement ();
-            }
-            
-            if (lparen_expression_starts_with_star_now ()) {
-                return parse_parenthesized_pointer_member_indirect_assignment_statement ();
-            }
-            
-            return parse_parenthesized_indirect_assignment_statement ();
-        
-        }
-        
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        expect_semi_or_recover ();
-        
-        return 1;
-    
-    }
-    
-    name = xstrdup (tok.ident);
-    name_start = tok.start;
-    name_caret = tok.caret;
-    name_line = get_line_number ();
-    
-    get_token ();
-    
-    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-    
-        enum token_kind postfix_op = tok.kind;
-        int step = 1;
-        
-        get_token ();
-        
-        if (!is_assignment_operator (tok.kind)) {
-        
-            free (name);
-            
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-            expect_semi_or_recover ();
-            
-            return 1;
-        
-        }
-        
-        op = tok.kind;
-        get_token ();
-        
-        lhs = find_local_symbol (name);
-        global_index = find_global_symbol (name);
-        
-        if (!lhs && global_index < 0) {
-        
-            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-            
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-            expect_semi_or_recover ();
-            
-            free (name);
-            return 1;
-        
-        }
-        
-        if (lhs) {
-        
-            if (lhs->pointer_depth > 1) {
-            
-                deref_size = DATA_PTR & 0x1f;
-                step = DATA_PTR & 0x1f;
-            
-            } else if (lhs->pointer_depth == 1) {
-            
-                deref_size = lhs->pointed_size & 0x1f;
-                step = lhs->pointed_size > 0 ? lhs->pointed_size : 1;
-            
-            }
-        
-        } else {
-            
-            if (get_global_symbol_pointer_depth (name) > 1) {
-            
-                deref_size = DATA_PTR & 0x1f;
-                step = DATA_PTR & 0x1f;
-            
-            } else if (get_global_symbol_pointer_depth (name) == 1) {
-            
-                deref_size = get_global_symbol_pointed_size (name) & 0x1f;
-                step = get_global_symbol_pointed_size (name) > 0 ? get_global_symbol_pointed_size (name) : 1;
-            
-            }
-        
-        }
-        
-        if (deref_size == 0) {
-            deref_size = DATA_INT & 0x1f;
-        }
-        
-        if (state->ofp) {
-        
-            if (lhs) {
-            
-                if (lhs->is_static && lhs->static_label) {
-                    emit_load_global_to_reg ("ecx", lhs->static_label, DATA_PTR);
-                } else {
-                    emit_load_local_to_reg ("ecx", lhs->offset, DATA_PTR);
-                }
-            
-            } else {
-                emit_load_global_to_reg ("ecx", name, DATA_PTR);
-            }
-            
-            emit_push_reg_now ("ecx");
-            
-            if (lhs) {
-            
-                if (lhs->is_static && lhs->static_label) {
-                
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s dword [%s], %d\n" : "    %s dword ptr [%s], %d\n"), postfix_op == TOK_INCR ? "add" : "sub", lhs->static_label, step);
-                    } else {
-                        fprintf (state->ofp, "    %sl $%d, %s\n", postfix_op == TOK_INCR ? "add" : "sub", step, lhs->static_label);
-                    }
-                
-                } else {
-                
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                    
-                        char memref[64];
-                        
-                        format_intel_ebp_offset (memref, sizeof (memref), lhs->offset);
-                        fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s dword %s, %d\n" : "    %s dword ptr %s, %d\n"), postfix_op == TOK_INCR ? "add" : "sub", memref, step);
-                    
-                    } else {
-                        fprintf (state->ofp, "    %sl $%d, %ld(%%ebp)\n", postfix_op == TOK_INCR ? "add" : "sub", step, lhs->offset);
-                    }
-                
-                }
-            
-            } else {
-                
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                    fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    %s dword [%s], %d\n" : "    %s dword ptr [%s], %d\n"), postfix_op == TOK_INCR ? "add" : "sub", name, step);
-                } else {
-                    fprintf (state->ofp, "    %sl $%d, %s\n", postfix_op == TOK_INCR ? "add" : "sub", step, name);
-                }
-            
-            }
-            
-            if (op == TOK_ASSIGN) {
-                emit_load_assignment_rhs_expression_to_reg ("eax");
-            } else {
-            
-                emit_pop_reg_now ("edx");
-                emit_push_reg_now ("edx");
-                emit_load_member_from_addr_reg_now ("eax", "edx", 0, deref_size);
-                emit_push_reg_now ("eax");
-                emit_load_assignment_rhs_expression_to_reg ("edx");
-                emit_pop_reg_now ("eax");
-                emit_assignment_binary_op (op, 0);
-            
-            }
-            
-            emit_pop_reg_now ("edx");
-            emit_store_reg_to_deref_reg_now ("edx", "eax", deref_size);
-        
-        } else {
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        }
-        
-        expect_semi_or_recover ();
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
-    
-        enum token_kind member_op = tok.kind;
-        enum token_kind postfix_op = TOK_EOF;
-        
-        char *member;
-        
-        const char *member_start;
-        const char *member_caret;
-        
-        unsigned long member_line;
-        
-        int offset = 0;
-        int member_size = DATA_PTR & 0x1f;
-        int member_elem_size = DATA_INT & 0x1f;
-        int member_pointer_depth = 0;
-        int step;
-        
-        get_token ();
-        
-        member_start = tok.start;
-        member_caret = tok.caret;
-        member_line = get_line_number ();
-        
-        if (tok.kind != TOK_IDENT) {
-        
-            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
-            
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-            expect_semi_or_recover ();
-            
-            free (name);
-            return 1;
-        
-        }
-        
-        member = xstrdup (tok.ident);
-        get_token ();
-        
-        if (!find_member_info_ex (member, &offset, &member_size, &member_elem_size, &member_pointer_depth, 0, 0)) {
-        
-            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
-            
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-            expect_semi_or_recover ();
-            
-            free (member);
-            free (name);
-            
-            return 1;
-        
-        }
-        
-        free (member);
-        
-        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-        
-            postfix_op = tok.kind;
-            get_token ();
-        
-        }
-        
-        if (!is_assignment_operator (tok.kind)) {
-        
-            free (name);
-            
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-            expect_semi_or_recover ();
-            
-            return 1;
-        
-        }
-        
-        op = tok.kind;
-        get_token ();
-        
-        lhs = find_local_symbol (name);
-        global_index = find_global_symbol (name);
-        
-        if (!lhs && global_index < 0) {
-        
-            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-            
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-            expect_semi_or_recover ();
-            
-            free (name);
-            return 1;
-        
-        }
-        
-        if (member_pointer_depth > 1) {
-            deref_size = DATA_PTR & 0x1f;
-        } else if (member_pointer_depth == 1 && member_elem_size > 0) {
-            deref_size = member_elem_size & 0x1f;
-        }
-        
-        if (deref_size == 0) {
-            deref_size = DATA_INT & 0x1f;
-        }
-        
-        step = member_elem_size > 0 ? member_elem_size : 1;
-        
-        if (state->ofp) {
-        
-            if (lhs) {
-            
-                if (member_op == TOK_ARROW) {
-                
-                    if (lhs->is_static && lhs->static_label) {
-                        emit_load_global_to_reg ("edx", lhs->static_label, DATA_PTR);
-                    } else {
-                        emit_load_local_to_reg ("edx", lhs->offset, DATA_PTR);
-                    }
-                
-                } else {
-                
-                    if (lhs->is_static && lhs->static_label) {
-                        emit_load_address_to_reg_now ("edx", lhs->static_label);
-                    } else {
-                        emit_load_local_address_to_reg_now ("edx", lhs->offset);
-                    }
-                
-                }
-            
-            } else {
-            
-                if (member_op == TOK_ARROW) {
-                    emit_load_global_to_reg ("edx", name, DATA_PTR);
-                } else {
-                    emit_load_address_to_reg_now ("edx", name);
-                }
-            
-            }
-            
-            emit_load_member_from_addr_reg_now ("ecx", "edx", offset, DATA_PTR & 0x1f);
-            
-            if (postfix_op == TOK_INCR || postfix_op == TOK_DECR) {
-            
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                
-                    if (state->syntax & ASM_SYNTAX_NASM) {
-                        fprintf (state->ofp, "    %s dword [edx + %d], %d\n", postfix_op == TOK_INCR ? "add" : "sub", offset, step);
-                    } else {
-                        fprintf (state->ofp, "    %s dword ptr [edx + %d], %d\n", postfix_op == TOK_INCR ? "add" : "sub", offset, step);
-                    }
-                
-                } else {
-                    fprintf (state->ofp, "    %sl $%d, %d(%%edx)\n", postfix_op == TOK_INCR ? "add" : "sub", step, offset);
-                }
-            
-            }
-            
-            emit_push_reg_now ("ecx");
-            
-            if (op == TOK_ASSIGN) {
-                emit_load_assignment_rhs_expression_to_reg ("eax");
-            } else {
-            
-                emit_load_member_from_addr_reg_now ("eax", "edx", 0, deref_size);
-                emit_push_reg_now ("eax");
-                emit_load_assignment_rhs_expression_to_reg ("edx");
-                emit_pop_reg_now ("eax");
-                emit_assignment_binary_op (op, 0);
-            
-            }
-            
-            emit_pop_reg_now ("edx");
-            emit_store_reg_to_deref_reg_now ("edx", "eax", deref_size);
-        
-        } else {
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        }
-        
-        expect_semi_or_recover ();
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    if (!is_assignment_operator (tok.kind)) {
-    
-        free (name);
-        
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        expect_semi_or_recover ();
-        
-        return 1;
-    
-    }
-    
-    op = tok.kind;
-    get_token ();
-    
-    lhs = find_local_symbol (name);
-    global_index = find_global_symbol (name);
-    
-    if (!lhs && global_index < 0) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-        
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        expect_semi_or_recover ();
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    if (lhs) {
-    
-        if (lhs->pointer_depth > 1) {
-        
-            deref_size = DATA_PTR & 0x1f;
-            deref_is_floating = 0;
-        
-        } else if (lhs->pointer_depth == 1) {
-        
-            /**
-             * Keep aggregate pointed-to sizes intact for assignments like
-             * *hashtab = old_hashtab;  Masking with 0x1f corrupts struct
-             * copies whose size is greater than 31 bytes.
-             */
-            deref_size = lhs->pointed_size;
-            deref_is_floating = lhs->pointed_is_floating;
-        
-        }
-    
-    } else {
-    
-        if (get_global_symbol_pointer_depth (name) > 1) {
-        
-            deref_size = DATA_PTR & 0x1f;
-            deref_is_floating = 0;
-        
-        } else if (get_global_symbol_pointer_depth (name) == 1) {
-        
-            deref_size = get_global_symbol_pointed_size (name);
-            deref_is_floating = get_global_symbol_pointed_is_floating (name);
-        
-        }
-    
-    }
-    
-    if (deref_size == 0) {
-        deref_size = DATA_INT & 0x1f;
-    }
-    
-    if (state->ofp) {
-    
-        if (lhs) {
-        
-            if (lhs->is_static && lhs->static_label) {
-                emit_load_global_to_reg ("edx", lhs->static_label, DATA_PTR);
-            } else {
-                emit_load_local_to_reg ("edx", lhs->offset, DATA_PTR);
-            }
-        
-        } else {
-            emit_load_global_to_reg ("edx", name, DATA_PTR);
-        }
-        
-        if (op == TOK_ASSIGN) {
-        
-            if (deref_is_floating) {
-            
-                emit_push_reg_now ("edx");
-                
-                emit_load_floating_rhs_expression_now (deref_size);
-                emit_pop_reg_now ("edx");
-                
-                emit_store_floating_member_to_addr_reg_now ("edx", 0, deref_size);
-                expect_semi_or_recover ();
-                
-                free (name);
-                return 1;
-            
-            }
-            
-            if (deref_size != (DATA_LLONG & 0x1f) && emit_aggregate_copy_from_current_rhs_to_addr_reg_now ("edx", 0, deref_size)) {
-            
-                expect_semi_or_recover ();
-                
-                free (name);
-                return 1;
-            
-            }
-            
-            emit_push_reg_now ("edx");
-            
-            if (deref_size == (DATA_LLONG & 0x1f)) {
-            
-                emit_load_assignment_rhs_expression_to_pair ("eax", "edx", 1);
-                emit_pop_reg_now ("ecx");
-            
-            } else {
-            
-                emit_load_assignment_rhs_expression_to_reg ("eax");
-                emit_pop_reg_now ("edx");
-            
-            }
-        
-        } else {
-        
-            emit_load_member_from_addr_reg_now ("eax", "edx", 0, deref_size);
-            
-            emit_push_reg_now ("edx");
-            emit_push_reg_now ("eax");
-            
-            emit_load_assignment_rhs_expression_to_reg ("edx");
-            emit_pop_reg_now ("eax");
-            
-            emit_assignment_binary_op (op, 0);
-            emit_pop_reg_now ("edx");
-        
-        }
-        
-        if (deref_size == (DATA_LLONG & 0x1f) && !deref_is_floating) {
-            emit_store_pair_to_deref_reg_now ("ecx", "eax", "edx");
-        } else {
-            emit_store_reg_to_deref_reg_now ("edx", "eax", deref_size);
-        }
-    
-    } else {
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-    }
-    
-    expect_semi_or_recover ();
-    
-    free (name);
-    return 1;
-
-}
-
-static int source_starts_parenthesized_star_now (void) {
-
-    const char *p = tok.caret ? tok.caret : tok.start;
-    
-    if (!p) {
-        return 0;
-    }
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (*p != '(') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    return *p == '*';
-
-}
-
-static int parse_parenthesized_indirect_member_assignment_statement (void) {
-
-    enum token_kind member_op;
-    enum token_kind op;
-    
-    char *member;
-    
-    const char *member_start;
-    const char *member_caret;
-    
-    unsigned long member_line;
-    
-    int member_offset = 0;
-    int member_size = DATA_INT & 0x1f;
-    int saw_close = 0;
-    
-    if (tok.kind != TOK_LPAREN || !source_starts_parenthesized_star_now ()) {
-        return 0;
-    }
-    
-    get_token ();
-    
-    if (tok.kind != TOK_STAR) {
-        return 0;
-    }
-    
-    get_token ();
-    
-    /*
-     * Parse only the object expression inside the parenthesized dereference.
-     * For macro-expanded lvalues such as
-     *
-     *     (*(__gtin()))->field = value;
-     *
-     * the normal assignment-expression loader can consume the complete
-     * "->field = value" tail as a value expression.  That emits only
-     * member loads and drops the store.
-     */
-    if (tok.kind == TOK_LPAREN) {
-    
-        int parens = 0;
-        char *inner_name = 0;
-        
-        const char *inner_start = 0;
-        const char *inner_caret = 0;
-        
-        unsigned long inner_line = 0;
-        struct local_symbol *inner_lhs;
-        
-        while (tok.kind == TOK_LPAREN) {
-        
-            parens++;
-            get_token ();
-        
-        }
-        
-        if (tok.kind == TOK_IDENT) {
-        
-            inner_name = xstrdup (tok.ident);
-            inner_start = tok.start;
-            inner_caret = tok.caret;
-            inner_line = get_line_number ();
-            
-            get_token ();
-            
-            if (tok.kind == TOK_LPAREN) {
-                emit_call_identifier_to_reg_now (inner_name, "edx", inner_start, inner_caret, inner_line);
-            } else {
-            
-                inner_lhs = find_local_symbol (inner_name);
-                
-                if (inner_lhs) {
-                
-                    if (inner_lhs->is_static && inner_lhs->static_label) {
-                        emit_load_global_to_reg ("edx", inner_lhs->static_label, DATA_PTR);
-                    } else {
-                        emit_load_local_to_reg ("edx", inner_lhs->offset, DATA_PTR);
-                    }
-                
-                } else {
-                    emit_load_global_to_reg ("edx", inner_name, DATA_PTR);
-                }
-            
-            }
-            
-            free (inner_name);
-            
-            while (parens > 0 && tok.kind == TOK_RPAREN) {
-            
-                saw_close = 1;
-                parens--;
-                
-                get_token ();
-            
-            }
-        
-        } else {
-            emit_load_assignment_rhs_expression_to_reg ("edx");
-        }
-    
-    } else {
-        emit_load_assignment_rhs_expression_to_reg ("edx");
-    }
-    
-    while (tok.kind == TOK_RPAREN) {
-    
-        saw_close = 1;
-        get_token ();
-    
-    }
-    
-    if (!saw_close) {
-    
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        expect_semi_or_recover ();
-        
-        return 1;
-    
-    }
-    
-    if (tok.kind != TOK_ARROW && tok.kind != TOK_DOT) {
-    
-        int deref_size = DATA_INT & 0x1f;
-        int step = 1;
-        
-        if (rhs_last_pointer_depth > 1) {
-        
-            deref_size = DATA_PTR & 0x1f;
-            step = DATA_PTR & 0x1f;
-        
-        } else if (rhs_last_pointer_depth == 1 && rhs_last_pointed_size > 0) {
-            deref_size = rhs_last_pointed_size & 0x1f;
-        }
-        
-        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-        
-            op = tok.kind;
-            get_token ();
-            
-            if (state->ofp) {
-            
-                emit_load_member_from_addr_reg_now ("eax", "edx", 0, deref_size);
-                
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                    fprintf (state->ofp, "    %s eax, %d\n", op == TOK_INCR ? "add" : "sub", step);
-                } else {
-                    fprintf (state->ofp, "    %sl $%d, %%eax\n", op == TOK_INCR ? "add" : "sub", step);
-                }
-                
-                emit_store_reg_to_deref_reg_now ("edx", "eax", deref_size);
-            
-            }
-            
-            expect_semi_or_recover ();
-            return 1;
-        
-        }
-        
-        if (!is_assignment_operator (tok.kind)) {
-        
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-            expect_semi_or_recover ();
-            
-            return 1;
-        
-        }
-        
-        op = tok.kind;
-        get_token ();
-        
-        if (state->ofp) {
-        
-            if (op == TOK_ASSIGN) {
-            
-                emit_push_reg_now ("edx");
-                emit_load_assignment_rhs_expression_to_reg ("eax");
-                emit_pop_reg_now ("edx");
-            
-            } else {
-            
-                emit_load_member_from_addr_reg_now ("eax", "edx", 0, deref_size);
-                emit_push_reg_now ("edx");
-                emit_push_reg_now ("eax");
-                emit_load_assignment_rhs_expression_to_reg ("edx");
-                emit_pop_reg_now ("eax");
-                emit_assignment_binary_op (op, 0);
-                emit_pop_reg_now ("edx");
-            
-            }
-            
-            emit_store_reg_to_deref_reg_now ("edx", "eax", deref_size);
-        
-        } else {
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        }
-        
-        expect_semi_or_recover ();
-        return 1;
-    
-    }
-    
-    if (state->ofp) {
-        emit_load_deref_reg_now ("edx", DATA_PTR);
-    }
-    
-    member_op = tok.kind;
-    get_token ();
-    
-    member_start = tok.start;
-    member_caret = tok.caret;
-    member_line = get_line_number ();
-    
-    if (tok.kind != TOK_IDENT) {
-    
-        report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
-        
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        expect_semi_or_recover ();
-        
-        return 1;
-    
-    }
-    
-    member = xstrdup (tok.ident);
-    get_token ();
-    
-    if (!find_member_info (member, &member_offset, &member_size)) {
-    
-        report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
-        free (member);
-        
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        expect_semi_or_recover ();
-        
-        return 1;
-    
-    }
-    
-    free (member);
-    
-    if (!is_assignment_operator (tok.kind)) {
-    
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        expect_semi_or_recover ();
-        
-        return 1;
-    
-    }
-    
-    op = tok.kind;
-    get_token ();
-    
-    if (state->ofp) {
-    
-        if (op == TOK_ASSIGN) {
-        
-            emit_push_reg_now ("edx");
-            emit_load_assignment_rhs_expression_to_reg ("eax");
-            emit_pop_reg_now ("edx");
-        
-        } else {
-        
-            emit_load_member_from_addr_reg_now ("eax", "edx", member_offset, member_size);
-            emit_push_reg_now ("edx");
-            emit_push_reg_now ("eax");
-            emit_load_assignment_rhs_expression_to_reg ("edx");
-            emit_pop_reg_now ("eax");
-            emit_assignment_binary_op (op, 0);
-            emit_pop_reg_now ("edx");
-        
-        }
-        
-        emit_store_member_to_addr_reg_now ("edx", member_offset, "eax", member_size);
-    
-    } else {
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-    }
-    
-    expect_semi_or_recover ();
-    return 1;
-
-}
-
-static int token_text_looks_like_postfix_call_now (void) {
-
-    const char *p;
-    
-    int saw_postfix;
-    int paren_depth;
-    int bracket_depth;
-    
-    if (tok.caret) {
-        p = tok.caret;
-    } else if (tok.start) {
-        p = tok.start;
-    } else {
-        return 0;
-    }
-    
-    saw_postfix = 0;
-    paren_depth = 0;
-    bracket_depth = 0;
-    
-    while (*p && *p != ';' && *p != '\n') {
-    
-        if (*p == '(') {
-        
-            if (saw_postfix && paren_depth == 0 && bracket_depth == 0) {
-                return 1;
-            }
-            
-            paren_depth++;
-        
-        } else if (*p == ')') {
-        
-            if (paren_depth > 0) {
-                paren_depth--;
-            }
-        
-        } else if (*p == '[') {
-            bracket_depth++;
-        } else if (*p == ']') {
-        
-            if (bracket_depth > 0) {
-                bracket_depth--;
-            }
-        
-        } else if (paren_depth == 0 && bracket_depth == 0 && *p == '.') {
-            saw_postfix = 1;
-        } else if (paren_depth == 0 && bracket_depth == 0 && *p == '-' && p[1] == '>') {
-        
-            saw_postfix = 1;
-            p++;
-        
-        } else if (paren_depth == 0 && bracket_depth == 0 && *p == '=') {
-            return 0;
-        }
-        
-        p++;
-    
-    }
-    
-    return 0;
-
-}
-
-static int parse_parenthesized_deref_subscript_statement (void) {
-
-    char *name;
-    
-    const char *name_start;
-    const char *name_caret;
-    
-    unsigned long name_line;
-    struct local_symbol *src;
-    
-    int global_index;
-    int pointer_depth;
-    int pointed_size;
-    
-    if (tok.kind != TOK_LPAREN || !source_starts_lparen_deref_subscript_at (tok.caret)) {
-        return 0;
-    }
-    
-    get_token ();
-    
-    if (tok.kind != TOK_STAR) {
-        return 0;
-    }
-    
-    get_token ();
-    
-    name_start = tok.start;
-    name_caret = tok.caret;
-    name_line = get_line_number ();
-    
-    if (tok.kind != TOK_IDENT || !tok.ident) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "expected identifier after *");
-        return 1;
-    
-    }
-    
-    name = xstrdup (tok.ident);
-    get_token ();
-    
-    expect (TOK_RPAREN, ")");
-    
-    src = find_local_symbol (name);
-    global_index = find_global_symbol (name);
-    
-    pointer_depth = 0;
-    pointed_size = DATA_INT & 0x1f;
-    
-    if (src) {
-    
-        pointer_depth = src->pointer_depth;
-        pointed_size = src->pointed_size;
-        
-        if (src->is_static && src->static_label) {
-            emit_load_global_to_reg ("eax", src->static_label, DATA_PTR);
-        } else {
-            emit_load_local_to_reg ("eax", src->offset, DATA_PTR);
-        }
-    
-    } else if (global_index >= 0) {
-    
-        pointer_depth = get_global_symbol_pointer_depth (name);
-        pointed_size = get_global_symbol_pointed_size (name);
-        
-        emit_load_global_to_reg ("eax", name, DATA_PTR);
-    
-    } else {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    if (pointer_depth <= 0) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid indirection of non-pointer '%s'", name);
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    emit_load_deref_reg_now ("eax", DATA_PTR & 0x1f);
-    emit_handle_subscript_after_loaded_pointer_to_reg_now ("eax", pointer_depth - 1, pointed_size, src ? src->pointed_is_unsigned : get_global_symbol_pointed_is_unsigned (name));
-    
-    free (name);
-    return 1;
-
-}
-
-static int parse_identifier_assignment_statement (void) {
-
-    char *name;
-    int global_index;
-    
-    const char *name_start, *name_caret;
-    unsigned long name_line;
-    
-    enum token_kind op;
-    struct local_symbol *lhs;
-    
-    int is_simple_assign;
-    int lhs_size;
-    int lhs_is_floating;
-    
-    if (tok.kind != TOK_IDENT) {
-        return 0;
-    }
-    
-    if (token_text_looks_like_postfix_call_now ()) {
-        return 0;
-    }
-    
-    name = xstrdup (tok.ident);
-    name_start = tok.start;
-    name_caret = tok.caret;
-    name_line = get_line_number ();
-    
-    get_token ();
-    
-    if (tok.kind == TOK_COLON) {
-    
-        define_goto_label (name, name_line, name_start, name_caret);
-        
-        get_token ();
-        free (name);
-        
-        parse_statement ();
-        return 1;
-    
-    }
-    
-    if (tok.kind == TOK_DOT || tok.kind == TOK_ARROW) {
-    
-        enum token_kind member_op = tok.kind;
-        char *member;
-        
-        const char *member_start;
-        const char *member_caret;
-        
-        unsigned long member_line;
-        
-        int member_offset = 0;
-        int member_size = DATA_INT & 0x1f;
-        int member_elem_size = DATA_INT & 0x1f;
-        int member_pointer_depth = 0;
-        int member_is_floating = 0;
-        int member_assignment_is_floating = 0;
-        
-        get_token ();
-        
-        member_start = tok.start;
-        member_caret = tok.caret;
-        member_line = get_line_number ();
-        
-        if (tok.kind != TOK_IDENT) {
-        
-            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
-            
-            free (name);
-            return 1;
-        
-        }
-        
-        member = xstrdup (tok.ident);
-        get_token ();
-        
-        lhs = find_local_symbol (name);
-        global_index = find_global_symbol (name);
-        
-        if (!find_member_info_ex_bounded (member,
-                member_op == TOK_DOT
-                    ? (lhs ? lhs->size : (global_index >= 0 ? get_global_symbol_size (name) : 0))
-                    : (lhs ? lhs->pointed_size : (global_index >= 0 ? get_global_symbol_pointed_size (name) : 0)),
-                member_op == TOK_DOT
-                    ? (lhs ? lhs->tag_name : (global_index >= 0 ? get_global_symbol_tag_name (name) : 0))
-                    : (lhs ? lhs->pointed_tag_name : 0),
-                &member_offset, &member_size, &member_elem_size, &member_pointer_depth, 0, &member_is_floating)) {
-        
-            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
-            
-            free (member);
-            free (name);
-            
-            return 1;
-        
-        }
-        
-        free (member);
-        
-        if (!is_assignment_operator (tok.kind)) {
-        
-            if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-            
-                enum token_kind postfix_op = tok.kind;
-                int step = member_pointer_depth > 0 && member_elem_size > 0 ? member_elem_size : 1;
-                
-                get_token ();
-                
-                lhs = find_local_symbol (name);
-                global_index = find_global_symbol (name);
-                
-                if (!lhs && global_index < 0) {
-                
-                    report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-                    
-                    skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-                    expect (TOK_SEMI, ";");
-                    
-                    free (name);
-                    return 1;
-                
-                }
-                
-                if (state->ofp) {
-                
-                    if (member_op == TOK_ARROW) {
-                    
-                        if (lhs) {
-                        
-                            if (lhs->is_static && lhs->static_label) {
-                                emit_load_global_to_reg ("edx", lhs->static_label, DATA_PTR);
-                            } else {
-                                emit_load_local_to_reg ("edx", lhs->offset, DATA_PTR);
-                            }
-                        
-                        } else {
-                            emit_load_global_to_reg ("edx", name, DATA_PTR);
-                        }
-                    
-                    } else {
-                    
-                        if (lhs) {
-                        
-                            if (lhs->is_static && lhs->static_label) {
-                                emit_load_address_to_reg_now ("edx", lhs->static_label);
-                            } else {
-                                emit_load_local_address_to_reg_now ("edx", lhs->offset);
-                            }
-                        
-                        } else {
-                            emit_load_address_to_reg_now ("edx", name);
-                        }
-                    
-                    }
-                    
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                    
-                        const char *opname = postfix_op == TOK_INCR ? "add" : "sub";
-                        const char *opsize = member_size == 1 ? "byte" : (member_size == 2 ? "word" : "dword");
-                        
-                        if (state->syntax & ASM_SYNTAX_NASM) {
-                            fprintf (state->ofp, "    %s %s [edx + %d], %d\n", opname, opsize, member_offset, step);
-                        } else {
-                            fprintf (state->ofp, "    %s %s ptr [edx + %d], %d\n", opname, opsize, member_offset, step);
-                        }
-                    
-                    } else {
-                    
-                        const char *suffix = member_size == 1 ? "b" : (member_size == 2 ? "w" : "l");
-                        fprintf (state->ofp, "    %s%s $%d, %d(%%edx)\n", postfix_op == TOK_INCR ? "add" : "sub", suffix, step, member_offset);
-                    
-                    }
-                
-                }
-                
-                expect_semi_or_recover ();
-                
-                free (name);
-                return 1;
-            
-            }
-            
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-            expect (TOK_SEMI, ";");
-            
-            free (name);
-            return 1;
-        
-        }
-        
-        op = tok.kind;
-        
-        is_simple_assign = (tok.kind == TOK_ASSIGN);
-        get_token ();
-        
-        if (!lhs && global_index < 0) {
-        
-            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-            
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-            expect (TOK_SEMI, ";");
-            
-            free (name);
-            return 1;
-        
-        }
-        
-        if (state->ofp) {
-        
-            if (member_op == TOK_ARROW) {
-            
-                if (lhs) {
-                
-                    if (lhs->is_static && lhs->static_label) {
-                        emit_load_global_to_reg ("edx", lhs->static_label, DATA_PTR);
-                    } else {
-                        emit_load_local_to_reg ("edx", lhs->offset, DATA_PTR);
-                    }
-                
-                } else {
-                    emit_load_global_to_reg ("edx", name, DATA_PTR);
-                }
-            
-            } else {
-            
-                if (lhs) {
-                
-                    if (lhs->is_static && lhs->static_label) {
-                        emit_load_address_to_reg_now ("edx", lhs->static_label);
-                    } else {
-                        emit_load_local_address_to_reg_now ("edx", lhs->offset);
-                    }
-                
-                } else {
-                    emit_load_address_to_reg_now ("edx", name);
-                }
-            
-            }
-            
-            if (is_simple_assign) {
-            
-                member_assignment_is_floating = member_is_floating || rhs_current_operand_is_floating_now ();
-                emit_push_reg_now ("edx");
-                
-                if (member_assignment_is_floating) {
-                    emit_load_floating_rhs_expression_now (member_size);
-                } else {
-                    emit_load_assignment_rhs_expression_to_reg ("eax");
-                }
-                
-                emit_pop_reg_now ("edx");
-            
-            } else {
-            
-                emit_load_member_from_addr_reg_now ("eax", "edx", member_offset, member_size);
-                
-                emit_push_reg_now ("edx");
-                emit_push_reg_now ("eax");
-                
-                if (tok.kind == TOK_TILDE) {
-                
-                    int64_s rhs_const;
-                    get_token ();
-                    
-                    if (tok.kind == TOK_LPAREN) {
-                    
-                        get_token ();
-                        
-                        rhs_const = const64_from_current_foldable_expr ();
-                        expect (TOK_RPAREN, ")");
-                    
-                    } else {
-                        rhs_const = const64_from_current_foldable_expr ();
-                    }
-                    
-                    rhs_const.low = (~rhs_const.low) & U32_MASK;
-                    rhs_const.high = (~rhs_const.high) & U32_MASK;
-                    
-                    emit_load_const32_to_reg_now ("edx", rhs_const);
-                
-                } else if (current_integer_expr_is_foldable_now ()) {
-                
-                    int64_s rhs_const = const64_from_current_foldable_expr ();
-                    emit_load_const32_to_reg_now ("edx", rhs_const);
-                
-                } else {
-                    emit_load_assignment_rhs_expression_to_reg ("edx");
-                }
-                
-                emit_pop_reg_now ("eax");
-                emit_assignment_binary_op (op, 0);
-                emit_pop_reg_now ("edx");
-            
-            }
-            
-            if (member_assignment_is_floating && 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);
-            }
-        
-        } else {
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        }
-        
-        expect_semi_or_recover ();
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    if (tok.kind == TOK_LBRACK) {
-    
-        int elem_size = DATA_INT & 0x1f;
-        int elem_pointer_depth = 0;
-        int elem_pointed_size = DATA_INT & 0x1f;
-        
-        lhs = find_local_symbol (name);
-        global_index = find_global_symbol (name);
-        
-        if (!lhs && global_index < 0) {
-        
-            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-            
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-            expect_semi_or_recover ();
-            
-            free (name);
-            return 1;
-        
-        }
-        
-        if (lhs) {
-        
-            elem_size = lhs->is_array ? (lhs->pointer_depth ? DATA_PTR : lhs->pointed_size) :
-                (lhs->pointer_depth > 1 ? DATA_PTR : lhs->pointed_size);
-            
-            elem_pointer_depth = lhs->pointer_depth > 0 ? lhs->pointer_depth - 1 : 0;
-            elem_pointed_size = lhs->pointed_size;
-        
-        } else {
-        
-            elem_size = get_global_symbol_array (name) ?
-                (get_global_symbol_pointer_depth (name) ? DATA_PTR : (get_global_symbol_array_element_size (name) > 0 ? get_global_symbol_array_element_size (name) : get_global_symbol_pointed_size (name))) :
-                    (get_global_symbol_pointer_depth (name) > 1 ? DATA_PTR : get_global_symbol_pointed_size (name));
-            
-            elem_pointer_depth = get_global_symbol_pointer_depth (name) > 0 ? get_global_symbol_pointer_depth (name) - 1 : 0;
-            elem_pointed_size = get_global_symbol_pointed_size (name);
-        
-        }
-        
-        if ((elem_size & 0x1f) == 0) {
-            elem_size = DATA_INT & 0x1f;
-        }
-        
-        if (state->ofp) {
-        
-            if (lhs) {
-            
-                if (lhs->is_array) {
-                
-                    if (lhs->is_static && lhs->static_label) {
-                        emit_load_symbol_address_to_reg_now ("edx", lhs->static_label, 0, 0);
-                    } else {
-                        emit_load_symbol_address_to_reg_now ("edx", 0, lhs->offset, 1);
-                    }
-                
-                } else if (lhs->is_static && lhs->static_label) {
-                    emit_load_global_to_reg ("edx", lhs->static_label, DATA_PTR);
-                } else {
-                    emit_load_local_to_reg ("edx", lhs->offset, DATA_PTR);
-                }
-            
-            } else if (get_global_symbol_array (name)) {
-                emit_load_symbol_address_to_reg_now ("edx", name, 0, 0);
-            } else {
-                emit_load_global_to_reg ("edx", name, DATA_PTR);
-            }
-            
-            emit_parse_postfix_subscript_scaled_address_to_reg_now ("edx", elem_size);
-        
-        } else {
-            emit_parse_postfix_subscript_scaled_address_to_reg_now ("edx", elem_size);
-        }
-        
-        if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-        
-            op = tok.kind;
-            
-            is_simple_assign = (tok.kind == TOK_ASSIGN);
-            get_token ();
-            
-            if (state->ofp) {
-            
-                int inc_amount = (elem_pointer_depth > 0 && (elem_pointed_size & 0x1f) > 0) ?
-                    (elem_pointed_size & 0x1f) : 1;
-                
-                emit_load_member_from_addr_reg_now ("eax", "edx", 0, elem_size);
-                
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                    fprintf (state->ofp, "    %s eax, %d\n", op == TOK_INCR ? "add" : "sub", inc_amount);
-                } else {
-                    fprintf (state->ofp, "    %sl $%d, %%eax\n", op == TOK_INCR ? "add" : "sub", inc_amount);
-                }
-                
-                emit_store_reg_to_deref_reg_now ("edx", "eax", elem_size);
-            
-            }
-            
-            expect_semi_or_recover ();
-            
-            free (name);
-            return 1;
-        
-        }
-        
-        if (!is_assignment_operator (tok.kind)) {
-        
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-            expect_semi_or_recover ();
-            
-            free (name);
-            return 1;
-        
-        }
-        
-        op = tok.kind;
-        
-        is_simple_assign = (tok.kind == TOK_ASSIGN);
-        get_token ();
-        
-        if (state->ofp) {
-        
-            if (is_simple_assign) {
-            
-                emit_push_reg_now ("edx");
-                emit_load_assignment_rhs_expression_to_reg ("eax");
-                emit_pop_reg_now ("edx");
-            
-            } else {
-            
-                emit_load_member_from_addr_reg_now ("eax", "edx", 0, elem_size);
-                emit_push_reg_now ("edx");
-                emit_push_reg_now ("eax");
-                emit_load_assignment_rhs_expression_to_reg ("edx");
-                emit_pop_reg_now ("eax");
-                emit_assignment_binary_op (op, 0);
-                emit_pop_reg_now ("edx");
-            
-            }
-            
-            emit_store_reg_to_deref_reg_now ("edx", "eax", elem_size);
-        
-        } else {
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        }
-        
-        expect_semi_or_recover ();
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    if (!is_assignment_operator (tok.kind)) {
-    
-        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);
-            emit_incdec_symbol_now (lhs, name, op, name_line, name_start, name_caret);
-            
-            expect_semi_or_recover ();
-            free (name);
-            
-            return 1;
-        
-        }
-        
-        if (tok.kind == TOK_LPAREN) {
-        
-            if (!find_local_symbol (name)) {
-                ensure_global_function_symbol (name, name_start, name_caret, name_line);
-            }
-            
-            emit_call_identifier_to_reg_now (name, "eax", name_start, name_caret, name_line);
-            
-            if (tok.kind == TOK_LBRACK) {
-            
-                int elem_size = get_global_symbol_pointed_size (name);
-                
-                if ((elem_size & 0x1f) == 0) {
-                    elem_size = DATA_INT & 0x1f;
-                }
-                
-                if (state->ofp) {
-                
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                        fprintf (state->ofp, "    mov edx, eax\n");
-                    } else {
-                        fprintf (state->ofp, "    movl %%eax, %%edx\n");
-                    }
-                
-                }
-                
-                emit_parse_postfix_subscript_scaled_address_to_reg_now ("edx", elem_size);
-                
-                if (is_assignment_operator (tok.kind)) {
-                
-                    op = tok.kind;
-                    
-                    is_simple_assign = (tok.kind == TOK_ASSIGN);
-                    get_token ();
-                    
-                    if (state->ofp) {
-                    
-                        if (is_simple_assign) {
-                        
-                            emit_push_reg_now ("edx");
-                            emit_load_assignment_rhs_expression_to_reg ("eax");
-                            emit_pop_reg_now ("edx");
-                        
-                        } else {
-                        
-                            emit_load_member_from_addr_reg_now ("eax", "edx", 0, elem_size);
-                            emit_push_reg_now ("edx");
-                            emit_push_reg_now ("eax");
-                            emit_load_assignment_rhs_expression_to_reg ("edx");
-                            emit_pop_reg_now ("eax");
-                            emit_assignment_binary_op (op, 0);
-                            emit_pop_reg_now ("edx");
-                        
-                        }
-                        
-                        emit_store_reg_to_deref_reg_now ("edx", "eax", elem_size);
-                    
-                    } else {
-                        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-                    }
-                    
-                    expect_semi_or_recover ();
-                    
-                    free (name);
-                    return 1;
-                
-                }
-            
-            }
-            
-            if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT) {
-            
-                enum token_kind member_op = tok.kind;
-                char *member;
-                
-                const char *member_start;
-                const char *member_caret;
-                
-                unsigned long member_line;
-                
-                int member_offset = 0;
-                int member_size = DATA_PTR & 0x1f;
-                
-                get_token ();
-                
-                member_start = tok.start;
-                member_caret = tok.caret;
-                member_line = get_line_number ();
-                
-                if (tok.kind != TOK_IDENT) {
-                
-                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
-                    
-                    skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-                    expect_semi_or_recover ();
-                    
-                    free (name);
-                    return 1;
-                
-                }
-                
-                member = xstrdup (tok.ident);
-                get_token ();
-                
-                if (!find_member_info (member, &member_offset, &member_size)) {
-                
-                    report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
-                    free (member);
-                    
-                    skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-                    expect_semi_or_recover ();
-                    
-                    free (name);
-                    return 1;
-                
-                }
-                
-                free (member);
-                
-                if (member_op == TOK_DOT && state->ofp) {
-                    emit_load_deref_reg_now ("eax", DATA_PTR);
-                }
-                
-                if (is_assignment_operator (tok.kind)) {
-                
-                    op = tok.kind;
-                    
-                    is_simple_assign = (tok.kind == TOK_ASSIGN);
-                    get_token ();
-                    
-                    if (state->ofp) {
-                    
-                        if (state->syntax & ASM_SYNTAX_INTEL) {
-                            fprintf (state->ofp, "    mov edx, eax\n");
-                        } else {
-                            fprintf (state->ofp, "    movl %%eax, %%edx\n");
-                        }
-                        
-                        if (is_simple_assign) {
-                        
-                            emit_push_reg_now ("edx");
-                            emit_load_assignment_rhs_expression_to_reg ("eax");
-                            emit_pop_reg_now ("edx");
-                        
-                        } else {
-                        
-                            emit_load_member_from_addr_reg_now ("eax", "edx", member_offset, member_size);
-                            emit_push_reg_now ("edx");
-                            emit_push_reg_now ("eax");
-                            emit_load_assignment_rhs_expression_to_reg ("edx");
-                            emit_pop_reg_now ("eax");
-                            emit_assignment_binary_op (op, 0);
-                            emit_pop_reg_now ("edx");
-                        
-                        }
-                        
-                        emit_store_member_to_addr_reg_now ("edx", member_offset, "eax", member_size);
-                    
-                    } else {
-                        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-                    }
-                    
-                    expect_semi_or_recover ();
-                    free (name);
-                    
-                    return 1;
-                
-                }
-                
-                if (tok.kind == TOK_LPAREN) {
-                
-                    enum token_kind member_calling_convention = last_found_member_calling_convention;
-                    
-                    FILE **arg_tmp_ofps = 0;
-                    FILE **new_arg_tmp_ofps;
-                    FILE *arg_tmp_ofp;
-                    FILE *arg_saved_ofp;
-                    
-                    int argc = 0;
-                    int i;
-                    int ch;
-                    int total_arg_bytes = 0;
-                    
-                    if (state->ofp) {
-                    
-                        emit_load_member_from_addr_reg_now ("ecx", "eax", member_offset, DATA_PTR & 0x1f);
-                        emit_push_reg_now ("ecx");
-                    
-                    }
-                    
-                    get_token ();
-                    
-                    if (tok.kind != TOK_RPAREN) {
-                    
-                        for (;;) {
-                        
-                            arg_tmp_ofp = 0;
-                            arg_saved_ofp = 0;
-                            
-                            if (state->ofp) {
-                            
-                                arg_tmp_ofp = scc_tmpfile ();
-                                
-                                if (arg_tmp_ofp) {
-                                    arg_saved_ofp = state->ofp;
-                                    state->ofp = arg_tmp_ofp;
-                                }
-                            
-                            }
-                            
-                            emit_load_assignment_rhs_expression_to_reg ("eax");
-                            
-                            if (state->ofp) {
-                                emit_push_reg_now ("eax");
-                            }
-                            
-                            if (arg_saved_ofp) {
-                            
-                                fflush (arg_tmp_ofp);
-                                state->ofp = arg_saved_ofp;
-                                
-                                new_arg_tmp_ofps = (FILE **) xrealloc (arg_tmp_ofps, sizeof (*arg_tmp_ofps) * (argc + 1));
-                                
-                                if (new_arg_tmp_ofps) {
-                                
-                                    arg_tmp_ofps = new_arg_tmp_ofps;
-                                    arg_tmp_ofps[argc] = arg_tmp_ofp;
-                                    arg_tmp_ofp = 0;
-                                
-                                }
-                            
-                            }
-                            
-                            if (arg_tmp_ofp) {
-                                scc_close (arg_tmp_ofp);
-                            }
-                            
-                            argc++;
-                            total_arg_bytes += DATA_PTR & 0x1f;
-                            
-                            if (!_accept (TOK_COMMA)) {
-                                break;
-                            }
-                        
-                        }
-                    
-                    }
-                    
-                    expect (TOK_RPAREN, ")");
-                    
-                    if (state->ofp) {
-                    
-                        for (i = argc - 1; i >= 0; i--) {
-                        
-                            if (arg_tmp_ofps && arg_tmp_ofps[i]) {
-                            
-                                fseek (arg_tmp_ofps[i], 0, SEEK_SET);
-                                
-                                while ((ch = fgetc (arg_tmp_ofps[i])) != EOF) {
-                                    fputc (ch, state->ofp);
-                                }
-                                
-                                scc_close (arg_tmp_ofps[i]);
-                                arg_tmp_ofps[i] = 0;
-                            
-                            }
-                        
-                        }
-                        
-                        if (arg_tmp_ofps) {
-                        
-                            free (arg_tmp_ofps);
-                            arg_tmp_ofps = 0;
-                        
-                        }
-                        
-                        if (state->syntax & ASM_SYNTAX_INTEL) {
-                        
-                            if (state->syntax & ASM_SYNTAX_NASM) {
-                                fprintf (state->ofp, "    mov ecx, dword [esp + %d]\n", total_arg_bytes);
-                            } else {
-                                fprintf (state->ofp, "    mov ecx, dword ptr [esp + %d]\n", total_arg_bytes);
-                            }
-                            
-                            fprintf (state->ofp, "    call ecx\n");
-                            
-                            if (member_calling_convention == TOK_STDCALL) {
-                                fprintf (state->ofp, "    add esp, %d\n", (DATA_PTR & 0x1f));
-                            } else {
-                                fprintf (state->ofp, "    add esp, %d\n", total_arg_bytes + (DATA_PTR & 0x1f));
-                            }
-                        
-                        } else {
-                        
-                            fprintf (state->ofp, "    movl %d(%%esp), %%ecx\n", total_arg_bytes);
-                            fprintf (state->ofp, "    call *%%ecx\n");
-                            
-                            if (member_calling_convention == TOK_STDCALL) {
-                                fprintf (state->ofp, "    addl $%d, %%esp\n", (DATA_PTR & 0x1f));
-                            } else {
-                                fprintf (state->ofp, "    addl $%d, %%esp\n", total_arg_bytes + (DATA_PTR & 0x1f));
-                            }
-                        
-                        }
-                    
-                    }
-                    
-                    expect_semi_or_recover ();
-                    free (name);
-                    
-                    return 1;
-                
-                }
-                
-                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-                
-                expect_semi_or_recover ();
-                free (name);
-                
-                return 1;
-            
-            }
-            
-            expect_semi_or_recover ();
-            free (name);
-            
-            return 1;
-        
-        }
-        
-        if (!find_local_symbol (name) && find_global_symbol (name) < 0) {
-        
-            int64_s ignored;
-            
-            if (!resolve_enum_constant (name, &ignored)) {
-                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-            }
-        
-        }
-        
-        free (name);
-        
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        expect (TOK_SEMI, ";");
-        
-        return 1;
-    
-    }
-    
-    op = tok.kind;
-    
-    is_simple_assign = (tok.kind == TOK_ASSIGN);
-    get_token ();
-    
-    lhs = find_local_symbol (name);
-    global_index = find_global_symbol (name);
-    
-    if (!lhs && global_index < 0) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-        
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        expect (TOK_SEMI, ";");
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    if (state->ofp) {
-    
-        lhs_size = lhs ? lhs->size : get_global_symbol_size (name);
-        lhs_is_floating = lhs ? lhs->is_floating : get_global_symbol_floating (name);
-        
-        if (is_simple_assign && lhs_size > (DATA_LLONG & 0x1f) && tok.kind == TOK_IDENT) {
-            
-            char *rhs_name = xstrdup (tok.ident);
-            
-            struct local_symbol *rhs_sym;
-            int rhs_global_index;
-            
-            get_token ();
-            
-            rhs_sym = find_local_symbol (rhs_name);
-            rhs_global_index = find_global_symbol (rhs_name);
-            
-            if (rhs_sym || rhs_global_index >= 0) {
-            
-                if (tok.kind == TOK_LPAREN && rhs_global_index >= 0 && get_global_symbol_kind (rhs_name) == GLOBAL_SYMBOL_FUNCTION) {
-                
-                    pending_struct_return_lhs = lhs;
-                    pending_struct_return_global_name = lhs ? 0 : name;
-                    
-                    emit_call_identifier_to_reg_now (rhs_name, "eax", name_start, name_caret, name_line);
-                
-                } else if (tok.kind == TOK_ARROW || tok.kind == TOK_DOT || tok.kind == TOK_LBRACK) {
-                
-                    if (emit_parse_postfix_copy_source_address_now ("eax", rhs_sym, rhs_name, name_start, name_caret, name_line)) {
-                    
-                        emit_load_symbol_address_for_copy_now ("edx", lhs, name);
-                        emit_copy_fixed_size_now (lhs_size);
-                    
-                    }
-                
-                } else {
-                    emit_memcpy_symbol_to_symbol_now (lhs, name, rhs_sym, rhs_name, lhs_size);
-                }
-            
-            } else {
-                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", rhs_name);
-            }
-            
-            free (rhs_name);
-            expect_semi_or_recover ();
-            
-            free (name);
-            return 1;
-        
-        }
-        
-        if (lhs_is_floating) {
-        
-            if (!floating_assignment_operator_supported_now (op)) {
-            
-                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid operands to floating assignment operator");
-                skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-            
-            } else {
-            
-                if (is_simple_assign) {
-                    emit_load_floating_rhs_expression_now (lhs_size);
-                } else {
-                
-                    emit_load_floating_symbol_now (lhs, name, lhs_size);
-                    emit_load_floating_rhs_expression_now (lhs_size);
-                    emit_floating_binary_now (op);
-                
-                }
-                
-                emit_store_floating_symbol_now (lhs, name, lhs_size);
-            
-            }
-        
-        } else if (lhs_size == (DATA_LLONG & 0x1f)) {
-        
-            if (is_simple_assign) {
-                emit_load_assignment_rhs_expression_to_pair ("eax", "edx", lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
-            } else {
-            
-                if (lhs) {
-                
-                    if (lhs->is_static && lhs->static_label) {
-                        emit_load_global64_to_pair ("eax", "edx", lhs->static_label);
-                    } else {
-                        emit_load_local64_to_pair (lhs->offset, "eax", "edx");
-                    }
-                
-                } else {
-                    emit_load_global64_to_pair ("eax", "edx", name);
-                }
-                
-                /*
-                 * Compound assignments need the complete RHS expression.
-                 * Using emit_load_assignment_rhs_to_pair() only consumes one
-                 * primary operand, so e.g.
-                 *
-                 *     final_value += symbol->frag->address + left_value;
-                 *
-                 * leaves the second + operand for the statement parser and
-                 * reports "expected ;".  Evaluate the full RHS in eax:edx,
-                 * copy it to the RHS pair ebx:ecx, then restore the original
-                 * LHS value before applying the compound operator.
-                 */
-                emit_push_reg_now ("eax");
-                emit_push_reg_now ("edx");
-                
-                emit_load_assignment_rhs_expression_to_pair ("eax", "edx", lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
-                
-                emit_mov_reg_to_reg_now ("ebx", "eax");
-                emit_mov_reg_to_reg_now ("ecx", "edx");
-                
-                emit_pop_reg_now ("edx");
-                emit_pop_reg_now ("eax");
-                
-                emit_preserve_assignment64_regs (op);
-                emit_assignment_binary_op64 (op, lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
-                emit_restore_assignment64_regs (op);
-            
-            }
-            
-            if (lhs) {
-            
-                if (lhs->is_static && lhs->static_label) {
-                    emit_store_pair_to_global64 (lhs->static_label, "eax", "edx");
-                } else {
-                    emit_store_pair_to_local64 (lhs->offset, "eax", "edx");
-                }
-            
-            } else {
-                emit_store_pair_to_global64 (name, "eax", "edx");
-            }
-        
-        } else {
-        
-            if (is_simple_assign) {
-                emit_load_assignment_rhs_expression_to_reg ("eax");
-            } else {
-            
-                if (lhs) {
-                
-                    if (lhs->is_static && lhs->static_label) {
-                        emit_load_global_to_reg_ex ("eax", lhs->static_label, lhs->size, lhs->is_unsigned);
-                    } else {
-                        emit_load_local_to_reg_ex ("eax", lhs->offset, lhs->size, lhs->is_unsigned);
-                    }
-                
-                } else {
-                    emit_load_global_to_reg ("eax", name, lhs_size);
-                }
-                
-                /*
-                 * Compound assignments still need the full RHS expression,
-                 * not just a single operand.  Otherwise cases such as:
-                 *
-                 *     processed += (int)(t - stream->upto) - 1;
-                 *
-                 * leave the trailing "- 1" unconsumed and the statement
-                 * parser reports "expected ;".  Preserve the current LHS
-                 * value in eax while the RHS expression is parsed, because
-                 * RHS binary-expression code may use eax internally even
-                 * when the requested result register is edx.
-                 */
-                emit_push_reg_now ("eax");
-                emit_load_assignment_rhs_expression_to_reg ("edx");
-                
-                emit_scale_reg_for_pointer_compound_assignment_now ("edx", lhs, name, op);
-                emit_pop_reg_now ("eax");
-                
-                emit_assignment_binary_op (op, lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
-            
-            }
-            
-            if (lhs) {
-            
-                if (lhs->is_static && lhs->static_label) {
-                    emit_store_reg_to_global (lhs->static_label, lhs->size, "eax");
-                } else {
-                    emit_store_reg_to_local (lhs->offset, lhs->size, "eax");
-                }
-            
-            } else {
-                emit_store_reg_to_global (name, lhs_size, "eax");
-            }
-        
-        }
-    
-    } else {
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-    }
-    
-    expect_semi_or_recover ();
-    
-    free (name);
-    return 1;
-
-}
-
-static void emit_statement_label_raw (int label) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
-        fprintf (state->ofp, "L%d:\n", label);
-    } else {
-        fprintf (state->ofp, ".L%d:\n", label);
-    }
-
-}
-
-static void flush_pending_statement_labels (void) {
-
-    int i;
-    int count = pending_statement_label_count;
-    
-    /**
-     * A queued case/default/C label marks the next statement.  If the
-     * previous statement was a return, its jump to the common epilogue may
-     * still be pending.  Emit that jump before placing the next label,
-     * otherwise the label lands between the return value setup and the
-     * deferred jump.
-     *
-     * Also flush the deferred return before any other emitted control-flow
-     * boundary even when there are no queued labels.  A switch body is emitted
-     * into a temporary stream and then replayed before the switch break label;
-     * if the last case returns, there may be no following case/default label to
-     * force this flush.
-     */
-    if (pending_return_jump) {
-        emit_pending_return_jump ();
-    }
-    
-    if (count <= 0) {
-        return;
-    }
-    
-    pending_statement_label_count = 0;
-    
-    for (i = 0; i < count; i++) {
-        emit_statement_label_raw (pending_statement_labels[i]);
-    }
-
-}
-
-static void emit_statement_label (int label) {
-
-    flush_pending_statement_labels ();
-    emit_statement_label_raw (label);
-
-}
-
-static void emit_statement_jump (int label) {
-
-    flush_pending_statement_labels ();
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
-        fprintf (state->ofp, "    jmp L%d\n", label);
-    } else {
-        fprintf (state->ofp, "    jmp .L%d\n", label);
-    }
-
-}
-
-static int token_is_integer_constant_now (enum token_kind k) {
-    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 == TOK_CUINT || k == TOK_CULONG || k == TOK_CULLONG;
-}
-
-#define     MAX_INLINE_ASM_INPUTS        16
-
-struct inline_asm_input_operand {
-
-    char constraint[16];
-    char subst[64];
-    int restore_reg;
-    const char *restore_name;
-
-};
-
-static void inline_asm_copy_trimmed_text (char *dst, size_t dst_size, const char *start, const char *end) {
-
-    size_t len;
-    
-    if (!dst || dst_size == 0) {
-        return;
-    }
-    
-    dst[0] = 0;
-    
-    if (!start || !end || end < start) {
-        return;
-    }
-    
-    while (start < end && (*start == ' ' || *start == '\t' || *start == '\r' || *start == '\n')) {
-        start++;
-    }
-    
-    while (end > start && (end[-1] == ' ' || end[-1] == '\t' || end[-1] == '\r' || end[-1] == '\n')) {
-        end--;
-    }
-    
-    len = (size_t) (end - start);
-    
-    if (len >= dst_size) {
-        len = dst_size - 1;
-    }
-    
-    memcpy (dst, start, len);
-    dst[len] = 0;
-
-}
-
-static void inline_asm_unquote_string_token (char *dst, size_t dst_size) {
-
-    const char *s;
-    char quote;
-    size_t n = 0;
-    
-    if (!dst || dst_size == 0) {
-        return;
-    }
-    
-    dst[0] = 0;
-    
-    if (!is_string_token ()) {
-        return;
-    }
-    
-    s = tok.ident;
-    
-    if (tok.kind == TOK_LSTR && *s == 'L') {
-        s++;
-    }
-    
-    quote = *s;
-    
-    if (quote != '"') {
-        return;
-    }
-    
-    s++;
-    
-    while (*s && *s != quote && n + 1 < dst_size) {
-    
-        if (*s == '\\' && s[1]) {
-        
-            s++;
-            
-            switch (*s) {
-            
-                case 'n':
-                
-                    dst[n++] = '\n'; s++;
-                    break;
-                
-                case 'r':
-                
-                    dst[n++] = '\r'; s++;
-                    break;
-                
-                case 't':
-                
-                    dst[n++] = '\t'; s++;
-                    break;
-                
-                case '\\':
-                
-                    dst[n++] = '\\'; s++;
-                    break;
-                
-                case '"':
-                
-                    dst[n++] = '"'; s++;
-                    break;
-                
-                default:
-                
-                    dst[n++] = *s++;
-                    break;
-            
-            }
-        
-        } else {
-            dst[n++] = *s++;
-        }
-    
-    }
-    
-    dst[n] = 0;
-
-}
-
-static const char *inline_asm_constraint_reg32 (const char *constraint) {
-
-    if (!constraint) {
-        return 0;
-    }
-    
-    if (strchr (constraint, 'a')) {
-        return "eax";
-    }
-    
-    if (strchr (constraint, 'b')) {
-        return "ebx";
-    }
-    
-    if (strchr (constraint, 'c')) {
-        return "ecx";
-    }
-    
-    if (strchr (constraint, 'd')) {
-        return "edx";
-    }
-    
-    if (strchr (constraint, 'S')) {
-        return "esi";
-    }
-    
-    if (strchr (constraint, 'D')) {
-        return "edi";
-    }
-    
-    return 0;
-
-}
-
-static const char *inline_asm_reg_for_template (const char *reg32) {
-
-    if (!reg32) {
-        return "";
-    }
-    
-    if (strcmp (reg32, "eax") == 0) {
-        return "al";
-    }
-    
-    if (strcmp (reg32, "ebx") == 0) {
-        return "bl";
-    }
-    
-    if (strcmp (reg32, "ecx") == 0) {
-        return "cl";
-    }
-    
-    if (strcmp (reg32, "edx") == 0) {
-        return "dx";
-    }
-    
-    if (strcmp (reg32, "esi") == 0) {
-        return "esi";
-    }
-    
-    if (strcmp (reg32, "edi") == 0) {
-        return "edi";
-    }
-    
-    return reg32;
-
-}
-
-static int inline_asm_reg_needs_restore (const char *reg32) {
-    return reg32 && (strcmp (reg32, "ebx") == 0 || strcmp (reg32, "esi") == 0 || strcmp (reg32, "edi") == 0);
-}
-
-static int inline_asm_template_is_out (const char *templ) {
-
-    if (!templ) {
-        return 0;
-    }
-    
-    while (*templ == ' ' || *templ == '\t') {
-        templ++;
-    }
-    
-    return  strncmp (templ, "outb ", 5) == 0 || strncmp (templ, "outw ", 5) == 0 ||
-                strncmp (templ, "outl ", 5) == 0 || strncmp (templ, "out ", 4) == 0;
-
-}
-
-static int inline_asm_is_reg32_name (const char *s, size_t len) {
-
-    return  (len == 3 && strncmp (s, "eax", 3) == 0) ||
-                (len == 3 && strncmp (s, "ebx", 3) == 0) ||
-                    (len == 3 && strncmp (s, "ecx", 3) == 0) ||
-                        (len == 3 && strncmp (s, "edx", 3) == 0) ||
-                            (len == 3 && strncmp (s, "esi", 3) == 0) ||
-                                (len == 3 && strncmp (s, "edi", 3) == 0);
-
-}
-
-static int inline_asm_rewrite_narrow_movzx (char *line, size_t line_size) {
-
-    char rewritten[512];
-    
-    const char *p;
-    const char *reg_start;
-    const char *reg_end;
-    const char *src;
-    
-    size_t reg_len;
-    size_t indent_len;
-    
-    if (!line || line_size == 0 || !(state->syntax & ASM_SYNTAX_INTEL)) {
-        return 0;
-    }
-    
-    p = line;
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    indent_len = (size_t) (p - line);
-    
-    if (strncmp (p, "mov", 3) != 0 || (p[3] != ' ' && p[3] != '\t')) {
-        return 0;
-    }
-    
-    p += 3;
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    reg_start = p;
-    
-    while ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9')) {
-        p++;
-    }
-    
-    reg_end = p;
-    reg_len = (size_t) (reg_end - reg_start);
-    
-    if (!inline_asm_is_reg32_name (reg_start, reg_len)) {
-        return 0;
-    }
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (*p != ',') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    src = p;
-    
-    /**
-     * Only change true narrow memory loads.  This deliberately does not
-     * touch register/register moves, immediates, or lines that have already
-     * been rewritten.
-     */
-    if (strncmp (src, "byte ptr ", 9) != 0 && strncmp (src, "word ptr ", 9) != 0) {
-        return 0;
-    }
-    
-    if (indent_len + 6 + reg_len + 2 + strlen (src) + 1 >= sizeof (rewritten)) {
-        return 0;
-    }
-    
-    memcpy (rewritten, line, indent_len);
-    rewritten[indent_len] = 0;
-    
-    strcat (rewritten, "movzx ");
-    strncat (rewritten, reg_start, reg_len);
-    strcat (rewritten, ", ");
-    strcat (rewritten, src);
-    
-    inline_copy_string (line, rewritten, line_size);
-    return 1;
-
-}
-
-static const char *inline_asm_intel_ptr_name (int size) {
-
-    if (size <= 1) {
-        return "byte";
-    }
-    
-    if (size == 2) {
-        return "word";
-    }
-    
-    if (size == 8) {
-        return "qword";
-    }
-    
-    return "dword";
-
-}
-
-static int inline_asm_format_identifier_operand (char *dst, size_t dst_size, const char *name) {
-
-    struct local_symbol *sym;
-    char memref[64];
-    const char *asm_name;
-    
-    if (!dst || dst_size == 0 || !name || !*name) {
-        return 0;
-    }
-    
-    dst[0] = 0;
-    sym = find_local_symbol (name);
-    
-    if (sym) {
-    
-        if (sym->is_static && sym->static_label) {
-        
-            asm_name = asm_global_symbol_name (sym->static_label);
-            
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                sprintf (dst, (state->syntax & ASM_SYNTAX_NASM ? "%s %s" : "%s ptr %s"), inline_asm_intel_ptr_name (sym->size), asm_name);
-            } else {
-                sprintf (dst, "%s", asm_name);
-            }
-            
-            return 1;
-        
-        }
-        
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-        
-            format_intel_ebp_offset (memref, sizeof (memref), sym->offset);
-            sprintf (dst, (state->syntax & ASM_SYNTAX_NASM ? "%s %s" : "%s ptr %s"), inline_asm_intel_ptr_name (sym->size), memref);
-        
-        } else {
-            sprintf (dst, "%ld(%%ebp)", sym->offset);
-        }
-        
-        return 1;
-    
-    }
-    
-    if (find_global_symbol (name) >= 0) {
-    
-        asm_name = asm_global_symbol_name (name);
-        
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-            sprintf (dst, (state->syntax & ASM_SYNTAX_NASM ? "%s %s" : "%s ptr %s"), inline_asm_intel_ptr_name (get_global_symbol_size (name)), asm_name);
-        } else {
-            sprintf (dst, "%s", asm_name);
-        }
-        
-        return 1;
-    
-    }
-    
-    return 0;
-
-}
-
-static void inline_asm_emit_input_load (const char *constraint, int input_index, struct inline_asm_input_operand *inputs, const char *templ) {
-
-    char expr_text[64];
-    
-    const char *expr_start;
-    const char *expr_end;
-    const char *reg32;
-    const char *subst;
-    
-    expr_text[0] = 0;
-    expr_start = tok.caret;
-    
-    inputs[input_index].restore_reg = 0;
-    inputs[input_index].restore_name = 0;
-    
-    if (strchr (constraint, 'N')) {
-    
-        if (token_is_integer_constant_now (tok.kind)) {
-        
-            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
-            expr_end = tok.caret;
-            
-            inline_asm_copy_trimmed_text (expr_text, sizeof (expr_text), expr_start, expr_end);
-            inline_copy_string (inputs[input_index].subst, expr_text, sizeof (inputs[input_index].subst));
-            
-            return;
-        
-        }
-        
-        if (inline_asm_template_is_out (templ)) {
-        
-            /**
-             * GCC's "N" constraint is really an 8-bit immediate port.
-             * For the OUT templates, allow a non-constant here as a
-             * convenience and lower it through DX, because x86 OUT cannot
-             * encode a variable port as an immediate.
-             */
-            emit_load_assignment_rhs_expression_to_reg ("edx");
-            inline_copy_string (inputs[input_index].subst, "dx", sizeof (inputs[input_index].subst));
-            
-            return;
-        
-        }
-        
-        if (tok.kind == TOK_IDENT && tok.ident && inline_asm_format_identifier_operand (expr_text, sizeof (expr_text), tok.ident)) {
-        
-            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
-            inline_copy_string (inputs[input_index].subst, expr_text, sizeof (inputs[input_index].subst));
-            
-            return;
-        
-        }
-        
-        skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
-        expr_end = tok.caret;
-        
-        inline_asm_copy_trimmed_text (expr_text, sizeof (expr_text), expr_start, expr_end);
-        inline_copy_string (inputs[input_index].subst, expr_text, sizeof (inputs[input_index].subst));
-        
-        return;
-    
-    }
-    
-    reg32 = inline_asm_constraint_reg32 (constraint);
-    
-    if (reg32) {
-    
-        subst = inline_asm_reg_for_template (reg32);
-        
-        if (inline_asm_reg_needs_restore (reg32) && state->ofp) {
-        
-            fprintf (state->ofp, "    push %s\n", reg32);
-            
-            inputs[input_index].restore_reg = 1;
-            inputs[input_index].restore_name = reg32;
-        
-        }
-        
-        if (token_is_integer_constant_now (tok.kind)) {
-        
-            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
-            expr_end = tok.caret;
-            
-            inline_asm_copy_trimmed_text (expr_text, sizeof (expr_text), expr_start, expr_end);
-            
-            if (state->ofp) {
-                fprintf (state->ofp, "    mov %s, %s\n", subst, expr_text[0] ? expr_text : "0");
-            }
-        
-        } else {
-            emit_load_assignment_rhs_expression_to_reg (reg32);
-        }
-        
-        inline_copy_string (inputs[input_index].subst, subst, sizeof (inputs[input_index].subst));
-        return;
-    
-    }
-    
-    if (tok.kind == TOK_IDENT && tok.ident && inline_asm_format_identifier_operand (expr_text, sizeof (expr_text), tok.ident)) {
-    
-        skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
-        inline_copy_string (inputs[input_index].subst, expr_text, sizeof (inputs[input_index].subst));
-        
-        return;
-    
-    }
-    
-    skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
-    expr_end = tok.caret;
-    
-    inline_asm_copy_trimmed_text (expr_text, sizeof (expr_text), expr_start, expr_end);
-    inline_copy_string (inputs[input_index].subst, expr_text, sizeof (inputs[input_index].subst));
-
-}
-
-static void inline_asm_emit_template (const char *templ, struct inline_asm_input_operand *inputs, int input_count) {
-
-    char line[512];
-    size_t n = 0;
-    
-    const char *p;
-    
-    if (!state->ofp || !templ) {
-        return;
-    }
-    
-    for (p = templ; *p && n + 1 < sizeof (line); p++) {
-    
-        if (*p == '%' && p[1] == '%') {
-        
-            if (state->syntax & ASM_SYNTAX_INTEL) {
-                p++;
-            } else {
-            
-                line[n++] = '%';
-                p++;
-            
-            }
-        
-        } else if (*p == '%' && p[1] >= '0' && p[1] <= '9') {
-        
-            int index = p[1] - '0';
-            const char *subst = "";
-            
-            if (index >= 0 && index < input_count) {
-                subst = inputs[index].subst;
-            }
-            
-            while (*subst && n + 1 < sizeof (line)) {
-                line[n++] = *subst++;
-            }
-            
-            p++;
-        
-        } else {
-            line[n++] = *p;
-        }
-    
-    }
-    
-    line[n] = 0;
-    
-    if ((strncmp (line, "outb ", 5) == 0 || strncmp (line, "outw ", 5) == 0 || strncmp (line, "outl ", 5) == 0 || strncmp (line, "out ", 4) == 0)) {
-    
-        char *args;
-        char *comma;
-        char *lhs;
-        char *rhs;
-        
-        args = strchr (line, ' ');
-        
-        if (args) {
-        
-            args++;
-            comma = strchr (args, ',');
-            
-            if (comma) {
-            
-                *comma = 0;
-                
-                lhs = args;
-                rhs = comma + 1;
-                
-                while (*lhs == ' ' || *lhs == '\t') {
-                    lhs++;
-                }
-                
-                while (*rhs == ' ' || *rhs == '\t') {
-                    rhs++;
-                }
-                
-                fprintf (state->ofp, "    out %s, %s\n", rhs, lhs);
-                
-                while (input_count-- > 0) {
-                
-                    if (inputs[input_count].restore_reg && inputs[input_count].restore_name) {
-                        fprintf (state->ofp, "    pop %s\n", inputs[input_count].restore_name);
-                    }
-                
-                }
-                
-                return;
-            
-            }
-        
-        }
-    
-    }
-    
-    if (line[0]) {
-    
-        inline_asm_rewrite_narrow_movzx (line, sizeof (line));
-        fprintf (state->ofp, "    %s\n", line);
-    
-    }
-    
-    while (input_count-- > 0) {
-    
-        if (inputs[input_count].restore_reg && inputs[input_count].restore_name) {
-            fprintf (state->ofp, "    pop %s\n", inputs[input_count].restore_name);
-        }
-    
-    }
-
-}
-
-static int parse_inline_asm_statement (void) {
-
-    char templ[256];
-    
-    struct inline_asm_input_operand inputs[MAX_INLINE_ASM_INPUTS];
-    int input_count = 0;
-    
-    if (tok.kind != TOK_ASM) {
-        return 0;
-    }
-    
-    memset (inputs, 0, sizeof (inputs));
-    
-    get_token ();
-    expect (TOK_LPAREN, "(");
-    
-    if (!is_string_token ()) {
-    
-        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected asm template string");
-        
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        expect (TOK_SEMI, ";");
-        
-        return 1;
-    
-    }
-    
-    inline_asm_unquote_string_token (templ, sizeof (templ));
-    get_token ();
-    
-    if (_accept (TOK_COLON)) {
-    
-        if (tok.kind != TOK_COLON) {
-            skip_balanced_until (TOK_COLON, TOK_RPAREN, TOK_EOF);
-        }
-        
-        if (_accept (TOK_COLON)) {
-        
-            while (tok.kind != TOK_RPAREN && tok.kind != TOK_EOF) {
-            
-                char constraint[16];
-                
-                if (!is_string_token ()) {
-                
-                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected asm input constraint string");
-                    
-                    skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
-                    break;
-                
-                }
-                
-                inline_asm_unquote_string_token (constraint, sizeof (constraint));
-                get_token ();
-                
-                expect (TOK_LPAREN, "(");
-                
-                if (input_count < MAX_INLINE_ASM_INPUTS) {
-                
-                    inline_copy_string (inputs[input_count].constraint, constraint, sizeof (inputs[input_count].constraint));
-                    inline_asm_emit_input_load (constraint, input_count, inputs, templ);
-                    
-                    input_count++;
-                
-                } else {
-                    skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
-                }
-                
-                expect (TOK_RPAREN, ")");
-                
-                if (!_accept (TOK_COMMA)) {
-                    break;
-                }
-            
-            }
-        
-        }
-    
-    }
-    
-    expect (TOK_RPAREN, ")");
-    expect (TOK_SEMI, ";");
-    
-    inline_asm_emit_template (templ, inputs, input_count);
-    return 1;
-
-}
-
-static int token_is_const_condition_operand_now (void) {
-    return token_is_sizeof_keyword () || token_is_integer_constant_now (tok.kind);
-}
-
-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 == '_';
-}
-
-static int ident_start_now (int ch) {
-    return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '_';
-}
-
-static int prefix_incdec_target_is_floating_now (void) {
-
-    const char *p;
-    const char *q;
-    
-    char *name;
-    int len;
-    
-    struct local_symbol *src;
-    int ret = 0;
-    
-    if (tok.kind != TOK_INCR && tok.kind != TOK_DECR) {
-        return 0;
-    }
-    
-    p = tok.caret;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (!ident_start_now ((unsigned char) *p)) {
-        return 0;
-    }
-    
-    q = p + 1;
-    
-    while (ident_char_now ((unsigned char) *q)) {
-        q++;
-    }
-    
-    len = (int) (q - p);
-    name = xmalloc ((unsigned long) len + 1);
-    
-    memcpy (name, p, (unsigned long) len);
-    name[len] = 0;
-    
-    src = find_local_symbol (name);
-    
-    if (src) {
-        ret = src->is_floating ? 1 : 0;
-    } else if (find_global_symbol (name) >= 0) {
-        ret = get_global_symbol_floating (name) ? 1 : 0;
-    }
-    
-    free (name);
-    return ret;
-
-}
-
-static int source_parenthesized_floating_condition_now (const char *p) {
-
-    char name[128];
-    int i;
-    
-    if (!p) {
-        return 0;
-    }
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (*p != '(') {
-        return 0;
-    }
-    
-    while (*p == '(' || *p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
-        return 0;
-    }
-    
-    i = 0;
-    
-    while (((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') && i < (int) sizeof (name) - 1) {
-        name[i++] = *p++;
-    }
-    
-    name[i] = 0;
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (*p == '.') {
-        return 0;
-    }
-    
-    if (*p == '(' && find_global_symbol (name) >= 0 && get_global_symbol_floating (name)) {
-        return 1;
-    }
-    
-    /*
-     * Parenthesized floating conditions such as:
-     *
-     *     if (num < 0)
-     *     while (b >= 10.0)
-     *
-     * arrive here while TOK_LPAREN is still current.  If we don't recognise
-     * the name inside the parens as floating, the generic parenthesized
-     * integer path consumes the expression and compares only the low dword.
-     */
-    if (find_local_symbol (name)) {
-    
-        struct local_symbol *src = find_local_symbol (name);
-        return src && src->is_floating ? 1 : 0;
-    
-    }
-    
-    if (find_global_symbol (name) >= 0) {
-        return get_global_symbol_floating (name) ? 1 : 0;
-    }
-    
-    return 0;
-
-}
-
-static int source_va_arg_type_is_double_now (const char *p) {
-
-    int paren;
-    
-    if (!p) {
-        return 0;
-    }
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (*p != '(') {
-        return 0;
-    }
-    
-    paren = 0;
-    
-    while (*p) {
-    
-        if (*p == '(') {
-            paren++;
-        } else if (*p == ')') {
-        
-            paren--;
-            
-            if (paren == 0) {
-                return 0;
-            }
-        
-        } else if (paren == 1 && *p == ',') {
-        
-            p++;
-            
-            while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-                p++;
-            }
-            
-            if (strncmp (p, "double", 6) == 0 &&
-                !(p[6] == '_' || (p[6] >= '0' && p[6] <= '9') ||
-                  (p[6] >= 'A' && p[6] <= 'Z') ||
-                  (p[6] >= 'a' && p[6] <= 'z'))) {
-                return 1;
-            }
-        
-        }
-        
-        p++;
-    
-    }
-    
-    return 0;
-
-}
-
-static int rhs_current_operand_is_floating_now (void) {
-
-    if (token_is_floating_constant_now ()) {
-        return 1;
-    }
-    
-    if (tok.kind == TOK_SCC_BUILTIN_VA_ARG) {
-    
-        const char *p = tok.caret ? tok.caret + tok.len : 0;
-        
-        if (source_va_arg_type_is_double_now (p)) {
-            return 1;
-        }
-    
-    }
-    
-    if (tok.kind == TOK_LPAREN && (source_parenthesized_floating_condition_now (tok.caret) || source_parenthesized_floating_condition_now (tok.start))) {
-        return 1;
-    }
-    
-    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-        return prefix_incdec_target_is_floating_now ();
-    }
-    
-    if (tok.kind == TOK_IDENT && tok.ident) {
-    
-        struct local_symbol *src = find_local_symbol (tok.ident);
-        const char *p = tok.caret ? tok.caret + tok.len : 0;
-        
-        while (p && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')) {
-            p++;
-        }
-        
-        if (strcmp (tok.ident, "__scc_builtin_va_arg") == 0 && source_va_arg_type_is_double_now (p)) {
-            return 1;
-        }
-        
-        if (p && *p == '(' && find_global_symbol (tok.ident) >= 0) {
-            return get_global_function_returns_floating (tok.ident) ? 1 : 0;
-        }
-        
-        if (p && ((p[0] == '-' && p[1] == '>') || p[0] == '.')) {
-        
-            const char *q = p + (p[0] == '-' ? 2 : 1);
-            char member[128];
-            
-            int n = 0;
-            int offset = 0;
-            int size = 0;
-            int elem_size = 0;
-            int pointer_depth = 0;
-            int is_array = 0;
-            int is_floating = 0;
-            int base_size = 0;
-            
-            const char *base_tag_name = 0;
-            
-            while (*q == ' ' || *q == '\t' || *q == '\r' || *q == '\n') {
-                q++;
-            }
-            
-            while (((*q >= 'A' && *q <= 'Z') || (*q >= 'a' && *q <= 'z') || (*q >= '0' && *q <= '9') || *q == '_') && n < (int) sizeof (member) - 1) {
-                member[n++] = *q++;
-            }
-            
-            member[n] = '\0';
-            
-            if (n > 0) {
-            
-                if (p[0] == '-') {
-                
-                    if (src) {
-                    
-                        base_size = src->pointed_size;
-                        base_tag_name = src->pointed_tag_name;
-                    
-                    } else if (find_global_symbol (tok.ident) >= 0) {
-                    
-                        base_size = get_global_symbol_pointed_size (tok.ident);
-                        base_tag_name = get_global_symbol_tag_name (tok.ident);
-                    
-                    }
-                
-                } else {
-                
-                    if (src) {
-                    
-                        base_size = src->size;
-                        base_tag_name = src->tag_name;
-                    
-                    } else if (find_global_symbol (tok.ident) >= 0) {
-                    
-                        base_size = get_global_symbol_size (tok.ident);
-                        base_tag_name = get_global_symbol_tag_name (tok.ident);
-                    
-                    }
-                
-                }
-                
-                if (find_member_info_ex_bounded (member, base_size, base_tag_name, &offset, &size, &elem_size, &pointer_depth, &is_array, &is_floating)) {
-                    return is_floating ? 1 : 0;
-                }
-            
-            }
-        
-        }
-        
-        if (src) {
-            return src->is_floating ? 1 : 0;
-        }
-        
-        if (find_global_symbol (tok.ident) >= 0) {
-            return get_global_function_returns_floating (tok.ident) ? 1 : 0;
-        }
-    
-    }
-    
-    return 0;
-
-}
-
-static int64_s floating_ld_to_bits_now (int size, double value) {
-
-    int64_s r;
-    
-    unsigned long bits32;
-    unsigned char bytes[8];
-    
-    int i;
-    
-    r.low = 0;
-    r.high = 0;
-    
-    if (size == (DATA_FLOAT & 0x1f)) {
-    
-        float f = (float) value;
-        
-        bits32 = 0;
-        
-        memcpy (&bits32, &f, sizeof (f));
-        r.low = bits32;
-        
-        return r;
-    
-    }
-    
-    {
-    
-        double d = (double) value;
-        
-        memset (bytes, 0, sizeof (bytes));
-        memcpy (bytes, &d, sizeof (d));
-        
-        for (i = 0; i < 4; i++) {
-            r.low |= ((unsigned long) bytes[i]) << (i * 8);
-        }
-        
-        for (i = 0; i < 4; i++) {
-            r.high |= ((unsigned long) bytes[i + 4]) << (i * 8);
-        }
-        
-        return r;
-    
-    }
-
-}
-
-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));
-}
-
-static int int64_statement_truth_value (int64_s v) {
-    return v.low != 0 || v.high != 0;
-}
-
-static long statement_int64_signed_high (int64_s v) {
-
-    unsigned long h = v.high & U32_MASK;
-    
-    if (h & 0x80000000UL) {
-        return -((long) ((~h + 1UL) & U32_MASK));
-    }
-    
-    return (long) h;
-
-}
-
-static int statement_cmp_const64_unsigned (int64_s left, int64_s right) {
-
-    unsigned long lh = left.high & U32_MASK;
-    unsigned long rh = right.high & U32_MASK;
-    unsigned long ll = left.low & U32_MASK;
-    unsigned long rl = right.low & U32_MASK;
-    
-    if (lh < rh) return -1;
-    if (lh > rh) return 1;
-    if (ll < rl) return -1;
-    if (ll > rl) return 1;
-    
-    return 0;
-
-}
-
-static int statement_cmp_const64_signed (int64_s left, int64_s right) {
-
-    long lh = statement_int64_signed_high (left);
-    long rh = statement_int64_signed_high (right);
-    
-    unsigned long ll = left.low & U32_MASK;
-    unsigned long rl = right.low & U32_MASK;
-
-    if (lh < rh) return -1;
-    if (lh > rh) return 1;
-    if (ll < rl) return -1;
-    if (ll > rl) return 1;
-    
-    return 0;
-
-}
-
-static int statement_compare_const64_true (int64_s left, enum token_kind op, int64_s right, int is_unsigned) {
-
-    int c = is_unsigned ? statement_cmp_const64_unsigned (left, right) : statement_cmp_const64_signed (left, right);
-    
-    switch (op) {
-    
-        case TOK_LESS:
-        
-            return c < 0;
-        
-        case TOK_LTEQ:
-        
-            return c <= 0;
-        
-        case TOK_GREATER:
-        
-            return c > 0;
-        
-        case TOK_GTEQ:
-        
-            return c >= 0;
-        
-        case TOK_EQEQ:
-        
-            return c == 0;
-        
-        case TOK_NOTEQ:
-        
-            return c != 0;
-        
-        default:
-        
-            return int64_statement_truth_value (left);
-    
-    }
-
-}
-
-static int rhs_current_operand_is_unsigned_now (void) {
-
-    if (token_is_sizeof_keyword ()) {
-        return 1;
-    }
-    
-    if (token_is_integer_unsigned_constant_now (tok.kind)) {
-        return 1;
-    }
-    
-    if (tok.kind == TOK_IDENT && tok.ident) {
-    
-        struct local_symbol *src = find_local_symbol (tok.ident);
-        
-        if (src) {
-            return src->is_unsigned ? 1 : 0;
-        }
-        
-        if (find_global_symbol (tok.ident) >= 0) {
-            return get_global_symbol_unsigned (tok.ident) ? 1 : 0;
-        }
-    
-    }
-    
-    return 0;
-
-}
-
-static int token_is_statement_compare_operator (enum token_kind k) {
-
-    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 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];
-    
-    const char *p;
-    int i;
-    
-    int64_s ignored;
-    
-    if (!pp || !*pp) {
-        return 0;
-    }
-    
-    p = *pp;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    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;
-    }
-    
-    for (;;) {
-    
-        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;
-        }
-        
-        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-            p++;
-        }
-        
-        if (source_condition_tail_end_now (p)) {
-            return 1;
-        }
-        
-        if (!((p[0] == '&' && p[1] == '&') || (p[0] == '|' && p[1] == '|'))) {
-            return 0;
-        }
-    
-    }
-
-}
-
-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;
-    }
-    
-    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;
-    }
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    /*
-     * 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;
-    }
-    
-    name_len = (int) strlen (tok.ident);
-    p = source_find_current_ident_on_line (p);
-    
-    if (!p) {
-        return 0;
-    }
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        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;
-    }
-    
-    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;
-
-}
-
-static int emit_statement_ident_enum_compare_jump_if_false_now (int label) {
-
-    enum token_kind op;
-    int is_unsigned;
-    
-    if (!source_condition_ident_enum_compare_now (tok.caret) && !source_condition_ident_enum_compare_now (tok.start)) {
-        return 0;
-    }
-    
-    is_unsigned = rhs_current_operand_is_unsigned_now ();
-    emit_load_assignment_rhs_to_reg ("eax");
-    
-    if (!token_is_statement_compare_operator (tok.kind)) {
-        return 0;
-    }
-    
-    op = tok.kind;
-    get_token ();
-    
-    /*
-     * 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 ();
-    
-    if (rhs_current_operand_is_unsigned_now ()) {
-        is_unsigned = 1;
-    }
-    
-    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 statement_condition_ident_call_at (const char *p) {
-
-    int len;
-    
-    if (tok.kind != TOK_IDENT || !tok.ident || !p) {
-        return 0;
-    }
-    
-    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) len) == 0 && !ident_char_now ((unsigned char) p[len])) {
-        
-            p += len;
-            
-            while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-                p++;
-            }
-            
-            return *p == '(';
-        
-        }
-        
-        p++;
-    
-    }
-    
-    return 0;
-
-}
-
-static int statement_condition_starts_with_ident_call_now (void) {
-
-    if (statement_condition_ident_call_at (tok.caret)) {
-        return 1;
-    }
-    
-    if (statement_condition_ident_call_at (tok.start)) {
-        return 1;
-    }
-    
-    return 0;
-
-}
-
-static const char *statement_false_jump_mnemonic (enum token_kind op, int is_unsigned) {
-
-    switch (op) {
-    
-        case TOK_LESS:
-        
-            return is_unsigned ? "jae" : "jge";
-        
-        case TOK_LTEQ:
-        
-            return is_unsigned ? "ja"  : "jg";
-        
-        case TOK_GREATER:
-        
-            return is_unsigned ? "jbe" : "jle";
-        
-        case TOK_GTEQ:
-        
-            return is_unsigned ? "jb"  : "jl";
-        
-        case TOK_EQEQ:
-        
-            return "jne";
-        
-        case TOK_NOTEQ:
-        
-            return "je";
-        
-        default:
-        
-            return "jz";
-    
-    }
-
-}
-
-static void emit_statement_const32_to_eax (int64_s v) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-        fprintf (state->ofp, "    mov eax, %lu\n", v.low & U32_MASK);
-    } else {
-        fprintf (state->ofp, "    movl $%lu, %%eax\n", v.low & U32_MASK);
-    }
-
-}
-
-static void emit_statement_cmp_eax_edx_jump_if_false (enum token_kind op, int is_unsigned, int label) {
-
-    const char *jmp;
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    jmp = statement_false_jump_mnemonic (op, is_unsigned);
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        fprintf (state->ofp, "    cmp eax, edx\n");
-        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    %s L%d\n" : "    %s .L%d\n"), jmp, label);
-    
-    } else {
-    
-        fprintf (state->ofp, "    cmpl %%edx, %%eax\n");
-        fprintf (state->ofp, "    %s .L%d\n", jmp, label);
-    
-    }
-
-}
-
-static void emit_statement_cmp64_to_eax (enum token_kind op, int is_unsigned) {
-
-    int true_label;
-    int false_label;
-    int end_label;
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    true_label = anon_label++;
-    false_label = anon_label++;
-    end_label = anon_label++;
-    
-    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
-    
-        switch (op) {
-        
-            case TOK_LESS:
-            
-                fprintf (state->ofp, "    cmp edx, ecx\n");
-                fprintf (state->ofp, is_unsigned ? "    jb L%d\n" : "    jl L%d\n", true_label);
-                fprintf (state->ofp, is_unsigned ? "    ja L%d\n" : "    jg L%d\n", false_label);
-                fprintf (state->ofp, "    cmp eax, ebx\n");
-                fprintf (state->ofp, "    jb L%d\n", true_label);
-                break;
-            
-            case TOK_LTEQ:
-            
-                fprintf (state->ofp, "    cmp edx, ecx\n");
-                fprintf (state->ofp, is_unsigned ? "    jb L%d\n" : "    jl L%d\n", true_label);
-                fprintf (state->ofp, is_unsigned ? "    ja L%d\n" : "    jg L%d\n", false_label);
-                fprintf (state->ofp, "    cmp eax, ebx\n");
-                fprintf (state->ofp, "    jbe L%d\n", true_label);
-                break;
-            
-            case TOK_GREATER:
-            
-                fprintf (state->ofp, "    cmp edx, ecx\n");
-                fprintf (state->ofp, is_unsigned ? "    ja L%d\n" : "    jg L%d\n", true_label);
-                fprintf (state->ofp, is_unsigned ? "    jb L%d\n" : "    jl L%d\n", false_label);
-                fprintf (state->ofp, "    cmp eax, ebx\n");
-                fprintf (state->ofp, "    ja L%d\n", true_label);
-                break;
-            
-            case TOK_GTEQ:
-            
-                fprintf (state->ofp, "    cmp edx, ecx\n");
-                fprintf (state->ofp, is_unsigned ? "    ja L%d\n" : "    jg L%d\n", true_label);
-                fprintf (state->ofp, is_unsigned ? "    jb L%d\n" : "    jl L%d\n", false_label);
-                fprintf (state->ofp, "    cmp eax, ebx\n");
-                fprintf (state->ofp, "    jae L%d\n", true_label);
-                break;
-            
-            case TOK_EQEQ:
-            
-                fprintf (state->ofp, "    cmp edx, ecx\n");
-                fprintf (state->ofp, "    jne L%d\n", false_label);
-                fprintf (state->ofp, "    cmp eax, ebx\n");
-                fprintf (state->ofp, "    je L%d\n", true_label);
-                break;
-            
-            case TOK_NOTEQ:
-            
-                fprintf (state->ofp, "    cmp edx, ecx\n");
-                fprintf (state->ofp, "    jne L%d\n", true_label);
-                fprintf (state->ofp, "    cmp eax, ebx\n");
-                fprintf (state->ofp, "    jne L%d\n", true_label);
-                break;
-            
-            default:
-            
-                fprintf (state->ofp, "    test edx, edx\n");
-                fprintf (state->ofp, "    jnz L%d\n", true_label);
-                fprintf (state->ofp, "    test eax, eax\n");
-                fprintf (state->ofp, "    jnz L%d\n", true_label);
-                break;
-        
-        }
-        
-        fprintf (state->ofp, "L%d:\n", false_label);
-        fprintf (state->ofp, "    xor eax, eax\n");
-        fprintf (state->ofp, "    jmp L%d\n", end_label);
-        fprintf (state->ofp, "L%d:\n", true_label);
-        fprintf (state->ofp, "    mov eax, 1\n");
-        fprintf (state->ofp, "L%d:\n", end_label);
-    
-    } else if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        switch (op) {
-        
-            case TOK_LESS:
-            
-                fprintf (state->ofp, "    cmp edx, ecx\n");
-                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", true_label);
-                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", false_label);
-                fprintf (state->ofp, "    cmp eax, ebx\n");
-                fprintf (state->ofp, "    jb .L%d\n", true_label);
-                break;
-            
-            case TOK_LTEQ:
-            
-                fprintf (state->ofp, "    cmp edx, ecx\n");
-                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", true_label);
-                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", false_label);
-                fprintf (state->ofp, "    cmp eax, ebx\n");
-                fprintf (state->ofp, "    jbe .L%d\n", true_label);
-                break;
-            
-            case TOK_GREATER:
-            
-                fprintf (state->ofp, "    cmp edx, ecx\n");
-                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", true_label);
-                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", false_label);
-                fprintf (state->ofp, "    cmp eax, ebx\n");
-                fprintf (state->ofp, "    ja .L%d\n", true_label);
-                break;
-            
-            case TOK_GTEQ:
-            
-                fprintf (state->ofp, "    cmp edx, ecx\n");
-                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", true_label);
-                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", false_label);
-                fprintf (state->ofp, "    cmp eax, ebx\n");
-                fprintf (state->ofp, "    jae .L%d\n", true_label);
-                break;
-            
-            case TOK_EQEQ:
-            
-                fprintf (state->ofp, "    cmp edx, ecx\n");
-                fprintf (state->ofp, "    jne .L%d\n", false_label);
-                fprintf (state->ofp, "    cmp eax, ebx\n");
-                fprintf (state->ofp, "    je .L%d\n", true_label);
-                break;
-            
-            case TOK_NOTEQ:
-            
-                fprintf (state->ofp, "    cmp edx, ecx\n");
-                fprintf (state->ofp, "    jne .L%d\n", true_label);
-                fprintf (state->ofp, "    cmp eax, ebx\n");
-                fprintf (state->ofp, "    jne .L%d\n", true_label);
-                break;
-            
-            default:
-            
-                fprintf (state->ofp, "    test edx, edx\n");
-                fprintf (state->ofp, "    jnz .L%d\n", true_label);
-                fprintf (state->ofp, "    test eax, eax\n");
-                fprintf (state->ofp, "    jnz .L%d\n", true_label);
-                break;
-        
-        }
-        
-        fprintf (state->ofp, ".L%d:\n", false_label);
-        fprintf (state->ofp, "    xor eax, eax\n");
-        fprintf (state->ofp, "    jmp .L%d\n", end_label);
-        fprintf (state->ofp, ".L%d:\n", true_label);
-        fprintf (state->ofp, "    mov eax, 1\n");
-        fprintf (state->ofp, ".L%d:\n", end_label);
-    
-    } else {
-    
-        switch (op) {
-        
-            case TOK_LESS:
-            
-                fprintf (state->ofp, "    cmpl %%ecx, %%edx\n");
-                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", true_label);
-                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", false_label);
-                fprintf (state->ofp, "    cmpl %%ebx, %%eax\n");
-                fprintf (state->ofp, "    jb .L%d\n", true_label);
-                break;
-            
-            case TOK_LTEQ:
-            
-                fprintf (state->ofp, "    cmpl %%ecx, %%edx\n");
-                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", true_label);
-                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", false_label);
-                fprintf (state->ofp, "    cmpl %%ebx, %%eax\n");
-                fprintf (state->ofp, "    jbe .L%d\n", true_label);
-                break;
-            
-            case TOK_GREATER:
-            
-                fprintf (state->ofp, "    cmpl %%ecx, %%edx\n");
-                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", true_label);
-                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", false_label);
-                fprintf (state->ofp, "    cmpl %%ebx, %%eax\n");
-                fprintf (state->ofp, "    ja .L%d\n", true_label);
-                break;
-            
-            case TOK_GTEQ:
-            
-                fprintf (state->ofp, "    cmpl %%ecx, %%edx\n");
-                fprintf (state->ofp, is_unsigned ? "    ja .L%d\n" : "    jg .L%d\n", true_label);
-                fprintf (state->ofp, is_unsigned ? "    jb .L%d\n" : "    jl .L%d\n", false_label);
-                fprintf (state->ofp, "    cmpl %%ebx, %%eax\n");
-                fprintf (state->ofp, "    jae .L%d\n", true_label);
-                break;
-            
-            case TOK_EQEQ:
-            
-                fprintf (state->ofp, "    cmpl %%ecx, %%edx\n");
-                fprintf (state->ofp, "    jne .L%d\n", false_label);
-                fprintf (state->ofp, "    cmpl %%ebx, %%eax\n");
-                fprintf (state->ofp, "    je .L%d\n", true_label);
-                break;
-            
-            case TOK_NOTEQ:
-            
-                fprintf (state->ofp, "    cmpl %%ecx, %%edx\n");
-                fprintf (state->ofp, "    jne .L%d\n", true_label);
-                fprintf (state->ofp, "    cmpl %%ebx, %%eax\n");
-                fprintf (state->ofp, "    jne .L%d\n", true_label);
-                break;
-            
-            default:
-            
-                fprintf (state->ofp, "    testl %%edx, %%edx\n");
-                fprintf (state->ofp, "    jnz .L%d\n", true_label);
-                fprintf (state->ofp, "    testl %%eax, %%eax\n");
-                fprintf (state->ofp, "    jnz .L%d\n", true_label);
-                break;
-        
-        }
-        
-        fprintf (state->ofp, ".L%d:\n", false_label);
-        fprintf (state->ofp, "    xorl %%eax, %%eax\n");
-        fprintf (state->ofp, "    jmp .L%d\n", end_label);
-        fprintf (state->ofp, ".L%d:\n", true_label);
-        fprintf (state->ofp, "    movl $1, %%eax\n");
-        fprintf (state->ofp, ".L%d:\n", end_label);
-    
-    }
-
-}
-
-static const char *statement_float_false_jump_mnemonic (enum token_kind op) {
-
-    switch (op) {
-    
-        case TOK_LESS:
-        
-            return "jae";
-        
-        case TOK_LTEQ:
-        
-            return "ja";
-        
-        case TOK_GREATER:
-        
-            return "jbe";
-        
-        case TOK_GTEQ:
-        
-            return "jb";
-        
-        case TOK_EQEQ:
-        
-            return "jne";
-        
-        case TOK_NOTEQ:
-        
-            return "je";
-        
-        default:
-        
-            return "jz";
-    
-    }
-
-}
-
-static void emit_statement_floating_compare_jump_if_false (enum token_kind op, int label) {
-
-    const char *jmp;
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    jmp = statement_float_false_jump_mnemonic (op);
-    
-    if (state->syntax & ASM_SYNTAX_NASM) {
-    
-        fprintf (state->ofp, "    fxch st1\n");
-        fprintf (state->ofp, "    fcompp\n");
-        fprintf (state->ofp, "    fnstsw ax\n");
-        fprintf (state->ofp, "    sahf\n");
-        fprintf (state->ofp, "    %s L%d\n", jmp, label);
-    
-    } else if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        fprintf (state->ofp, "    fxch st(1)\n");
-        fprintf (state->ofp, "    fcompp\n");
-        fprintf (state->ofp, "    fnstsw ax\n");
-        fprintf (state->ofp, "    sahf\n");
-        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    %s L%d\n" : "    %s .L%d\n"), jmp, label);
-    
-    } else {
-    
-        fprintf (state->ofp, "    fxch %%st(1)\n");
-        fprintf (state->ofp, "    fcompp\n");
-        fprintf (state->ofp, "    fnstsw %%ax\n");
-        fprintf (state->ofp, "    sahf\n");
-        fprintf (state->ofp, "    %s .L%d\n", jmp, label);
-    
-    }
-
-}
-
-static int statement_compare_floating_const_true (double left, enum token_kind op, double right) {
-
-    switch (op) {
-    
-        case TOK_LESS:
-        
-            return left < right;
-        
-        case TOK_LTEQ:
-        
-            return left <= right;
-        
-        case TOK_GREATER:
-        
-            return left > right;
-        
-        case TOK_GTEQ:
-        
-            return left >= right;
-        
-        case TOK_EQEQ:
-        
-            return left == right;
-        
-        case TOK_NOTEQ:
-        
-            return left != right;
-        
-        default:
-        
-            return left != 0.0;
-    
-    }
-
-}
-
-static void emit_statement_test_eax_jump_if_false (int label) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    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)) ? "    jz L%d\n" : "    jz .L%d\n"), label);
-    
-    } else {
-    
-        fprintf (state->ofp, "    testl %%eax, %%eax\n");
-        fprintf (state->ofp, "    jz .L%d\n", label);
-    
-    }
-
-}
-
-static void emit_statement_test_pair_jump_if_false (const char *lo, const char *hi, int label) {
-
-    int nonzero_label;
-    
-    if (!state->ofp) {
-        return;
-    }
-    
-    nonzero_label = anon_label++;
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        fprintf (state->ofp, "    test %s, %s\n", hi, hi);
-        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), nonzero_label);
-        fprintf (state->ofp, "    test %s, %s\n", lo, lo);
-        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jz L%d\n" : "    jz .L%d\n"), label);
-        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "L%d:\n" : ".L%d:\n"), nonzero_label);
-    
-    } else {
-    
-        fprintf (state->ofp, "    testl %%%s, %%%s\n", hi, hi);
-        fprintf (state->ofp, "    jnz .L%d\n", nonzero_label);
-        fprintf (state->ofp, "    testl %%%s, %%%s\n", lo, lo);
-        fprintf (state->ofp, "    jz .L%d\n", label);
-        fprintf (state->ofp, ".L%d:\n", nonzero_label);
-    
-    }
-
-}
-
-static void emit_statement_test_pair_jump_if_true (const char *lo, const char *hi, int label) {
-
-    if (!state->ofp) {
-        return;
-    }
-    
-    if (state->syntax & ASM_SYNTAX_INTEL) {
-    
-        fprintf (state->ofp, "    test %s, %s\n", hi, hi);
-        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), label);
-        fprintf (state->ofp, "    test %s, %s\n", lo, lo);
-        fprintf (state->ofp, (((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) ? "    jnz L%d\n" : "    jnz .L%d\n"), label);
-    
-    } else {
-    
-        fprintf (state->ofp, "    testl %%%s, %%%s\n", hi, hi);
-        fprintf (state->ofp, "    jnz .L%d\n", label);
-        fprintf (state->ofp, "    testl %%%s, %%%s\n", lo, lo);
-        fprintf (state->ofp, "    jnz .L%d\n", label);
-    
-    }
-
-}
-
-static int statement_condition_constant_known = 0;
-static int statement_condition_constant_value = 0;
-
-static void parse_statement (void);
-static void parse_statement_suppressed (void);
-static void emit_statement_jump_if_false (int label);
-
-static void replay_tmp_file_to_output (FILE *tmp, FILE *out) {
-
-    int ch;
-    
-    if (!tmp || !out) {
-        return;
-    }
-    
-    fflush (tmp);
-    fseek (tmp, 0, SEEK_SET);
-    
-    while ((ch = fgetc (tmp)) != EOF) {
-        fputc (ch, out);
-    }
-
-}
-
-static void parse_for_header_expression_until (enum token_kind end_token) {
-
-    char *name;
-    int global_index;
-    
-    const char *name_start, *name_caret;
-    unsigned long name_line;
-    
-    enum token_kind op;
-    struct local_symbol *lhs;
-    
-    int lhs_size;
-    int lhs_is_floating;
-    
-#define     FINISH_FOR_HEADER_EXPR(free_name)                                   \
-    do {                                                                        \
-        if (tok.kind == TOK_COMMA) {                                            \
-            get_token ();                                                       \
-            if (free_name) {                                                    \
-                free (name);                                                    \
-            }                                                                   \
-            parse_for_header_expression_until (end_token);                      \
-            return;                                                             \
-        }                                                                       \
-        if (tok.kind != end_token) {                                            \
-            skip_balanced_until (end_token, TOK_EOF, TOK_EOF);                  \
-        }                                                                       \
-        expect (end_token, end_token == TOK_SEMI ? ";" : ")");                  \
-        if (free_name) {                                                        \
-            free (name);                                                        \
-        }                                                                       \
-        return;                                                                 \
-    } while (0)
-    
-    if (tok.kind == end_token) {
-        return;
-    }
-    
-    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-    
-        op = tok.kind;
-        get_token ();
-        
-        if (tok.kind == TOK_IDENT) {
-        
-            name = xstrdup (tok.ident);
-            name_start = tok.start;
-            name_caret = tok.caret;
-            name_line = get_line_number ();
-            get_token ();
-            
-            lhs = find_local_symbol (name);
-            emit_incdec_symbol_now (lhs, name, op, name_line, name_start, name_caret);
-            free (name);
-        
-        } else {
-            report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after %s", op == TOK_INCR ? "++" : "--");
-        }
-        
-        FINISH_FOR_HEADER_EXPR (0);
-    
-    }
-    
-    if (tok.kind != TOK_IDENT) {
-    
-        if (state->ofp) {
-            emit_load_assignment_rhs_expression_to_reg ("eax");
-        } else {
-            skip_balanced_until (end_token, TOK_EOF, TOK_EOF);
-        }
-        
-        FINISH_FOR_HEADER_EXPR (0);
-    
-    }
-    
-    name = xstrdup (tok.ident);
-    name_start = tok.start;
-    name_caret = tok.caret;
-    name_line = get_line_number ();
-    
-    get_token ();
-    
-    if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
-    
-        op = tok.kind;
-        get_token ();
-        
-        lhs = find_local_symbol (name);
-        emit_incdec_symbol_now (lhs, name, op, name_line, name_start, name_caret);
-        
-        FINISH_FOR_HEADER_EXPR (1);
-    
-    }
-    
-    if (tok.kind == TOK_LPAREN) {
-    
-        if (!find_local_symbol (name)) {
-            ensure_global_function_symbol (name, name_start, name_caret, name_line);
-        }
-        
-        emit_call_identifier_to_reg_now (name, "eax", name_start, name_caret, name_line);
-        FINISH_FOR_HEADER_EXPR (1);
-    
-    }
-    
-    if (!is_assignment_operator (tok.kind)) {
-    
-        if (!find_local_symbol (name) && find_global_symbol (name) < 0) {
-        
-            int64_s ignored;
-            
-            if (!resolve_enum_constant (name, &ignored)) {
-                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-            }
-        
-        }
-        
-        if (tok.kind == TOK_COMMA) {
-        
-            get_token ();
-            free (name);
-            
-            parse_for_header_expression_until (end_token);
-            return;
-        
-        }
-        
-        skip_balanced_until (end_token, TOK_EOF, TOK_EOF);
-        expect (end_token, end_token == TOK_SEMI ? ";" : ")");
-        
-        free (name);
-        return;
-    
-    }
-    
-    op = tok.kind;
-    get_token ();
-    
-    lhs = find_local_symbol (name);
-    global_index = find_global_symbol (name);
-    
-    if (!lhs && global_index < 0) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-        FINISH_FOR_HEADER_EXPR (1);
-    
-    }
-    
-    if (state->ofp) {
-    
-        lhs_size = lhs ? lhs->size : get_global_symbol_size (name);
-        lhs_is_floating = lhs ? lhs->is_floating : get_global_symbol_floating (name);
-        
-        if (lhs_is_floating) {
-        
-            if (!floating_assignment_operator_supported_now (op)) {
-            
-                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "invalid operands to floating assignment operator");
-                skip_balanced_until (end_token, TOK_EOF, TOK_EOF);
-            
-            } else {
-            
-                if (op == TOK_ASSIGN) {
-                    emit_load_floating_rhs_expression_now (lhs_size);
-                } else {
-                
-                    emit_load_floating_symbol_now (lhs, name, lhs_size);
-                    emit_load_floating_rhs_expression_now (lhs_size);
-                    emit_floating_binary_now (op);
-                
-                }
-                
-                emit_store_floating_symbol_now (lhs, name, lhs_size);
-            
-            }
-        
-        } else if (lhs_size == (DATA_LLONG & 0x1f)) {
-        
-            if (op == TOK_ASSIGN) {
-                emit_load_assignment_rhs_expression_to_pair ("eax", "edx", lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
-            } else {
-            
-                if (lhs) {
-                
-                    if (lhs->is_static && lhs->static_label) {
-                        emit_load_global64_to_pair ("eax", "edx", lhs->static_label);
-                    } else {
-                        emit_load_local64_to_pair (lhs->offset, "eax", "edx");
-                    }
-                
-                } else {
-                    emit_load_global64_to_pair ("eax", "edx", name);
-                }
-                
-                /*
-                 * Compound assignments need the complete RHS expression.
-                 * Using emit_load_assignment_rhs_to_pair() only consumes one
-                 * primary operand, so e.g.
-                 *
-                 *     final_value += symbol->frag->address + left_value;
-                 *
-                 * leaves the second + operand for the statement parser and
-                 * reports "expected ;".  Evaluate the full RHS in eax:edx,
-                 * copy it to the RHS pair ebx:ecx, then restore the original
-                 * LHS value before applying the compound operator.
-                 */
-                emit_push_reg_now ("eax");
-                emit_push_reg_now ("edx");
-                
-                emit_load_assignment_rhs_expression_to_pair ("eax", "edx", lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
-                
-                emit_mov_reg_to_reg_now ("ebx", "eax");
-                emit_mov_reg_to_reg_now ("ecx", "edx");
-                
-                emit_pop_reg_now ("edx");
-                emit_pop_reg_now ("eax");
-                
-                emit_preserve_assignment64_regs (op);
-                emit_assignment_binary_op64 (op, lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
-                emit_restore_assignment64_regs (op);
-            
-            }
-            
-            if (lhs) {
-            
-                if (lhs->is_static && lhs->static_label) {
-                    emit_store_pair_to_global64 (lhs->static_label, "eax", "edx");
-                } else {
-                    emit_store_pair_to_local64 (lhs->offset, "eax", "edx");
-                }
-            
-            } else {
-                emit_store_pair_to_global64 (name, "eax", "edx");
-            }
-        
-        } else {
-        
-            if (op == TOK_ASSIGN) {
-                emit_load_assignment_rhs_expression_to_reg ("eax");
-            } else {
-            
-                if (lhs) {
-                
-                    if (lhs->is_static && lhs->static_label) {
-                        emit_load_global_to_reg_ex ("eax", lhs->static_label, lhs->size, lhs->is_unsigned);
-                    } else {
-                        emit_load_local_to_reg_ex ("eax", lhs->offset, lhs->size, lhs->is_unsigned);
-                    }
-                
-                } else {
-                    emit_load_global_to_reg ("eax", name, lhs_size);
-                }
-                
-                emit_load_assignment_rhs_to_reg ("edx");
-                emit_assignment_binary_op (op, lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name));
-            
-            }
-            
-            if (lhs) {
-            
-                if (lhs->is_static && lhs->static_label) {
-                    emit_store_reg_to_global (lhs->static_label, lhs->size, "eax");
-                } else {
-                    emit_store_reg_to_local (lhs->offset, lhs->size, "eax");
-                }
-            
-            } else {
-                emit_store_reg_to_global (name, lhs_size, "eax");
-            }
-        
-        }
-    
-    } else {
-        skip_balanced_until (end_token, TOK_EOF, TOK_EOF);
-    }
-    
-    FINISH_FOR_HEADER_EXPR (1);
-
-#undef      FINISH_FOR_HEADER_EXPR
-
-}
-
-static void parse_for_statement (void) {
-
-    int loop_label = anon_label++;
-    int body_label = anon_label++;
-    int continue_label = anon_label++;
-    int break_label = anon_label++;
-    int old_break_label = current_break_label;
-    int old_continue_label = current_continue_label;
-    
-    long old_break_cleanup_base = current_break_cleanup_base;
-    long old_continue_cleanup_base = current_continue_cleanup_base;
-    
-    int cond_known = 0;
-    int cond_value = 1;
-    
-    FILE *saved_ofp;
-    FILE *step_tmp = 0;
-    
-    get_token ();
-    expect (TOK_LPAREN, "(");
-    
-    if (tok.kind == TOK_SEMI) {
-        get_token ();
-    } else {
-        parse_for_header_expression_until (TOK_SEMI);
-    }
-    
-    emit_statement_label (loop_label);
-    
-    if (tok.kind == TOK_SEMI) {
-        get_token ();
-    } else {
-    
-        emit_statement_jump_if_false (break_label);
-        
-        cond_known = statement_condition_constant_known;
-        cond_value = statement_condition_constant_value;
-        
-        if (tok.kind != TOK_SEMI) {
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        }
-        
-        expect (TOK_SEMI, ";");
-    
-    }
-    
-    if (tok.kind == TOK_RPAREN) {
-        get_token ();
-    } else {
-    
-        if (state->ofp) {
-            step_tmp = scc_tmpfile ();
-        }
-        
-        if (step_tmp) {
-        
-            saved_ofp = state->ofp;
-            
-            state->ofp = step_tmp;
-            parse_for_header_expression_until (TOK_RPAREN);
-            
-            state->ofp = saved_ofp;
-        
-        } else {
-            parse_for_header_expression_until (TOK_RPAREN);
-        }
-    
-    }
-    
-    current_break_label = break_label;
-    current_continue_label = continue_label;
-    current_break_cleanup_base = current_block_cleanup_bytes;
-    current_continue_cleanup_base = current_block_cleanup_bytes;
-    
-    if (cond_known && !cond_value) {
-        parse_statement_suppressed ();
-    } else {
-    
-        emit_statement_jump (body_label);
-        emit_statement_label (body_label);
-        
-        parse_statement ();
-        emit_statement_label (continue_label);
-        
-        if (step_tmp) {
-        
-            replay_tmp_file_to_output (step_tmp, state->ofp);
-            scc_close (step_tmp);
-            
-            step_tmp = 0;
-        
-        }
-        
-        emit_statement_jump (loop_label);
-    
-    }
-    
-    if (step_tmp) {
-        scc_close (step_tmp);
-    }
-    
-    emit_statement_label (break_label);
-    
-    current_break_label = old_break_label;
-    current_continue_label = old_continue_label;
-    current_break_cleanup_base = old_break_cleanup_base;
-    current_continue_cleanup_base = old_continue_cleanup_base;
-    
-    statement_ends_control_flow = 0;
-
-}
-
-static void parse_while_statement (void) {
-
-    int loop_label = anon_label++;
-    int body_label = anon_label++;
-    int break_label = anon_label++;
-    int old_break_label = current_break_label;
-    int old_continue_label = current_continue_label;
-    
-    long old_break_cleanup_base = current_break_cleanup_base;
-    long old_continue_cleanup_base = current_continue_cleanup_base;
-    
-    int cond_known;
-    int cond_value;
-    
-    get_token ();
-    expect (TOK_LPAREN, "(");
-    
-    emit_statement_label (loop_label);
-    emit_statement_jump_if_false (break_label);
-    
-    cond_known = statement_condition_constant_known;
-    cond_value = statement_condition_constant_value;
-    
-    if (tok.kind != TOK_RPAREN) {
-        skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
-    }
-    
-    expect (TOK_RPAREN, ")");
-    
-    current_break_label = break_label;
-    current_continue_label = loop_label;
-    current_break_cleanup_base = current_block_cleanup_bytes;
-    current_continue_cleanup_base = current_block_cleanup_bytes;
-    
-    if (cond_known && !cond_value) {
-        parse_statement_suppressed ();
-    } else {
-    
-        emit_statement_jump (body_label);
-        emit_statement_label (body_label);
-        
-        parse_statement ();
-        
-        if (!statement_ends_control_flow) {
-            emit_statement_jump (loop_label);
-        }
-    
-    }
-    
-    emit_statement_label (break_label);
-    
-    current_break_label = old_break_label;
-    current_continue_label = old_continue_label;
-    current_break_cleanup_base = old_break_cleanup_base;
-    current_continue_cleanup_base = old_continue_cleanup_base;
-    
-    statement_ends_control_flow = 0;
-
-}
-
-static void parse_do_statement (void) {
-
-    int body_label = anon_label++;
-    int cond_label = anon_label++;
-    int break_label = anon_label++;
-    int old_break_label = current_break_label;
-    int old_continue_label = current_continue_label;
-    
-    long old_break_cleanup_base = current_break_cleanup_base;
-    long old_continue_cleanup_base = current_continue_cleanup_base;
-    
-    int cond_known = 0;
-    int cond_value = 0;
-    
-    get_token ();
-    
-    current_break_label = break_label;
-    current_continue_label = cond_label;
-    current_break_cleanup_base = current_block_cleanup_bytes;
-    current_continue_cleanup_base = current_block_cleanup_bytes;
-    
-    emit_statement_jump (body_label);
-    
-    emit_statement_label (body_label);
-    parse_statement ();
-    
-    emit_statement_label (cond_label);
-    
-    if (_accept (TOK_WHILE)) {
-    
-        expect (TOK_LPAREN, "(");
-        emit_statement_jump_if_false (break_label);
-        
-        cond_known = statement_condition_constant_known;
-        cond_value = statement_condition_constant_value;
-        
-        if (tok.kind != TOK_RPAREN) {
-            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
-        }
-        
-        expect (TOK_RPAREN, ")");
-        expect (TOK_SEMI, ";");
-        
-        if (!cond_known || cond_value) {
-            emit_statement_jump (body_label);
-        }
-    
-    } else {
-        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected while after do statement");
-    }
-    
-    emit_statement_label (break_label);
-    
-    current_break_label = old_break_label;
-    current_continue_label = old_continue_label;
-    current_break_cleanup_base = old_break_cleanup_base;
-    current_continue_cleanup_base = old_continue_cleanup_base;
-    
-    statement_ends_control_flow = 0;
-
-}
-
-static int statement_condition_emit_logical_tail (int label) {
-
-    int skip_label;
-    
-    if (tok.kind == TOK_LOGAND) {
-    
-        get_token ();
-        
-        emit_statement_jump_if_false (label);
-        return 1;
-    
-    }
-    
-    if (tok.kind == TOK_LOGOR) {
-    
-        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);
-            }
-        
-        }
-        
-        emit_statement_jump_if_false (label);
-        emit_statement_label (skip_label);
-        
-        return 1;
-    
-    }
-    
-    return 0;
-
-}
-
-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 ();
-        
-        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);
-        return 1;
-    
-    }
-    
-    emit_statement_cmp_eax_edx_jump_if_false (op, is_unsigned, label);
-    return 1;
-
-}
-
-static int statement_condition_fold_logical_tail (int label) {
-
-    enum token_kind logop;
-    
-    while (tok.kind == TOK_LOGOR || tok.kind == TOK_LOGAND) {
-    
-        logop = tok.kind;
-        
-        /*
-         * Constant short-circuit cases can discard the rest of the condition.
-         *
-         *     true  || anything  -> true
-         *     false && anything  -> false
-         *
-         * Leave tok on ')' so the caller's expect(TOK_RPAREN) still works.
-         */
-        if ((logop == TOK_LOGOR && statement_condition_constant_value) || (logop == TOK_LOGAND && !statement_condition_constant_value)) {
-        
-            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
-            return 1;
-        
-        }
-        
-        /*
-         * The left side is non-decisive:
-         *
-         *     false || rhs  -> rhs
-         *     true  && rhs  -> rhs
-         *
-         * So consume the logical operator and emit/fold the RHS normally.
-         */
-        get_token ();
-        
-        statement_condition_constant_known = 0;
-        statement_condition_constant_value = 0;
-        
-        emit_statement_jump_if_false (label);
-        return 1;
-    
-    }
-    
-    return 0;
-
-}
-
-static int source_starts_with_parenthesized_assignment_at (const char *p) {
-
-    int parens = 0;
-    
-    if (!p || *p != '(') {
-        return 0;
-    }
-    
-    /*
-     * 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++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (*p == '(') {
-        return 0;
-    }
-    
-    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
-        return 0;
-    }
-    
-    p++;
-    
-    while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
-        p++;
-    }
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    while (parens > 0 && *p == ')') {
-    
-        parens--;
-        p++;
-        
-        while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-            p++;
-        }
-    
-    }
-    
-    /*
-     * A condition assignment normally looks like:
-     *
-     *     if ((x = y))
-     *
-     * At this point the scanner has consumed the opening paren(s) and the
-     * identifier.  For the common form above, the assignment operator appears
-     * before the closing paren, so `parens' is still non-zero.  The previous
-     * guard returned 0 before checking for '=', which made the statement
-     * condition parser treat the expression as just `(x' and then report a
-     * false "expected )" at the assignment operator.  Check for assignment
-     * operators first, while still rejecting comparison operators.
-     */
-    if (*p == '=') {
-        return p[1] != '=';
-    }
-    
-    if (parens != 0) {
-        return 0;
-    }
-    
-    if ((*p == '+' || *p == '-' || *p == '*' || *p == '/' || *p == '%' ||
-         *p == '&' || *p == '|' || *p == '^') && p[1] == '=') {
-        return 1;
-    }
-    
-    if ((*p == '<' && p[1] == '<' && p[2] == '=') ||
-        (*p == '>' && p[1] == '>' && p[2] == '=')) {
-        return 1;
-    }
-    
-    return 0;
-
-}
-
-static int source_starts_with_parenthesized_assignment_now (void) {
-
-    /**
-     * Only test the current token text.  tok.start can point at the start of
-     * the whole source line, so scanning the whole line misclassifies a for
-     * condition such as:
-     *
-     *     for (len = 0; (len < max_len) && str[len]; len++);
-     *
-     * as a parenthesized assignment because of the earlier ``(len = 0`` in the
-     * same line.  This helper is a look-ahead guard; it must not match any
-     * parenthesized assignment except the one beginning at the current token.
-     */
-    if (source_starts_with_parenthesized_assignment_at (tok.caret)) {
-        return 1;
-    }
-    
-    return 0;
-
-}
-
-static int parenthesized_assignment_open_parens = 0;
-static int parenthesized_assignment_closed_parens = 0;
-
-static void consume_parenthesized_assignment_remaining_closes (void) {
-
-    while (parenthesized_assignment_closed_parens < parenthesized_assignment_open_parens && tok.kind == TOK_RPAREN) {
-    
-        get_token ();
-        parenthesized_assignment_closed_parens++;
-    
-    }
-
-}
-
-static int emit_load_parenthesized_assignment_expression_to_reg_now (const char *reg, int *out_is_unsigned) {
-
-    char *name;
-    int global_index;
-    
-    const char *name_start, *name_caret;
-    unsigned long name_line;
-    
-    enum token_kind op;
-    struct local_symbol *lhs;
-    
-    int lhs_size;
-    int lhs_is_floating;
-    int lhs_is_unsigned;
-    int paren_count = 0;
-    
-    parenthesized_assignment_open_parens = 0;
-    parenthesized_assignment_closed_parens = 0;
-    
-    if (out_is_unsigned) {
-        *out_is_unsigned = 0;
-    }
-    
-    if (tok.kind != TOK_LPAREN || !source_starts_with_parenthesized_assignment_now ()) {
-        return 0;
-    }
-    
-    while (tok.kind == TOK_LPAREN) {
-    
-        paren_count++;
-        get_token ();
-    
-    }
-    
-    if (tok.kind != TOK_IDENT) {
-        return 0;
-    }
-    
-    parenthesized_assignment_open_parens = paren_count;
-    
-    name = xstrdup (tok.ident);
-    name_start = tok.start;
-    name_caret = tok.caret;
-    name_line = get_line_number ();
-    
-    get_token ();
-    
-    while (parenthesized_assignment_closed_parens < parenthesized_assignment_open_parens && tok.kind == TOK_RPAREN) {
-    
-        get_token ();
-        parenthesized_assignment_closed_parens++;
-    
-    }
-    
-    if (tok.kind == TOK_DOT || tok.kind == TOK_ARROW) {
-    
-        enum token_kind member_op = tok.kind;
-        char *member;
-        
-        const char *member_start;
-        const char *member_caret;
-        
-        unsigned long member_line;
-        
-        int member_offset = 0;
-        int member_size = DATA_INT & 0x1f;
-        
-        get_token ();
-        
-        member_start = tok.start;
-        member_caret = tok.caret;
-        member_line = get_line_number ();
-        
-        if (tok.kind != TOK_IDENT) {
-        
-            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "expected member name after %s", member_op == TOK_ARROW ? "->" : ".");
-            
-            free (name);
-            return 1;
-        
-        }
-        
-        member = xstrdup (tok.ident);
-        get_token ();
-        
-        if (!find_member_info (member, &member_offset, &member_size)) {
-        
-            report_line_at (get_filename (), member_line, REPORT_ERROR, member_start, member_caret, "unknown member '%s'", member);
-            
-            free (member);
-            free (name);
-            
-            return 1;
-        
-        }
-        
-        free (member);
-        
-        if (!is_assignment_operator (tok.kind)) {
-        
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-            expect (TOK_SEMI, ";");
-            
-            free (name);
-            return 1;
-        
-        }
-        
-        op = tok.kind;
-        get_token ();
-        
-        lhs = find_local_symbol (name);
-        global_index = find_global_symbol (name);
-        
-        if (!lhs && global_index < 0) {
-        
-            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-            
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-            expect (TOK_SEMI, ";");
-            
-            free (name);
-            return 1;
-        
-        }
-        
-        if (state->ofp) {
-        
-            if (member_op == TOK_ARROW) {
-            
-                if (lhs) {
-                
-                    if (lhs->is_static && lhs->static_label) {
-                        emit_load_global_to_reg ("edx", lhs->static_label, DATA_PTR);
-                    } else {
-                        emit_load_local_to_reg ("edx", lhs->offset, DATA_PTR);
-                    }
-                
-                } else {
-                    emit_load_global_to_reg ("edx", name, DATA_PTR);
-                }
-            
-            } else {
-            
-                if (lhs) {
-                
-                    if (lhs->is_static && lhs->static_label) {
-                        emit_load_address_to_reg_now ("edx", lhs->static_label);
-                    } else {
-                        emit_load_local_address_to_reg_now ("edx", lhs->offset);
-                    }
-                
-                } else {
-                    emit_load_address_to_reg_now ("edx", name);
-                }
-            
-            }
-            
-            if (op == TOK_ASSIGN) {
-            
-                emit_push_reg_now ("edx");
-                emit_load_assignment_rhs_expression_to_reg ("eax");
-                emit_pop_reg_now ("edx");
-            
-            } else {
-            
-                emit_load_member_from_addr_reg_now ("eax", "edx", member_offset, member_size);
-                emit_push_reg_now ("edx");
-                emit_push_reg_now ("eax");
-                
-                if (tok.kind == TOK_TILDE) {
-                
-                    int64_s rhs_const;
-                    get_token ();
-                    
-                    if (tok.kind == TOK_LPAREN) {
-                    
-                        get_token ();
-                        
-                        rhs_const = const64_from_current_foldable_expr ();
-                        expect (TOK_RPAREN, ")");
-                    
-                    } else {
-                        rhs_const = const64_from_current_foldable_expr ();
-                    }
-                    
-                    rhs_const.low = (~rhs_const.low) & U32_MASK;
-                    rhs_const.high = (~rhs_const.high) & U32_MASK;
-                    
-                    emit_load_const32_to_reg_now ("edx", rhs_const);
-                
-                } else if (current_integer_expr_is_foldable_now ()) {
-                
-                    int64_s rhs_const = const64_from_current_foldable_expr ();
-                    emit_load_const32_to_reg_now ("edx", rhs_const);
-                
-                } else {
-                    emit_load_assignment_rhs_expression_to_reg ("edx");
-                }
-                
-                emit_pop_reg_now ("eax");
-                emit_assignment_binary_op (op, 0);
-                emit_pop_reg_now ("edx");
-            
-            }
-            
-            emit_store_member_to_addr_reg_now ("edx", member_offset, "eax", member_size);
-        
-        } else {
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        }
-        
-        expect_semi_or_recover ();
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    if (!is_assignment_operator (tok.kind)) {
-    
-        free (name);
-        return 0;
-    
-    }
-    
-    op = tok.kind;
-    get_token ();
-    
-    lhs = find_local_symbol (name);
-    global_index = find_global_symbol (name);
-    
-    if (!lhs && global_index < 0) {
-    
-        report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "unknown symbol '%s'", name);
-        
-        skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
-        expect (TOK_RPAREN, ")");
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    lhs_size = lhs ? lhs->size : get_global_symbol_size (name);
-    lhs_is_floating = lhs ? lhs->is_floating : get_global_symbol_floating (name);
-    lhs_is_unsigned = lhs ? lhs->is_unsigned : get_global_symbol_unsigned (name);
-    
-    if (out_is_unsigned) {
-        *out_is_unsigned = lhs_is_unsigned;
-    }
-    
-    if (state->ofp) {
-    
-        if (lhs_is_floating) {
-        
-            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "floating assignment expression in condition not implemented");
-            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
-        
-        } else if (lhs_size == (DATA_LLONG & 0x1f)) {
-        
-            if (op == TOK_ASSIGN) {
-                emit_load_assignment_rhs_expression_to_pair ("eax", "edx", lhs_is_unsigned);
-            } else {
-            
-                if (lhs) {
-                
-                    if (lhs->is_static && lhs->static_label) {
-                        emit_load_global64_to_pair ("eax", "edx", lhs->static_label);
-                    } else {
-                        emit_load_local64_to_pair (lhs->offset, "eax", "edx");
-                    }
-                
-                } else {
-                    emit_load_global64_to_pair ("eax", "edx", name);
-                }
-                
-                /*
-                 * Compound assignments need the complete RHS expression.
-                 * Using emit_load_assignment_rhs_to_pair() only consumes one
-                 * primary operand, so e.g.
-                 *
-                 *     final_value += symbol->frag->address + left_value;
-                 *
-                 * leaves the second + operand for the statement parser and
-                 * reports "expected ;".  Evaluate the full RHS in eax:edx,
-                 * copy it to the RHS pair ebx:ecx, then restore the original
-                 * LHS value before applying the compound operator.
-                 */
-                emit_push_reg_now ("eax");
-                emit_push_reg_now ("edx");
-                
-                emit_load_assignment_rhs_expression_to_pair ("eax", "edx", lhs_is_unsigned);
-                
-                emit_mov_reg_to_reg_now ("ebx", "eax");
-                emit_mov_reg_to_reg_now ("ecx", "edx");
-                
-                emit_pop_reg_now ("edx");
-                emit_pop_reg_now ("eax");
-                
-                emit_preserve_assignment64_regs (op);
-                emit_assignment_binary_op64 (op, lhs_is_unsigned);
-                emit_restore_assignment64_regs (op);
-            
-            }
-            
-            if (lhs) {
-            
-                if (lhs->is_static && lhs->static_label) {
-                    emit_store_pair_to_global64 (lhs->static_label, "eax", "edx");
-                } else {
-                    emit_store_pair_to_local64 (lhs->offset, "eax", "edx");
-                }
-            
-            } else {
-                emit_store_pair_to_global64 (name, "eax", "edx");
-            }
-        
-        } else {
-        
-            if (op == TOK_ASSIGN) {
-                emit_load_assignment_rhs_expression_to_reg (reg);
-            } else {
-            
-                if (lhs) {
-                
-                    if (lhs->is_static && lhs->static_label) {
-                        emit_load_global_to_reg_ex (reg, lhs->static_label, lhs->size, lhs->is_unsigned);
-                    } else {
-                        emit_load_local_to_reg_ex (reg, lhs->offset, lhs->size, lhs->is_unsigned);
-                    }
-                
-                } else {
-                    emit_load_global_to_reg (reg, name, lhs_size);
-                }
-                
-                emit_load_assignment_rhs_to_reg ("edx");
-                
-                if (strcmp (reg, "eax") != 0 && state->ofp) {
-                
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                        fprintf (state->ofp, "    mov eax, %s\n", reg);
-                    } else {
-                        fprintf (state->ofp, "    movl %%%s, %%eax\n", reg);
-                    }
-                
-                }
-                
-                emit_assignment_binary_op (op, lhs_is_unsigned);
-                
-                if (strcmp (reg, "eax") != 0 && state->ofp) {
-                
-                    if (state->syntax & ASM_SYNTAX_INTEL) {
-                        fprintf (state->ofp, "    mov %s, eax\n", reg);
-                    } else {
-                        fprintf (state->ofp, "    movl %%eax, %%%s\n", reg);
-                    }
-                
-                }
-            
-            }
-            
-            if (lhs) {
-            
-                if (lhs->is_static && lhs->static_label) {
-                    emit_store_reg_to_global (lhs->static_label, lhs->size, reg);
-                } else {
-                    emit_store_reg_to_local (lhs->offset, lhs->size, reg);
-                }
-            
-            } else {
-                emit_store_reg_to_global (name, lhs_size, reg);
-            }
-        
-        }
-    
-    } else {
-        skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
-    }
-    
-    consume_parenthesized_assignment_remaining_closes ();
-    
-    free (name);
-    return 1;
-
-}
-
-static int source_condition_has_top_level_compare_now (const char *p) {
-
-    int paren_depth = 0;
-    int bracket_depth = 0;
-    int saw_operand = 0;
-    
-    if (!p) {
-        return 0;
-    }
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    while (*p) {
-    
-        if (*p == '\'' || *p == '"') {
-        
-            int quote = *p++;
-            
-            while (*p) {
-            
-                if (*p == '\\' && p[1]) {
-                
-                    p += 2;
-                    continue;
-                
-                }
-                
-                if (*p == quote) {
-                
-                    p++;
-                    break;
-                
-                }
-                
-                p++;
-            
-            }
-            
-            saw_operand = 1;
-            continue;
-        
-        }
-        
-        if (*p == '(') {
-        
-            paren_depth++;
-            
-            saw_operand = 1;
-            p++;
-            
-            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;
-                }
-                
-                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]) {
-                
-                    p += 2;
-                    continue;
-                
-                }
-                
-                if (*p == quote) {
-                
-                    p++;
-                    break;
-                
-                }
-                
-                p++;
-            
-            }
-            
-            continue;
-        
-        }
-        
-        if (*p == '(') {
-        
-            paren_depth++;
-            p++;
-            
-            continue;
-        
-        }
-        
-        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;
-    }
-    
-    /*
-     * Do not let the generic integer direct-compare fast path consume
-     * floating conditions such as:
-     *
-     *     while (value_fractional_d - ((int64_t)value_fractional_d) != 0)
-     *
-     * That path lowers the LHS through eax and compares integer dwords,
-     * so the example above becomes low_word - low_word and the fractional
-     * loop exits immediately.  Leave floating expressions for the x87
-     * condition path below.
-     */
-    if (token_is_const_floating_condition_operand_now () || rhs_current_operand_is_floating_now ()) {
-        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)) {
-    
-        while (is_arithmetic_binary_operator (tok.kind)) {
-        
-            op = tok.kind;
-            get_token ();
-            
-            if (rhs_current_operand_is_unsigned_now ()) {
-                is_unsigned = 1;
-            }
-            
-            emit_load_assignment_rhs_to_reg ("edx");
-            emit_assignment_binary_op (op, is_unsigned);
-        
-        }
-        
-        if (token_is_statement_compare_operator (tok.kind)) {
-        
-            op = tok.kind;
-            get_token ();
-            
-            if (rhs_current_operand_is_unsigned_now ()) {
-                is_unsigned = 1;
-            }
-            
-            emit_load_assignment_compare_expression_to_reg ("edx");
-            consume_parenthesized_assignment_remaining_closes ();
-            
-            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_eax_truth_jump_if_false_and_tail (label);
-        return;
-    
-    }
-    
-    if (emit_statement_parenthesized_lhs_compare_jump_if_false_now (label)) {
-        return;
-    }
-    
-    if (emit_statement_direct_compare_jump_if_false_now (label)) {
-        return;
-    }
-    
-    if (tok.kind == TOK_LPAREN && (token_is_const_floating_condition_operand_now () || rhs_current_operand_is_floating_now ())) {
-    
-        double left_float = 0.0;
-        
-        int left_float_constant = 0;
-        int float_size = DATA_DOUBLE & 0x1f;
-        
-        if (token_is_const_floating_condition_operand_now ()) {
-        
-            left_float = parse_floating_const_expr_value_now ();
-            left_float_constant = 1;
-        
-        } else {
-            emit_load_floating_rhs_expression_now (float_size);
-        }
-        
-        if (token_is_statement_compare_operator (tok.kind)) {
-        
-            op = tok.kind;
-            get_token ();
-            
-            if (left_float_constant && (token_is_floating_constant_now () || token_is_const_condition_operand_now ())) {
-            
-                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 = int64_to_double_now (right_int);
-                
-                }
-                
-                statement_condition_constant_known = 1;
-                statement_condition_constant_value = statement_compare_floating_const_true (left_float, op, right_float) ? 1 : 0;
-                
-                if (statement_condition_fold_logical_tail (label)) {
-                    return;
-                }
-                
-                return;
-            
-            }
-            
-            if (left_float_constant) {
-                emit_load_floating_ld_now (float_size, left_float);
-            }
-            
-            emit_load_floating_rhs_expression_now (float_size);
-            emit_statement_floating_compare_jump_if_false (op, label);
-            
-            return;
-        
-        }
-        
-        if (floating_rhs_result_in_eax_bool) {
-        
-            emit_statement_eax_truth_jump_if_false_and_tail (label);
-            
-            floating_rhs_result_in_eax_bool = 0;
-            return;
-        
-        }
-        
-        if (left_float_constant) {
-        
-            statement_condition_constant_known = 1;
-            statement_condition_constant_value = left_float != 0.0 ? 1 : 0;
-            
-            if (statement_condition_fold_logical_tail (label)) {
-                return;
-            }
-            
-            return;
-        
-        }
-        
-        emit_load_floating_ld_now (float_size, 0.0);
-        
-        emit_statement_floating_compare_jump_if_false (TOK_NOTEQ, 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");
-        
-        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;
-
-    }
-    
-    if (tok.kind == TOK_LPAREN && !source_starts_with_parenthesized_assignment_now ()) {
-    
-        get_token ();
-        
-        emit_statement_jump_if_false (label);
-        expect (TOK_RPAREN, ")");
-        
-        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;
-    
-    }
-    
-    /*
-     * Fold simple constant conditions at parse time.  This avoids emitting:
-     *
-     *     mov eax, 1
-     *     test eax, eax
-     *     jz ...
-     *
-     * for things like if (1), and avoids cmp/jcc for things like
-     * if (1 < 10), if (5 > 2), if (1ULL < 10LL), etc.
-     */
-    if (token_is_const_floating_condition_operand_now () || rhs_current_operand_is_floating_now ()) {
-    
-        double left_float = 0.0;
-        
-        int left_float_constant = 0;
-        int float_size = DATA_DOUBLE & 0x1f;
-        
-        if (token_is_const_floating_condition_operand_now ()) {
-        
-            left_float = parse_floating_const_expr_value_now ();
-            left_float_constant = 1;
-        
-        } else {
-            emit_load_floating_rhs_expression_now (float_size);
-        }
-        
-        if (token_is_statement_compare_operator (tok.kind)) {
-        
-            op = tok.kind;
-            get_token ();
-            
-            if (left_float_constant && (token_is_floating_constant_now () || token_is_const_condition_operand_now ())) {
-            
-                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 = int64_to_double_now (right_int);
-                
-                }
-                
-                statement_condition_constant_known = 1;
-                statement_condition_constant_value = statement_compare_floating_const_true (left_float, op, right_float) ? 1 : 0;
-                
-                if (statement_condition_fold_logical_tail (label)) {
-                    return;
-                }
-                
-                return;
-            
-            }
-            
-            if (left_float_constant) {
-                emit_load_floating_ld_now (float_size, left_float);
-            }
-            
-            emit_load_floating_rhs_expression_now (float_size);
-            emit_statement_floating_compare_jump_if_false (op, label);
-            
-            return;
-        
-        }
-        
-        if (floating_rhs_result_in_eax_bool) {
-        
-            emit_statement_eax_truth_jump_if_false_and_tail (label);
-            
-            floating_rhs_result_in_eax_bool = 0;
-            return;
-        
-        }
-        
-        if (left_float_constant) {
-        
-            statement_condition_constant_known = 1;
-            statement_condition_constant_value = left_float != 0.0 ? 1 : 0;
-            
-            if (statement_condition_fold_logical_tail (label)) {
-                return;
-            }
-            
-            return;
-        
-        }
-        
-        emit_load_floating_ld_now (float_size, 0.0);
-        emit_statement_floating_compare_jump_if_false (TOK_NOTEQ, label);
-        
-        return;
-    
-    }
-    
-    /*
-     * 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 = current_integer_expr_is_foldable_now ();
-        int left_unsigned = rhs_current_operand_is_unsigned_now ();
-        
-        int64_s left;
-        
-        if (fold_whole_expr) {
-            left = const64_from_current_foldable_expr ();
-        } else {
-            left = const64_from_current_operand ();
-        }
-        
-        if (is_arithmetic_binary_operator (tok.kind)) {
-        
-            emit_statement_const32_to_eax (left);
-            
-            while (is_arithmetic_binary_operator (tok.kind)) {
-            
-                op = tok.kind;
-                get_token ();
-                
-                if (rhs_current_operand_is_unsigned_now ()) {
-                    left_unsigned = 1;
-                }
-                
-                emit_load_assignment_rhs_to_reg ("edx");
-                emit_assignment_binary_op (op, left_unsigned);
-            
-            }
-            
-            if (token_is_statement_compare_operator (tok.kind)) {
-            
-                op = tok.kind;
-                get_token ();
-                
-                is_unsigned = left_unsigned;
-                
-                if (rhs_current_operand_is_unsigned_now ()) {
-                    is_unsigned = 1;
-                }
-                
-                emit_statement_cmp_eax_edx_jump_if_false_and_tail (op, is_unsigned, label);
-                return;
-            
-            }
-            
-            emit_statement_test_eax_jump_if_false (label);
-            return;
-        
-        }
-        
-        if (token_is_statement_compare_operator (tok.kind)) {
-        
-            op = tok.kind;
-            get_token ();
-            
-            is_unsigned = left_unsigned;
-            
-            if (rhs_current_operand_is_unsigned_now ()) {
-                is_unsigned = 1;
-            }
-            
-            if (token_is_floating_constant_now ()) {
-            
-                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;
-                statement_condition_constant_value = statement_compare_floating_const_true (left_float, op, right_float) ? 1 : 0;
-                
-                if (statement_condition_fold_logical_tail (label)) {
-                    return;
-                }
-                
-                return;
-            
-            }
-            
-            if (token_is_const_condition_operand_now ()) {
-            
-                int64_s right;
-                
-                if (current_integer_expr_is_foldable_now ()) {
-                    right = const64_from_current_foldable_expr ();
-                } else {
-                    right = const64_from_current_operand ();
-                }
-                
-                statement_condition_constant_known = 1;
-                statement_condition_constant_value = statement_compare_const64_true (left, op, right, is_unsigned) ? 1 : 0;
-                
-                if (statement_condition_fold_logical_tail (label)) {
-                    return;
-                }
-                
-                return;
-            
-            }
-            
-            if (rhs_current_operand_is_floating_now ()) {
-            
-                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);
-                emit_statement_floating_compare_jump_if_false (op, label);
-                
-                return;
-            
-            }
-            
-            emit_statement_const32_to_eax (left);
-            emit_load_assignment_rhs_expression_to_reg ("edx");
-            
-            emit_statement_cmp_eax_edx_jump_if_false_and_tail (op, is_unsigned, label);
-            return;
-        
-        }
-        
-        statement_condition_constant_known = 1;
-        statement_condition_constant_value = int64_statement_truth_value (left) ? 1 : 0;
-        
-        if (statement_condition_fold_logical_tail (label)) {
-            return;
-        }
-        
-        return;
-    
-    }
-    
-    /*
-     * A leading unary ! always yields an int truth value.  Do not route it
-     * through the 64-bit condition path just because the operand text happens
-     * to mention a symbol that the coarse scanner thinks is 64-bit; that path
-     * expects an unconverted 64-bit value and will compare EDX:EAX against
-     * uninitialised ECX:EBX for a plain if (!p).
-     */
-    if (tok.kind == TOK_XMARK) {
-    
-        emit_load_assignment_rhs_expression_to_reg ("eax");
-        
-        emit_statement_eax_truth_jump_if_false_and_tail (label);
-        return;
-    
-    }
-    
-    if (current_expression_mentions_64bit_symbol_now ()) {
-    
-        int old_assignment64_stop_before_condition_operator;
-        is_unsigned = rhs_current_operand_is_unsigned_now ();
-        
-        old_assignment64_stop_before_condition_operator = assignment64_stop_before_condition_operator;
-        assignment64_stop_before_condition_operator = 1;
-        
-        emit_load_assignment_rhs_expression_to_pair ("eax", "edx", is_unsigned);
-        assignment64_stop_before_condition_operator = old_assignment64_stop_before_condition_operator;
-        
-        if (token_is_statement_compare_operator (tok.kind)) {
-        
-            op = tok.kind;
-            get_token ();
-            
-            if (rhs_current_operand_is_unsigned_now ()) {
-                is_unsigned = 1;
-            }
-            
-            if (state->ofp) {
-            
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                
-                    fprintf (state->ofp, "    push ebx\n");
-                    fprintf (state->ofp, "    push eax\n");
-                    fprintf (state->ofp, "    push edx\n");
-                
-                } else {
-                
-                    fprintf (state->ofp, "    pushl %%ebx\n");
-                    fprintf (state->ofp, "    pushl %%eax\n");
-                    fprintf (state->ofp, "    pushl %%edx\n");
-                
-                }
-            
-            }
-            
-            /*
-             * The stop-before-compare guard is only needed while loading the
-             * left hand side of the statement condition.  After the condition
-             * operator has been consumed, the right hand side must be parsed as
-             * a complete expression.  Keeping the guard enabled here makes a
-             * parenthesized conditional expression such as:
-             *
-             *     i < (len_fract == 0 ? 1 : precision - len_fract)
-             *
-             * stop at the nested == and leave the parser expecting the closing
-             * ')'.  That is what produced the false "expected )" diagnostic.
-             */
-            emit_load_assignment_rhs_expression_to_pair ("eax", "edx", is_unsigned);
-            
-            if (state->ofp) {
-            
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                
-                    fprintf (state->ofp, "    mov ebx, eax\n");
-                    fprintf (state->ofp, "    mov ecx, edx\n");
-                    fprintf (state->ofp, "    pop edx\n");
-                    fprintf (state->ofp, "    pop eax\n");
-                
-                } else {
-                
-                    fprintf (state->ofp, "    movl %%eax, %%ebx\n");
-                    fprintf (state->ofp, "    movl %%edx, %%ecx\n");
-                    fprintf (state->ofp, "    popl %%edx\n");
-                    fprintf (state->ofp, "    popl %%eax\n");
-                
-                }
-            
-            }
-            
-            emit_statement_cmp64_to_eax (op, is_unsigned);
-            
-            if (state->ofp) {
-            
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                    fprintf (state->ofp, "    pop ebx\n");
-                } else {
-                    fprintf (state->ofp, "    popl %%ebx\n");
-                }
-            
-            }
-            
-            emit_statement_test_eax_jump_if_false (label);
-            return;
-        
-        }
-        
-        if (tok.kind == TOK_LOGAND) {
-        
-            get_token ();
-            
-            emit_statement_test_pair_jump_if_false ("eax", "edx", label);
-            emit_statement_jump_if_false (label);
-            
-            return;
-        
-        }
-        
-        if (tok.kind == TOK_LOGOR) {
-        
-            int skip_label = anon_label++;
-            get_token ();
-            
-            emit_statement_test_pair_jump_if_true ("eax", "edx", skip_label);
-            emit_statement_jump_if_false (label);
-            emit_statement_label (skip_label);
-            
-            return;
-        
-        }
-        
-        emit_statement_test_pair_jump_if_false ("eax", "edx", label);
-        return;
-    
-    }
-    
-    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)) {
-    
-        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);
-
-}
-
-static int token_text_starts_void_cast_now (void) {
-
-    const char *p = tok.caret;
-    
-    if (!p || *p != '(') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    if (strncmp (p, "void", 4) != 0) {
-        return 0;
-    }
-    
-    p += 4;
-    
-    if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
-        return 0;
-    }
-    
-    while (*p == ' ' || *p == '\t') {
-        p++;
-    }
-    
-    return *p == ')';
-
-}
-
-static int parse_void_cast_discard_statement (void) {
-
-    if (tok.kind != TOK_LPAREN || !token_text_starts_void_cast_now ()) {
-        return 0;
-    }
-    
-    get_token ();
-    
-    expect (TOK_VOID, "void");
-    expect (TOK_RPAREN, ")");
-    
-    if (tok.kind != TOK_SEMI) {
-    
-        emit_load_assignment_rhs_expression_to_reg ("eax");
-        
-        if (tok.kind != TOK_SEMI) {
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        }
-    
-    }
-    
-    expect (TOK_SEMI, ";");
-    return 1;
-
-}
-
-static int token_text_looks_like_postfix_assignment_now (void) {
-
-    const char *p;
-    int saw_postfix;
-    int paren_depth;
-    int bracket_depth;
-    
-    if (tok.caret) {
-        p = tok.caret;
-    } else if (tok.start) {
-        p = tok.start;
-    } else {
-        return 0;
-    }
-    
-    saw_postfix = 0;
-    paren_depth = 0;
-    bracket_depth = 0;
-    
-    while (*p && *p != ';' && *p != '\n') {
-    
-        if (*p == '(') {
-        
-            /**
-             * A postfix/member expression followed by a top-level '(' is a
-             * function call through that member, not a postfix assignment.
-             * This pre-scan must reject it before the destructive postfix
-             * assignment parser consumes the tokens.
-             */
-            if (saw_postfix && paren_depth == 0 && bracket_depth == 0) {
-                return 0;
-            }
-            
-            paren_depth++;
-        
-        } else if (*p == ')') {
-            if (paren_depth > 0) paren_depth--;
-        } else if (*p == '[') {
-        
-            saw_postfix = 1;
-            bracket_depth++;
-        
-        } else if (*p == ']') {
-            if (bracket_depth > 0) bracket_depth--;
-        } else if (paren_depth == 0 && bracket_depth == 0 && *p == ',') {
-            return 0;
-        } else if (paren_depth == 0 && bracket_depth == 0 && *p == '.') {
-            saw_postfix = 1;
-        } else if (paren_depth == 0 && bracket_depth == 0 && *p == '-' && p[1] == '>') {
-        
-            saw_postfix = 1;
-            p++;
-        
-        } else if (paren_depth == 0 && bracket_depth == 0 && *p == '=') {
-        
-            if (p[1] == '=') {
-                return 0;
-            }
-            
-            return saw_postfix;
-        
-        }
-        
-        p++;
-    
-    }
-    
-    return 0;
-
-}
-
-static int source_starts_with_parenthesized_indirect_call_now (void) {
-
-    const char *p = tok.caret;
-    
-    int member_depth = 1;
-    int saw_member = 0;
-    int depth;
-    
-    if (!p || *p != '(') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (*p != '*') {
-        return 0;
-    }
-    
-    depth = 1;
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    /*
-     * Accept both
-     *
-     *     (*obj->member)(...)
-     *     (*(obj->member))(...)
-     *
-     * but keep this recognizer deliberately narrow.  It must not claim an
-     * arbitrary parenthesized expression, otherwise normal statement parsing
-     * and C labels can be pulled into this special call path.
-     */
-    if (*p == '(') {
-    
-        depth++;
-        
-        member_depth = 2;
-        p++;
-    
-    }
-    
-    while (*p && depth > 0) {
-    
-        if (*p == '(') {
-            depth++;
-        } else if (*p == ')') {
-        
-            depth--;
-            
-            if (depth == 0) {
-                break;
-            }
-        
-        } else if (depth == member_depth && *p == '-' && p[1] == '>') {
-        
-            saw_member = 1;
-            p++;
-        
-        } else if (depth == member_depth && *p == '.') {
-            saw_member = 1;
-        }
-        
-        p++;
-    
-    }
-    
-    if (depth != 0 || !saw_member) {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    return *p == '(';
-
-}
-
-static int parse_postfix_assignment_statement_now (void) {
-
-    char *name;
-    
-    struct local_symbol *src;
-    int global_index;
-    
-    enum token_kind assign_op;
-    int lvalue_size;
-    
-    if (tok.kind != TOK_IDENT || !token_text_looks_like_postfix_assignment_now ()) {
-        return 0;
-    }
-    
-    name = xstrdup (tok.ident);
-    
-    {
-    
-        const char *name_start = tok.start;
-        const char *name_caret = tok.caret;
-        
-        unsigned long name_line = get_line_number ();
-        get_token ();
-        
-        src = find_local_symbol (name);
-        global_index = find_global_symbol (name);
-        
-        if (!src && global_index < 0) {
-        
-            free (name);
-            return 0;
-        
-        }
-        
-        if (!emit_parse_postfix_copy_source_address_now ("edx", src, name, name_start, name_caret, name_line)) {
-        
-            free (name);
-            return 0;
-        
-        }
-    
-    }
-    
-    free (name);
-    
-    if (!is_assignment_operator (tok.kind)) {
-        return 0;
-    }
-    
-    assign_op = tok.kind;
-    lvalue_size = index_step_size (postfix_copy_lvalue_size);
-    
-    if (lvalue_size <= 0) {
-        lvalue_size = DATA_INT & 0x1f;
-    }
-    
-    get_token ();
-    
-    if (assign_op == TOK_ASSIGN) {
-    
-        if (postfix_member_is_floating || token_is_floating_constant_now () || rhs_current_operand_is_floating_now ()) {
-        
-            emit_push_reg_now ("edx");
-            emit_load_floating_rhs_expression_now (lvalue_size);
-            
-            emit_pop_reg_now ("edx");
-            emit_store_floating_member_to_addr_reg_now ("edx", 0, lvalue_size);
-            
-            return 1;
-        
-        }
-        
-        if (lvalue_size == (DATA_LLONG & 0x1f)) {
-        
-            emit_push_reg_now ("edx");
-            
-            emit_load_assignment_rhs_expression_to_pair ("eax", "edx", 1);
-            emit_pop_reg_now ("ecx");
-            
-            emit_store_pair_to_deref_reg_now ("ecx", "eax", "edx");
-            return 1;
-        
-        }
-        
-        if (lvalue_size > (DATA_LLONG & 0x1f)
-            && tok.kind == TOK_IDENT && tok.ident && token_identifier_is_function_call_rhs_now ()
-            && get_global_symbol_kind (tok.ident) == GLOBAL_SYMBOL_FUNCTION
-            && get_global_symbol_size (tok.ident) > (DATA_LLONG & 0x1f)) {
-        
-            char *rhs_name = xstrdup (tok.ident);
-            const char *rhs_start = tok.start;
-            const char *rhs_caret = tok.caret;
-            unsigned long rhs_line = get_line_number ();
-            
-            emit_push_reg_now ("edx");
-            
-            pending_struct_return_lhs = 0;
-            pending_struct_return_global_name = 0;
-            pending_struct_return_stack_address = 1;
-            pending_struct_return_stack_offset = 0;
-            
-            get_token ();
-            emit_call_identifier_to_reg_now (rhs_name, "eax", rhs_start, rhs_caret, rhs_line);
-            
-            pending_struct_return_stack_address = 0;
-            pending_struct_return_stack_offset = 0;
-            
-            emit_pop_reg_now ("edx");
-            
-            free (rhs_name);
-            return 1;
-        
-        }
-        
-        if (emit_aggregate_copy_from_current_rhs_to_addr_reg_now ("edx", 0, lvalue_size)) {
-            return 1;
-        }
-        
-        /**
-         * Keep the computed lvalue address across the RHS evaluation.
-         * The RHS emitter is free to use edx for indexing, calls, and
-         * arithmetic, so storing through edx after it can corrupt memory.
-         */
-        emit_push_reg_now ("edx");
-        
-        emit_load_assignment_rhs_expression_to_reg ("eax");
-        emit_pop_reg_now ("edx");
-
-    } else {
-    
-        emit_push_reg_now ("edx");
-        
-        emit_load_member_from_addr_reg_now ("eax", "edx", 0, lvalue_size);
-        emit_push_reg_now ("eax");
-        
-        emit_load_assignment_rhs_expression_to_reg ("edx");
-        emit_pop_reg_now ("eax");
-        
-        emit_assignment_binary_op (assign_op, 0);
-        emit_pop_reg_now ("edx");
-    
-    }
-    
-    emit_store_reg_to_deref_reg_now ("edx", "eax", lvalue_size);
-    return 1;
-
-}
-
-static int parse_parenthesized_member_function_pointer_call_statement (void) {
-
-    struct local_symbol *src;
-    char *name;
-    
-    int global_index;
-    int wrapped_member_expr = 0;
-    
-    const char *name_start;
-    const char *name_caret;
-    
-    unsigned long name_line;
-    int base_size = DATA_INT & 0x1f;
-    
-    const char *base_tag_name = 0;
-    
-    if (tok.kind != TOK_LPAREN || !source_starts_with_parenthesized_indirect_call_now ()) {
-        return 0;
-    }
-    
-    get_token ();
-    
-    if (tok.kind != TOK_STAR) {
-        return 0;
-    }
-    
-    get_token ();
-    
-    if (tok.kind == TOK_LPAREN) {
-    
-        wrapped_member_expr = 1;
-        get_token ();
-    
-    }
-    
-    if (tok.kind != TOK_IDENT || !tok.ident) {
-        return 0;
-    }
-    
-    name = xstrdup (tok.ident);
-    name_start = tok.start;
-    name_caret = tok.caret;
-    name_line = get_line_number ();
-    
-    get_token ();
-    
-    src = find_local_symbol (name);
-    global_index = find_global_symbol (name);
-    
-    if (!src && global_index < 0) {
-    
-        free (name);
-        return 0;
-    
-    }
-    
-    if (tok.kind == TOK_ARROW || tok.kind == TOK_LBRACK) {
-    
-        if (src) {
-        
-            base_size = src->pointer_depth > 0 ? src->pointed_size : src->size;
-            base_tag_name = src->pointer_depth > 0 ? src->pointed_tag_name : 0;
-        
-        } else {
-        
-            base_size = get_global_symbol_pointer_depth (name) > 0 ? get_global_symbol_pointed_size (name) : get_global_symbol_size (name);
-            base_tag_name = get_global_symbol_pointer_depth (name) > 0 ? get_global_symbol_tag_name (name) : 0;
-        
-        }
-    
-    } else if (tok.kind == TOK_DOT) {
-    
-        if (src) {
-        
-            base_size = src->size;
-            base_tag_name = src->tag_name;
-        
-        } else {
-        
-            base_size = get_global_symbol_size (name);
-            base_tag_name = get_global_symbol_tag_name (name);
-        
-        }
-    
-    } else {
-    
-        free (name);
-        return 0;
-    
-    }
-    
-    postfix_copy_lvalue_size = base_size;
-    postfix_copy_lvalue_tag_name = base_tag_name;
-    
-    if (!emit_parse_postfix_copy_source_address_now ("ecx", src, name, name_start, name_caret, name_line)) {
-    
-        free (name);
-        return 0;
-    
-    }
-    
-    free (name);
-    
-    if (wrapped_member_expr) {
-        expect (TOK_RPAREN, ")");
-    }
-    
-    expect (TOK_RPAREN, ")");
-    
-    if (tok.kind != TOK_LPAREN) {
-        return 0;
-    }
-    
-    emit_load_deref_reg_now ("ecx", DATA_PTR & 0x1f);
-    emit_call_pointer_in_reg_now ("ecx", "eax");
-    
-    expect_semi_or_recover ();
-    return 1;
-
-}
-
-static void parse_statement_suppressed (void) {
-
-    FILE *save_ofp = state->ofp;
-    
-    state->ofp = 0;
-    parse_statement ();
-    state->ofp = save_ofp;
-
-}
-
-static void parse_statement (void) {
-
-    statement_ends_control_flow = 0;
-    flush_pending_statement_labels ();
-    
-    if (parse_inline_asm_statement ()) {
-        return;
-    }
-    
-    if (parse_prefix_incdec_statement ()) {
-        return;
-    }
-    
-    if (parse_void_cast_discard_statement ()) {
-        return;
-    }
-    
-    
-    if (tok.kind == TOK_LPAREN && source_starts_lparen_deref_postfix_incdec_at (tok.caret)) {
-    
-        get_token ();
-        
-        if (emit_load_parenthesized_deref_postfix_incdec_subscript_to_reg_now ("eax")) {
-        
-            expect_semi_or_recover ();
-            return;
-        
-        }
-    
-    }
-    
-    if (parse_parenthesized_deref_subscript_statement ()) {
-    
-        expect_semi_or_recover ();
-        return;
-    
-    }
-    
-    if (parse_parenthesized_member_function_pointer_call_statement ()) {
-        return;
-    }
-    
-    if (tok.kind == TOK_LPAREN) {
-    
-        int parenthesized_assignment_is_unsigned;
-        
-        if (emit_load_parenthesized_assignment_expression_to_reg_now ("eax", &parenthesized_assignment_is_unsigned)) {
-        
-            expect_semi_or_recover ();
-            return;
-        
-        }
-    
-    }
-    
-    if (tok.kind == TOK_LPAREN && parse_parenthesized_indirect_member_assignment_statement ()) {
-        return;
-    }
-    
-    if (parse_indirect_assignment_statement ()) {
-        return;
-    }
-    
-    if (parse_postfix_assignment_statement_now ()) {
-    
-        expect_semi_or_recover ();
-        return;
-    
-    }
-    
-    if (parse_identifier_assignment_statement ()) {
-        return;
-    }
-    
-    if (tok.kind == TOK_RETURN) {
-    
-        int has_value = 0;
-        long v = 0;
-        
-        const char *ret_start = tok.start;
-        const char *ret_caret = tok.caret;
-        
-        int ret_line = get_line_number ();
-        
-        current_function_has_return_statement = 1;
-        get_token ();
-        
-        if (tok.kind != TOK_SEMI) {
-        
-            if (current_function_is_void) {
-            
-                FILE *saved_return_ofp = state->ofp;
-                state->ofp = 0;
-                
-                emit_load_assignment_rhs_expression_to_reg ("eax");
-                state->ofp = saved_return_ofp;
-            
-            } else if (current_function_is_floating) {
-            
-                if (state->ofp && pending_return_jump) {
-                    emit_pending_return_jump ();
-                }
-                
-                emit_load_floating_rhs_expression_now (current_function_return_size);
-            
-            } else {
-            
-                if (state->ofp && pending_return_jump) {
-                    emit_pending_return_jump ();
-                }
-                
-                if (state->ofp) {
-                
-                    if (current_function_returns_aggregate) {
-                    
-                        if (state->syntax & ASM_SYNTAX_INTEL) {
-                            fprintf (state->ofp, (state->syntax & ASM_SYNTAX_NASM ? "    mov edx, dword [ebp + 8]\n" : "    mov edx, dword ptr [ebp + 8]\n"));
-                        } else {
-                            fprintf (state->ofp, "    movl 8(%%ebp), %%edx\n");
-                        }
-                        
-                        if (!emit_aggregate_copy_from_current_rhs_to_addr_reg_now ("edx", 0, current_function_return_size)) {
-                            emit_load_assignment_rhs_expression_to_reg ("eax");
-                        }
-                    
-                    } else if (current_function_return_size == (DATA_LLONG & 0x1f)) {
-                        emit_load_assignment_rhs_expression_to_pair ("eax", "edx", current_function_return_is_unsigned);
-                    } else if (current_expression_mentions_64bit_symbol_now ()) {
-                        emit_load_assignment_rhs_expression_to_pair ("eax", "edx", current_function_return_is_unsigned);
-                    } else {
-                        emit_load_assignment_rhs_expression_to_reg ("eax");
-                    }
-                
-                } else {
-                    v = const_from_current_expr ();
-                }
-            
-            }
-            
-            has_value = 1;
-        
-        }
-        
-        if (current_function_is_void && has_value) {
-            report_line_at (get_filename (), ret_line, REPORT_WARNING, ret_start, ret_caret, "return with a value in void function");
-        } else if (!current_function_is_void && !has_value) {
-            report_line_at (get_filename (), ret_line, REPORT_WARNING, ret_start, ret_caret, "return with no value in non-void function");
-        }
-        
-        if (state->ofp) {
-        
-            if (pending_return_jump) {
-                emit_pending_return_jump ();
-            }
-            
-            if (!current_function_is_floating && !has_value) {
-            
-                if (state->syntax & ASM_SYNTAX_INTEL) {
-                
-                    fprintf (state->ofp, "    mov eax, %ld\n", v);
-                    
-                    if (current_function_return_size == (DATA_LLONG & 0x1f)) {
-                        fprintf (state->ofp, "    cdq\n");
-                    }
-                
-                } else {
-                
-                    fprintf (state->ofp, "    movl $%ld, %%eax\n", v);
-                    
-                    if (current_function_return_size == (DATA_LLONG & 0x1f)) {
-                        fprintf (state->ofp, "    cdq\n");
-                    }
-                
-                }
-            
-            }
-            
-            pending_return_jump = 1;
-            statement_ends_control_flow = 1;
-        
-        }
-        
-        expect (TOK_SEMI, ";");
-        return;
-    
-    }
-    
-    if (tok.kind == TOK_LBRACE) {
-    
-        parse_block ();
-        return;
-    
-    }
-    
-    if (tok.kind == TOK_IF) {
-    
-        int else_label = anon_label++;
-        int end_label = anon_label++;
-        
-        get_token ();
-        expect (TOK_LPAREN, "(");
-        
-        /*
-         * Compile the full if-condition as an expression before testing it.
-         * The older specialised condition emitter jumps to the false label as
-         * soon as the left side of a logical OR is false, which skips the RHS.
-         * That miscompiled expressions such as:
-         *
-         *     if ((base && !base->dword) || (index && ...))
-         *
-         * and made pdas reject valid 32-bit AT&T base/index operands.
-         */
-        emit_statement_jump_if_false (else_label);
-        
-        if (tok.kind != TOK_RPAREN) {
-            skip_balanced_until (TOK_RPAREN, TOK_EOF, TOK_EOF);
-        }
-        
-        expect (TOK_RPAREN, ")");
-        
-        if (statement_condition_constant_known) {
-        
-            if (statement_condition_constant_value) {
-            
-                parse_statement ();
-                
-                if (_accept (TOK_ELSE)) {
-                    parse_statement_suppressed ();
-                }
-            
-            } else {
-            
-                parse_statement_suppressed ();
-                
-                if (_accept (TOK_ELSE)) {
-                    parse_statement ();
-                }
-            
-            }
-            
-            return;
-        
-        }
-        
-        parse_statement ();
-        
-        {
-        
-            int then_ends_control_flow = statement_ends_control_flow;
-            
-            if (_accept (TOK_ELSE)) {
-            
-                if (pending_return_jump) {
-                
-                    emit_pending_return_jump ();
-                    then_ends_control_flow = 1;
-                
-                } else if (!then_ends_control_flow) {
-                    emit_statement_jump (end_label);
-                }
-                
-                emit_statement_label (else_label);
-                parse_statement ();
-                
-                if (pending_return_jump) {
-                
-                    emit_pending_return_jump ();
-                    statement_ends_control_flow = 1;
-                
-                }
-                
-                emit_statement_label (end_label);
-                statement_ends_control_flow = then_ends_control_flow && statement_ends_control_flow;
-            
-            } else {
-            
-                if (pending_return_jump) {
-                    emit_pending_return_jump ();
-                }
-                
-                emit_statement_label (else_label);
-                statement_ends_control_flow = 0;
-            
-            }
-        
-        }
-        
-        return;
-    
-    }
-    
-    if (tok.kind == TOK_SWITCH) {
-    
-        parse_switch_statement ();
-        return;
-    
-    }
-    
-    if (tok.kind == TOK_WHILE) {
-    
-        parse_while_statement ();
-        return;
-    
-    }
-    
-    if (tok.kind == TOK_DO) {
-    
-        parse_do_statement ();
-        return;
-    
-    }
-    
-    if (tok.kind == TOK_FOR) {
-    
-        parse_for_statement ();
-        return;
-    
-    }
-    
-    if (tok.kind == TOK_GOTO) {
-    
-        const char *label_start;
-        const char *label_caret;
-        
-        unsigned long label_line;
-        char *label_name = 0;
-        
-        get_token ();
-        
-        label_start = tok.start;
-        label_caret = tok.caret;
-        label_line = get_line_number ();
-        
-        if (tok.kind == TOK_IDENT) {
-        
-            label_name = xstrdup (tok.ident);
-            get_token ();
-            
-            /*
-             * Do not eagerly pop block-local temporary storage for a forward
-             * goto.  A label can legally be later in the same block after
-             * nested statements, and the earlier text scan was too
-             * conservative: it treated the first nested '}' as the end of the
-             * current block.  That produced an extra add to esp before
-             * `goto skip;` in i386_gen.c's process_bitfield_init(), corrupting
-             * the stack before the local label was reached.
-             */
-            
-            reference_goto_label (label_name, label_line, label_start, label_caret);
-            statement_ends_control_flow = 1;
-            
-            free (label_name);
-        
-        } else {
-            report_line_at (get_filename (), label_line, REPORT_ERROR, label_start, label_caret, "expected label name after goto");
-        }
-        
-        expect (TOK_SEMI, ";");
-        return;
-    
-    }
-    
-    if (tok.kind == TOK_BREAK) {
-    
-        int target_label = current_break_label;
-        
-        long cleanup_base = current_break_cleanup_base;
-        long cleanup_bytes;
-        
-        get_token ();
-        
-        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) {
-        
-            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_CASE) {
-    
-        long value;
-        unsigned long case_line = get_line_number ();
-        
-        const char *case_start = tok.start;
-        const char *case_caret = tok.caret;
-        
-        get_token ();
-        
-        value = const_from_current_case_expr ();
-        add_switch_case_label (value, case_line, case_start, case_caret);
-        
-        if (tok.kind != TOK_COLON) {
-            skip_balanced_until (TOK_COLON, TOK_EOF, TOK_EOF);
-        }
-        
-        expect (TOK_COLON, ":");
-        statement_ends_control_flow = 0;
-        
-        return;
-    
-    }
-    
-    if (tok.kind == TOK_DEFAULT) {
-    
-        unsigned long default_line = get_line_number ();
-        
-        const char *default_start = tok.start;
-        const char *default_caret = tok.caret;
-        
-        get_token ();
-        
-        set_switch_default_label (default_line, default_start, default_caret);
-        expect (TOK_COLON, ":");
-        
-        statement_ends_control_flow = 0;
-        return;
-    
-    }
-    
-    if (tok.kind != TOK_SEMI && tok.kind != TOK_RBRACE && tok.kind != TOK_EOF) {
-    
-        if (parse_postfix_assignment_statement_now ()) {
-        
-            if (tok.kind == TOK_SEMI) {
-            
-                get_token ();
-                return;
-            
-            }
-            
-            skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-            
-            expect (TOK_SEMI, ";");
-            return;
-        
-        }
-        
-        emit_load_assignment_rhs_expression_to_reg ("eax");
-        
-        if (tok.kind == TOK_SEMI) {
-        
-            get_token ();
-            return;
-        
-        }
-        
-        skip_balanced_until (TOK_SEMI, TOK_EOF, TOK_EOF);
-        
-        expect (TOK_SEMI, ";");
-        return;
-    
-    }
-    
-    expect (TOK_SEMI, ";");
-
-}
-
-static void parse_function_body (const char *name, int storage_class, int is_inline, int return_is_void, int return_is_floating, int return_is_unsigned, int return_size, unsigned long function_line, const char *function_start, const char *function_caret) {
-
-    int old_return_label = current_return_label;
-    int should_emit = 1;
-    int emit_body = 1;
-    int emit_public = 1;
-    int emit_inline_definition_to_output = 1;
-    
-    FILE *saved_ofp;
-    FILE *function_tmp = 0;
-    
-    char *inline_asm_text = 0;
-    char *function_asm_text = 0;
-    
-    int capture_inline_body = 0;
-    int capture_function_body = 0;
-    
-    int saved_declarator_function_param_count;
-    int saved_declarator_function_has_prototype;
-    int saved_declarator_function_is_variadic;
-    int saved_current_section = current_section;
-    
-    int old_function_is_void;
-    int old_function_is_floating;
-    int old_function_return_size;
-    int old_function_return_is_unsigned;
-    int old_function_returns_aggregate;
-    int old_function_has_return_statement;
-    
-    char *function_filename_copy = 0;
-    
-    /**
-     * Inline definitions are compiled into a temporary assembler buffer so
-     * calls in this translation unit can be expanded at the call site.
-     *
-     *   inline int f(...) { ... }
-     *   static inline int f(...) { ... }
-     *       Remember the generated body for inline expansion.  Do not emit an
-     *       out-of-line copy unless a later rule explicitly asks for one.
-     *
-     *   extern inline int f(...) { ... }
-     *       Remember the generated body and also emit the normal public
-     *       definition.
-     *
-     *   int f(...) { ... }
-     *       Normal external definition.  Emit it as public.
-     */
-    if (storage_class == STORAGE_STATIC) {
-        emit_public = 0;
-    } else if (is_inline && storage_class != STORAGE_EXTERN) {
-        emit_public = 0;
-    }
-    
-    if (is_inline && storage_class != STORAGE_EXTERN && !return_is_floating) {
-        emit_inline_definition_to_output = 0;
-    }
-    
-    saved_ofp = state->ofp;
-    
-    saved_declarator_function_param_count = declarator_function_param_count;
-    saved_declarator_function_has_prototype = declarator_function_has_prototype;
-    saved_declarator_function_is_variadic = declarator_function_is_variadic;
-    
-    if (get_filename ()) {
-        function_filename_copy = xstrdup (get_filename ());
-    }
-    
-    capture_inline_body = is_inline && saved_ofp != 0;
-    capture_function_body = saved_ofp != 0;
-    
-    if (capture_function_body) {
-    
-        function_tmp = scc_tmpfile ();
-        
-        if (!function_tmp) {
-            capture_function_body = 0;
-        }
-    
-    }
-    
-    if (emit_body) {
-    
-        if (parsed_dllimport) {
-            report_line_at (get_filename (), last_declarator_name_line, REPORT_ERROR, last_declarator_name_start, last_declarator_name_caret, "function '%s' cannot be defined with '__dllimport'", name);
-        }
-        
-        should_emit = add_global_symbol (name, GLOBAL_SYMBOL_FUNCTION, 0, last_declarator_name_start, last_declarator_name_caret, last_declarator_name_line);
-        
-        set_global_symbol_size (name, return_is_void ? DATA_VOID : return_size);
-        set_global_symbol_unsigned (name, 0);
-        set_global_symbol_floating (name, return_is_floating);
-        set_global_symbol_returns_void (name, return_is_void);
-        set_global_symbol_calling_convention (name, (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention);
-        set_global_symbol_dllimport (name, 0);
-        set_global_symbol_param_count (name, saved_declarator_function_param_count, saved_declarator_function_has_prototype || saved_declarator_function_param_count > 0, saved_declarator_function_is_variadic);
-        
-        if (is_inline) {
-        
-            remember_inline_function_signature (name, saved_declarator_function_param_count, saved_declarator_function_has_prototype || saved_declarator_function_param_count > 0,
-                return_is_void, return_is_floating, return_size);
-        
-        }
-    
-    }
-    
-    old_function_has_return_statement = current_function_has_return_statement;
-    old_function_is_void = current_function_is_void;
-    old_function_is_floating = current_function_is_floating;
-    old_function_return_size = current_function_return_size;
-    old_function_return_is_unsigned = current_function_return_is_unsigned;
-    old_function_returns_aggregate = current_function_returns_aggregate;
-    
-    current_function_is_void = return_is_void;
-    current_function_is_floating = return_is_floating;
-    current_function_return_is_unsigned = return_is_unsigned;
-    current_function_return_size = return_size;
-    current_function_returns_aggregate = (!return_is_void && !return_is_floating && return_size > (DATA_LLONG & 0x1f));
-    current_function_calling_convention = (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention;
-    current_function_param_stack_bytes = 0;
-    current_function_has_return_statement = 0;
-    
-    parse_old_style_param_decls ();
-    remove_duplicate_pending_params ();
-    
-    /*
-     * Old-style definitions start with an identifier list, so the first
-     * function-symbol install only knows the default int-sized parameter
-     * placeholders.  The declaration list between ')' and '{' is what gives
-     * those parameters their real types.  Refresh the saved call signature
-     * after that list has been parsed, otherwise later calls in the same
-     * translation unit pass 64-bit parameters as single words.
-     */
-    if (emit_body && should_emit) {
-        copy_pending_params_to_global_symbol (name);
-    }
-    
-    current_function_param_stack_bytes = global_symbol_stdcall_stack_bytes (name);
-    
-    reset_local_symbols ();
-    reset_goto_labels ();
-    
-    install_pending_params_as_locals ();
-    clear_pending_params ();
-    
-    if (!emit_body || !should_emit) {
-        state->ofp = 0;
-    } else if (capture_function_body) {
-        state->ofp = function_tmp;
-    }
-    
-    current_return_label = anon_label++;
-    pending_return_jump = 0;
-    current_function_preserve_assignment64_regs = 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 ();
-    check_goto_labels ();
-    
-    if (!current_function_is_void && !current_function_has_return_statement) {
-        report_line_at (function_filename_copy ? function_filename_copy : get_filename (), function_line, REPORT_WARNING, function_start, function_caret, "control reaches end of non-void function");
-    }
-    
-    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_function_body && function_tmp) {
-    
-        function_asm_text = read_tmp_file_text (function_tmp);
-        
-        if (function_asm_text) {
-        
-            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);
-            }
-            
-            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);
-            
-            }
-        
-        }
-        
-        if (function_asm_text) {
-            free (function_asm_text);
-        }
-        
-        if (inline_asm_text) {
-        
-            free (inline_asm_text);
-            inline_asm_text = 0;
-        
-        }
-        
-        scc_close (function_tmp);
-        function_tmp = 0;
-    
-    }
-    
-    reset_local_symbols ();
-    reset_goto_labels ();
-    
-    current_function_has_return_statement = old_function_has_return_statement;
-    current_function_is_void = old_function_is_void;
-    current_function_is_floating = old_function_is_floating;
-    current_function_return_size = old_function_return_size;
-    current_function_return_is_unsigned = old_function_return_is_unsigned;
-    current_function_returns_aggregate = old_function_returns_aggregate;
-    
-    current_return_label = old_return_label;
-    state->ofp = saved_ofp;
-    
-    if (capture_inline_body) {
-        current_section = saved_current_section;
-    }
-    
-    if (function_filename_copy) {
-        free (function_filename_copy);
-    }
-    
-    if (inline_asm_text) {
-        free (inline_asm_text);
-    }
-
-}
-
-static int parse_possible_knr_function (void) {
-
-    char *name;
-    
-    const char *name_start;
-    const char *name_caret;
-    
-    unsigned long name_line;
-    
-    if (!token_is_ident ()) {
-        return 0;
-    }
-    
-    name_line = get_line_number ();
-    
-    name_start = tok.start;
-    name_caret = tok.caret;
-    
-    name = take_ident ();
-    
-    if (!_accept (TOK_LPAREN)) {
-    
-        free (name);
-        return 0;
-    
-    }
-    
-    clear_pending_params ();
-    
-    declarator_function_param_count = 0;
-    declarator_function_has_prototype = 0;
-    declarator_function_is_variadic = 0;
-    
-    if (tok.kind != TOK_RPAREN) {
-    
-        int old_style_param_start = pending_param_count;
-        
-        for (;;) {
-       
-            if (tok.kind == TOK_ELLIPSIS) {
-            
-                declarator_function_is_variadic = 1;
-                declarator_function_has_prototype = 1;
-                
-                get_token ();
-            
-            } else if (is_type_start (tok.kind)) {
-            
-                int param_base_size;
-                int param_size;
-                int param_pointer_depth;
-                int saved_function_param_count;
-                
-                int count_this_param = 0;
-                int saw_void_param_list = 0;
-                
-                char *param_name = 0;
-                
-                parse_type_spec ();
-                param_base_size = parsed_type_size;
-                
-                preserve_pending_params++;
-                
-                declarator_is_pointer = 0;
-                declarator_pointer_depth = 0;
-                declarator_has_array = 0;
-                declarator_has_function = 0;
-                declarator_function_is_pointer = 0;
-                declarator_array_unsized = 0;
-                declarator_array_count = 1;
-                declarator_last_array_count = 1;
-                
-                if (parsed_type_only_qualifiers && token_is_ident ()) {
-                    get_token ();
-                }
-                
-                saved_function_param_count = declarator_function_param_count;
-                
-                if (tok.kind != TOK_COMMA && tok.kind != TOK_RPAREN) {
-                    parse_declarator (&param_name);
-                }
-                
-                preserve_pending_params--;
-                
-                if (!parsed_type_is_void || declarator_is_pointer || declarator_has_array || declarator_has_function || param_name) {
-                
-                    count_this_param = 1;
-                    
-                    param_size = (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef) ? DATA_PTR : declarator_object_size (param_base_size);
-                    param_pointer_depth = declarator_pointer_depth;
-                    
-                    if ((declarator_has_array || declarator_has_function || parsed_type_is_array_typedef) && param_pointer_depth < 1) {
-                        param_pointer_depth = 1;
-                    }
-                    
-                    if (param_name && find_pending_param_from (param_name, old_style_param_start) >= 0) {
-                        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate parameter '%s'", param_name);
-                    } else {
-                    
-                        add_pending_param (param_name, param_size, type_alignment (param_size),
-                            (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef ? 0 : parsed_type_is_unsigned),
-                                (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef ? 0 : parsed_type_is_floating),
-                                    param_pointer_depth, parsed_type_is_aggregate ? parsed_type_size : (parsed_type_size & 0x1f), parsed_type_is_unsigned);
-                    
-                    }
-                
-                } else {
-                    saw_void_param_list = 1;
-                }
-                
-                if (param_name) {
-                    free (param_name);
-                }
-                
-                declarator_function_param_count = saved_function_param_count + (count_this_param ? 1 : 0);
-                declarator_function_has_prototype = declarator_function_has_prototype || count_this_param || saw_void_param_list;
-            
-            } else if (token_is_ident ()) {
-            
-                if (find_pending_param_from (tok.ident, old_style_param_start) >= 0) {
-                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate parameter '%s'", tok.ident);
-                } else {
-                
-                    add_pending_param (tok.ident, DATA_INT & 0x1f, type_alignment (DATA_INT & 0x1f), 0, 0, 0, 0, 0);
-                    declarator_function_param_count++;
-                
-                }
-                
-                get_token ();
-            
-            } else {
-                skip_balanced_until (TOK_COMMA, TOK_RPAREN, TOK_EOF);
-            }
-            
-            if (!_accept (TOK_COMMA)) {
-                break;
-            }
-        
-        }
-    
-    }
-    
-    expect (TOK_RPAREN, ")");
-    
-    if (is_type_start (tok.kind) || tok.kind == TOK_LBRACE) {
-    
-        parse_function_body (name, STORAGE_NONE, 0, 0, 0, 0, DATA_INT & 0x1f, name_line, name_start, name_caret);
-        
-        if (parsed_dllexport || declarator_dllexport) {
-        
-            vec_push (&vec_dllexports, xstrdup (name));
-            
-            declarator_dllexport = 0;
-            parsed_dllexport = 0;
-        
-        }
-        
-        free (name);
-        return 1;
-    
-    }
-    
-    free (name);
-    return 0;
-
-}
-
-static int is_string_token (void) {
-    return tok.kind == TOK_PPSTR || tok.kind == TOK_LSTR;
-}
-
-static void append_global_init_value (int64_s *values, int max_values, int *count, unsigned int value, int elem_size) {
-
-    unsigned int mask = 0xffU;
-    
-    if (elem_size == (DATA_SHORT & 0x1f)) {
-        mask = 0xffffU;
-    }
-    
-    if (*count < max_values) {
-        zext64 (&values[*count], value & mask);
-    }
-    
-    (*count)++;
-
-}
-
-static int parsed_string_initializer_elem_size = DATA_CHAR & 0x1f;
-
-static void append_global_init_byte (int64_s *values, int max_values, int *count, unsigned int value) {
-    append_global_init_value (values, max_values, count, value, DATA_CHAR & 0x1f);
-}
-
-static int parse_octal_escape_value (const char **ps) {
-
-    const char *s = *ps;
-    int value = 0, i;
-    
-    for (i = 0; i < 3; i++) {
-    
-        if (*s < '0' || *s > '7') {
-            break;
-        }
-        
-        value = value * 8 + (*s - '0');
-        s++;
-    
-    }
-    
-    *ps = s;
-    return value;
-
-}
-
-static int parse_hex_escape_value (const char **ps) {
-
-    const char *s = *ps;
-    
-    int value = 0;
-    int any = 0;
-    
-    while ((*s >= '0' && *s <= '9') || (*s >= 'a' && *s <= 'f') || (*s >= 'A' && *s <= 'F')) {
-    
-        int digit;
-        
-        if (*s >= '0' && *s <= '9') {
-            digit = *s - '0';
-        } else if (*s >= 'a' && *s <= 'f') {
-            digit = *s - 'a' + 10;
-        } else {
-            digit = *s - 'A' + 10;
-        }
-        
-        value = (value << 4) + digit;
-        any = 1;
-        
-        s++;
-    
-    }
-    
-    if (!any) {
-        value = 'x';
-    }
-    
-    *ps = s;
-    return value;
-
-}
-
-static void parse_string_initializer_values (int64_s *values, int max_values, int *count) {
-
-    int elem_size = DATA_CHAR & 0x1f;
+void parse_string_initializer_values (int64_s *values, int max_values, int *count) {
+
+    int elem_size = DATA_CHAR & 0x1f;
     
     while (is_string_token ()) {
     
@@ -37529,1533 +1384,1916 @@ static void parse_string_initializer_values (int64_s *values, int max_values, in
                     
                     default:
                     
-                        ch = (unsigned char) *s;
-                        
-                        if (*s) {
-                            s++;
-                        }
-                        
+                        ch = (unsigned char) *s;
+                        
+                        if (*s) {
+                            s++;
+                        }
+                        
+                        break;
+                
+                }
+            
+            } else {
+                ch = (unsigned char) *s++;
+            }
+            
+            append_global_init_value (values, max_values, count, ch, elem_size);
+        
+        }
+        
+        get_token ();
+    
+    }
+    
+    append_global_init_value (values, max_values, count, 0, elem_size);
+    parsed_string_initializer_elem_size = elem_size;
+
+}
+
+int parse_sizeof_value (void) {
+
+    int saved_type_size = parsed_type_size;
+    int saved_storage_class = parsed_storage_class;
+    int saved_is_aggregate = parsed_type_is_aggregate;
+    int saved_is_void = parsed_type_is_void;
+    int saved_is_unsigned = parsed_type_is_unsigned;
+    int saved_is_floating = parsed_type_is_floating;
+    int saved_has_tag = parsed_type_has_tag;
+    int saved_is_inline = parsed_type_is_inline;
+    int saved_field_count = parsed_field_count;
+    int saved_fields[MAX_AGG_FIELDS];
+    
+    int saved_declarator_is_pointer = declarator_is_pointer;
+    int saved_declarator_has_array = declarator_has_array;
+    int saved_declarator_has_function = declarator_has_function;
+    int saved_declarator_array_unsized = declarator_array_unsized;
+    int saved_declarator_array_dimensions = declarator_array_dimensions;
+    
+    long saved_declarator_array_count = declarator_array_count;
+    long saved_declarator_first_array_count = declarator_first_array_count;
+    
+    int size = DATA_INT & 0x1f, i;
+    
+    for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
+        saved_fields[i] = parsed_field_sizes[i];
+    }
+    
+    if (_accept (TOK_LPAREN)) {
+    
+        if (is_type_start (tok.kind)) {
+        
+            char *name = 0;
+            int base_size;
+            
+            parse_type_spec ();
+            base_size = parsed_type_size;
+            
+            /*
+             * sizeof(type-name) may not contain a declarator, for example
+             * sizeof(FILE).  parse_declarator() normally clears these flags,
+             * but when the next token is ')' it is not called.  Do not let a
+             * previous declaration such as FILE **__gtin(void) make this
+             * type-name look like a pointer and collapse the size to 4.
+             */
+            declarator_is_pointer = 0;
+            declarator_pointer_depth = 0;
+            declarator_has_array = 0;
+            declarator_has_function = 0;
+            declarator_function_is_pointer = 0;
+            declarator_function_param_count = 0;
+            declarator_function_has_prototype = 0;
+            declarator_function_is_variadic = 0;
+            declarator_array_unsized = 0;
+            declarator_array_count = 1;
+            declarator_first_array_count = 1;
+            declarator_last_array_count = 1;
+            
+            if (tok.kind != TOK_RPAREN) {
+                parse_declarator (&name);
+            }
+            
+            size = declarator_object_size (base_size);
+            
+            if (name) {
+                free (name);
+            }
+            
+            expect (TOK_RPAREN, ")");
+        
+        } else if (is_string_token ()) {
+        
+            int64_s values[MAX_STRING_INIT_BYTES];
+            int value_count = 0;
+            
+            parse_string_initializer_values (values, MAX_STRING_INIT_BYTES, &value_count);
+            size = value_count;
+            expect (TOK_RPAREN, ")");
+        
+        } else {
+        
+            int depth = 1;
+            int first = 1;
+            int leading_stars = 0;
+            
+            while (tok.kind != TOK_EOF && depth > 0) {
+            
+                if (first) {
+                
+                    while (tok.kind == TOK_STAR || tok.kind == TOK_AMPER || tok.kind == TOK_PLUS || tok.kind == TOK_MINUS) {
+                    
+                        if (tok.kind == TOK_STAR) {
+                            leading_stars++;
+                        }
+                        
+                        get_token ();
+                    
+                    }
+                
+                }
+                
+                if (first && tok.kind == TOK_IDENT) {
+                
+                    parse_sizeof_member_expr_size (leading_stars, &size);
+                    
+                    first = 0;
+                    continue;
+                
+                }
+                
+                if (first && tok.kind == TOK_LPAREN && leading_stars > 0) {
+                
+                    get_token ();
+                    
+                    if (tok.kind == TOK_IDENT) {
+                        parse_sizeof_member_expr_size (leading_stars, &size);
+                    }
+                    
+                    while (tok.kind != TOK_EOF && tok.kind != TOK_RPAREN) {
+                        get_token ();
+                    }
+                    
+                    if (tok.kind == TOK_RPAREN) {
+                        get_token ();
+                    }
+                    
+                    first = 0;
+                    continue;
+                
+                }
+                
+                first = 0;
+                
+                if (tok.kind == TOK_LPAREN) {
+                    depth++;
+                } else if (tok.kind == TOK_RPAREN) {
+                
+                    depth--;
+                    
+                    if (depth == 0) {
+                        break;
+                    }
+                
+                }
+                
+                get_token ();
+            
+            }
+            
+            expect (TOK_RPAREN, ")");
+        
+        }
+    
+    } else {
+    
+        int leading_stars = 0;
+        
+        while (tok.kind == TOK_STAR || tok.kind == TOK_AMPER || tok.kind == TOK_PLUS || tok.kind == TOK_MINUS) {
+        
+            if (tok.kind == TOK_STAR) {
+                leading_stars++;
+            }
+            
+            get_token ();
+        
+        }
+        
+        if (is_string_token ()) {
+        
+            int64_s values[MAX_STRING_INIT_BYTES];
+            int value_count = 0;
+            
+            parse_string_initializer_values (values, MAX_STRING_INIT_BYTES, &value_count);
+            size = value_count;
+        
+        } else if (tok.kind == TOK_IDENT) {
+            parse_sizeof_member_expr_size (leading_stars, &size);
+        } else if (tok.kind == TOK_LPAREN) {
+        
+            int depth = 1;
+            
+            get_token ();
+            
+            while (tok.kind != TOK_EOF && depth > 0) {
+            
+                if (tok.kind == TOK_LPAREN) {
+                    depth++;
+                } else if (tok.kind == TOK_RPAREN) {
+                
+                    depth--;
+                    
+                    if (depth == 0) {
+                        break;
+                    }
+                
+                }
+                
+                get_token ();
+            
+            }
+            
+            expect (TOK_RPAREN, ")");
+        
+        } else if (tok.kind != TOK_EOF) {
+            get_token ();
+        }
+        
+        while (tok.kind == TOK_LBRACK || tok.kind == TOK_LPAREN) {
+        
+            enum token_kind close = (tok.kind == TOK_LBRACK) ? TOK_RBRACK : TOK_RPAREN;
+            int depth = 1;
+            
+            get_token ();
+            
+            while (tok.kind != TOK_EOF && depth > 0) {
+            
+                if ((close == TOK_RBRACK && tok.kind == TOK_LBRACK) || (close == TOK_RPAREN && tok.kind == TOK_LPAREN)) {
+                    depth++;
+                } else if (tok.kind == close) {
+                
+                    depth--;
+                    
+                    if (depth == 0) {
                         break;
+                    }
                 
                 }
+                
+                get_token ();
             
-            } else {
-                ch = (unsigned char) *s++;
             }
             
-            append_global_init_value (values, max_values, count, ch, elem_size);
+            expect (close, (close == TOK_RBRACK) ? "]" : ")");
         
         }
-        
-        get_token ();
     
     }
     
-    append_global_init_value (values, max_values, count, 0, elem_size);
-    parsed_string_initializer_elem_size = elem_size;
+    parsed_type_size = saved_type_size;
+    parsed_storage_class = saved_storage_class;
+    parsed_type_is_aggregate = saved_is_aggregate;
+    parsed_type_is_void = saved_is_void;
+    parsed_type_is_unsigned = saved_is_unsigned;
+    parsed_type_is_floating = saved_is_floating;
+    parsed_type_has_tag = saved_has_tag;
+    parsed_type_is_inline = saved_is_inline;
+    
+    clear_parsed_fields ();
+    
+    for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
+        append_parsed_field (saved_fields[i]);
+    }
+    
+    declarator_is_pointer = saved_declarator_is_pointer;
+    declarator_has_array = saved_declarator_has_array;
+    declarator_has_function = saved_declarator_has_function;
+    declarator_array_unsized = saved_declarator_array_unsized;
+    declarator_array_count = saved_declarator_array_count;
+    declarator_first_array_count = saved_declarator_first_array_count;
+    declarator_array_dimensions = saved_declarator_array_dimensions;
+    
+    if (size < 1) {
+        size = DATA_INT & 0x1f;
+    }
+    
+    return size;
 
 }
 
-static void parse_char_array_initializer_values (int64_s *values, int max_values, int *count, long row_width) {
+int parse_constexpr_address_of_null_member (int64_s *out) {
 
-    if (tok.kind == TOK_LBRACE) {
+    if (tok.kind != TOK_AMPER) {
+        return 0;
+    }
     
-        get_token ();
-        
-        while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
+    get_token ();
+    
+    if (tok.kind != TOK_LPAREN) {
+        return 0;
+    }
+    
+    get_token ();
+    
+    if (parse_constexpr_null_member_address_after_lparen (out)) {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+int token_is_sizeof_keyword (void) {
+    return tok.kind == TOK_SIZEOF;
+}
+
+int token_is_ms_int_type_name (void) {
+
+    if (tok.kind != TOK_IDENT || !tok.ident) {
+        return 0;
+    }
+    
+    return  strcmp (tok.ident, "__int8") == 0 || strcmp (tok.ident, "__int16") == 0 ||
+                strcmp (tok.ident, "__int32") == 0 || strcmp (tok.ident, "__int64") == 0;
+
+}
+
+int is_type_start (enum token_kind k) {
+
+    switch (k) {
+    
+        case TOK_IDENT:
         
-            parse_char_array_initializer_values (values, max_values, count, row_width);
+            if (token_is_ms_int_type_name ()) {
+                return 1;
+            }
             
-            if (!_accept (TOK_COMMA)) {
-                break;
+            if (is_current_typedef_name ()) {
+                return 1;
             }
+            
+            return 0;
         
-        }
+        case TOK_AUTO:          case TOK_REGISTER:      case TOK_STATIC:
+        case TOK_DLLEXPORT:     case TOK_DLLIMPORT:
+        case TOK_EXTERN:        case TOK_TYPEDEF:       case TOK_INLINE:
+        case TOK_CONST:         case TOK_VOLATILE:      case TOK_RESTRICT:
+        case TOK_SIGNED:        case TOK_UNSIGNED:
+        case TOK_SHORT:         case TOK_LONG:
+        case TOK_CHAR:          case TOK_INT:           case TOK_VOID:
+        case TOK_FLOAT:         case TOK_DOUBLE:
+        case TOK_STRUCT:        case TOK_UNION:         case TOK_ENUM:
         
-        expect (TOK_RBRACE, "}");
-        return;
+            return 1;
+        
+        default:
+        
+            break;
+    
+    }
+    
+    return 0;
+
+}
+
+int token_starts_type_name (void) {
+    return is_type_start (tok.kind);
+}
+
+int parse_cast_type_name (int *out_size, int *out_is_unsigned, int *out_is_pointer) {
+
+    int saved_type_size = parsed_type_size;
+    int saved_storage_class = parsed_storage_class;
+    int saved_is_aggregate = parsed_type_is_aggregate;
+    int saved_is_void = parsed_type_is_void;
+    int saved_is_unsigned = parsed_type_is_unsigned;
+    int saved_is_floating = parsed_type_is_floating;
+    int saved_has_tag = parsed_type_has_tag;
+    int saved_is_inline = parsed_type_is_inline;
+    int saved_field_count = parsed_field_count;
+    int saved_fields[MAX_AGG_FIELDS];
+    
+    int saved_declarator_is_pointer = declarator_is_pointer;
+    int saved_declarator_has_array = declarator_has_array;
+    int saved_declarator_has_function = declarator_has_function;
+    int saved_declarator_array_unsized = declarator_array_unsized;
+    int saved_declarator_array_dimensions = declarator_array_dimensions;
+    
+    long saved_declarator_array_count = declarator_array_count;
+    long saved_declarator_first_array_count = declarator_first_array_count;
+    
+    char *name = 0;
+    int size = DATA_INT & 0x1f;
+    int is_unsigned = 0;
+    int is_pointer = 0;
+    int ok = 0;
+    int i;
     
+    for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
+        saved_fields[i] = parsed_field_sizes[i];
     }
     
-    if (is_string_token ()) {
+    if (is_type_start (tok.kind)) {
     
-        int64_s tmp[MAX_STRING_INIT_BYTES];
-        int tmp_count = 0;
+        declarator_is_pointer = 0;
+        declarator_pointer_depth = 0;
+        declarator_has_array = 0;
+        declarator_has_function = 0;
+        declarator_array_unsized = 0;
+        declarator_array_count = 0;
         
-        int i;
-        int n;
+        parse_type_spec ();
         
-        parse_string_initializer_values (tmp, MAX_STRING_INIT_BYTES, &tmp_count);
+        size = parsed_type_size & 0x1f;
+        is_unsigned = parsed_type_is_unsigned;
         
-        if (row_width <= 0) {
-            n = tmp_count;
-        } else {
-            n = (tmp_count < row_width) ? tmp_count : (int) row_width;
+        if (tok.kind != TOK_RPAREN) {
+            parse_declarator (&name);
         }
         
-        for (i = 0; i < n; i++) {
-            append_global_init_byte (values, max_values, count, (unsigned int) (tmp[i].low & 0xff));
+        if (declarator_is_pointer) {
+        
+            size = DATA_PTR;
+            
+            is_unsigned = 1;
+            is_pointer = 1;
+        
         }
         
-        while (row_width > 0 && i < row_width) {
+        if (tok.kind == TOK_RPAREN) {
         
-            append_global_init_byte (values, max_values, count, 0);
-            i++;
+            get_token ();
+            ok = 1;
         
+        } else {
+            expect (TOK_RPAREN, ")");
         }
         
-        return;
+        if (name) {
+            free (name);
+        }
     
     }
     
-    if (tok.kind != TOK_COMMA && tok.kind != TOK_SEMI && tok.kind != TOK_RBRACE && tok.kind != TOK_EOF) {
+    last_cast_type_tag_name[0] = '\0';
+    last_cast_type_object_size = parsed_type_size & 0x1f;
+    last_cast_type_is_floating = (is_pointer ? 0 : parsed_type_is_floating);
     
-        if (*count < max_values) {
-            values[*count] = const64_from_current_expr ();
-        } else {
-            const64_from_current_expr ();
-        }
-        
-        (*count)++;
+    if (parsed_type_tag_name[0]) {
+    
+        strncpy (last_cast_type_tag_name, parsed_type_tag_name, sizeof (last_cast_type_tag_name) - 1);
+        last_cast_type_tag_name[sizeof (last_cast_type_tag_name) - 1] = '\0';
+    
+    }
+    
+    if (parsed_type_is_aggregate && parsed_type_size > 0) {
+        last_cast_type_object_size = parsed_type_size;
+    }
+    
+    parsed_type_size = saved_type_size;
+    parsed_storage_class = saved_storage_class;
+    parsed_type_is_aggregate = saved_is_aggregate;
+    parsed_type_is_void = saved_is_void;
+    parsed_type_is_unsigned = saved_is_unsigned;
+    parsed_type_is_floating = saved_is_floating;
+    parsed_type_has_tag = saved_has_tag;
+    parsed_type_is_inline = saved_is_inline;
+    
+    clear_parsed_fields ();
+    
+    for (i = 0; i < saved_field_count && i < MAX_AGG_FIELDS; i++) {
+        parsed_field_sizes[i] = saved_fields[i];
+    }
+    
+    parsed_field_count = saved_field_count;
+    
+    declarator_is_pointer = saved_declarator_is_pointer;
+    declarator_has_array = saved_declarator_has_array;
+    declarator_has_function = saved_declarator_has_function;
+    declarator_array_unsized = saved_declarator_array_unsized;
+    declarator_array_count = saved_declarator_array_count;
+    declarator_first_array_count = saved_declarator_first_array_count;
+    declarator_array_dimensions = saved_declarator_array_dimensions;
+    
+    if (out_size) {
+        *out_size = size;
+    }
+    
+    if (out_is_unsigned) {
+        *out_is_unsigned = is_unsigned;
+    }
+    
+    if (out_is_pointer) {
+        *out_is_pointer = is_pointer;
+    }
+    
+    return ok;
+
+}
+
+int resolve_enum_constant (const char *name, int64_s *out) {
+
+    struct enum_const_entry *entry = find_enum_constant (name);
+    
+    if (!entry) {
+        return 0;
+    }
     
+    if (out) {
+        *out = entry->value;
     }
+    
+    return 1;
 
 }
 
-static int global_initializer_parenthesized_string_now (void) {
+struct local_symbol local_symbols[MAX_LOCAL_SYMBOLS];
+int local_symbol_count = 0;
+
+struct local_symbol *find_local_symbol (const char *name) {
 
-    const char *p = tok.caret;
+    int i;
     
-    if (!p || *p != '(') {
+    if (!name) {
         return 0;
     }
     
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
-    
-    if (*p == '"') {
-        return 1;
-    }
+    for (i = local_symbol_count - 1; i >= 0; i--) {
     
-    if ((*p == 'L' || *p == 'u' || *p == 'U') && p[1] == '"') {
-        return 1;
-    }
+        if (local_symbols[i].name && strcmp (local_symbols[i].name, name) == 0) {
+            return &local_symbols[i];
+        }
     
-    if (*p == 'u' && p[1] == '8' && p[2] == '"') {
-        return 1;
     }
     
     return 0;
 
 }
 
-static int global_initializer_cast_before_string_now (void) {
+struct global_symbol_entry global_symbols[MAX_GLOBAL_SYMBOLS];
+int global_symbol_count = 0;
 
-    const char *p = tok.caret;
-    int depth;
-    
-    if (!p || *p != '(') {
-        return 0;
-    }
-    
-    p++;
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
+int find_global_symbol (const char *name) {
+
+    int i;
     
-    if (!(ident_start_now ((unsigned char) *p))) {
-        return 0;
+    if (!name) {
+        return -1;
     }
     
-    depth = 1;
-    
-    while (*p && depth > 0) {
+    for (i = 0; i < global_symbol_count; i++) {
     
-        if (*p == '(') {
-            depth++;
-        } else if (*p == ')') {
-            depth--;
+        if (strcmp (global_symbols[i].name, name) == 0) {
+            return i;
         }
-        
-        p++;
     
     }
     
-    if (depth != 0) {
-        return 0;
-    }
-    
-    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-        p++;
-    }
+    return -1;
+
+}
+
+int get_global_symbol_size (const char *name) {
+
+    int i = find_global_symbol (name);
     
-    if (*p == '"') {
-        return 1;
+    if (i >= 0 && global_symbols[i].size > 0) {
+        return global_symbols[i].size;
     }
     
-    if ((*p == 'L' || *p == 'u' || *p == 'U') && p[1] == '"') {
-        return 1;
-    }
+    return DATA_INT & 0x1f;
+
+}
+
+int get_global_symbol_param_pointer_depth (const char *name, int param_index) {
+
+    int i = find_global_symbol (name);
     
-    if (*p == 'u' && p[1] == '8' && p[2] == '"') {
-        return 1;
+    if (i >= 0 && param_index >= 0 && param_index < 128) {
+       return global_symbols[i].param_pointer_depths[param_index];
     }
     
     return 0;
 
 }
 
-static void append_global_zero_initializer_value (int64_s *values, char **symbols, int max_values, int *count) {
+int get_global_symbol_pointer_depth (const char *name) {
 
-    if (*count < max_values) {
-    
-        values[*count].low = 0;
-        values[*count].high = 0;
-        
-        if (symbols) {
-            symbols[*count] = 0;
-        }
+    int i = find_global_symbol (name);
     
+    if (i >= 0) {
+        return global_symbols[i].pointer_depth;
     }
-
-    (*count)++;
+    
+    return 0;
 
 }
 
-static int aggregate_initializer_value_field_count (const int *field_sizes, int field_count) {
+int get_global_symbol_pointed_size (const char *name) {
 
-    int count = 0;
-    int i;
-    
-    for (i = 0; i < field_count; i++) {
-    
-        if (field_sizes[i] > 0) {
-            count++;
-        }
+    int i = find_global_symbol (name);
     
+    if (i >= 0 && global_symbols[i].pointed_size > 0) {
+        return global_symbols[i].pointed_size;
     }
     
-    return count;
+    return DATA_INT & 0x1f;
 
 }
 
-static void parse_global_initializer_values_padded_elements (int64_s *values, char **symbols, int max_values, int *count, int element_field_count) {
+int get_global_symbol_array (const char *name) {
 
-    if (element_field_count <= 0 || tok.kind != TOK_LBRACE) {
-    
-        parse_global_initializer_values (values, symbols, max_values, count);
-        return;
+    int i = find_global_symbol (name);
     
+    if (i >= 0) {
+        return global_symbols[i].is_array;
     }
     
-    get_token ();
+    return 0;
+
+}
+
+int get_global_symbol_array_element_size (const char *name) {
+
+    int i = find_global_symbol (name);
     
-    while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
+    if (i >= 0) {
     
-        int before = *count;
-        parse_global_initializer_values (values, symbols, max_values, count);
+        if (global_symbols[i].array_element_size > 0) {
+            return global_symbols[i].array_element_size;
+        }
         
-        if (*count > before) {
+        if (global_symbols[i].tag_name && global_symbols[i].tag_name[0]) {
         
-            while ((*count - before) < element_field_count) {
-                append_global_zero_initializer_value (values, symbols, max_values, count);
+            struct aggregate_tag_entry *entry = find_aggregate_tag (global_symbols[i].tag_name, 0);
+            
+            if (entry && entry->size > 0) {
+                return entry->size;
             }
         
         }
-        
-        if (!_accept (TOK_COMMA)) {
-            break;
-        }
     
     }
     
-    expect (TOK_RBRACE, "}");
+    return 0;
 
 }
 
-static void parse_global_initializer_values (int64_s *values, char **symbols, int max_values, int *count) {
+int find_member_info_ex (const char *name, int *offset, int *size, int *elem_size, int *pointer_depth, int *is_array, int *is_floating) {
 
-    if (tok.kind == TOK_LBRACE) {
+    int best;
+    int i;
     
-        get_token ();
-        
-        while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
-        
-            parse_global_initializer_values (values, symbols, max_values, count);
-            
-            if (!_accept (TOK_COMMA)) {
-                break;
-            }
-        
-        }
-        
-        expect (TOK_RBRACE, "}");
-        return;
+    last_found_member_tag_name = 0;
+    last_found_member_is_unsigned = 0;
+    last_found_member_calling_convention = TOK_EOF;
     
+    if (!name) {
+        return 0;
     }
     
-    if (tok.kind != TOK_COMMA && tok.kind != TOK_SEMI && tok.kind != TOK_RBRACE && tok.kind != TOK_EOF) {
+    best = -1;
     
-        if (is_string_token ()) {
-        
-            if (*count < max_values) {
-            
-                values[*count].low = 0;
-                values[*count].high = 0;
-                
-                if (symbols) {
-                    symbols[*count] = emit_string_literal_global ();
-                }
-            
-            } else {
-                get_token ();
-            }
-            
-            (*count)++;
-        
-        } else if (tok.kind == TOK_LPAREN && global_initializer_parenthesized_string_now ()) {
-        
-            get_token ();
-            
-            if (*count < max_values) {
-            
-                values[*count].low = 0;
-                values[*count].high = 0;
-                
-                if (symbols) {
-                    symbols[*count] = emit_string_literal_global ();
-                } else {
-                
-                    int64_s ignored_values[MAX_AGG_FIELDS];
-                    int ignored_count = 0;
-                    
-                    parse_string_initializer_values (ignored_values, MAX_AGG_FIELDS, &ignored_count);
-                
-                }
-            
-            } else {
-            
-                int64_s ignored_values[MAX_AGG_FIELDS];
-                int ignored_count = 0;
-                
-                parse_string_initializer_values (ignored_values, MAX_AGG_FIELDS, &ignored_count);
-            
-            }
-            
-            expect (TOK_RPAREN, ")");
-            (*count)++;
-        
-        } else if (tok.kind == TOK_LPAREN && global_initializer_cast_before_string_now ()) {
-        
-            int cast_size = 0;
-            int cast_is_unsigned = 0;
-            int cast_is_pointer = 0;
-            
-            get_token ();
-            
-            if (token_starts_type_name () && parse_cast_type_name (&cast_size, &cast_is_unsigned, &cast_is_pointer) && is_string_token ()) {
-            
-                if (*count < max_values) {
-                
-                    values[*count].low = 0;
-                    values[*count].high = 0;
-                    
-                    if (symbols) {
-                        symbols[*count] = emit_string_literal_global ();
-                    }
-                
-                } else {
-                    get_token ();
-                }
-                
-                (*count)++;
-            
-            } else {
-            
-                if (*count < max_values) {
-                
-                    values[*count] = const64_from_current_expr ();
-                    
-                    if (symbols) {
-                        symbols[*count] = 0;
-                    }
-                
-                } else {
-                    const64_from_current_expr ();
-                }
-                
-                (*count)++;
-            
-            }
-        
-        } else if (tok.kind == TOK_AMPER) {
-        
-            get_token ();
-            
-            if (tok.kind != TOK_IDENT) {
-                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected identifier after '&'");
-            } else {
-            
-                char addr_symbol[256];
-                char *base_name = xstrdup (tok.ident);
-                long addr_offset = 0;
-                int sym_index = find_global_symbol (base_name);
-                long array_count = get_global_symbol_array_count (base_name);
-                long base_size = sym_index >= 0 ? global_symbols[sym_index].size : 0;
-                long elem_size = 0;
-                
-                if (array_count > 0 && base_size > 0) {
-                    elem_size = base_size / array_count;
-                }
-                
-                get_token ();
-                
-                while (tok.kind == TOK_LBRACK) {
-                
-                    int64_s index_value;
-                    long index;
-                    
-                    get_token ();
-                    
-                    index_value.low = 0;
-                    index_value.high = 0;
-                    
-                    if (tok.kind != TOK_RBRACK) {
-                        index_value = const64_from_current_expr ();
-                    }
-                    
-                    index = (long) index_value.low;
-                    
-                    if (elem_size > 0) {
-                        addr_offset += index * elem_size;
-                    }
-                    
-                    expect (TOK_RBRACK, "]");
-                
-                }
-                
-                if (*count < max_values) {
-                
-                    values[*count].low = 0;
-                    values[*count].high = 0;
-                    
-                    if (symbols) {
-                    
-                        if (addr_offset != 0) {
-                        
-                            sprintf (addr_symbol, "%s+%ld", base_name, addr_offset);
-                            symbols[*count] = xstrdup (addr_symbol);
-                        
-                        } else {
-                            symbols[*count] = xstrdup (base_name);
-                        }
-                    
-                    }
-                
-                }
-                
-                (*count)++;
-                free (base_name);
-            
-            }
-        
-        } else if (global_initializer_accept_symbol_addresses && tok.kind == TOK_IDENT && find_global_symbol (tok.ident) >= 0) {
-        
-            if (*count < max_values) {
-            
-                values[*count].low = 0;
-                values[*count].high = 0;
-                
-                if (symbols) {
-                    symbols[*count] = xstrdup (tok.ident);
-                }
-            
-            }
-            
-            (*count)++;
-            get_token ();
-        
-        } else if (*count < max_values) {
+    for (i = member_info_count - 1; i >= 0; i--) {
+    
+        if (member_infos[i].name && strcmp (member_infos[i].name, name) == 0) {
         
-            values[*count] = const64_from_current_expr ();
-                        
-            if (symbols) {
-                symbols[*count] = 0;
-            }
-            
-            (*count)++;
+            best = i;
+            break;
         
-        } else {
-            const64_from_current_expr ();
         }
     
     }
 
-}
-
-static int int64_is_zero_value (int64_s value) {
-    return value.low == 0 && value.high == 0;
-}
-
-static char masm_pending_data_label[512];
-static char masm_open_data_directive[8];
-
-static int masm_has_pending_data_label = 0;
-static int masm_data_line_open = 0;
-static int masm_data_line_values = 0;
-
-static void masm_set_pending_data_label (const char *name) {
-
-    const char *asm_name = asm_global_symbol_name (name);
-    unsigned long len;
+    if (best < 0) {
+        return 0;
+    }
     
-    if (!asm_name) {
+    last_found_member_tag_name = member_infos[best].tag_name;
+    last_found_member_is_unsigned = member_infos[best].is_unsigned ? 1 : 0;
+    last_found_member_calling_convention = member_infos[best].calling_convention;
+
+    if (offset) {
+        *offset = member_infos[best].offset;
+    }
     
-        masm_has_pending_data_label = 0;
-        masm_pending_data_label[0] = 0;
-        
-        return;
+    if (size) {
+        *size = member_infos[best].size;
+    }
     
+    if (elem_size) {
+        *elem_size = member_infos[best].elem_size;
     }
     
-    len = strlen (asm_name);
+    if (pointer_depth) {
+        *pointer_depth = member_infos[best].pointer_depth;
+    }
     
-    if (len >= sizeof (masm_pending_data_label)) {
-        len = sizeof (masm_pending_data_label) - 1;
+    if (is_array) {
+        *is_array = member_infos[best].is_array;
     }
     
-    memcpy (masm_pending_data_label, asm_name, len);
+    if (is_floating) {
+        *is_floating = member_infos[best].is_floating;
+    }
     
-    masm_pending_data_label[len] = 0;
-    masm_has_pending_data_label = 1;
+    return 1;
 
 }
 
-static void masm_flush_data_line (void) {
-
-    if (masm_data_line_open) {
-    
-        fprintf (state->ofp, "\n");
-        
-        masm_data_line_open = 0;
-        masm_data_line_values = 0;
-        
-        masm_open_data_directive[0] = 0;
-    
-    }
-
-}
+struct aggregate_tag_entry aggregate_tags[MAX_AGG_TAGS];
+int aggregate_tag_count = 0;
 
-static void masm_emit_data_prefix (const char *directive) {
+struct aggregate_tag_entry *find_aggregate_tag (const char *name, int is_union) {
 
-    if (masm_has_pending_data_label) {
+    int i;
     
-        masm_flush_data_line ();
-        fprintf (state->ofp, "%s %s ", masm_pending_data_label, directive);
-        
-        masm_has_pending_data_label = 0;
-        masm_pending_data_label[0] = 0;
-        
-        strncpy (masm_open_data_directive, directive, sizeof (masm_open_data_directive) - 1);
-        
-        masm_open_data_directive[sizeof (masm_open_data_directive) - 1] = 0;
-        masm_data_line_open = 1;
-        masm_data_line_values = 0;
+    if (!name) {
+        return 0;
+    }
     
-    } else if (masm_data_line_open && strcmp (masm_open_data_directive, directive) == 0) {
+    for (i = 0; i < aggregate_tag_count; i++) {
     
-        if (masm_data_line_values >= 8) {
-        
-            fprintf (state->ofp, "\n    %s ", directive);
-            masm_data_line_values = 0;
-        
-        } else {
-            fprintf (state->ofp, ", ");
+        if (aggregate_tags[i].is_union == is_union && strcmp (aggregate_tags[i].name, name) == 0) {
+            return &aggregate_tags[i];
         }
     
-    } else {
-    
-        masm_flush_data_line ();
-        
-        fprintf (state->ofp, "    %s ", directive);
-        strncpy (masm_open_data_directive, directive, sizeof (masm_open_data_directive) - 1);
-        
-        masm_open_data_directive[sizeof (masm_open_data_directive) - 1] = 0;
-        masm_data_line_open = 1;
-        masm_data_line_values = 0;
-    
     }
     
-    masm_data_line_values++;
+    return 0;
 
 }
 
-static void emit_global_scalar (int64_s value, int size) {
+static void load_typedef_name (struct typedef_entry *entry) {
 
-    unsigned long high = value.high;
-    unsigned long low = value.low;
+    int i;
+    clear_parsed_fields ();
     
-    if (state->syntax & ASM_SYNTAX_MASM) {
+    if (!entry) {
     
-        if (size == (DATA_CHAR & 0x1f)) {
-        
-            masm_emit_data_prefix ("db");
-            fprintf (state->ofp, "%ld", low & 0xFFUL);
-        
-        } else if (size == (DATA_SHORT & 0x1f)) {
-        
-            masm_emit_data_prefix ("dw");
-            fprintf (state->ofp, "%ld", low & 0xFFFFUL);
-        
-        } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
-        
-            masm_emit_data_prefix ("dq");
-            fprintf (state->ofp, "0%08lX%08lXh", high & U32_MASK, low & U32_MASK);
-        
-        } else {
+        parsed_type_size = DATA_INT & 0x1f;
         
-            masm_emit_data_prefix ("dd");
-            fprintf (state->ofp, "%lu", low & U32_MASK);
+        parsed_type_is_aggregate = 0;
+        parsed_type_is_unsigned = 0;
+        parsed_type_is_void = 0;
+        parsed_type_is_floating = 0;
+        parsed_type_is_array_typedef = 0;
+        parsed_type_array_count = 1;
+        parsed_type_array_element_size = DATA_NONE;
+        parsed_calling_convention = TOK_EOF;
         
-        }
+        append_parsed_field (DATA_INT & 0x1f);
+        return;
+    
+    }
     
-    } else if (state->syntax & ASM_SYNTAX_NASM) {
+    parsed_type_size = entry->size;
     
-        if (size == (DATA_CHAR & 0x1f)) {
-            fprintf (state->ofp, "    db %ld\n", low & 0xFFUL);
-        } else if (size == (DATA_SHORT & 0x1f)) {
-            fprintf (state->ofp, "    dw %ld\n", low & 0xFFFFUL);
-        } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
-        
-            fprintf (state->ofp, "    dd %lu\n", low & U32_MASK);
-            fprintf (state->ofp, "    dd %lu\n", high & U32_MASK);
-        
-        } else {
-            fprintf (state->ofp, "    dd %lu\n", low & U32_MASK);
-        }
+    parsed_type_is_aggregate = entry->is_aggregate;
+    parsed_type_is_unsigned = entry->is_unsigned;
+    parsed_type_is_void = entry->is_void;
+    parsed_type_is_floating = 0;
+    parsed_type_is_array_typedef = entry->is_array;
+    parsed_type_array_count = entry->array_count > 0 ? entry->array_count : 1;
+    parsed_type_array_element_size = entry->array_element_size > 0 ? entry->array_element_size : DATA_INT;
+    parsed_calling_convention = entry->calling_convention;
     
-    } else {
+    parsed_type_has_tag = 0;
+    parsed_type_tag_name[0] = '\0';
     
-        if (size == (DATA_CHAR & 0x1f)) {
-            fprintf (state->ofp, "    .byte %ld\n", low & 0xFFUL);
-        } else if (size == (DATA_SHORT & 0x1f)) {
-            fprintf (state->ofp, "    .word %ld\n", low & 0xFFFFUL);
-        } else if (size == (DATA_LLONG & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
+    if (entry->tag_name && entry->tag_name[0]) {
         
-            fprintf (state->ofp, "    .long %lu\n", low & U32_MASK);
-            fprintf (state->ofp, "    .long %lu\n", high & U32_MASK);
+        strncpy (parsed_type_tag_name, entry->tag_name, sizeof (parsed_type_tag_name) - 1);
+        parsed_type_tag_name[sizeof (parsed_type_tag_name) - 1] = '\0';
         
-        } else {
-            fprintf (state->ofp, "    .long %lu\n", low & U32_MASK);
-        }
+        parsed_type_has_tag = 1;
+    
+    }
     
+    for (i = 0; i < entry->field_count; i++) {
+        append_parsed_field (entry->field_sizes[i]);
     }
 
 }
 
-static void emit_global_address (const char *symbol, int size) {
+static void remember_member_info_ex (const char *name, int offset, int size, int elem_size, int pointer_depth, int is_array, int is_floating) {
 
-    const char *asm_symbol;
-    int64_s zero;
-    
-    if (!symbol || !*symbol) {
-    
-        zero.low = 0;
-        zero.high = 0;
-        
-        emit_global_scalar (zero, size);
+    if (!name) {
         return;
-    
     }
     
-    if (size != DATA_PTR) {
-        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "address initializer requires pointer-sized object");
+    if (member_info_count >= MAX_MEMBER_INFOS) {
+        return;
     }
     
-    emit_extern_reference_symbol (symbol, DATA_PTR);
-    asm_symbol = asm_global_symbol_name (symbol);
-    
-    if (state->syntax & ASM_SYNTAX_MASM) {
+    member_infos[member_info_count].name = xstrdup (name);
+    member_infos[member_info_count].offset = offset;
+    member_infos[member_info_count].size = size;
+    member_infos[member_info_count].elem_size = elem_size > 0 ? elem_size : size;
+    member_infos[member_info_count].pointer_depth = pointer_depth;
+    member_infos[member_info_count].is_array = is_array;
+    member_infos[member_info_count].is_floating = is_floating ? 1 : 0;
+    member_infos[member_info_count].is_unsigned = parsed_type_is_unsigned ? 1 : 0;
+    member_infos[member_info_count].calling_convention = (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention;
+    member_infos[member_info_count].tag_name = parsed_type_tag_name[0] ? xstrdup (parsed_type_tag_name) : 0;
+    member_infos[member_info_count].owner_size = 0;
+    member_infos[member_info_count].owner_tag_name = 0;
     
-        masm_emit_data_prefix ("dd");
-        fprintf (state->ofp, "offset %s", asm_symbol);
+    member_info_count++;
+
+}
+
+static int fields_storage_size (const int *sizes, int count) {
+
+    int total = 0, i;
     
-    } else if (state->syntax & ASM_SYNTAX_NASM) {
-        fprintf (state->ofp, "    dd %s\n", asm_symbol);
-    } else {
+    for (i = 0; i < count; i++) {
     
-        if (state->syntax & ASM_SYNTAX_INTEL) {
-            fprintf (state->ofp, "    .long offset %s\n", asm_symbol);
+        if (sizes[i] < 0) {
+            total += -sizes[i];
         } else {
-            fprintf (state->ofp, "    .long %s\n", asm_symbol);
+            total += sizes[i];
         }
     
     }
+    
+    return total;
 
 }
 
-static void emit_global_value (const int64_s *value, const char *symbol, int size) {
+void add_pending_param (const char *name, int size, int align, int is_unsigned, int is_floating, int pointer_depth, int pointed_size, int pointed_is_unsigned) {
 
-    int64_s zero;
-    
-    if (symbol) {
-    
-        emit_global_address (symbol, size);
-        return;
-    
+    if (pointer_depth > 0 && parsed_type_is_aggregate && parsed_type_size > (DATA_PTR & 0x1f) && pointed_size <= (DATA_PTR & 0x1f)) {
+        pointed_size = parsed_type_size;
     }
     
-    if (value) {
+    if (pending_param_count >= MAX_PENDING_PARAMS) {
     
-        emit_global_scalar (*value, size);
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "too many function parameters");
         return;
     
     }
     
-    zero.low = 0;
-    zero.high = 0;
-    
-    emit_global_scalar (zero, size);
-
-}
-
-static void emit_global_space (long bytes) {
-
-    if (bytes <= 0) {
-        return;
+    if (size < 1) {
+        size = DATA_INT & 0x1f;
     }
     
-    if (state->syntax & ASM_SYNTAX_MASM) {
-    
-        masm_emit_data_prefix ("db");
-        fprintf (state->ofp, "%ld dup (?)", bytes);
-    
-    } else if (state->syntax & ASM_SYNTAX_NASM) {
-        fprintf (state->ofp, "    resb %ld\n", bytes);
-    } else {
-        fprintf (state->ofp, "    .space %ld\n", bytes);
-    }
-
-}
-
-static int field_size_bytes (int field_size) {
-
-    if (field_size < 0) {
-        return -field_size;
+    if (align < 1) {
+        align = type_alignment (size);
     }
     
-    return field_size;
+    pending_params[pending_param_count].name = (name && *name) ? xstrdup (name) : 0;
+    pending_params[pending_param_count].size = size;
+    pending_params[pending_param_count].align = align;
+    pending_params[pending_param_count].is_unsigned = is_unsigned ? 1 : 0;
+    pending_params[pending_param_count].is_floating = is_floating ? 1 : 0;
+    pending_params[pending_param_count].knr_declared = 0;
+    pending_params[pending_param_count].pointer_depth = pointer_depth;
+    pending_params[pending_param_count].pointed_size = pointed_size > 0 ? pointed_size : 0;
+    pending_params[pending_param_count].pointed_is_floating = pointer_depth > 0 ? (parsed_type_is_floating ? 1 : 0) : 0;
+    pending_params[pending_param_count].pointed_is_unsigned = pointer_depth > 0 ? (pointed_is_unsigned ? 1 : 0) : 0;
+    pending_params[pending_param_count].pointed_tag_name = (pointer_depth > 0 && parsed_type_tag_name[0]) ? xstrdup (parsed_type_tag_name) : 0;
+    
+    pending_param_count++;
 
 }
 
-static int global_initializer_is_all_zero (const int64_s *values, char **symbols, int value_count) {
+int find_pending_param_from (const char *name, int start) {
 
     int i;
-
-    if (symbols) {
-        for (i = 0; i < value_count; i++) {
-            if (symbols[i]) {
-                return 0;
-            }
-        }
+    
+    if (!name) {
+        return -1;
     }
-
-    if (!values || value_count <= 0) {
-        return 1;
+    
+    if (start < 0) {
+        start = 0;
     }
-
-    for (i = 0; i < value_count; i++) {
-        if (!int64_is_zero_value (values[i])) {
-            return 0;
+    
+    for (i = start; i < pending_param_count; i++) {
+    
+        if (pending_params[i].name && strcmp (pending_params[i].name, name) == 0) {
+            return i;
         }
+    
     }
-
-    return 1;
+    
+    return -1;
 
 }
 
-static void emit_global_label (const char *name, int is_static) {
+char *take_ident (void) {
 
-    const char *asm_name = asm_global_symbol_name (name);
-    
-    if (state->syntax & ASM_SYNTAX_MASM) {
+    char *name;
     
-        if (!is_static) {
-            fprintf (state->ofp, "public %s\n", asm_name);
-        }
-        
-        fprintf (state->ofp, "%s:\n", asm_name);
+    if (!token_is_ident ()) {
+        return 0;
+    }
     
-    } else if (state->syntax & ASM_SYNTAX_NASM) {
+    name = xstrdup (tok.ident);
     
-        if (!is_static) {
-            fprintf (state->ofp, "global %s\n", asm_name);
-        }
-        
-        fprintf (state->ofp, "%s:\n", asm_name);
+    last_declarator_name_line = get_line_number ();
+    last_declarator_name_start = tok.start;
+    last_declarator_name_caret = tok.caret;
     
-    } else {
+    if (capture_declarator_name_location && !captured_declarator_name_location) {
     
-        if (!is_static) {
-            fprintf (state->ofp, ".globl %s\n", asm_name);
-        }
-        
-        fprintf (state->ofp, "%s:\n", asm_name);
+        captured_declarator_name_location = 1;
+        captured_declarator_name_line = last_declarator_name_line;
+        captured_declarator_name_start = last_declarator_name_start;
+        captured_declarator_name_caret = last_declarator_name_caret;
     
     }
+    
+    get_token ();
+    return name;
 
 }
 
-static void emit_global_data_label (const char *name, int is_static) {
+long align_up_long (long value, int align) {
 
-    const char *asm_name = asm_global_symbol_name (name);
+    long mask;
     
-    if (state->syntax & ASM_SYNTAX_MASM) {
+    if (align <= 1) {
+        return value;
+    }
     
-        masm_flush_data_line ();
-        
-        if (!is_static) {
-            fprintf (state->ofp, "public %s\n", asm_name);
-        }
-        
-        masm_set_pending_data_label (name);
+    mask = (long) align - 1;
+    return (value + mask) & ~mask;
+
+}
+
+int type_alignment (int size) {
+
+    if (size <= 1) {
+        return 1;
+    }
     
-    } else {
-        emit_global_label (name, is_static);
+    if (size == 2) {
+        return 2;
     }
+    
+    return 4;
 
 }
 
-static void emit_global_object (const char *name, int size, int is_array, long array_count, const int *field_sizes, int field_count, const int64_s *values, char **symbols, int value_count, int is_aggregate, int is_static) {
+void parse_type_spec (void) {
 
-    int64_s zero;
+    int saw = 0;
     
-    int value_index, use_bss, i;
-    long emitted, total;
-
-    zero.low = 0;
-    zero.high = 0;
+    int saw_float = 0;
+    int saw_double = 0;
+    int saw_void = 0;
     
-    if (!state->ofp || !name || !*name) {
-        return;
-    }
+    int saw_signed = 0;
+    int saw_unsigned = 0;
+    int saw_real_type = 0;
+    
+    parsed_storage_class = STORAGE_NONE;
+    parsed_type_is_aggregate = 0;
+    parsed_type_is_unsigned = 0;
+    parsed_type_has_tag = 0;
+    parsed_type_tag_name[0] = '\0';
+    parsed_type_is_array_typedef = 0;
+    parsed_type_array_count = 1;
+    parsed_type_array_element_size = DATA_NONE;
+    parsed_type_is_inline = 0;
+    parsed_type_is_void = 0;
+    parsed_type_only_qualifiers = 0;
+    parsed_type_size = DATA_NONE;
     
-    if (size <= 0) {
-        size = DATA_INT & 0x1f;
-    }
+    parsed_calling_convention = TOK_EOF;
     
-    if (array_count <= 0) {
-        array_count = 1;
+    if (declarator_depth == 0) {
+        declarator_calling_convention = TOK_EOF;
     }
     
-    total = size * array_count;
-    use_bss = global_initializer_is_all_zero (values, symbols, value_count);
-
-    if (use_bss) {
+    parsed_dllexport = 0;
+    parsed_dllimport = 0;
     
-        switch_section (SECTION_BSS);
+    clear_parsed_fields ();
+    
+    while (tok.kind == TOK_AUTO || tok.kind == TOK_REGISTER || tok.kind == TOK_STATIC ||
+           tok.kind == TOK_EXTERN || tok.kind == TOK_TYPEDEF || tok.kind == TOK_CONST ||
+           tok.kind == TOK_VOLATILE || tok.kind == TOK_SIGNED || tok.kind == TOK_UNSIGNED ||
+           tok.kind == TOK_SHORT || tok.kind == TOK_LONG || tok.kind == TOK_CHAR ||
+           tok.kind == TOK_INT || tok.kind == TOK_VOID || tok.kind == TOK_FLOAT ||
+           tok.kind == TOK_DOUBLE || tok.kind == TOK_INLINE || tok.kind == TOK_RESTRICT ||
+           tok.kind == TOK_DLLEXPORT || tok.kind == TOK_DLLIMPORT || tok.kind == TOK_STDCALL || token_is_ms_int_type_name ()) {
         
-        emit_global_data_label (name, is_static);
-        emit_global_space (total);
+        saw = 1;
         
-        return;
-    
-    }
-    
-    switch_section (SECTION_DATA);
-    emit_global_data_label (name, is_static);
-    
-    value_index = 0;
-    emitted = 0;
-    
-    if (!is_array && !is_aggregate) {
-    
-        if (value_count > 0) {
-            emit_global_value (&values[0], symbols ? symbols[0] : 0, size);
-        } else {
-            emit_global_value (0, 0, size);
+        if (tok.kind == TOK_SIGNED || tok.kind == TOK_UNSIGNED ||
+            tok.kind == TOK_SHORT || tok.kind == TOK_LONG || tok.kind == TOK_CHAR ||
+            tok.kind == TOK_INT || tok.kind == TOK_VOID || tok.kind == TOK_FLOAT ||
+            tok.kind == TOK_DOUBLE || token_is_ms_int_type_name ()) {
+            saw_real_type = 1;
         }
         
-        return;
-    
-    }
-    
-    if (is_aggregate && field_count > 0) {
-    
-        while (emitted < total) {
+        if (tok.kind == TOK_STDCALL || tok.kind == TOK_DLLEXPORT || tok.kind == TOK_DLLIMPORT) {
         
-            for (i = 0; i < field_count && emitted < total; i++) {
-            
-                int fsize = field_sizes[i];
-                
-                if (fsize < 0) {
-                
-                    emit_global_space (-fsize);
-                    
-                    emitted += -fsize;
-                    continue;
-                
-                }
-                
-                if (value_index < value_count) {
-                
-                    emit_global_value (&values[value_index], symbols ? symbols[value_index] : 0, fsize);
-                    value_index++;
-                
-                } else {
-                    emit_global_scalar (zero, fsize);
-                }
-                
-                emitted += field_size_bytes (fsize);
-            
+            parse_decl_modifier ();
+            continue;
+        
+        } else if (tok.kind == TOK_EXTERN) {
+        
+            if (parsed_storage_class == STORAGE_EXTERN) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate 'extern'");
+            } else if (parsed_storage_class != STORAGE_NONE) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple storage classes in declaration specifiers");
+            } else {
+                parsed_storage_class = STORAGE_EXTERN;
             }
         
-        }
+        } else if (tok.kind == TOK_STATIC) {
         
-        emit_global_space (total - emitted);
-        return;
-    
-    }
-    
-    if (is_array) {
-    
-        int elem_size = size;
+            if (parsed_storage_class == STORAGE_STATIC) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate 'static'");
+            } else if (parsed_storage_class != STORAGE_NONE) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple storage classes in declaration specifiers");
+            } else {
+                parsed_storage_class = STORAGE_STATIC;
+            }
         
-        if (field_count > 0 && field_sizes[0] > 0) {
-            elem_size = field_sizes[0];
-        }
+        } else if (tok.kind == TOK_TYPEDEF) {
+        
+            if (parsed_storage_class == STORAGE_TYPEDEF) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate 'typedef'");
+            } else if (parsed_storage_class != STORAGE_NONE) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple storage classes in declaration specifiers");
+            } else {
+                parsed_storage_class = STORAGE_TYPEDEF;
+            }
         
-        while (emitted + elem_size <= total) {
+        } else if (tok.kind == TOK_INLINE) {
+            parsed_type_is_inline = 1;
+        } else if (tok.kind == TOK_CHAR) {
         
-            if (value_index < value_count) {
-            
-                emit_global_value (&values[value_index], symbols ? symbols[value_index] : 0, elem_size);
-                value_index++;
-            
+            if (parsed_type_size == DATA_CHAR) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate 'char'");
+            } else if (parsed_type_size != DATA_NONE) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");
             } else {
-                emit_global_scalar (zero, elem_size);
+                parsed_type_size = DATA_CHAR;
             }
-            
-            emitted += elem_size;
         
-        }
+        } else if (tok.kind == TOK_SHORT) {
         
-        emit_global_space (total - emitted);
-        return;
-    
-    }
-    
-    emit_global_space (total);
-
-}
-
-static char *emit_string_literal_global (void) {
-
-    int64_s values[MAX_AGG_FIELDS];
-    
-    char label[64];
-    char skip_label[64];
-    
-    int elem_size = DATA_CHAR & 0x1f;
-    int value_count = 0, i;
-    
-    if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
-        sprintf (label, "LC%d", anon_label++);
-    } else {
-        sprintf (label, ".LC%d", anon_label++);
-    }
-    
-    parse_string_initializer_values (values, MAX_AGG_FIELDS, &value_count);
-    elem_size = parsed_string_initializer_elem_size;
-    
-    /*
-     * Dead statement parsing suppresses output by temporarily clearing
-     * state->ofp.  Still consume the literal so the token stream remains
-     * correct, but do not try to emit a .data label through a NULL FILE *.
-     * This is needed for optimised-away bodies such as:
-     *
-     *     while (0) { printf ("Hello\n"); }
-     */
-    if (!state->ofp) {
-        return xstrdup (label);
-    }
-    
-    if (current_section == SECTION_TEXT) {
-    
-        if ((state->syntax & ASM_SYNTAX_MASM) || (state->syntax & ASM_SYNTAX_NASM)) {
-            sprintf (skip_label, "L%d", anon_label++);
-        } else {
-            sprintf (skip_label, ".L%d", anon_label++);
-        }
+            if (parsed_type_size == DATA_SHORT) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate 'short'");
+            } else if (parsed_type_size != DATA_NONE) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");
+            } else {
+                parsed_type_size = DATA_SHORT;
+            }
         
-        fprintf (state->ofp, "    jmp %s\n", skip_label);
+        } else if (tok.kind == TOK_INT) {
         
-        switch_section (SECTION_DATA);
-        emit_global_data_label (label, 1);
+            if (parsed_type_size == DATA_INT) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate 'int'");
+            } else if (parsed_type_size != DATA_NONE) {
+                /*report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");*/
+            } else {
+                parsed_type_size = DATA_INT;
+            }
         
-        for (i = 0; i < value_count; i++) {
-            emit_global_scalar (values[i], elem_size);
-        }
+        } else if (tok.kind == TOK_LONG) {
         
-        switch_section (SECTION_TEXT);
-        emit_global_label (skip_label, 1);
+            if (parsed_type_size == DATA_LONG) {
+                parsed_type_size = DATA_LLONG;
+            } else if (parsed_type_size == DATA_LLONG) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "too many 'long' keywords");
+            } else if (parsed_type_size != DATA_NONE) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");
+            } else {
+                parsed_type_size = DATA_LONG;
+            }
         
-        return xstrdup (label);
-    
-    }
-    
-    switch_section (SECTION_DATA);
-    emit_global_data_label (label, 1);
-    
-    for (i = 0; i < value_count; i++) {
-        emit_global_scalar (values[i], elem_size);
-    }
-    
-    return xstrdup (label);
-
-}
-
-static const char *masm_extern_type_name (int size, int is_function) {
-
-    if (is_function) {
-        return "PROC";
-    }
-
-    if (size == (DATA_CHAR & 0x1f)) {
-        return "BYTE";
-    }
-
-    if (size == (DATA_SHORT & 0x1f)) {
-        return "WORD";
-    }
-
-    if (size == (DATA_LLONG & 0x1f) || size == (DATA_DOUBLE & 0x1f)) {
-        return "QWORD";
-    }
-
-    return "DWORD";
-
-}
-
-static void emit_extern_line (const char *name, int size, int is_function) {
-
-    const char *asm_name = get_global_symbol_dllimport (name) ? asm_global_import_symbol_name (name) : asm_global_symbol_name (name);
-    
-    if (get_global_symbol_dllimport (name)) {
-    
-        size = DATA_PTR & 0x1f;
-        is_function = 0;
+        } else if (tok.kind == TOK_SIGNED) {
+            saw_signed = 1;
+        } else if (tok.kind == TOK_UNSIGNED) {
+            saw_unsigned = 1;
+        } else if (tok.kind == TOK_FLOAT) {
+        
+            if (parsed_type_size == DATA_FLOAT) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate 'float'");
+            } else if (parsed_type_size != DATA_NONE) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");
+            } else {
+            
+                parsed_type_size = DATA_FLOAT;
+                saw_float = 1;
+            
+            }
+        
+        } else if (tok.kind == TOK_DOUBLE) {
+        
+            if (parsed_type_size == DATA_LONG) {
+            
+                parsed_type_size = DATA_DOUBLE;
+                saw_double = 1;
+            
+            } else if (parsed_type_size == DATA_DOUBLE) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate 'double'");
+            } else if (parsed_type_size != DATA_NONE) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");
+            } else {
+            
+                parsed_type_size = DATA_DOUBLE;
+                saw_double = 1;
+            
+            }
+        
+        } else if (tok.kind == TOK_VOID) {
+        
+            if (parsed_type_size == DATA_VOID) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate 'void'");
+            } else if (parsed_type_size != DATA_NONE) {
+                report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");
+            } else {
+            
+                parsed_type_size = DATA_VOID;
+                parsed_type_is_void = 1;
+                
+                saw_void = 1;
+            
+            }
+        
+        } else if (token_is_ms_int_type_name ()) {
+        
+            if (strcmp (tok.ident, "__int8") == 0) {
+            
+                if (parsed_type_size != DATA_NONE) {
+                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");
+                } else {
+                    parsed_type_size = DATA_CHAR & 0x1f;
+                }
+            
+            } else if (strcmp (tok.ident, "__int16") == 0) {
+            
+                if (parsed_type_size != DATA_NONE) {
+                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");
+                } else {
+                    parsed_type_size = DATA_SHORT & 0x1f;
+                }
+            
+            } else if (strcmp (tok.ident, "__int32") == 0) {
+            
+                if (parsed_type_size != DATA_NONE) {
+                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");
+                } else {
+                    parsed_type_size = DATA_INT & 0x1f;
+                }
+            
+            } else {
+            
+                if (parsed_type_size != DATA_NONE) {
+                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "multiple data types in declaration specifiers");
+                } else {
+                    parsed_type_size = DATA_LLONG & 0x1f;
+                }
+            
+            }
+        
+        }
+        
+        get_token ();
     
     }
     
-    if (state->syntax & ASM_SYNTAX_MASM) {
-        fprintf (state->ofp, "extrn %s:%s\n", asm_name, masm_extern_type_name (size, is_function));
-    } else if (state->syntax & ASM_SYNTAX_NASM) {
-        fprintf (state->ofp, "extern %s\n", asm_name);
-    } else {
-        fprintf (state->ofp, ".extern %s\n", asm_name);
-    }
-
-}
-
-static void emit_extern_symbol (const char *name, int size, int is_function) {
-
-    int i;
+    /*
+     * Be tolerant of project typedef chains where the base typedef name is
+     * not already known to this parser.  In
+     *
+     *     typedef some_base new_name;
+     *     typedef some_base *new_ptr;
+     *
+     * the declarator name is new_name/new_ptr, not some_base.  Without
+     * consuming the unknown base identifier here, parse_declarator() records
+     * some_base as the typedef name and the real declarator is then parsed as
+     * junk.
+     */
+    if (parsed_storage_class == STORAGE_TYPEDEF && !saw_real_type &&
+        tok.kind == TOK_IDENT && !is_current_typedef_name ()) {
     
-    (void) size;
-    (void) is_function;
+        get_token ();
+        
+        saw = 1;
+        saw_real_type = 1;
+        
+        parsed_type_size = DATA_INT;
     
-    if (!state->ofp || !name || !*name) {
-        return;
     }
     
-    i = find_global_symbol (name);
-    
-    /**
-     * Do not write assembler externs at the point of use.  A symbol can be
-     * declared/called before its real definition appears later in the same
-     * translation unit; NASM then rejects "extern foo" followed by "foo:" as
-     * an inconsistent redefinition.  Just mark that generated code referenced
-     * the external-looking symbol, and emit the actual assembler externs once
-     * the whole file has been parsed and we know which names stayed external.
-     */
-    if (i < 0 || !global_symbols[i].is_extern) {
-        return;
-    }
+    if (parsed_type_size == DATA_NONE) {
     
-    global_symbols[i].extern_emitted = 1;
-
-}
-
-static void emit_pending_extern_symbols (void) {
-
-    int i;
+        parsed_type_only_qualifiers = (saw && !saw_real_type) ? 1 : 0;
+        parsed_type_size = DATA_INT;
     
-    if (!state->ofp) {
-        return;
+    } else if (parsed_type_size == DATA_LONG && state->long64) {
+        parsed_type_size = DATA_LLONG;
     }
     
-    for (i = 0; i < global_symbol_count; i++) {
-    
-        if (!global_symbols[i].is_extern || !global_symbols[i].extern_emitted) {
-            continue;
-        }
-        
-        emit_extern_line (global_symbols[i].name,
-            global_symbols[i].size > 0 ? global_symbols[i].size : (DATA_INT & 0x1f),
-                global_symbols[i].kind == GLOBAL_SYMBOL_FUNCTION);
+    parsed_type_size &= 0x1f;
     
-    }
-
-}
-
-static void emit_extern_reference_symbol (const char *name, int size) {
-    emit_extern_symbol (name, size, get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION);
-}
-
-static void parse_external_after_type (void) {
+    if (is_current_typedef_name ()) {
 
-    for (;;) {
-    
-        char **init_symbols = 0;
-        int64_s *init_values = 0;
+        struct typedef_entry *entry;
+        
+        entry = find_typedef_name (tok.ident);
+        get_token ();
+        
+        load_typedef_name (entry);
         
-        char *name = 0;
-        int init_value_count = 0, i;
+        if (entry && entry->is_aggregate && entry->tag_name && entry->tag_name[0]) {
         
-        int object_fields[MAX_AGG_FIELDS];
-        int object_field_count = 0;
+            strncpy (parsed_type_tag_name, entry->tag_name, sizeof (parsed_type_tag_name) - 1);
+            parsed_type_tag_name[sizeof (parsed_type_tag_name) - 1] = '\0';
+            
+            parsed_type_has_tag = 1;
         
-        const char *name_start, *name_caret;
-        unsigned long name_line;
+        }
         
-        int saved_field_count = parsed_field_count;
+        parsed_type_only_qualifiers = 0;
+        return;
+    
+    }
+    
+    if (tok.kind == TOK_STRUCT || tok.kind == TOK_UNION) {
+    
+        int is_union = (tok.kind == TOK_UNION);
+        int has_tag = 0;
         
-        int declaration_is_inline;
-        int declaration_storage;
-        int declaration_dllimport = 0;
+        int aggregate_size = 0;
+        int aggregate_align = 1;
         
-        int decl_is_pointer;
-        int decl_pointer_depth;
-        int decl_has_array;
-        int decl_has_function;
-        int decl_function_is_pointer;
-        int decl_function_param_count;
-        int decl_function_has_prototype;
-        int decl_function_is_variadic;
-        int decl_array_unsized;
+        int aggregate_fields[MAX_AGG_FIELDS];
+        int aggregate_field_count = 0;
         
-        long decl_array_count;
-        long decl_first_array_count;
-        long decl_last_array_count;
+        int union_init_fields[MAX_AGG_FIELDS];
+        int union_init_field_count = 0;
+        int union_init_size = 0;
         
-        for (i = 0; i < saved_field_count; i++) {
-            object_fields[i] = parsed_field_sizes[i];
-        }
+        struct aggregate_tag_entry *tag_entry = 0;
         
-        object_field_count = saved_field_count;
+        int aggregate_storage_class = parsed_storage_class;
+        int aggregate_is_inline = parsed_type_is_inline;
         
-        declaration_is_inline = parsed_type_is_inline;
-        declaration_storage = parsed_storage_class;
-        declaration_dllimport = parsed_dllimport;
+        char *tag_name = 0;
+        int member_info_start = member_info_count;
         
-        parse_declarator (&name);
+        parsed_type_size = DATA_PTR;
+        parsed_type_is_void = 0;
         
-        declaration_dllimport = declaration_dllimport || parsed_dllimport || declarator_dllimport;
-        apply_typedef_array_to_declarator ();
+        clear_parsed_fields ();
+        get_token ();
         
-        decl_is_pointer = declarator_is_pointer;
-        decl_pointer_depth = declarator_pointer_depth;
-        decl_has_array = declarator_has_array;
-        decl_has_function = declarator_has_function;
-        decl_function_is_pointer = declarator_function_is_pointer;
-        decl_function_param_count = declarator_function_param_count;
-        decl_function_has_prototype = declarator_function_has_prototype;
-        decl_function_is_variadic = declarator_function_is_variadic;
-        decl_array_unsized = declarator_array_unsized;
-        decl_array_count = declarator_array_count;
-        decl_first_array_count = declarator_first_array_count;
-        decl_last_array_count = declarator_last_array_count;
+        if (token_is_ident ()) {
         
-        name_start = last_declarator_name_start;
-        name_caret = last_declarator_name_caret;
+            tag_name = xstrdup (tok.ident);
+            strncpy (parsed_type_tag_name, tok.ident, sizeof (parsed_type_tag_name) - 1);
+            
+            parsed_type_tag_name[sizeof (parsed_type_tag_name) - 1] = '\0';
+            has_tag = 1;
+            
+            get_token ();
         
-        name_line = last_declarator_name_line;
+        }
         
-        if (declaration_storage == STORAGE_TYPEDEF) {
+        if (tok.kind == TOK_LBRACE) {
         
-            if (name) {
+            get_token ();
+            
+            while (tok.kind != TOK_EOF && tok.kind != TOK_RBRACE) {
             
-                make_declarator_fields (object_fields, &object_field_count, parsed_field_sizes, parsed_field_count, parsed_type_size, parsed_type_is_aggregate);
+                int member_type_size;
+                int member_type_is_floating;
+                int member_is_aggregate;
+                int member_has_tag;
+                
+                int member_fields[MAX_AGG_FIELDS];
+                int member_field_count;
+                
+                int i;
+                
+                if (!is_type_start (tok.kind)) {
+                
+                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected member declaration");
+                    
+                    skip_balanced_until (TOK_SEMI, TOK_RBRACE, TOK_EOF);
+                    _accept (TOK_SEMI);
+                    
+                    continue;
+                
+                }
+                
+                parse_type_spec ();
+                
+                member_type_size = parsed_type_size;
+                member_type_is_floating = parsed_type_is_floating;
+                member_is_aggregate = parsed_type_is_aggregate;
+                member_has_tag = parsed_type_has_tag;
+                member_field_count = parsed_field_count;
+                
+                for (i = 0; i < member_field_count; i++) {
+                    member_fields[i] = parsed_field_sizes[i];
+                }
+                
+                if (tok.kind == TOK_SEMI) {
+
+                    if (member_is_aggregate && !member_has_tag) {
+
+                        int member_init_size = fields_storage_size (member_fields, member_field_count);
+                        
+                        if (is_union) {
+                        
+                            if (member_type_size > aggregate_size) {
+                                aggregate_size = member_type_size;
+                            }
+                            
+                            if (union_init_field_count == 0) {
+                            
+                                union_init_field_count = member_field_count;
+                                
+                                for (i = 0; i < member_field_count; i++) {
+                                    union_init_fields[i] = member_fields[i];
+                                }
+                                
+                                union_init_size = member_init_size;
+                            
+                            }
+                        
+                        } else {
+                        
+                            aggregate_size += member_type_size;
+                            
+                            for (i = 0; i < member_field_count && aggregate_field_count < MAX_AGG_FIELDS; i++) {
+                                aggregate_fields[aggregate_field_count++] = member_fields[i];
+                            }
+                            
+                            if (member_type_size > member_init_size && aggregate_field_count < MAX_AGG_FIELDS) {
+                                aggregate_fields[aggregate_field_count++] = -(member_type_size - member_init_size);
+                            }
+                        
+                        }
+                    
+                    }
+
+                } else {
+                
+                    for (;;) {
+                    
+                        char *member = 0;
+                        
+                        int member_size, repeat;
+                        int init_size;
+                        
+                        int member_info_elem_size;
+                        int member_align;
+                        
+                        parse_declarator (&member);
+                        
+                        if (declarator_is_pointer) {
+                        
+                            member_size = DATA_PTR;
+                            member_field_count = 1;
+                            member_fields[0] = DATA_PTR;
+                        
+                        } else {
+                        
+                            member_size = member_type_size;
+                            
+                            if (member_field_count <= 0) {
+                            
+                                member_field_count = 1;
+                                member_fields[0] = member_type_size;
+                            
+                            }
+                        
+                        }
+                        
+                        member_align = declarator_is_pointer ? type_alignment (DATA_PTR) : type_alignment (member_type_size);
+                        
+                        if (member_align > aggregate_align) {
+                            aggregate_align = member_align;
+                        }
+                        
+                        repeat = 1;
+                        
+                        if (declarator_has_array) {
+                        
+                            repeat = (int) declarator_array_count;
+                            member_size *= declarator_array_count;
+                        
+                        }
+                        
+                        if (_accept (TOK_COLON)) {
+                            skip_balanced_until (TOK_COMMA, TOK_SEMI, TOK_RBRACE);
+                        }
+                        
+                        if (declarator_has_array && declarator_is_pointer) {
+                            member_info_elem_size = DATA_PTR;
+                        } else {
+                        
+                            member_info_elem_size = declarator_is_pointer ?
+                                (declarator_pointer_depth > 1 ? DATA_PTR : (parsed_type_is_aggregate ? parsed_type_size : (parsed_type_size & 0x1f))) :
+                                    (declarator_has_array ? member_type_size : member_size);
+                        
+                        }
+                        
+                        init_size = fields_storage_size (member_fields, member_field_count);
+                        
+                        if (is_union) {
+                        
+                            remember_member_info_ex (member, 0, member_size, member_info_elem_size, declarator_is_pointer ? declarator_pointer_depth : 0, declarator_has_array, declarator_is_pointer ? 0 : member_type_is_floating);
+                            
+                            if (member_size > aggregate_size) {
+                                aggregate_size = member_size;
+                            }
+                            
+                            if (union_init_field_count == 0) {
+                            
+                                union_init_field_count = member_field_count;
+                                
+                                for (i = 0; i < member_field_count; i++) {
+                                    union_init_fields[i] = member_fields[i];
+                                }
+                                
+                                union_init_size = init_size;
+                            
+                            }
+                        
+                        } else {
+                        
+                            int member_offset = (int) align_up_long (aggregate_size, member_align);
+                            int padding = member_offset - aggregate_size;
+                            
+                            int r;
+                            
+                            if (padding > 0 && aggregate_field_count < MAX_AGG_FIELDS) {
+                                aggregate_fields[aggregate_field_count++] = -padding;
+                            }
+                            
+                            aggregate_size = member_offset;
+                            
+                            remember_member_info_ex (member, member_offset, member_size, member_info_elem_size, declarator_is_pointer ? declarator_pointer_depth : 0, declarator_has_array, declarator_is_pointer ? 0 : member_type_is_floating);
+                            aggregate_size += member_size;
+                            
+                            for (r = 0; r < repeat; r++) {
+                            
+                                for (i = 0; i < member_field_count && aggregate_field_count < MAX_AGG_FIELDS; i++) {
+                                    aggregate_fields[aggregate_field_count++] = member_fields[i];
+                                }
+                            
+                            }
+                            
+                            if (member_size > init_size * repeat && aggregate_field_count < MAX_AGG_FIELDS) {
+                                aggregate_fields[aggregate_field_count++] = -(member_size - init_size * repeat);
+                            }
+                        
+                        }
+                        
+                        if (member) {
+                            free (member);
+                        }
+                        
+                        if (!_accept (TOK_COMMA)) {
+                            break;
+                        }
+                    
+                    }
+                
+                }
                 
-                save_typedef_name (name, declarator_object_size (parsed_type_size),
-                    (declarator_is_pointer ? 0 : parsed_type_is_unsigned),
-                        (declarator_is_pointer ? 0 : parsed_type_is_void),
-                            (!declarator_is_pointer && (parsed_type_is_aggregate || declarator_has_array)),
-                                (!declarator_is_pointer && declarator_has_array),
-                                    declarator_array_count, parsed_type_size,
-                                        (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention,
-                                            object_fields, object_field_count);
+                expect (TOK_SEMI, ";");
             
             }
             
-            if (_accept (TOK_ASSIGN)) {
-            
-                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "typedef '%s' is initialized", name ? name : "");
-                skip_initializer ();
-            
-            }
+            expect (TOK_RBRACE, "}");
             
-            if (name) {
-                free (name);
+            if (aggregate_size <= 0) {
+                aggregate_size = DATA_CHAR & 0x1f;
             }
             
-            if (!_accept (TOK_COMMA)) {
-                break;
-            }
+            aggregate_size = (int) align_up_long (aggregate_size, aggregate_align);
             
-            continue;
-        
-        }
-        
-        if (name && declarator_has_function && (tok.kind == TOK_LBRACE || is_type_start (tok.kind))) {
-        
-            if (parsed_dllexport || declarator_dllexport) {
+            {
             
-                vec_push (&vec_dllexports, xstrdup (name));
+                const char *owner_name = 0;
+                char anon_owner_name[64];
                 
-                declarator_dllexport = 0;
-                parsed_dllexport = 0;
-            
-            }
-            
-            parse_function_body (name, declaration_storage, declaration_is_inline,
-                (parsed_type_is_void && !declarator_is_pointer),
-                    (declarator_is_pointer ? 0 : parsed_type_is_floating),
-                        (declarator_is_pointer ? 0 : parsed_type_is_unsigned),
-                            (declarator_is_pointer ? DATA_PTR : parsed_type_size),
-                                name_line, name_start, name_caret);
-            
-            free (name);
-            return;
-        
-        }
-        
-        if (parsed_type_is_void && !declarator_is_pointer && !declarator_has_function) {
-            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "variable '%s' declared void", name ? name : "");
-        }
-        
-        if (declarator_is_pointer) {
-        
-            object_field_count = 1;
-            object_fields[0] = DATA_PTR;
-        
-        }
-        
-        init_values = xmalloc (sizeof (*init_values) * MAX_GLOBAL_INIT_FIELDS);
-        init_symbols = xmalloc (sizeof (*init_symbols) * MAX_GLOBAL_INIT_FIELDS);
-        
-        for (i = 0; i < MAX_GLOBAL_INIT_FIELDS; i++) {
-            init_symbols[i] = 0;
-        }
-        
-        if (_accept (TOK_ASSIGN)) {
-        
-            if (declarator_has_array && !declarator_is_pointer && (parsed_type_size & 0x1f) == (DATA_CHAR & 0x1f) && (is_string_token () || tok.kind == TOK_LBRACE)) {
-            
-                if (is_string_token ()) {
-                    parse_string_initializer_values (init_values, MAX_GLOBAL_INIT_FIELDS, &init_value_count);
+                int mi;
+                
+                if (has_tag) {
+                    owner_name = tag_name;
                 } else {
-                    parse_char_array_initializer_values (init_values, MAX_GLOBAL_INIT_FIELDS, &init_value_count, declarator_last_array_count);
-                }
                 
-                if (decl_array_unsized) {
-                    decl_array_count = init_value_count;
+                    sprintf (anon_owner_name, "<anon-aggregate-%d>", anonymous_aggregate_owner_id++);
+                    owner_name = anon_owner_name;
+                
                 }
-            
-            } else if (declarator_is_pointer && is_string_token ()) {
-            
-                init_values[0].low = 0;
-                init_values[0].high = 0;
                 
-                init_symbols[0] = emit_string_literal_global ();
-                init_value_count = 1;
-            
-            } else if (!declarator_is_pointer && parsed_type_is_floating) {
-            
-                init_values[0] = parse_floating_const_expr_bits_now (parsed_type_size);
-                init_symbols[0] = 0;
-                init_value_count = 1;
-            
-            } else {
-            
-                {
+                for (mi = member_info_start; mi < member_info_count; mi++) {
                 
-                    int saved_accept_symbol_addresses = global_initializer_accept_symbol_addresses;
-                    global_initializer_accept_symbol_addresses = declarator_is_pointer || declarator_has_function || parsed_type_is_aggregate || declarator_has_array;
-                    
-                    if (declarator_has_array && !declarator_is_pointer && parsed_type_is_aggregate && parsed_field_count > 0 && tok.kind == TOK_LBRACE) {
-                        parse_global_initializer_values_padded_elements (init_values, init_symbols, MAX_GLOBAL_INIT_FIELDS, &init_value_count, aggregate_initializer_value_field_count (parsed_field_sizes, parsed_field_count));
-                    } else {
-                        parse_global_initializer_values (init_values, init_symbols, MAX_GLOBAL_INIT_FIELDS, &init_value_count);
+                    if (member_infos[mi].owner_size == 0) {
+                        member_infos[mi].owner_size = aggregate_size;
                     }
                     
-                    global_initializer_accept_symbol_addresses = saved_accept_symbol_addresses;
+                    if (owner_name && member_infos[mi].owner_tag_name == 0) {
+                        member_infos[mi].owner_tag_name = xstrdup (owner_name);
+                    }
                 
                 }
                 
-                if (decl_has_array && decl_array_unsized) {
+                if (!has_tag && owner_name) {
                 
-                    if (parsed_type_is_aggregate && object_field_count > 0) {
-                        decl_array_count = (init_value_count + object_field_count - 1) / object_field_count;
-                    } else {
-                        decl_array_count = init_value_count;
-                    }
+                    strncpy (parsed_type_tag_name, owner_name, sizeof (parsed_type_tag_name) - 1);
+                    parsed_type_tag_name[sizeof (parsed_type_tag_name) - 1] = '\0';
                 
                 }
             
             }
-        
-        }
-        
-        if (init_value_count > MAX_GLOBAL_INIT_FIELDS) {
-        
-            report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "too many initializer values for '%s'", name ? name : "");
-            init_value_count = MAX_GLOBAL_INIT_FIELDS;
-        
-        }
-        
-        declarator_is_pointer = decl_is_pointer;
-        declarator_pointer_depth = decl_pointer_depth;
-        declarator_has_array = decl_has_array;
-        declarator_has_function = decl_has_function;
-        declarator_function_is_pointer = decl_function_is_pointer;
-        declarator_function_param_count = decl_function_param_count;
-        declarator_function_has_prototype = decl_function_has_prototype;
-        declarator_function_is_variadic = decl_function_is_variadic;
-        declarator_array_unsized = decl_array_unsized;
-        declarator_array_count = decl_array_count;
-        declarator_first_array_count = decl_first_array_count;
-        declarator_last_array_count = decl_last_array_count;
-        
-        if (name) {
-        
-            if (declarator_has_function && !declarator_function_is_pointer && !declarator_has_array) {
             
-                /*
-                 * A file-scope function declaration is a declaration even
-                 * without an explicit extern storage class.  Keep it in the
-                 * global symbol table so a later call does not fall back to
-                 * the implicit-function-declaration path.
-                 *
-                 * Store prototypes as extern-like declarations here.  A real
-                 * function body will later turn the symbol into a definition
-                 * through add_global_symbol(), which already handles replacing
-                 * an extern declaration with the definition.
-                 */
-                add_global_symbol (name, GLOBAL_SYMBOL_FUNCTION, 1, name_start, name_caret, name_line);
-                
-                if (find_global_symbol (name) >= 0) {
-                
-                    set_global_symbol_size (name, declarator_is_pointer ? DATA_PTR : (parsed_type_is_void ? DATA_VOID : parsed_type_size));
-                    set_global_symbol_pointer_info (name, declarator_effective_pointer_depth_now (),
-                        declarator_effective_pointed_size_now (parsed_type_size, object_fields, object_field_count));
-                    set_global_symbol_tag_name (name, parsed_type_tag_name);
-                    set_global_symbol_unsigned (name, 0);
-                    set_global_symbol_floating (name, declarator_is_pointer ? 0 : parsed_type_is_floating);
-                    set_global_symbol_returns_void (name, parsed_type_is_void && !declarator_is_pointer && !declarator_function_is_pointer);
-                    set_global_symbol_param_count (name, declarator_function_param_count, declarator_function_has_prototype || declarator_function_param_count > 0, declarator_function_is_variadic);
-                    
-                    set_global_symbol_calling_convention (name, (declarator_calling_convention != TOK_EOF) ? declarator_calling_convention : parsed_calling_convention);
-                    set_global_symbol_dllimport (name, declaration_dllimport);
-                    
-                    copy_pending_params_to_global_symbol (name);
-                
-                }
+            parsed_type_size = aggregate_size;
+            parsed_type_is_aggregate = 1;
+            parsed_type_is_void = 0;
+            parsed_type_has_tag = has_tag;
             
-            } else if ((declaration_storage == STORAGE_EXTERN || declaration_dllimport) && init_value_count == 0) {
+            clear_parsed_fields ();
+
+            if (is_union) {
             
-                add_global_symbol (name, GLOBAL_SYMBOL_OBJECT, 1, name_start, name_caret, name_line);
-                
-                if (find_global_symbol (name) >= 0) {
+                int i;
                 
-                    set_global_symbol_size (name, declarator_is_pointer ? DATA_PTR : declarator_object_size (parsed_type_size));
-                    set_global_symbol_pointer_info (name, declarator_effective_pointer_depth_now (),
-                        declarator_effective_pointed_size_now (parsed_type_size, object_fields, object_field_count));
-                    set_global_symbol_tag_name (name, parsed_type_tag_name);
-                    set_global_symbol_unsigned (name, declarator_is_pointer ? 0 : parsed_type_is_unsigned);
-                    set_global_symbol_array (name, declarator_has_array);
-                    set_global_symbol_array_count (name, declarator_has_array ? declarator_array_count : 0);
-                    set_global_symbol_array_dimensions (name, declarator_has_array ? declarator_array_dimensions : 0);
-                    set_global_symbol_array_element_size (name, declarator_array_element_size_now (parsed_type_size));
-                    set_global_symbol_dllimport (name, declaration_dllimport);
+                for (i = 0; i < union_init_field_count; i++) {
+                    append_parsed_field (union_init_fields[i]);
+                }
                 
+                if (aggregate_size > union_init_size) {
+                    append_parsed_field (-(aggregate_size - union_init_size));
                 }
             
             } else {
             
-                if (add_global_symbol (name, GLOBAL_SYMBOL_OBJECT, 0, name_start, name_caret, name_line)) {
-                
-                    set_global_symbol_size (name, declarator_is_pointer ? DATA_PTR : declarator_object_size (parsed_type_size));
-                    set_global_symbol_pointer_info (name, declarator_effective_pointer_depth_now (),
-                        declarator_effective_pointed_size_now (parsed_type_size, object_fields, object_field_count));
-                    set_global_symbol_tag_name (name, parsed_type_tag_name);
-                    set_global_symbol_unsigned (name, declarator_is_pointer ? 0 : parsed_type_is_unsigned);
-                    set_global_symbol_floating (name, declarator_is_pointer ? 0 : parsed_type_is_floating);
-                    set_global_symbol_array (name, declarator_has_array);
-                    set_global_symbol_array_count (name, declarator_has_array ? declarator_array_count : 0);
-                    set_global_symbol_array_dimensions (name, declarator_has_array ? declarator_array_dimensions : 0);
-                    set_global_symbol_array_element_size (name, declarator_array_element_size_now (parsed_type_size));
-                    
-                    emit_global_object (name, declarator_is_pointer ? DATA_PTR : (declarator_has_array ? parsed_type_size : (parsed_type_is_aggregate ? parsed_type_size : (parsed_type_size & 0x1f))),
-                        declarator_has_array, declarator_array_count, object_fields, object_field_count,
-                            init_values, init_symbols, init_value_count, (!declarator_is_pointer && parsed_type_is_aggregate),
-                                declaration_storage == STORAGE_STATIC);
+                int i;
                 
+                for (i = 0; i < aggregate_field_count; i++) {
+                    append_parsed_field (aggregate_fields[i]);
                 }
             
             }
             
-            free (name);
-        
-        }
+            if (tag_name) {
+            
+                save_aggregate_tag (tag_name, is_union, parsed_type_size, parsed_field_sizes, parsed_field_count);
+                update_typedef_name_from_aggregate_tag (tag_name, parsed_type_size, parsed_field_sizes, parsed_field_count);
+            
+            }
         
-        for (i = 0; i < MAX_GLOBAL_INIT_FIELDS; i++) {
+        } else {
         
-            if (init_symbols[i]) {
+            tag_entry = find_aggregate_tag (tag_name, is_union);
+
+            if (tag_entry) {
+                load_aggregate_tag_fields (tag_entry);
+            } else {
             
-                free (init_symbols[i]);
-                init_symbols[i] = 0;
+                parsed_type_size = DATA_PTR;
+                append_parsed_field (DATA_PTR);
             
             }
         
         }
         
-        free (init_symbols);
-        free (init_values);
-        
-        if (!_accept (TOK_COMMA)) {
-            break;
+        if (tag_name) {
+            free (tag_name);
         }
+        
+        parsed_storage_class = aggregate_storage_class;
+        parsed_type_is_inline = aggregate_is_inline;
+        
+        return;
     
     }
     
-    if (tok.kind == TOK_SEMI) {
-        get_token ();
-    } else if (is_type_start (tok.kind)) {
-        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "missing ';' after declaration");
-    } else {
-        expect (TOK_SEMI, ";");
-    }
-
-}
-
-void compile_translation_unit (void) {
-
-    if (state->ofp) {
+    if (tok.kind == TOK_ENUM) {
     
-        if (state->syntax & ASM_SYNTAX_MASM) {
-        
-            fprintf (state->ofp, ".386\n");
-            fprintf (state->ofp, ".model flat\n");
+        parsed_type_size = DATA_INT & 0x1f;
+        parsed_type_is_unsigned = 0;
         
-        } else if (state->syntax & ASM_SYNTAX_NASM) {
+        get_token ();
         
-            fprintf (state->ofp, "cpu 386\n");
-            fprintf (state->ofp, "bits 32\n");
+        if (token_is_ident ()) {
+            get_token ();
+        }
         
-        } else if (state->syntax & ASM_SYNTAX_INTEL) {
-            fprintf (state->ofp, ".intel_syntax noprefix\n");
+        if (tok.kind == TOK_LBRACE) {
+            parse_enum_body ();
         }
+        
+        append_parsed_field (DATA_INT & 0x1f);
+        return;
     
     }
     
-    current_section = SECTION_NONE;
+    /*if (saw_void) {
+        parsed_type_size = DATA_INT;
+    }*/
     
-    clear_global_symbols ();
-    clear_inline_functions ();
-    clear_enum_constants ();
-    clear_typedef_names ();
+    parsed_type_is_floating = (saw_float || saw_double) ? 1 : 0;
     
-    get_token ();
+    if (saw_signed && saw_unsigned) {
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "both signed and unsigned specified");
+    }
+
+    if ((saw_signed || saw_unsigned) && (saw_float || saw_double || saw_void)) {
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "signed/unsigned invalid for this type");
+    }
+
+    parsed_type_is_unsigned = saw_unsigned ? 1 : 0;
+    append_parsed_field (parsed_type_size);
     
-    while (tok.kind != TOK_EOF) {
+    if (!saw) {
     
-        if (is_type_start (tok.kind)) {
-        
-            parse_type_spec ();
-            parse_external_after_type ();
-            
-            continue;
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected type");
+        get_token ();
+    
+    }
+
+}
+
+void parse_direct_declarator (char **out_name) {
+
+    if (_accept (TOK_LPAREN)) {
+    
+        parse_declarator_inner (out_name);
+        expect (TOK_RPAREN, ")");
         
+        if (declarator_is_pointer && !declarator_has_function) {
+            declarator_function_is_pointer = 1;
         }
-        
-        if (parse_possible_knr_function ()) {
-            continue;
+    
+    } else if (token_is_ident ()) {
+    
+        if (out_name && !*out_name) {
+            *out_name = take_ident ();
+        } else {
+            get_token ();
         }
-        
-        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "expected external declaration");
-        get_token ();
-    
-    }
     
-    if (state->syntax & ASM_SYNTAX_MASM) {
-        masm_flush_data_line ();
     }
     
-    emit_pending_extern_symbols ();
-    
-    if (vec_dllexports.length) {
+    for (;;) {
     
-        char *p, *tmp;
-        
-        const char *name;
-        long i;
-        
-        FILE *fp;
-        
-        if ((p = strrchr (state->ofile, '.'))) {
-        
-            tmp = xmalloc (p - state->ofile + 5);
-            sprintf (tmp, "%.*s.def", (int) (p - state->ofile), state->ofile);
-        
-        } else {
+        if (_accept (TOK_LBRACK)) {
         
-            tmp = xmalloc (strlen (state->ofile) + 5);
-            sprintf (tmp, "%s.def", state->ofile);
+            int was_array = declarator_has_array;
+            long count = 1;
+            
+            if (tok.kind != TOK_RBRACK) {
+            
+                enum token_kind kill[3];
+                int v;
+                
+                kill[0] = TOK_RBRACK;
+                kill[1] = TOK_EOF;
+                kill[2] = 0;
+                
+                v = expr_const (kill);
+                
+                if (v > 0) {
+                    count = v;
+                }
+            
+            } else {
+                declarator_array_unsized = 1;
+            }
+            
+            if (!was_array) {
+                declarator_first_array_count = count;
+            }
+            
+            declarator_has_array = 1;
+            declarator_array_dimensions++;
+            
+            if (declarator_array_count <= 0) {
+                declarator_array_count = 1;
+            }
+            
+            declarator_array_count *= count;
+            declarator_last_array_count = count;
+            
+            expect (TOK_RBRACK, "]");
+            continue;
         
         }
         
-        if ((fp = fopen (tmp, "w"))) {
+        if (_accept (TOK_LPAREN)) {
         
-            fprintf (fp, "EXPORTS\n");
+            int old_style_param_start = pending_param_count;
+            declarator_has_function = 1;
             
-            for (i = 0; i < vec_dllexports.length; i++) {
+            if (tok.kind != TOK_RPAREN) {
             
-                if ((name = asm_global_symbol_name (vec_dllexports.data[i]))) {
-                    fprintf (fp, "    %s\n", name);
+                for (;;) {
+                
+                    if (tok.kind == TOK_ELLIPSIS) {
+                    
+                        declarator_function_is_variadic = 1;
+                        get_token ();
+                    
+                    } else if (is_type_start (tok.kind)) {
+                    
+                        enum token_kind saved_calling_convention = declarator_calling_convention;
+                        enum token_kind saved_parsed_calling_convention = parsed_calling_convention;
+                        
+                        long saved_array_count = declarator_array_count;
+                        
+                        int saved_type_size = parsed_type_size;
+                        int saved_storage_class = parsed_storage_class;
+                        int saved_is_aggregate = parsed_type_is_aggregate;
+                        int saved_is_void = parsed_type_is_void;
+                        int saved_is_unsigned = parsed_type_is_unsigned;
+                        int saved_is_floating = parsed_type_is_floating;
+                        int saved_has_tag = parsed_type_has_tag;
+                        int saved_is_pointer = declarator_is_pointer;
+                        int saved_pointer_depth = declarator_pointer_depth;
+                        int saved_has_array = declarator_has_array;
+                        int saved_has_function = declarator_has_function;
+                        int saved_function_is_pointer = declarator_function_is_pointer;
+                        int saved_function_param_count = declarator_function_param_count;
+                        int saved_function_has_prototype = declarator_function_has_prototype;
+                        int saved_array_unsized = declarator_array_unsized;
+                        int saved_is_inline = parsed_type_is_inline;
+                        
+                        char *param_name = 0;
+                        int param_base_size, param_size;
+                        
+                        int count_this_param = 0;
+                        int saw_void_param_list = 0;
+                        
+                        parse_type_spec ();
+                        param_base_size = parsed_type_size;
+                        
+                        /*
+                         * Parameter declarators must not inherit the outer
+                         * declarator state.  In particular, in declarations
+                         * such as:
+                         *
+                         *     FILE **__gtin(void);
+                         *
+                         * the function return type leaves declarator_is_pointer
+                         * set before the parameter list is parsed.  If that flag
+                         * is still set while looking at the abstract void
+                         * parameter list, void is mistaken for a real pointer
+                         * parameter and the prototype is recorded as taking one
+                         * argument.
+                         */
+                        declarator_is_pointer = 0;
+                        declarator_pointer_depth = 0;
+                        declarator_has_array = 0;
+                        declarator_has_function = 0;
+                        declarator_function_is_pointer = 0;
+                        declarator_array_unsized = 0;
+                        declarator_array_count = 1;
+                        declarator_last_array_count = 1;
+                        
+                        if (parsed_type_only_qualifiers && token_is_ident ()) {
+                            get_token ();
+                        }
+                        
+                        if (tok.kind != TOK_COMMA && tok.kind != TOK_RPAREN) {
+                            parse_declarator (&param_name);
+                        }
+                        
+                        if (!parsed_type_is_void || declarator_is_pointer || declarator_has_array || declarator_has_function || param_name) {
+                        
+                            count_this_param = 1;
+                            param_size = (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef) ? DATA_PTR : declarator_object_size (param_base_size);
+                            
+                            if (declarator_depth == 1) {
+                            
+                                add_pending_param (param_name, param_size, type_alignment (param_size),
+                                    (declarator_is_pointer || parsed_type_is_array_typedef ? 0 : parsed_type_is_unsigned),
+                                        (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef) ? 0 : parsed_type_is_floating,
+                                            declarator_pointer_depth, parsed_type_is_aggregate ? parsed_type_size : (parsed_type_size & 0x1f), parsed_type_is_unsigned);
+                            
+                            }
+                        
+                        } else {
+                            saw_void_param_list = 1;
+                        }
+                        
+                        if (param_name) {
+                            free (param_name);
+                        }
+                        
+                        parsed_calling_convention = saved_parsed_calling_convention;
+                        parsed_type_size = saved_type_size;
+                        parsed_storage_class = saved_storage_class;
+                        parsed_type_is_aggregate = saved_is_aggregate;
+                        parsed_type_is_void = saved_is_void;
+                        parsed_type_is_unsigned = saved_is_unsigned;
+                        parsed_type_is_floating = saved_is_floating;
+                        parsed_type_has_tag = saved_has_tag;
+                        parsed_type_is_inline = saved_is_inline;
+                        
+                        declarator_calling_convention = saved_calling_convention;
+                        declarator_is_pointer = saved_is_pointer;
+                        declarator_pointer_depth = saved_pointer_depth;
+                        declarator_has_array = saved_has_array;
+                        declarator_has_function = saved_has_function;
+                        declarator_function_is_pointer = saved_function_is_pointer;
+                        declarator_function_param_count = saved_function_param_count + (count_this_param ? 1 : 0);
+                        declarator_function_has_prototype = saved_function_has_prototype || count_this_param || saw_void_param_list;
+                        declarator_array_count = saved_array_count;
+                        
+                        declarator_array_unsized = saved_array_unsized;
+                    
+                    } else if (token_is_ident ()) {
+                    
+                        char *maybe_type_name = xstrdup (tok.ident);
+                        int unknown_typedef_pointer = 0;
+                        int consumed_as_prototype_param = 0;
+                        
+                        get_token ();
+                        
+                        while (tok.kind == TOK_CONST || tok.kind == TOK_VOLATILE || tok.kind == TOK_RESTRICT) {
+                            get_token ();
+                        }
+                        
+                        while (tok.kind == TOK_STAR) {
+                        
+                            unknown_typedef_pointer = 1;
+                            get_token ();
+                            
+                            while (tok.kind == TOK_CONST || tok.kind == TOK_VOLATILE || tok.kind == TOK_RESTRICT) {
+                                get_token ();
+                            }
+                        
+                        }
+                        
+                        if (token_is_ident ()) {
+                        
+                            char *param_name = xstrdup (tok.ident);
+                            int param_size = unknown_typedef_pointer ? DATA_PTR : DATA_PTR;
+                            
+                            get_token ();
+                            
+                            if (declarator_depth == 1) {
+                            
+                                if (find_pending_param_from (param_name, old_style_param_start) >= 0) {
+                                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate parameter '%s'", param_name);
+                                } else {
+                                    add_pending_param (param_name, param_size, type_alignment (param_size), 0, 0, unknown_typedef_pointer ? 1 : 0, DATA_INT & 0x1f, 0);
+                                }
+                            
+                            }
+                            
+                            free (param_name);
+                            
+                            declarator_function_param_count++;
+                            declarator_function_has_prototype = 1;
+                            consumed_as_prototype_param = 1;
+                        
+                        }
+                        
+                        if (!consumed_as_prototype_param) {
+                        
+                            if (declarator_depth == 1) {
+                            
+                                if (find_pending_param_from (maybe_type_name, old_style_param_start) >= 0) {
+                                    report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate parameter '%s'", maybe_type_name);
+                                } else {
+                                    add_pending_param (maybe_type_name, DATA_INT & 0x1f, type_alignment (DATA_INT & 0x1f), 0, 0, 0, 0, 0);
+                                }
+                            
+                            }
+                            
+                            declarator_function_param_count++;
+                        
+                        }
+                        
+                        if (maybe_type_name) {
+                            free (maybe_type_name);
+                        }
+                    
+                    } else {
+                        skip_balanced_until (TOK_COMMA, TOK_RPAREN, TOK_EOF);
+                    }
+                    
+                    if (!_accept (TOK_COMMA)) {
+                        break;
+                    }
+                
                 }
             
             }
             
-            fclose (fp);
-            
+            expect (TOK_RPAREN, ")");
+            continue;
         }
-    
-    }
-    
-    if (state->ofp) {
-    
-        if (state->syntax & ASM_SYNTAX_MASM) {
-        
-            masm_flush_data_line ();
-            fprintf (state->ofp, "end\n");
         
-        }
+        break;
     
     }
 
diff --git a/parse.h b/parse.h
index 85318a2ec9b96966fe9bef6eae42559bb0a5601f..0958ff02fda90e593a581b31074cd0800f068437 100644 (file)
--- a/parse.h
+++ b/parse.h
 #ifndef     _PARSE_H
 #define     _PARSE_H
 
-void compile_translation_unit (void);
+#include    "int64.h"
+#include    "token.h"
+#include    "vector.h"
+
+#define     DATA_NONE                   0
+#define     DATA_VOID                   4
+
+#define     DATA_PTR                    (state->bits == 64 ? 8 : 4)
+extern int anonymous_aggregate_owner_id;
+
+extern enum token_kind last_found_member_calling_convention;
+extern enum token_kind postfix_member_calling_convention;
+extern enum token_kind parsed_calling_convention;
+
+extern struct vector vec_dllexports;
+extern int parsed_dllexport;
+extern int parsed_dllimport;
+
+extern int parsed_type_size;
+extern int parsed_type_is_inline;
+extern int parsed_type_is_void;
+extern int parsed_type_is_unsigned;
+extern int parsed_type_is_floating;
+extern int parsed_type_only_qualifiers;
+
+extern int parsed_type_is_aggregate;
+extern int parsed_type_has_tag;
+
+extern char parsed_type_tag_name[128];
+extern char last_cast_type_tag_name[128];
+
+extern int last_cast_type_object_size;
+extern int last_cast_type_is_floating;
+extern int floating_rhs_result_in_eax_bool;
+
+extern int parsed_type_is_array_typedef;
+extern int parsed_type_array_element_size;
+
+extern long parsed_type_array_count;
+
+extern int declarator_depth;
+extern int declarator_has_function;
+extern int declarator_function_is_pointer;
+extern int declarator_function_param_count;
+extern int declarator_function_has_prototype;
+extern int declarator_function_is_variadic;
+extern int declarator_array_unsized;
+
+extern int declarator_is_pointer;
+extern int declarator_pointer_depth;
+extern int declarator_has_array;
+
+extern int declarator_dllexport;
+extern int declarator_dllimport;
+
+extern enum token_kind declarator_calling_convention;
+extern int global_initializer_accept_symbol_addresses;
+
+extern long declarator_array_count;
+extern long declarator_first_array_count;
+extern long declarator_last_array_count;
+
+extern int declarator_array_dimensions;
+
+#define     STORAGE_NONE                0
+#define     STORAGE_EXTERN              1
+#define     STORAGE_STATIC              2
+#define     STORAGE_TYPEDEF             3
+
+extern int parsed_storage_class;
+
+#define     MAX_GLOBAL_INIT_FIELDS      262144
+#define     MAX_AGG_FIELDS              512
+
+extern int parsed_field_sizes[MAX_AGG_FIELDS];
+extern int parsed_field_count;
+
+#define     MAX_STRING_INIT_BYTES       4096
+int _accept (enum token_kind k);
+
+void compile_translation_unit32 (void);
+void compile_translation_unit64 (void);
 
 int token_is_sizeof_keyword (void);
 int parse_sizeof_value (void);
 
+int is_type_start (enum token_kind k);
+int token_is_ms_int_type_name (void);
 int token_starts_type_name (void);
-int parse_cast_type_name (int *out_size, int *out_is_unsigned, int *out_is_pointer);
 
 int parse_constexpr_address_of_null_member (int64_s *out);
+int parse_cast_type_name (int *out_size, int *out_is_unsigned, int *out_is_pointer);
+
 int resolve_enum_constant (const char *name, int64_s *out);
 
+#define     DATA_CHAR                   (1 | (1 << 5))
+#define     DATA_SHORT                  (2 | (1 << 6))
+#define     DATA_INT                    (4 | (1 << 7))
+#define     DATA_LONG                   (4 | (1 << 8))
+#define     DATA_LLONG                  (8 | (1 << 9))
+#define     DATA_FLOAT                  (4 | (1 << 10))
+#define     DATA_DOUBLE                 (8 | (1 << 11))
+
+struct enum_const_entry {
+
+    char *name;
+    int64_s value;
+
+};
+
+#define     MAX_ENUM_CONSTANTS          4096
+
+struct member_info_entry {
+
+    char *name;
+    int offset;
+    int size;
+    int elem_size;
+    int pointer_depth;
+    
+    int is_array;
+    int is_floating;
+    int is_unsigned;
+    
+    char *tag_name;
+    char *owner_tag_name;
+    
+    enum token_kind calling_convention;
+    int owner_size;
+
+};
+
+#define     MAX_MEMBER_INFOS            4096
+
+extern struct member_info_entry member_infos[MAX_MEMBER_INFOS];
+extern int member_info_count;
+
+struct local_symbol {
+
+    char *name;
+    
+    int size;
+    int align;
+    
+    int is_floating;
+    long offset;
+    
+    char *static_label;
+    
+    int is_static, is_unsigned;
+    int is_array;
+    int array_element_size;
+    int array_dimensions;
+    
+    int pointer_depth;
+    int pointed_size;
+    int pointed_is_floating;
+    int pointed_is_unsigned;
+    
+    char *pointed_tag_name;
+    char *tag_name;
+
+};
+
+extern const char *last_found_member_tag_name;
+extern int last_found_member_is_unsigned;
+
+struct aggregate_tag_entry {
+
+    char *name;
+    
+    int is_union;
+    int size;
+    
+    int field_count;
+    int field_sizes[MAX_AGG_FIELDS];
+
+};
+
+#define     MAX_LOCAL_SYMBOLS           1024
+
+extern struct local_symbol local_symbols[MAX_LOCAL_SYMBOLS];
+extern int local_symbol_count;
+
+struct local_symbol *find_local_symbol (const char *name);
+
+#define     MAX_GLOBAL_SYMBOLS          4096
+int find_global_symbol (const char *name);
+
+#define     GLOBAL_SYMBOL_OBJECT        1
+#define     GLOBAL_SYMBOL_FUNCTION      2
+
+struct global_symbol_entry {
+
+    char *name;
+    
+    int is_unsigned, is_extern;
+    int is_dllimport;
+    int kind, size;
+    
+    int array_element_size;
+    int is_array;
+    int array_dimensions;
+    
+    long array_count;
+    
+    int is_floating;
+    int pointer_depth;
+    int pointed_size;
+    int pointed_is_floating;
+    int pointed_is_unsigned;
+    int returns_void;
+    
+    int param_count;
+    int has_prototype;
+    int is_variadic;
+    
+    int param_sizes[128];
+    int param_unsigneds[128];
+    int param_floatings[128];
+    int param_pointer_depths[128];
+    
+    int import_call_stack_bytes;
+    int is_implicit;
+    int extern_emitted;
+    
+    enum token_kind calling_convention;
+    char *tag_name;
+
+};
+
+extern struct global_symbol_entry global_symbols[MAX_GLOBAL_SYMBOLS];
+extern int global_symbol_count;
+
+int get_global_symbol_param_pointer_depth (const char *name, int param_index);
+int get_global_symbol_array_element_size (const char *name);
+int get_global_symbol_pointer_depth (const char *name);
+int get_global_symbol_pointed_size (const char *name);
+int get_global_symbol_array (const char *name);
+int get_global_symbol_size (const char *name);
+
+int find_member_info_ex (const char *name, int *offset, int *size, int *elem_size, int *pointer_depth, int *is_array, int *is_floating);
+
+#define     MAX_AGG_TAGS                256
+
+extern struct aggregate_tag_entry aggregate_tags[MAX_AGG_TAGS];
+extern int aggregate_tag_count;
+
+struct aggregate_tag_entry *find_aggregate_tag (const char *name, int is_union);
+void parse_type_spec (void);
+
+#define     MAX_TYPEDEF_NAMES            512
+
+struct typedef_entry {
+
+    char *name;
+    int size;
+    
+    int is_aggregate;
+    int is_unsigned;
+    int is_void;
+    
+    int field_count;
+    int field_sizes[MAX_AGG_FIELDS];
+    
+    int array_element_size;
+    int is_array;
+    
+    char *tag_name;
+    long array_count;
+    
+    enum token_kind calling_convention;
+
+};
+
+extern struct typedef_entry typedef_names[MAX_TYPEDEF_NAMES];
+extern int typedef_name_count;
+
+extern int capture_declarator_name_location;
+extern int captured_declarator_name_location;
+
+extern const char *captured_declarator_name_start;
+extern const char *captured_declarator_name_caret;
+
+extern unsigned long captured_declarator_name_line;
+
+#define     MAX_PENDING_PARAMS          128
+
+struct pending_param {
+
+    char *name;
+    int align, size;
+    
+    int is_unsigned;
+    int is_floating;
+    
+    int pointer_depth;
+    int pointed_size;
+    int pointed_is_floating;
+    int pointed_is_unsigned;
+    
+    char *pointed_tag_name;
+    int knr_declared;
+
+};
+
+extern struct pending_param pending_params[MAX_PENDING_PARAMS];
+
+extern int pending_param_count;
+extern int preserve_pending_params;
+
+extern const char *last_declarator_name_start;
+extern const char *last_declarator_name_caret;
+
+extern unsigned long last_declarator_name_line;
+int declarator_object_size (int base_size);
+
+void parse_declarator_inner (char **out_name);
+void parse_declarator (char **out_name);
+
+void parse_direct_declarator (char **out_name);
+void append_parsed_field (int size);
+void clear_parsed_fields (void);
+
+int expect (enum token_kind k, const char *what);
+int is_string_token (void);
+
+extern struct enum_const_entry enum_constants[MAX_ENUM_CONSTANTS];
+extern int enum_constant_count;
+
+struct typedef_entry *find_typedef_name (const char *name);
+int token_is_ident (void);
+
+extern int parsed_string_initializer_elem_size;
+void parse_string_initializer_values (int64_s *values, int max_values, int *count);
+
+void append_global_init_value (int64_s *values, int max_values, int *count, unsigned int value, int elem_size);
+void clear_pending_params (void);
+
+void skip_balanced_until (enum token_kind stop1, enum token_kind stop2, enum token_kind stop3);
+int parse_constexpr_null_member_address_after_lparen (int64_s *out);
+
+int find_member_info_ex_bounded (const char *name, int max_size, const char *owner_tag_name, int *offset, int *size, int *elem_size, int *pointer_depth, int *is_array, int *is_floating);
+int type_alignment (int size);
+
+char *take_ident (void);
+int find_pending_param_from (const char *name, int start);
+
+void add_pending_param (const char *name, int size, int align, int is_unsigned, int is_floating, int pointer_depth, int pointed_size, int pointed_is_unsigned);
+long align_up_long (long value, int align);
+
 #endif      /* _PARSE_H */