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