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 <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <errno.h>
44#include <stdarg.h>
45
46#define MAXTYPES 50		/* max number of node types */
47#define MAXFIELDS 20		/* max fields in a structure */
48#define BUFLEN 100		/* size of character buffers */
49
50/* field types */
51#define T_NODE 1		/* union node *field */
52#define T_NODELIST 2		/* struct nodelist *field */
53#define T_STRING 3
54#define T_INT 4			/* int field */
55#define T_OTHER 5		/* other */
56#define T_TEMP 6		/* don't copy this field */
57
58
59struct field {			/* a structure field */
60	char *name;		/* name of field */
61	int type;			/* type of field */
62	char *decl;		/* declaration of field */
63};
64
65
66struct str {			/* struct representing a node structure */
67	char *tag;		/* structure tag */
68	int nfields;		/* number of fields in the structure */
69	struct field field[MAXFIELDS];	/* the fields of the structure */
70	int done;			/* set if fully parsed */
71};
72
73
74static int ntypes;			/* number of node types */
75static char *nodename[MAXTYPES];	/* names of the nodes */
76static struct str *nodestr[MAXTYPES];	/* type of structure used by the node */
77static int nstr;			/* number of structures */
78static struct str str[MAXTYPES];	/* the structures */
79static struct str *curstr;		/* current structure */
80static char line[1024];
81static int linno;
82static char *linep;
83
84static void parsenode(void);
85static void parsefield(void);
86static void output(char *);
87static void outsizes(FILE *);
88static void outfunc(FILE *, int);
89static void indent(int, FILE *);
90static int nextfield(char *);
91static void skipbl(void);
92static int readline(FILE *);
93static void error(const char *, ...) __printf0like(1, 2) __dead2;
94static char *savestr(const char *);
95
96
97int
98main(int argc, char *argv[])
99{
100	FILE *infp;
101
102	if (argc != 3)
103		error("usage: mknodes file");
104	if ((infp = fopen(argv[1], "r")) == NULL)
105		error("Can't open %s: %s", argv[1], strerror(errno));
106	while (readline(infp)) {
107		if (line[0] == ' ' || line[0] == '\t')
108			parsefield();
109		else if (line[0] != '\0')
110			parsenode();
111	}
112	fclose(infp);
113	output(argv[2]);
114	exit(0);
115}
116
117
118
119static void
120parsenode(void)
121{
122	char name[BUFLEN];
123	char tag[BUFLEN];
124	struct str *sp;
125
126	if (curstr && curstr->nfields > 0)
127		curstr->done = 1;
128	nextfield(name);
129	if (! nextfield(tag))
130		error("Tag expected");
131	if (*linep != '\0')
132		error("Garbage at end of line");
133	nodename[ntypes] = savestr(name);
134	for (sp = str ; sp < str + nstr ; sp++) {
135		if (strcmp(sp->tag, tag) == 0)
136			break;
137	}
138	if (sp >= str + nstr) {
139		sp->tag = savestr(tag);
140		sp->nfields = 0;
141		curstr = sp;
142		nstr++;
143	}
144	nodestr[ntypes] = sp;
145	ntypes++;
146}
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
195
196static const char writer[] = "\
197/*\n\
198 * This file was generated by the mknodes program.\n\
199 */\n\
200\n";
201
202static void
203output(char *file)
204{
205	FILE *hfile;
206	FILE *cfile;
207	FILE *patfile;
208	int i;
209	struct str *sp;
210	struct field *fp;
211	char *p;
212
213	if ((patfile = fopen(file, "r")) == NULL)
214		error("Can't open %s: %s", file, strerror(errno));
215	if ((hfile = fopen("nodes.h", "w")) == NULL)
216		error("Can't create nodes.h: %s", strerror(errno));
217	if ((cfile = fopen("nodes.c", "w")) == NULL)
218		error("Can't create nodes.c");
219	fputs(writer, hfile);
220	for (i = 0 ; i < ntypes ; i++)
221		fprintf(hfile, "#define %s %d\n", nodename[i], i);
222	fputs("\n\n\n", hfile);
223	for (sp = str ; sp < &str[nstr] ; sp++) {
224		fprintf(hfile, "struct %s {\n", sp->tag);
225		for (i = sp->nfields, fp = sp->field ; --i >= 0 ; fp++) {
226			fprintf(hfile, "      %s;\n", fp->decl);
227		}
228		fputs("};\n\n\n", hfile);
229	}
230	fputs("union node {\n", hfile);
231	fprintf(hfile, "      int type;\n");
232	for (sp = str ; sp < &str[nstr] ; sp++) {
233		fprintf(hfile, "      struct %s %s;\n", sp->tag, sp->tag);
234	}
235	fputs("};\n\n\n", hfile);
236	fputs("struct nodelist {\n", hfile);
237	fputs("\tstruct nodelist *next;\n", hfile);
238	fputs("\tunion node *n;\n", hfile);
239	fputs("};\n\n\n", hfile);
240	fputs("struct funcdef;\n", hfile);
241	fputs("struct funcdef *copyfunc(union node *);\n", hfile);
242	fputs("union node *getfuncnode(struct funcdef *);\n", hfile);
243	fputs("void reffunc(struct funcdef *);\n", hfile);
244	fputs("void unreffunc(struct funcdef *);\n", hfile);
245	if (ferror(hfile))
246		error("Can't write to nodes.h");
247	if (fclose(hfile))
248		error("Can't close nodes.h");
249
250	fputs(writer, cfile);
251	while (fgets(line, sizeof line, patfile) != NULL) {
252		for (p = line ; *p == ' ' || *p == '\t' ; p++);
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
269
270
271static void
272outsizes(FILE *cfile)
273{
274	int i;
275
276	fprintf(cfile, "static const short nodesize[%d] = {\n", ntypes);
277	for (i = 0 ; i < ntypes ; i++) {
278		fprintf(cfile, "      ALIGN(sizeof (struct %s)),\n", nodestr[i]->tag);
279	}
280	fprintf(cfile, "};\n");
281}
282
283
284static void
285outfunc(FILE *cfile, int calcsize)
286{
287	struct str *sp;
288	struct field *fp;
289	int i;
290
291	fputs("      if (n == NULL)\n", cfile);
292	if (calcsize)
293		fputs("	    return;\n", cfile);
294	else
295		fputs("	    return NULL;\n", cfile);
296	if (calcsize)
297		fputs("      result->blocksize += nodesize[n->type];\n", cfile);
298	else {
299		fputs("      new = state->block;\n", cfile);
300		fputs("      state->block = (char *)state->block + nodesize[n->type];\n", cfile);
301	}
302	fputs("      switch (n->type) {\n", cfile);
303	for (sp = str ; sp < &str[nstr] ; sp++) {
304		for (i = 0 ; i < ntypes ; i++) {
305			if (nodestr[i] == sp)
306				fprintf(cfile, "      case %s:\n", nodename[i]);
307		}
308		for (i = sp->nfields ; --i >= 1 ; ) {
309			fp = &sp->field[i];
310			switch (fp->type) {
311			case T_NODE:
312				if (calcsize) {
313					indent(12, cfile);
314					fprintf(cfile, "calcsize(n->%s.%s, result);\n",
315						sp->tag, fp->name);
316				} else {
317					indent(12, cfile);
318					fprintf(cfile, "new->%s.%s = copynode(n->%s.%s, state);\n",
319						sp->tag, fp->name, sp->tag, fp->name);
320				}
321				break;
322			case T_NODELIST:
323				if (calcsize) {
324					indent(12, cfile);
325					fprintf(cfile, "sizenodelist(n->%s.%s, result);\n",
326						sp->tag, fp->name);
327				} else {
328					indent(12, cfile);
329					fprintf(cfile, "new->%s.%s = copynodelist(n->%s.%s, state);\n",
330						sp->tag, fp->name, sp->tag, fp->name);
331				}
332				break;
333			case T_STRING:
334				if (calcsize) {
335					indent(12, cfile);
336					fprintf(cfile, "result->stringsize += strlen(n->%s.%s) + 1;\n",
337						sp->tag, fp->name);
338				} else {
339					indent(12, cfile);
340					fprintf(cfile, "new->%s.%s = nodesavestr(n->%s.%s, state);\n",
341						sp->tag, fp->name, sp->tag, fp->name);
342				}
343				break;
344			case T_INT:
345			case T_OTHER:
346				if (! calcsize) {
347					indent(12, cfile);
348					fprintf(cfile, "new->%s.%s = n->%s.%s;\n",
349						sp->tag, fp->name, sp->tag, fp->name);
350				}
351				break;
352			}
353		}
354		indent(12, cfile);
355		fputs("break;\n", cfile);
356	}
357	fputs("      };\n", cfile);
358	if (! calcsize)
359		fputs("      new->type = n->type;\n", cfile);
360}
361
362
363static void
364indent(int amount, FILE *fp)
365{
366	while (amount >= 8) {
367		putc('\t', fp);
368		amount -= 8;
369	}
370	while (--amount >= 0) {
371		putc(' ', fp);
372	}
373}
374
375
376static int
377nextfield(char *buf)
378{
379	char *p, *q;
380
381	p = linep;
382	while (*p == ' ' || *p == '\t')
383		p++;
384	q = buf;
385	while (*p != ' ' && *p != '\t' && *p != '\0')
386		*q++ = *p++;
387	*q = '\0';
388	linep = p;
389	return (q > buf);
390}
391
392
393static void
394skipbl(void)
395{
396	while (*linep == ' ' || *linep == '\t')
397		linep++;
398}
399
400
401static int
402readline(FILE *infp)
403{
404	char *p;
405
406	if (fgets(line, 1024, infp) == NULL)
407		return 0;
408	for (p = line ; *p != '#' && *p != '\n' && *p != '\0' ; p++);
409	while (p > line && (p[-1] == ' ' || p[-1] == '\t'))
410		p--;
411	*p = '\0';
412	linep = line;
413	linno++;
414	if (p - line > BUFLEN)
415		error("Line too long");
416	return 1;
417}
418
419
420
421static void
422error(const char *msg, ...)
423{
424	va_list va;
425	va_start(va, msg);
426
427	(void) fprintf(stderr, "line %d: ", linno);
428	(void) vfprintf(stderr, msg, va);
429	(void) fputc('\n', stderr);
430
431	va_end(va);
432
433	exit(2);
434}
435
436
437
438static char *
439savestr(const char *s)
440{
441	char *p;
442
443	if ((p = malloc(strlen(s) + 1)) == NULL)
444		error("Out of space");
445	(void) strcpy(p, s);
446	return p;
447}
448