master xplshn/aruu / cmd / posix / sh / mknodes.c
  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}