Copied from old documentation. Removed all Gedcom_val details.
[gedcom-parse.git] / gedcom / gedcom_date.y
1 /* Parser for Gedcom dates.
2    Copyright (C) 2001 The Genes Development Team
3    This file is part of the Gedcom parser library.
4    Contributed by Peter Verthez <Peter.Verthez@advalvas.be>, 2001.
5
6    The Gedcom parser library is free software; you can redistribute it
7    and/or modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The Gedcom parser library is distributed in the hope that it will be
12    useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the Gedcom parser library; if not, write to the
18    Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 /* $Id$ */
22 /* $Name$ */
23
24 %{
25 #include <stdlib.h>
26 #include "date.h"
27 #include "compat.h"
28
29 int _get_day_num(const char* input);
30 int _get_year_num(Year_type ytype, const char* input1, const char* input2);
31 void error_missing_year();
32 void error_missing_month(); 
33   
34 %}
35
36 %union {
37   char *string;
38   struct date_value date_val;
39   struct date date;
40 }
41
42 %token <string> ESC_DATE_GREG
43 %token <string> ESC_DATE_JULN
44 %token <string> ESC_DATE_HEBR
45 %token <string> ESC_DATE_FREN
46 %token <string> MOD_FROM
47 %token <string> MOD_TO
48 %token <string> MOD_BEF
49 %token <string> MOD_AFT
50 %token <string> MOD_BET
51 %token <string> MOD_AND
52 %token <string> MOD_ABT
53 %token <string> MOD_CAL
54 %token <string> MOD_EST
55 %token <string> MOD_INT
56 %token <string> MON_JAN
57 %token <string> MON_FEB
58 %token <string> MON_MAR
59 %token <string> MON_APR
60 %token <string> MON_MAY
61 %token <string> MON_JUN
62 %token <string> MON_JUL
63 %token <string> MON_AUG
64 %token <string> MON_SEP
65 %token <string> MON_OCT
66 %token <string> MON_NOV
67 %token <string> MON_DEC
68 %token <string> MON_TSH
69 %token <string> MON_CSH
70 %token <string> MON_KSL
71 %token <string> MON_TVT
72 %token <string> MON_SHV
73 %token <string> MON_ADR
74 %token <string> MON_ADS
75 %token <string> MON_NSN
76 %token <string> MON_IYR
77 %token <string> MON_SVN
78 %token <string> MON_TMZ
79 %token <string> MON_AAV
80 %token <string> MON_ELL
81 %token <string> MON_VEND
82 %token <string> MON_BRUM
83 %token <string> MON_FRIM
84 %token <string> MON_NIVO
85 %token <string> MON_PLUV
86 %token <string> MON_VENT
87 %token <string> MON_GERM
88 %token <string> MON_FLOR
89 %token <string> MON_PRAI
90 %token <string> MON_MESS
91 %token <string> MON_THER
92 %token <string> MON_FRUC
93 %token <string> MON_COMP
94 %token <string> OPEN
95 %token <string> CLOSE
96 %token <string> TEXT
97 %token <string> NUMBER
98 %token <string> SLASH
99 %token <string> BADTOKEN
100
101 %type <date_val> date_value
102 %type <date_val> date_period
103 %type <date_val> date_range
104 %type <date_val> date_approx
105 %type <date_val> date_interpr
106 %type <string> date_phrase
107 %type <date> date
108
109 %%
110
111 date_value   : date           { make_date_value(DV_NO_MODIFIER,
112                                                 &$1, &def_date, ""); }
113              | date_period    
114              | date_range
115              | date_approx
116              | date_interpr
117              | date_phrase    { make_date_value(DV_PHRASE,
118                                                 &def_date, &def_date, $1); }
119              | /* empty */
120                {
121                  /* If empty string: return empty string in 'phrase'
122                     member as fallback */
123                  /* Note: this can only happen in compatibility mode */
124                  make_date_value(DV_PHRASE,
125                                  &def_date, &def_date, curr_line_value);
126                }
127              | error { /* On error: put entire string in 'phrase' member
128                           as fallback */
129                        gedcom_date_error(_("Putting date '%s' in 'phrase' member"), curr_line_value);
130                        make_date_value(DV_PHRASE,
131                                        &def_date, &def_date, curr_line_value);
132                        YYABORT;
133                      }
134              ;
135
136 date         : ESC_DATE_GREG date_greg { copy_date(&$$, &date_s);
137                                          $$.cal = CAL_GREGORIAN; }
138              | ESC_DATE_JULN date_juln { copy_date(&$$, &date_s);
139                                          $$.cal = CAL_JULIAN;  }
140              | ESC_DATE_HEBR date_hebr { copy_date(&$$, &date_s);
141                                          $$.cal = CAL_HEBREW;  }
142              | ESC_DATE_FREN date_fren { copy_date(&$$, &date_s);
143                                          $$.cal = CAL_FRENCH_REV;  }
144              | date_greg               { copy_date(&$$, &date_s);
145                                          $$.cal = CAL_GREGORIAN;  }
146              ;
147
148 date_period  : MOD_FROM date   { make_date_value(DV_FROM,
149                                                  &$2, &def_date, ""); }
150              | MOD_TO date     { make_date_value(DV_TO,
151                                                  &$2, &def_date, ""); }
152              | MOD_FROM date   { copy_date(&$<date>$, &$2); }
153                MOD_TO date
154                       { make_date_value(DV_FROM_TO, &$<date>3, &$5, ""); }
155              ;
156
157 date_range   : MOD_BEF date    { make_date_value(DV_BEFORE,
158                                                  &$2, &def_date, ""); }
159              | MOD_AFT date    { make_date_value(DV_AFTER,
160                                                  &$2, &def_date, ""); }
161              | MOD_BET date    { copy_date(&$<date>$, &$2); }
162                MOD_AND date
163                       { make_date_value(DV_BETWEEN, &$<date>3, &$5, ""); }
164              ;
165
166 date_approx  : MOD_ABT date    { make_date_value(DV_ABOUT,
167                                                  &$2, &def_date, ""); }
168              | MOD_CAL date    { make_date_value(DV_CALCULATED,
169                                                  &$2, &def_date, ""); }
170              | MOD_EST date    { make_date_value(DV_ESTIMATED,
171                                                  &$2, &def_date, ""); }
172              ;
173
174 date_interpr : MOD_INT date date_phrase
175                  { make_date_value(DV_INTERPRETED, &$2, &def_date, $3); }
176              ;
177
178 date_phrase  : OPEN TEXT CLOSE { $$ = $2; }
179              ;
180
181 date_greg    : day month_greg year_greg
182              | month_greg year_greg
183              | year_greg
184              | day month_greg { error_missing_year(); YYERROR; }
185              | month_greg     { error_missing_year(); YYERROR; }
186              | day year_greg  { error_missing_month(); YYERROR; }
187              ;
188
189 date_juln    : day month_greg year
190              | month_greg year
191              | year
192              | day month_greg { error_missing_year(); YYERROR; }
193              | month_greg     { error_missing_year(); YYERROR; }
194              | day year_greg  { error_missing_month(); YYERROR; }
195              ;
196
197 date_hebr    : day month_hebr year
198              | month_hebr year
199              | year
200              | day month_hebr { error_missing_year(); YYERROR; }
201              | month_hebr     { error_missing_year(); YYERROR; }
202              | day year       { error_missing_month(); YYERROR; }
203              ;
204
205 date_fren    : day month_fren year
206              | month_fren year
207              | year
208              | day month_hebr { error_missing_year(); YYERROR; }
209              | month_hebr     { error_missing_year(); YYERROR; }
210              | day year       { error_missing_month(); YYERROR; }
211              ;
212
213 day          : NUMBER
214                {
215                  int d = _get_day_num($1);
216                  if (d != -1) {
217                    strcpy(date_s.day_str, $1);
218                    date_s.day = d;
219                  }
220                  else YYERROR;
221                }
222              ;
223
224 month_greg   : MON_JAN { strcpy(date_s.month_str, $1);
225                          date_s.month = 1; }
226              | MON_FEB { strcpy(date_s.month_str, $1);
227                          date_s.month = 2; }
228              | MON_MAR { strcpy(date_s.month_str, $1);
229                          date_s.month = 3; }
230              | MON_APR { strcpy(date_s.month_str, $1);
231                          date_s.month = 4; }
232              | MON_MAY { strcpy(date_s.month_str, $1);
233                          date_s.month = 5; }
234              | MON_JUN { strcpy(date_s.month_str, $1);
235                          date_s.month = 6; }
236              | MON_JUL { strcpy(date_s.month_str, $1);
237                          date_s.month = 7; }
238              | MON_AUG { strcpy(date_s.month_str, $1);
239                          date_s.month = 8; }
240              | MON_SEP { strcpy(date_s.month_str, $1);
241                          date_s.month = 9; }
242              | MON_OCT { strcpy(date_s.month_str, $1);
243                          date_s.month = 10; }
244              | MON_NOV { strcpy(date_s.month_str, $1);
245                          date_s.month = 11; }
246              | MON_DEC { strcpy(date_s.month_str, $1);
247                          date_s.month = 12; }
248              ;
249
250 month_hebr   : MON_TSH { strcpy(date_s.month_str, $1);
251                          date_s.month = 1; }
252              | MON_CSH { strcpy(date_s.month_str, $1);
253                          date_s.month = 2; }
254              | MON_KSL { strcpy(date_s.month_str, $1);
255                          date_s.month = 3; }
256              | MON_TVT { strcpy(date_s.month_str, $1);
257                          date_s.month = 4; }
258              | MON_SHV { strcpy(date_s.month_str, $1);
259                          date_s.month = 5; }
260              | MON_ADR { strcpy(date_s.month_str, $1);
261                          date_s.month = 6; }
262              | MON_ADS { strcpy(date_s.month_str, $1);
263                          date_s.month = 7; }
264              | MON_NSN { strcpy(date_s.month_str, $1);
265                          date_s.month = 8; }
266              | MON_IYR { strcpy(date_s.month_str, $1);
267                          date_s.month = 9; }
268              | MON_SVN { strcpy(date_s.month_str, $1);
269                          date_s.month = 10; }
270              | MON_TMZ { strcpy(date_s.month_str, $1);
271                          date_s.month = 11; }
272              | MON_AAV { strcpy(date_s.month_str, $1);
273                          date_s.month = 12; }
274              | MON_ELL { strcpy(date_s.month_str, $1);
275                          date_s.month = 13; }
276              ;
277
278 month_fren   : MON_VEND { strcpy(date_s.month_str, $1);
279                          date_s.month = 1; }
280              | MON_BRUM { strcpy(date_s.month_str, $1);
281                          date_s.month = 2; }
282              | MON_FRIM { strcpy(date_s.month_str, $1);
283                          date_s.month = 3; }
284              | MON_NIVO { strcpy(date_s.month_str, $1);
285                          date_s.month = 4; }
286              | MON_PLUV { strcpy(date_s.month_str, $1);
287                          date_s.month = 5; }
288              | MON_VENT { strcpy(date_s.month_str, $1);
289                          date_s.month = 6; }
290              | MON_GERM { strcpy(date_s.month_str, $1);
291                          date_s.month = 7; }
292              | MON_FLOR { strcpy(date_s.month_str, $1);
293                          date_s.month = 8; }
294              | MON_PRAI { strcpy(date_s.month_str, $1);
295                          date_s.month = 9; }
296              | MON_MESS { strcpy(date_s.month_str, $1);
297                          date_s.month = 10; }
298              | MON_THER { strcpy(date_s.month_str, $1);
299                          date_s.month = 11; }
300              | MON_FRUC { strcpy(date_s.month_str, $1);
301                          date_s.month = 12; }
302              | MON_COMP { strcpy(date_s.month_str, $1);
303                          date_s.month = 13; }
304              ;
305
306 year         : NUMBER
307                  { int y = _get_year_num(YEAR_SINGLE, $1, NULL);
308                    if (y != -1) {
309                      strcpy(date_s.year_str, $1);
310                      date_s.year = y;
311                      date_s.year_type = YEAR_SINGLE;
312                    }
313                    else YYERROR;
314                  }
315              ;
316
317 year_greg    : NUMBER
318                  { int y = _get_year_num(YEAR_SINGLE, $1, NULL);
319                    if (y != -1) {
320                      strcpy(date_s.year_str, $1);
321                      date_s.year = y;
322                      date_s.year_type = YEAR_SINGLE;
323                    }
324                    else YYERROR;
325                  }
326              | NUMBER SLASH NUMBER
327                  { if (compat_double_date_check($3)) {
328                      safe_buf_append(&compat_buffer, "BET %s AND %s",
329                                      $1, $3);
330                    }
331                    else {
332                      int y = _get_year_num(YEAR_DOUBLE, $1, $3);
333                      if (y != -1) {
334                        sprintf(date_s.year_str, "%d/%02d", y-1, y%100);
335                        date_s.year = y;
336                        date_s.year_type = YEAR_DOUBLE;
337                      }
338                      else YYERROR;
339                    }
340                  }
341              ;
342
343 %%
344
345 void error_missing_year()
346 {
347   gedcom_date_error(_("Year is missing: '%s'"),
348                     curr_line_value);
349 }
350
351 void error_missing_month()
352 {
353   gedcom_date_error(_("Month is missing: '%s'"),
354                     curr_line_value);
355 }
356
357 int _get_day_num(const char* input)
358 {
359   if (strlen(input) <= MAX_DAY_LEN)
360     return atoi(input);
361   else {
362     gedcom_date_error(_("Too many characters in day '%s'"), input);
363     return -1;
364   }
365 }
366
367 int get_day_num(const char* input)
368 {
369   int token = get_date_token(input);
370   if (token == NUMBER)
371     return _get_day_num(input);
372   else {
373     gedcom_date_error(_("Not a valid day number: '%s'"), input);
374     return -1;
375   }
376 }
377
378 int begin_month[] =
379 { /* CAL_GREGORIAN */   MON_JAN,
380   /* CAL_JULIAN */      MON_JAN,
381   /* CAL_HEBREW */      MON_TSH,
382   /* CAL_FRENCH_REV */  MON_VEND
383 };
384
385 int end_month[] =
386 { /* CAL_GREGORIAN */   MON_DEC,
387   /* CAL_JULIAN */      MON_DEC,
388   /* CAL_HEBREW */      MON_ELL,
389   /* CAL_FRENCH_REV */  MON_COMP
390 };
391
392 int get_month_num(Calendar_type cal, const char* input)
393 {
394   int token = get_date_token(input);
395   if (token >= begin_month[cal] && token <= end_month[cal])
396     return token - begin_month[cal] + 1;
397   else {
398     gedcom_date_error(_("Not a valid month for the given calendar: '%s'"),
399                       input);
400     return -1;
401   }
402 }
403
404 int _get_year_num(Year_type ytype, const char* input1, const char* input2)
405 {
406   if (ytype == YEAR_SINGLE) {
407     if (strlen(input1) <= MAX_YEAR_LEN) {
408       return atoi(input1);
409     }
410     else {
411       gedcom_date_error(_("Too many characters in year '%s'"), input1);
412       return -1;
413     }
414   }
415   else {
416     if (strlen(input2) != 2) {
417       gedcom_date_error(_("Year after slash should be two digits: '%s/%s'"),
418                         input1, input2);
419       return -1;
420     }
421     if (strlen(input1) <= MAX_YEAR_LEN - 3) {
422       int year1 = atoi(input1) + 1;
423       int year2 = atoi(input2);
424       if (year1 % 100 != year2) {
425         gedcom_date_error(_("Year after slash should be following year: '%s/%s'"),
426                           input1, input2);
427         return -1;
428       }
429       else 
430         return year1;
431     }
432     else {
433       gedcom_date_error(_("Too many characters in year '%s/%s'"),
434                         input1, input2);
435       return -1;
436     }
437   }
438 }
439
440 int get_year_num(const char* input, Year_type* ytype)
441 {
442   char *year1, *year2 = NULL;
443   int numtok = get_year_tokens(input, &year1, &year2);
444   if (numtok) {
445     *ytype = (numtok == 1 ? YEAR_SINGLE : YEAR_DOUBLE);
446     return _get_year_num (*ytype, year1, year2);
447   }
448   else {
449     gedcom_date_error(_("Not a valid year: '%s'"), input); 
450     return -1;
451   }
452 }