xref: /386bsd/usr/src/bin/sh/mksyntax.c (revision a2142627)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * 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
38 char copyright[] =
39 "@(#) Copyright (c) 1991 The Regents of the University of California.\n\
40  All rights reserved.\n";
41 #endif /* not lint */
42 
43 #ifndef lint
44 static char sccsid[] = "@(#)mksyntax.c	5.2 (Berkeley) 3/8/91";
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 
55 struct synclass {
56 	char *name;
57 	char *comment;
58 };
59 
60 /* Syntax classes */
61 struct 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 	"CEOF",		"end of file",
72 	"CCTL",		"like CWORD, except it must be escaped",
73 	"CSPCL",		"these terminate a word",
74 	NULL, NULL
75 };
76 
77 
78 /*
79  * Syntax classes for is_ functions.  Warning:  if you add new classes
80  * you may have to change the definition of the is_in_name macro.
81  */
82 struct synclass is_entry[] = {
83 	"ISDIGIT",	"a digit",
84 	"ISUPPER",	"an upper case letter",
85 	"ISLOWER",	"a lower case letter",
86 	"ISUNDER",	"an underscore",
87 	"ISSPECL",	"the name of a special parameter",
88 	NULL, NULL,
89 };
90 
91 char writer[] = "\
92 /*\n\
93  * This file was generated by the mksyntax program.\n\
94  */\n\
95 \n";
96 
97 
98 FILE *cfile;
99 FILE *hfile;
100 char *syntax[513];
101 int base;
102 int size;		/* number of values which a char variable can have */
103 int nbits;		/* number of bits in a character */
104 int digit_contig;	/* true if digits are contiguous */
105 
106 
main()107 main() {
108 	char c;
109 	char d;
110 	int sign;
111 	int i;
112 	char buf[80];
113 	int pos;
114 	static char digit[] = "0123456789";
115 
116 	/* Create output files */
117 	if ((cfile = fopen("syntax.c", "w")) == NULL) {
118 		perror("syntax.c");
119 		exit(2);
120 	}
121 	if ((hfile = fopen("syntax.h", "w")) == NULL) {
122 		perror("syntax.h");
123 		exit(2);
124 	}
125 	fputs(writer, hfile);
126 	fputs(writer, cfile);
127 
128 	/* Determine the characteristics of chars. */
129 	c = -1;
130 	if (c < 0)
131 		sign = 1;
132 	else
133 		sign = 0;
134 	for (nbits = 1 ; ; nbits++) {
135 		d = (1 << nbits) - 1;
136 		if (d == c)
137 			break;
138 	}
139 	printf("%s %d bit chars\n", sign? "signed" : "unsigned", nbits);
140 	if (nbits > 9) {
141 		fputs("Characters can't have more than 9 bits\n", stderr);
142 		exit(2);
143 	}
144 	size = (1 << nbits) + 1;
145 	base = 1;
146 	if (sign)
147 		base += 1 << (nbits - 1);
148 	digit_contig = 1;
149 	for (i = 0 ; i < 10 ; i++) {
150 		if (digit[i] != '0' + i)
151 			digit_contig = 0;
152 	}
153 
154 	fputs("#include <sys/cdefs.h>\n", hfile);
155 
156 	/* Generate the #define statements in the header file */
157 	fputs("/* Syntax classes */\n", hfile);
158 	for (i = 0 ; synclass[i].name ; i++) {
159 		sprintf(buf, "#define %s %d", synclass[i].name, i);
160 		fputs(buf, hfile);
161 		for (pos = strlen(buf) ; pos < 32 ; pos = pos + 8 &~ 07)
162 			putc('\t', hfile);
163 		fprintf(hfile, "/* %s */\n", synclass[i].comment);
164 	}
165 	putc('\n', hfile);
166 	fputs("/* Syntax classes for is_ functions */\n", hfile);
167 	for (i = 0 ; is_entry[i].name ; i++) {
168 		sprintf(buf, "#define %s %#o", is_entry[i].name, 1 << i);
169 		fputs(buf, hfile);
170 		for (pos = strlen(buf) ; pos < 32 ; pos = pos + 8 &~ 07)
171 			putc('\t', hfile);
172 		fprintf(hfile, "/* %s */\n", is_entry[i].comment);
173 	}
174 	putc('\n', hfile);
175 	fprintf(hfile, "#define SYNBASE %d\n", base);
176 	fprintf(hfile, "#define PEOF %d\n\n", -base);
177 	putc('\n', hfile);
178 	fputs("#define BASESYNTAX (basesyntax + SYNBASE)\n", hfile);
179 	fputs("#define DQSYNTAX (dqsyntax + SYNBASE)\n", hfile);
180 	fputs("#define SQSYNTAX (sqsyntax + SYNBASE)\n", hfile);
181 	putc('\n', hfile);
182 	output_type_macros();		/* is_digit, etc. */
183 	putc('\n', hfile);
184 
185 	/* Generate the syntax tables. */
186 	fputs("#include \"shell.h\"\n", cfile);
187 	fputs("#include \"syntax.h\"\n\n", cfile);
188 	init();
189 	fputs("/* syntax table used when not in quotes */\n", cfile);
190 	add("\n", "CNL");
191 	add("\\", "CBACK");
192 	add("'", "CSQUOTE");
193 	add("\"", "CDQUOTE");
194 	add("`", "CBQUOTE");
195 	add("$", "CVAR");
196 	add("}", "CENDVAR");
197 	add("<>();&| \t", "CSPCL");
198 	print("basesyntax");
199 	init();
200 	fputs("\n/* syntax table used when in double quotes */\n", cfile);
201 	add("\n", "CNL");
202 	add("\\", "CBACK");
203 	add("\"", "CENDQUOTE");
204 	add("`", "CBQUOTE");
205 	add("$", "CVAR");
206 	add("}", "CENDVAR");
207 	add("!*?[=", "CCTL");
208 	print("dqsyntax");
209 	init();
210 	fputs("\n/* syntax table used when in single quotes */\n", cfile);
211 	add("\n", "CNL");
212 	add("'", "CENDQUOTE");
213 	add("!*?[=", "CCTL");
214 	print("sqsyntax");
215 	filltable("0");
216 	fputs("\n/* character classification table */\n", cfile);
217 	add("0123456789", "ISDIGIT");
218 	add("abcdefghijklmnopqrstucvwxyz", "ISLOWER");
219 	add("ABCDEFGHIJKLMNOPQRSTUCVWXYZ", "ISUPPER");
220 	add("_", "ISUNDER");
221 	add("#?$!-*@", "ISSPECL");
222 	print("is_type");
223 	if (! digit_contig)
224 		digit_convert();
225 	exit(0);
226 }
227 
228 
229 
230 /*
231  * Clear the syntax table.
232  */
233 
filltable(dftval)234 filltable(dftval)
235 	char *dftval;
236 	{
237 	int i;
238 
239 	for (i = 0 ; i < size ; i++)
240 		syntax[i] = dftval;
241 }
242 
243 
244 /*
245  * Initialize the syntax table with default values.
246  */
247 
init()248 init() {
249 	filltable("CWORD");
250 	syntax[0] = "CEOF";
251 	syntax[base + CTLESC] = "CCTL";
252 	syntax[base + CTLVAR] = "CCTL";
253 	syntax[base + CTLENDVAR] = "CCTL";
254 	syntax[base + CTLBACKQ] = "CCTL";
255 	syntax[base + CTLBACKQ + CTLQUOTE] = "CCTL";
256 }
257 
258 
259 /*
260  * Add entries to the syntax table.
261  */
262 
add(p,type)263 add(p, type)
264 	char *p, *type;
265 	{
266 	while (*p)
267 		syntax[*p++ + base] = type;
268 }
269 
270 
271 
272 /*
273  * Output the syntax table.
274  */
275 
print(name)276 print(name)
277 	char *name;
278 	{
279 	int i;
280 	int col;
281 
282 	fprintf(hfile, "extern const char %s[];\n", name);
283 	fprintf(cfile, "const char %s[%d] = {\n", name, size);
284 	col = 0;
285 	for (i = 0 ; i < size ; i++) {
286 		if (i == 0) {
287 			fputs("      ", cfile);
288 		} else if ((i & 03) == 0) {
289 			fputs(",\n      ", cfile);
290 			col = 0;
291 		} else {
292 			putc(',', cfile);
293 			while (++col < 9 * (i & 03))
294 				putc(' ', cfile);
295 		}
296 		fputs(syntax[i], cfile);
297 		col += strlen(syntax[i]);
298 	}
299 	fputs("\n};\n", cfile);
300 }
301 
302 
303 
304 /*
305  * Output character classification macros (e.g. is_digit).  If digits are
306  * contiguous, we can test for them quickly.
307  */
308 
309 char *macro[] = {
310 	"#define is_digit(c)\t((is_type+SYNBASE)[c] & ISDIGIT)",
311 	"#define is_alpha(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER))",
312 	"#define is_name(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER|ISUNDER))",
313 	"#define is_in_name(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER|ISUNDER|ISDIGIT))",
314 	"#define is_special(c)\t((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))",
315 	NULL
316 };
317 
output_type_macros()318 output_type_macros() {
319 	char **pp;
320 
321 	if (digit_contig)
322 		macro[0] = "#define is_digit(c)\t((unsigned)((c) - '0') <= 9)";
323 	for (pp = macro ; *pp ; pp++)
324 		fprintf(hfile, "%s\n", *pp);
325 	if (digit_contig)
326 		fputs("#define digit_val(c)\t((c) - '0')\n", hfile);
327 	else
328 		fputs("#define digit_val(c)\t(digit_value[c])\n", hfile);
329 }
330 
331 
332 
333 /*
334  * Output digit conversion table (if digits are not contiguous).
335  */
336 
digit_convert()337 digit_convert() {
338 	int maxdigit;
339 	static char digit[] = "0123456789";
340 	char *p;
341 	int i;
342 
343 	maxdigit = 0;
344 	for (p = digit ; *p ; p++)
345 		if (*p > maxdigit)
346 			maxdigit = *p;
347 	fputs("extern const char digit_value[];\n", hfile);
348 	fputs("\n\nconst char digit_value[] = {\n", cfile);
349 	for (i = 0 ; i <= maxdigit ; i++) {
350 		for (p = digit ; *p && *p != i ; p++);
351 		if (*p == '\0')
352 			p = digit;
353 		fprintf(cfile, "      %d,\n", p - digit);
354 	}
355 	fputs("};\n", cfile);
356 }
357