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