parse.y revision 293290
1%{
2/*-
3 * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
4 *		at Electronni Visti IA, Kiev, Ukraine.
5 *			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 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/10/usr.bin/colldef/parse.y 293290 2016-01-07 00:40:51Z bdrewery $");
31
32#include <sys/types.h>
33#include <arpa/inet.h>
34#include <err.h>
35#include <stdarg.h>
36#include <stdio.h>
37#include <string.h>
38#include <unistd.h>
39#include <sysexits.h>
40#include "collate.h"
41#include "common.h"
42
43extern FILE *yyin;
44void yyerror(const char *fmt, ...) __printflike(1, 2);
45int yyparse(void);
46int yylex(void);
47static void usage(void);
48static void collate_print_tables(void);
49
50char map_name[FILENAME_MAX] = ".";
51char curr_chain[STR_LEN];
52
53char __collate_version[STR_LEN];
54u_char charmap_table[UCHAR_MAX + 1][CHARMAP_SYMBOL_LEN];
55
56#undef __collate_substitute_table
57u_char __collate_substitute_table[UCHAR_MAX + 1][STR_LEN];
58#undef __collate_char_pri_table
59struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1];
60struct __collate_st_chain_pri *__collate_chain_pri_table;
61
62int chain_index = 0;
63int prim_pri = 1, sec_pri = 1;
64#ifdef COLLATE_DEBUG
65int debug;
66#endif
67
68const char *out_file = "LC_COLLATE";
69%}
70%union {
71	u_char ch;
72	u_char str[BUFSIZE];
73}
74%token SUBSTITUTE WITH ORDER RANGE
75%token <str> STRING
76%token <str> DEFN
77%token <ch> CHAR
78%%
79collate : statment_list
80;
81statment_list : statment
82	| statment_list '\n' statment
83;
84statment :
85	| charmap
86	| substitute
87	| order
88;
89charmap : DEFN CHAR {
90	if (strlen($1) + 1 > CHARMAP_SYMBOL_LEN)
91		yyerror("Charmap symbol name '%s' is too long", $1);
92	strcpy(charmap_table[$2], $1);
93}
94;
95substitute : SUBSTITUTE CHAR WITH STRING {
96	if ($2 == '\0')
97		yyerror("NUL character can't be substituted");
98	if (strchr($4, $2) != NULL)
99		yyerror("Char 0x%02x substitution is recursive", $2);
100	if (strlen($4) + 1 > STR_LEN)
101		yyerror("Char 0x%02x substitution is too long", $2);
102	strcpy(__collate_substitute_table[$2], $4);
103}
104;
105order : ORDER order_list {
106	FILE *fp;
107	int ch, substed, ordered;
108	uint32_t u32;
109
110	for (ch = 0; ch < UCHAR_MAX + 1; ch++) {
111		substed = (__collate_substitute_table[ch][0] != ch);
112		ordered = !!__collate_char_pri_table[ch].prim;
113		if (!ordered && !substed)
114			yyerror("Char 0x%02x not found", ch);
115		if (substed && ordered)
116			yyerror("Char 0x%02x can't be ordered since substituted", ch);
117	}
118
119	if ((__collate_chain_pri_table = realloc(__collate_chain_pri_table,
120	     sizeof(*__collate_chain_pri_table) * (chain_index + 1))) == NULL)
121		yyerror("can't grow chain table");
122	(void)memset(&__collate_chain_pri_table[chain_index], 0,
123		     sizeof(__collate_chain_pri_table[0]));
124	chain_index++;
125
126#ifdef COLLATE_DEBUG
127	if (debug)
128		collate_print_tables();
129#endif
130	if ((fp = fopen(out_file, "w")) == NULL)
131		err(EX_UNAVAILABLE, "can't open destination file %s",
132		    out_file);
133
134	strcpy(__collate_version, COLLATE_VERSION1_2);
135	if (fwrite(__collate_version, sizeof(__collate_version), 1, fp) != 1)
136		err(EX_IOERR,
137		"I/O error writing collate version to destination file %s",
138		    out_file);
139	u32 = htonl(chain_index);
140	if (fwrite(&u32, sizeof(u32), 1, fp) != 1)
141		err(EX_IOERR,
142		"I/O error writing chains number to destination file %s",
143		    out_file);
144	if (fwrite(__collate_substitute_table,
145		   sizeof(__collate_substitute_table), 1, fp) != 1)
146		err(EX_IOERR,
147		"I/O error writing substitution table to destination file %s",
148		    out_file);
149	for (ch = 0; ch < UCHAR_MAX + 1; ch++) {
150		__collate_char_pri_table[ch].prim =
151		    htonl(__collate_char_pri_table[ch].prim);
152		__collate_char_pri_table[ch].sec =
153		    htonl(__collate_char_pri_table[ch].sec);
154	}
155	if (fwrite(__collate_char_pri_table,
156		   sizeof(__collate_char_pri_table), 1, fp) != 1)
157		err(EX_IOERR,
158		"I/O error writing char table to destination file %s",
159		    out_file);
160	for (ch = 0; ch < chain_index; ch++) {
161		__collate_chain_pri_table[ch].prim =
162		    htonl(__collate_chain_pri_table[ch].prim);
163		__collate_chain_pri_table[ch].sec =
164		    htonl(__collate_chain_pri_table[ch].sec);
165	}
166	if (fwrite(__collate_chain_pri_table,
167		   sizeof(*__collate_chain_pri_table), chain_index, fp) !=
168		   (size_t)chain_index)
169		err(EX_IOERR,
170		"I/O error writing chain table to destination file %s",
171		    out_file);
172	if (fclose(fp) != 0)
173		err(EX_IOERR, "I/O error closing destination file %s",
174		    out_file);
175	exit(EX_OK);
176}
177;
178order_list : item
179	| order_list ';' item
180;
181chain : CHAR CHAR {
182	curr_chain[0] = $1;
183	curr_chain[1] = $2;
184	if (curr_chain[0] == '\0' || curr_chain[1] == '\0')
185		yyerror("\\0 can't be chained");
186	curr_chain[2] = '\0';
187}
188	| chain CHAR {
189	static char tb[2];
190
191	tb[0] = $2;
192	if (tb[0] == '\0')
193		yyerror("\\0 can't be chained");
194	if (strlen(curr_chain) + 2 > STR_LEN)
195		yyerror("Chain '%s' grows too long", curr_chain);
196	(void)strcat(curr_chain, tb);
197}
198;
199item :  CHAR {
200	if (__collate_char_pri_table[$1].prim)
201		yyerror("Char 0x%02x duplicated", $1);
202	__collate_char_pri_table[$1].prim = prim_pri++;
203}
204	| chain {
205	if ((__collate_chain_pri_table = realloc(__collate_chain_pri_table,
206	     sizeof(*__collate_chain_pri_table) * (chain_index + 1))) == NULL)
207		yyerror("can't grow chain table");
208	(void)memset(&__collate_chain_pri_table[chain_index], 0,
209		     sizeof(__collate_chain_pri_table[0]));
210	(void)strcpy(__collate_chain_pri_table[chain_index].str, curr_chain);
211	__collate_chain_pri_table[chain_index].prim = prim_pri++;
212	chain_index++;
213}
214	| CHAR RANGE CHAR {
215	u_int i;
216
217	if ($3 <= $1)
218		yyerror("Illegal range 0x%02x -- 0x%02x", $1, $3);
219
220	for (i = $1; i <= $3; i++) {
221		if (__collate_char_pri_table[(u_char)i].prim)
222			yyerror("Char 0x%02x duplicated", (u_char)i);
223		__collate_char_pri_table[(u_char)i].prim = prim_pri++;
224	}
225}
226	| '{' prim_order_list '}' {
227	prim_pri++;
228}
229	| '(' sec_order_list ')' {
230	prim_pri++;
231	sec_pri = 1;
232}
233;
234prim_order_list : prim_sub_item
235	| prim_order_list ',' prim_sub_item
236;
237sec_order_list : sec_sub_item
238	| sec_order_list ',' sec_sub_item
239;
240prim_sub_item : CHAR {
241	if (__collate_char_pri_table[$1].prim)
242		yyerror("Char 0x%02x duplicated", $1);
243	__collate_char_pri_table[$1].prim = prim_pri;
244}
245	| CHAR RANGE CHAR {
246	u_int i;
247
248	if ($3 <= $1)
249		yyerror("Illegal range 0x%02x -- 0x%02x",
250			$1, $3);
251
252	for (i = $1; i <= $3; i++) {
253		if (__collate_char_pri_table[(u_char)i].prim)
254			yyerror("Char 0x%02x duplicated", (u_char)i);
255		__collate_char_pri_table[(u_char)i].prim = prim_pri;
256	}
257}
258	| chain {
259	if ((__collate_chain_pri_table = realloc(__collate_chain_pri_table,
260	     sizeof(*__collate_chain_pri_table) * (chain_index + 1))) == NULL)
261		yyerror("can't grow chain table");
262	(void)memset(&__collate_chain_pri_table[chain_index], 0,
263		     sizeof(__collate_chain_pri_table[0]));
264	(void)strcpy(__collate_chain_pri_table[chain_index].str, curr_chain);
265	__collate_chain_pri_table[chain_index].prim = prim_pri;
266	chain_index++;
267}
268;
269sec_sub_item : CHAR {
270	if (__collate_char_pri_table[$1].prim)
271		yyerror("Char 0x%02x duplicated", $1);
272	__collate_char_pri_table[$1].prim = prim_pri;
273	__collate_char_pri_table[$1].sec = sec_pri++;
274}
275	| CHAR RANGE CHAR {
276	u_int i;
277
278	if ($3 <= $1)
279		yyerror("Illegal range 0x%02x -- 0x%02x",
280			$1, $3);
281
282	for (i = $1; i <= $3; i++) {
283		if (__collate_char_pri_table[(u_char)i].prim)
284			yyerror("Char 0x%02x duplicated", (u_char)i);
285		__collate_char_pri_table[(u_char)i].prim = prim_pri;
286		__collate_char_pri_table[(u_char)i].sec = sec_pri++;
287	}
288}
289	| chain {
290	if ((__collate_chain_pri_table = realloc(__collate_chain_pri_table,
291	     sizeof(*__collate_chain_pri_table) * (chain_index + 1))) == NULL)
292		yyerror("can't grow chain table");
293	(void)memset(&__collate_chain_pri_table[chain_index], 0,
294		     sizeof(__collate_chain_pri_table[0]));
295	(void)strcpy(__collate_chain_pri_table[chain_index].str, curr_chain);
296	__collate_chain_pri_table[chain_index].prim = prim_pri;
297	__collate_chain_pri_table[chain_index].sec = sec_pri++;
298	chain_index++;
299}
300;
301%%
302int
303main(int ac, char **av)
304{
305	int ch;
306
307#ifdef COLLATE_DEBUG
308	while((ch = getopt(ac, av, ":do:I:")) != -1) {
309#else
310	while((ch = getopt(ac, av, ":o:I:")) != -1) {
311#endif
312		switch (ch)
313		{
314#ifdef COLLATE_DEBUG
315		  case 'd':
316			debug++;
317			break;
318#endif
319		  case 'o':
320			out_file = optarg;
321			break;
322
323		  case 'I':
324			strlcpy(map_name, optarg, sizeof(map_name));
325			break;
326
327		  default:
328			usage();
329		}
330	}
331	ac -= optind;
332	av += optind;
333	if (ac > 0) {
334		if ((yyin = fopen(*av, "r")) == NULL)
335			err(EX_UNAVAILABLE, "can't open source file %s", *av);
336	}
337	for (ch = 0; ch <= UCHAR_MAX; ch++)
338		__collate_substitute_table[ch][0] = ch;
339	yyparse();
340	return 0;
341}
342
343static void
344usage(void)
345{
346	fprintf(stderr, "usage: colldef [-I map_dir] [-o out_file] [filename]\n");
347	exit(EX_USAGE);
348}
349
350void
351yyerror(const char *fmt, ...)
352{
353	va_list ap;
354	char msg[128];
355
356	va_start(ap, fmt);
357	vsnprintf(msg, sizeof(msg), fmt, ap);
358	va_end(ap);
359	errx(EX_UNAVAILABLE, "%s near line %d", msg, line_no);
360}
361
362#ifdef COLLATE_DEBUG
363static void
364collate_print_tables(void)
365{
366	int i;
367
368	printf("Substitute table:\n");
369	for (i = 0; i < UCHAR_MAX + 1; i++)
370	    if (i != *__collate_substitute_table[i])
371		printf("\t'%c' --> \"%s\"\n", i,
372		       __collate_substitute_table[i]);
373	printf("Chain priority table:\n");
374	for (i = 0; i < chain_index - 1; i++)
375		printf("\t\"%s\" : %d %d\n",
376		    __collate_chain_pri_table[i].str,
377		    __collate_chain_pri_table[i].prim,
378		    __collate_chain_pri_table[i].sec);
379	printf("Char priority table:\n");
380	for (i = 0; i < UCHAR_MAX + 1; i++)
381		printf("\t'%c' : %d %d\n", i, __collate_char_pri_table[i].prim,
382		       __collate_char_pri_table[i].sec);
383}
384#endif
385