Added graceful fallback for date parse errors: put everything as a
[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
29 %union {
30   char *string;
31   struct date_value date_val;
32   struct date date;
33 }
34
35 %token <string> ESC_DATE_GREG
36 %token <string> ESC_DATE_JULN
37 %token <string> ESC_DATE_HEBR
38 %token <string> ESC_DATE_FREN
39 %token <string> MOD_FROM
40 %token <string> MOD_TO
41 %token <string> MOD_BEF
42 %token <string> MOD_AFT
43 %token <string> MOD_BET
44 %token <string> MOD_AND
45 %token <string> MOD_ABT
46 %token <string> MOD_CAL
47 %token <string> MOD_EST
48 %token <string> MOD_INT
49 %token <string> MON_JAN
50 %token <string> MON_FEB
51 %token <string> MON_MAR
52 %token <string> MON_APR
53 %token <string> MON_MAY
54 %token <string> MON_JUN
55 %token <string> MON_JUL
56 %token <string> MON_AUG
57 %token <string> MON_SEP
58 %token <string> MON_OCT
59 %token <string> MON_NOV
60 %token <string> MON_DEC
61 %token <string> MON_TSH
62 %token <string> MON_CSH
63 %token <string> MON_KSL
64 %token <string> MON_TVT
65 %token <string> MON_SHV
66 %token <string> MON_ADR
67 %token <string> MON_ADS
68 %token <string> MON_NSN
69 %token <string> MON_IYR
70 %token <string> MON_SVN
71 %token <string> MON_TMZ
72 %token <string> MON_AAV
73 %token <string> MON_ELL
74 %token <string> MON_VEND
75 %token <string> MON_BRUM
76 %token <string> MON_FRIM
77 %token <string> MON_NIVO
78 %token <string> MON_PLUV
79 %token <string> MON_VENT
80 %token <string> MON_GERM
81 %token <string> MON_FLOR
82 %token <string> MON_PRAI
83 %token <string> MON_MESS
84 %token <string> MON_THER
85 %token <string> MON_FRUC
86 %token <string> MON_COMP
87 %token <string> OPEN
88 %token <string> CLOSE
89 %token <string> TEXT
90 %token <string> NUMBER
91 %token <string> SLASH
92 %token <string> BADTOKEN
93
94 %type <date_val> date_value
95 %type <date_val> date_period
96 %type <date_val> date_range
97 %type <date_val> date_approx
98 %type <date_val> date_interpr
99 %type <string> date_phrase
100 %type <date> date
101
102 %%
103
104 date_value   : date           { make_date_value(DV_NO_MODIFIER,
105                                                 $1, def_date, ""); }
106              | date_period    
107              | date_range
108              | date_approx
109              | date_interpr
110              | date_phrase    { make_date_value(DV_PHRASE,
111                                                 def_date, def_date, $1); }
112              | error { /* On error: put entire string in 'phrase' member
113                           as fallback */
114                        make_date_value(DV_PHRASE,
115                                        def_date, def_date, curr_line_value); }
116              ;
117
118 date         : ESC_DATE_GREG date_greg { copy_date(&$$, date_s);
119                                          $$.cal = CAL_GREGORIAN; }
120              | ESC_DATE_JULN date_juln { copy_date(&$$, date_s);
121                                          $$.cal = CAL_JULIAN;  }
122              | ESC_DATE_HEBR date_hebr { copy_date(&$$, date_s);
123                                          $$.cal = CAL_HEBREW;  }
124              | ESC_DATE_FREN date_fren { copy_date(&$$, date_s);
125                                          $$.cal = CAL_FRENCH_REV;  }
126              | date_greg               { copy_date(&$$, date_s);
127                                          $$.cal = CAL_GREGORIAN;  }
128              ;
129
130 date_period  : MOD_FROM date   { make_date_value(DV_FROM,
131                                                  $2, def_date, ""); }
132              | MOD_TO date     { make_date_value(DV_TO,
133                                                  $2, def_date, ""); }
134              | MOD_FROM date   { copy_date(&$<date>$, $2); }
135                MOD_TO date
136                       { make_date_value(DV_FROM_TO, $<date>3, $5, ""); }
137              ;
138
139 date_range   : MOD_BEF date    { make_date_value(DV_BEFORE,
140                                                  $2, def_date, ""); }
141              | MOD_AFT date    { make_date_value(DV_AFTER,
142                                                  $2, def_date, ""); }
143              | MOD_BET date    { copy_date(&$<date>$, $2); }
144                MOD_AND date
145                       { make_date_value(DV_BETWEEN, $<date>3, $5, ""); }
146              ;
147
148 date_approx  : MOD_ABT date    { make_date_value(DV_ABOUT,
149                                                  $2, def_date, ""); }
150              | MOD_CAL date    { make_date_value(DV_CALCULATED,
151                                                  $2, def_date, ""); }
152              | MOD_EST date    { make_date_value(DV_ESTIMATED,
153                                                  $2, def_date, ""); }
154              ;
155
156 date_interpr : MOD_INT date date_phrase
157                  { make_date_value(DV_INTERPRETED, $2, def_date, $3); }
158              ;
159
160 date_phrase  : OPEN TEXT CLOSE { $$ = $2; }
161              ;
162
163 date_greg    : day month_greg year_greg
164              | month_greg year_greg
165              | year_greg
166              ;
167
168 date_juln    : day month_greg year
169              | month_greg year
170              | year
171              ;
172
173 date_hebr    : day month_hebr year
174              | month_hebr year
175              | year
176              ;
177
178 date_fren    : day month_fren year
179              | month_fren year
180              | year
181              ;
182
183 day          : NUMBER
184                {
185                  if (strlen($1) <= MAX_DAY_LEN) {
186                    strcpy(date_s.day_str, $1);
187                    date_s.day = atoi($1);
188                  }
189                  else {
190                    gedcom_date_error(_("Too many characters in day '%s'"),
191                                      $1); 
192                  }
193                }
194              ;
195
196 month_greg   : MON_JAN { strcpy(date_s.month_str, $1);
197                          date_s.month = 1; }
198              | MON_FEB { strcpy(date_s.month_str, $1);
199                          date_s.month = 2; }
200              | MON_MAR { strcpy(date_s.month_str, $1);
201                          date_s.month = 3; }
202              | MON_APR { strcpy(date_s.month_str, $1);
203                          date_s.month = 4; }
204              | MON_MAY { strcpy(date_s.month_str, $1);
205                          date_s.month = 5; }
206              | MON_JUN { strcpy(date_s.month_str, $1);
207                          date_s.month = 6; }
208              | MON_JUL { strcpy(date_s.month_str, $1);
209                          date_s.month = 7; }
210              | MON_AUG { strcpy(date_s.month_str, $1);
211                          date_s.month = 8; }
212              | MON_SEP { strcpy(date_s.month_str, $1);
213                          date_s.month = 9; }
214              | MON_OCT { strcpy(date_s.month_str, $1);
215                          date_s.month = 10; }
216              | MON_NOV { strcpy(date_s.month_str, $1);
217                          date_s.month = 11; }
218              | MON_DEC { strcpy(date_s.month_str, $1);
219                          date_s.month = 12; }
220              ;
221
222 month_hebr   : MON_TSH { strcpy(date_s.month_str, $1);
223                          date_s.month = 1; }
224              | MON_CSH { strcpy(date_s.month_str, $1);
225                          date_s.month = 2; }
226              | MON_KSL { strcpy(date_s.month_str, $1);
227                          date_s.month = 3; }
228              | MON_TVT { strcpy(date_s.month_str, $1);
229                          date_s.month = 4; }
230              | MON_SHV { strcpy(date_s.month_str, $1);
231                          date_s.month = 5; }
232              | MON_ADR { strcpy(date_s.month_str, $1);
233                          date_s.month = 6; }
234              | MON_ADS { strcpy(date_s.month_str, $1);
235                          date_s.month = 7; }
236              | MON_NSN { strcpy(date_s.month_str, $1);
237                          date_s.month = 8; }
238              | MON_IYR { strcpy(date_s.month_str, $1);
239                          date_s.month = 9; }
240              | MON_SVN { strcpy(date_s.month_str, $1);
241                          date_s.month = 10; }
242              | MON_TMZ { strcpy(date_s.month_str, $1);
243                          date_s.month = 11; }
244              | MON_AAV { strcpy(date_s.month_str, $1);
245                          date_s.month = 12; }
246              | MON_ELL { strcpy(date_s.month_str, $1);
247                          date_s.month = 13; }
248              ;
249
250 month_fren   : MON_VEND { strcpy(date_s.month_str, $1);
251                          date_s.month = 1; }
252              | MON_BRUM { strcpy(date_s.month_str, $1);
253                          date_s.month = 2; }
254              | MON_FRIM { strcpy(date_s.month_str, $1);
255                          date_s.month = 3; }
256              | MON_NIVO { strcpy(date_s.month_str, $1);
257                          date_s.month = 4; }
258              | MON_PLUV { strcpy(date_s.month_str, $1);
259                          date_s.month = 5; }
260              | MON_VENT { strcpy(date_s.month_str, $1);
261                          date_s.month = 6; }
262              | MON_GERM { strcpy(date_s.month_str, $1);
263                          date_s.month = 7; }
264              | MON_FLOR { strcpy(date_s.month_str, $1);
265                          date_s.month = 8; }
266              | MON_PRAI { strcpy(date_s.month_str, $1);
267                          date_s.month = 9; }
268              | MON_MESS { strcpy(date_s.month_str, $1);
269                          date_s.month = 10; }
270              | MON_THER { strcpy(date_s.month_str, $1);
271                          date_s.month = 11; }
272              | MON_FRUC { strcpy(date_s.month_str, $1);
273                          date_s.month = 12; }
274              | MON_COMP { strcpy(date_s.month_str, $1);
275                          date_s.month = 13; }
276              ;
277
278 year         : NUMBER
279                  { if (strlen($1) <= MAX_YEAR_LEN) {
280                      strcpy(date_s.year_str, $1);
281                      date_s.year = atoi($1);
282                      date_s.year_type = YEAR_SINGLE;
283                    }
284                    else {
285                      gedcom_date_error(_("Too many characters in year '%s'"),
286                                      $1); 
287                    }
288                  }
289              ;
290
291 year_greg    : NUMBER
292                  { if (strlen($1) <= MAX_YEAR_LEN) {
293                      strcpy(date_s.year_str, $1);
294                      date_s.year = atoi($1);
295                      date_s.year_type = YEAR_SINGLE;
296                    }
297                    else {
298                      gedcom_date_error(_("Too many characters in year '%s'"),
299                                      $1); 
300                    }
301                  }
302              | NUMBER SLASH NUMBER
303                  { if (strlen($1) + strlen($3) + 1 <= MAX_YEAR_LEN) {
304                      sprintf(date_s.year_str, "%s/%s", $1, $3);
305                      date_s.year = atoi($1) + 1;
306                      date_s.year_type = YEAR_DOUBLE;
307                    }
308                    else {
309                      gedcom_date_error(_("Too many characters in year '%s/%s'"),
310                                      $1, $3); 
311                    }
312                  
313                  }
314              ;
315
316 %%