mksyntax.c revision 1556
1/*-
2 * Copyright (c) 1991, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38static char copyright[] =
39"@(#) Copyright (c) 1991, 1993\n\
40	The Regents of the University of California.  All rights reserved.\n";
41#endif /* not lint */
42
43#ifndef lint
44static char sccsid[] = "@(#)mksyntax.c	8.1 (Berkeley) 5/31/93";
45#endif /* not lint */
46
47/*
48 * This program creates syntax.h and syntax.c.
49 */
50
51#include <stdio.h>
52#include "parser.h"
53
54
55struct synclass {
56	char *name;
57	char *comment;
58};
59
60/* Syntax classes */
61struct synclass synclass[] = {
62	"CWORD",		"character is nothing special",
63	"CNL",		"newline character",
64	"CBACK",		"a backslash character",
65	"CSQUOTE",	"single quote",
66	"CDQUOTE",	"double quote",
67	"CENDQUOTE",	"a terminating quote",
68	"CBQUOTE",	"backwards single quote",
69	"CVAR",		"a dollar sign",
70	"CENDVAR",	"a '}' character",
71	"CLP",		"a left paren in arithmetic",
72	"CRP",		"a right paren in arithmetic",
73	"CEOF",		"end of file",
74	"CCTL",		"like CWORD, except it must be escaped",
75	"CSPCL",		"these terminate a word",
76	NULL, NULL
77};
78
79
80/*
81 * Syntax classes for is_ functions.  Warning:  if you add new classes
82 * you may have to change the definition of the is_in_name macro.
83 */
84struct synclass is_entry[] = {
85	"ISDIGIT",	"a digit",
86	"ISUPPER",	"an upper case letter",
87	"ISLOWER",	"a lower case letter",
88	"ISUNDER",	"an underscore",
89	"ISSPECL",	"the name of a special parameter",
90	NULL, NULL,
91};
92
93char writer[] = "\
94/*\n\
95 * This file was generated by the mksyntax program.\n\
96 */\n\
97\n";
98
99
100FILE *cfile;
101FILE *hfile;
102char *syntax[513];
103int base;
104int size;		/* number of values which a char variable can have */
105int nbits;		/* number of bits in a character */
106int digit_contig;	/* true if digits are contiguous */
107
108
109main() {
110	char c;
111	char d;
112	int sign;
113	int i;
114	char buf[80];
115	int pos;
116	static char digit[] = "0123456789";
117
118	/* Create output files */
119	if ((cfile = fopen("syntax.c", "w")) == NULL) {
120		perror("syntax.c");
121		exit(2);
122	}
123	if ((hfile = fopen("syntax.h", "w")) == NULL) {
124		perror("syntax.h");
125		exit(2);
126	}
127	fputs(writer, hfile);
128	fputs(writer, cfile);
129
130	/* Determine the characteristics of chars. */
131	c = -1;
132	if (c < 0)
133		sign = 1;
134	else
135		sign = 0;
136	for (nbits = 1 ; ; nbits++) {
137		d = (1 << nbits) - 1;
138		if (d == c)
139			break;
140	}
141	printf("%s %d bit chars\n", sign? "signed" : "unsigned", nbits);
142	if (nbits > 9) {
143		fputs("Characters can't have more than 9 bits\n", stderr);
144		exit(2);
145	}
146	size = (1 << nbits) + 1;
147	base = 1;
148	if (sign)
149		base += 1 << (nbits - 1);
150	digit_contig = 1;
151	for (i = 0 ; i < 10 ; i++) {
152		if (digit[i] != '0' + i)
153			digit_contig = 0;
154	}
155
156	fputs("#include <sys/cdefs.h>\n", hfile);
157
158	/* Generate the #define statements in the header file */
159	fputs("/* Syntax classes */\n", hfile);
160	for (i = 0 ; synclass[i].name ; i++) {
161		sprintf(buf, "#define %s %d", synclass[i].name, i);
162		fputs(buf, hfile);
163		for (pos = strlen(buf) ; pos < 32 ; pos = pos + 8 &~ 07)
164			putc('\t', hfile);
165		fprintf(hfile, "/* %s */\n", synclass[i].comment);
166	}
167	putc('\n', hfile);
168	fputs("/* Syntax classes for is_ functions */\n", hfile);
169	for (i = 0 ; is_entry[i].name ; i++) {
170		sprintf(buf, "#define %s %#o", is_entry[i].name, 1 << i);
171		fputs(buf, hfile);
172		for (pos = strlen(buf) ; pos < 32 ; pos = pos + 8 &~ 07)
173			putc('\t', hfile);
174		fprintf(hfile, "/* %s */\n", is_entry[i].comment);
175	}
176	putc('\n', hfile);
177	fprintf(hfile, "#define SYNBASE %d\n", base);
178	fprintf(hfile, "#define PEOF %d\n\n", -base);
179	putc('\n', hfile);
180	fputs("#define BASESYNTAX (basesyntax + SYNBASE)\n", hfile);
181	fputs("#define DQSYNTAX (dqsyntax + SYNBASE)\n", hfile);
182	fputs("#define SQSYNTAX (sqsyntax + SYNBASE)\n", hfile);
183	fputs("#define ARISYNTAX (arisyntax + SYNBASE)\n", hfile);
184	putc('\n', hfile);
185	output_type_macros();		/* is_digit, etc. */
186	putc('\n', hfile);
187
188	/* Generate the syntax tables. */
189	fputs("#include \"shell.h\"\n", cfile);
190	fputs("#include \"syntax.h\"\n\n", cfile);
191	init();
192	fputs("/* syntax table used when not in quotes */\n", cfile);
193	add("\n", "CNL");
194	add("\\", "CBACK");
195	add("'", "CSQUOTE");
196	add("\"", "CDQUOTE");
197	add("`", "CBQUOTE");
198	add("$", "CVAR");
199	add("}", "CENDVAR");
200	add("<>();&| \t", "CSPCL");
201	print("basesyntax");
202	init();
203	fputs("\n/* syntax table used when in double quotes */\n", cfile);
204	add("\n", "CNL");
205	add("\\", "CBACK");
206	add("\"", "CENDQUOTE");
207	add("`", "CBQUOTE");
208	add("$", "CVAR");
209	add("}", "CENDVAR");
210	add("!*?[=~:/", "CCTL");	/* ':/' for tilde - yuck */
211	print("dqsyntax");
212	init();
213	fputs("\n/* syntax table used when in single quotes */\n", cfile);
214	add("\n", "CNL");
215	add("'", "CENDQUOTE");
216	add("!*?[=~:/", "CCTL");	/* ':/' for tilde - yuck */
217	print("sqsyntax");
218	init();
219	fputs("\n/* syntax table used when in arithmetic */\n", cfile);
220	add("\n", "CNL");
221	add("\\", "CBACK");
222	add("`", "CBQUOTE");
223	add("'", "CSQUOTE");
224	add("\"", "CDQUOTE");
225	add("$", "CVAR");
226	add("}", "CENDVAR");
227	add("(", "CLP");
228	add(")", "CRP");
229	print("arisyntax");
230	filltable("0");
231	fputs("\n/* character classification table */\n", cfile);
232	add("0123456789", "ISDIGIT");
233	add("abcdefghijklmnopqrstucvwxyz", "ISLOWER");
234	add("ABCDEFGHIJKLMNOPQRSTUCVWXYZ", "ISUPPER");
235	add("_", "ISUNDER");
236	add("#?$!-*@", "ISSPECL");
237	print("is_type");
238	if (! digit_contig)
239		digit_convert();
240	exit(0);
241}
242
243
244
245/*
246 * Clear the syntax table.
247 */
248
249filltable(dftval)
250	char *dftval;
251	{
252	int i;
253
254	for (i = 0 ; i < size ; i++)
255		syntax[i] = dftval;
256}
257
258
259/*
260 * Initialize the syntax table with default values.
261 */
262
263init() {
264	filltable("CWORD");
265	syntax[0] = "CEOF";
266	syntax[base + CTLESC] = "CCTL";
267	syntax[base + CTLVAR] = "CCTL";
268	syntax[base + CTLENDVAR] = "CCTL";
269	syntax[base + CTLBACKQ] = "CCTL";
270	syntax[base + CTLBACKQ + CTLQUOTE] = "CCTL";
271	syntax[base + CTLARI] = "CCTL";
272	syntax[base + CTLENDARI] = "CCTL";
273}
274
275
276/*
277 * Add entries to the syntax table.
278 */
279
280add(p, type)
281	char *p, *type;
282	{
283	while (*p)
284		syntax[*p++ + base] = type;
285}
286
287
288
289/*
290 * Output the syntax table.
291 */
292
293print(name)
294	char *name;
295	{
296	int i;
297	int col;
298
299	fprintf(hfile, "extern const char %s[];\n", name);
300	fprintf(cfile, "const char %s[%d] = {\n", name, size);
301	col = 0;
302	for (i = 0 ; i < size ; i++) {
303		if (i == 0) {
304			fputs("      ", cfile);
305		} else if ((i & 03) == 0) {
306			fputs(",\n      ", cfile);
307			col = 0;
308		} else {
309			putc(',', cfile);
310			while (++col < 9 * (i & 03))
311				putc(' ', cfile);
312		}
313		fputs(syntax[i], cfile);
314		col += strlen(syntax[i]);
315	}
316	fputs("\n};\n", cfile);
317}
318
319
320
321/*
322 * Output character classification macros (e.g. is_digit).  If digits are
323 * contiguous, we can test for them quickly.
324 */
325
326char *macro[] = {
327	"#define is_digit(c)\t((is_type+SYNBASE)[c] & ISDIGIT)",
328	"#define is_alpha(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER))",
329	"#define is_name(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER|ISUNDER))",
330	"#define is_in_name(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER|ISUNDER|ISDIGIT))",
331	"#define is_special(c)\t((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))",
332	NULL
333};
334
335output_type_macros() {
336	char **pp;
337
338	if (digit_contig)
339		macro[0] = "#define is_digit(c)\t((unsigned)((c) - '0') <= 9)";
340	for (pp = macro ; *pp ; pp++)
341		fprintf(hfile, "%s\n", *pp);
342	if (digit_contig)
343		fputs("#define digit_val(c)\t((c) - '0')\n", hfile);
344	else
345		fputs("#define digit_val(c)\t(digit_value[c])\n", hfile);
346}
347
348
349
350/*
351 * Output digit conversion table (if digits are not contiguous).
352 */
353
354digit_convert() {
355	int maxdigit;
356	static char digit[] = "0123456789";
357	char *p;
358	int i;
359
360	maxdigit = 0;
361	for (p = digit ; *p ; p++)
362		if (*p > maxdigit)
363			maxdigit = *p;
364	fputs("extern const char digit_value[];\n", hfile);
365	fputs("\n\nconst char digit_value[] = {\n", cfile);
366	for (i = 0 ; i <= maxdigit ; i++) {
367		for (p = digit ; *p && *p != i ; p++);
368		if (*p == '\0')
369			p = digit;
370		fprintf(cfile, "      %d,\n", p - digit);
371	}
372	fputs("};\n", cfile);
373}
374