Fix bug in make distcheck.
[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
28 int _get_day_num(const char* input);
29 int _get_year_num(Year_type ytype, const char* input1, const char* input2);
30   
31 %}
32
33 %union {
34   char *string;
35   struct date_value date_val;
36   struct date date;
37 }
38
39 %token <string> ESC_DATE_GREG
40 %token <string> ESC_DATE_JULN
41 %token <string> ESC_DATE_HEBR
42 %token <string> ESC_DATE_FREN
43 %token <string> MOD_FROM
44 %token <string> MOD_TO
45 %token <string> MOD_BEF
46 %token <string> MOD_AFT
47 %token <string> MOD_BET
48 %token <string> MOD_AND
49 %token <string> MOD_ABT
50 %token <string> MOD_CAL
51 %token <string> MOD_EST
52 %token <string> MOD_INT
53 %token <string> MON_JAN
54 %token <string> MON_FEB
55 %token <string> MON_MAR
56 %token <string> MON_APR
57 %token <string> MON_MAY
58 %token <string> MON_JUN
59 %token <string> MON_JUL
60 %token <string> MON_AUG
61 %token <string> MON_SEP
62 %token <string> MON_OCT
63 %token <string> MON_NOV
64 %token <string> MON_DEC
65 %token <string> MON_TSH
66 %token <string> MON_CSH
67 %token <string> MON_KSL
68 %token <string> MON_TVT
69 %token <string> MON_SHV
70 %token <string> MON_ADR
71 %token <string> MON_ADS
72 %token <string> MON_NSN
73 %token <string> MON_IYR
74 %token <string> MON_SVN
75 %token <string> MON_TMZ
76 %token <string> MON_AAV
77 %token <string> MON_ELL
78 %token <string> MON_VEND
79 %token <string> MON_BRUM
80 %token <string> MON_FRIM
81 %token <string> MON_NIVO
82 %token <string> MON_PLUV
83 %token <string> MON_VENT
84 %token <string> MON_GERM
85 %token <string> MON_FLOR
86 %token <string> MON_PRAI
87 %token <string> MON_MESS
88 %token <string> MON_THER
89 %token <string> MON_FRUC
90 %token <string> MON_COMP
91 %token <string> OPEN
92 %token <string> CLOSE
93 %token <string> TEXT
94 %token <string> NUMBER
95 %token <string> SLASH
96 %token <string> BADTOKEN
97
98 %type <date_val> date_value
99 %type <date_val> date_period
100 %type <date_val> date_range
101 %type <date_val> date_approx
102 %type <date_val> date_interpr
103 %type <string> date_phrase
104 %type <date> date
105
106 %%
107
108 date_value   : date           { make_date_value(DV_NO_MODIFIER,
109                                                 $1, def_date, ""); }
110              | date_period    
111              | date_range
112              | date_approx
113              | date_interpr
114              | date_phrase    { make_date_value(DV_PHRASE,
115                                                 def_date, def_date, $1); }
116              | /* empty */
117                {
118                  /* If empty string: return empty string in 'phrase'
119                     member as fallback */
120                  /* Note: this can only happen in compatibility mode */
121                  make_date_value(DV_PHRASE,
122                                  def_date, def_date, curr_line_value);
123                }
124              | error { /* On error: put entire string in 'phrase' member
125                           as fallback */
126                        make_date_value(DV_PHRASE,
127                                        def_date, def_date, curr_line_value);
128                      }
129              ;
130
131 date         : ESC_DATE_GREG date_greg { copy_date(&$$, date_s);
132                                          $$.cal = CAL_GREGORIAN; }
133              | ESC_DATE_JULN date_juln { copy_date(&$$, date_s);
134                                          $$.cal = CAL_JULIAN;  }
135              | ESC_DATE_HEBR date_hebr { copy_date(&$$, date_s);
136                                          $$.cal = CAL_HEBREW;  }
137              | ESC_DATE_FREN date_fren { copy_date(&$$, date_s);
138                                          $$.cal = CAL_FRENCH_REV;  }
139              | date_greg               { copy_date(&$$, date_s);
140                                          $$.cal = CAL_GREGORIAN;  }
141              ;
142
143 date_period  : MOD_FROM date   { make_date_value(DV_FROM,
144                                                  $2, def_date, ""); }
145              | MOD_TO date     { make_date_value(DV_TO,
146                                                  $2, def_date, ""); }
147              | MOD_FROM date   { copy_date(&$<date>$, $2); }
148                MOD_TO date
149                       { make_date_value(DV_FROM_TO, $<date>3, $5, ""); }
150              ;
151
152 date_range   : MOD_BEF date    { make_date_value(DV_BEFORE,
153                                                  $2, def_date, ""); }
154              | MOD_AFT date    { make_date_value(DV_AFTER,
155                                                  $2, def_date, ""); }
156              | MOD_BET date    { copy_date(&$<date>$, $2); }
157                MOD_AND date
158                       { make_date_value(DV_BETWEEN, $<date>3, $5, ""); }
159              ;
160
161 date_approx  : MOD_ABT date    { make_date_value(DV_ABOUT,
162                                                  $2, def_date, ""); }
163              | MOD_CAL date    { make_date_value(DV_CALCULATED,
164                                                  $2, def_date, ""); }
165              | MOD_EST date    { make_date_value(DV_ESTIMATED,
166                                                  $2, def_date, ""); }
167              ;
168
169 date_interpr : MOD_INT date date_phrase
170                  { make_date_value(DV_INTERPRETED, $2, def_date, $3); }
171              ;
172
173 date_phrase  : OPEN TEXT CLOSE { $$ = $2; }
174              ;
175
176 date_greg    : day month_greg year_greg
177              | month_greg year_greg
178              | year_greg
179              ;
180
181 date_juln    : day month_greg year
182              | month_greg year
183              | year
184              ;
185
186 date_hebr    : day month_hebr year
187              | month_hebr year
188              | year
189              ;
190
191 date_fren    : day month_fren year
192              | month_fren year
193              | year
194              ;
195
196 day          : NUMBER
197                {
198                  int d = _get_day_num($1);
199                  if (d != -1) {
200                    strcpy(date_s.day_str, $1);
201                    date_s.day = d;
202                  }
203                }
204              ;
205
206 month_greg   : MON_JAN { strcpy(date_s.month_str, $1);
207                          date_s.month = 1; }
208              | MON_FEB { strcpy(date_s.month_str, $1);
209                          date_s.month = 2; }
210              | MON_MAR { strcpy(date_s.month_str, $1);
211                          date_s.month = 3; }
212              | MON_APR { strcpy(date_s.month_str, $1);
213                          date_s.month = 4; }
214              | MON_MAY { strcpy(date_s.month_str, $1);
215                          date_s.month = 5; }
216              | MON_JUN { strcpy(date_s.month_str, $1);
217                          date_s.month = 6; }
218              | MON_JUL { strcpy(date_s.month_str, $1);
219                          date_s.month = 7; }
220              | MON_AUG { strcpy(date_s.month_str, $1);
221                          date_s.month = 8; }
222              | MON_SEP { strcpy(date_s.month_str, $1);
223                          date_s.month = 9; }
224              | MON_OCT { strcpy(date_s.month_str, $1);
225                          date_s.month = 10; }
226              | MON_NOV { strcpy(date_s.month_str, $1);
227                          date_s.month = 11; }
228              | MON_DEC { strcpy(date_s.month_str, $1);
229                          date_s.month = 12; }
230              ;
231
232 month_hebr   : MON_TSH { strcpy(date_s.month_str, $1);
233                          date_s.month = 1; }
234              | MON_CSH { strcpy(date_s.month_str, $1);
235                          date_s.month = 2; }
236              | MON_KSL { strcpy(date_s.month_str, $1);
237                          date_s.month = 3; }
238              | MON_TVT { strcpy(date_s.month_str, $1);
239                          date_s.month = 4; }
240              | MON_SHV { strcpy(date_s.month_str, $1);
241                          date_s.month = 5; }
242              | MON_ADR { strcpy(date_s.month_str, $1);
243                          date_s.month = 6; }
244              | MON_ADS { strcpy(date_s.month_str, $1);
245                          date_s.month = 7; }
246              | MON_NSN { strcpy(date_s.month_str, $1);
247                          date_s.month = 8; }
248              | MON_IYR { strcpy(date_s.month_str, $1);
249                          date_s.month = 9; }
250              | MON_SVN { strcpy(date_s.month_str, $1);
251                          date_s.month = 10; }
252              | MON_TMZ { strcpy(date_s.month_str, $1);
253                          date_s.month = 11; }
254              | MON_AAV { strcpy(date_s.month_str, $1);
255                          date_s.month = 12; }
256              | MON_ELL { strcpy(date_s.month_str, $1);
257                          date_s.month = 13; }
258              ;
259
260 month_fren   : MON_VEND { strcpy(date_s.month_str, $1);
261                          date_s.month = 1; }
262              | MON_BRUM { strcpy(date_s.month_str, $1);
263                          date_s.month = 2; }
264              | MON_FRIM { strcpy(date_s.month_str, $1);
265                          date_s.month = 3; }
266              | MON_NIVO { strcpy(date_s.month_str, $1);
267                          date_s.month = 4; }
268              | MON_PLUV { strcpy(date_s.month_str, $1);
269                          date_s.month = 5; }
270              | MON_VENT { strcpy(date_s.month_str, $1);
271                          date_s.month = 6; }
272              | MON_GERM { strcpy(date_s.month_str, $1);
273                          date_s.month = 7; }
274              | MON_FLOR { strcpy(date_s.month_str, $1);
275                          date_s.month = 8; }
276              | MON_PRAI { strcpy(date_s.month_str, $1);
277                          date_s.month = 9; }
278              | MON_MESS { strcpy(date_s.month_str, $1);
279                          date_s.month = 10; }
280              | MON_THER { strcpy(date_s.month_str, $1);
281                          date_s.month = 11; }
282              | MON_FRUC { strcpy(date_s.month_str, $1);
283                          date_s.month = 12; }
284              | MON_COMP { strcpy(date_s.month_str, $1);
285                          date_s.month = 13; }
286              ;
287
288 year         : NUMBER
289                  { int y = _get_year_num(YEAR_SINGLE, $1, NULL);
290                    if (y != -1) {
291                      strcpy(date_s.year_str, $1);
292                      date_s.year = y;
293                      date_s.year_type = YEAR_SINGLE;
294                    }
295                  }
296              ;
297
298 year_greg    : NUMBER
299                  { int y = _get_year_num(YEAR_SINGLE, $1, NULL);
300                    if (y != -1) {
301                      strcpy(date_s.year_str, $1);
302                      date_s.year = y;
303                      date_s.year_type = YEAR_SINGLE;
304                    }
305                  }
306              | NUMBER SLASH NUMBER
307                  { int y = _get_year_num(YEAR_DOUBLE, $1, $3);
308                    if (y != 1) {
309                      sprintf(date_s.year_str, "%s/%s", $1, $3);
310                      date_s.year = y;
311                      date_s.year_type = YEAR_DOUBLE;
312                    }
313                  }
314              ;
315
316 %%
317
318 int _get_day_num(const char* input)
319 {
320   if (strlen(input) <= MAX_DAY_LEN)
321     return atoi(input);
322   else {
323     gedcom_date_error(_("Too many characters in day '%s'"), input);
324     return -1;
325   }
326 }
327
328 int get_day_num(const char* input)
329 {
330   int token = get_date_token(input);
331   if (token == NUMBER)
332     return _get_day_num(input);
333   else {
334     gedcom_date_error(_("Not a valid day number: '%s'"), input);
335     return -1;
336   }
337 }
338
339 int begin_month[] =
340 { /* CAL_GREGORIAN */   MON_JAN,
341   /* CAL_JULIAN */      MON_JAN,
342   /* CAL_HEBREW */      MON_TSH,
343   /* CAL_FRENCH_REV */  MON_VEND
344 };
345
346 int end_month[] =
347 { /* CAL_GREGORIAN */   MON_DEC,
348   /* CAL_JULIAN */      MON_DEC,
349   /* CAL_HEBREW */      MON_ELL,
350   /* CAL_FRENCH_REV */  MON_COMP
351 };
352
353 int get_month_num(Calendar_type cal, const char* input)
354 {
355   int token = get_date_token(input);
356   if (token >= begin_month[cal] && token <= end_month[cal])
357     return token - begin_month[cal] + 1;
358   else {
359     gedcom_date_error(_("Not a valid month for the given calendar: '%s'"),
360                       input);
361     return -1;
362   }
363 }
364
365 int _get_year_num(Year_type ytype, const char* input1, const char* input2)
366 {
367   if (ytype == YEAR_SINGLE) {
368     if (strlen(input1) <= MAX_YEAR_LEN) {
369       return atoi(input1);
370     }
371     else {
372       gedcom_date_error(_("Too many characters in year '%s'"), input1);
373       return -1;
374     }
375   }
376   else {
377     if (strlen(input1) + strlen(input2) + 1 <= MAX_YEAR_LEN) {
378       return atoi(input1) + 1;
379     }
380     else {
381       gedcom_date_error(_("Too many characters in year '%s/%s'"),
382                         input1, input2);
383       return -1;
384     }
385   }
386 }
387
388 int get_year_num(const char* input, Year_type* ytype)
389 {
390   char *year1, *year2 = NULL;
391   int numtok = get_year_tokens(input, &year1, &year2);
392   if (numtok) {
393     *ytype = (numtok == 1 ? YEAR_SINGLE : YEAR_DOUBLE);
394     return _get_year_num (*ytype, year1, year2);
395   }
396   else {
397     gedcom_date_error(_("Not a valid year: '%s'"), input); 
398     return -1;
399   }
400 }