1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35/*
36 * This program reads the nodetypes file and nodes.c.pat file. It generates
37 * the files nodes.h and nodes.c.
38 */
39
40#include <errno.h>
41#include <stdarg.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45
46#ifndef __printf0like
47#define __printf0like(n, m) __attribute__((__format__(__printf__, n, m)))
48#endif
49#ifndef __dead2
50#define __dead2 __attribute__((__noreturn__))
51#endif
52
53#define MAXTYPES 50 /* max number of node types */
54#define MAXFIELDS 20 /* max fields in a structure */
55#define BUFLEN 100 /* size of character buffers */
56
57/* field types */
58#define T_NODE 1 /* union node *field */
59#define T_NODELIST 2 /* struct nodelist *field */
60#define T_STRING 3
61#define T_INT 4 /* int field */
62#define T_OTHER 5 /* other */
63#define T_TEMP 6 /* don't copy this field */
64
65struct field { /* a structure field */
66 char *name; /* name of field */
67 int type; /* type of field */
68 char *decl; /* declaration of field */
69};
70
71struct str { /* struct representing a node structure */
72 char *tag; /* structure tag */
73 int nfields; /* number of fields in the structure */
74 struct field field[MAXFIELDS]; /* the fields of the structure */
75 int done; /* set if fully parsed */
76};
77
78static int ntypes; /* number of node types */
79static char *nodename[MAXTYPES]; /* names of the nodes */
80static struct str *nodestr[MAXTYPES]; /* type of structure used by the node */
81static int nstr; /* number of structures */
82static struct str str[MAXTYPES]; /* the structures */
83static struct str *curstr; /* current structure */
84static char line[1024];
85static int linno;
86static char *linep;
87
88static void parsenode(void);
89static void parsefield(void);
90static void output(char *);
91static void outsizes(FILE *);
92static void outfunc(FILE *, int);
93static void indent(int, FILE *);
94static int nextfield(char *);
95static void skipbl(void);
96static int readline(FILE *);
97static void error(const char *, ...) __printf0like(1, 2) __dead2;
98static char *savestr(const char *);
99
100int
101main(int argc, char *argv[])
102{
103 FILE *infp;
104
105 if (argc != 3)
106 error("usage: mknodes file");
107 if ((infp = fopen(argv[1], "r")) == NULL)
108 error("Can't open %s: %s", argv[1], strerror(errno));
109 while (readline(infp)) {
110 if (line[0] == ' ' || line[0] == '\t')
111 parsefield();
112 else if (line[0] != '\0')
113 parsenode();
114 }
115 fclose(infp);
116 output(argv[2]);
117 exit(0);
118}
119
120static void
121parsenode(void)
122{
123 char name[BUFLEN];
124 char tag[BUFLEN];
125 struct str *sp;
126
127 if (curstr && curstr->nfields > 0)
128 curstr->done = 1;
129 nextfield(name);
130 if (!nextfield(tag))
131 error("Tag expected");
132 if (*linep != '\0')
133 error("Garbage at end of line");
134 nodename[ntypes] = savestr(name);
135 for (sp = str; sp < str + nstr; sp++) {
136 if (strcmp(sp->tag, tag) == 0)
137 break;
138 }
139 if (sp >= str + nstr) {
140 sp->tag = savestr(tag);
141 sp->nfields = 0;
142 curstr = sp;
143 nstr++;
144 }
145 nodestr[ntypes] = sp;
146 ntypes++;
147}
148
149static void
150parsefield(void)
151{
152 char name[BUFLEN];
153 char type[BUFLEN];
154 char decl[2 * BUFLEN];
155 struct field *fp;
156
157 if (curstr == NULL || curstr->done)
158 error("No current structure to add field to");
159 if (!nextfield(name))
160 error("No field name");
161 if (!nextfield(type))
162 error("No field type");
163 fp = &curstr->field[curstr->nfields];
164 fp->name = savestr(name);
165 if (strcmp(type, "nodeptr") == 0) {
166 fp->type = T_NODE;
167 sprintf(decl, "union node *%s", name);
168 } else if (strcmp(type, "nodelist") == 0) {
169 fp->type = T_NODELIST;
170 sprintf(decl, "struct nodelist *%s", name);
171 } else if (strcmp(type, "string") == 0) {
172 fp->type = T_STRING;
173 sprintf(decl, "char *%s", name);
174 } else if (strcmp(type, "int") == 0) {
175 fp->type = T_INT;
176 sprintf(decl, "int %s", name);
177 } else if (strcmp(type, "other") == 0) {
178 fp->type = T_OTHER;
179 } else if (strcmp(type, "temp") == 0) {
180 fp->type = T_TEMP;
181 } else {
182 error("Unknown type %s", type);
183 }
184 if (fp->type == T_OTHER || fp->type == T_TEMP) {
185 skipbl();
186 fp->decl = savestr(linep);
187 } else {
188 if (*linep)
189 error("Garbage at end of line");
190 fp->decl = savestr(decl);
191 }
192 curstr->nfields++;
193}
194
195static const char writer[] = "\
196/*\n\
197 * This file was generated by the mknodes program.\n\
198 */\n\
199\n";
200
201static void
202output(char *file)
203{
204 FILE *hfile;
205 FILE *cfile;
206 FILE *patfile;
207 int i;
208 struct str *sp;
209 struct field *fp;
210 char *p;
211
212 if ((patfile = fopen(file, "r")) == NULL)
213 error("Can't open %s: %s", file, strerror(errno));
214 if ((hfile = fopen("nodes.h", "w")) == NULL)
215 error("Can't create nodes.h: %s", strerror(errno));
216 if ((cfile = fopen("nodes.c", "w")) == NULL)
217 error("Can't create nodes.c");
218 fputs(writer, hfile);
219 for (i = 0; i < ntypes; i++)
220 fprintf(hfile, "#define %s %d\n", nodename[i], i);
221 fputs("\n\n\n", hfile);
222 for (sp = str; sp < &str[nstr]; sp++) {
223 fprintf(hfile, "struct %s {\n", sp->tag);
224 for (i = sp->nfields, fp = sp->field; --i >= 0; fp++) {
225 fprintf(hfile, " %s;\n", fp->decl);
226 }
227 fputs("};\n\n\n", hfile);
228 }
229 fputs("union node {\n", hfile);
230 fprintf(hfile, " int type;\n");
231 for (sp = str; sp < &str[nstr]; sp++) {
232 fprintf(hfile, " struct %s %s;\n", sp->tag, sp->tag);
233 }
234 fputs("};\n\n\n", hfile);
235 fputs("struct nodelist {\n", hfile);
236 fputs("\tstruct nodelist *next;\n", hfile);
237 fputs("\tunion node *n;\n", hfile);
238 fputs("};\n\n\n", hfile);
239 fputs("struct funcdef;\n", hfile);
240 fputs("struct funcdef *copyfunc(union node *);\n", hfile);
241 fputs("union node *getfuncnode(struct funcdef *);\n", hfile);
242 fputs("void reffunc(struct funcdef *);\n", hfile);
243 fputs("void unreffunc(struct funcdef *);\n", hfile);
244 if (ferror(hfile))
245 error("Can't write to nodes.h");
246 if (fclose(hfile))
247 error("Can't close nodes.h");
248
249 fputs(writer, cfile);
250 while (fgets(line, sizeof line, patfile) != NULL) {
251 for (p = line; *p == ' ' || *p == '\t'; p++)
252 ;
253 if (strcmp(p, "%SIZES\n") == 0)
254 outsizes(cfile);
255 else if (strcmp(p, "%CALCSIZE\n") == 0)
256 outfunc(cfile, 1);
257 else if (strcmp(p, "%COPY\n") == 0)
258 outfunc(cfile, 0);
259 else
260 fputs(line, cfile);
261 }
262 fclose(patfile);
263 if (ferror(cfile))
264 error("Can't write to nodes.c");
265 if (fclose(cfile))
266 error("Can't close nodes.c");
267}
268
269static void
270outsizes(FILE *cfile)
271{
272 int i;
273
274 fprintf(cfile, "static const short nodesize[%d] = {\n", ntypes);
275 for (i = 0; i < ntypes; i++) {
276 fprintf(cfile, " ALIGN(sizeof (struct %s)),\n", nodestr[i]->tag);
277 }
278 fprintf(cfile, "};\n");
279}
280
281static void
282outfunc(FILE *cfile, int calcsize)
283{
284 struct str *sp;
285 struct field *fp;
286 int i;
287
288 fputs(" if (n == NULL)\n", cfile);
289 if (calcsize)
290 fputs(" return;\n", cfile);
291 else
292 fputs(" return NULL;\n", cfile);
293 if (calcsize)
294 fputs(" result->blocksize += nodesize[n->type];\n", cfile);
295 else {
296 fputs(" new = state->block;\n", cfile);
297 fputs(
298 " state->block = (char *)state->block + "
299 "nodesize[n->type];\n",
300 cfile
301 );
302 }
303 fputs(" switch (n->type) {\n", cfile);
304 for (sp = str; sp < &str[nstr]; sp++) {
305 for (i = 0; i < ntypes; i++) {
306 if (nodestr[i] == sp)
307 fprintf(cfile, " case %s:\n", nodename[i]);
308 }
309 for (i = sp->nfields; --i >= 1;) {
310 fp = &sp->field[i];
311 switch (fp->type) {
312 case T_NODE:
313 if (calcsize) {
314 indent(12, cfile);
315 fprintf(cfile, "calcsize(n->%s.%s, result);\n", sp->tag, fp->name);
316 } else {
317 indent(12, cfile);
318 fprintf(
319 cfile,
320 "new->%s.%s = "
321 "copynode(n->%s.%s, state);\n",
322 sp->tag,
323 fp->name,
324 sp->tag,
325 fp->name
326 );
327 }
328 break;
329 case T_NODELIST:
330 if (calcsize) {
331 indent(12, cfile);
332 fprintf(
333 cfile,
334 "sizenodelist(n->%s.%s, "
335 "result);\n",
336 sp->tag,
337 fp->name
338 );
339 } else {
340 indent(12, cfile);
341 fprintf(
342 cfile,
343 "new->%s.%s = "
344 "copynodelist(n->%s.%s, "
345 "state);\n",
346 sp->tag,
347 fp->name,
348 sp->tag,
349 fp->name
350 );
351 }
352 break;
353 case T_STRING:
354 if (calcsize) {
355 indent(12, cfile);
356 fprintf(
357 cfile,
358 "result->stringsize += "
359 "strlen(n->%s.%s) + 1;\n",
360 sp->tag,
361 fp->name
362 );
363 } else {
364 indent(12, cfile);
365 fprintf(
366 cfile,
367 "new->%s.%s = "
368 "nodesavestr(n->%s.%s, "
369 "state);\n",
370 sp->tag,
371 fp->name,
372 sp->tag,
373 fp->name
374 );
375 }
376 break;
377 case T_INT:
378 case T_OTHER:
379 if (!calcsize) {
380 indent(12, cfile);
381 fprintf(cfile, "new->%s.%s = n->%s.%s;\n", sp->tag, fp->name, sp->tag, fp->name);
382 }
383 break;
384 }
385 }
386 indent(12, cfile);
387 fputs("break;\n", cfile);
388 }
389 fputs(" };\n", cfile);
390 if (!calcsize)
391 fputs(" new->type = n->type;\n", cfile);
392}
393
394static void
395indent(int amount, FILE *fp)
396{
397 while (amount >= 8) {
398 putc('\t', fp);
399 amount -= 8;
400 }
401 while (--amount >= 0) {
402 putc(' ', fp);
403 }
404}
405
406static int
407nextfield(char *buf)
408{
409 char *p, *q;
410
411 p = linep;
412 while (*p == ' ' || *p == '\t')
413 p++;
414 q = buf;
415 while (*p != ' ' && *p != '\t' && *p != '\0')
416 *q++ = *p++;
417 *q = '\0';
418 linep = p;
419 return (q > buf);
420}
421
422static void
423skipbl(void)
424{
425 while (*linep == ' ' || *linep == '\t')
426 linep++;
427}
428
429static int
430readline(FILE *infp)
431{
432 char *p;
433
434 if (fgets(line, 1024, infp) == NULL)
435 return 0;
436 for (p = line; *p != '#' && *p != '\n' && *p != '\0'; p++)
437 ;
438 while (p > line && (p[-1] == ' ' || p[-1] == '\t'))
439 p--;
440 *p = '\0';
441 linep = line;
442 linno++;
443 if (p - line > BUFLEN)
444 error("Line too long");
445 return 1;
446}
447
448static void
449error(const char *msg, ...)
450{
451 va_list va;
452 va_start(va, msg);
453
454 (void)fprintf(stderr, "line %d: ", linno);
455 (void)vfprintf(stderr, msg, va);
456 (void)fputc('\n', stderr);
457
458 va_end(va);
459
460 exit(2);
461}
462
463static char *
464savestr(const char *s)
465{
466 char *p;
467
468 if ((p = malloc(strlen(s) + 1)) == NULL)
469 error("Out of space");
470 (void)strcpy(p, s);
471 return p;
472}