1 /*        $NetBSD: parse.c,v 1.18 2021/05/02 12:50:43 rillig Exp $    */
2 
3 /*
4  * Copyright (c) 1983, 1993
5  *        The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)parse.c     8.2 (Berkeley) 4/28/95";
36 #else
37 __RCSID("$NetBSD: parse.c,v 1.18 2021/05/02 12:50:43 rillig Exp $");
38 #endif
39 #endif                                  /* not lint */
40 
41 #include "extern.h"
42 
43 #define HASHSIZE    256
44 #define HASHMUL               81
45 #define HASHMASK    (HASHSIZE - 1)
46 
47 static int hash(const char *);
48 static void install(struct wlist *);
49 static struct wlist *lookup(const char *);
50 
51 static struct wlist *hashtab[HASHSIZE];
52 
53 void
wordinit(void)54 wordinit(void)
55 {
56           struct wlist *w;
57 
58           for (w = wlist; w->string; w++)
59                     install(w);
60 }
61 
62 static int
hash(const char * s)63 hash(const char *s)
64 {
65           int     hashval = 0;
66 
67           while (*s) {
68                     hashval += *s++;
69                     hashval *= HASHMUL;
70                     hashval &= HASHMASK;
71           }
72           return hashval;
73 }
74 
75 static struct wlist *
lookup(const char * s)76 lookup(const char   *s)
77 {
78           struct wlist *wp;
79 
80           for (wp = hashtab[hash(s)]; wp != NULL; wp = wp->next)
81                     if (*s == *wp->string && strcmp(s, wp->string) == 0)
82                               return wp;
83           return NULL;
84 }
85 
86 static void
install(struct wlist * wp)87 install(struct wlist *wp)
88 {
89           int     hashval;
90 
91           if (lookup(wp->string) == NULL) {
92                     hashval = hash(wp->string);
93                     wp->next = hashtab[hashval];
94                     hashtab[hashval] = wp;
95           } else
96                     printf("Multiply defined %s.\n", wp->string);
97 }
98 
99 void
parse(void)100 parse(void)
101 {
102           struct wlist *wp;
103           int     n;
104           int     flag;
105 
106           wordnumber = 0;               /* for cypher */
107           for (n = 0; n <= wordcount; n++) {
108                     if ((wp = lookup(words[n])) == NULL) {
109                               wordvalue[n] = -1;
110                               wordtype[n] = -1;
111                     } else {
112                               wordvalue[n] = wp->value;
113                               wordtype[n] = wp->article;
114                     }
115           }
116           /* We never use adjectives for anything, so yank them all. */
117           for (n = 1; n < wordcount; n++)
118                     if (wordtype[n] == ADJS) {
119                               int i;
120                               for (i = n + 1; i < wordcount; i++) {
121                                         wordtype[i - 1] = wordtype[i];
122                                         wordvalue[i - 1] = wordvalue[i];
123                                         strlcpy(words[i - 1], words[i], WORDLEN);
124                               }
125                               wordcount--;
126                     }
127           /* Don't let a comma mean AND if followed by a verb. */
128           for (n = 0; n < wordcount; n++)
129                     if (wordvalue[n] == AND && words[n][0] == ','
130                         && wordtype[n + 1] == VERB) {
131                               wordvalue[n] = -1;
132                               wordtype[n] = -1;
133                     }
134           /* Trim "AND AND" which can happen naturally at the end of a
135            * comma-delimited list.
136            */
137           for (n = 1; n < wordcount; n++)
138                     if (wordvalue[n - 1] == AND && wordvalue[n] == AND) {
139                               int i;
140                               for (i = n + 1; i < wordcount; i++) {
141                                         wordtype[i - 1] = wordtype[i];
142                                         wordvalue[i - 1] = wordvalue[i];
143                                         strlcpy(words[i - 1], words[i], WORDLEN);
144                               }
145                               wordcount--;
146                     }
147 
148           /* If there is a sequence (NOUN | OBJECT) AND EVERYTHING
149            * then move all the EVERYTHINGs to the beginning, since that's where
150            * they're expected.  We can't get rid of the NOUNs and OBJECTs in
151            * case they aren't in EVERYTHING (i.e. not here or nonexistent).
152            */
153           flag = 1;
154           while (flag) {
155                     flag = 0;
156                     for (n = 1; n < wordcount; n++)
157                               if ((wordtype[n - 1] == NOUNS ||
158                                   wordtype[n - 1] == OBJECT) &&
159                                   wordvalue[n] == AND &&
160                                   wordvalue[n + 1] == EVERYTHING) {
161                                         char tmpword[WORDLEN];
162                                         wordvalue[n + 1] = wordvalue[n - 1];
163                                         wordvalue[n - 1] = EVERYTHING;
164                                         wordtype[n + 1] = wordtype[n - 1];
165                                         wordtype[n - 1] = OBJECT;
166                                         strcpy(tmpword, words[n - 1]);
167                                         strlcpy(words[n - 1], words[n + 1], WORDLEN);
168                                         strcpy(words[n + 1], tmpword);
169                                         flag = 1;
170                     }
171                     /* And trim EVERYTHING AND EVERYTHING. */
172                     for (n = 1; n < wordcount; n++)
173                               if (wordvalue[n - 1] == EVERYTHING &&
174                                   wordvalue[n] == AND &&
175                                   wordvalue[n + 1] == EVERYTHING) {
176                                         int i;
177                                         for (i = n + 1; i < wordcount; i++) {
178                                                   wordtype[i - 1] = wordtype[i + 1];
179                                                   wordvalue[i - 1] = wordvalue[i + 1];
180                                                   strlcpy(words[i - 1], words[i + 1], WORDLEN);
181                                         }
182                                         wordcount--;
183                                         wordcount--;
184                                         flag = 1;
185                               }
186           }
187 }
188