* src/include/nonposix.h: Remove first line -- this file is used in C also.
[s-roff.git] / src / preproc / refer / label.cc
blob04dcbf5d04f4a220d0e43a7a760e115b2d8a55d0
1 #ifndef lint
2 /*static char yysccsid[] = "from: @(#)yaccpar 1.9 (Berkeley) 02/21/93";*/
3 static char yyrcsid[] = "$Id$";
4 #endif
5 #define YYBYACC 1
6 #define YYMAJOR 1
7 #define YYMINOR 9
8 #define yyclearin (yychar=(-1))
9 #define yyerrok (yyerrflag=0)
10 #define YYRECOVERING (yyerrflag!=0)
11 #define YYPREFIX "yy"
12 #line 22 "label.y"
14 #include "refer.h"
15 #include "refid.h"
16 #include "ref.h"
17 #include "token.h"
19 int yylex();
20 void yyerror(const char *);
21 int yyparse();
23 static const char *format_serial(char c, int n);
25 struct label_info {
26 int start;
27 int length;
28 int count;
29 int total;
30 label_info(const string &);
33 label_info *lookup_label(const string &label);
35 struct expression {
36 enum {
37 /* Does the tentative label depend on the reference?*/
38 CONTAINS_VARIABLE = 01,
39 CONTAINS_STAR = 02,
40 CONTAINS_FORMAT = 04,
41 CONTAINS_AT = 010
43 virtual ~expression() { }
44 virtual void evaluate(int, const reference &, string &,
45 substring_position &) = 0;
46 virtual unsigned analyze() { return 0; }
49 class at_expr : public expression {
50 public:
51 at_expr() { }
52 void evaluate(int, const reference &, string &, substring_position &);
53 unsigned analyze() { return CONTAINS_VARIABLE|CONTAINS_AT; }
56 class format_expr : public expression {
57 char type;
58 int width;
59 int first_number;
60 public:
61 format_expr(char c, int w = 0, int f = 1)
62 : type(c), width(w), first_number(f) { }
63 void evaluate(int, const reference &, string &, substring_position &);
64 unsigned analyze() { return CONTAINS_FORMAT; }
67 class field_expr : public expression {
68 int number;
69 char name;
70 public:
71 field_expr(char nm, int num) : number(num), name(nm) { }
72 void evaluate(int, const reference &, string &, substring_position &);
73 unsigned analyze() { return CONTAINS_VARIABLE; }
76 class literal_expr : public expression {
77 string s;
78 public:
79 literal_expr(const char *ptr, int len) : s(ptr, len) { }
80 void evaluate(int, const reference &, string &, substring_position &);
83 class unary_expr : public expression {
84 protected:
85 expression *expr;
86 public:
87 unary_expr(expression *e) : expr(e) { }
88 ~unary_expr() { delete expr; }
89 void evaluate(int, const reference &, string &, substring_position &) = 0;
90 unsigned analyze() { return expr ? expr->analyze() : 0; }
93 /* This caches the analysis of an expression.*/
95 class analyzed_expr : public unary_expr {
96 unsigned flags;
97 public:
98 analyzed_expr(expression *);
99 void evaluate(int, const reference &, string &, substring_position &);
100 unsigned analyze() { return flags; }
103 class star_expr : public unary_expr {
104 public:
105 star_expr(expression *e) : unary_expr(e) { }
106 void evaluate(int, const reference &, string &, substring_position &);
107 unsigned analyze() {
108 return ((expr ? (expr->analyze() & ~CONTAINS_VARIABLE) : 0)
109 | CONTAINS_STAR);
113 typedef void map_func(const char *, const char *, string &);
115 class map_expr : public unary_expr {
116 map_func *func;
117 public:
118 map_expr(expression *e, map_func *f) : unary_expr(e), func(f) { }
119 void evaluate(int, const reference &, string &, substring_position &);
122 typedef const char *extractor_func(const char *, const char *, const char **);
124 class extractor_expr : public unary_expr {
125 int part;
126 extractor_func *func;
127 public:
128 enum { BEFORE = +1, MATCH = 0, AFTER = -1 };
129 extractor_expr(expression *e, extractor_func *f, int pt)
130 : unary_expr(e), part(pt), func(f) { }
131 void evaluate(int, const reference &, string &, substring_position &);
134 class truncate_expr : public unary_expr {
135 int n;
136 public:
137 truncate_expr(expression *e, int i) : unary_expr(e), n(i) { }
138 void evaluate(int, const reference &, string &, substring_position &);
141 class separator_expr : public unary_expr {
142 public:
143 separator_expr(expression *e) : unary_expr(e) { }
144 void evaluate(int, const reference &, string &, substring_position &);
147 class binary_expr : public expression {
148 protected:
149 expression *expr1;
150 expression *expr2;
151 public:
152 binary_expr(expression *e1, expression *e2) : expr1(e1), expr2(e2) { }
153 ~binary_expr() { delete expr1; delete expr2; }
154 void evaluate(int, const reference &, string &, substring_position &) = 0;
155 unsigned analyze() {
156 return (expr1 ? expr1->analyze() : 0) | (expr2 ? expr2->analyze() : 0);
160 class alternative_expr : public binary_expr {
161 public:
162 alternative_expr(expression *e1, expression *e2) : binary_expr(e1, e2) { }
163 void evaluate(int, const reference &, string &, substring_position &);
166 class list_expr : public binary_expr {
167 public:
168 list_expr(expression *e1, expression *e2) : binary_expr(e1, e2) { }
169 void evaluate(int, const reference &, string &, substring_position &);
172 class substitute_expr : public binary_expr {
173 public:
174 substitute_expr(expression *e1, expression *e2) : binary_expr(e1, e2) { }
175 void evaluate(int, const reference &, string &, substring_position &);
178 class ternary_expr : public expression {
179 protected:
180 expression *expr1;
181 expression *expr2;
182 expression *expr3;
183 public:
184 ternary_expr(expression *e1, expression *e2, expression *e3)
185 : expr1(e1), expr2(e2), expr3(e3) { }
186 ~ternary_expr() { delete expr1; delete expr2; delete expr3; }
187 void evaluate(int, const reference &, string &, substring_position &) = 0;
188 unsigned analyze() {
189 return ((expr1 ? expr1->analyze() : 0)
190 | (expr2 ? expr2->analyze() : 0)
191 | (expr3 ? expr3->analyze() : 0));
195 class conditional_expr : public ternary_expr {
196 public:
197 conditional_expr(expression *e1, expression *e2, expression *e3)
198 : ternary_expr(e1, e2, e3) { }
199 void evaluate(int, const reference &, string &, substring_position &);
202 static expression *parsed_label = 0;
203 static expression *parsed_date_label = 0;
204 static expression *parsed_short_label = 0;
206 static expression *parse_result;
208 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;
217 #line 218 "y.tab.c"
218 #define TOKEN_LETTER 257
219 #define TOKEN_LITERAL 258
220 #define TOKEN_DIGIT 259
221 #define YYERRCODE 256
222 short yylhs[] = { -1,
223 0, 1, 1, 6, 6, 2, 2, 2, 3, 3,
224 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
225 4, 4, 4, 4, 9, 9, 7, 7, 8, 8,
226 10, 10, 10,
228 short yylen[] = { 2,
229 1, 1, 5, 0, 1, 1, 3, 3, 1, 2,
230 1, 3, 1, 1, 1, 2, 2, 2, 5, 3,
231 3, 2, 3, 3, 0, 1, 1, 2, 1, 2,
232 0, 1, 1,
234 short yydefred[] = { 0,
235 0, 14, 13, 0, 0, 0, 0, 5, 0, 0,
236 0, 0, 1, 27, 0, 17, 29, 0, 0, 0,
237 0, 0, 0, 0, 0, 0, 0, 22, 0, 28,
238 30, 23, 24, 0, 0, 0, 32, 33, 0, 0,
239 0, 0, 0, 0, 3, 0, 19,
241 short yydgoto[] = { 7,
242 8, 9, 10, 11, 12, 13, 15, 18, 47, 39,
244 short yysindex[] = { -32,
245 -257, 0, 0, -240, -32, -32, 0, 0, -18, -32,
246 -36, -114, 0, 0, -246, 0, 0, -241, -14, -39,
247 -32, -32, -32, -114, -21, -257, -257, 0, -32, 0,
248 0, 0, 0, -25, -32, -32, 0, 0, -223, -246,
249 -246, -36, -32, -257, 0, -246, 0,
251 short yyrindex[] = { 35,
252 1, 0, 0, 0, -5, -4, 0, 0, 14, 208,
253 159, 224, 0, 0, 11, 0, 0, 40, 0, 0,
254 2, 0, 0, 253, -220, 0, 0, 0, 0, 0,
255 0, 0, 0, 0, 263, 281, 0, 0, 0, 50,
256 105, 214, 0, 115, 0, 149, 0,
258 short yygindex[] = { 0,
259 19, 0, 7, 37, -10, 10, -23, 0, 0, 0,
261 #define YYTABLESIZE 511
262 short yytable[] = { 24,
263 15, 14, 40, 41, 4, 28, 26, 5, 27, 25,
264 16, 29, 30, 2, 19, 20, 16, 31, 17, 23,
265 46, 37, 33, 38, 24, 24, 32, 6, 35, 36,
266 34, 3, 43, 44, 4, 4, 31, 15, 15, 18,
267 15, 15, 15, 15, 21, 15, 15, 16, 16, 20,
268 16, 16, 16, 16, 2, 16, 16, 4, 15, 4,
269 15, 45, 15, 15, 15, 42, 0, 0, 16, 0,
270 16, 2, 16, 16, 16, 2, 18, 18, 0, 18,
271 18, 18, 18, 0, 18, 18, 20, 20, 0, 20,
272 20, 20, 20, 0, 20, 20, 0, 18, 0, 18,
273 0, 18, 18, 18, 21, 22, 0, 20, 0, 20,
274 0, 20, 20, 20, 25, 0, 0, 0, 0, 0,
275 0, 0, 0, 0, 15, 0, 15, 0, 0, 0,
276 0, 0, 0, 0, 16, 0, 16, 0, 0, 0,
277 0, 21, 21, 0, 21, 21, 21, 21, 26, 21,
278 21, 25, 25, 0, 25, 25, 25, 25, 11, 25,
279 25, 0, 21, 18, 21, 18, 21, 21, 21, 0,
280 0, 0, 25, 20, 25, 20, 25, 25, 25, 0,
281 0, 0, 0, 0, 0, 26, 26, 0, 26, 26,
282 26, 26, 0, 26, 26, 11, 11, 0, 11, 11,
283 0, 0, 0, 0, 0, 0, 26, 6, 26, 0,
284 26, 26, 26, 12, 0, 0, 11, 0, 11, 0,
285 11, 11, 11, 9, 1, 2, 0, 0, 21, 0,
286 21, 0, 0, 0, 0, 0, 0, 0, 25, 0,
287 25, 0, 0, 0, 0, 6, 0, 0, 6, 0,
288 12, 12, 10, 12, 12, 0, 0, 15, 15, 0,
289 9, 9, 7, 9, 9, 6, 0, 16, 16, 6,
290 6, 12, 26, 12, 26, 12, 12, 12, 0, 0,
291 8, 9, 11, 9, 11, 9, 9, 9, 0, 10,
292 10, 0, 10, 10, 0, 0, 18, 18, 0, 0,
293 7, 0, 0, 7, 0, 0, 20, 20, 0, 0,
294 10, 0, 10, 0, 10, 10, 10, 0, 8, 0,
295 7, 8, 0, 0, 7, 7, 0, 0, 0, 0,
296 0, 6, 0, 0, 0, 0, 0, 12, 8, 12,
297 0, 0, 8, 8, 0, 0, 0, 9, 0, 0,
298 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
299 0, 21, 21, 0, 0, 0, 0, 0, 0, 0,
300 0, 25, 25, 0, 0, 0, 10, 0, 0, 0,
301 0, 0, 0, 0, 0, 0, 7, 0, 0, 0,
302 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
303 0, 0, 0, 0, 8, 26, 26, 0, 0, 0,
304 0, 0, 0, 0, 0, 11, 11, 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
310 12, 12, 0, 0, 0, 0, 0, 0, 0, 0,
311 9, 9, 0, 0, 0, 0, 0, 0, 0, 0,
312 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
313 0, 0, 0, 0, 0, 0, 0, 0, 0, 10,
316 short yycheck[] = { 10,
317 0, 259, 26, 27, 37, 42, 43, 40, 45, 46,
318 0, 126, 259, 0, 5, 6, 257, 259, 259, 38,
319 44, 43, 62, 45, 35, 36, 41, 60, 22, 23,
320 21, 64, 58, 257, 0, 41, 257, 37, 38, 0,
321 40, 41, 42, 43, 63, 45, 46, 37, 38, 0,
322 40, 41, 42, 43, 41, 45, 46, 62, 58, 58,
323 60, 43, 62, 63, 64, 29, -1, -1, 58, -1,
324 60, 58, 62, 63, 64, 62, 37, 38, -1, 40,
325 41, 42, 43, -1, 45, 46, 37, 38, -1, 40,
326 41, 42, 43, -1, 45, 46, -1, 58, -1, 60,
327 -1, 62, 63, 64, 0, 124, -1, 58, -1, 60,
328 -1, 62, 63, 64, 0, -1, -1, -1, -1, -1,
329 -1, -1, -1, -1, 124, -1, 126, -1, -1, -1,
330 -1, -1, -1, -1, 124, -1, 126, -1, -1, -1,
331 -1, 37, 38, -1, 40, 41, 42, 43, 0, 45,
332 46, 37, 38, -1, 40, 41, 42, 43, 0, 45,
333 46, -1, 58, 124, 60, 126, 62, 63, 64, -1,
334 -1, -1, 58, 124, 60, 126, 62, 63, 64, -1,
335 -1, -1, -1, -1, -1, 37, 38, -1, 40, 41,
336 42, 43, -1, 45, 46, 37, 38, -1, 40, 41,
337 -1, -1, -1, -1, -1, -1, 58, 0, 60, -1,
338 62, 63, 64, 0, -1, -1, 58, -1, 60, -1,
339 62, 63, 64, 0, 257, 258, -1, -1, 124, -1,
340 126, -1, -1, -1, -1, -1, -1, -1, 124, -1,
341 126, -1, -1, -1, -1, 38, -1, -1, 41, -1,
342 37, 38, 0, 40, 41, -1, -1, 257, 258, -1,
343 37, 38, 0, 40, 41, 58, -1, 257, 258, 62,
344 63, 58, 124, 60, 126, 62, 63, 64, -1, -1,
345 0, 58, 124, 60, 126, 62, 63, 64, -1, 37,
346 38, -1, 40, 41, -1, -1, 257, 258, -1, -1,
347 38, -1, -1, 41, -1, -1, 257, 258, -1, -1,
348 58, -1, 60, -1, 62, 63, 64, -1, 38, -1,
349 58, 41, -1, -1, 62, 63, -1, -1, -1, -1,
350 -1, 124, -1, -1, -1, -1, -1, 124, 58, 126,
351 -1, -1, 62, 63, -1, -1, -1, 124, -1, -1,
352 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
353 -1, 257, 258, -1, -1, -1, -1, -1, -1, -1,
354 -1, 257, 258, -1, -1, -1, 124, -1, -1, -1,
355 -1, -1, -1, -1, -1, -1, 124, -1, -1, -1,
356 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
357 -1, -1, -1, -1, 124, 257, 258, -1, -1, -1,
358 -1, -1, -1, -1, -1, 257, 258, -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 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
364 257, 258, -1, -1, -1, -1, -1, -1, -1, -1,
365 257, 258, -1, -1, -1, -1, -1, -1, -1, -1,
366 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
367 -1, -1, -1, -1, -1, -1, -1, -1, -1, 257,
368 258,
370 #define YYFINAL 7
371 #ifndef YYDEBUG
372 #define YYDEBUG 0
373 #endif
374 #define YYMAXTOKEN 259
375 #if YYDEBUG
376 char *yyname[] = {
377 "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,
378 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,
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,
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,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,
384 0,0,0,0,0,0,0,0,0,0,0,0,0,"TOKEN_LETTER","TOKEN_LITERAL","TOKEN_DIGIT",
386 char *yyrule[] = {
387 "$accept : expr",
388 "expr : optional_conditional",
389 "conditional : alternative",
390 "conditional : alternative '?' optional_conditional ':' conditional",
391 "optional_conditional :",
392 "optional_conditional : conditional",
393 "alternative : list",
394 "alternative : alternative '|' list",
395 "alternative : alternative '&' list",
396 "list : substitute",
397 "list : list substitute",
398 "substitute : string",
399 "substitute : substitute '~' string",
400 "string : '@'",
401 "string : TOKEN_LITERAL",
402 "string : TOKEN_LETTER",
403 "string : TOKEN_LETTER number",
404 "string : '%' TOKEN_LETTER",
405 "string : '%' digits",
406 "string : string '.' flag TOKEN_LETTER optional_number",
407 "string : string '+' number",
408 "string : string '-' number",
409 "string : string '*'",
410 "string : '(' optional_conditional ')'",
411 "string : '<' optional_conditional '>'",
412 "optional_number :",
413 "optional_number : number",
414 "number : TOKEN_DIGIT",
415 "number : number TOKEN_DIGIT",
416 "digits : TOKEN_DIGIT",
417 "digits : digits TOKEN_DIGIT",
418 "flag :",
419 "flag : '+'",
420 "flag : '-'",
422 #endif
423 #ifdef YYSTACKSIZE
424 #undef YYMAXDEPTH
425 #define YYMAXDEPTH YYSTACKSIZE
426 #else
427 #ifdef YYMAXDEPTH
428 #define YYSTACKSIZE YYMAXDEPTH
429 #else
430 #define YYSTACKSIZE 500
431 #define YYMAXDEPTH 500
432 #endif
433 #endif
434 int yydebug;
435 int yynerrs;
436 int yyerrflag;
437 int yychar;
438 short *yyssp;
439 YYSTYPE *yyvsp;
440 YYSTYPE yyval;
441 YYSTYPE yylval;
442 short yyss[YYSTACKSIZE];
443 YYSTYPE yyvs[YYSTACKSIZE];
444 #define yystacksize YYSTACKSIZE
445 #line 397 "label.y"
447 /* bison defines const to be empty unless __STDC__ is defined, which it
448 isn't under cfront */
450 #ifdef const
451 #undef const
452 #endif
454 const char *spec_ptr;
455 const char *spec_end;
456 const char *spec_cur;
458 int yylex()
460 while (spec_ptr < spec_end && csspace(*spec_ptr))
461 spec_ptr++;
462 spec_cur = spec_ptr;
463 if (spec_ptr >= spec_end)
464 return 0;
465 unsigned char c = *spec_ptr++;
466 if (csalpha(c)) {
467 yylval.num = c;
468 return TOKEN_LETTER;
470 if (csdigit(c)) {
471 yylval.num = c - '0';
472 return TOKEN_DIGIT;
474 if (c == '\'') {
475 yylval.str.start = literals.length();
476 for (; spec_ptr < spec_end; spec_ptr++) {
477 if (*spec_ptr == '\'') {
478 if (++spec_ptr < spec_end && *spec_ptr == '\'')
479 literals += '\'';
480 else {
481 yylval.str.len = literals.length() - yylval.str.start;
482 return TOKEN_LITERAL;
485 else
486 literals += *spec_ptr;
488 yylval.str.len = literals.length() - yylval.str.start;
489 return TOKEN_LITERAL;
491 return c;
494 int set_label_spec(const char *label_spec)
496 spec_cur = spec_ptr = label_spec;
497 spec_end = strchr(label_spec, '\0');
498 literals.clear();
499 if (yyparse())
500 return 0;
501 delete parsed_label;
502 parsed_label = parse_result;
503 return 1;
506 int set_date_label_spec(const char *label_spec)
508 spec_cur = spec_ptr = label_spec;
509 spec_end = strchr(label_spec, '\0');
510 literals.clear();
511 if (yyparse())
512 return 0;
513 delete parsed_date_label;
514 parsed_date_label = parse_result;
515 return 1;
518 int set_short_label_spec(const char *label_spec)
520 spec_cur = spec_ptr = label_spec;
521 spec_end = strchr(label_spec, '\0');
522 literals.clear();
523 if (yyparse())
524 return 0;
525 delete parsed_short_label;
526 parsed_short_label = parse_result;
527 return 1;
530 void yyerror(const char *message)
532 if (spec_cur < spec_end)
533 command_error("label specification %1 before `%2'", message, spec_cur);
534 else
535 command_error("label specification %1 at end of string",
536 message, spec_cur);
539 void at_expr::evaluate(int tentative, const reference &ref,
540 string &result, substring_position &)
542 if (tentative)
543 ref.canonicalize_authors(result);
544 else {
545 const char *end, *start = ref.get_authors(&end);
546 if (start)
547 result.append(start, end - start);
551 void format_expr::evaluate(int tentative, const reference &ref,
552 string &result, substring_position &)
554 if (tentative)
555 return;
556 const label_info *lp = ref.get_label_ptr();
557 int num = lp == 0 ? ref.get_number() : lp->count;
558 if (type != '0')
559 result += format_serial(type, num + 1);
560 else {
561 const char *ptr = i_to_a(num + first_number);
562 int pad = width - strlen(ptr);
563 while (--pad >= 0)
564 result += '0';
565 result += ptr;
569 static const char *format_serial(char c, int n)
571 assert(n > 0);
572 static char buf[128]; // more than enough.
573 switch (c) {
574 case 'i':
575 case 'I':
577 char *p = buf;
578 // troff uses z and w to represent 10000 and 5000 in Roman
579 // numerals; I can find no historical basis for this usage
580 const char *s = c == 'i' ? "zwmdclxvi" : "ZWMDCLXVI";
581 if (n >= 40000)
582 return i_to_a(n);
583 while (n >= 10000) {
584 *p++ = s[0];
585 n -= 10000;
587 for (int i = 1000; i > 0; i /= 10, s += 2) {
588 int m = n/i;
589 n -= m*i;
590 switch (m) {
591 case 3:
592 *p++ = s[2];
593 /* falls through */
594 case 2:
595 *p++ = s[2];
596 /* falls through */
597 case 1:
598 *p++ = s[2];
599 break;
600 case 4:
601 *p++ = s[2];
602 *p++ = s[1];
603 break;
604 case 8:
605 *p++ = s[1];
606 *p++ = s[2];
607 *p++ = s[2];
608 *p++ = s[2];
609 break;
610 case 7:
611 *p++ = s[1];
612 *p++ = s[2];
613 *p++ = s[2];
614 break;
615 case 6:
616 *p++ = s[1];
617 *p++ = s[2];
618 break;
619 case 5:
620 *p++ = s[1];
621 break;
622 case 9:
623 *p++ = s[2];
624 *p++ = s[0];
627 *p = 0;
628 break;
630 case 'a':
631 case 'A':
633 char *p = buf;
634 // this is derived from troff/reg.c
635 while (n > 0) {
636 int d = n % 26;
637 if (d == 0)
638 d = 26;
639 n -= d;
640 n /= 26;
641 *p++ = c + d - 1; // ASCII dependent
643 *p-- = 0;
644 // Reverse it.
645 char *q = buf;
646 while (q < p) {
647 char temp = *q;
648 *q = *p;
649 *p = temp;
650 --p;
651 ++q;
653 break;
655 default:
656 assert(0);
658 return buf;
661 void field_expr::evaluate(int, const reference &ref,
662 string &result, substring_position &)
664 const char *end;
665 const char *start = ref.get_field(name, &end);
666 if (start) {
667 start = nth_field(number, start, &end);
668 if (start)
669 result.append(start, end - start);
673 void literal_expr::evaluate(int, const reference &,
674 string &result, substring_position &)
676 result += s;
679 analyzed_expr::analyzed_expr(expression *e)
680 : unary_expr(e), flags(e ? e->analyze() : 0)
684 void analyzed_expr::evaluate(int tentative, const reference &ref,
685 string &result, substring_position &pos)
687 if (expr)
688 expr->evaluate(tentative, ref, result, pos);
691 void star_expr::evaluate(int tentative, const reference &ref,
692 string &result, substring_position &pos)
694 const label_info *lp = ref.get_label_ptr();
695 if (!tentative
696 && (lp == 0 || lp->total > 1)
697 && expr)
698 expr->evaluate(tentative, ref, result, pos);
701 void separator_expr::evaluate(int tentative, const reference &ref,
702 string &result, substring_position &pos)
704 int start_length = result.length();
705 int is_first = pos.start < 0;
706 if (expr)
707 expr->evaluate(tentative, ref, result, pos);
708 if (is_first) {
709 pos.start = start_length;
710 pos.length = result.length() - start_length;
714 void map_expr::evaluate(int tentative, const reference &ref,
715 string &result, substring_position &)
717 if (expr) {
718 string temp;
719 substring_position temp_pos;
720 expr->evaluate(tentative, ref, temp, temp_pos);
721 (*func)(temp.contents(), temp.contents() + temp.length(), result);
725 void extractor_expr::evaluate(int tentative, const reference &ref,
726 string &result, substring_position &)
728 if (expr) {
729 string temp;
730 substring_position temp_pos;
731 expr->evaluate(tentative, ref, temp, temp_pos);
732 const char *end, *start = (*func)(temp.contents(),
733 temp.contents() + temp.length(),
734 &end);
735 switch (part) {
736 case BEFORE:
737 if (start)
738 result.append(temp.contents(), start - temp.contents());
739 else
740 result += temp;
741 break;
742 case MATCH:
743 if (start)
744 result.append(start, end - start);
745 break;
746 case AFTER:
747 if (start)
748 result.append(end, temp.contents() + temp.length() - end);
749 break;
750 default:
751 assert(0);
756 static void first_part(int len, const char *ptr, const char *end,
757 string &result)
759 for (;;) {
760 const char *token_start = ptr;
761 if (!get_token(&ptr, end))
762 break;
763 const token_info *ti = lookup_token(token_start, ptr);
764 int counts = ti->sortify_non_empty(token_start, ptr);
765 if (counts && --len < 0)
766 break;
767 if (counts || ti->is_accent())
768 result.append(token_start, ptr - token_start);
772 static void last_part(int len, const char *ptr, const char *end,
773 string &result)
775 const char *start = ptr;
776 int count = 0;
777 for (;;) {
778 const char *token_start = ptr;
779 if (!get_token(&ptr, end))
780 break;
781 const token_info *ti = lookup_token(token_start, ptr);
782 if (ti->sortify_non_empty(token_start, ptr))
783 count++;
785 ptr = start;
786 int skip = count - len;
787 if (skip > 0) {
788 for (;;) {
789 const char *token_start = ptr;
790 if (!get_token(&ptr, end))
791 assert(0);
792 const token_info *ti = lookup_token(token_start, ptr);
793 if (ti->sortify_non_empty(token_start, ptr) && --skip < 0) {
794 ptr = token_start;
795 break;
799 first_part(len, ptr, end, result);
802 void truncate_expr::evaluate(int tentative, const reference &ref,
803 string &result, substring_position &)
805 if (expr) {
806 string temp;
807 substring_position temp_pos;
808 expr->evaluate(tentative, ref, temp, temp_pos);
809 const char *start = temp.contents();
810 const char *end = start + temp.length();
811 if (n > 0)
812 first_part(n, start, end, result);
813 else if (n < 0)
814 last_part(-n, start, end, result);
818 void alternative_expr::evaluate(int tentative, const reference &ref,
819 string &result, substring_position &pos)
821 int start_length = result.length();
822 if (expr1)
823 expr1->evaluate(tentative, ref, result, pos);
824 if (result.length() == start_length && expr2)
825 expr2->evaluate(tentative, ref, result, pos);
828 void list_expr::evaluate(int tentative, const reference &ref,
829 string &result, substring_position &pos)
831 if (expr1)
832 expr1->evaluate(tentative, ref, result, pos);
833 if (expr2)
834 expr2->evaluate(tentative, ref, result, pos);
837 void substitute_expr::evaluate(int tentative, const reference &ref,
838 string &result, substring_position &pos)
840 int start_length = result.length();
841 if (expr1)
842 expr1->evaluate(tentative, ref, result, pos);
843 if (result.length() > start_length && result[result.length() - 1] == '-') {
844 // ought to see if pos covers the -
845 result.set_length(result.length() - 1);
846 if (expr2)
847 expr2->evaluate(tentative, ref, result, pos);
851 void conditional_expr::evaluate(int tentative, const reference &ref,
852 string &result, substring_position &pos)
854 string temp;
855 substring_position temp_pos;
856 if (expr1)
857 expr1->evaluate(tentative, ref, temp, temp_pos);
858 if (temp.length() > 0) {
859 if (expr2)
860 expr2->evaluate(tentative, ref, result, pos);
862 else {
863 if (expr3)
864 expr3->evaluate(tentative, ref, result, pos);
868 void reference::pre_compute_label()
870 if (parsed_label != 0
871 && (parsed_label->analyze() & expression::CONTAINS_VARIABLE)) {
872 label.clear();
873 substring_position temp_pos;
874 parsed_label->evaluate(1, *this, label, temp_pos);
875 label_ptr = lookup_label(label);
879 void reference::compute_label()
881 label.clear();
882 if (parsed_label)
883 parsed_label->evaluate(0, *this, label, separator_pos);
884 if (short_label_flag && parsed_short_label)
885 parsed_short_label->evaluate(0, *this, short_label, short_separator_pos);
886 if (date_as_label) {
887 string new_date;
888 if (parsed_date_label) {
889 substring_position temp_pos;
890 parsed_date_label->evaluate(0, *this, new_date, temp_pos);
892 set_date(new_date);
894 if (label_ptr)
895 label_ptr->count += 1;
898 void reference::immediate_compute_label()
900 if (label_ptr)
901 label_ptr->total = 2; // force use of disambiguator
902 compute_label();
905 int reference::merge_labels(reference **v, int n, label_type type,
906 string &result)
908 if (abbreviate_label_ranges)
909 return merge_labels_by_number(v, n, type, result);
910 else
911 return merge_labels_by_parts(v, n, type, result);
914 int reference::merge_labels_by_number(reference **v, int n, label_type type,
915 string &result)
917 if (n <= 1)
918 return 0;
919 int num = get_number();
920 // Only merge three or more labels.
921 if (v[0]->get_number() != num + 1
922 || v[1]->get_number() != num + 2)
923 return 0;
924 int i;
925 for (i = 2; i < n; i++)
926 if (v[i]->get_number() != num + i + 1)
927 break;
928 result = get_label(type);
929 result += label_range_indicator;
930 result += v[i - 1]->get_label(type);
931 return i;
934 const substring_position &reference::get_separator_pos(label_type type) const
936 if (type == SHORT_LABEL && short_label_flag)
937 return short_separator_pos;
938 else
939 return separator_pos;
942 const string &reference::get_label(label_type type) const
944 if (type == SHORT_LABEL && short_label_flag)
945 return short_label;
946 else
947 return label;
950 int reference::merge_labels_by_parts(reference **v, int n, label_type type,
951 string &result)
953 if (n <= 0)
954 return 0;
955 const string &lb = get_label(type);
956 const substring_position &sp = get_separator_pos(type);
957 if (sp.start < 0
958 || sp.start != v[0]->get_separator_pos(type).start
959 || memcmp(lb.contents(), v[0]->get_label(type).contents(),
960 sp.start) != 0)
961 return 0;
962 result = lb;
963 int i = 0;
964 do {
965 result += separate_label_second_parts;
966 const substring_position &s = v[i]->get_separator_pos(type);
967 int sep_end_pos = s.start + s.length;
968 result.append(v[i]->get_label(type).contents() + sep_end_pos,
969 v[i]->get_label(type).length() - sep_end_pos);
970 } while (++i < n
971 && sp.start == v[i]->get_separator_pos(type).start
972 && memcmp(lb.contents(), v[i]->get_label(type).contents(),
973 sp.start) == 0);
974 return i;
977 string label_pool;
979 label_info::label_info(const string &s)
980 : start(label_pool.length()), length(s.length()), count(0), total(1)
982 label_pool += s;
985 static label_info **label_table = 0;
986 static int label_table_size = 0;
987 static int label_table_used = 0;
989 label_info *lookup_label(const string &label)
991 if (label_table == 0) {
992 label_table = new label_info *[17];
993 label_table_size = 17;
994 for (int i = 0; i < 17; i++)
995 label_table[i] = 0;
997 unsigned h = hash_string(label.contents(), label.length()) % label_table_size;
998 label_info **ptr;
999 for (ptr = label_table + h;
1000 *ptr != 0;
1001 (ptr == label_table)
1002 ? (ptr = label_table + label_table_size - 1)
1003 : ptr--)
1004 if ((*ptr)->length == label.length()
1005 && memcmp(label_pool.contents() + (*ptr)->start, label.contents(),
1006 label.length()) == 0) {
1007 (*ptr)->total += 1;
1008 return *ptr;
1010 label_info *result = *ptr = new label_info(label);
1011 if (++label_table_used * 2 > label_table_size) {
1012 // Rehash the table.
1013 label_info **old_table = label_table;
1014 int old_size = label_table_size;
1015 label_table_size = next_size(label_table_size);
1016 label_table = new label_info *[label_table_size];
1017 int i;
1018 for (i = 0; i < label_table_size; i++)
1019 label_table[i] = 0;
1020 for (i = 0; i < old_size; i++)
1021 if (old_table[i]) {
1022 unsigned h = hash_string(label_pool.contents() + old_table[i]->start,
1023 old_table[i]->length);
1024 label_info **p;
1025 for (p = label_table + (h % label_table_size);
1026 *p != 0;
1027 (p == label_table)
1028 ? (p = label_table + label_table_size - 1)
1029 : --p)
1031 *p = old_table[i];
1033 a_delete old_table;
1035 return result;
1038 void clear_labels()
1040 for (int i = 0; i < label_table_size; i++) {
1041 delete label_table[i];
1042 label_table[i] = 0;
1044 label_table_used = 0;
1045 label_pool.clear();
1048 static void consider_authors(reference **start, reference **end, int i);
1050 void compute_labels(reference **v, int n)
1052 if (parsed_label
1053 && (parsed_label->analyze() & expression::CONTAINS_AT)
1054 && sort_fields.length() >= 2
1055 && sort_fields[0] == 'A'
1056 && sort_fields[1] == '+')
1057 consider_authors(v, v + n, 0);
1058 for (int i = 0; i < n; i++)
1059 v[i]->compute_label();
1063 /* A reference with a list of authors <A0,A1,...,AN> _needs_ author i
1064 where 0 <= i <= N if there exists a reference with a list of authors
1065 <B0,B1,...,BM> such that <A0,A1,...,AN> != <B0,B1,...,BM> and M >= i
1066 and Aj = Bj for 0 <= j < i. In this case if we can't say ``A0,
1067 A1,...,A(i-1) et al'' because this would match both <A0,A1,...,AN> and
1068 <B0,B1,...,BM>. If a reference needs author i we only have to call
1069 need_author(j) for some j >= i such that the reference also needs
1070 author j. */
1072 /* This function handles 2 tasks:
1073 determine which authors are needed (cannot be elided with et al.);
1074 determine which authors can have only last names in the labels.
1076 References >= start and < end have the same first i author names.
1077 Also they're sorted by A+. */
1079 static void consider_authors(reference **start, reference **end, int i)
1081 if (start >= end)
1082 return;
1083 reference **p = start;
1084 if (i >= (*p)->get_nauthors()) {
1085 for (++p; p < end && i >= (*p)->get_nauthors(); p++)
1087 if (p < end && i > 0) {
1088 // If we have an author list <A B C> and an author list <A B C D>,
1089 // then both lists need C.
1090 for (reference **q = start; q < end; q++)
1091 (*q)->need_author(i - 1);
1093 start = p;
1095 while (p < end) {
1096 reference **last_name_start = p;
1097 reference **name_start = p;
1098 for (++p;
1099 p < end && i < (*p)->get_nauthors()
1100 && same_author_last_name(**last_name_start, **p, i);
1101 p++) {
1102 if (!same_author_name(**name_start, **p, i)) {
1103 consider_authors(name_start, p, i + 1);
1104 name_start = p;
1107 consider_authors(name_start, p, i + 1);
1108 if (last_name_start == name_start) {
1109 for (reference **q = last_name_start; q < p; q++)
1110 (*q)->set_last_name_unambiguous(i);
1112 // If we have an author list <A B C D> and <A B C E>, then the lists
1113 // need author D and E respectively.
1114 if (name_start > start || p < end) {
1115 for (reference **q = last_name_start; q < p; q++)
1116 (*q)->need_author(i);
1121 int same_author_last_name(const reference &r1, const reference &r2, int n)
1123 const char *ae1;
1124 const char *as1 = r1.get_sort_field(0, n, 0, &ae1);
1125 assert(as1 != 0);
1126 const char *ae2;
1127 const char *as2 = r2.get_sort_field(0, n, 0, &ae2);
1128 assert(as2 != 0);
1129 return ae1 - as1 == ae2 - as2 && memcmp(as1, as2, ae1 - as1) == 0;
1132 int same_author_name(const reference &r1, const reference &r2, int n)
1134 const char *ae1;
1135 const char *as1 = r1.get_sort_field(0, n, -1, &ae1);
1136 assert(as1 != 0);
1137 const char *ae2;
1138 const char *as2 = r2.get_sort_field(0, n, -1, &ae2);
1139 assert(as2 != 0);
1140 return ae1 - as1 == ae2 - as2 && memcmp(as1, as2, ae1 - as1) == 0;
1144 void int_set::set(int i)
1146 assert(i >= 0);
1147 int bytei = i >> 3;
1148 if (bytei >= v.length()) {
1149 int old_length = v.length();
1150 v.set_length(bytei + 1);
1151 for (int j = old_length; j <= bytei; j++)
1152 v[j] = 0;
1154 v[bytei] |= 1 << (i & 7);
1157 int int_set::get(int i) const
1159 assert(i >= 0);
1160 int bytei = i >> 3;
1161 return bytei >= v.length() ? 0 : (v[bytei] & (1 << (i & 7))) != 0;
1164 void reference::set_last_name_unambiguous(int i)
1166 last_name_unambiguous.set(i);
1169 void reference::need_author(int n)
1171 if (n > last_needed_author)
1172 last_needed_author = n;
1175 const char *reference::get_authors(const char **end) const
1177 if (!computed_authors) {
1178 ((reference *)this)->computed_authors = 1;
1179 string &result = ((reference *)this)->authors;
1180 int na = get_nauthors();
1181 result.clear();
1182 for (int i = 0; i < na; i++) {
1183 if (last_name_unambiguous.get(i)) {
1184 const char *e, *start = get_author_last_name(i, &e);
1185 assert(start != 0);
1186 result.append(start, e - start);
1188 else {
1189 const char *e, *start = get_author(i, &e);
1190 assert(start != 0);
1191 result.append(start, e - start);
1193 if (i == last_needed_author
1194 && et_al.length() > 0
1195 && et_al_min_elide > 0
1196 && last_needed_author + et_al_min_elide < na
1197 && na >= et_al_min_total) {
1198 result += et_al;
1199 break;
1201 if (i < na - 1) {
1202 if (na == 2)
1203 result += join_authors_exactly_two;
1204 else if (i < na - 2)
1205 result += join_authors_default;
1206 else
1207 result += join_authors_last_two;
1211 const char *start = authors.contents();
1212 *end = start + authors.length();
1213 return start;
1216 int reference::get_nauthors() const
1218 if (nauthors < 0) {
1219 const char *dummy;
1220 int na;
1221 for (na = 0; get_author(na, &dummy) != 0; na++)
1223 ((reference *)this)->nauthors = na;
1225 return nauthors;
1227 #line 1228 "y.tab.c"
1228 #define YYABORT goto yyabort
1229 #define YYREJECT goto yyabort
1230 #define YYACCEPT goto yyaccept
1231 #define YYERROR goto yyerrlab
1233 #if defined(__STDC__)
1234 yyparse(void)
1235 #else
1236 yyparse()
1237 #endif
1239 register int yym, yyn, yystate;
1240 #if YYDEBUG
1241 register char *yys;
1242 extern char *getenv();
1244 if (yys = getenv("YYDEBUG"))
1246 yyn = *yys;
1247 if (yyn >= '0' && yyn <= '9')
1248 yydebug = yyn - '0';
1250 #endif
1252 yynerrs = 0;
1253 yyerrflag = 0;
1254 yychar = (-1);
1256 yyssp = yyss;
1257 yyvsp = yyvs;
1258 *yyssp = yystate = 0;
1260 yyloop:
1261 if ((yyn = yydefred[yystate]) != 0) goto yyreduce;
1262 if (yychar < 0)
1264 if ((yychar = yylex()) < 0) yychar = 0;
1265 #if YYDEBUG
1266 if (yydebug)
1268 yys = 0;
1269 if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
1270 if (!yys) yys = "illegal-symbol";
1271 printf("%sdebug: state %d, reading %d (%s)\n",
1272 YYPREFIX, yystate, yychar, yys);
1274 #endif
1276 if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
1277 yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
1279 #if YYDEBUG
1280 if (yydebug)
1281 printf("%sdebug: state %d, shifting to state %d\n",
1282 YYPREFIX, yystate, yytable[yyn]);
1283 #endif
1284 if (yyssp >= yyss + yystacksize - 1)
1286 goto yyoverflow;
1288 *++yyssp = yystate = yytable[yyn];
1289 *++yyvsp = yylval;
1290 yychar = (-1);
1291 if (yyerrflag > 0) --yyerrflag;
1292 goto yyloop;
1294 if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
1295 yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
1297 yyn = yytable[yyn];
1298 goto yyreduce;
1300 if (yyerrflag) goto yyinrecovery;
1301 yyerror("syntax error");
1302 #ifdef lint
1303 goto yyerrlab;
1304 #endif
1305 yyerrlab:
1306 ++yynerrs;
1307 yyinrecovery:
1308 if (yyerrflag < 3)
1310 yyerrflag = 3;
1311 for (;;)
1313 if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
1314 yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
1316 #if YYDEBUG
1317 if (yydebug)
1318 printf("%sdebug: state %d, error recovery shifting\
1319 to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
1320 #endif
1321 if (yyssp >= yyss + yystacksize - 1)
1323 goto yyoverflow;
1325 *++yyssp = yystate = yytable[yyn];
1326 *++yyvsp = yylval;
1327 goto yyloop;
1329 else
1331 #if YYDEBUG
1332 if (yydebug)
1333 printf("%sdebug: error recovery discarding state %d\n",
1334 YYPREFIX, *yyssp);
1335 #endif
1336 if (yyssp <= yyss) goto yyabort;
1337 --yyssp;
1338 --yyvsp;
1342 else
1344 if (yychar == 0) goto yyabort;
1345 #if YYDEBUG
1346 if (yydebug)
1348 yys = 0;
1349 if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
1350 if (!yys) yys = "illegal-symbol";
1351 printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
1352 YYPREFIX, yystate, yychar, yys);
1354 #endif
1355 yychar = (-1);
1356 goto yyloop;
1358 yyreduce:
1359 #if YYDEBUG
1360 if (yydebug)
1361 printf("%sdebug: state %d, reducing by rule %d (%s)\n",
1362 YYPREFIX, yystate, yyn, yyrule[yyn]);
1363 #endif
1364 yym = yylen[yyn];
1365 yyval = yyvsp[1-yym];
1366 switch (yyn)
1368 case 1:
1369 #line 250 "label.y"
1370 { parse_result = (yyvsp[0].expr ? new analyzed_expr(yyvsp[0].expr) : 0); }
1371 break;
1372 case 2:
1373 #line 255 "label.y"
1374 { yyval.expr = yyvsp[0].expr; }
1375 break;
1376 case 3:
1377 #line 257 "label.y"
1378 { yyval.expr = new conditional_expr(yyvsp[-4].expr, yyvsp[-2].expr, yyvsp[0].expr); }
1379 break;
1380 case 4:
1381 #line 262 "label.y"
1382 { yyval.expr = 0; }
1383 break;
1384 case 5:
1385 #line 264 "label.y"
1386 { yyval.expr = yyvsp[0].expr; }
1387 break;
1388 case 6:
1389 #line 269 "label.y"
1390 { yyval.expr = yyvsp[0].expr; }
1391 break;
1392 case 7:
1393 #line 271 "label.y"
1394 { yyval.expr = new alternative_expr(yyvsp[-2].expr, yyvsp[0].expr); }
1395 break;
1396 case 8:
1397 #line 273 "label.y"
1398 { yyval.expr = new conditional_expr(yyvsp[-2].expr, yyvsp[0].expr, 0); }
1399 break;
1400 case 9:
1401 #line 278 "label.y"
1402 { yyval.expr = yyvsp[0].expr; }
1403 break;
1404 case 10:
1405 #line 280 "label.y"
1406 { yyval.expr = new list_expr(yyvsp[-1].expr, yyvsp[0].expr); }
1407 break;
1408 case 11:
1409 #line 285 "label.y"
1410 { yyval.expr = yyvsp[0].expr; }
1411 break;
1412 case 12:
1413 #line 287 "label.y"
1414 { yyval.expr = new substitute_expr(yyvsp[-2].expr, yyvsp[0].expr); }
1415 break;
1416 case 13:
1417 #line 292 "label.y"
1418 { yyval.expr = new at_expr; }
1419 break;
1420 case 14:
1421 #line 294 "label.y"
1423 yyval.expr = new literal_expr(literals.contents() + yyvsp[0].str.start,
1424 yyvsp[0].str.len);
1426 break;
1427 case 15:
1428 #line 299 "label.y"
1429 { yyval.expr = new field_expr(yyvsp[0].num, 0); }
1430 break;
1431 case 16:
1432 #line 301 "label.y"
1433 { yyval.expr = new field_expr(yyvsp[-1].num, yyvsp[0].num - 1); }
1434 break;
1435 case 17:
1436 #line 303 "label.y"
1438 switch (yyvsp[0].num) {
1439 case 'I':
1440 case 'i':
1441 case 'A':
1442 case 'a':
1443 yyval.expr = new format_expr(yyvsp[0].num);
1444 break;
1445 default:
1446 command_error("unrecognized format `%1'", char(yyvsp[0].num));
1447 yyval.expr = new format_expr('a');
1448 break;
1451 break;
1452 case 18:
1453 #line 319 "label.y"
1455 yyval.expr = new format_expr('0', yyvsp[0].dig.ndigits, yyvsp[0].dig.val);
1457 break;
1458 case 19:
1459 #line 323 "label.y"
1461 switch (yyvsp[-1].num) {
1462 case 'l':
1463 yyval.expr = new map_expr(yyvsp[-4].expr, lowercase);
1464 break;
1465 case 'u':
1466 yyval.expr = new map_expr(yyvsp[-4].expr, uppercase);
1467 break;
1468 case 'c':
1469 yyval.expr = new map_expr(yyvsp[-4].expr, capitalize);
1470 break;
1471 case 'r':
1472 yyval.expr = new map_expr(yyvsp[-4].expr, reverse_name);
1473 break;
1474 case 'a':
1475 yyval.expr = new map_expr(yyvsp[-4].expr, abbreviate_name);
1476 break;
1477 case 'y':
1478 yyval.expr = new extractor_expr(yyvsp[-4].expr, find_year, yyvsp[-2].num);
1479 break;
1480 case 'n':
1481 yyval.expr = new extractor_expr(yyvsp[-4].expr, find_last_name, yyvsp[-2].num);
1482 break;
1483 default:
1484 yyval.expr = yyvsp[-4].expr;
1485 command_error("unknown function `%1'", char(yyvsp[-1].num));
1486 break;
1489 break;
1490 case 20:
1491 #line 354 "label.y"
1492 { yyval.expr = new truncate_expr(yyvsp[-2].expr, yyvsp[0].num); }
1493 break;
1494 case 21:
1495 #line 356 "label.y"
1496 { yyval.expr = new truncate_expr(yyvsp[-2].expr, -yyvsp[0].num); }
1497 break;
1498 case 22:
1499 #line 358 "label.y"
1500 { yyval.expr = new star_expr(yyvsp[-1].expr); }
1501 break;
1502 case 23:
1503 #line 360 "label.y"
1504 { yyval.expr = yyvsp[-1].expr; }
1505 break;
1506 case 24:
1507 #line 362 "label.y"
1508 { yyval.expr = new separator_expr(yyvsp[-1].expr); }
1509 break;
1510 case 25:
1511 #line 367 "label.y"
1512 { yyval.num = -1; }
1513 break;
1514 case 26:
1515 #line 369 "label.y"
1516 { yyval.num = yyvsp[0].num; }
1517 break;
1518 case 27:
1519 #line 374 "label.y"
1520 { yyval.num = yyvsp[0].num; }
1521 break;
1522 case 28:
1523 #line 376 "label.y"
1524 { yyval.num = yyvsp[-1].num*10 + yyvsp[0].num; }
1525 break;
1526 case 29:
1527 #line 381 "label.y"
1528 { yyval.dig.ndigits = 1; yyval.dig.val = yyvsp[0].num; }
1529 break;
1530 case 30:
1531 #line 383 "label.y"
1532 { yyval.dig.ndigits = yyvsp[-1].dig.ndigits + 1; yyval.dig.val = yyvsp[-1].dig.val*10 + yyvsp[0].num; }
1533 break;
1534 case 31:
1535 #line 389 "label.y"
1536 { yyval.num = 0; }
1537 break;
1538 case 32:
1539 #line 391 "label.y"
1540 { yyval.num = 1; }
1541 break;
1542 case 33:
1543 #line 393 "label.y"
1544 { yyval.num = -1; }
1545 break;
1546 #line 1547 "y.tab.c"
1548 yyssp -= yym;
1549 yystate = *yyssp;
1550 yyvsp -= yym;
1551 yym = yylhs[yyn];
1552 if (yystate == 0 && yym == 0)
1554 #if YYDEBUG
1555 if (yydebug)
1556 printf("%sdebug: after reduction, shifting from state 0 to\
1557 state %d\n", YYPREFIX, YYFINAL);
1558 #endif
1559 yystate = YYFINAL;
1560 *++yyssp = YYFINAL;
1561 *++yyvsp = yyval;
1562 if (yychar < 0)
1564 if ((yychar = yylex()) < 0) yychar = 0;
1565 #if YYDEBUG
1566 if (yydebug)
1568 yys = 0;
1569 if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
1570 if (!yys) yys = "illegal-symbol";
1571 printf("%sdebug: state %d, reading %d (%s)\n",
1572 YYPREFIX, YYFINAL, yychar, yys);
1574 #endif
1576 if (yychar == 0) goto yyaccept;
1577 goto yyloop;
1579 if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
1580 yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
1581 yystate = yytable[yyn];
1582 else
1583 yystate = yydgoto[yym];
1584 #if YYDEBUG
1585 if (yydebug)
1586 printf("%sdebug: after reduction, shifting from state %d \
1587 to state %d\n", YYPREFIX, *yyssp, yystate);
1588 #endif
1589 if (yyssp >= yyss + yystacksize - 1)
1591 goto yyoverflow;
1593 *++yyssp = yystate;
1594 *++yyvsp = yyval;
1595 goto yyloop;
1596 yyoverflow:
1597 yyerror("yacc stack overflow");
1598 yyabort:
1599 return (1);
1600 yyaccept:
1601 return (0);