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