xref: /freebsd/bin/sh/mksyntax.c (revision afe61c15161c324a7af299a9b8457aba5afc92db)
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
38 static 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
44 static 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 
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 	"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  */
84 struct 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 
93 char writer[] = "\
94 /*\n\
95  * This file was generated by the mksyntax program.\n\
96  */\n\
97 \n";
98 
99 
100 FILE *cfile;
101 FILE *hfile;
102 char *syntax[513];
103 int base;
104 int size;		/* number of values which a char variable can have */
105 int nbits;		/* number of bits in a character */
106 int digit_contig;	/* true if digits are contiguous */
107 
108 
109 main() {
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 
249 filltable(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 
263 init() {
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 
280 add(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 
293 print(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 
326 char *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 
335 output_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 
354 digit_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