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