2 static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93 (groff)";
7 #define yyclearin (yychar=(-1))
8 #define yyerrok (yyerrflag=0)
9 #define YYRECOVERING (yyerrflag!=0)
19 void yyerror(const char *);
22 static const char *format_serial(char c, int n);
29 label_info(const string &);
32 label_info *lookup_label(const string &label);
36 /* Does the tentative label depend on the reference?*/
37 CONTAINS_VARIABLE = 01,
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 {
51 void evaluate(int, const reference &, string &, substring_position &);
52 unsigned analyze() { return CONTAINS_VARIABLE|CONTAINS_AT; }
55 class format_expr : public expression {
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 {
70 field_expr(char nm, int num) : number(num), name(nm) { }
71 void evaluate(int, const reference &, string &, substring_position &);
72 unsigned analyze() { return CONTAINS_VARIABLE; }
75 class literal_expr : public expression {
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 {
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 {
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 {
104 star_expr(expression *e) : unary_expr(e) { }
105 void evaluate(int, const reference &, string &, substring_position &);
107 return ((expr ? (expr->analyze() & ~CONTAINS_VARIABLE) : 0)
112 typedef void map_func(const char *, const char *, string &);
114 class map_expr : public unary_expr {
117 map_expr(expression *e, map_func *f) : unary_expr(e), func(f) { }
118 void evaluate(int, const reference &, string &, substring_position &);
121 typedef const char *extractor_func(const char *, const char *, const char **);
123 class extractor_expr : public unary_expr {
125 extractor_func *func;
127 enum { BEFORE = +1, MATCH = 0, AFTER = -1 };
128 extractor_expr(expression *e, extractor_func *f, int pt)
129 : unary_expr(e), part(pt), func(f) { }
130 void evaluate(int, const reference &, string &, substring_position &);
133 class truncate_expr : public unary_expr {
136 truncate_expr(expression *e, int i) : unary_expr(e), n(i) { }
137 void evaluate(int, const reference &, string &, substring_position &);
140 class separator_expr : public unary_expr {
142 separator_expr(expression *e) : unary_expr(e) { }
143 void evaluate(int, const reference &, string &, substring_position &);
146 class binary_expr : public expression {
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;
155 return (expr1 ? expr1->analyze() : 0) | (expr2 ? expr2->analyze() : 0);
159 class alternative_expr : public binary_expr {
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 {
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 {
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 {
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;
188 return ((expr1 ? expr1->analyze() : 0)
189 | (expr2 ? expr2->analyze() : 0)
190 | (expr3 ? expr3->analyze() : 0));
194 class conditional_expr : public ternary_expr {
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;
213 struct { int ndigits; int val; } dig;
214 struct { int start; int len; } str;
217 #define TOKEN_LETTER 257
218 #define TOKEN_LITERAL 258
219 #define TOKEN_DIGIT 259
220 #define YYERRCODE 256
221 short yylhs[] = { -1,
222 0, 1, 1, 6, 6, 2, 2, 2, 3, 3,
223 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
224 4, 4, 4, 4, 9, 9, 7, 7, 8, 8,
228 1, 1, 5, 0, 1, 1, 3, 3, 1, 2,
229 1, 3, 1, 1, 1, 2, 2, 2, 5, 3,
230 3, 2, 3, 3, 0, 1, 1, 2, 1, 2,
233 short yydefred[] = { 0,
234 0, 14, 13, 0, 0, 0, 0, 5, 0, 0,
235 0, 0, 1, 27, 0, 17, 29, 0, 0, 0,
236 0, 0, 0, 0, 0, 0, 0, 22, 0, 28,
237 30, 23, 24, 0, 0, 0, 32, 33, 0, 0,
238 0, 0, 0, 0, 3, 0, 19,
240 short yydgoto[] = { 7,
241 8, 9, 10, 11, 12, 13, 15, 18, 47, 39,
243 short yysindex[] = { -32,
244 -257, 0, 0, -240, -32, -32, 0, 0, -18, -32,
245 -36, -114, 0, 0, -246, 0, 0, -241, -14, -39,
246 -32, -32, -32, -114, -21, -257, -257, 0, -32, 0,
247 0, 0, 0, -25, -32, -32, 0, 0, -223, -246,
248 -246, -36, -32, -257, 0, -246, 0,
250 short yyrindex[] = { 35,
251 1, 0, 0, 0, -5, -4, 0, 0, 14, 208,
252 159, 224, 0, 0, 11, 0, 0, 40, 0, 0,
253 2, 0, 0, 253, -220, 0, 0, 0, 0, 0,
254 0, 0, 0, 0, 263, 281, 0, 0, 0, 50,
255 105, 214, 0, 115, 0, 149, 0,
257 short yygindex[] = { 0,
258 19, 0, 7, 37, -10, 10, -23, 0, 0, 0,
260 #define YYTABLESIZE 511
261 short yytable[] = { 24,
262 15, 14, 40, 41, 4, 28, 26, 5, 27, 25,
263 16, 29, 30, 2, 19, 20, 16, 31, 17, 23,
264 46, 37, 33, 38, 24, 24, 32, 6, 35, 36,
265 34, 3, 43, 44, 4, 4, 31, 15, 15, 18,
266 15, 15, 15, 15, 21, 15, 15, 16, 16, 20,
267 16, 16, 16, 16, 2, 16, 16, 4, 15, 4,
268 15, 45, 15, 15, 15, 42, 0, 0, 16, 0,
269 16, 2, 16, 16, 16, 2, 18, 18, 0, 18,
270 18, 18, 18, 0, 18, 18, 20, 20, 0, 20,
271 20, 20, 20, 0, 20, 20, 0, 18, 0, 18,
272 0, 18, 18, 18, 21, 22, 0, 20, 0, 20,
273 0, 20, 20, 20, 25, 0, 0, 0, 0, 0,
274 0, 0, 0, 0, 15, 0, 15, 0, 0, 0,
275 0, 0, 0, 0, 16, 0, 16, 0, 0, 0,
276 0, 21, 21, 0, 21, 21, 21, 21, 26, 21,
277 21, 25, 25, 0, 25, 25, 25, 25, 11, 25,
278 25, 0, 21, 18, 21, 18, 21, 21, 21, 0,
279 0, 0, 25, 20, 25, 20, 25, 25, 25, 0,
280 0, 0, 0, 0, 0, 26, 26, 0, 26, 26,
281 26, 26, 0, 26, 26, 11, 11, 0, 11, 11,
282 0, 0, 0, 0, 0, 0, 26, 6, 26, 0,
283 26, 26, 26, 12, 0, 0, 11, 0, 11, 0,
284 11, 11, 11, 9, 1, 2, 0, 0, 21, 0,
285 21, 0, 0, 0, 0, 0, 0, 0, 25, 0,
286 25, 0, 0, 0, 0, 6, 0, 0, 6, 0,
287 12, 12, 10, 12, 12, 0, 0, 15, 15, 0,
288 9, 9, 7, 9, 9, 6, 0, 16, 16, 6,
289 6, 12, 26, 12, 26, 12, 12, 12, 0, 0,
290 8, 9, 11, 9, 11, 9, 9, 9, 0, 10,
291 10, 0, 10, 10, 0, 0, 18, 18, 0, 0,
292 7, 0, 0, 7, 0, 0, 20, 20, 0, 0,
293 10, 0, 10, 0, 10, 10, 10, 0, 8, 0,
294 7, 8, 0, 0, 7, 7, 0, 0, 0, 0,
295 0, 6, 0, 0, 0, 0, 0, 12, 8, 12,
296 0, 0, 8, 8, 0, 0, 0, 9, 0, 0,
297 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
298 0, 21, 21, 0, 0, 0, 0, 0, 0, 0,
299 0, 25, 25, 0, 0, 0, 10, 0, 0, 0,
300 0, 0, 0, 0, 0, 0, 7, 0, 0, 0,
301 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
302 0, 0, 0, 0, 8, 26, 26, 0, 0, 0,
303 0, 0, 0, 0, 0, 11, 11, 0, 0, 0,
304 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
305 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
306 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
307 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
308 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
309 12, 12, 0, 0, 0, 0, 0, 0, 0, 0,
310 9, 9, 0, 0, 0, 0, 0, 0, 0, 0,
311 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
312 0, 0, 0, 0, 0, 0, 0, 0, 0, 10,
315 short yycheck[] = { 10,
316 0, 259, 26, 27, 37, 42, 43, 40, 45, 46,
317 0, 126, 259, 0, 5, 6, 257, 259, 259, 38,
318 44, 43, 62, 45, 35, 36, 41, 60, 22, 23,
319 21, 64, 58, 257, 0, 41, 257, 37, 38, 0,
320 40, 41, 42, 43, 63, 45, 46, 37, 38, 0,
321 40, 41, 42, 43, 41, 45, 46, 62, 58, 58,
322 60, 43, 62, 63, 64, 29, -1, -1, 58, -1,
323 60, 58, 62, 63, 64, 62, 37, 38, -1, 40,
324 41, 42, 43, -1, 45, 46, 37, 38, -1, 40,
325 41, 42, 43, -1, 45, 46, -1, 58, -1, 60,
326 -1, 62, 63, 64, 0, 124, -1, 58, -1, 60,
327 -1, 62, 63, 64, 0, -1, -1, -1, -1, -1,
328 -1, -1, -1, -1, 124, -1, 126, -1, -1, -1,
329 -1, -1, -1, -1, 124, -1, 126, -1, -1, -1,
330 -1, 37, 38, -1, 40, 41, 42, 43, 0, 45,
331 46, 37, 38, -1, 40, 41, 42, 43, 0, 45,
332 46, -1, 58, 124, 60, 126, 62, 63, 64, -1,
333 -1, -1, 58, 124, 60, 126, 62, 63, 64, -1,
334 -1, -1, -1, -1, -1, 37, 38, -1, 40, 41,
335 42, 43, -1, 45, 46, 37, 38, -1, 40, 41,
336 -1, -1, -1, -1, -1, -1, 58, 0, 60, -1,
337 62, 63, 64, 0, -1, -1, 58, -1, 60, -1,
338 62, 63, 64, 0, 257, 258, -1, -1, 124, -1,
339 126, -1, -1, -1, -1, -1, -1, -1, 124, -1,
340 126, -1, -1, -1, -1, 38, -1, -1, 41, -1,
341 37, 38, 0, 40, 41, -1, -1, 257, 258, -1,
342 37, 38, 0, 40, 41, 58, -1, 257, 258, 62,
343 63, 58, 124, 60, 126, 62, 63, 64, -1, -1,
344 0, 58, 124, 60, 126, 62, 63, 64, -1, 37,
345 38, -1, 40, 41, -1, -1, 257, 258, -1, -1,
346 38, -1, -1, 41, -1, -1, 257, 258, -1, -1,
347 58, -1, 60, -1, 62, 63, 64, -1, 38, -1,
348 58, 41, -1, -1, 62, 63, -1, -1, -1, -1,
349 -1, 124, -1, -1, -1, -1, -1, 124, 58, 126,
350 -1, -1, 62, 63, -1, -1, -1, 124, -1, -1,
351 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
352 -1, 257, 258, -1, -1, -1, -1, -1, -1, -1,
353 -1, 257, 258, -1, -1, -1, 124, -1, -1, -1,
354 -1, -1, -1, -1, -1, -1, 124, -1, -1, -1,
355 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
356 -1, -1, -1, -1, 124, 257, 258, -1, -1, -1,
357 -1, -1, -1, -1, -1, 257, 258, -1, -1, -1,
358 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
359 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
360 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
361 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
362 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
363 257, 258, -1, -1, -1, -1, -1, -1, -1, -1,
364 257, 258, -1, -1, -1, -1, -1, -1, -1, -1,
365 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
366 -1, -1, -1, -1, -1, -1, -1, -1, -1, 257,
373 #define YYMAXTOKEN 259
376 "end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
377 0,0,0,"'%'","'&'",0,"'('","')'","'*'","'+'",0,"'-'","'.'",0,0,0,0,0,0,0,0,0,0,0,
378 "':'",0,"'<'",0,"'>'","'?'","'@'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
379 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'|'",0,
380 "'~'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
381 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
382 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
383 0,0,0,0,0,0,0,0,0,0,0,0,0,"TOKEN_LETTER","TOKEN_LITERAL","TOKEN_DIGIT",
387 "expr : optional_conditional",
388 "conditional : alternative",
389 "conditional : alternative '?' optional_conditional ':' conditional",
390 "optional_conditional :",
391 "optional_conditional : conditional",
392 "alternative : list",
393 "alternative : alternative '|' list",
394 "alternative : alternative '&' list",
396 "list : list substitute",
397 "substitute : string",
398 "substitute : substitute '~' string",
400 "string : TOKEN_LITERAL",
401 "string : TOKEN_LETTER",
402 "string : TOKEN_LETTER number",
403 "string : '%' TOKEN_LETTER",
404 "string : '%' digits",
405 "string : string '.' flag TOKEN_LETTER optional_number",
406 "string : string '+' number",
407 "string : string '-' number",
408 "string : string '*'",
409 "string : '(' optional_conditional ')'",
410 "string : '<' optional_conditional '>'",
412 "optional_number : number",
413 "number : TOKEN_DIGIT",
414 "number : number TOKEN_DIGIT",
415 "digits : TOKEN_DIGIT",
416 "digits : digits TOKEN_DIGIT",
424 #define YYMAXDEPTH YYSTACKSIZE
427 #define YYSTACKSIZE YYMAXDEPTH
429 #define YYSTACKSIZE 500
430 #define YYMAXDEPTH 500
441 short yyss[YYSTACKSIZE];
442 YYSTYPE yyvs[YYSTACKSIZE];
443 #define yystacksize YYSTACKSIZE
446 /* bison defines const to be empty unless __STDC__ is defined, which it
447 isn't under cfront */
453 const char *spec_ptr;
454 const char *spec_end;
455 const char *spec_cur;
457 static char uppercase_array[] = {
458 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
459 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
460 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
464 static char lowercase_array[] = {
465 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
466 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
467 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
473 while (spec_ptr < spec_end && csspace(*spec_ptr))
476 if (spec_ptr >= spec_end)
478 unsigned char c = *spec_ptr++;
484 yylval.num = c - '0';
488 yylval.str.start = literals.length();
489 for (; spec_ptr < spec_end; spec_ptr++) {
490 if (*spec_ptr == '\'') {
491 if (++spec_ptr < spec_end && *spec_ptr == '\'')
494 yylval.str.len = literals.length() - yylval.str.start;
495 return TOKEN_LITERAL;
499 literals += *spec_ptr;
501 yylval.str.len = literals.length() - yylval.str.start;
502 return TOKEN_LITERAL;
507 int set_label_spec(const char *label_spec)
509 spec_cur = spec_ptr = label_spec;
510 spec_end = strchr(label_spec, '\0');
515 parsed_label = parse_result;
519 int set_date_label_spec(const char *label_spec)
521 spec_cur = spec_ptr = label_spec;
522 spec_end = strchr(label_spec, '\0');
526 delete parsed_date_label;
527 parsed_date_label = parse_result;
531 int set_short_label_spec(const char *label_spec)
533 spec_cur = spec_ptr = label_spec;
534 spec_end = strchr(label_spec, '\0');
538 delete parsed_short_label;
539 parsed_short_label = parse_result;
543 void yyerror(const char *message)
545 if (spec_cur < spec_end)
546 command_error("label specification %1 before `%2'", message, spec_cur);
548 command_error("label specification %1 at end of string",
552 void at_expr::evaluate(int tentative, const reference &ref,
553 string &result, substring_position &)
556 ref.canonicalize_authors(result);
558 const char *end, *start = ref.get_authors(&end);
560 result.append(start, end - start);
564 void format_expr::evaluate(int tentative, const reference &ref,
565 string &result, substring_position &)
569 const label_info *lp = ref.get_label_ptr();
570 int num = lp == 0 ? ref.get_number() : lp->count;
572 result += format_serial(type, num + 1);
574 const char *ptr = i_to_a(num + first_number);
575 int pad = width - strlen(ptr);
582 static const char *format_serial(char c, int n)
585 static char buf[128]; // more than enough.
591 // troff uses z and w to represent 10000 and 5000 in Roman
592 // numerals; I can find no historical basis for this usage
593 const char *s = c == 'i' ? "zwmdclxvi" : "ZWMDCLXVI";
600 for (int i = 1000; i > 0; i /= 10, s += 2) {
647 // this is derived from troff/reg.c
654 *p++ = c == 'a' ? lowercase_array[d - 1] :
655 uppercase_array[d - 1];
675 void field_expr::evaluate(int, const reference &ref,
676 string &result, substring_position &)
679 const char *start = ref.get_field(name, &end);
681 start = nth_field(number, start, &end);
683 result.append(start, end - start);
687 void literal_expr::evaluate(int, const reference &,
688 string &result, substring_position &)
693 analyzed_expr::analyzed_expr(expression *e)
694 : unary_expr(e), flags(e ? e->analyze() : 0)
698 void analyzed_expr::evaluate(int tentative, const reference &ref,
699 string &result, substring_position &pos)
702 expr->evaluate(tentative, ref, result, pos);
705 void star_expr::evaluate(int tentative, const reference &ref,
706 string &result, substring_position &pos)
708 const label_info *lp = ref.get_label_ptr();
710 && (lp == 0 || lp->total > 1)
712 expr->evaluate(tentative, ref, result, pos);
715 void separator_expr::evaluate(int tentative, const reference &ref,
716 string &result, substring_position &pos)
718 int start_length = result.length();
719 int is_first = pos.start < 0;
721 expr->evaluate(tentative, ref, result, pos);
723 pos.start = start_length;
724 pos.length = result.length() - start_length;
728 void map_expr::evaluate(int tentative, const reference &ref,
729 string &result, substring_position &)
733 substring_position temp_pos;
734 expr->evaluate(tentative, ref, temp, temp_pos);
735 (*func)(temp.contents(), temp.contents() + temp.length(), result);
739 void extractor_expr::evaluate(int tentative, const reference &ref,
740 string &result, substring_position &)
744 substring_position temp_pos;
745 expr->evaluate(tentative, ref, temp, temp_pos);
746 const char *end, *start = (*func)(temp.contents(),
747 temp.contents() + temp.length(),
752 result.append(temp.contents(), start - temp.contents());
758 result.append(start, end - start);
762 result.append(end, temp.contents() + temp.length() - end);
770 static void first_part(int len, const char *ptr, const char *end,
774 const char *token_start = ptr;
775 if (!get_token(&ptr, end))
777 const token_info *ti = lookup_token(token_start, ptr);
778 int counts = ti->sortify_non_empty(token_start, ptr);
779 if (counts && --len < 0)
781 if (counts || ti->is_accent())
782 result.append(token_start, ptr - token_start);
786 static void last_part(int len, const char *ptr, const char *end,
789 const char *start = ptr;
792 const char *token_start = ptr;
793 if (!get_token(&ptr, end))
795 const token_info *ti = lookup_token(token_start, ptr);
796 if (ti->sortify_non_empty(token_start, ptr))
800 int skip = count - len;
803 const char *token_start = ptr;
804 if (!get_token(&ptr, end))
806 const token_info *ti = lookup_token(token_start, ptr);
807 if (ti->sortify_non_empty(token_start, ptr) && --skip < 0) {
813 first_part(len, ptr, end, result);
816 void truncate_expr::evaluate(int tentative, const reference &ref,
817 string &result, substring_position &)
821 substring_position temp_pos;
822 expr->evaluate(tentative, ref, temp, temp_pos);
823 const char *start = temp.contents();
824 const char *end = start + temp.length();
826 first_part(n, start, end, result);
828 last_part(-n, start, end, result);
832 void alternative_expr::evaluate(int tentative, const reference &ref,
833 string &result, substring_position &pos)
835 int start_length = result.length();
837 expr1->evaluate(tentative, ref, result, pos);
838 if (result.length() == start_length && expr2)
839 expr2->evaluate(tentative, ref, result, pos);
842 void list_expr::evaluate(int tentative, const reference &ref,
843 string &result, substring_position &pos)
846 expr1->evaluate(tentative, ref, result, pos);
848 expr2->evaluate(tentative, ref, result, pos);
851 void substitute_expr::evaluate(int tentative, const reference &ref,
852 string &result, substring_position &pos)
854 int start_length = result.length();
856 expr1->evaluate(tentative, ref, result, pos);
857 if (result.length() > start_length && result[result.length() - 1] == '-') {
858 // ought to see if pos covers the -
859 result.set_length(result.length() - 1);
861 expr2->evaluate(tentative, ref, result, pos);
865 void conditional_expr::evaluate(int tentative, const reference &ref,
866 string &result, substring_position &pos)
869 substring_position temp_pos;
871 expr1->evaluate(tentative, ref, temp, temp_pos);
872 if (temp.length() > 0) {
874 expr2->evaluate(tentative, ref, result, pos);
878 expr3->evaluate(tentative, ref, result, pos);
882 void reference::pre_compute_label()
884 if (parsed_label != 0
885 && (parsed_label->analyze() & expression::CONTAINS_VARIABLE)) {
887 substring_position temp_pos;
888 parsed_label->evaluate(1, *this, label, temp_pos);
889 label_ptr = lookup_label(label);
893 void reference::compute_label()
897 parsed_label->evaluate(0, *this, label, separator_pos);
898 if (short_label_flag && parsed_short_label)
899 parsed_short_label->evaluate(0, *this, short_label, short_separator_pos);
902 if (parsed_date_label) {
903 substring_position temp_pos;
904 parsed_date_label->evaluate(0, *this, new_date, temp_pos);
909 label_ptr->count += 1;
912 void reference::immediate_compute_label()
915 label_ptr->total = 2; // force use of disambiguator
919 int reference::merge_labels(reference **v, int n, label_type type,
922 if (abbreviate_label_ranges)
923 return merge_labels_by_number(v, n, type, result);
925 return merge_labels_by_parts(v, n, type, result);
928 int reference::merge_labels_by_number(reference **v, int n, label_type type,
933 int num = get_number();
934 // Only merge three or more labels.
935 if (v[0]->get_number() != num + 1
936 || v[1]->get_number() != num + 2)
939 for (i = 2; i < n; i++)
940 if (v[i]->get_number() != num + i + 1)
942 result = get_label(type);
943 result += label_range_indicator;
944 result += v[i - 1]->get_label(type);
948 const substring_position &reference::get_separator_pos(label_type type) const
950 if (type == SHORT_LABEL && short_label_flag)
951 return short_separator_pos;
953 return separator_pos;
956 const string &reference::get_label(label_type type) const
958 if (type == SHORT_LABEL && short_label_flag)
964 int reference::merge_labels_by_parts(reference **v, int n, label_type type,
969 const string &lb = get_label(type);
970 const substring_position &sp = get_separator_pos(type);
972 || sp.start != v[0]->get_separator_pos(type).start
973 || memcmp(lb.contents(), v[0]->get_label(type).contents(),
979 result += separate_label_second_parts;
980 const substring_position &s = v[i]->get_separator_pos(type);
981 int sep_end_pos = s.start + s.length;
982 result.append(v[i]->get_label(type).contents() + sep_end_pos,
983 v[i]->get_label(type).length() - sep_end_pos);
985 && sp.start == v[i]->get_separator_pos(type).start
986 && memcmp(lb.contents(), v[i]->get_label(type).contents(),
993 label_info::label_info(const string &s)
994 : start(label_pool.length()), length(s.length()), count(0), total(1)
999 static label_info **label_table = 0;
1000 static int label_table_size = 0;
1001 static int label_table_used = 0;
1003 label_info *lookup_label(const string &label)
1005 if (label_table == 0) {
1006 label_table = new label_info *[17];
1007 label_table_size = 17;
1008 for (int i = 0; i < 17; i++)
1011 unsigned h = hash_string(label.contents(), label.length()) % label_table_size;
1013 for (ptr = label_table + h;
1015 (ptr == label_table)
1016 ? (ptr = label_table + label_table_size - 1)
1018 if ((*ptr)->length == label.length()
1019 && memcmp(label_pool.contents() + (*ptr)->start, label.contents(),
1020 label.length()) == 0) {
1024 label_info *result = *ptr = new label_info(label);
1025 if (++label_table_used * 2 > label_table_size) {
1026 // Rehash the table.
1027 label_info **old_table = label_table;
1028 int old_size = label_table_size;
1029 label_table_size = next_size(label_table_size);
1030 label_table = new label_info *[label_table_size];
1032 for (i = 0; i < label_table_size; i++)
1034 for (i = 0; i < old_size; i++)
1036 h = hash_string(label_pool.contents() + old_table[i]->start,
1037 old_table[i]->length);
1039 for (p = label_table + (h % label_table_size);
1042 ? (p = label_table + label_table_size - 1)
1054 for (int i = 0; i < label_table_size; i++) {
1055 delete label_table[i];
1058 label_table_used = 0;
1062 static void consider_authors(reference **start, reference **end, int i);
1064 void compute_labels(reference **v, int n)
1067 && (parsed_label->analyze() & expression::CONTAINS_AT)
1068 && sort_fields.length() >= 2
1069 && sort_fields[0] == 'A'
1070 && sort_fields[1] == '+')
1071 consider_authors(v, v + n, 0);
1072 for (int i = 0; i < n; i++)
1073 v[i]->compute_label();
1077 /* A reference with a list of authors <A0,A1,...,AN> _needs_ author i
1078 where 0 <= i <= N if there exists a reference with a list of authors
1079 <B0,B1,...,BM> such that <A0,A1,...,AN> != <B0,B1,...,BM> and M >= i
1080 and Aj = Bj for 0 <= j < i. In this case if we can't say ``A0,
1081 A1,...,A(i-1) et al'' because this would match both <A0,A1,...,AN> and
1082 <B0,B1,...,BM>. If a reference needs author i we only have to call
1083 need_author(j) for some j >= i such that the reference also needs
1086 /* This function handles 2 tasks:
1087 determine which authors are needed (cannot be elided with et al.);
1088 determine which authors can have only last names in the labels.
1090 References >= start and < end have the same first i author names.
1091 Also they're sorted by A+. */
1093 static void consider_authors(reference **start, reference **end, int i)
1097 reference **p = start;
1098 if (i >= (*p)->get_nauthors()) {
1099 for (++p; p < end && i >= (*p)->get_nauthors(); p++)
1101 if (p < end && i > 0) {
1102 // If we have an author list <A B C> and an author list <A B C D>,
1103 // then both lists need C.
1104 for (reference **q = start; q < end; q++)
1105 (*q)->need_author(i - 1);
1110 reference **last_name_start = p;
1111 reference **name_start = p;
1113 p < end && i < (*p)->get_nauthors()
1114 && same_author_last_name(**last_name_start, **p, i);
1116 if (!same_author_name(**name_start, **p, i)) {
1117 consider_authors(name_start, p, i + 1);
1121 consider_authors(name_start, p, i + 1);
1122 if (last_name_start == name_start) {
1123 for (reference **q = last_name_start; q < p; q++)
1124 (*q)->set_last_name_unambiguous(i);
1126 // If we have an author list <A B C D> and <A B C E>, then the lists
1127 // need author D and E respectively.
1128 if (name_start > start || p < end) {
1129 for (reference **q = last_name_start; q < p; q++)
1130 (*q)->need_author(i);
1135 int same_author_last_name(const reference &r1, const reference &r2, int n)
1138 const char *as1 = r1.get_sort_field(0, n, 0, &ae1);
1140 const char *as2 = r2.get_sort_field(0, n, 0, &ae2);
1141 if (!as1 && !as2) return 1; // they are the same
1142 if (!as1 || !as2) return 0;
1143 return ae1 - as1 == ae2 - as2 && memcmp(as1, as2, ae1 - as1) == 0;
1146 int same_author_name(const reference &r1, const reference &r2, int n)
1149 const char *as1 = r1.get_sort_field(0, n, -1, &ae1);
1151 const char *as2 = r2.get_sort_field(0, n, -1, &ae2);
1152 if (!as1 && !as2) return 1; // they are the same
1153 if (!as1 || !as2) return 0;
1154 return ae1 - as1 == ae2 - as2 && memcmp(as1, as2, ae1 - as1) == 0;
1158 void int_set::set(int i)
1162 if (bytei >= v.length()) {
1163 int old_length = v.length();
1164 v.set_length(bytei + 1);
1165 for (int j = old_length; j <= bytei; j++)
1168 v[bytei] |= 1 << (i & 7);
1171 int int_set::get(int i) const
1175 return bytei >= v.length() ? 0 : (v[bytei] & (1 << (i & 7))) != 0;
1178 void reference::set_last_name_unambiguous(int i)
1180 last_name_unambiguous.set(i);
1183 void reference::need_author(int n)
1185 if (n > last_needed_author)
1186 last_needed_author = n;
1189 const char *reference::get_authors(const char **end) const
1191 if (!computed_authors) {
1192 ((reference *)this)->computed_authors = 1;
1193 string &result = ((reference *)this)->authors;
1194 int na = get_nauthors();
1196 for (int i = 0; i < na; i++) {
1197 if (last_name_unambiguous.get(i)) {
1198 const char *e, *start = get_author_last_name(i, &e);
1200 result.append(start, e - start);
1203 const char *e, *start = get_author(i, &e);
1205 result.append(start, e - start);
1207 if (i == last_needed_author
1208 && et_al.length() > 0
1209 && et_al_min_elide > 0
1210 && last_needed_author + et_al_min_elide < na
1211 && na >= et_al_min_total) {
1217 result += join_authors_exactly_two;
1218 else if (i < na - 2)
1219 result += join_authors_default;
1221 result += join_authors_last_two;
1225 const char *start = authors.contents();
1226 *end = start + authors.length();
1230 int reference::get_nauthors() const
1235 for (na = 0; get_author(na, &dummy) != 0; na++)
1237 ((reference *)this)->nauthors = na;
1241 #line 1242 "y.tab.c"
1242 #define YYABORT goto yyabort
1243 #define YYREJECT goto yyabort
1244 #define YYACCEPT goto yyaccept
1245 #define YYERROR goto yyerrlab
1247 #if defined(__STDC__)
1253 register int yym, yyn, yystate;
1256 extern char *getenv();
1258 if (yys = getenv("YYDEBUG"))
1261 if (yyn >= '0' && yyn <= '9')
1262 yydebug = yyn - '0';
1272 *yyssp = yystate = 0;
1275 if ((yyn = yydefred[yystate]) != 0) goto yyreduce;
1278 if ((yychar = yylex()) < 0) yychar = 0;
1283 if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
1284 if (!yys) yys = "illegal-symbol";
1285 printf("%sdebug: state %d, reading %d (%s)\n",
1286 YYPREFIX, yystate, yychar, yys);
1290 if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
1291 yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
1295 printf("%sdebug: state %d, shifting to state %d\n",
1296 YYPREFIX, yystate, yytable[yyn]);
1298 if (yyssp >= yyss + yystacksize - 1)
1302 *++yyssp = yystate = yytable[yyn];
1305 if (yyerrflag > 0) --yyerrflag;
1308 if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
1309 yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
1314 if (yyerrflag) goto yyinrecovery;
1319 yyerror("syntax error");
1331 if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
1332 yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
1336 printf("%sdebug: state %d, error recovery shifting\
1337 to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
1339 if (yyssp >= yyss + yystacksize - 1)
1343 *++yyssp = yystate = yytable[yyn];
1351 printf("%sdebug: error recovery discarding state %d\n",
1354 if (yyssp <= yyss) goto yyabort;
1362 if (yychar == 0) goto yyabort;
1367 if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
1368 if (!yys) yys = "illegal-symbol";
1369 printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
1370 YYPREFIX, yystate, yychar, yys);
1379 printf("%sdebug: state %d, reducing by rule %d (%s)\n",
1380 YYPREFIX, yystate, yyn, yyrule[yyn]);
1383 yyval = yyvsp[1-yym];
1388 { parse_result = (yyvsp[0].expr ? new analyzed_expr(yyvsp[0].expr) : 0); }
1392 { yyval.expr = yyvsp[0].expr; }
1396 { yyval.expr = new conditional_expr(yyvsp[-4].expr, yyvsp[-2].expr, yyvsp[0].expr); }
1404 { yyval.expr = yyvsp[0].expr; }
1408 { yyval.expr = yyvsp[0].expr; }
1412 { yyval.expr = new alternative_expr(yyvsp[-2].expr, yyvsp[0].expr); }
1416 { yyval.expr = new conditional_expr(yyvsp[-2].expr, yyvsp[0].expr, 0); }
1420 { yyval.expr = yyvsp[0].expr; }
1424 { yyval.expr = new list_expr(yyvsp[-1].expr, yyvsp[0].expr); }
1428 { yyval.expr = yyvsp[0].expr; }
1432 { yyval.expr = new substitute_expr(yyvsp[-2].expr, yyvsp[0].expr); }
1436 { yyval.expr = new at_expr; }
1441 yyval.expr = new literal_expr(literals.contents() + yyvsp[0].str.start,
1447 { yyval.expr = new field_expr(yyvsp[0].num, 0); }
1451 { yyval.expr = new field_expr(yyvsp[-1].num, yyvsp[0].num - 1); }
1456 switch (yyvsp[0].num) {
1461 yyval.expr = new format_expr(yyvsp[0].num);
1464 command_error("unrecognized format `%1'", char(yyvsp[0].num));
1465 yyval.expr = new format_expr('a');
1473 yyval.expr = new format_expr('0', yyvsp[0].dig.ndigits, yyvsp[0].dig.val);
1479 switch (yyvsp[-1].num) {
1481 yyval.expr = new map_expr(yyvsp[-4].expr, lowercase);
1484 yyval.expr = new map_expr(yyvsp[-4].expr, uppercase);
1487 yyval.expr = new map_expr(yyvsp[-4].expr, capitalize);
1490 yyval.expr = new map_expr(yyvsp[-4].expr, reverse_name);
1493 yyval.expr = new map_expr(yyvsp[-4].expr, abbreviate_name);
1496 yyval.expr = new extractor_expr(yyvsp[-4].expr, find_year, yyvsp[-2].num);
1499 yyval.expr = new extractor_expr(yyvsp[-4].expr, find_last_name, yyvsp[-2].num);
1502 yyval.expr = yyvsp[-4].expr;
1503 command_error("unknown function `%1'", char(yyvsp[-1].num));
1510 { yyval.expr = new truncate_expr(yyvsp[-2].expr, yyvsp[0].num); }
1514 { yyval.expr = new truncate_expr(yyvsp[-2].expr, -yyvsp[0].num); }
1518 { yyval.expr = new star_expr(yyvsp[-1].expr); }
1522 { yyval.expr = yyvsp[-1].expr; }
1526 { yyval.expr = new separator_expr(yyvsp[-1].expr); }
1534 { yyval.num = yyvsp[0].num; }
1538 { yyval.num = yyvsp[0].num; }
1542 { yyval.num = yyvsp[-1].num*10 + yyvsp[0].num; }
1546 { yyval.dig.ndigits = 1; yyval.dig.val = yyvsp[0].num; }
1550 { yyval.dig.ndigits = yyvsp[-1].dig.ndigits + 1; yyval.dig.val = yyvsp[-1].dig.val*10 + yyvsp[0].num; }
1564 #line 1565 "y.tab.c"
1570 if (yystate == 0 && yym == 0)
1574 printf("%sdebug: after reduction, shifting from state 0 to\
1575 state %d\n", YYPREFIX, YYFINAL);
1582 if ((yychar = yylex()) < 0) yychar = 0;
1587 if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
1588 if (!yys) yys = "illegal-symbol";
1589 printf("%sdebug: state %d, reading %d (%s)\n",
1590 YYPREFIX, YYFINAL, yychar, yys);
1594 if (yychar == 0) goto yyaccept;
1597 if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
1598 yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
1599 yystate = yytable[yyn];
1601 yystate = yydgoto[yym];
1604 printf("%sdebug: after reduction, shifting from state %d \
1605 to state %d\n", YYPREFIX, *yyssp, yystate);
1607 if (yyssp >= yyss + yystacksize - 1)
1615 yyerror("yacc stack overflow");