groff before CVS: release 1.06
[s-roff.git] / refer / label.cc
blobdd88fa93ccb863c57a2325349245b7fd67cc6389
2 /* A Bison parser, made from label.y */
4 #define YYBISON 1 /* Identify Bison output. */
6 #define TOKEN_LETTER 258
7 #define TOKEN_LITERAL 259
8 #define TOKEN_DIGIT 260
10 #line 21 "label.y"
13 #include "refer.h"
14 #include "refid.h"
15 #include "ref.h"
16 #include "token.h"
18 int yylex();
19 void yyerror(const char *);
20 int yyparse();
22 static const char *format_serial(char c, int n);
24 struct label_info {
25 int start;
26 int length;
27 int count;
28 int total;
29 label_info(const string &);
32 label_info *lookup_label(const string &label);
34 struct expression {
35 enum {
36 // Does the tentative label depend on the reference?
37 CONTAINS_VARIABLE = 01,
38 CONTAINS_STAR = 02,
39 CONTAINS_FORMAT = 04,
40 CONTAINS_AT = 010
42 virtual ~expression() { }
43 virtual void evaluate(int, const reference &, string &,
44 substring_position &) = 0;
45 virtual unsigned analyze() { return 0; }
48 class at_expr : public expression {
49 public:
50 at_expr() { }
51 void evaluate(int, const reference &, string &, substring_position &);
52 unsigned analyze() { return CONTAINS_VARIABLE|CONTAINS_AT; }
55 class format_expr : public expression {
56 char type;
57 int width;
58 int first_number;
59 public:
60 format_expr(char c, int w = 0, int f = 1)
61 : type(c), width(w), first_number(f) { }
62 void evaluate(int, const reference &, string &, substring_position &);
63 unsigned analyze() { return CONTAINS_FORMAT; }
66 class field_expr : public expression {
67 int number;
68 char name;
69 public:
70 field_expr(char nm, int num) : name(nm), number(num) { }
71 void evaluate(int, const reference &, string &, substring_position &);
72 unsigned analyze() { return CONTAINS_VARIABLE; }
75 class literal_expr : public expression {
76 string s;
77 public:
78 literal_expr(const char *ptr, int len) : s(ptr, len) { }
79 void evaluate(int, const reference &, string &, substring_position &);
82 class unary_expr : public expression {
83 protected:
84 expression *expr;
85 public:
86 unary_expr(expression *e) : expr(e) { }
87 ~unary_expr() { delete expr; }
88 void evaluate(int, const reference &, string &, substring_position &) = 0;
89 unsigned analyze() { return expr ? expr->analyze() : 0; }
92 // This caches the analysis of an expression.
94 class analyzed_expr : public unary_expr {
95 unsigned flags;
96 public:
97 analyzed_expr(expression *);
98 void evaluate(int, const reference &, string &, substring_position &);
99 unsigned analyze() { return flags; }
102 class star_expr : public unary_expr {
103 public:
104 star_expr(expression *e) : unary_expr(e) { }
105 void evaluate(int, const reference &, string &, substring_position &);
106 unsigned analyze() {
107 return ((expr ? (expr->analyze() & ~CONTAINS_VARIABLE) : 0)
108 | CONTAINS_STAR);
112 typedef void map_t(const char *, const char *, string &);
114 class map_expr : public unary_expr {
115 map_t *func;
116 public:
117 map_expr(expression *e, map_t *f) : unary_expr(e), func(f) { }
118 void evaluate(int, const reference &, string &, substring_position &);
121 typedef const char *extractor_t(const char *, const char *, const char **);
123 class extractor_expr : public unary_expr {
124 int part;
125 extractor_t *func;
126 public:
127 enum { BEFORE = +1, MATCH = 0, AFTER = -1 };
128 extractor_expr(expression *e, extractor_t *f, int pt)
129 : unary_expr(e), func(f), part(pt) { }
130 void evaluate(int, const reference &, string &, substring_position &);
133 class truncate_expr : public unary_expr {
134 int n;
135 public:
136 truncate_expr(expression *e, int i) : n(i), unary_expr(e) { }
137 void evaluate(int, const reference &, string &, substring_position &);
140 class separator_expr : public unary_expr {
141 public:
142 separator_expr(expression *e) : unary_expr(e) { }
143 void evaluate(int, const reference &, string &, substring_position &);
146 class binary_expr : public expression {
147 protected:
148 expression *expr1;
149 expression *expr2;
150 public:
151 binary_expr(expression *e1, expression *e2) : expr1(e1), expr2(e2) { }
152 ~binary_expr() { delete expr1; delete expr2; }
153 void evaluate(int, const reference &, string &, substring_position &) = 0;
154 unsigned analyze() {
155 return (expr1 ? expr1->analyze() : 0) | (expr2 ? expr2->analyze() : 0);
159 class alternative_expr : public binary_expr {
160 public:
161 alternative_expr(expression *e1, expression *e2) : binary_expr(e1, e2) { }
162 void evaluate(int, const reference &, string &, substring_position &);
165 class list_expr : public binary_expr {
166 public:
167 list_expr(expression *e1, expression *e2) : binary_expr(e1, e2) { }
168 void evaluate(int, const reference &, string &, substring_position &);
171 class substitute_expr : public binary_expr {
172 public:
173 substitute_expr(expression *e1, expression *e2) : binary_expr(e1, e2) { }
174 void evaluate(int, const reference &, string &, substring_position &);
177 class ternary_expr : public expression {
178 protected:
179 expression *expr1;
180 expression *expr2;
181 expression *expr3;
182 public:
183 ternary_expr(expression *e1, expression *e2, expression *e3)
184 : expr1(e1), expr2(e2), expr3(e3) { }
185 ~ternary_expr() { delete expr1; delete expr2; delete expr3; }
186 void evaluate(int, const reference &, string &, substring_position &) = 0;
187 unsigned analyze() {
188 return ((expr1 ? expr1->analyze() : 0)
189 | (expr2 ? expr2->analyze() : 0)
190 | (expr3 ? expr3->analyze() : 0));
194 class conditional_expr : public ternary_expr {
195 public:
196 conditional_expr(expression *e1, expression *e2, expression *e3)
197 : ternary_expr(e1, e2, e3) { }
198 void evaluate(int, const reference &, string &, substring_position &);
201 static expression *parsed_label = 0;
202 static expression *parsed_date_label = 0;
203 static expression *parsed_short_label = 0;
205 static expression *parse_result;
207 string literals;
210 #line 221 "label.y"
211 typedef union {
212 int num;
213 expression *expr;
214 struct { int ndigits; int val; } dig;
215 struct { int start; int len; } str;
216 } YYSTYPE;
218 #ifndef YYLTYPE
219 typedef
220 struct yyltype
222 int timestamp;
223 int first_line;
224 int first_column;
225 int last_line;
226 int last_column;
227 char *text;
229 yyltype;
231 #define YYLTYPE yyltype
232 #endif
234 #include <stdio.h>
236 #ifndef __STDC__
237 #define const
238 #endif
242 #define YYFINAL 49
243 #define YYFLAG -32768
244 #define YYNTBASE 21
246 #define YYTRANSLATE(x) ((unsigned)(x) <= 260 ? yytranslate[x] : 32)
248 static const char yytranslate[] = { 0,
249 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
250 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
251 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
252 2, 2, 2, 2, 2, 2, 12, 9, 2, 17,
253 18, 16, 14, 2, 15, 13, 2, 2, 2, 2,
254 2, 2, 2, 2, 2, 2, 2, 7, 2, 19,
255 2, 20, 6, 11, 2, 2, 2, 2, 2, 2,
256 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
257 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
258 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
259 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
260 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
261 2, 2, 2, 8, 2, 10, 2, 2, 2, 2,
262 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
263 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
264 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
265 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
266 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
267 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
268 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
269 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
270 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
271 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
272 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
273 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
274 2, 2, 2, 2, 2, 1, 2, 3, 4, 5
277 #if YYDEBUG != 0
278 static const short yyprhs[] = { 0,
279 0, 2, 4, 10, 11, 13, 15, 19, 23, 25,
280 28, 30, 34, 36, 38, 40, 43, 46, 49, 55,
281 59, 63, 66, 70, 74, 75, 77, 79, 82, 84,
282 87, 88, 90
285 #endif
287 static const short yyrhs[] = { 23,
288 0, 24, 0, 24, 6, 23, 7, 22, 0, 0,
289 22, 0, 25, 0, 24, 8, 25, 0, 24, 9,
290 25, 0, 26, 0, 25, 26, 0, 27, 0, 26,
291 10, 27, 0, 11, 0, 4, 0, 3, 0, 3,
292 29, 0, 12, 3, 0, 12, 30, 0, 27, 13,
293 31, 3, 28, 0, 27, 14, 29, 0, 27, 15,
294 29, 0, 27, 16, 0, 17, 23, 18, 0, 19,
295 23, 20, 0, 0, 29, 0, 5, 0, 29, 5,
296 0, 5, 0, 30, 5, 0, 0, 14, 0, 15,
300 #if YYDEBUG != 0
301 static const short yyrline[] = { 0,
302 248, 253, 256, 260, 263, 267, 270, 272, 276, 279,
303 283, 286, 290, 293, 298, 300, 302, 318, 322, 353,
304 355, 357, 359, 361, 365, 368, 372, 375, 379, 382,
305 387, 390, 392
308 static const char * const yytname[] = { "$","error","$illegal.","TOKEN_LETTER",
309 "TOKEN_LITERAL","TOKEN_DIGIT","'?'","':'","'|'","'&'","'~'","'@'","'%'","'.'",
310 "'+'","'-'","'*'","'('","')'","'<'","'>'","expr","conditional","optional_conditional",
311 "alternative","list","substitute","string","optional_number","number","digits",
312 "flag",""
314 #endif
316 static const short yyr1[] = { 0,
317 21, 22, 22, 23, 23, 24, 24, 24, 25, 25,
318 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
319 27, 27, 27, 27, 28, 28, 29, 29, 30, 30,
320 31, 31, 31
323 static const short yyr2[] = { 0,
324 1, 1, 5, 0, 1, 1, 3, 3, 1, 2,
325 1, 3, 1, 1, 1, 2, 2, 2, 5, 3,
326 3, 2, 3, 3, 0, 1, 1, 2, 1, 2,
327 0, 1, 1
330 static const short yydefact[] = { 4,
331 15, 14, 13, 0, 4, 4, 5, 1, 2, 6,
332 9, 11, 27, 16, 17, 29, 18, 0, 0, 4,
333 0, 0, 10, 0, 31, 0, 0, 22, 28, 30,
334 23, 24, 0, 7, 8, 12, 32, 33, 0, 20,
335 21, 0, 25, 3, 19, 26, 0, 0, 0
338 static const short yydefgoto[] = { 47,
339 7, 8, 9, 10, 11, 12, 45, 14, 17, 39
342 static const short yypact[] = { 0,
343 4,-32768,-32768, 5, 0, 0,-32768,-32768, 7, 0,
344 -5, 13,-32768, 15,-32768,-32768, 27, -4, 14, 0,
345 0, 0, -5, 0, 8, 4, 4,-32768,-32768,-32768,
346 -32768,-32768, 26, 0, 0, 13,-32768,-32768, 32, 15,
347 15, 0, 4,-32768,-32768, 15, 36, 37,-32768
350 static const short yypgoto[] = {-32768,
351 -3, 1,-32768, 9, -10, 16,-32768, -25,-32768,-32768
355 #define YYLAST 40
358 static const short yytable[] = { 23,
359 40, 41, 1, 2, 24, 18, 19, 15, 13, 16,
360 3, 4, 20, 31, 21, 22, 5, 46, 6, 29,
361 33, 37, 38, 23, 23, 25, 26, 27, 28, 34,
362 35, 30, 42, 32, 43, 48, 49, 0, 44, 36
365 static const short yycheck[] = { 10,
366 26, 27, 3, 4, 10, 5, 6, 3, 5, 5,
367 11, 12, 6, 18, 8, 9, 17, 43, 19, 5,
368 20, 14, 15, 34, 35, 13, 14, 15, 16, 21,
369 22, 5, 7, 20, 3, 0, 0, -1, 42, 24
371 /* -*-C-*- Note some compilers choke on comments on `#line' lines. */
372 #line 3 "/usr/local/lib/bison.simple"
374 /* Skeleton output parser for bison,
375 Copyright (C) 1984, 1989, 1990 Bob Corbett and Richard Stallman
377 This program is free software; you can redistribute it and/or modify
378 it under the terms of the GNU General Public License as published by
379 the Free Software Foundation; either version 2, or (at your option)
380 any later version.
382 This program is distributed in the hope that it will be useful,
383 but WITHOUT ANY WARRANTY; without even the implied warranty of
384 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
385 GNU General Public License for more details.
387 You should have received a copy of the GNU General Public License
388 along with this program; if not, write to the Free Software
389 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
392 #ifndef alloca
393 #ifdef __GNUC__
394 #define alloca __builtin_alloca
395 #else /* not GNU C. */
396 #if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc)
397 #include <alloca.h>
398 #else /* not sparc */
399 #if defined (MSDOS) && !defined (__TURBOC__)
400 #include <malloc.h>
401 #else /* not MSDOS, or __TURBOC__ */
402 #if defined(_AIX)
403 #include <malloc.h>
404 #pragma alloca
405 #endif /* not _AIX */
406 #endif /* not MSDOS, or __TURBOC__ */
407 #endif /* not sparc. */
408 #endif /* not GNU C. */
409 #endif /* alloca not defined. */
411 /* This is the parser code that is written into each bison parser
412 when the %semantic_parser declaration is not specified in the grammar.
413 It was written by Richard Stallman by simplifying the hairy parser
414 used when %semantic_parser is specified. */
416 /* Note: there must be only one dollar sign in this file.
417 It is replaced by the list of actions, each action
418 as one case of the switch. */
420 #define yyerrok (yyerrstatus = 0)
421 #define yyclearin (yychar = YYEMPTY)
422 #define YYEMPTY -2
423 #define YYEOF 0
424 #define YYACCEPT return(0)
425 #define YYABORT return(1)
426 #define YYERROR goto yyerrlab1
427 /* Like YYERROR except do call yyerror.
428 This remains here temporarily to ease the
429 transition to the new meaning of YYERROR, for GCC.
430 Once GCC version 2 has supplanted version 1, this can go. */
431 #define YYFAIL goto yyerrlab
432 #define YYRECOVERING() (!!yyerrstatus)
433 #define YYBACKUP(token, value) \
434 do \
435 if (yychar == YYEMPTY && yylen == 1) \
436 { yychar = (token), yylval = (value); \
437 yychar1 = YYTRANSLATE (yychar); \
438 YYPOPSTACK; \
439 goto yybackup; \
441 else \
442 { yyerror ("syntax error: cannot back up"); YYERROR; } \
443 while (0)
445 #define YYTERROR 1
446 #define YYERRCODE 256
448 #ifndef YYPURE
449 #define YYLEX yylex()
450 #endif
452 #ifdef YYPURE
453 #ifdef YYLSP_NEEDED
454 #define YYLEX yylex(&yylval, &yylloc)
455 #else
456 #define YYLEX yylex(&yylval)
457 #endif
458 #endif
460 /* If nonreentrant, generate the variables here */
462 #ifndef YYPURE
464 int yychar; /* the lookahead symbol */
465 YYSTYPE yylval; /* the semantic value of the */
466 /* lookahead symbol */
468 #ifdef YYLSP_NEEDED
469 YYLTYPE yylloc; /* location data for the lookahead */
470 /* symbol */
471 #endif
473 int yynerrs; /* number of parse errors so far */
474 #endif /* not YYPURE */
476 #if YYDEBUG != 0
477 int yydebug; /* nonzero means print parse trace */
478 /* Since this is uninitialized, it does not stop multiple parsers
479 from coexisting. */
480 #endif
482 /* YYINITDEPTH indicates the initial size of the parser's stacks */
484 #ifndef YYINITDEPTH
485 #define YYINITDEPTH 200
486 #endif
488 /* YYMAXDEPTH is the maximum size the stacks can grow to
489 (effective only if the built-in stack extension method is used). */
491 #if YYMAXDEPTH == 0
492 #undef YYMAXDEPTH
493 #endif
495 #ifndef YYMAXDEPTH
496 #define YYMAXDEPTH 10000
497 #endif
499 #if __GNUC__ > 1 /* GNU C and GNU C++ define this. */
500 #define __yy_bcopy(FROM,TO,COUNT) __builtin_memcpy(TO,FROM,COUNT)
501 #else /* not GNU C or C++ */
502 #ifndef __cplusplus
504 /* This is the most reliable way to avoid incompatibilities
505 in available built-in functions on various systems. */
506 static void
507 __yy_bcopy (from, to, count)
508 char *from;
509 char *to;
510 int count;
512 register char *f = from;
513 register char *t = to;
514 register int i = count;
516 while (i-- > 0)
517 *t++ = *f++;
520 #else /* __cplusplus */
522 /* This is the most reliable way to avoid incompatibilities
523 in available built-in functions on various systems. */
524 static void
525 __yy_bcopy (char *from, char *to, int count)
527 register char *f = from;
528 register char *t = to;
529 register int i = count;
531 while (i-- > 0)
532 *t++ = *f++;
535 #endif
536 #endif
538 #line 169 "/usr/local/lib/bison.simple"
540 yyparse()
542 register int yystate;
543 register int yyn;
544 register short *yyssp;
545 register YYSTYPE *yyvsp;
546 int yyerrstatus; /* number of tokens to shift before error messages enabled */
547 int yychar1; /* lookahead token as an internal (translated) token number */
549 short yyssa[YYINITDEPTH]; /* the state stack */
550 YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */
552 short *yyss = yyssa; /* refer to the stacks thru separate pointers */
553 YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */
555 #ifdef YYLSP_NEEDED
556 YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */
557 YYLTYPE *yyls = yylsa;
558 YYLTYPE *yylsp;
560 #define YYPOPSTACK (yyvsp--, yyssp--, yylsp--)
561 #else
562 #define YYPOPSTACK (yyvsp--, yyssp--)
563 #endif
565 int yystacksize = YYINITDEPTH;
567 #ifdef YYPURE
568 int yychar;
569 YYSTYPE yylval;
570 int yynerrs;
571 #ifdef YYLSP_NEEDED
572 YYLTYPE yylloc;
573 #endif
574 #endif
576 YYSTYPE yyval; /* the variable used to return */
577 /* semantic values from the action */
578 /* routines */
580 int yylen;
582 #if YYDEBUG != 0
583 if (yydebug)
584 fprintf(stderr, "Starting parse\n");
585 #endif
587 yystate = 0;
588 yyerrstatus = 0;
589 yynerrs = 0;
590 yychar = YYEMPTY; /* Cause a token to be read. */
592 /* Initialize stack pointers.
593 Waste one element of value and location stack
594 so that they stay on the same level as the state stack. */
596 yyssp = yyss - 1;
597 yyvsp = yyvs;
598 #ifdef YYLSP_NEEDED
599 yylsp = yyls;
600 #endif
602 /* Push a new state, which is found in yystate . */
603 /* In all cases, when you get here, the value and location stacks
604 have just been pushed. so pushing a state here evens the stacks. */
605 yynewstate:
607 *++yyssp = yystate;
609 if (yyssp >= yyss + yystacksize - 1)
611 /* Give user a chance to reallocate the stack */
612 /* Use copies of these so that the &'s don't force the real ones into memory. */
613 YYSTYPE *yyvs1 = yyvs;
614 short *yyss1 = yyss;
615 #ifdef YYLSP_NEEDED
616 YYLTYPE *yyls1 = yyls;
617 #endif
619 /* Get the current used size of the three stacks, in elements. */
620 int size = yyssp - yyss + 1;
622 #ifdef yyoverflow
623 /* Each stack pointer address is followed by the size of
624 the data in use in that stack, in bytes. */
625 yyoverflow("parser stack overflow",
626 &yyss1, size * sizeof (*yyssp),
627 &yyvs1, size * sizeof (*yyvsp),
628 #ifdef YYLSP_NEEDED
629 &yyls1, size * sizeof (*yylsp),
630 #endif
631 &yystacksize);
633 yyss = yyss1; yyvs = yyvs1;
634 #ifdef YYLSP_NEEDED
635 yyls = yyls1;
636 #endif
637 #else /* no yyoverflow */
638 /* Extend the stack our own way. */
639 if (yystacksize >= YYMAXDEPTH)
641 yyerror("parser stack overflow");
642 return 2;
644 yystacksize *= 2;
645 if (yystacksize > YYMAXDEPTH)
646 yystacksize = YYMAXDEPTH;
647 yyss = (short *) alloca (yystacksize * sizeof (*yyssp));
648 __yy_bcopy ((char *)yyss1, (char *)yyss, size * sizeof (*yyssp));
649 yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp));
650 __yy_bcopy ((char *)yyvs1, (char *)yyvs, size * sizeof (*yyvsp));
651 #ifdef YYLSP_NEEDED
652 yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp));
653 __yy_bcopy ((char *)yyls1, (char *)yyls, size * sizeof (*yylsp));
654 #endif
655 #endif /* no yyoverflow */
657 yyssp = yyss + size - 1;
658 yyvsp = yyvs + size - 1;
659 #ifdef YYLSP_NEEDED
660 yylsp = yyls + size - 1;
661 #endif
663 #if YYDEBUG != 0
664 if (yydebug)
665 fprintf(stderr, "Stack size increased to %d\n", yystacksize);
666 #endif
668 if (yyssp >= yyss + yystacksize - 1)
669 YYABORT;
672 #if YYDEBUG != 0
673 if (yydebug)
674 fprintf(stderr, "Entering state %d\n", yystate);
675 #endif
677 yybackup:
679 /* Do appropriate processing given the current state. */
680 /* Read a lookahead token if we need one and don't already have one. */
681 /* yyresume: */
683 /* First try to decide what to do without reference to lookahead token. */
685 yyn = yypact[yystate];
686 if (yyn == YYFLAG)
687 goto yydefault;
689 /* Not known => get a lookahead token if don't already have one. */
691 /* yychar is either YYEMPTY or YYEOF
692 or a valid token in external form. */
694 if (yychar == YYEMPTY)
696 #if YYDEBUG != 0
697 if (yydebug)
698 fprintf(stderr, "Reading a token: ");
699 #endif
700 yychar = YYLEX;
703 /* Convert token to internal form (in yychar1) for indexing tables with */
705 if (yychar <= 0) /* This means end of input. */
707 yychar1 = 0;
708 yychar = YYEOF; /* Don't call YYLEX any more */
710 #if YYDEBUG != 0
711 if (yydebug)
712 fprintf(stderr, "Now at end of input.\n");
713 #endif
715 else
717 yychar1 = YYTRANSLATE(yychar);
719 #if YYDEBUG != 0
720 if (yydebug)
722 fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
723 /* Give the individual parser a way to print the precise meaning
724 of a token, for further debugging info. */
725 #ifdef YYPRINT
726 YYPRINT (stderr, yychar, yylval);
727 #endif
728 fprintf (stderr, ")\n");
730 #endif
733 yyn += yychar1;
734 if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
735 goto yydefault;
737 yyn = yytable[yyn];
739 /* yyn is what to do for this token type in this state.
740 Negative => reduce, -yyn is rule number.
741 Positive => shift, yyn is new state.
742 New state is final state => don't bother to shift,
743 just return success.
744 0, or most negative number => error. */
746 if (yyn < 0)
748 if (yyn == YYFLAG)
749 goto yyerrlab;
750 yyn = -yyn;
751 goto yyreduce;
753 else if (yyn == 0)
754 goto yyerrlab;
756 if (yyn == YYFINAL)
757 YYACCEPT;
759 /* Shift the lookahead token. */
761 #if YYDEBUG != 0
762 if (yydebug)
763 fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
764 #endif
766 /* Discard the token being shifted unless it is eof. */
767 if (yychar != YYEOF)
768 yychar = YYEMPTY;
770 *++yyvsp = yylval;
771 #ifdef YYLSP_NEEDED
772 *++yylsp = yylloc;
773 #endif
775 /* count tokens shifted since error; after three, turn off error status. */
776 if (yyerrstatus) yyerrstatus--;
778 yystate = yyn;
779 goto yynewstate;
781 /* Do the default action for the current state. */
782 yydefault:
784 yyn = yydefact[yystate];
785 if (yyn == 0)
786 goto yyerrlab;
788 /* Do a reduction. yyn is the number of a rule to reduce with. */
789 yyreduce:
790 yylen = yyr2[yyn];
791 yyval = yyvsp[1-yylen]; /* implement default value of the action */
793 #if YYDEBUG != 0
794 if (yydebug)
796 int i;
798 fprintf (stderr, "Reducing via rule %d (line %d), ",
799 yyn, yyrline[yyn]);
801 /* Print the symboles being reduced, and their result. */
802 for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
803 fprintf (stderr, "%s ", yytname[yyrhs[i]]);
804 fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
806 #endif
809 switch (yyn) {
811 case 1:
812 #line 250 "label.y"
813 { parse_result = (yyvsp[0].expr ? new analyzed_expr(yyvsp[0].expr) : 0); ;
814 break;}
815 case 2:
816 #line 255 "label.y"
817 { yyval.expr = yyvsp[0].expr; ;
818 break;}
819 case 3:
820 #line 257 "label.y"
821 { yyval.expr = new conditional_expr(yyvsp[-4].expr, yyvsp[-2].expr, yyvsp[0].expr); ;
822 break;}
823 case 4:
824 #line 262 "label.y"
825 { yyval.expr = 0; ;
826 break;}
827 case 5:
828 #line 264 "label.y"
829 { yyval.expr = yyvsp[0].expr; ;
830 break;}
831 case 6:
832 #line 269 "label.y"
833 { yyval.expr = yyvsp[0].expr; ;
834 break;}
835 case 7:
836 #line 271 "label.y"
837 { yyval.expr = new alternative_expr(yyvsp[-2].expr, yyvsp[0].expr); ;
838 break;}
839 case 8:
840 #line 273 "label.y"
841 { yyval.expr = new conditional_expr(yyvsp[-2].expr, yyvsp[0].expr, 0); ;
842 break;}
843 case 9:
844 #line 278 "label.y"
845 { yyval.expr = yyvsp[0].expr; ;
846 break;}
847 case 10:
848 #line 280 "label.y"
849 { yyval.expr = new list_expr(yyvsp[-1].expr, yyvsp[0].expr); ;
850 break;}
851 case 11:
852 #line 285 "label.y"
853 { yyval.expr = yyvsp[0].expr; ;
854 break;}
855 case 12:
856 #line 287 "label.y"
857 { yyval.expr = new substitute_expr(yyvsp[-2].expr, yyvsp[0].expr); ;
858 break;}
859 case 13:
860 #line 292 "label.y"
861 { yyval.expr = new at_expr; ;
862 break;}
863 case 14:
864 #line 294 "label.y"
866 yyval.expr = new literal_expr(literals.contents() + yyvsp[0].str.start,
867 yyvsp[0].str.len);
869 break;}
870 case 15:
871 #line 299 "label.y"
872 { yyval.expr = new field_expr(yyvsp[0].num, 0); ;
873 break;}
874 case 16:
875 #line 301 "label.y"
876 { yyval.expr = new field_expr(yyvsp[-1].num, yyvsp[0].num - 1); ;
877 break;}
878 case 17:
879 #line 303 "label.y"
881 switch (yyvsp[0].num) {
882 case 'I':
883 case 'i':
884 case 'A':
885 case 'a':
886 yyval.expr = new format_expr(yyvsp[0].num);
887 break;
888 default:
889 command_error("unrecognized format `%1'", char(yyvsp[0].num));
890 yyval.expr = new format_expr('a');
891 break;
894 break;}
895 case 18:
896 #line 319 "label.y"
898 yyval.expr = new format_expr('0', yyvsp[0].dig.ndigits, yyvsp[0].dig.val);
900 break;}
901 case 19:
902 #line 323 "label.y"
904 switch (yyvsp[-1].num) {
905 case 'l':
906 yyval.expr = new map_expr(yyvsp[-4].expr, lowercase);
907 break;
908 case 'u':
909 yyval.expr = new map_expr(yyvsp[-4].expr, uppercase);
910 break;
911 case 'c':
912 yyval.expr = new map_expr(yyvsp[-4].expr, capitalize);
913 break;
914 case 'r':
915 yyval.expr = new map_expr(yyvsp[-4].expr, reverse_name);
916 break;
917 case 'a':
918 yyval.expr = new map_expr(yyvsp[-4].expr, abbreviate_name);
919 break;
920 case 'y':
921 yyval.expr = new extractor_expr(yyvsp[-4].expr, find_year, yyvsp[-2].num);
922 break;
923 case 'n':
924 yyval.expr = new extractor_expr(yyvsp[-4].expr, find_last_name, yyvsp[-2].num);
925 break;
926 default:
927 yyval.expr = yyvsp[-4].expr;
928 command_error("unknown function `%1'", char(yyvsp[-1].num));
929 break;
932 break;}
933 case 20:
934 #line 354 "label.y"
935 { yyval.expr = new truncate_expr(yyvsp[-2].expr, yyvsp[0].num); ;
936 break;}
937 case 21:
938 #line 356 "label.y"
939 { yyval.expr = new truncate_expr(yyvsp[-2].expr, -yyvsp[0].num); ;
940 break;}
941 case 22:
942 #line 358 "label.y"
943 { yyval.expr = new star_expr(yyvsp[-1].expr); ;
944 break;}
945 case 23:
946 #line 360 "label.y"
947 { yyval.expr = yyvsp[-1].expr; ;
948 break;}
949 case 24:
950 #line 362 "label.y"
951 { yyval.expr = new separator_expr(yyvsp[-1].expr); ;
952 break;}
953 case 25:
954 #line 367 "label.y"
955 { yyval.num = -1; ;
956 break;}
957 case 26:
958 #line 369 "label.y"
959 { yyval.num = yyvsp[0].num; ;
960 break;}
961 case 27:
962 #line 374 "label.y"
963 { yyval.num = yyvsp[0].num; ;
964 break;}
965 case 28:
966 #line 376 "label.y"
967 { yyval.num = yyvsp[-1].num*10 + yyvsp[0].num; ;
968 break;}
969 case 29:
970 #line 381 "label.y"
971 { yyval.dig.ndigits = 1; yyval.dig.val = yyvsp[0].num; ;
972 break;}
973 case 30:
974 #line 383 "label.y"
975 { yyval.dig.ndigits = yyvsp[-1].dig.ndigits + 1; yyval.dig.val = yyvsp[-1].dig.val*10 + yyvsp[0].num; ;
976 break;}
977 case 31:
978 #line 389 "label.y"
979 { yyval.num = 0; ;
980 break;}
981 case 32:
982 #line 391 "label.y"
983 { yyval.num = 1; ;
984 break;}
985 case 33:
986 #line 393 "label.y"
987 { yyval.num = -1; ;
988 break;}
990 /* the action file gets copied in in place of this dollarsign */
991 #line 440 "/usr/local/lib/bison.simple"
993 yyvsp -= yylen;
994 yyssp -= yylen;
995 #ifdef YYLSP_NEEDED
996 yylsp -= yylen;
997 #endif
999 #if YYDEBUG != 0
1000 if (yydebug)
1002 short *ssp1 = yyss - 1;
1003 fprintf (stderr, "state stack now");
1004 while (ssp1 != yyssp)
1005 fprintf (stderr, " %d", *++ssp1);
1006 fprintf (stderr, "\n");
1008 #endif
1010 *++yyvsp = yyval;
1012 #ifdef YYLSP_NEEDED
1013 yylsp++;
1014 if (yylen == 0)
1016 yylsp->first_line = yylloc.first_line;
1017 yylsp->first_column = yylloc.first_column;
1018 yylsp->last_line = (yylsp-1)->last_line;
1019 yylsp->last_column = (yylsp-1)->last_column;
1020 yylsp->text = 0;
1022 else
1024 yylsp->last_line = (yylsp+yylen-1)->last_line;
1025 yylsp->last_column = (yylsp+yylen-1)->last_column;
1027 #endif
1029 /* Now "shift" the result of the reduction.
1030 Determine what state that goes to,
1031 based on the state we popped back to
1032 and the rule number reduced by. */
1034 yyn = yyr1[yyn];
1036 yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
1037 if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
1038 yystate = yytable[yystate];
1039 else
1040 yystate = yydefgoto[yyn - YYNTBASE];
1042 goto yynewstate;
1044 yyerrlab: /* here on detecting error */
1046 if (! yyerrstatus)
1047 /* If not already recovering from an error, report this error. */
1049 ++yynerrs;
1051 #ifdef YYERROR_VERBOSE
1052 yyn = yypact[yystate];
1054 if (yyn > YYFLAG && yyn < YYLAST)
1056 int size = 0;
1057 char *msg;
1058 int x, count;
1060 count = 0;
1061 for (x = 0; x < (sizeof(yytname) / sizeof(char *)); x++)
1062 if (yycheck[x + yyn] == x)
1063 size += strlen(yytname[x]) + 15, count++;
1064 msg = (char *) malloc(size + 15);
1065 if (msg != 0)
1067 strcpy(msg, "parse error");
1069 if (count < 5)
1071 count = 0;
1072 for (x = 0; x < (sizeof(yytname) / sizeof(char *)); x++)
1073 if (yycheck[x + yyn] == x)
1075 strcat(msg, count == 0 ? ", expecting `" : " or `");
1076 strcat(msg, yytname[x]);
1077 strcat(msg, "'");
1078 count++;
1081 yyerror(msg);
1082 free(msg);
1084 else
1085 yyerror ("parse error; also virtual memory exceeded");
1087 else
1088 #endif /* YYERROR_VERBOSE */
1089 yyerror("parse error");
1092 yyerrlab1: /* here on error raised explicitly by an action */
1094 if (yyerrstatus == 3)
1096 /* if just tried and failed to reuse lookahead token after an error, discard it. */
1098 /* return failure if at end of input */
1099 if (yychar == YYEOF)
1100 YYABORT;
1102 #if YYDEBUG != 0
1103 if (yydebug)
1104 fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
1105 #endif
1107 yychar = YYEMPTY;
1110 /* Else will try to reuse lookahead token
1111 after shifting the error token. */
1113 yyerrstatus = 3; /* Each real token shifted decrements this */
1115 goto yyerrhandle;
1117 yyerrdefault: /* current state does not do anything special for the error token. */
1119 #if 0
1120 /* This is wrong; only states that explicitly want error tokens
1121 should shift them. */
1122 yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/
1123 if (yyn) goto yydefault;
1124 #endif
1126 yyerrpop: /* pop the current state because it cannot handle the error token */
1128 if (yyssp == yyss) YYABORT;
1129 yyvsp--;
1130 yystate = *--yyssp;
1131 #ifdef YYLSP_NEEDED
1132 yylsp--;
1133 #endif
1135 #if YYDEBUG != 0
1136 if (yydebug)
1138 short *ssp1 = yyss - 1;
1139 fprintf (stderr, "Error: state stack now");
1140 while (ssp1 != yyssp)
1141 fprintf (stderr, " %d", *++ssp1);
1142 fprintf (stderr, "\n");
1144 #endif
1146 yyerrhandle:
1148 yyn = yypact[yystate];
1149 if (yyn == YYFLAG)
1150 goto yyerrdefault;
1152 yyn += YYTERROR;
1153 if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
1154 goto yyerrdefault;
1156 yyn = yytable[yyn];
1157 if (yyn < 0)
1159 if (yyn == YYFLAG)
1160 goto yyerrpop;
1161 yyn = -yyn;
1162 goto yyreduce;
1164 else if (yyn == 0)
1165 goto yyerrpop;
1167 if (yyn == YYFINAL)
1168 YYACCEPT;
1170 #if YYDEBUG != 0
1171 if (yydebug)
1172 fprintf(stderr, "Shifting error token, ");
1173 #endif
1175 *++yyvsp = yylval;
1176 #ifdef YYLSP_NEEDED
1177 *++yylsp = yylloc;
1178 #endif
1180 yystate = yyn;
1181 goto yynewstate;
1183 #line 396 "label.y"
1186 /* bison defines const to be empty unless __STDC__ is defined, which it
1187 isn't under cfront */
1189 #ifdef const
1190 #undef const
1191 #endif
1193 const char *spec_ptr;
1194 const char *spec_end;
1195 const char *spec_cur;
1197 int yylex()
1199 while (spec_ptr < spec_end && csspace(*spec_ptr))
1200 spec_ptr++;
1201 spec_cur = spec_ptr;
1202 if (spec_ptr >= spec_end)
1203 return 0;
1204 unsigned char c = *spec_ptr++;
1205 if (csalpha(c)) {
1206 yylval.num = c;
1207 return TOKEN_LETTER;
1209 if (csdigit(c)) {
1210 yylval.num = c - '0';
1211 return TOKEN_DIGIT;
1213 if (c == '\'') {
1214 yylval.str.start = literals.length();
1215 for (; spec_ptr < spec_end; spec_ptr++) {
1216 if (*spec_ptr == '\'') {
1217 if (++spec_ptr < spec_end && *spec_ptr == '\'')
1218 literals += '\'';
1219 else {
1220 yylval.str.len = literals.length() - yylval.str.start;
1221 return TOKEN_LITERAL;
1224 else
1225 literals += *spec_ptr;
1227 yylval.str.len = literals.length() - yylval.str.start;
1228 return TOKEN_LITERAL;
1230 return c;
1233 int set_label_spec(const char *label_spec)
1235 spec_cur = spec_ptr = label_spec;
1236 spec_end = strchr(label_spec, '\0');
1237 literals.clear();
1238 if (yyparse())
1239 return 0;
1240 delete parsed_label;
1241 parsed_label = parse_result;
1242 return 1;
1245 int set_date_label_spec(const char *label_spec)
1247 spec_cur = spec_ptr = label_spec;
1248 spec_end = strchr(label_spec, '\0');
1249 literals.clear();
1250 if (yyparse())
1251 return 0;
1252 delete parsed_date_label;
1253 parsed_date_label = parse_result;
1254 return 1;
1257 int set_short_label_spec(const char *label_spec)
1259 spec_cur = spec_ptr = label_spec;
1260 spec_end = strchr(label_spec, '\0');
1261 literals.clear();
1262 if (yyparse())
1263 return 0;
1264 delete parsed_short_label;
1265 parsed_short_label = parse_result;
1266 return 1;
1269 void yyerror(const char *message)
1271 if (spec_cur < spec_end)
1272 command_error("label specification %1 before `%2'", message, spec_cur);
1273 else
1274 command_error("label specification %1 at end of string",
1275 message, spec_cur);
1278 void at_expr::evaluate(int tentative, const reference &ref,
1279 string &result, substring_position &)
1281 if (tentative)
1282 ref.canonicalize_authors(result);
1283 else {
1284 const char *end, *start = ref.get_authors(&end);
1285 if (start)
1286 result.append(start, end - start);
1290 void format_expr::evaluate(int tentative, const reference &ref,
1291 string &result, substring_position &)
1293 if (tentative)
1294 return;
1295 const label_info *lp = ref.get_label_ptr();
1296 int num = lp == 0 ? ref.get_number() : lp->count;
1297 if (type != '0')
1298 result += format_serial(type, num + 1);
1299 else {
1300 const char *ptr = itoa(num + first_number);
1301 int pad = width - strlen(ptr);
1302 while (--pad >= 0)
1303 result += '0';
1304 result += ptr;
1308 static const char *format_serial(char c, int n)
1310 assert(n > 0);
1311 static char buf[128]; // more than enough.
1312 switch (c) {
1313 case 'i':
1314 case 'I':
1316 char *p = buf;
1317 // troff uses z and w to represent 10000 and 5000 in Roman
1318 // numerals; I can find no historical basis for this usage
1319 const char *s = c == 'i' ? "zwmdclxvi" : "ZWMDCLXVI";
1320 if (n >= 40000)
1321 return itoa(n);
1322 while (n >= 10000) {
1323 *p++ = s[0];
1324 n -= 10000;
1326 for (int i = 1000; i > 0; i /= 10, s += 2) {
1327 int m = n/i;
1328 n -= m*i;
1329 switch (m) {
1330 case 3:
1331 *p++ = s[2];
1332 /* falls through */
1333 case 2:
1334 *p++ = s[2];
1335 /* falls through */
1336 case 1:
1337 *p++ = s[2];
1338 break;
1339 case 4:
1340 *p++ = s[2];
1341 *p++ = s[1];
1342 break;
1343 case 8:
1344 *p++ = s[1];
1345 *p++ = s[2];
1346 *p++ = s[2];
1347 *p++ = s[2];
1348 break;
1349 case 7:
1350 *p++ = s[1];
1351 *p++ = s[2];
1352 *p++ = s[2];
1353 break;
1354 case 6:
1355 *p++ = s[1];
1356 *p++ = s[2];
1357 break;
1358 case 5:
1359 *p++ = s[1];
1360 break;
1361 case 9:
1362 *p++ = s[2];
1363 *p++ = s[0];
1366 *p = 0;
1367 break;
1369 case 'a':
1370 case 'A':
1372 char *p = buf;
1373 // this is derived from troff/reg.c
1374 while (n > 0) {
1375 int d = n % 26;
1376 if (d == 0)
1377 d = 26;
1378 n -= d;
1379 n /= 26;
1380 *p++ = c + d - 1; // ASCII dependent
1382 *p-- = 0;
1383 // Reverse it.
1384 char *q = buf;
1385 while (q < p) {
1386 char temp = *q;
1387 *q = *p;
1388 *p = temp;
1389 --p;
1390 ++q;
1392 break;
1394 default:
1395 assert(0);
1397 return buf;
1400 void field_expr::evaluate(int, const reference &ref,
1401 string &result, substring_position &)
1403 const char *end;
1404 const char *start = ref.get_field(name, &end);
1405 if (start) {
1406 start = nth_field(number, start, &end);
1407 if (start)
1408 result.append(start, end - start);
1412 void literal_expr::evaluate(int, const reference &,
1413 string &result, substring_position &)
1415 result += s;
1418 analyzed_expr::analyzed_expr(expression *e)
1419 : unary_expr(e), flags(e ? e->analyze() : 0)
1423 void analyzed_expr::evaluate(int tentative, const reference &ref,
1424 string &result, substring_position &pos)
1426 if (expr)
1427 expr->evaluate(tentative, ref, result, pos);
1430 void star_expr::evaluate(int tentative, const reference &ref,
1431 string &result, substring_position &pos)
1433 const label_info *lp = ref.get_label_ptr();
1434 if (!tentative
1435 && (lp == 0 || lp->total > 1)
1436 && expr)
1437 expr->evaluate(tentative, ref, result, pos);
1440 void separator_expr::evaluate(int tentative, const reference &ref,
1441 string &result, substring_position &pos)
1443 int start_length = result.length();
1444 int is_first = pos.start < 0;
1445 if (expr)
1446 expr->evaluate(tentative, ref, result, pos);
1447 if (is_first) {
1448 pos.start = start_length;
1449 pos.length = result.length() - start_length;
1453 void map_expr::evaluate(int tentative, const reference &ref,
1454 string &result, substring_position &)
1456 if (expr) {
1457 string temp;
1458 substring_position temp_pos;
1459 expr->evaluate(tentative, ref, temp, temp_pos);
1460 (*func)(temp.contents(), temp.contents() + temp.length(), result);
1464 void extractor_expr::evaluate(int tentative, const reference &ref,
1465 string &result, substring_position &)
1467 if (expr) {
1468 string temp;
1469 substring_position temp_pos;
1470 expr->evaluate(tentative, ref, temp, temp_pos);
1471 const char *end, *start = (*func)(temp.contents(),
1472 temp.contents() + temp.length(),
1473 &end);
1474 switch (part) {
1475 case BEFORE:
1476 if (start)
1477 result.append(temp.contents(), start - temp.contents());
1478 else
1479 result += temp;
1480 break;
1481 case MATCH:
1482 if (start)
1483 result.append(start, end - start);
1484 break;
1485 case AFTER:
1486 if (start)
1487 result.append(end, temp.contents() + temp.length() - end);
1488 break;
1489 default:
1490 assert(0);
1495 static void first_part(int len, const char *ptr, const char *end,
1496 string &result)
1498 for (;;) {
1499 const char *token_start = ptr;
1500 if (!get_token(&ptr, end))
1501 break;
1502 const token_info *ti = lookup_token(token_start, ptr);
1503 int counts = ti->sortify_non_empty(token_start, ptr);
1504 if (counts && --len < 0)
1505 break;
1506 if (counts || ti->is_accent())
1507 result.append(token_start, ptr - token_start);
1511 static void last_part(int len, const char *ptr, const char *end,
1512 string &result)
1514 const char *start = ptr;
1515 int count = 0;
1516 for (;;) {
1517 const char *token_start = ptr;
1518 if (!get_token(&ptr, end))
1519 break;
1520 const token_info *ti = lookup_token(token_start, ptr);
1521 if (ti->sortify_non_empty(token_start, ptr))
1522 count++;
1524 ptr = start;
1525 int skip = count - len;
1526 if (skip > 0) {
1527 for (;;) {
1528 const char *token_start = ptr;
1529 if (!get_token(&ptr, end))
1530 assert(0);
1531 const token_info *ti = lookup_token(token_start, ptr);
1532 if (ti->sortify_non_empty(token_start, ptr) && --skip < 0) {
1533 ptr = token_start;
1534 break;
1538 first_part(len, ptr, end, result);
1541 void truncate_expr::evaluate(int tentative, const reference &ref,
1542 string &result, substring_position &)
1544 if (expr) {
1545 string temp;
1546 substring_position temp_pos;
1547 expr->evaluate(tentative, ref, temp, temp_pos);
1548 const char *start = temp.contents();
1549 const char *end = start + temp.length();
1550 if (n > 0)
1551 first_part(n, start, end, result);
1552 else if (n < 0)
1553 last_part(-n, start, end, result);
1557 void alternative_expr::evaluate(int tentative, const reference &ref,
1558 string &result, substring_position &pos)
1560 int start_length = result.length();
1561 if (expr1)
1562 expr1->evaluate(tentative, ref, result, pos);
1563 if (result.length() == start_length && expr2)
1564 expr2->evaluate(tentative, ref, result, pos);
1567 void list_expr::evaluate(int tentative, const reference &ref,
1568 string &result, substring_position &pos)
1570 if (expr1)
1571 expr1->evaluate(tentative, ref, result, pos);
1572 if (expr2)
1573 expr2->evaluate(tentative, ref, result, pos);
1576 void substitute_expr::evaluate(int tentative, const reference &ref,
1577 string &result, substring_position &pos)
1579 int start_length = result.length();
1580 if (expr1)
1581 expr1->evaluate(tentative, ref, result, pos);
1582 if (result.length() > start_length && result[result.length() - 1] == '-') {
1583 // ought to see if pos covers the -
1584 result.set_length(result.length() - 1);
1585 if (expr2)
1586 expr2->evaluate(tentative, ref, result, pos);
1590 void conditional_expr::evaluate(int tentative, const reference &ref,
1591 string &result, substring_position &pos)
1593 string temp;
1594 substring_position temp_pos;
1595 if (expr1)
1596 expr1->evaluate(tentative, ref, temp, temp_pos);
1597 if (temp.length() > 0) {
1598 if (expr2)
1599 expr2->evaluate(tentative, ref, result, pos);
1601 else {
1602 if (expr3)
1603 expr3->evaluate(tentative, ref, result, pos);
1607 void reference::pre_compute_label()
1609 if (parsed_label != 0
1610 && (parsed_label->analyze() & expression::CONTAINS_VARIABLE)) {
1611 label.clear();
1612 substring_position temp_pos;
1613 parsed_label->evaluate(1, *this, label, temp_pos);
1614 label_ptr = lookup_label(label);
1618 void reference::compute_label()
1620 label.clear();
1621 if (parsed_label)
1622 parsed_label->evaluate(0, *this, label, separator_pos);
1623 if (short_label_flag && parsed_short_label)
1624 parsed_short_label->evaluate(0, *this, short_label, short_separator_pos);
1625 if (date_as_label) {
1626 string new_date;
1627 if (parsed_date_label) {
1628 substring_position temp_pos;
1629 parsed_date_label->evaluate(0, *this, new_date, temp_pos);
1631 set_date(new_date);
1633 if (label_ptr)
1634 label_ptr->count += 1;
1637 void reference::immediate_compute_label()
1639 if (label_ptr)
1640 label_ptr->total = 2; // force use of disambiguator
1641 compute_label();
1644 int reference::merge_labels(reference **v, int n, label_type type,
1645 string &result)
1647 if (abbreviate_label_ranges)
1648 return merge_labels_by_number(v, n, type, result);
1649 else
1650 return merge_labels_by_parts(v, n, type, result);
1653 int reference::merge_labels_by_number(reference **v, int n, label_type type,
1654 string &result)
1656 if (n <= 1)
1657 return 0;
1658 int num = get_number();
1659 // Only merge three or more labels.
1660 if (v[0]->get_number() != num + 1
1661 || v[1]->get_number() != num + 2)
1662 return 0;
1663 for (int i = 2; i < n; i++)
1664 if (v[i]->get_number() != num + i + 1)
1665 break;
1666 result = get_label(type);
1667 result += label_range_indicator;
1668 result += v[i - 1]->get_label(type);
1669 return i;
1672 const substring_position &reference::get_separator_pos(label_type type) const
1674 if (type == SHORT_LABEL && short_label_flag)
1675 return short_separator_pos;
1676 else
1677 return separator_pos;
1680 const string &reference::get_label(label_type type) const
1682 if (type == SHORT_LABEL && short_label_flag)
1683 return short_label;
1684 else
1685 return label;
1688 int reference::merge_labels_by_parts(reference **v, int n, label_type type,
1689 string &result)
1691 if (n <= 0)
1692 return 0;
1693 const string &lb = get_label(type);
1694 const substring_position &sp = get_separator_pos(type);
1695 if (sp.start < 0
1696 || sp.start != v[0]->get_separator_pos(type).start
1697 || memcmp(lb.contents(), v[0]->get_label(type).contents(),
1698 sp.start) != 0)
1699 return 0;
1700 result = lb;
1701 int i = 0;
1702 do {
1703 result += separate_label_second_parts;
1704 const substring_position &s = v[i]->get_separator_pos(type);
1705 int sep_end_pos = s.start + s.length;
1706 result.append(v[i]->get_label(type).contents() + sep_end_pos,
1707 v[i]->get_label(type).length() - sep_end_pos);
1708 } while (++i < n
1709 && sp.start == v[i]->get_separator_pos(type).start
1710 && memcmp(lb.contents(), v[i]->get_label(type).contents(),
1711 sp.start) == 0);
1712 return i;
1715 string label_pool;
1717 label_info::label_info(const string &s)
1718 : count(0), total(1), length(s.length()), start(label_pool.length())
1720 label_pool += s;
1723 static label_info **label_table = 0;
1724 static int label_table_size = 0;
1725 static int label_table_used = 0;
1727 label_info *lookup_label(const string &label)
1729 if (label_table == 0) {
1730 label_table = new label_info *[17];
1731 label_table_size = 17;
1732 for (int i = 0; i < 17; i++)
1733 label_table[i] = 0;
1735 unsigned h = hash_string(label.contents(), label.length()) % label_table_size;
1736 for (label_info **ptr = label_table + h;
1737 *ptr != 0;
1738 (ptr == label_table)
1739 ? (ptr = label_table + label_table_size - 1)
1740 : ptr--)
1741 if ((*ptr)->length == label.length()
1742 && memcmp(label_pool.contents() + (*ptr)->start, label.contents(),
1743 label.length()) == 0) {
1744 (*ptr)->total += 1;
1745 return *ptr;
1747 label_info *result = *ptr = new label_info(label);
1748 if (++label_table_used * 2 > label_table_size) {
1749 // Rehash the table.
1750 label_info **old_table = label_table;
1751 int old_size = label_table_size;
1752 label_table_size = next_size(label_table_size);
1753 label_table = new label_info *[label_table_size];
1754 int i;
1755 for (i = 0; i < label_table_size; i++)
1756 label_table[i] = 0;
1757 for (i = 0; i < old_size; i++)
1758 if (old_table[i]) {
1759 unsigned h = hash_string(label_pool.contents() + old_table[i]->start,
1760 old_table[i]->length);
1761 for (label_info **p = label_table + (h % label_table_size);
1762 *p != 0;
1763 (p == label_table)
1764 ? (p = label_table + label_table_size - 1)
1765 : --p)
1767 *p = old_table[i];
1769 a_delete old_table;
1771 return result;
1774 void clear_labels()
1776 for (int i = 0; i < label_table_size; i++) {
1777 delete label_table[i];
1778 label_table[i] = 0;
1780 label_table_used = 0;
1781 label_pool.clear();
1784 static void consider_authors(reference **start, reference **end, int i);
1786 void compute_labels(reference **v, int n)
1788 if (parsed_label
1789 && (parsed_label->analyze() & expression::CONTAINS_AT)
1790 && sort_fields.length() >= 2
1791 && sort_fields[0] == 'A'
1792 && sort_fields[1] == '+')
1793 consider_authors(v, v + n, 0);
1794 for (int i = 0; i < n; i++)
1795 v[i]->compute_label();
1799 /* A reference with a list of authors <A0,A1,...,AN> _needs_ author i
1800 where 0 <= i <= N if there exists a reference with a list of authors
1801 <B0,B1,...,BM> such that <A0,A1,...,AN> != <B0,B1,...,BM> and M >= i
1802 and Aj = Bj for 0 <= j < i. In this case if we can't say ``A0,
1803 A1,...,A(i-1) et al'' because this would match both <A0,A1,...,AN> and
1804 <B0,B1,...,BM>. If a reference needs author i we only have to call
1805 need_author(j) for some j >= i such that the reference also needs
1806 author j. */
1808 /* This function handles 2 tasks:
1809 determine which authors are needed (cannot be elided with et al.);
1810 determine which authors can have only last names in the labels.
1812 References >= start and < end have the same first i author names.
1813 Also they're sorted by A+. */
1815 static void consider_authors(reference **start, reference **end, int i)
1817 if (start >= end)
1818 return;
1819 reference **p = start;
1820 if (i >= (*p)->get_nauthors()) {
1821 for (++p; p < end && i >= (*p)->get_nauthors(); p++)
1823 if (p < end && i > 0) {
1824 // If we have an author list <A B C> and an author list <A B C D>,
1825 // then both lists need C.
1826 for (reference **q = start; q < end; q++)
1827 (*q)->need_author(i - 1);
1829 start = p;
1831 while (p < end) {
1832 reference **last_name_start = p;
1833 reference **name_start = p;
1834 for (++p;
1835 p < end && i < (*p)->get_nauthors()
1836 && same_author_last_name(**last_name_start, **p, i);
1837 p++) {
1838 if (!same_author_name(**name_start, **p, i)) {
1839 consider_authors(name_start, p, i + 1);
1840 name_start = p;
1843 consider_authors(name_start, p, i + 1);
1844 if (last_name_start == name_start) {
1845 for (reference **q = last_name_start; q < p; q++)
1846 (*q)->set_last_name_unambiguous(i);
1848 // If we have an author list <A B C D> and <A B C E>, then the lists
1849 // need author D and E respectively.
1850 if (name_start > start || p < end) {
1851 for (reference **q = last_name_start; q < p; q++)
1852 (*q)->need_author(i);
1857 int same_author_last_name(const reference &r1, const reference &r2, int n)
1859 const char *ae1;
1860 const char *as1 = r1.get_sort_field(0, n, 0, &ae1);
1861 assert(as1 != 0);
1862 const char *ae2;
1863 const char *as2 = r2.get_sort_field(0, n, 0, &ae2);
1864 assert(as2 != 0);
1865 return ae1 - as1 == ae2 - as2 && memcmp(as1, as2, ae1 - as1) == 0;
1868 int same_author_name(const reference &r1, const reference &r2, int n)
1870 const char *ae1;
1871 const char *as1 = r1.get_sort_field(0, n, -1, &ae1);
1872 assert(as1 != 0);
1873 const char *ae2;
1874 const char *as2 = r2.get_sort_field(0, n, -1, &ae2);
1875 assert(as2 != 0);
1876 return ae1 - as1 == ae2 - as2 && memcmp(as1, as2, ae1 - as1) == 0;
1880 void int_set::set(int i)
1882 assert(i >= 0);
1883 int bytei = i >> 3;
1884 if (bytei >= v.length()) {
1885 int old_length = v.length();
1886 v.set_length(bytei + 1);
1887 for (int j = old_length; j <= bytei; j++)
1888 v[j] = 0;
1890 v[bytei] |= 1 << (i & 7);
1893 int int_set::get(int i) const
1895 assert(i >= 0);
1896 int bytei = i >> 3;
1897 return bytei >= v.length() ? 0 : (v[bytei] & (1 << (i & 7))) != 0;
1900 void reference::set_last_name_unambiguous(int i)
1902 last_name_unambiguous.set(i);
1905 void reference::need_author(int n)
1907 if (n > last_needed_author)
1908 last_needed_author = n;
1911 const char *reference::get_authors(const char **end) const
1913 if (!computed_authors) {
1914 ((reference *)this)->computed_authors = 1;
1915 string &result = ((reference *)this)->authors;
1916 int na = get_nauthors();
1917 result.clear();
1918 for (int i = 0; i < na; i++) {
1919 if (last_name_unambiguous.get(i)) {
1920 const char *e, *start = get_author_last_name(i, &e);
1921 assert(start != 0);
1922 result.append(start, e - start);
1924 else {
1925 const char *e, *start = get_author(i, &e);
1926 assert(start != 0);
1927 result.append(start, e - start);
1929 if (i == last_needed_author
1930 && et_al.length() > 0
1931 && et_al_min_elide > 0
1932 && last_needed_author + et_al_min_elide < na
1933 && na >= et_al_min_total) {
1934 result += et_al;
1935 break;
1937 if (i < na - 1) {
1938 if (na == 2)
1939 result += join_authors_exactly_two;
1940 else if (i < na - 2)
1941 result += join_authors_default;
1942 else
1943 result += join_authors_last_two;
1947 const char *start = authors.contents();
1948 *end = start + authors.length();
1949 return start;
1952 int reference::get_nauthors() const
1954 if (nauthors < 0) {
1955 const char *dummy;
1956 for (int na = 0; get_author(na, &dummy) != 0; na++)
1958 ((reference *)this)->nauthors = na;
1960 return nauthors;