source: trunk/third/ispell/parse.y @ 10334

Revision 10334, 49.2 KB checked in by ghudson, 27 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r10333, which included commits to RCS files with non-trunk default branches.
Line 
1%{
2#ifndef lint
3static char Rcs_Id[] =
4    "$Id: parse.y,v 1.1.1.1 1997-09-03 21:08:10 ghudson Exp $";
5#endif
6
7/*
8 * Copyright 1992, 1993, Geoff Kuenning, Granada Hills, CA
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 * 3. All modifications to the source code must be clearly marked as
21 *    such.  Binary redistributions based on modified source code
22 *    must be clearly marked as modified versions in the documentation
23 *    and/or other materials provided with the distribution.
24 * 4. All advertising materials mentioning features or use of this software
25 *    must display the following acknowledgment:
26 *      This product includes software developed by Geoff Kuenning and
27 *      other unpaid contributors.
28 * 5. The name of Geoff Kuenning may not be used to endorse or promote
29 *    products derived from this software without specific prior
30 *    written permission.
31 *
32 * THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING AND CONTRIBUTORS ``AS IS'' AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED.  IN NO EVENT SHALL GEOFF KUENNING OR CONTRIBUTORS BE LIABLE
36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * SUCH DAMAGE.
43 */
44
45/*
46 * $Log: not supported by cvs2svn $
47 * Revision 1.52  1994/11/21  07:03:03  geoff
48 * Get rid of the last vestiges of the "+" flag option.
49 *
50 * Revision 1.51  1994/11/02  06:56:13  geoff
51 * Remove the anyword feature, which I've decided is a bad idea.
52 *
53 * Revision 1.50  1994/10/25  05:46:22  geoff
54 * Add support for the "+" (any word) flag modifier.
55 *
56 * Revision 1.49  1994/09/16  04:48:30  geoff
57 * Allow more than 128 string characters, by using different types in the
58 * appropriate places.
59 *
60 * Revision 1.48  1994/05/24  05:31:25  geoff
61 * Remember to convert the flag bit from a character to a bit number
62 * before putting it in the hash file.
63 *
64 * Revision 1.47  1994/05/24  04:54:33  geoff
65 * Improve the error checking for affix flag names, detecting bad flags
66 * and duplicates.
67 *
68 * Revision 1.46  1994/05/22  01:38:02  geoff
69 * Don't force flags to uppercase if lowercase flags are legal
70 *
71 * Revision 1.45  1994/05/17  06:44:17  geoff
72 * Add support for controlled compound formation and the COMPOUNDONLY
73 * option to affix flags.
74 *
75 * Revision 1.44  1994/02/07  05:51:03  geoff
76 * Fix a place where atoi got the wrong argument type (lint error only)
77 *
78 * Revision 1.43  1994/01/25  07:12:01  geoff
79 * Get rid of all old RCS log lines in preparation for the 3.1 release.
80 *
81 */
82
83#include <ctype.h>
84#include "config.h"
85#include "ispell.h"
86#include "proto.h"
87#include "msgs.h"
88
89%}
90
91%union
92    {
93    int                 simple;         /* Simple char or lval from yylex */
94    struct
95        {
96        char *          set;            /* Character set */
97        int             complement;     /* NZ if it is a complement set */
98        }
99                        charset;
100    unsigned char *     string;         /* String */
101    ichar_t *           istr;           /* Internal string */
102    struct flagent *    entry;          /* Flag entry */
103    }
104
105%{
106
107static int      yylex P ((void)); /* Trivial lexical analyzer */
108static int      kwanalyze P ((int backslashed, unsigned char * str));
109                                /* Analyze a possible keyword */
110static void     getqstring P ((void));
111                                /* Get (double-)quoted string */
112static void     getrange P ((void)); /* Get a lexical character range */
113static int      backch P ((void)); /* Process a backslashed character */
114static void     yyerror P ((char * msg));
115                                /* Print out an error message */
116int             yyopen P ((char * file));
117                                /* Open a table file */
118void            yyinit P ((void)); /* Initialize for parsing */
119static int      grabchar P ((void));
120                                /* Get a character and track line number */
121static void     ungrabchar P ((int ch));
122                                /* Unget a character, tracking line numbers */
123static int      sufcmp P ((struct flagent * flag1, struct flagent * flag2));
124                                /* Compare suffix flags for qsort */
125static int      precmp P ((struct flagent * flag1, struct flagent * flag2));
126                                /* Compare prefix flags for qsort */
127static int      addstringchar P ((unsigned char * str, int lower, int upper));
128                                /* Add a string character to the table */
129static int      stringcharcmp P ((char * a, char * b));
130                                /* Strcmp() done right, for Sun 4's */
131#ifdef TBLDEBUG
132static void     tbldump P ((struct flagent * flagp, int numflags));
133                                /* Dump a flag table */
134static void     entdump P ((struct flagent * flagp));
135                                /* Dump one flag entry */
136static void     setdump P ((char * setp, int mask));
137                                /* Dump a set specification */
138static void     subsetdump P ((char * setp, int mask, int dumpval));
139                                /* Dump part of a set spec */
140#endif
141
142struct kwtab
143    {
144    char *      kw;             /* Syntactic keyword */
145    int         val;            /* Lexical value */
146    };
147
148#define TBLINC          10              /* Size to allocate table by */
149
150static FILE *           aff_file = NULL; /* Input file pointer */
151static int              centnum;        /* Number of entries in curents */
152static int              centsize = 0;   /* Size of alloc'ed space in curents */
153static int              ctypechars;     /* Size of string in current strtype */
154static int              ctypenum = 0;   /* Number of entries in chartypes */
155static int              ctypesize = 0;  /* Size of alloc'ed spc in chartypes */
156static struct flagent * curents;        /* Current flag entry collection */
157static char *           fname = "(stdin)"; /* Current file name */
158static char             lexungrab[MAXSTRINGCHARLEN * 2]; /* Spc for ungrabch */
159static int              lineno = 1;     /* Current line number in file */
160static struct flagent * table;          /* Current table being built */
161static int              tblnum;         /* Numer of entries in table */
162static int              tblsize = 0;    /* Size of the flag table */
163static int              ungrablen;      /* Size of ungrab area */
164%}
165
166%token <simple> '-'
167%token <simple> '>'
168%token <simple> ','
169%token <simple> ':'
170%token <simple> '.'
171%token <simple> '*'
172%token <simple> '~'
173%token <simple> ALLAFFIXES
174%token <simple> ALTSTRINGCHAR
175%token <simple> ALTSTRINGTYPE
176%token <simple> BOUNDARYCHARS
177%token <simple> COMPOUNDMIN
178%token <simple> COMPOUNDWORDS
179%token <simple> CONTROLLED
180%token <simple> DEFSTRINGTYPE
181%token <simple> FLAG
182%token <simple> FLAGMARKER
183%token <simple> NROFFCHARS
184%token <simple> OFF
185%token <simple> ON
186%token <simple> PREFIXES
187%token <charset> RANGE
188%token <simple> SUFFIXES
189%token <string> STRING
190%token <simple> STRINGCHAR
191%token <simple> TEXCHARS
192%token <simple> WORDCHARS
193
194%type <simple> file
195%type <simple> headers
196%type <simple> option_group
197%type <simple> charset_group
198%type <simple> altchar_group
199%type <simple> charset_stmt
200%type <simple> option_stmt
201%type <simple> altchar_stmt
202%type <simple> altchar_spec_group
203%type <simple> altchar_spec
204%type <simple> deftype_stmt
205%type <string> stringtype_info
206%type <simple> filesuf_list
207%type <string> filesuf
208%type <charset> char_set
209%type <simple> tables
210%type <simple> prefix_table
211%type <simple> suffix_table
212%type <simple> table
213%type <simple> flagdef
214%type <simple> flagoptions
215%type <simple> flagoption
216%type <simple> error
217%type <simple> on_or_off
218%type <simple> rules
219%type <entry> affix_rule
220%type <entry> cond_or_null
221%type <entry> conditions
222%type <istr> ichar_string
223%%
224file            :       headers tables
225                |       tables
226                ;
227
228headers         :       option_group charset_group
229                |       option_group charset_group altchar_group
230                |       charset_group
231                |       charset_group altchar_group
232                ;
233
234option_group    :       option_stmt
235                |       option_group option_stmt
236                ;
237
238charset_group   :       deftype_stmt charset_stmt
239                |       charset_stmt
240                |       charset_group charset_stmt
241                ;
242
243deftype_stmt    :       DEFSTRINGTYPE stringtype_info
244                ;
245
246altchar_group   :       altchar_stmt
247                |       altchar_group altchar_stmt
248                ;
249
250charset_stmt    :       WORDCHARS char_set char_set
251                            {
252                            int nextlower;
253                            int nextupper;
254
255                            for (nextlower = SET_SIZE + hashheader.nstrchars;
256                              --nextlower > SET_SIZE;
257                              )
258                                {
259                                if ($2.set[nextlower] != 0
260                                  ||  $3.set[nextlower] != 0)
261                                    {
262                                    yyerror (PARSE_Y_NO_WORD_STRINGS);
263                                    break;
264                                    }
265                                }
266                            for (nextlower = 0;
267                              nextlower < SET_SIZE;
268                              nextlower++)
269                                {
270                                hashheader.wordchars[nextlower]
271                                  |= $2.set[nextlower] | $3.set[nextlower];
272                                hashheader.lowerchars[nextlower]
273                                  |= $2.set[nextlower];
274                                hashheader.upperchars[nextlower]
275                                  |= $3.set[nextlower];
276                                }
277                            for (nextlower = nextupper = 0;
278                              nextlower < SET_SIZE;
279                              nextlower++)
280                                {
281                                if ($2.set[nextlower])
282                                    {
283                                    for (  ;
284                                      nextupper < SET_SIZE
285                                        &&  !$3.set[nextupper];
286                                      nextupper++)
287                                        ;
288                                    if (nextupper == SET_SIZE)
289                                        yyerror (PARSE_Y_UNMATCHED);
290                                    else
291                                        {
292                                        hashheader.lowerconv[nextupper]
293                                          = (ichar_t) nextlower;
294                                        hashheader.upperconv[nextlower]
295                                          = (ichar_t) nextupper;
296                                        hashheader.sortorder[nextupper]
297                                          = hashheader.sortval++;
298                                        hashheader.sortorder[nextlower]
299                                          = hashheader.sortval++;
300                                        nextupper++;
301                                        }
302                                    }
303                                }
304                            for (  ;  nextupper < SET_SIZE;  nextupper++)
305                                {
306                                if ($3.set[nextupper])
307                                    yyerror (PARSE_Y_UNMATCHED);
308                                }
309                            free ($2.set);
310                            free ($3.set);
311                            }
312                |       WORDCHARS char_set
313                            {
314                            int i;
315
316                            for (i = SET_SIZE + hashheader.nstrchars;
317                              --i > SET_SIZE;
318                              )
319                                {
320                                if ($2.set[i] != 0)
321                                    {
322                                    yyerror (PARSE_Y_NO_WORD_STRINGS);
323                                    break;
324                                    }
325                                }
326                            for (i = 0;  i < SET_SIZE;  i++)
327                                {
328                                if ($2.set[i])
329                                    {
330                                    hashheader.wordchars[i] = 1;
331                                    hashheader.sortorder[i]
332                                      = hashheader.sortval++;
333                                    }
334                                }
335                            free ($2.set);
336                            }
337                |       BOUNDARYCHARS char_set char_set
338                            {
339                            int nextlower;
340                            int nextupper;
341
342                            for (nextlower = SET_SIZE + hashheader.nstrchars;
343                              --nextlower > SET_SIZE;
344                              )
345                                {
346                                if ($2.set[nextlower] != 0
347                                  ||  $3.set[nextlower] != 0)
348                                    {
349                                    yyerror (PARSE_Y_NO_BOUNDARY_STRINGS);
350                                    break;
351                                    }
352                                }
353                            for (nextlower = 0;
354                              nextlower < SET_SIZE;
355                              nextlower++)
356                                {
357                                hashheader.boundarychars[nextlower]
358                                  |= $2.set[nextlower] | $3.set[nextlower];
359                                hashheader.lowerchars[nextlower]
360                                  |= $2.set[nextlower];
361                                hashheader.upperchars[nextlower]
362                                  |= $3.set[nextlower];
363                                }
364                            for (nextlower = nextupper = 0;
365                              nextlower < SET_SIZE;
366                              nextlower++)
367                                {
368                                if ($2.set[nextlower])
369                                    {
370                                    for (  ;
371                                      nextupper < SET_SIZE
372                                        &&  !$3.set[nextupper];
373                                      nextupper++)
374                                        ;
375                                    if (nextupper == SET_SIZE)
376                                        yyerror (PARSE_Y_UNMATCHED);
377                                    else
378                                        {
379                                        hashheader.lowerconv[nextupper]
380                                          = (ichar_t) nextlower;
381                                        hashheader.upperconv[nextlower]
382                                          = (ichar_t) nextupper;
383                                        hashheader.sortorder[nextupper]
384                                          = hashheader.sortval++;
385                                        hashheader.sortorder[nextlower]
386                                          = hashheader.sortval++;
387                                        nextupper++;
388                                        }
389                                    }
390                                }
391                            for (  ;  nextupper < SET_SIZE;  nextupper++)
392                                {
393                                if ($3.set[nextupper])
394                                    yyerror (PARSE_Y_UNMATCHED);
395                                }
396                            free ($2.set);
397                            free ($3.set);
398                            }
399                |       BOUNDARYCHARS char_set
400                            {
401                            int i;
402
403                            for (i = SET_SIZE + hashheader.nstrchars;
404                              --i > SET_SIZE;
405                              )
406                                {
407                                if ($2.set[i] != 0)
408                                    {
409                                    yyerror (PARSE_Y_NO_BOUNDARY_STRINGS);
410                                    break;
411                                    }
412                                }
413                            for (i = 0;  i < SET_SIZE;  i++)
414                                {
415                                if ($2.set[i])
416                                    {
417                                    hashheader.boundarychars[i] = 1;
418                                    hashheader.sortorder[i]
419                                      = hashheader.sortval++;
420                                    }
421                                }
422                            free ($2.set);
423                            }
424                |       STRINGCHAR STRING
425                            {
426                            int len;
427
428                            len = strlen ((char *) $2);
429                            if (len > MAXSTRINGCHARLEN)
430                                yyerror (PARSE_Y_LONG_STRING);
431                            else if (len == 0)
432                                yyerror (PARSE_Y_NULL_STRING);
433                            else if (hashheader.nstrchars >= MAXSTRINGCHARS)
434                                yyerror (PARSE_Y_MANY_STRINGS);
435                            else
436                                (void) addstringchar ($2, 0, 0);
437                            free ((char *) $2);
438                            }
439                |       STRINGCHAR STRING STRING
440                            {
441                            int lcslot;
442                            int len;
443                            int ucslot;
444
445                            len = strlen ((char *) $2);
446                            if (strlen ((char *) $3) != len)
447                                yyerror (PARSE_Y_LENGTH_MISMATCH);
448                            else if (len > MAXSTRINGCHARLEN)
449                                yyerror (PARSE_Y_LONG_STRING);
450                            else if (len == 0)
451                                yyerror (PARSE_Y_NULL_STRING);
452                            else if (hashheader.nstrchars >= MAXSTRINGCHARS)
453                                yyerror (PARSE_Y_MANY_STRINGS);
454                            else
455                                {
456                                /*
457                                 * Add the uppercase character first, so that
458                                 * it will sort first.
459                                 */
460                                lcslot = ucslot = addstringchar ($3, 0, 1);
461                                if (ucslot >= 0)
462                                    lcslot = addstringchar ($2, 1, 0);
463                                if (ucslot >= 0  &&  lcslot >= 0)
464                                    {
465                                    if (ucslot >= lcslot)
466                                        ucslot++;
467                                    hashheader.lowerconv[ucslot] =
468                                      (ichar_t) lcslot;
469                                    hashheader.upperconv[lcslot] =
470                                      (ichar_t) ucslot;
471                                    }
472                                }
473                            free ((char *) $2);
474                            free ((char *) $3);
475                            }
476                ;
477
478altchar_stmt    :       ALTSTRINGTYPE stringtype_info
479                |       ALTSTRINGTYPE stringtype_info altchar_spec_group
480                ;
481
482stringtype_info :       STRING STRING filesuf_list
483                            {
484                            chartypes[ctypenum].name = (char *) $1;
485                            chartypes[ctypenum].deformatter = (char *) $2;
486                            /*
487                             * Implement a few common synonyms.  This should
488                             * be generalized.
489                             */
490                            if (strcmp ((char *) $2, "TeX") == 0)
491                                (void) strcpy ((char *) $2, "tex");
492                            else if (strcmp ((char *) $2, "troff") == 0)
493                                (void) strcpy ((char *) $2, "nroff");
494                            /*
495                             * Someday, we'll accept generalized deformatters.
496                             * Then we can get rid of this test.
497                             */
498                            if (strcmp ((char *) $2, "nroff") != 0
499                              &&  strcmp ((char *) $2, "tex") != 0)
500                                yyerror (PARSE_Y_BAD_DEFORMATTER);
501                            ctypenum++;
502                            hashheader.nstrchartype = ctypenum;
503                            }
504                ;
505
506filesuf_list    :       filesuf
507                            {
508                            if (ctypenum >= ctypesize)
509                                {
510                                if (ctypesize == 0)
511                                    chartypes = (struct strchartype *)
512                                      malloc (TBLINC
513                                        * sizeof (struct strchartype));
514                                else
515                                    chartypes = (struct strchartype *)
516                                      realloc ((char *) chartypes,
517                                        (ctypesize + TBLINC)
518                                          * sizeof (struct strchartype));
519                                if (chartypes == NULL)
520                                    {
521                                    yyerror (PARSE_Y_NO_SPACE);
522                                    exit (1);
523                                    }
524                                ctypesize += TBLINC;
525                                }
526                            ctypechars =
527                              TBLINC * (strlen ((char *) $1) + 1) + 1;
528                            chartypes[ctypenum].suffixes =
529                              malloc ((unsigned int) ctypechars);
530                            if (chartypes[ctypenum].suffixes == NULL)
531                                {
532                                yyerror (PARSE_Y_NO_SPACE);
533                                exit (1);
534                                }
535                            (void) strcpy (chartypes[ctypenum].suffixes,
536                             (char *) $1);
537                            chartypes[ctypenum].suffixes
538                                [strlen ((char *) $1) + 1]
539                              = '\0';
540                            free ((char *) $1);
541                            }
542                |       filesuf_list filesuf
543                            {
544                            char *      nexttype;
545                            int         offset;
546
547                            for (nexttype = chartypes[ctypenum].suffixes;
548                              *nexttype != '\0';
549                              nexttype += strlen (nexttype) + 1)
550                                ;
551                            offset = nexttype - chartypes[ctypenum].suffixes;
552                            if ((int) (offset + strlen ((char *) $2) + 1)
553                               >= ctypechars)
554                                {
555                                ctypechars +=
556                                  TBLINC * (strlen ((char *) $2) + 1);
557                                chartypes[ctypenum].suffixes =
558                                  realloc (chartypes[ctypenum].suffixes,
559                                    (unsigned int) ctypechars);
560                                if (chartypes[ctypenum].suffixes == NULL)
561                                    {
562                                    yyerror (PARSE_Y_NO_SPACE);
563                                    exit (1);
564                                    }
565                                nexttype =
566                                  chartypes[ctypenum].suffixes + offset;
567                                }
568                            (void) strcpy (nexttype, (char *) $2);
569                            nexttype[strlen ((char *) $2) + 1] = '\0';
570                            free ((char *) $2);
571                            }
572                ;
573
574filesuf         :       STRING
575                ;
576
577altchar_spec_group
578                :       altchar_spec
579                |       altchar_spec_group altchar_spec
580                ;
581
582altchar_spec    :       ALTSTRINGCHAR STRING STRING
583                            {
584                            int i;
585                            int len;
586                            int slot;
587
588                            len = strlen ((char *) $2);
589                            if (len > MAXSTRINGCHARLEN)
590                                yyerror (PARSE_Y_LONG_STRING);
591                            else if (len == 0)
592                                yyerror (PARSE_Y_NULL_STRING);
593                            else if (hashheader.nstrchars >= MAXSTRINGCHARS)
594                                yyerror (PARSE_Y_MANY_STRINGS);
595                            else if (!isstringch ((char *) $3, 1))
596                                yyerror (PARSE_Y_NO_SUCH_STRING);
597                            else
598                                {
599                                slot = addstringchar ($2, 0, 0) - SET_SIZE;
600                                if (laststringch >= slot)
601                                    laststringch++;
602                                hashheader.stringdups[slot] = laststringch;
603                                for (i = hashheader.nstrchars;  --i >= 0;  )
604                                    {
605                                    if (hashheader.stringdups[i]
606                                      == laststringch)
607                                        hashheader.dupnos[slot]++;
608                                    }
609                                /*
610                                 * The above code sets dupnos one too high,
611                                 * because it counts the character itself.
612                                 */
613                                if (hashheader.dupnos[slot]
614                                  != hashheader.nstrchartype)
615                                    yyerror (PARSE_Y_MULTIPLE_STRINGS);
616                                hashheader.dupnos[slot]--;
617                                }
618                            free ((char *) $2);
619                            free ((char *) $3);
620                            }
621                ;
622
623option_stmt     :       NROFFCHARS STRING
624                            {
625                            if (strlen ((char *) $2)
626                              == sizeof (hashheader.nrchars))
627                                (void) bcopy ((char *) $2, hashheader.nrchars,
628                                  sizeof (hashheader.nrchars));
629                            else
630                                yyerror (PARSE_Y_WRONG_NROFF);
631                            free ((char *) $2);
632                            }
633                ;
634                |       TEXCHARS STRING
635                            {
636                            if (strlen ((char *) $2)
637                              == sizeof (hashheader.texchars))
638                                (void) bcopy ((char *) $2, hashheader.texchars,
639                                  sizeof (hashheader.texchars));
640                            else
641                                yyerror (PARSE_Y_WRONG_TEX);
642                            free ((char *) $2);
643                            }
644                |       COMPOUNDMIN STRING
645                            {
646                            unsigned char * digitp; /* Pointer to next digit */
647
648                            for (digitp = $2;  *digitp != '\0';  digitp++)
649                                {
650                                if (*digitp <= '0'  ||  *digitp >= '9')
651                                    {
652                                    yyerror (PARSE_Y_BAD_NUMBER);
653                                    break;
654                                    }
655                                }
656                            hashheader.compoundmin = atoi ((char *) $2);
657                            }
658                |       COMPOUNDWORDS on_or_off
659                            {
660                            hashheader.compoundflag = $2;
661                            }
662                |       COMPOUNDWORDS CONTROLLED STRING
663                            {
664                            if (strlen ((char *) $3) != 1)
665                                yyerror (PARSE_Y_LONG_FLAG);
666                            else if (hashheader.compoundbit >= 0)
667                                yyerror (PARSE_Y_DOUBLE_COMPOUND);
668                            else
669                                {
670                                hashheader.compoundbit = (unsigned char) $3[0];
671#if MASKBITS <= 128
672                                hashheader.compoundbit &= 0x7f;
673#endif /* MASKBITS */
674#if MASKBITS <= 32
675                                if (islower (hashheader.compoundbit))
676                                    hashheader.compoundbit =
677                                      toupper (hashheader.compoundbit);
678#endif /* MASKBITS */
679#if MASKBITS <= 64
680                                if (!isalpha (hashheader.compoundbit))
681                                    yyerror (PARSE_Y_BAD_FLAG);
682#endif /* MASKBITS */
683                                hashheader.compoundbit =
684                                  CHARTOBIT (hashheader.compoundbit);
685                                }
686                            hashheader.compoundflag = COMPOUND_CONTROLLED;
687                            }
688                |       ALLAFFIXES on_or_off
689                            {
690                            hashheader.defhardflag = $2;
691                            }
692                |       FLAGMARKER STRING
693                            {
694                            if (strlen ((char *) $2) != 1)
695                                yyerror (PARSE_Y_LONG_FLAG);
696                            else
697                                hashheader.flagmarker = $2[0];
698                            free ((char *) $2);
699                            }
700                ;
701
702char_set        :       '.'
703                            {
704                            int         i;
705                            char *      set;
706
707                            set = malloc (SET_SIZE + MAXSTRINGCHARS);
708                            if (set == NULL)
709                                {
710                                yyerror (PARSE_Y_NO_SPACE);
711                                exit (1);
712                                }
713                            $$.set = set;
714                            for (i = SET_SIZE + MAXSTRINGCHARS;  --i >= 0;  )
715                                *set++ = 1;
716                            $$.complement = 0;
717                            }
718                |       STRING
719                            {
720                            int         setlen;
721
722                            $$.set = malloc (SET_SIZE + MAXSTRINGCHARS);
723                            if ($$.set == NULL)
724                                {
725                                yyerror (PARSE_Y_NO_SPACE);
726                                exit (1);
727                                }
728                            (void) bzero ($$.set, SET_SIZE + MAXSTRINGCHARS);
729                            if (l1_isstringch ((char *) $1, setlen, 1))
730                                {
731                                if (setlen != strlen ((char *) $1))
732                                    yyerror (PARSE_Y_NEED_BLANK);
733                                $$.set[SET_SIZE + laststringch] = 1;
734                                }
735                            else
736                                {
737                                if (strlen ((char *) $1) != 1)
738                                    yyerror (PARSE_Y_NEED_BLANK);
739                                $$.set[*$1] = 1;
740                                }
741                            free ((char *) $1);
742                            $$.complement = 0;
743                            }
744                |       RANGE
745                ;
746
747on_or_off       :       ON
748                            {
749                            $$ = 1;
750                            }
751                |       OFF
752                            {
753                            $$ = 0;
754                            }
755                ;
756
757tables          :       prefix_table suffix_table
758                |       suffix_table prefix_table
759                |       prefix_table
760                |       suffix_table
761                ;
762
763prefix_table    :       PREFIXES table
764                            {
765                            pflaglist = table;
766                            numpflags = tblnum;
767                            /*
768                             * Sort the flag table.  This is critical so
769                             * that ispell can build a correct index
770                             * table.  The idea is to put similar affixes
771                             * together.
772                             */
773                            qsort ((char *) table, (unsigned) tblnum,
774                              sizeof (*table),
775                              (int (*) P ((const void *, const void *)))
776                                precmp);
777#ifdef TBLDEBUG
778                            (void) fprintf (stderr, "prefixes\n");
779                            tbldump (table, tblnum);
780#endif
781                            tblsize = 0;
782                            }
783                ;
784
785suffix_table    :       SUFFIXES table
786                            {
787                            sflaglist = table;
788                            numsflags = tblnum;
789                            /*
790                             * See comments on the prefix sort.
791                             */
792                            qsort ((char *) table, (unsigned) tblnum,
793                              sizeof (*table),
794                              (int (*) P ((const void *, const void *)))
795                                sufcmp);
796#ifdef TBLDEBUG
797                            (void) fprintf (stderr, "suffixes\n");
798                            tbldump (table, tblnum);
799#endif
800                            tblsize = 0;
801                            }
802                ;
803
804table           :       flagdef
805                            {
806                            if (tblsize == 0)
807                                {
808                                tblsize = centnum + TBLINC;
809                                tblnum = 0;
810                                table = (struct flagent *)
811                                  malloc (tblsize * (sizeof (struct flagent)));
812                                if (table == NULL)
813                                    {
814                                    yyerror (PARSE_Y_NO_SPACE);
815                                    exit (1);
816                                    }
817                                }
818                            else if (tblnum + centnum >= tblsize)
819                                {
820                                tblsize = tblnum + centnum + TBLINC;
821                                table = (struct flagent *)
822                                  realloc ((char *) table,
823                                    tblsize * (sizeof (struct flagent)));
824                                if (table == NULL)
825                                    {
826                                    yyerror (PARSE_Y_NO_SPACE);
827                                    exit (1);
828                                    }
829                                }
830                            for (tblnum = 0;  tblnum < centnum;  tblnum++)
831                                table[tblnum] = curents[tblnum];
832                            centnum = 0;
833                            }
834                |       table flagdef
835                            {
836                            int i;
837
838                            if (tblnum + centnum >= tblsize)
839                                {
840                                tblsize = tblnum + centnum + TBLINC;
841                                table = (struct flagent *)
842                                  realloc ((char *) table,
843                                    tblsize * (sizeof (struct flagent)));
844                                if (table == NULL)
845                                    {
846                                    yyerror (PARSE_Y_NO_SPACE);
847                                    exit (1);
848                                    }
849                                }
850                            for (i = 0;  i < centnum;  i++)
851                                table[tblnum + i] = curents[i];
852                            tblnum += centnum;
853                            centnum = 0;
854                            }
855                ;
856
857flagdef         :       FLAG STRING ':' rules
858                            {
859                            int flagbit;
860                            int i;
861
862                            if (strlen ((char *) $2) != 1)
863                                yyerror (PARSE_Y_LONG_FLAG);
864                            flagbit = (unsigned char) $2[0];
865#if MASKBITS <= 128
866                            flagbit &= 0x7f;
867#endif /* MASKBITS */
868#if MASKBITS <= 32
869                            if (islower (flagbit))
870                                flagbit = toupper (flagbit);
871#endif /* MASKBITS */
872#if MASKBITS <= 64
873                            if (!isalpha (flagbit))
874                                yyerror (PARSE_Y_BAD_FLAG);
875#endif /* MASKBITS */
876                            flagbit = CHARTOBIT (flagbit);
877                            for (i = 0;  i < tblnum;  i++)
878                                {
879                                if (table[i].flagbit == flagbit)
880                                    yyerror (PARSE_Y_DUP_FLAG);
881                                }
882                            for (i = 0;  i < centnum;  i++)
883                                {
884                                curents[i].flagbit = flagbit;
885                                curents[i].flagflags = 0;
886                                }
887                            free ((char *) $2);
888                            }
889                |       FLAG flagoptions STRING ':' rules
890                            {
891                            int flagbit;
892                            int i;
893
894                            if (strlen ((char *) $3) != 1)
895                                yyerror (PARSE_Y_LONG_FLAG);
896                            flagbit = (unsigned char) $3[0];
897#if MASKBITS <= 128
898                            flagbit &= 0x7f;
899#endif /* MASKBITS */
900#if MASKBITS <= 32
901                            if (islower (flagbit))
902                                flagbit = toupper (flagbit);
903#endif /* MASKBITS */
904#if MASKBITS <= 64
905                            if (!isalpha (flagbit))
906                                yyerror (PARSE_Y_BAD_FLAG);
907#endif /* MASKBITS */
908                            flagbit = CHARTOBIT (flagbit);
909                            for (i = 0;  i < tblnum;  i++)
910                                {
911                                if (table[i].flagbit == flagbit)
912                                    yyerror (PARSE_Y_DUP_FLAG);
913                                }
914                            for (i = 0;  i < centnum;  i++)
915                                {
916                                curents[i].flagbit = flagbit;
917                                curents[i].flagflags = $2;
918                                }
919                            free ((char *) $3);
920                            }
921                |       error
922                            { $$ = 0; }
923                ;
924
925flagoptions     :       flagoption
926                |       flagoptions flagoption
927                            {
928                            $$ = $1 | $2;
929                            }
930                ;
931
932flagoption      :       '*'
933                            { $$ = FF_CROSSPRODUCT; }
934                |       '~'
935                            { $$ = FF_COMPOUNDONLY; }
936                ;
937
938rules           :       affix_rule
939                            {
940                            if (centsize == 0)
941                                {
942                                curents = (struct flagent *)
943                                  malloc (TBLINC * (sizeof (struct flagent)));
944                                if (curents == NULL)
945                                    {
946                                    yyerror (PARSE_Y_NO_SPACE);
947                                    exit (1);
948                                    }
949                                centsize = TBLINC;
950                                }
951                            curents[0] = *$1;
952                            centnum = 1;
953                            free ((char *) $1);
954                            $$ = 0;
955                            }
956                |       rules affix_rule
957                            {
958                            if (centnum >= centsize)
959                                {
960                                centsize += TBLINC;
961                                curents = (struct flagent *)
962                                  realloc ((char *) curents,
963                                    centsize * (sizeof (struct flagent)));
964                                if (curents == NULL)
965                                    {
966                                    yyerror (PARSE_Y_NO_SPACE);
967                                    exit (1);
968                                    }
969                                }
970                            curents[centnum] = *$2;
971                            centnum++;
972                            free ((char *) $2);
973                            }
974                ;
975
976affix_rule      :       cond_or_null '>' ichar_string
977                            {
978                            int         i;
979
980                            $1->stripl = 0;
981                            $1->strip = NULL;
982                            $1->affl = icharlen ($3);
983                            $1->affix = $3;
984                            upcase ($3);
985                            /*
986                             * As a special optimization (and a
987                             * concession to those who prefer the syntax
988                             * that way), convert any single condition
989                             * that accepts all characters into no
990                             * condition at all.
991                             */
992                            if ($1->numconds == 1)
993                                {
994                                for (i = SET_SIZE + hashheader.nstrchars;
995                                  --i >= 0;
996                                  )
997                                    {
998                                    if (($1->conds[i] & 1) == 0)
999                                        break;
1000                                    }
1001                                if (i < 0)
1002                                    $1->numconds = 0;
1003                                }
1004                            $$ = $1;
1005                            }
1006                |       cond_or_null '>' '-' ichar_string ',' ichar_string
1007                            {
1008                            int             i;
1009
1010                            $1->stripl = icharlen ($4);
1011                            $1->strip = $4;
1012                            upcase ($4);
1013                            $1->affl = icharlen ($6);
1014                            $1->affix = $6;
1015                            upcase ($6);
1016                            /*
1017                             * Convert the syntax ". > -xxx,yyy" into
1018                             * " > -xxx,yyy", as in the code just above.
1019                             */
1020                            if ($1->numconds == 1)
1021                                {
1022                                for (i = SET_SIZE + hashheader.nstrchars;
1023                                  --i >= 0;
1024                                  )
1025                                    {
1026                                    if (($1->conds[i] & 1) == 0)
1027                                        break;
1028                                    }
1029                                if (i < 0)
1030                                    $1->numconds = 0;
1031                                }
1032                            $$ = $1;
1033                            }
1034                |       cond_or_null '>' '-' ichar_string ',' '-'
1035                            {
1036                            int             i;
1037
1038                            $1->stripl = icharlen ($4);
1039                            $1->strip = $4;
1040                            upcase ($4);
1041                            $1->affl = 0;
1042                            $1->affix = NULL;
1043                            /*
1044                             * Convert the syntax ". > -xxx," into
1045                             * " > -xxx,", as in the code just above.
1046                             */
1047                            if ($1->numconds == 1)
1048                                {
1049                                for (i = SET_SIZE + hashheader.nstrchars;
1050                                  --i >= 0;
1051                                  )
1052                                    {
1053                                    if (($1->conds[i] & 1) == 0)
1054                                        break;
1055                                    }
1056                                if (i < 0)
1057                                    $1->numconds = 0;
1058                                }
1059                            $$ = $1;
1060                            }
1061                |       cond_or_null '>' '-' ',' '-'
1062                            {
1063                            int             i;
1064
1065                            $1->stripl = 0;
1066                            $1->strip = NULL;
1067                            $1->affl = 0;
1068                            $1->affix = NULL;
1069                            /*
1070                             * Convert the syntax ". > -,-" into
1071                             * " > -,-", as in the code just above.
1072                             */
1073                            if ($1->numconds == 1)
1074                                {
1075                                for (i = SET_SIZE + hashheader.nstrchars;
1076                                  --i >= 0;
1077                                  )
1078                                    {
1079                                    if (($1->conds[i] & 1) == 0)
1080                                        break;
1081                                    }
1082                                if (i < 0)
1083                                    $1->numconds = 0;
1084                                }
1085                            $$ = $1;
1086                            }
1087                ;
1088
1089cond_or_null    :       /* Empty */
1090                            {
1091                            struct flagent *    ent;
1092
1093                            ent = (struct flagent *)
1094                              malloc (sizeof (struct flagent));
1095                            if (ent == NULL)
1096                                {
1097                                yyerror (PARSE_Y_NO_SPACE);
1098                                exit (1);
1099                                }
1100                            ent->numconds = 0;
1101                            (void) bzero (ent->conds,
1102                               SET_SIZE + MAXSTRINGCHARS);
1103                            $$ = ent;
1104                            }
1105                |       conditions
1106                ;
1107
1108conditions      :       char_set
1109                            {
1110                            struct flagent *    ent;
1111                            int                 i;
1112
1113                            ent = (struct flagent *)
1114                              malloc (sizeof (struct flagent));
1115                            if (ent == NULL)
1116                                {
1117                                yyerror (PARSE_Y_NO_SPACE);
1118                                exit (1);
1119                                }
1120                            ent->numconds = 1;
1121                            (void) bzero (ent->conds,
1122                               SET_SIZE + MAXSTRINGCHARS);
1123                            /*
1124                             * Copy conditions to the new entry, making
1125                             * sure that uppercase versions are generated
1126                             * for lowercase input.
1127                             */
1128                            for (i = SET_SIZE + MAXSTRINGCHARS;  --i >= 0;  )
1129                                {
1130                                if ($1.set[i])
1131                                    {
1132                                    ent->conds[i] = 1;
1133                                    if (!$1.complement)
1134                                        ent->conds[mytoupper ((ichar_t) i)] = 1;
1135                                    }
1136                                }
1137                            if ($1.complement)
1138                                {
1139                                for (i = SET_SIZE + MAXSTRINGCHARS;
1140                                --i >= 0;
1141                                )
1142                                    {
1143                                    if ($1.set[i] == 0)
1144                                        ent->conds[mytoupper ((ichar_t) i)] = 0;
1145                                    }
1146                                }
1147                            free ($1.set);
1148                            $$ = ent;
1149                            }
1150                |       conditions char_set
1151                            {
1152                            int                 i;
1153                            int                 mask;
1154
1155                            if ($1->numconds >= 8)
1156                                {
1157                                yyerror (PARSE_Y_MANY_CONDS);
1158                                $1->numconds = 7;
1159                                }
1160                            mask = 1 << $1->numconds;
1161                            $1->numconds++;
1162                            for (i = SET_SIZE + MAXSTRINGCHARS;
1163                              --i >= 0;
1164                              )
1165                                {
1166                                if ($2.set[i])
1167                                    {
1168                                    $1->conds[i] |= mask;
1169                                    if (!$2.complement)
1170                                        $1->conds[mytoupper ((ichar_t) i)]
1171                                          |= mask;
1172                                    }
1173                                }
1174                            if ($2.complement)
1175                                {
1176                                mask = ~mask;
1177                                for (i = SET_SIZE + MAXSTRINGCHARS;
1178                                  --i >= 0;
1179                                  )
1180                                    {
1181                                    if ($2.set[i] == 0)
1182                                        $1->conds[mytoupper ((ichar_t) i)]
1183                                          &= mask;
1184                                    }
1185                                }
1186                            free ($2.set);
1187                            }
1188                ;
1189
1190ichar_string    :       STRING
1191                            {
1192                            ichar_t *tichar;
1193
1194                            tichar = strtosichar ((char *) $1, 1);
1195                            $$ = (ichar_t *) malloc (sizeof (ichar_t)
1196                              * (icharlen (tichar) + 1));
1197                            if ($$ == NULL)
1198                                {
1199                                yyerror (PARSE_Y_NO_SPACE);
1200                                exit (1);
1201                                }
1202                            (void) icharcpy ($$, tichar);
1203                            free ((char *) $1);
1204                            }
1205                ;
1206%%
1207static struct kwtab                     /* Table of built-in keywords */
1208                keywords[] =
1209    {
1210    {"allaffixes", ALLAFFIXES},
1211    {"altstringchar", ALTSTRINGCHAR},
1212    {"altstringtype", ALTSTRINGTYPE},
1213    {"boundarychars", BOUNDARYCHARS},
1214    {"compoundmin", COMPOUNDMIN},
1215    {"compoundwords", COMPOUNDWORDS},
1216    {"controlled", CONTROLLED},
1217    {"defstringtype", DEFSTRINGTYPE},
1218    {"flag", FLAG},
1219    {"flagmarker", FLAGMARKER},
1220    {"nroffchars", NROFFCHARS},
1221    {"troffchars", NROFFCHARS},
1222    {"on", ON},
1223    {"off", OFF},
1224    {"prefixes", PREFIXES},
1225    {"stringchar", STRINGCHAR},
1226    {"suffixes", SUFFIXES},
1227    {"TeXchars", TEXCHARS},
1228    {"texchars", TEXCHARS},
1229    {"wordchars", WORDCHARS},
1230    {NULL, 0}
1231    };
1232
1233/*
1234 * Trivial lexical analyzer.
1235 */
1236static int yylex ()
1237    {
1238    int                 backslashed; /* NZ if backslash appeared */
1239    register int        ch;     /* Next character seen */
1240    register unsigned char *
1241                        lexp;   /* Pointer into lexstring */
1242    unsigned char       lexstring[256]; /* Space for collecting strings */
1243
1244    while ((ch = grabchar ()) != EOF  &&  (isspace (ch)  ||  ch == '#'))
1245        {                       /* Skip whitespace and comments */
1246        if (ch == '#')
1247            {
1248            while ((ch = grabchar ()) != EOF  &&  ch != '\n')
1249                ;
1250            }
1251        }
1252    switch (ch)
1253        {
1254        case EOF:
1255            return EOF;
1256        case '"':
1257            getqstring ();
1258            return STRING;
1259        case '-':
1260        case '>':
1261        case ',':
1262        case ':':
1263        case '.':
1264        case '*':
1265        case '~':
1266            yylval.simple = ch;
1267            return ch;
1268        case '[':               /* Beginning of a range set ] */
1269            getrange ();        /* Get the range */
1270            return RANGE;
1271        }
1272    /*
1273     * We get here if the character is an ordinary one;  note that
1274     * this includes backslashes.
1275     */
1276    backslashed = 0;
1277    lexp = lexstring;
1278    for (  ;  ;  )
1279        {
1280        switch (ch)
1281            {
1282            case EOF:
1283                *lexp = '\0';
1284                return kwanalyze (backslashed, lexstring);
1285            case '\\':
1286                backslashed = 1;
1287                ch = backch ();
1288                *lexp++ = (char) ch;
1289                break;
1290            case ' ':
1291            case '\t':
1292            case '\n':
1293            case '\f':
1294            case '\r':
1295                *lexp = '\0';
1296                return kwanalyze (backslashed, lexstring);
1297            case '#':
1298            case '>':
1299            case ':':
1300            case '-':
1301            case ',':
1302            case '[':                   /* ] */
1303                ungrabchar (ch);
1304                *lexp = '\0';
1305                return kwanalyze (backslashed, lexstring);
1306            default:
1307                *lexp++ = (char) ch;
1308#ifdef NO8BIT
1309                if (ch & 0x80)
1310                    yyerror (PARSE_Y_8_BIT);
1311#endif /* NO8BIT */
1312                break;
1313            }
1314        ch = grabchar ();
1315        }
1316    }
1317
1318static int kwanalyze (backslashed, str)
1319    int                 backslashed;    /* NZ if string had a backslash */
1320    register unsigned char *
1321                        str;            /* String to analyze */
1322    {
1323    register struct kwtab *
1324                        kwptr;          /* Pointer into keyword table */
1325
1326    yylval.simple = 0;
1327    if (!backslashed)                   /* Backslash means not keyword */
1328        {
1329        for (kwptr = keywords;  kwptr->kw != NULL;  kwptr++)
1330            {
1331            if (strcmp (kwptr->kw, (char *) str) == 0)
1332                return (yylval.simple = kwptr->val);
1333            }
1334        }
1335    yylval.string =
1336      (unsigned char *) malloc ((unsigned) strlen ((char *) str) + 1);
1337    if (yylval.string == NULL)
1338        {
1339        yyerror (PARSE_Y_NO_SPACE);
1340        exit (1);
1341        }
1342    (void) strcpy ((char *) yylval.string, (char *) str);
1343#ifdef NO8BIT
1344    while (*str != '\0')
1345        {
1346        if (*str++ & 0x80)
1347            yyerror (PARSE_Y_8_BIT);
1348        }
1349#endif /* NO8BIT */
1350    return STRING;
1351    }
1352
1353/*
1354 * Analyze a string in double quotes.  The leading quote has already
1355 * been processed.
1356 */
1357static void getqstring ()
1358    {
1359    register int        ch;             /* Next character read */
1360    char                lexstring[256]; /* Room to collect the string */
1361    register char *     lexp;           /* Pointer into lexstring */
1362
1363    for (lexp = lexstring;
1364      (ch = grabchar ()) != EOF  &&  ch != '"'
1365        &&  lexp < &lexstring[sizeof lexstring - 1];
1366      )
1367        {
1368        if (ch == '\\')
1369            ch = backch ();
1370        *lexp++ = (char) ch;
1371        }
1372    *lexp++ = '\0';
1373    if (ch == EOF)
1374        yyerror (PARSE_Y_EOF);
1375    else if (ch != '"')
1376        {
1377        yyerror (PARSE_Y_LONG_QUOTE);
1378        while ((ch = grabchar ()) != EOF  &&  ch != '"')
1379            {
1380            if (ch == '\\')
1381                ch = backch ();
1382            }
1383        }
1384    yylval.string = (unsigned char *) malloc ((unsigned) (lexp - lexstring));
1385    if (yylval.string == NULL)
1386        {
1387        yyerror (PARSE_Y_NO_SPACE);
1388        exit (1);
1389        }
1390    (void) strcpy ((char *) yylval.string, lexstring);
1391#ifdef NO8BIT
1392    for (lexp = lexstring;  *lexp != '\0';  )
1393        {
1394        if (*lexp++ & 0x80)
1395            yyerror (PARSE_Y_8_BIT);
1396        }
1397#endif /* NO8BIT */
1398    }
1399
1400/*
1401 * Analyze a range (e.g., [A-Za-z]).  The left square bracket
1402 * has already been processed.
1403 */
1404static void getrange ()                 /* Parse a range set */
1405    {
1406    register int        ch;             /* Next character read */
1407    register int        lastch;         /* Previous char, for ranges */
1408    char                stringch[MAXSTRINGCHARLEN];
1409    int                 stringchlen;
1410
1411    yylval.charset.set = malloc (SET_SIZE + MAXSTRINGCHARS);
1412    if (yylval.charset.set == NULL)
1413        {
1414        yyerror (PARSE_Y_NO_SPACE);
1415        exit (1);
1416        }
1417
1418    /* Start with a null set */
1419    (void) bzero (yylval.charset.set, SET_SIZE + MAXSTRINGCHARS);
1420    yylval.charset.complement = 0;
1421
1422    lastch = -1;
1423    ch = grabchar ();
1424    if (ch == '^')
1425        {
1426        yylval.charset.complement = 1;
1427        ch = grabchar ();
1428        }
1429    /* [ */
1430    if (ch == ']')
1431        {
1432        /* [[ */
1433        lastch = ']';
1434        yylval.charset.set[']'] = 1;
1435        }
1436    else
1437        ungrabchar (ch);
1438    /* [ */
1439    while ((ch = grabchar ()) != EOF  &&  ch != ']')
1440        {
1441        if (isstringstart (ch))         /* Handle a possible string character */
1442            {
1443            stringch[0] = (char) ch;
1444            for (stringchlen = 1;
1445              stringchlen < MAXSTRINGCHARLEN;
1446              stringchlen++)
1447                {
1448                stringch[stringchlen] = '\0';
1449                if (isstringch (stringch, 1))
1450                    {
1451                    yylval.charset.set[SET_SIZE + laststringch] = 1;
1452                    stringchlen = 0;
1453                    break;
1454                    }
1455                ch = grabchar ();
1456                if (ch == EOF)
1457                    break;
1458                else
1459                    stringch[stringchlen] = (char) ch;
1460                }
1461            if (stringchlen == 0)
1462                {
1463                lastch = -1;            /* String characters can't be ranges */
1464                continue;               /* We found a string character */
1465                }
1466            /*
1467             * Not a string character - put it back
1468             */
1469            while (--stringchlen > 0)
1470                ungrabchar (stringch[stringchlen] & 0xFF);
1471            ch = stringch[0] & 0xFF;
1472            }
1473        if (ch == '\\')
1474            {
1475            lastch = ch = backch ();
1476            yylval.charset.set[ch] = 1;
1477            continue;
1478            }
1479#ifdef NO8BIT
1480        if (ch & 0x80)
1481            {
1482            yyerror (PARSE_Y_8_BIT);
1483            ch &= 0x7F;
1484            }
1485#endif /* NO8BIT */
1486        if (ch == '-')                  /* Handle a range */
1487            {
1488            if (lastch == -1)
1489                {
1490                lastch = ch = '-';      /* Not really a range */
1491                yylval.charset.set['-'] = 1;
1492                }
1493            else
1494                {
1495                ch = grabchar ();
1496                /* [ */
1497                if (ch == EOF  ||  ch == ']')
1498                    {
1499                    lastch = ch = '-';  /* Not really range */
1500                    yylval.charset.set['-'] = 1;
1501                    if (ch != EOF)
1502                        ungrabchar (ch);
1503                    }
1504                else
1505                    {
1506#ifdef NO8BIT
1507                    if (ch & 0x80)
1508                        {
1509                        yyerror (PARSE_Y_8_BIT);
1510                        ch &= 0x7F;
1511                        }
1512#endif /* NO8BIT */
1513                    if (ch == '\\')
1514                        ch = backch ();
1515                    while (lastch <= ch)
1516                        yylval.charset.set[lastch++] = 1;
1517                    lastch = -1;
1518                    }
1519                }
1520            }
1521        else
1522            {
1523            lastch = ch;
1524            yylval.charset.set[ch] = 1;
1525            }
1526        }
1527    if (yylval.charset.complement)
1528        {
1529        for (ch = 0;  ch < SET_SIZE + MAXSTRINGCHARS;  ch++)
1530            yylval.charset.set[ch] = !yylval.charset.set[ch];
1531        }
1532    }
1533
1534static int backch ()                    /* Process post-backslash characters */
1535    {
1536    register int        ch;             /* Next character read */
1537    register int        octval;         /* Budding octal value */
1538
1539    ch = grabchar ();
1540    if (ch == EOF)
1541        return '\\';
1542    else if (ch >= '0'  &&  ch <= '7')
1543        {
1544        octval = ch - '0';
1545        ch = grabchar ();
1546        if (ch >= '0'  &&  ch <= '7')
1547            {
1548            octval = (octval << 3) + ch - '0';
1549            ch = grabchar ();
1550            if (ch >= '0'  &&  ch <= '7')
1551                octval = (octval << 3) + ch - '0';
1552            else
1553                ungrabchar (ch);
1554            }
1555        else if (ch != EOF)
1556            ungrabchar (ch);
1557        ch = octval;
1558        }
1559    else if (ch == 'x')
1560        {
1561        ch = grabchar ();
1562        octval = 0;
1563        if ((ch >= '0'  &&  ch <= '9')
1564          ||  (ch >= 'a'  &&  ch <= 'f')
1565          ||  (ch >= 'A'  &&  ch <= 'F'))
1566            {
1567            if (ch >= '0'  &&  ch <= '9')
1568                octval = ch - '0';
1569            else if (ch >= 'a'  &&  ch <= 'f')
1570                octval = ch - 'a' + 0xA;
1571            else if (ch >= 'A'  &&  ch <= 'F')
1572                octval = ch - 'A' + 0xA;
1573            ch = grabchar ();
1574            octval <<= 4;
1575            if (ch >= '0'  &&  ch <= '9')
1576                octval |= ch -'0';
1577            else if (ch >= 'a'  &&  ch <= 'f')
1578                octval |= ch - 'a' + 0xA;
1579            else if (ch >= 'A'  &&  ch <= 'F')
1580                octval |= ch - 'A' + 0xA;
1581            else if (ch != EOF)
1582                {
1583                octval >>= 4;
1584                ungrabchar (ch);
1585                }
1586            }
1587        else if (ch != EOF)
1588            ungrabchar (ch);
1589        ch = octval;
1590        }
1591    else
1592        {
1593        switch (ch)
1594            {
1595            case 'n':
1596                ch = '\n';
1597                break;
1598            case 'f':
1599                ch = '\f';
1600                break;
1601            case 'r':
1602                ch = '\r';
1603                break;
1604            case 'b':
1605                ch = '\b';
1606                break;
1607            case 't':
1608                ch = '\t';
1609                break;
1610            case 'v':
1611                ch = '\v';
1612                break;
1613            }
1614        }
1615#ifdef NO8BIT
1616    if (ch & 0x80)
1617        {
1618        yyerror (PARSE_Y_8_BIT);
1619        ch &= 0x7F;
1620        }
1621#endif /* NO8BIT */
1622    return ch;
1623    }
1624
1625static void yyerror (str)
1626    char *              str;    /* Error string */
1627    {
1628    (void) fflush (stdout);
1629    (void) fprintf (stderr, PARSE_Y_ERROR_FORMAT(fname, lineno, str));
1630    (void) fflush (stderr);
1631    }
1632
1633int yyopen (file)
1634    register char *     file;   /* File name to be opened */
1635    {
1636    fname = malloc ((unsigned) strlen (file) + 1);
1637    if (fname == NULL)
1638        {
1639        (void) fprintf (stderr, PARSE_Y_MALLOC_TROUBLE);
1640        exit (1);
1641        }
1642    (void) strcpy (fname, file);
1643    aff_file = fopen (file, "r");
1644    if (aff_file == NULL)
1645        {
1646        (void) fprintf (stderr, CANT_OPEN, file);
1647        perror ("");
1648        return 1;
1649        }
1650    lineno = 1;
1651    return 0;
1652    }
1653
1654void yyinit ()
1655    {
1656    register unsigned int i;    /* Loop counter */
1657
1658    if (aff_file == NULL)
1659        aff_file = stdin;       /* Must be dynamically initialized on Amigas */
1660    for (i = 0;  i < SET_SIZE + MAXSTRINGCHARS;  i++)
1661        {
1662        hashheader.lowerconv[i] = (ichar_t) i;
1663        hashheader.upperconv[i] = (ichar_t) i;
1664        hashheader.wordchars[i] = 0;
1665        hashheader.lowerchars[i] = 0;
1666        hashheader.upperchars[i] = 0;
1667        hashheader.boundarychars[i] = 0;
1668        /*
1669         * The default sort order is a big value so that there is room
1670         * to insert "underneath" it.  In this way, special characters
1671         * will sort last, but in ASCII order.
1672         */
1673        hashheader.sortorder[i] = i + 1 + 2 * SET_SIZE;
1674        }
1675    for (i = 0;  i < SET_SIZE;  i++)
1676        hashheader.stringstarts[i] = 0;
1677    for (i = 0;  i < MAXSTRINGCHARS;  i++)
1678        {
1679        hashheader.stringdups[i] = i;
1680        hashheader.dupnos[i] = 0;
1681        }
1682   
1683    hashheader.sortval = 1;     /* This is so 0 can mean uninitialized */
1684    (void) bcopy (NRSPECIAL, hashheader.nrchars, sizeof hashheader.nrchars);
1685    (void) bcopy (TEXSPECIAL, hashheader.texchars, sizeof hashheader.texchars);
1686    hashheader.compoundflag = COMPOUND_NEVER; /* Dflt is report missing blks */
1687    hashheader.defhardflag = 0; /* Default is to try hard only if failures */
1688    hashheader.nstrchars = 0;   /* No string characters to start with */
1689    hashheader.flagmarker = '/'; /* Default flag marker is slash */
1690    hashheader.compoundmin = 3; /* Dflt is at least 3 chars in cmpnd parts */
1691    hashheader.compoundbit = -1; /* Dflt is no compound bit */
1692    /* Set up magic numbers and compile options */
1693    hashheader.magic = hashheader.magic2 = MAGIC;
1694    hashheader.compileoptions = COMPILEOPTIONS;
1695    hashheader.maxstringchars = MAXSTRINGCHARS;
1696    hashheader.maxstringcharlen = MAXSTRINGCHARLEN;
1697    }
1698
1699static int grabchar ()          /* Get a character and count lines */
1700    {
1701    int                 ch;     /* Next input character */
1702
1703    if (ungrablen > 0)
1704        ch = lexungrab[--ungrablen] & 0xFF;
1705    else
1706        ch = getc (aff_file);
1707    if (ch == '\n')
1708        lineno++;
1709    return ch;
1710    }
1711
1712static void ungrabchar (ch)     /* Unget a character, tracking line numbers */
1713    int                 ch;     /* Character to put back */
1714    {
1715
1716    if (ch == '\n')
1717        lineno--;
1718    if (ch != EOF)
1719        {
1720        if (ungrablen == sizeof (lexungrab))
1721            yyerror (PARSE_Y_UNGRAB_PROBLEM);
1722        else
1723            lexungrab[ungrablen++] = (char) ch;
1724        }
1725    }
1726
1727static int sufcmp (flag1, flag2)        /* Compare suffix flags for qsort */
1728    register struct flagent *   flag1;  /* Flags to be compared */
1729    register struct flagent *   flag2;  /* ... */
1730    {
1731    register ichar_t *          cp1;    /* Pointer into flag1's suffix */
1732    register ichar_t *          cp2;    /* Pointer into flag2's suffix */
1733
1734    if (flag1->affl == 0  ||  flag2->affl == 0)
1735        return flag1->affl - flag2->affl;
1736    cp1 = flag1->affix + flag1->affl;
1737    cp2 = flag2->affix + flag2->affl;
1738    while (*--cp1 == *--cp2  &&  cp1 > flag1->affix  &&  cp2 > flag2->affix)
1739        ;
1740    if (*cp1 == *cp2)
1741        {
1742        if (cp1 == flag1->affix)
1743            {
1744            if (cp2 == flag2->affix)
1745                return 0;
1746            else
1747                return -1;
1748            }
1749        else
1750            return 1;
1751        }
1752    return *cp1 - *cp2;
1753    }
1754
1755static int precmp (flag1, flag2)        /* Compare prefix flags for qsort */
1756    register struct flagent *   flag1;  /* Flags to be compared */
1757    register struct flagent *   flag2;  /* ... */
1758    {
1759
1760    if (flag1->affl == 0  ||  flag2->affl == 0)
1761        return flag1->affl - flag2->affl;
1762    else
1763        return icharcmp (flag1->affix, flag2->affix);
1764    }
1765
1766static int addstringchar (str, lower, upper) /* Add a string character */
1767    register unsigned char *    str;    /* String character to be added */
1768    int                         lower;  /* NZ if a lower string */
1769    int                         upper;  /* NZ if an upper string */
1770    {
1771    int                         len;    /* Length of the string */
1772    register unsigned int       mslot;  /* Slot being moved or modified */
1773    register unsigned int       slot;   /* Where to put it */
1774
1775    len = strlen ((char *) str);
1776    if (len > MAXSTRINGCHARLEN)
1777        {
1778        yyerror (PARSE_Y_LONG_STRING);
1779        }
1780    else if (len == 0)
1781        {
1782        yyerror (PARSE_Y_NULL_STRING);
1783        return -1;
1784        }
1785    else if (hashheader.nstrchars >= MAXSTRINGCHARS)
1786        {
1787        yyerror (PARSE_Y_MANY_STRINGS);
1788        return -1;
1789        }
1790
1791    /*
1792     * Find where to put the new character
1793     */
1794    for (slot = 0;  slot < hashheader.nstrchars;  slot++)
1795        {
1796        if (stringcharcmp (&hashheader.stringchars[slot][0], (char *) str) > 0)
1797            break;
1798        }
1799    /*
1800     * Fix all duplicate numbers to reflect the new slot.
1801     */
1802    for (mslot = 0;  mslot < hashheader.nstrchars;  mslot++)
1803        {
1804        if (hashheader.stringdups[mslot] >= slot)
1805            hashheader.stringdups[mslot]++;
1806        }
1807    /*
1808     * Fix all characters before it so that their case conversion reflects
1809     * the new locations of the characters that will follow the new one.
1810     */
1811    slot += SET_SIZE;
1812    for (mslot = SET_SIZE;  mslot < slot;  mslot++)
1813        {
1814        if (hashheader.lowerconv[mslot] >= (ichar_t) slot)
1815            hashheader.lowerconv[mslot]++;
1816        if (hashheader.upperconv[mslot] >= (ichar_t) slot)
1817            hashheader.upperconv[mslot]++;
1818        }
1819    /*
1820     * Slide up all the other characters to make room for the new one, also
1821     * making the appropriate changes in the case-conversion tables.
1822     */
1823    for (mslot = hashheader.nstrchars + SET_SIZE;  --mslot >= slot;  )
1824        {
1825        (void) strcpy (&hashheader.stringchars[mslot + 1 - SET_SIZE][0],
1826          &hashheader.stringchars[mslot - SET_SIZE][0]);
1827        hashheader.lowerchars[mslot + 1] = hashheader.lowerchars[mslot];
1828        hashheader.upperchars[mslot + 1] = hashheader.upperchars[mslot];
1829        hashheader.wordchars[mslot + 1] = hashheader.wordchars[mslot];
1830        hashheader.boundarychars[mslot + 1] = hashheader.boundarychars[mslot];
1831        if (hashheader.lowerconv[mslot] >= (ichar_t) slot)
1832            hashheader.lowerconv[mslot]++;
1833        if (hashheader.upperconv[mslot] >= (ichar_t) slot)
1834            hashheader.upperconv[mslot]++;
1835        hashheader.lowerconv[mslot + 1] = hashheader.lowerconv[mslot];
1836        hashheader.upperconv[mslot + 1] = hashheader.upperconv[mslot];
1837        hashheader.sortorder[mslot + 1] = hashheader.sortorder[mslot];
1838        hashheader.stringdups[mslot + 1 - SET_SIZE] =
1839          hashheader.stringdups[mslot - SET_SIZE];
1840        hashheader.dupnos[mslot + 1 - SET_SIZE] =
1841          hashheader.dupnos[mslot - SET_SIZE];
1842        }
1843    /*
1844     * Insert the new string character into the slot we made.  The
1845     * caller may choose to change the case-conversion field.
1846     */
1847    (void) strcpy (&hashheader.stringchars[slot - SET_SIZE][0], (char *) str);
1848    hashheader.lowerchars[slot] = (char) lower;
1849    hashheader.upperchars[slot] = (char) upper;
1850    hashheader.wordchars[slot] = 1;
1851    hashheader.boundarychars[slot] = 0;
1852    hashheader.sortorder[slot] = hashheader.sortval++;
1853    hashheader.lowerconv[slot] = (ichar_t) slot;
1854    hashheader.upperconv[slot] = (ichar_t) slot;
1855    hashheader.stringdups[slot - SET_SIZE] = slot - SET_SIZE;
1856    hashheader.dupnos[slot - SET_SIZE] = 0;
1857    /*
1858     * Add the first character of the string to the string-starts table, and
1859     * bump the count.
1860     */
1861    hashheader.stringstarts[str[0]] = 1;
1862    hashheader.nstrchars++;
1863    return slot;
1864    }
1865
1866/*
1867 * This routine is a reimplemention of strcmp(), needed because the
1868 * idiots at Sun managed to screw up the implementation of strcmp on
1869 * Sun 4's (they used unsigned comparisons, even though characters
1870 * default to signed).  I hate hate HATE putting in this routine just
1871 * to support the stupidity of one programmer who ought to find a new
1872 * career digging ditches, but there are a lot of Sun 4's out there,
1873 * so I don't really have a lot of choice.
1874 */
1875static int stringcharcmp (a,  b)
1876    register char *             a;
1877    register char *             b;
1878    {
1879
1880#ifdef NO8BIT
1881    while (*a != '\0')
1882        {
1883        if (((*a++ ^ *b++) & NOPARITY) != 0)
1884            return (*--a & NOPARITY) - (*--b & NOPARITY);
1885        }
1886    return (*a & NOPARITY) - (*b & NOPARITY);
1887#else /* NO8BIT */
1888    while (*a != '\0')
1889        {
1890        if (*a++ != *b++)
1891            return *--a - *--b;
1892        }
1893    return *a - *b;
1894#endif /* NO8BIT */
1895    }
1896
1897#ifdef TBLDEBUG
1898static void tbldump (flagp, numflags)   /* Dump a flag table */
1899    register struct flagent *   flagp;  /* First flag entry to dump */
1900    register int                numflags; /* Number of flags to dump */
1901    {
1902    while (--numflags >= 0)
1903        entdump (flagp++);
1904    }
1905
1906static void entdump (flagp)             /* Dump one flag entry */
1907    register struct flagent *   flagp;  /* Flag entry to dump */
1908    {
1909    register int                cond;   /* Condition number */
1910
1911    (void) fprintf (stderr, "flag %s%c:\t",
1912      (flagp->flagflags & FF_CROSSPRODUCT) ? "*" : "",
1913      BITTOCHAR (flagp->flagbit));
1914    for (cond = 0;  cond < flagp->numconds;  cond++)
1915        {
1916        setdump (flagp->conds, 1 << cond);
1917        if (cond < flagp->numconds - 1)
1918            (void) putc (' ', stderr);
1919        }
1920    if (cond == 0)                      /* No conditions at all? */
1921        (void) putc ('.', stderr);
1922    (void) fprintf (stderr, "\t> ");
1923    (void) putc ('\t', stderr);
1924    if (flagp->stripl)
1925        (void) fprintf (stderr, "-%s,", ichartosstr (flagp->strip, 1));
1926    (void) fprintf (stderr, "%s\n",
1927      flagp->affl ? ichartosstr (flagp->affix, 1) : "-");
1928    }
1929
1930static void setdump (setp, mask)        /* Dump a set specification */
1931    register char *             setp;   /* Set to be dumped */
1932    register int                mask;   /* Mask for bit to be dumped */
1933    {
1934    register int                cnum;   /* Next character's number */
1935    register int                firstnz; /* Number of first NZ character */
1936    register int                numnz;  /* Number of NZ characters */
1937
1938    numnz = 0;
1939    for (cnum = SET_SIZE + hashheader.nstrchars;  --cnum >= 0;  )
1940        {
1941        if (setp[cnum] & mask)
1942            {
1943            numnz++;
1944            firstnz = cnum;
1945            }
1946        }
1947    if (numnz == 1)
1948        {
1949        if (cnum < SET_SIZE)
1950            (void) putc (firstnz, stderr);
1951        else
1952            (void) fputs (hashheader.stringchars[cnum - SET_SIZE], stderr);
1953        }
1954    else if (numnz == SET_SIZE)
1955        (void) putc ('.', stderr);
1956    else if (numnz > SET_SIZE / 2)
1957        {
1958        (void) fprintf (stderr, "[^");
1959        subsetdump (setp, mask, 0);
1960        (void) putc (']', stderr);
1961        }
1962    else
1963        {
1964        (void) putc ('[', stderr);
1965        subsetdump (setp, mask, mask);
1966        (void) putc (']', stderr);
1967        }
1968    }
1969
1970static void subsetdump (setp, mask, dumpval) /* Dump part of a set spec */
1971    register char *             setp;   /* Set to be dumped */
1972    register int                mask;   /* Mask for bit to be dumped */
1973    register int                dumpval; /* Value to be printed */
1974    {
1975    register int                cnum;   /* Next character's number */
1976    register int                rangestart; /* Value starting a range */
1977
1978    for (cnum = 0;  cnum < SET_SIZE;  setp++, cnum++)
1979        {
1980        if (((*setp ^ dumpval) & mask) == 0)
1981            {
1982            for (rangestart = cnum;  cnum < SET_SIZE;  setp++, cnum++)
1983                {
1984                if ((*setp ^ dumpval) & mask)
1985                    break;
1986                }
1987            if (cnum == rangestart + 1)
1988                (void) putc (rangestart, stderr);
1989            else if (cnum <= rangestart + 3)
1990                {
1991                while (rangestart < cnum)
1992                    {
1993                    (void) putc (rangestart, stderr);
1994                    rangestart++;
1995                    }
1996                }
1997            else
1998                (void) fprintf (stderr, "%c-%c", rangestart, cnum - 1);
1999            }
2000        }
2001    for (  ;  cnum < SET_SIZE + hashheader.nstrchars;  setp++, cnum++)
2002        {
2003        if (((*setp ^ dumpval) & mask) == 0)
2004            (void) fputs (hashheader.stringchars[cnum - SET_SIZE], stderr);
2005        }
2006    }
2007#endif
Note: See TracBrowser for help on using the repository browser.