1 /* Unicode CLDR plural rule parser and converter
2 Copyright (C) 2015, 2018-2020 Free Software Foundation, Inc.
3
4 This file was written by Daiki Ueno <ueno@gnu.org>, 2015.
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 <https://www.gnu.org/licenses/>. */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include "unistr.h"
28 #include "xalloc.h"
29
30 #include "cldr-plural-exp.h"
31 #include "cldr-plural.h"
32
33 /* The grammar of Unicode CLDR plural rules is defined at:
34 https://unicode.org/reports/tr35/tr35-numbers.html#Plural_rules_syntax
35
36 This implementation only supports the "preferred" form, which
37 doesn't support obsolete keywords "in", "is", "not", and "within".
38
39 Unlike gettext, CLDR allows an unsigned decimal value as an
40 operand, in addition to unsigned integers. For simplicity, we
41 treat decimal relations as if it has a constant truth value.
42
43 The implementation is largely based on the idea of Michele Locati's
44 cldr-to-gettext-plural-rules:
45 https://github.com/mlocati/cldr-to-gettext-plural-rules */
46
47 void
48 cldr_plural_range_free (struct cldr_plural_range_ty *range)
49 {
50 if (range->start != range->end)
51 free (range->start);
52 free (range->end);
53 free (range);
54 }
55
56 void
57 cldr_plural_range_list_free (struct cldr_plural_range_list_ty *ranges)
58 {
59 while (ranges->nitems-- > 0)
60 cldr_plural_range_free (ranges->items[ranges->nitems]);
61 free (ranges->items);
62 free (ranges);
63 }
64
65 void
66 cldr_plural_condition_free (struct cldr_plural_condition_ty *condition)
67 {
68 if (condition->type == CLDR_PLURAL_CONDITION_AND
69 || condition->type == CLDR_PLURAL_CONDITION_OR)
70 {
71 cldr_plural_condition_free (condition->value.conditions[0]);
72 cldr_plural_condition_free (condition->value.conditions[1]);
73 }
74 else if (condition->type == CLDR_PLURAL_CONDITION_RELATION)
75 cldr_plural_relation_free (condition->value.relation);
76 free (condition);
77 }
78
79 void
80 cldr_plural_relation_free (struct cldr_plural_relation_ty *relation)
81 {
82 free (relation->expression);
83 cldr_plural_range_list_free (relation->ranges);
84 free (relation);
85 }
86
87 static void
88 cldr_plural_rule_free (struct cldr_plural_rule_ty *rule)
89 {
90 free (rule->name);
91 cldr_plural_condition_free (rule->condition);
92 free (rule);
93 }
94
95 void
96 cldr_plural_rule_list_free (struct cldr_plural_rule_list_ty *rules)
97 {
98 while (rules->nitems-- > 0)
99 cldr_plural_rule_free (rules->items[rules->nitems]);
100 free (rules->items);
101 free (rules);
102 }
103
104 struct cldr_plural_rule_list_ty *
105 cldr_plural_parse (const char *input)
106 {
107 struct cldr_plural_parse_args arg;
108
109 memset (&arg, 0, sizeof (struct cldr_plural_parse_args));
110 arg.cp = input;
111 arg.cp_end = input + strlen (input);
112 arg.result = XMALLOC (struct cldr_plural_rule_list_ty);
113 memset (arg.result, 0, sizeof (struct cldr_plural_rule_list_ty));
114
115 if (yyparse (&arg) != 0)
116 return NULL;
117
118 return arg.result;
119 }
120
121 #define OPERAND_ZERO_P(o) \
122 (((o)->type == CLDR_PLURAL_OPERAND_INTEGER \
123 && (o)->value.ival == 0) \
124 || ((o)->type == CLDR_PLURAL_OPERAND_DECIMAL \
125 && (o)->value.dval.d == 0))
126
127 static enum cldr_plural_condition
128 eval_relation (struct cldr_plural_relation_ty *relation)
129 {
130 switch (relation->expression->operand)
131 {
132 case 'n': case 'i':
133 {
134 /* Coerce decimal values in ranges into integers. */
135 size_t i;
136 for (i = 0; i < relation->ranges->nitems; i++)
137 {
138 struct cldr_plural_range_ty *range = relation->ranges->items[i];
139 if (range->start->type == CLDR_PLURAL_OPERAND_DECIMAL)
140 {
141 int truncated = (int) range->start->value.dval.d;
142 range->start->type = CLDR_PLURAL_OPERAND_INTEGER;
143 range->start->value.ival =
144 (range->start->value.dval.d == truncated
145 ? truncated
146 : truncated + 1);
147 }
148 if (range->end->type == CLDR_PLURAL_OPERAND_DECIMAL)
149 {
150 range->end->type = CLDR_PLURAL_OPERAND_INTEGER;
151 range->end->value.ival = (int) range->end->value.dval.d;
152 }
153 }
154 relation->expression->operand = 'i';
155 }
156 break;
157 case 'f': case 't':
158 case 'v': case 'w':
159 {
160 /* Since plural expression in gettext only supports unsigned
161 integer, turn relations whose operand is either 'f', 't',
162 'v', or 'w' into a constant truth value. */
163 /* FIXME: check mod? */
164 size_t i;
165 for (i = 0; i < relation->ranges->nitems; i++)
166 {
167 struct cldr_plural_range_ty *range = relation->ranges->items[i];
168 if ((relation->type == CLDR_PLURAL_RELATION_EQUAL
169 && (!OPERAND_ZERO_P (range->start)
170 || !OPERAND_ZERO_P (range->end)))
171 || (relation->type == CLDR_PLURAL_RELATION_NOT_EQUAL
172 && (OPERAND_ZERO_P (range->start)
173 || OPERAND_ZERO_P (range->end))))
174 return CLDR_PLURAL_CONDITION_FALSE;
175 }
176 return CLDR_PLURAL_CONDITION_TRUE;
177 }
178 break;
179 }
180 return CLDR_PLURAL_CONDITION_RELATION;
181 }
182
183 static void
184 eval_condition (struct cldr_plural_condition_ty *condition)
185 {
186 if (condition->type == CLDR_PLURAL_CONDITION_AND)
187 {
188 eval_condition (condition->value.conditions[0]);
189 eval_condition (condition->value.conditions[1]);
190
191 if ((condition->value.conditions[0]->type
192 == CLDR_PLURAL_CONDITION_FALSE)
193 || (condition->value.conditions[1]->type
194 == CLDR_PLURAL_CONDITION_FALSE))
195 {
196 cldr_plural_condition_free (condition->value.conditions[0]);
197 cldr_plural_condition_free (condition->value.conditions[1]);
198 condition->type = CLDR_PLURAL_CONDITION_FALSE;
199 }
200 else if ((condition->value.conditions[0]->type
201 == CLDR_PLURAL_CONDITION_TRUE)
202 && (condition->value.conditions[1]->type
203 == CLDR_PLURAL_CONDITION_TRUE))
204 {
205 cldr_plural_condition_free (condition->value.conditions[0]);
206 cldr_plural_condition_free (condition->value.conditions[1]);
207 condition->type = CLDR_PLURAL_CONDITION_TRUE;
208 }
209 else if (condition->value.conditions[0]->type
210 == CLDR_PLURAL_CONDITION_TRUE)
211 {
212 struct cldr_plural_condition_ty *original =
213 condition->value.conditions[1];
214 cldr_plural_condition_free (condition->value.conditions[0]);
215 condition->type = condition->value.conditions[1]->type;
216 condition->value = condition->value.conditions[1]->value;
217 free (original);
218 }
219 else if (condition->value.conditions[1]->type
220 == CLDR_PLURAL_CONDITION_TRUE)
221 {
222 struct cldr_plural_condition_ty *original =
223 condition->value.conditions[0];
224 cldr_plural_condition_free (condition->value.conditions[1]);
225 condition->type = condition->value.conditions[0]->type;
226 condition->value = condition->value.conditions[0]->value;
227 free (original);
228 }
229 }
230 else if (condition->type == CLDR_PLURAL_CONDITION_OR)
231 {
232 eval_condition (condition->value.conditions[0]);
233 eval_condition (condition->value.conditions[1]);
234
235 if ((condition->value.conditions[0]->type
236 == CLDR_PLURAL_CONDITION_TRUE)
237 || (condition->value.conditions[1]->type
238 == CLDR_PLURAL_CONDITION_TRUE))
239 {
240 cldr_plural_condition_free (condition->value.conditions[0]);
241 cldr_plural_condition_free (condition->value.conditions[1]);
242 condition->type = CLDR_PLURAL_CONDITION_TRUE;
243 }
244 else if ((condition->value.conditions[0]->type
245 == CLDR_PLURAL_CONDITION_FALSE)
246 && (condition->value.conditions[1]->type
247 == CLDR_PLURAL_CONDITION_FALSE))
248 {
249 cldr_plural_condition_free (condition->value.conditions[0]);
250 cldr_plural_condition_free (condition->value.conditions[1]);
251 condition->type = CLDR_PLURAL_CONDITION_FALSE;
252 }
253 else if (condition->value.conditions[0]->type
254 == CLDR_PLURAL_CONDITION_FALSE)
255 {
256 struct cldr_plural_condition_ty *original =
257 condition->value.conditions[1];
258 cldr_plural_condition_free (condition->value.conditions[0]);
259 condition->type = condition->value.conditions[1]->type;
260 condition->value = condition->value.conditions[1]->value;
261 free (original);
262 }
263 else if (condition->value.conditions[1]->type
264 == CLDR_PLURAL_CONDITION_FALSE)
265 {
266 struct cldr_plural_condition_ty *original =
267 condition->value.conditions[0];
268 cldr_plural_condition_free (condition->value.conditions[1]);
269 condition->type = condition->value.conditions[0]->type;
270 condition->value = condition->value.conditions[0]->value;
271 free (original);
272 }
273 }
274 else
275 {
276 enum cldr_plural_condition value =
277 eval_relation (condition->value.relation);
278 if (value == CLDR_PLURAL_CONDITION_TRUE
279 || value == CLDR_PLURAL_CONDITION_FALSE)
280 {
281 cldr_plural_relation_free (condition->value.relation);
282 condition->type = value;
283 }
284 }
285 }
286
287 #define MAX(a,b) ((a) > (b) ? (a) : (b))
288
289 static int
290 find_largest_modulus (struct cldr_plural_condition_ty *condition)
291 {
292 if (condition->type == CLDR_PLURAL_CONDITION_AND
293 || condition->type == CLDR_PLURAL_CONDITION_OR)
294 {
295 int modulus0 =
296 find_largest_modulus (condition->value.conditions[0]);
297 int modulus1 =
298 find_largest_modulus (condition->value.conditions[1]);
299 return MAX (modulus0, modulus1);
300 }
301 else if (condition->type == CLDR_PLURAL_CONDITION_RELATION)
302 return condition->value.relation->expression->mod;
303 else
304 return 0;
305 }
306
307 static int
308 find_largest_number (struct cldr_plural_condition_ty *condition)
309 {
310 if (condition->type == CLDR_PLURAL_CONDITION_AND
311 || condition->type == CLDR_PLURAL_CONDITION_OR)
312 {
313 int number0 =
314 find_largest_number (condition->value.conditions[0]);
315 int number1 =
316 find_largest_number (condition->value.conditions[1]);
317 return MAX (number0, number1);
318 }
319 else if (condition->type == CLDR_PLURAL_CONDITION_RELATION)
320 {
321 int number = 0;
322 size_t i;
323 for (i = 0; i < condition->value.relation->ranges->nitems; i++)
324 {
325 struct cldr_plural_operand_ty *operand;
326
327 operand = condition->value.relation->ranges->items[i]->end;
328 if (operand->type == CLDR_PLURAL_OPERAND_INTEGER
329 && operand->value.ival > number)
330 number = operand->value.ival;
331 else if (operand->type == CLDR_PLURAL_OPERAND_DECIMAL
332 && operand->value.dval.d > number)
333 number = (int) operand->value.dval.d;
334 }
335 return number;
336 }
337 else
338 return 0;
339 }
340
341 static bool
342 apply_condition (struct cldr_plural_condition_ty *condition, int value)
343 {
344 if (condition->type == CLDR_PLURAL_CONDITION_AND)
345 return apply_condition (condition->value.conditions[0], value)
346 && apply_condition (condition->value.conditions[1], value);
347 else if (condition->type == CLDR_PLURAL_CONDITION_OR)
348 return apply_condition (condition->value.conditions[0], value)
349 || apply_condition (condition->value.conditions[1], value);
350 else if (condition->type == CLDR_PLURAL_CONDITION_RELATION)
351 {
352 struct cldr_plural_relation_ty *relation = condition->value.relation;
353 int number = value;
354 size_t i;
355
356 if (relation->expression->mod > 0)
357 number %= relation->expression->mod;
358 for (i = 0; i < relation->ranges->nitems; i++)
359 {
360 struct cldr_plural_range_ty *range = relation->ranges->items[i];
361 if (range->start->value.ival <= number
362 && number <= range->end->value.ival)
363 return relation->type == CLDR_PLURAL_RELATION_EQUAL;
364 }
365 return relation->type != CLDR_PLURAL_RELATION_EQUAL;
366 }
367 return false;
368 }
369
370 static void
371 print_expression (struct cldr_plural_expression_ty *expression, bool space,
372 FILE *fp)
373 {
374 if (expression->mod == 0)
375 fprintf (fp, "n");
376 else
377 fprintf (fp, space ? "n %% %d" : "n%%%d", expression->mod);
378 }
379
380 static void
381 print_relation (struct cldr_plural_relation_ty *relation,
382 enum cldr_plural_condition parent, bool space,
383 FILE *fp)
384 {
385 if (relation->type == CLDR_PLURAL_RELATION_EQUAL)
386 {
387 size_t i;
388 if (parent == CLDR_PLURAL_CONDITION_AND
389 && relation->ranges->nitems > 1)
390 fputc ('(', fp);
391 for (i = 0; i < relation->ranges->nitems; i++)
392 {
393 struct cldr_plural_range_ty *range = relation->ranges->items[i];
394 if (i > 0)
395 fprintf (fp, " || ");
396 if (range->start->value.ival == range->end->value.ival)
397 {
398 print_expression (relation->expression, space, fp);
399 fprintf (fp,
400 (space && relation->ranges->nitems == 1
401 ? " == %d" : "==%d"),
402 range->start->value.ival);
403 }
404 else if (range->start->value.ival == 0)
405 {
406 print_expression (relation->expression, false, fp);
407 fprintf (fp, "<=%d", range->end->value.ival);
408 }
409 else
410 {
411 if (parent == CLDR_PLURAL_CONDITION_OR
412 || relation->ranges->nitems > 1)
413 fputc ('(', fp);
414 print_expression (relation->expression, false, fp);
415 fprintf (fp, ">=%d", range->start->value.ival);
416 fprintf (fp, " && ");
417 print_expression (relation->expression, false, fp);
418 fprintf (fp, "<=%d", range->end->value.ival);
419 if (parent == CLDR_PLURAL_CONDITION_OR
420 || relation->ranges->nitems > 1)
421 fputc (')', fp);
422 }
423 }
424 if (parent == CLDR_PLURAL_CONDITION_AND
425 && relation->ranges->nitems > 1)
426 fputc (')', fp);
427 }
428 else
429 {
430 size_t i;
431 if (parent == CLDR_PLURAL_CONDITION_OR
432 && relation->ranges->nitems > 1)
433 fputc ('(', fp);
434 for (i = 0; i < relation->ranges->nitems; i++)
435 {
436 struct cldr_plural_range_ty *range = relation->ranges->items[i];
437 if (i > 0)
438 fprintf (fp," && ");
439 if (range->start->value.ival == range->end->value.ival)
440 {
441 print_expression (relation->expression, space, fp);
442 fprintf (fp, space && relation->ranges->nitems == 1
443 ? " != %d" : "!=%d", range->start->value.ival);
444 }
445 else if (range->start->value.ival == 0)
446 {
447 print_expression (relation->expression, false, fp);
448 fprintf (fp, ">%d", range->end->value.ival);
449 }
450 else
451 {
452 if (parent == CLDR_PLURAL_CONDITION_AND
453 || relation->ranges->nitems > 1)
454 fputc ('(', fp);
455 print_expression (relation->expression, false, fp);
456 fprintf (fp, "<%d", range->start->value.ival);
457 fprintf (fp, " || ");
458 print_expression (relation->expression, false, fp);
459 fprintf (fp, ">%d", range->end->value.ival);
460 if (parent == CLDR_PLURAL_CONDITION_AND
461 || relation->ranges->nitems > 1)
462 fputc (')', fp);
463 }
464 }
465 if (parent == CLDR_PLURAL_CONDITION_OR
466 && relation->ranges->nitems > 1)
467 fputc (')', fp);
468 }
469 }
470
471 static bool
472 print_condition (struct cldr_plural_condition_ty *condition,
473 enum cldr_plural_condition parent, bool space,
474 FILE *fp)
475 {
476 if (condition->type == CLDR_PLURAL_CONDITION_AND)
477 {
478 if (parent == CLDR_PLURAL_CONDITION_OR)
479 fputc ('(', fp);
480 print_condition (condition->value.conditions[0],
481 CLDR_PLURAL_CONDITION_AND, false,
482 fp);
483 fprintf (fp, " && ");
484 print_condition (condition->value.conditions[1],
485 CLDR_PLURAL_CONDITION_AND, false,
486 fp);
487 if (parent == CLDR_PLURAL_CONDITION_OR)
488 fputc (')', fp);
489 return true;
490 }
491 else if (condition->type == CLDR_PLURAL_CONDITION_OR)
492 {
493 if (parent == CLDR_PLURAL_CONDITION_AND)
494 fputc ('(', fp);
495 print_condition (condition->value.conditions[0],
496 CLDR_PLURAL_CONDITION_OR, false,
497 fp);
498 fprintf (fp, " || ");
499 print_condition (condition->value.conditions[1],
500 CLDR_PLURAL_CONDITION_OR, false,
501 fp);
502 if (parent == CLDR_PLURAL_CONDITION_AND)
503 fputc (')', fp);
504 return true;
505 }
506 else if (condition->type == CLDR_PLURAL_CONDITION_RELATION)
507 {
508 print_relation (condition->value.relation, parent, space, fp);
509 return true;
510 }
511 return false;
512 }
513
514 #define RULE_PRINTABLE_P(r) \
515 ((r)->condition->type != CLDR_PLURAL_CONDITION_TRUE \
516 && (r)->condition->type != CLDR_PLURAL_CONDITION_FALSE)
517
518 /* Convert n == N into n != N. */
519 static bool
520 print_condition_negation (struct cldr_plural_condition_ty *condition, FILE *fp)
521 {
522 if (condition->type == CLDR_PLURAL_CONDITION_RELATION
523 && condition->value.relation->type == CLDR_PLURAL_RELATION_EQUAL
524 && condition->value.relation->ranges->nitems == 1
525 && condition->value.relation->ranges->items[0]->start
526 == condition->value.relation->ranges->items[0]->end)
527 {
528 fprintf (fp, "nplurals=2; plural=(n != %d);\n",
529 condition->value.relation->ranges->items[0]->start->value.ival);
530 return true;
531 }
532 return false;
533 }
534
535 /* Convert n == 0,...,N into n > N. */
536 static bool
537 print_condition_greater (struct cldr_plural_condition_ty *condition, FILE *fp)
538 {
539 if (condition->type == CLDR_PLURAL_CONDITION_RELATION
540 && condition->value.relation->type == CLDR_PLURAL_RELATION_EQUAL)
541 {
542 int last = -1;
543 size_t i;
544 for (i = 0; i < condition->value.relation->ranges->nitems; i++)
545 {
546 struct cldr_plural_range_ty *range =
547 condition->value.relation->ranges->items[i];
548 if (range->start->type != CLDR_PLURAL_OPERAND_INTEGER
549 || range->end->type != CLDR_PLURAL_OPERAND_INTEGER
550 || range->start->value.ival != last + 1)
551 break;
552 last = range->end->value.ival;
553 }
554 if (i == condition->value.relation->ranges->nitems)
555 {
556 struct cldr_plural_range_ty *range =
557 condition->value.relation->ranges->items[i - 1];
558 fprintf (fp, "nplurals=2; plural=(n > %d);\n",
559 range->end->value.ival);
560 return true;
561 }
562 }
563 return false;
564 }
565
566 typedef bool (*print_condition_function_ty) (struct cldr_plural_condition_ty *,
567 FILE *);
568 static print_condition_function_ty print_condition_functions[] =
569 {
570 print_condition_negation,
571 print_condition_greater
572 };
573
574 #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
575
576 void
577 cldr_plural_rule_list_print (struct cldr_plural_rule_list_ty *rules, FILE *fp)
578 {
579 size_t i;
580 size_t count;
581 size_t nplurals;
582 int modulus_max = 0;
583
584 /* Prune trivial conditions. */
585 for (i = 0; i < rules->nitems; i++)
586 {
587 struct cldr_plural_rule_ty *rule = rules->items[i];
588 eval_condition (rule->condition);
589 }
590
591 /* Omit trivial rules (e.g., the last rule for "ru") with the
592 following algorithm:
593 1. From all rules, find the largest modulus M
594 2. Prepare a bit vector with M elements and initialize it with zeros
595 3. Loop over the rules, until all bits are set:
596 For each value in the range [1, M], apply a rule, and flip the
597 corresponding bit if it evaluates true */
598
599 /* Find the largest modulus. */
600 for (i = 0; i < rules->nitems; i++)
601 {
602 struct cldr_plural_rule_ty *rule = rules->items[i];
603 int modulus = find_largest_modulus (rule->condition);
604 int number = find_largest_number (rule->condition);
605 /* If the rule contains a range whose end is larger than
606 MODULUS, we can't use MODULUS as the upper bound. Skip
607 it. */
608 if (modulus >= number && modulus > modulus_max)
609 modulus_max = modulus;
610 }
611
612 if (modulus_max > 0)
613 {
614 bool *values = XNMALLOC (modulus_max, bool);
615
616 memset (values, 0, sizeof (bool) * modulus_max);
617 for (i = 0; i < rules->nitems; i++)
618 {
619 struct cldr_plural_rule_ty *rule = rules->items[i];
620 int j;
621
622 for (j = 0; j < modulus_max; j++)
623 {
624 bool result = apply_condition (rule->condition, j + 1);
625 if (result)
626 values[j] = true;
627 }
628
629 /* Check if all bits are set. Then we can omit one more rule. */
630 for (j = 0; j < modulus_max; j++)
631 if (values[j] == false)
632 break;
633 if (j == modulus_max)
634 break;
635 }
636
637 free (values);
638
639 while (i < rules->nitems)
640 cldr_plural_rule_free (rules->items[--rules->nitems]);
641 }
642
643 for (i = 0, nplurals = 1; i < rules->nitems; i++)
644 if (RULE_PRINTABLE_P (rules->items[i]))
645 nplurals++;
646
647 /* Special case when rules is empty. */
648 if (nplurals == 1)
649 {
650 fprintf (fp, "nplurals=1; plural=0;\n");
651 return;
652 }
653
654 /* If we have only one printable rule, apply some heuristics. */
655 if (nplurals == 2)
656 {
657 struct cldr_plural_condition_ty *condition;
658 size_t j;
659
660 for (j = 0; j < rules->nitems; j++)
661 if (RULE_PRINTABLE_P (rules->items[j]))
662 break;
663
664 condition = rules->items[j]->condition;
665 for (j = 0; j < SIZEOF (print_condition_functions); j++)
666 if (print_condition_functions[j] (condition, fp))
667 return;
668 }
669
670 /* If there are more printable rules, build a ternary operator. */
671 fprintf (fp, "nplurals=%lu; plural=(", (unsigned long) nplurals);
672 for (i = 0, count = 0; i < rules->nitems; i++)
673 {
674 struct cldr_plural_rule_ty *rule = rules->items[i];
675 if (print_condition (rule->condition,
676 CLDR_PLURAL_CONDITION_FALSE,
677 nplurals == 2,
678 fp)
679 && rules->nitems > 1)
680 {
681 bool printable_left = false;
682 size_t j;
683
684 for (j = i + 1; j < rules->nitems; j++)
685 if (RULE_PRINTABLE_P (rules->items[j]))
686 printable_left = true;
687
688 if (i < rules->nitems - 1 && printable_left)
689 fprintf (fp, " ? %lu : ", (unsigned long) count++);
690 }
691 }
692 if (rules->nitems > 1)
693 fprintf (fp, " ? %lu : %lu",
694 (unsigned long) count, (unsigned long) (count + 1));
695 fprintf (fp, ");\n");
696 }