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