Imported Upstream version 0.19.7
[platform/upstream/gettext.git] / gettext-tools / src / po-gram-gen.y
1 /* GNU gettext - internationalization aids
2    Copyright (C) 1995-1996, 1998, 2000-2001, 2003, 2005-2006, 2012, 2015
3    Free Software Foundation, Inc.
4
5    This file was written by Peter Miller <pmiller@agso.gov.au>
6
7    This program is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20 %{
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 /* Specification.  */
26 #include "po-gram.h"
27
28 #include <stdbool.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "str-list.h"
34 #include "po-lex.h"
35 #include "po-charset.h"
36 #include "error.h"
37 #include "xalloc.h"
38 #include "gettext.h"
39 #include "read-catalog-abstract.h"
40
41 #define _(str) gettext (str)
42
43 /* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
44    as well as gratuitiously global symbol names, so we can have multiple
45    yacc generated parsers in the same program.  Note that these are only
46    the variables produced by yacc.  If other parser generators (bison,
47    byacc, etc) produce additional global names that conflict at link time,
48    then those parser generators need to be fixed instead of adding those
49    names to this list. */
50
51 #define yymaxdepth po_gram_maxdepth
52 #define yyparse po_gram_parse
53 #define yylex   po_gram_lex
54 #define yyerror po_gram_error
55 #define yylval  po_gram_lval
56 #define yychar  po_gram_char
57 #define yydebug po_gram_debug
58 #define yypact  po_gram_pact
59 #define yyr1    po_gram_r1
60 #define yyr2    po_gram_r2
61 #define yydef   po_gram_def
62 #define yychk   po_gram_chk
63 #define yypgo   po_gram_pgo
64 #define yyact   po_gram_act
65 #define yyexca  po_gram_exca
66 #define yyerrflag po_gram_errflag
67 #define yynerrs po_gram_nerrs
68 #define yyps    po_gram_ps
69 #define yypv    po_gram_pv
70 #define yys     po_gram_s
71 #define yy_yys  po_gram_yys
72 #define yystate po_gram_state
73 #define yytmp   po_gram_tmp
74 #define yyv     po_gram_v
75 #define yy_yyv  po_gram_yyv
76 #define yyval   po_gram_val
77 #define yylloc  po_gram_lloc
78 #define yyreds  po_gram_reds          /* With YYDEBUG defined */
79 #define yytoks  po_gram_toks          /* With YYDEBUG defined */
80 #define yylhs   po_gram_yylhs
81 #define yylen   po_gram_yylen
82 #define yydefred po_gram_yydefred
83 #define yydgoto po_gram_yydgoto
84 #define yysindex po_gram_yysindex
85 #define yyrindex po_gram_yyrindex
86 #define yygindex po_gram_yygindex
87 #define yytable  po_gram_yytable
88 #define yycheck  po_gram_yycheck
89
90 static long plural_counter;
91
92 #define check_obsolete(value1,value2) \
93   if ((value1).obsolete != (value2).obsolete) \
94     po_gram_error_at_line (&(value2).pos, _("inconsistent use of #~"));
95
96 static inline void
97 do_callback_message (char *msgctxt,
98                      char *msgid, lex_pos_ty *msgid_pos, char *msgid_plural,
99                      char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos,
100                      char *prev_msgctxt,
101                      char *prev_msgid, char *prev_msgid_plural,
102                      bool obsolete)
103 {
104   /* Test for header entry.  Ignore fuzziness of the header entry.  */
105   if (msgctxt == NULL && msgid[0] == '\0' && !obsolete)
106     po_lex_charset_set (msgstr, gram_pos.file_name);
107
108   po_callback_message (msgctxt,
109                        msgid, msgid_pos, msgid_plural,
110                        msgstr, msgstr_len, msgstr_pos,
111                        prev_msgctxt, prev_msgid, prev_msgid_plural,
112                        false, obsolete);
113 }
114
115 #define free_message_intro(value) \
116   if ((value).prev_ctxt != NULL)        \
117     free ((value).prev_ctxt);           \
118   if ((value).prev_id != NULL)          \
119     free ((value).prev_id);             \
120   if ((value).prev_id_plural != NULL)   \
121     free ((value).prev_id_plural);      \
122   if ((value).ctxt != NULL)             \
123     free ((value).ctxt);
124
125 %}
126
127 %token COMMENT
128 %token DOMAIN
129 %token JUNK
130 %token PREV_MSGCTXT
131 %token PREV_MSGID
132 %token PREV_MSGID_PLURAL
133 %token PREV_STRING
134 %token MSGCTXT
135 %token MSGID
136 %token MSGID_PLURAL
137 %token MSGSTR
138 %token NAME
139 %token '[' ']'
140 %token NUMBER
141 %token STRING
142
143 %union
144 {
145   struct { char *string; lex_pos_ty pos; bool obsolete; } string;
146   struct { string_list_ty stringlist; lex_pos_ty pos; bool obsolete; } stringlist;
147   struct { long number; lex_pos_ty pos; bool obsolete; } number;
148   struct { lex_pos_ty pos; bool obsolete; } pos;
149   struct { char *ctxt; char *id; char *id_plural; lex_pos_ty pos; bool obsolete; } prev;
150   struct { char *prev_ctxt; char *prev_id; char *prev_id_plural; char *ctxt; lex_pos_ty pos; bool obsolete; } message_intro;
151   struct { struct msgstr_def rhs; lex_pos_ty pos; bool obsolete; } rhs;
152 }
153
154 %type <string> STRING PREV_STRING COMMENT NAME
155                msg_intro prev_msg_intro msgid_pluralform prev_msgid_pluralform
156 %type <stringlist> string_list prev_string_list
157 %type <number> NUMBER
158 %type <pos> DOMAIN
159             PREV_MSGCTXT PREV_MSGID PREV_MSGID_PLURAL
160             MSGCTXT MSGID MSGID_PLURAL MSGSTR '[' ']'
161 %type <prev> prev
162 %type <message_intro> message_intro
163 %type <rhs> pluralform pluralform_list
164
165 %right MSGSTR
166
167 %%
168
169 po_file
170         : /* empty */
171         | po_file comment
172         | po_file domain
173         | po_file message
174         | po_file error
175         ;
176
177
178 comment
179         : COMMENT
180                 {
181                   po_callback_comment_dispatcher ($1.string);
182                 }
183         ;
184
185
186 domain
187         : DOMAIN STRING
188                 {
189                    po_callback_domain ($2.string);
190                 }
191         ;
192
193
194 message
195         : message_intro string_list MSGSTR string_list
196                 {
197                   char *string2 = string_list_concat_destroy (&$2.stringlist);
198                   char *string4 = string_list_concat_destroy (&$4.stringlist);
199
200                   check_obsolete ($1, $2);
201                   check_obsolete ($1, $3);
202                   check_obsolete ($1, $4);
203                   if (!$1.obsolete || pass_obsolete_entries)
204                     do_callback_message ($1.ctxt, string2, &$1.pos, NULL,
205                                          string4, strlen (string4) + 1, &$3.pos,
206                                          $1.prev_ctxt,
207                                          $1.prev_id, $1.prev_id_plural,
208                                          $1.obsolete);
209                   else
210                     {
211                       free_message_intro ($1);
212                       free (string2);
213                       free (string4);
214                     }
215                 }
216         | message_intro string_list msgid_pluralform pluralform_list
217                 {
218                   char *string2 = string_list_concat_destroy (&$2.stringlist);
219
220                   check_obsolete ($1, $2);
221                   check_obsolete ($1, $3);
222                   check_obsolete ($1, $4);
223                   if (!$1.obsolete || pass_obsolete_entries)
224                     {
225                       do_callback_message ($1.ctxt, string2, &$1.pos, $3.string,
226                                            $4.rhs.msgstr, $4.rhs.msgstr_len, &$4.pos,
227                                            $1.prev_ctxt,
228                                            $1.prev_id, $1.prev_id_plural,
229                                            $1.obsolete);
230                       free ($3.string);
231                     }
232                   else
233                     {
234                       free_message_intro ($1);
235                       free (string2);
236                       free ($3.string);
237                       free ($4.rhs.msgstr);
238                     }
239                 }
240         | message_intro string_list msgid_pluralform
241                 {
242                   check_obsolete ($1, $2);
243                   check_obsolete ($1, $3);
244                   po_gram_error_at_line (&$1.pos, _("missing 'msgstr[]' section"));
245                   free_message_intro ($1);
246                   string_list_destroy (&$2.stringlist);
247                   free ($3.string);
248                 }
249         | message_intro string_list pluralform_list
250                 {
251                   check_obsolete ($1, $2);
252                   check_obsolete ($1, $3);
253                   po_gram_error_at_line (&$1.pos, _("missing 'msgid_plural' section"));
254                   free_message_intro ($1);
255                   string_list_destroy (&$2.stringlist);
256                   free ($3.rhs.msgstr);
257                 }
258         | message_intro string_list
259                 {
260                   check_obsolete ($1, $2);
261                   po_gram_error_at_line (&$1.pos, _("missing 'msgstr' section"));
262                   free_message_intro ($1);
263                   string_list_destroy (&$2.stringlist);
264                 }
265         ;
266
267
268 message_intro
269         : msg_intro
270                 {
271                   $$.prev_ctxt = NULL;
272                   $$.prev_id = NULL;
273                   $$.prev_id_plural = NULL;
274                   $$.ctxt = $1.string;
275                   $$.pos = $1.pos;
276                   $$.obsolete = $1.obsolete;
277                 }
278         | prev msg_intro
279                 {
280                   check_obsolete ($1, $2);
281                   $$.prev_ctxt = $1.ctxt;
282                   $$.prev_id = $1.id;
283                   $$.prev_id_plural = $1.id_plural;
284                   $$.ctxt = $2.string;
285                   $$.pos = $2.pos;
286                   $$.obsolete = $2.obsolete;
287                 }
288         ;
289
290
291 prev
292         : prev_msg_intro prev_string_list
293                 {
294                   check_obsolete ($1, $2);
295                   $$.ctxt = $1.string;
296                   $$.id = string_list_concat_destroy (&$2.stringlist);
297                   $$.id_plural = NULL;
298                   $$.pos = $1.pos;
299                   $$.obsolete = $1.obsolete;
300                 }
301         | prev_msg_intro prev_string_list prev_msgid_pluralform
302                 {
303                   check_obsolete ($1, $2);
304                   check_obsolete ($1, $3);
305                   $$.ctxt = $1.string;
306                   $$.id = string_list_concat_destroy (&$2.stringlist);
307                   $$.id_plural = $3.string;
308                   $$.pos = $1.pos;
309                   $$.obsolete = $1.obsolete;
310                 }
311         ;
312
313
314 msg_intro
315         : MSGID
316                 {
317                   $$.string = NULL;
318                   $$.pos = $1.pos;
319                   $$.obsolete = $1.obsolete;
320                 }
321         | MSGCTXT string_list MSGID
322                 {
323                   check_obsolete ($1, $2);
324                   check_obsolete ($1, $3);
325                   $$.string = string_list_concat_destroy (&$2.stringlist);
326                   $$.pos = $3.pos;
327                   $$.obsolete = $3.obsolete;
328                 }
329         ;
330
331 prev_msg_intro
332         : PREV_MSGID
333                 {
334                   $$.string = NULL;
335                   $$.pos = $1.pos;
336                   $$.obsolete = $1.obsolete;
337                 }
338         | PREV_MSGCTXT prev_string_list PREV_MSGID
339                 {
340                   check_obsolete ($1, $2);
341                   check_obsolete ($1, $3);
342                   $$.string = string_list_concat_destroy (&$2.stringlist);
343                   $$.pos = $3.pos;
344                   $$.obsolete = $3.obsolete;
345                 }
346         ;
347
348
349 msgid_pluralform
350         : MSGID_PLURAL string_list
351                 {
352                   check_obsolete ($1, $2);
353                   plural_counter = 0;
354                   $$.string = string_list_concat_destroy (&$2.stringlist);
355                   $$.pos = $1.pos;
356                   $$.obsolete = $1.obsolete;
357                 }
358         ;
359
360 prev_msgid_pluralform
361         : PREV_MSGID_PLURAL prev_string_list
362                 {
363                   check_obsolete ($1, $2);
364                   $$.string = string_list_concat_destroy (&$2.stringlist);
365                   $$.pos = $1.pos;
366                   $$.obsolete = $1.obsolete;
367                 }
368         ;
369
370
371 pluralform_list
372         : pluralform
373                 {
374                   $$ = $1;
375                 }
376         | pluralform_list pluralform
377                 {
378                   check_obsolete ($1, $2);
379                   $$.rhs.msgstr = XNMALLOC ($1.rhs.msgstr_len + $2.rhs.msgstr_len, char);
380                   memcpy ($$.rhs.msgstr, $1.rhs.msgstr, $1.rhs.msgstr_len);
381                   memcpy ($$.rhs.msgstr + $1.rhs.msgstr_len, $2.rhs.msgstr, $2.rhs.msgstr_len);
382                   $$.rhs.msgstr_len = $1.rhs.msgstr_len + $2.rhs.msgstr_len;
383                   free ($1.rhs.msgstr);
384                   free ($2.rhs.msgstr);
385                   $$.pos = $1.pos;
386                   $$.obsolete = $1.obsolete;
387                 }
388         ;
389
390 pluralform
391         : MSGSTR '[' NUMBER ']' string_list
392                 {
393                   check_obsolete ($1, $2);
394                   check_obsolete ($1, $3);
395                   check_obsolete ($1, $4);
396                   check_obsolete ($1, $5);
397                   if ($3.number != plural_counter)
398                     {
399                       if (plural_counter == 0)
400                         po_gram_error_at_line (&$1.pos, _("first plural form has nonzero index"));
401                       else
402                         po_gram_error_at_line (&$1.pos, _("plural form has wrong index"));
403                     }
404                   plural_counter++;
405                   $$.rhs.msgstr = string_list_concat_destroy (&$5.stringlist);
406                   $$.rhs.msgstr_len = strlen ($$.rhs.msgstr) + 1;
407                   $$.pos = $1.pos;
408                   $$.obsolete = $1.obsolete;
409                 }
410         ;
411
412
413 string_list
414         : STRING
415                 {
416                   string_list_init (&$$.stringlist);
417                   string_list_append (&$$.stringlist, $1.string);
418                   free ($1.string);
419                   $$.pos = $1.pos;
420                   $$.obsolete = $1.obsolete;
421                 }
422         | string_list STRING
423                 {
424                   check_obsolete ($1, $2);
425                   $$.stringlist = $1.stringlist;
426                   string_list_append (&$$.stringlist, $2.string);
427                   free ($2.string);
428                   $$.pos = $1.pos;
429                   $$.obsolete = $1.obsolete;
430                 }
431         ;
432
433 prev_string_list
434         : PREV_STRING
435                 {
436                   string_list_init (&$$.stringlist);
437                   string_list_append (&$$.stringlist, $1.string);
438                   free ($1.string);
439                   $$.pos = $1.pos;
440                   $$.obsolete = $1.obsolete;
441                 }
442         | prev_string_list PREV_STRING
443                 {
444                   check_obsolete ($1, $2);
445                   $$.stringlist = $1.stringlist;
446                   string_list_append (&$$.stringlist, $2.string);
447                   free ($2.string);
448                   $$.pos = $1.pos;
449                   $$.obsolete = $1.obsolete;
450                 }
451         ;