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
main(argc,argv)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
filltable(dftval)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
init()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
add(p,type)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
print(name)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
output_type_macros()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
digit_convert()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