]> git.unchartedbackwaters.co.uk Git - francis/libjit.git/commitdiff
Loading and storing record fields in Dynamic Pascal.
authorRhys Weatherley <rweather@southern-storm.com.au>
Mon, 10 May 2004 03:43:11 +0000 (03:43 +0000)
committerRhys Weatherley <rweather@southern-storm.com.au>
Mon, 10 May 2004 03:43:11 +0000 (03:43 +0000)
ChangeLog
dpas/dpas-parser.y
dpas/dpas-types.c
dpas/dpas-types.h

index 6b318dcd582b3aa1a2bb15229f6993c461a597bf..5f094422b007d973002236267a6a9c9f540801fa 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,9 @@
        interpreter code conversion for relative pointer and copy opcodes;
        fix some bugs in stack-based register allocation.
 
+       * dpas/dpas-parser.y, dpas/dpas-types.c, dpas/dpas-types.h:
+       loading and storing record fields in Dynamic Pascal.
+
 2004-05-08  Rhys Weatherley  <rweather@southern-storm.com.au>
 
        * jit/jit-cache.c, jit/jit-cache.h, jit/jit-dump.c, jit/jit-interp.h,
index 1a55a8b2d6bd534fb332f19ba483ecd4459285c8..a05c3e0f6a88547823d7c67821b61fd6b7516d21 100644 (file)
@@ -2645,8 +2645,69 @@ Variable
                                /* TODO */
                        }
        | Variable '.' Identifier                       {
-                               /* Fetch the effective address of a structure field */
-                               /* TODO */
+                               /* Fetch the effective address of a record field */
+                               jit_type_t type = dpas_sem_get_type($1);
+                               jit_type_t field_type;
+                               jit_value_t address;
+                               jit_nint offset;
+                               if(dpas_sem_is_lvalue_ea($1))
+                               {
+                                       address = dpas_sem_get_value($1);
+                               }
+                               else if(dpas_sem_is_lvalue($1))
+                               {
+                                       address = jit_insn_address_of
+                                               (dpas_current_function(), dpas_sem_get_value($1));
+                                       if(!address)
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                               }
+                               else
+                               {
+                                       if(!dpas_sem_is_error($1))
+                                       {
+                                               dpas_error("invalid left hand side for `.'");
+                                       }
+                                       type = 0;
+                                       address = 0;
+                               }
+                               if(type && dpas_type_is_record(type))
+                               {
+                                       field_type = dpas_type_get_field(type, $3, &offset);
+                                       if(field_type)
+                                       {
+                                               if(offset != 0)
+                                               {
+                                                       address = jit_insn_add_relative
+                                                               (dpas_current_function(), address, offset);
+                                                       if(!address)
+                                                       {
+                                                               dpas_out_of_memory();
+                                                       }
+                                               }
+                                               dpas_sem_set_lvalue_ea($$, field_type, address);
+                                       }
+                                       else
+                                       {
+                                               char *name = dpas_type_name(type);
+                                               dpas_error("`%s' is not a member of `%s'", $3, name);
+                                               jit_free(name);
+                                               dpas_sem_set_error($$);
+                                       }
+                               }
+                               else if(type)
+                               {
+                                       char *name = dpas_type_name(type);
+                                       dpas_error("`%s' is not a record type", name);
+                                       jit_free(name);
+                                       dpas_sem_set_error($$);
+                               }
+                               else
+                               {
+                                       dpas_sem_set_error($$);
+                               }
+                               jit_free($3);
                        }
        | Variable '^'                                          {
                                /* Dereference a pointer value */
index 56cafc806dda963f738a09e926b9c9747be3ec18..056daa5c6566c2f7c93885604852d65751184fa0 100644 (file)
@@ -220,6 +220,41 @@ unsigned int dpas_type_find_name(jit_type_t type, const char *name)
        return JIT_INVALID_NAME;
 }
 
+jit_type_t dpas_type_get_field(jit_type_t type, const char *name,
+                                                          jit_nint *offset)
+{
+       unsigned int field;
+       const char *fname;
+       jit_type_t field_type;
+       type = jit_type_normalize(type);
+       field = jit_type_num_fields(type);
+       while(field > 0)
+       {
+               --field;
+               fname = jit_type_get_name(type, field);
+               field_type = jit_type_get_field(type, field);
+               if(fname && !jit_stricmp(fname, name))
+               {
+                       *offset = jit_type_get_offset(type, field);
+                       return field_type;
+               }
+               else if(!fname)
+               {
+                       /* Probably a nested struct or union in a variant record */
+                       if(dpas_type_is_record(field_type))
+                       {
+                               field_type = dpas_type_get_field(field_type, name, offset);
+                               if(field_type != 0)
+                               {
+                                       *offset += jit_type_get_offset(type, field);
+                                       return field_type;
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
 /*
  * Concatenate two strings.
  */
index 295769c5b9b054177837dd8ef9de0999dbca698e..855d9134ccdc31c4be0c69eb5c7bdea850d62ed7 100644 (file)
@@ -101,6 +101,12 @@ void dpas_init_types(void);
  */
 unsigned int dpas_type_find_name(jit_type_t type, const char *name);
 
+/*
+ * Get the type and offset of a field within a record type.
+ */
+jit_type_t dpas_type_get_field(jit_type_t type, const char *name,
+                                                          jit_nint *offset);
+
 /*
  * Get the name of a type, for printing in error messages.
  */