view cgbigen/cgbigen.syn @ 17:12171da8943f

Don't refer to CVS.
author David A. Holland
date Tue, 31 May 2022 01:56:37 -0400
parents 13d2b8934445
children
line wrap: on
line source

{
/*
 * AnaGram, a System for Syntax Directed Programming
 * Copyright 1993 Parsifal Software. All Rights Reserved.
 * Copyright 2006 David A. Holland. All Rights Reserved.
 * See the file COPYING for license and usage terms.
 *
 * cgbigen.syn - Syntax for CG source file (cg46.cgs)
 *               Generates cg46.h.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
}


{

static FILE *infile, *outfile;
#define GET_INPUT  ((PCB).input_code = getc(infile))

#define TEMPFILE ".cgstemp"

//////////////////////////////

#define STRBUFSIZE 32768
static char strbuf[STRBUFSIZE];
static size_t strbufpos = 0;

static void addstr(int ch) {
  if (strbufpos >= sizeof(strbuf)) {
    fprintf(stderr, "compile-cgs: string buffer overflow; make it larger\n");
    exit(1);
  }
  strbuf[strbufpos++] = ch;
}

static const char *getstr(void) {
  addstr(0);
  strbufpos = 0;
  return strbuf;
}

//////////////////////////////

/* remove a character from strbuf[] */
static void strsnip(size_t pos) {
  assert(pos < strbufpos);
  strbufpos--;
  memmove(strbuf+pos, strbuf+pos+1, strbufpos);
}

/* munge newlines in strbuf[]. for exact regression test compliance. */
static void fudgenewlines(void) {
  while (strbufpos > 0 && strbuf[0] == '\n') {
    strsnip(0);
  }
  while (strbufpos > 1 && 
	 strbuf[strbufpos-1] == '\n' && 
	 strbuf[strbufpos-2] == '\n') {
    strbufpos--;
  }
}

//////////////////////////////

static void emitstring(const char *s) {
  size_t i, len;
  unsigned pos = 0;

  len = strlen(s);
  if (len==0) {
    fprintf(outfile, "  \"\"\n");
    return;
  }

  for (i=0; i<len; i++) {
    if (pos==0) {
      fprintf(outfile, "  \"");
    }
    switch (s[i]) {
      case '\r': if (pos==0) pos++; continue;
      case '\n': fputs("\\n", outfile); pos+=3; break;
      case '?': fputs("\\077", outfile); pos+=4; break;
      case '"': fputs("\\\"", outfile); pos+=4; break;
      case '\\': fputs("\\\\", outfile); pos+=4; break;
      default:
        if (s[i]>=32 && s[i]<127) {
	  fputc(s[i], outfile);
	  pos++;
        }
        else {
          fprintf(outfile, "\\%03o", (unsigned)(unsigned char)s[i]);
          pos+=4;
        }
	break;
    }
    if (pos>=72) {
      fprintf(outfile, "\"\n");
      pos = 0;
    }
  }
  if (pos>0) {
    fprintf(outfile, "\"\n");
  }
}

//////////////////////////////

static unsigned bodynum = 0, titlenum = 0;
static int havetitle = 0;

static void emitbody(const char *s) {
  unsigned num;

  num = bodynum;
  bodynum = titlenum;
  havetitle = 0;

  fprintf(outfile, "static const char cgbody_%u[] =\n", num);
  emitstring(s);
  fprintf(outfile, ";\n");
}

static void emittitle(const char *s) {
  unsigned num;

  num = titlenum++;
  if (havetitle) {
    fprintf(outfile, "#define cgbody_%u cgbody_%u\n", num, bodynum);
  }
  else {
    havetitle = 1;
  }

  fprintf(outfile, "static const char cgtitle_%u[] =\n", num);
  emitstring(s);
  fprintf(outfile, ";\n");
}

static void emittable(void) {
  unsigned i;

  assert(bodynum == titlenum);

  fprintf(outfile, "struct cgentry {\n");
  fprintf(outfile, "  const char *name;\n");
  fprintf(outfile, "  const char *data;\n");
  fprintf(outfile, "};\n\n");

  fprintf(outfile, "static const unsigned cgtablenum = %u;\n", bodynum);
  fprintf(outfile, "static struct cgentry cgtable[%u] = {\n", bodynum);
  for (i=0; i<bodynum; i++) {
    fprintf(outfile, "  { cgtitle_%u, cgbody_%u },\n", i, i);
  }
  fprintf(outfile, "};\n\n");
}

//////////////////////////////

static void compile(const char *inpath, const char *outpath) {
  infile = fopen(inpath, "rt");
  if (!infile) {
    fprintf(stderr, "compile-cgs: %s: %s\n", inpath, strerror(errno));
    exit(1);
  }

  outfile = fopen(TEMPFILE, "wt");
  if (!outfile) {
    fprintf(stderr, "compile-cgs: %s: %s\n", TEMPFILE, strerror(errno));
    exit(1);
  }

  fprintf(outfile, "/* Automatically generated; do not edit */\n\n");

  cgbigen();
  if (PCB.exit_flag != AG_SUCCESS_CODE) {
    exit(1);
  }

  emittable();

  fclose(outfile);
  fclose(infile);

  rename(TEMPFILE, outpath);
}

int main(int argc, char *argv[]) {
  if (argc != 3) {
    fprintf(stderr, "Usage: compile-cgs input-file output-file\n");
    exit(1);
  }

  compile(argv[1], argv[2]);
  return 0;
}

}

[
  default token type = void
  //error trace
  line numbers
  line numbers path = "cgbigen.syn"
]

eof = -1
range = 0..255
blank = ' ' + '\t'
cr = '\r'
nl = '\n'
textchar = range - cr - nl
namechar = textchar - blank - ';' - ','

//////////////////////////////

(void) file $
 -> blank lines?, block..., eof

(void) block
 -> title line,
    body line?...,
    "##", blank lines? = fudgenewlines(), emitbody(getstr());

(void) title line
 -> titles, comment?, newline

//////////////////////////////

(void) titles
 -> title
 -> titles, ',', blank?..., [comment?, newline, blank?...], title

(void) title
 -> name, blank?...  = emittitle(getstr());

(void) name
 -> namechar:c                      = addstr(c);
 -> name, namechar:c                = addstr(c);
 -> name, blank..., namechar:c      = addstr(' '), addstr(c);

//////////////////////////////

(void) body line
 -> newline                   = addstr('\n');
 -> text, newline             = addstr('\n');

(void) text
 -> textchar:c       = addstr(c);
 -> text, textchar:c = addstr(c);

//////////////////////////////

(void) comment
 -> {';' | "//"}, textchar...

(void) newline
 -> cr?, nl

(void) blank lines
 -> blank line...

(void) blank line
 -> blank?..., newline