Use XREF_ANY for an association, instead of XREF_INDI.
[gedcom-parse.git] / gedcom / gedcom.y
index fcffbd4dbffc70a429561e27e5c4b1713e455be0..44613d991e52eb560bbcec9a6176e68f8a1fb35f 100644 (file)
 #include "encoding.h"
 #include "interface.h"
 #include "date.h"
+#include "age.h"
 #include "xref.h"
+#include "compat.h"
 
 int  count_level    = 0;
 int  fail           = 0;
-int  compat_enabled = 1;
 int  gedcom_high_level_debug = 0; 
-int  compatibility  = 0; 
 Gedcom_err_mech error_mechanism = IMMED_FAIL;
 Gedcom_val_struct val1;
 Gedcom_val_struct val2; 
@@ -160,21 +160,15 @@ Gedcom_val_struct val2;
 char line_item_buf[MAXGEDCLINELEN * UTF_FACTOR + 1];
 char *line_item_buf_ptr;
 
-enum _COMPAT {
-  C_FTREE = 0x01
-};
-
 /* These are defined at the bottom of the file */ 
 void push_countarray();
 void set_parenttag(char* tag);
-char* get_parenttag(); 
+char* get_parenttag(int offset); 
 void set_parentctxt(Gedcom_ctxt ctxt);
-Gedcom_ctxt get_parentctxt();
+Gedcom_ctxt get_parentctxt(int offset);
 void pop_countarray();
 int  count_tag(int tag);
 int  check_occurrence(int tag);
-void set_compatibility(char* program);
-int  compat_mode(int flags); 
 
 #define CLEAR_BUFFER(BUF)                                                     \
      memset(BUF, 0, sizeof(BUF));
@@ -203,15 +197,17 @@ int  compat_mode(int flags);
        START2(PARENTCTXT);                                                    \
      }
 #define PARENT                                                                \
-     get_parentctxt()
+     get_parentctxt(0)
+#define GRANDPARENT(OFF)                                                      \
+     get_parentctxt(OFF)
 #define CHK(TAG)                                                              \
      { if (!check_occurrence(TAG_##TAG)) {                                    \
-         char* parenttag = get_parenttag();                                   \
+         char* parenttag = get_parenttag(0);                                  \
          gedcom_error(_("The tag '%s' is mandatory within '%s', but missing"),\
                      #TAG, parenttag);                                       \
          HANDLE_ERROR;                                                        \
        }                                                                      \
-     }
+     } 
 #define POP                                                                   \
      { pop_countarray();                                                      \
        --count_level;                                                         \
@@ -228,14 +224,14 @@ int  compat_mode(int flags);
 #define OCCUR2(CHILDTAG, MIN, MAX)                                            \
      { int num = count_tag(TAG_##CHILDTAG);                                   \
        if (num > MAX) {                                                       \
-         char* parenttag = get_parenttag();                                   \
+         char* parenttag = get_parenttag(0);                                  \
          gedcom_error(_("The tag '%s' can maximally occur %d time(s) within '%s'"),                                                                          \
                      #CHILDTAG, MAX, parenttag);                             \
          HANDLE_ERROR;                                                        \
        }                                                                      \
      }
 #define INVALID_TAG(CHILDTAG)                                                 \
-     { char* parenttag = get_parenttag();                                     \
+     { char* parenttag = get_parenttag(0);                                    \
        gedcom_error(_("The tag '%s' is not a valid tag within '%s'"),         \
                    CHILDTAG, parenttag);                                     \
        HANDLE_ERROR;                                                          \
@@ -256,7 +252,7 @@ int  compat_mode(int flags);
 }
 
 %token_table
-%expect 300
+%expect 304
 
 %token <string> BADTOKEN
 %token <number> OPEN
@@ -417,6 +413,8 @@ int  compat_mode(int flags);
 
 file        : head_sect records trlr_sect
                { if (fail == 1) YYABORT; }
+            | error
+               {  }
             ;
 
 records     : /* empty */
@@ -443,13 +441,24 @@ head_sect    : OPEN DELIM TAG_HEAD
                                         NULL, GEDCOM_MAKE_NULL(val2));
                 START(HEAD, $<ctxt>$) }
                head_subs
-               { if (compat_mode(C_FTREE))
-                  CHECK3(SOUR, GEDC, CHAR)
+               { if (compat_mode(C_FTREE)) {
+                  CHECK3(SOUR, GEDC, CHAR);
+                  compat_generate_submitter_link($<ctxt>4);
+                }
+                else if (compat_mode(C_LIFELINES)) {
+                  CHECK1(SOUR);
+                  compat_generate_submitter_link($<ctxt>4);
+                  compat_generate_gedcom($<ctxt>4);
+                  if (compat_generate_char($<ctxt>4)) YYABORT;
+                }
                 else
                   CHECK4(SOUR, SUBM, GEDC, CHAR)
               }
                CLOSE
-               { end_record(REC_HEAD, $<ctxt>4); }
+               { end_record(REC_HEAD, $<ctxt>4);
+                if (compat_mode(C_FTREE | C_LIFELINES))
+                  compat_generate_submitter();
+              }
              ;
 
 head_subs    : /* empty */
@@ -459,6 +468,9 @@ head_subs    : /* empty */
 head_sub     : head_sour_sect  { OCCUR2(SOUR, 1, 1) }
              | head_dest_sect  { OCCUR2(DEST, 0, 1) }
              | head_date_sect  { OCCUR2(DATE, 0, 1) }
+             | head_time_sect  { if (!compat_mode(C_LIFELINES))
+                                 INVALID_TAG("TIME");
+                                OCCUR2(TIME, 0, 1) }
              | head_subm_sect  { OCCUR2(SUBM, 1, 1) }
              | head_subn_sect  { OCCUR2(SUBN, 0, 1) }
              | head_file_sect  { OCCUR2(FILE, 0, 1) }
@@ -650,6 +662,13 @@ head_date_time_sect : OPEN DELIM TAG_TIME mand_line_item
                      }
                     ;
 
+/* HEAD.TIME (Only for 'Lifelines' compatibility) */
+/* Just ignore the time... */
+head_time_sect : OPEN DELIM TAG_TIME opt_line_item
+                 { }
+                 CLOSE
+              ;
+
 /* HEAD.SUBM */
 head_subm_sect : OPEN DELIM TAG_SUBM mand_pointer
                  { struct xref_value *xr = gedcom_parse_xref($4, XREF_USED,
@@ -1166,7 +1185,51 @@ indi_afn_sect  : OPEN DELIM TAG_AFN mand_line_item
 
 /* INDI.ADDR (Only for 'ftree' compatibility) */
 ftree_addr_sect : OPEN DELIM TAG_ADDR opt_line_item
-                  { START(ADDR, NULL) } no_std_subs { CHECK0 } CLOSE { }
+                  { if (compat_mode(C_FTREE)) {
+                     Gedcom_ctxt par = compat_generate_resi_start(PARENT);
+                     START(RESI, par);
+                     $<ctxt>$
+                       = start_element(ELT_SUB_ADDR,
+                                       par, $1 + 1, $3, $4,
+                                       GEDCOM_MAKE_NULL_OR_STRING(val2, $4));
+                     START(ADDR, $<ctxt>$);
+                   }
+                 else { START(ADDR, NULL) }
+                 }
+                  ftree_addr_subs
+                  { CHECK0 }
+                  CLOSE
+                  { if (compat_mode(C_FTREE)) {
+                     Gedcom_ctxt par = PARENT;
+                     end_element(ELT_SUB_ADDR, par, $<ctxt>5, NULL);
+                     CHECK0;
+                     compat_generate_resi_end(PARENT, par);
+                   } 
+                 }
+
+ftree_addr_subs : /* empty */
+                | ftree_addr_subs ftree_addr_sub
+                ;
+
+ftree_addr_sub  : continuation_sub
+                | ftree_addr_phon_sect
+                | no_std_sub
+                ;
+
+ftree_addr_phon_sect : OPEN DELIM TAG_PHON mand_line_item              
+                       { $<ctxt>$
+                          = start_element(ELT_SUB_PHON,
+                                          GRANDPARENT(1), $1, $3, $4, 
+                                          GEDCOM_MAKE_STRING(val1, $4));
+                        START(PHON, $<ctxt>$)               
+                      }               
+                       no_std_subs               
+                       { CHECK0 }               
+                       CLOSE               
+                       { end_element(ELT_SUB_PHON, GRANDPARENT(1),
+                                    $<ctxt>5, NULL);
+                      }
+            ;
 
 /*********************************************************************/
 /**** Multimedia record                                           ****/
@@ -1746,7 +1809,7 @@ subm_subs  : /* empty */
            | subm_subs subm_sub
            ;
 
-subm_sub   : subm_name_sect  { OCCUR2(NAME, 0, 1) }
+subm_sub   : subm_name_sect  { OCCUR2(NAME, 1, 1) }
            | addr_struc_sub  /* 0:1 */
            | multim_link_sub  /* 0:M */
            | subm_lang_sect  { OCCUR2(LANG, 0, 3) }
@@ -1952,7 +2015,7 @@ assoc_struc_sub : asso_sect /* 0:M */
 
 asso_sect : OPEN DELIM TAG_ASSO mand_pointer
             { struct xref_value *xr = gedcom_parse_xref($4, XREF_USED,
-                                                       XREF_INDI);
+                                                       XREF_ANY);
              if (xr == NULL) HANDLE_ERROR;
              $<ctxt>$ = start_element(ELT_SUB_ASSO,
                                       PARENT, $1, $3, $4, 
@@ -2179,10 +2242,11 @@ event_detail_date_sect : OPEN DELIM TAG_DATE mand_line_item
                         }
                        ;
 event_detail_age_sect  : OPEN DELIM TAG_AGE mand_line_item 
-                         { $<ctxt>$
+                         { struct age_value age = gedcom_parse_age($4);
+                          $<ctxt>$
                             = start_element(ELT_SUB_EVT_AGE,
                                             PARENT, $1, $3, $4, 
-                                            GEDCOM_MAKE_STRING(val1, $4));
+                                            GEDCOM_MAKE_AGE(val1, age));
                           START(AGE, $<ctxt>$)  
                          }  
                          no_std_subs  
@@ -2285,9 +2349,10 @@ fam_even_husb_sub : fam_even_age_sect  { OCCUR2(AGE, 1, 1) }
                   ;
 
 fam_even_age_sect : OPEN DELIM TAG_AGE mand_line_item  
-                    { $<ctxt>$ = start_element(ELT_SUB_FAM_EVT_AGE,
+                    { struct age_value age = gedcom_parse_age($4);
+                     $<ctxt>$ = start_element(ELT_SUB_FAM_EVT_AGE,
                                               PARENT, $1, $3, $4,
-                                              GEDCOM_MAKE_STRING(val1, $4));
+                                              GEDCOM_MAKE_AGE(val1, age));
                      START(AGE, $<ctxt>$)   
                     }   
                     no_std_subs   
@@ -3491,12 +3556,21 @@ mand_pointer : /* empty */ { gedcom_error(_("Missing pointer")); YYERROR; }
                                $$ = $2; }
              ;
 
-mand_line_item : /* empty */ { gedcom_error(_("Missing value")); YYERROR; }
+mand_line_item : /* empty */
+                 { if (compat_mode(C_LIFELINES)) {
+                     /* Lifelines tends to not care about mandatory values */
+                    gedcom_debug_print("==Val: ==");
+                    $$ = "";
+                  }
+                  else {
+                    gedcom_error(_("Missing value")); YYERROR;
+                  }
+                }
                | DELIM line_item { gedcom_debug_print("==Val: %s==", $2);
                                    $$ = $2; }
                ;
 
-opt_line_item : /* empty */ { }
+opt_line_item : /* empty */     { $$ = NULL; }
               | DELIM line_item { gedcom_debug_print("==Val: %s==", $2);
                                  $$ = $2; }
               ;
@@ -3548,7 +3622,7 @@ error_subs  : /* empty */
 error_sect  : OPEN DELIM opt_xref anytag opt_value error_subs CLOSE { }
 
 gen_sect    : OPEN DELIM opt_xref anystdtag
-              { INVALID_TAG($4); }
+              { INVALID_TAG($4.string); }
               opt_value opt_sects CLOSE
               { }
             ;
@@ -3558,7 +3632,7 @@ gen_rec : gen_rec_top
         ;
 
 gen_rec_norm : OPEN DELIM opt_xref anystdtag
-               { INVALID_TOP_TAG($4) }
+               { INVALID_TOP_TAG($4.string) }
                opt_value opt_sects CLOSE
                { }
              ;
@@ -3752,14 +3826,14 @@ void set_parentctxt(Gedcom_ctxt ctxt)
   ctxt_stack[count_level+1] = ctxt;
 }
 
-char* get_parenttag()
+char* get_parenttag(int offset)
 {
-  return tag_stack[count_level];
+  return tag_stack[count_level - offset];
 }
 
-Gedcom_ctxt get_parentctxt()
+Gedcom_ctxt get_parentctxt(int offset)
 {
-  return ctxt_stack[count_level];
+  return ctxt_stack[count_level - offset];
 }
 
 int count_tag(int tag)
@@ -3828,29 +3902,3 @@ void gedcom_set_error_handling(Gedcom_err_mech mechanism)
 {
   error_mechanism = mechanism;
 }
-
-/* Compatibility handling */
-
-void gedcom_set_compat_handling(int enable_compat)
-{
-  compat_enabled = enable_compat;
-}
-
-void set_compatibility(char* program)
-{
-  if (compat_enabled) {
-    if (! strncmp(program, "ftree", 6)) {
-      gedcom_warning(_("Enabling compatibility with 'ftree'"));
-      compatibility = C_FTREE;
-    }
-    else {
-      compatibility = 0;
-    }
-  }
-}
-
-int compat_mode(int compat_flags)
-{
-  return (compat_flags & compatibility);
-}
-