head	1.4;
access;
symbols;
locks
	gtoal:1.4; strict;
comment	@ * @;


1.4
date	2022.02.19.02.47.29;	author gtoal;	state Exp;
branches;
next	1.3;

1.3
date	2022.02.18.19.26.43;	author gtoal;	state Exp;
branches;
next	1.2;

1.2
date	2022.02.18.19.24.42;	author gtoal;	state Exp;
branches;
next	1.1;

1.1
date	2022.02.13.07.49.51;	author gtoal;	state Exp;
branches;
next	;


desc
@Generate body of compile() procedure from data in grammar tables
@


1.4
log
@*** empty log message ***
@
text
@#include <stdio.h>
#include <stdlib.h>

#define WANT_COMMENT 1
#define DEBUG_PARSER 1
#define WANT_SEMANTIC_TABLE 1
#include TABLE                  // "parser-*.h"

#ifndef SEMANTIC_NAME
// There was no semantic table in the header file, despite the programmer asking for it above!
#undef WANT_SEMANTIC_TABLE
#endif

#ifndef WANT_SEMANTIC_TABLE
#define SEMANTIC 0
#endif

void escape (FILE * out, char *s) {
  while (*s != '\0') {
  int c = *s++;

    if ((c == '\\') || (c == '\"'))
      fputc ('\\', out);
    fputc (c, out);
  }
}

#define NO_WHITESPACE_PHRASES 1

// Reconstitute grammar from tables.
// Parsing code will be very similar, except recursing from PHRASE_BASE
// rather than scanning sequentially from there.

char *uline (char *s) {
  static char T[128];
  char *tp = T;
  int c;
  *tp = '\0';
  if (s == NULL) return T;
  for (;;) {
    c = *s++;
    if (c == '-')
      c = '_';
    *tp++ = c;
    if (c == '\0')
      return T;
  }
}

#define DROP_SPECIAL_BITS ((1<<29)-1)
#define NEGATED_PHRASE (1<<29)
#define OPTIONAL_PHRASE (1<<30)
#define MAX_PHRASES 1024
#define WHITESPACE (MAX_PHRASES-1)

void walk (int p) {
  int gp, i, alts, altno, this_phrase = p;
  int savegp = gp, savep = p;

  if (p == AST_EOF) {
    fprintf (stdout, "    case AST_EOF:\n");
#ifdef WANT_COMMENT
    if (comment[p]) {
      int lastch = '\n';
      char *s = comment[p];

      while (*s != '\0') {
        if (lastch == '\n')
          fprintf (stdout, "      //\\\\ # %c", *s);
        else
          fprintf (stdout, "%c", *s);
        lastch = *s++;
      }
    }
#endif
    fprintf (stdout, "      break;\n");
  } else if (p < MAX_BIP) {
#ifdef WANT_COMMENT
    if (comment[p]) {
      int lastch = '\n';
      char *s = comment[p];

      while (*s != '\0') {
        if (lastch == '\n')
          fprintf (stdout, "    //\\\\ # %c", *s);
        else
          fprintf (stdout, "%c", *s);
        lastch = *s++;
      }
    }
#endif
    fprintf (stdout, "    case AST_%s: //\\\\ B<%s> = %d;\n", uline(phrasename[p]), phrasename[p], BIP[p]);
    fprintf (stdout, "      RECONSTITUTE(A[A_child[1]+A_literal_offset], stdout);\n");
    fprintf (stdout, "      break;\n");
  } else if (p < AST__LIT) {
    gp = phrase_start[p - MAX_BIP];
#ifdef WANT_COMMENT
    if (comment[p]) {
      int lastch = '\n';
      char *s = comment[p];

      while (*s != '\0') {
        if (lastch == '\n')
          fprintf (stdout, "    //\\\\ # %c", *s);
        else
          fprintf (stdout, "%c", *s);
        lastch = *s++;
      }
    }
#endif
    {int len;
      fprintf (stdout, "    case AST_");
      len = fprintf (stdout, "%s:", uline(phrasename[p]));
      for (i = 0; i < 20-len; i++) fprintf (stdout, "%c", ' ');
    }
    fprintf (stdout, "//\\\\ P<%s> =\n", phrasename[p]);
    alts = gram[gp];
    gp++;                       // gp now points to first element (length) of first alt
    fflush (stdout);
    for (i = 0; i < alts; i++) {
      int each, phrases = gram[gp++];

      // without this unused parameter here, the output file is seriously corrupted!:
      if (i == 0)
        fprintf (stdout, "      if (alt == 0) {       ");
      else {
        fprintf (stdout, "\n");
        fprintf (stdout, "      } else if (alt == %0d) {", i);
      }
      fprintf (stdout, "     //\\\\  ");
      if (phrases == 0) fprintf (stdout, " ");
      for (each = 0; each < phrases; each++) {
        int phrase = gram[gp] & DROP_SPECIAL_BITS;
        int optional_phrase = gram[gp] & OPTIONAL_PHRASE;
        int negated_phrase = gram[gp] & NEGATED_PHRASE;

        if (phrase < 256) {
          fprintf (stdout, " '%s%c'", phrase == '\'' ? "'" : "", phrase);
        } else if (phrase < 512) {
          fprintf (stdout, " \"%s\"", keyword[phrase - 256]);
        } else if (phrase < 512 + MAX_BIP) {
          fprintf (stdout, " <");
          if (optional_phrase)
            fprintf (stdout, "?");
          if (negated_phrase)
            fprintf (stdout, "!");
          fprintf (stdout, "%s>", phrasename[phrase - 512]);
#ifdef WANT_SEMANTIC_TABLE
        } else if ((phrase) >= SEMANTIC) {
          // SEMANTIC PHRASE
          fprintf (stdout, " <%s%s:", optional_phrase ? "?" : negated_phrase ? "!" : "", SEMANTIC_NAME);
          escape (stdout, semantic_code[phrase - SEMANTIC]);
          fprintf (stdout, ">");
#endif
        } else {
          if (phrase != WHITESPACE) {
            fprintf (stdout, " <");
            if (optional_phrase)
              fprintf (stdout, "?");
            if (negated_phrase)
              fprintf (stdout, "!");
            fprintf (stdout, "%s>", phrasename[phrase - 512]);
          }
        }
        gp++;                   // move over element
        fflush (stdout);
      }
      if (i+1 == alts) fprintf (stdout, ";"); else fprintf (stdout, ",");
      // gp now points to first element (length) of next alt, or start of next phrase
    }
    fprintf (stdout, "\n");
    fprintf (stdout, "      }\n");
    fprintf (stdout, "      for (i = 1; i <= count; i++) compile(nthchild(astp,i));\n");
    fprintf (stdout, "      break;\n");

  } else {
    if (p == AST__KW) {
      fprintf (stdout, "    case AST__KW:\n");
      fprintf (stdout, "      for (i = A_child[1]; i < A_child[1]+A_child[2]; i++) {\n");
      fprintf (stdout, "        // fprintf(stdout, \"%%s\", String(i));\n");
      fprintf (stdout, "        RECONSTITUTE(i, stdout);\n");
      fprintf (stdout, "      }\n");
      fprintf (stdout, "      break;\n\n");
    } else if (p == AST__LIT) {
      fprintf (stdout, "    case AST__LIT:\n");
      fprintf (stdout, "      RECONSTITUTE(A[A_child[1]+A_literal_offset], stdout);\n");
      fprintf (stdout, "      break;\n\n");
    } else {
      // fprintf (stdout, "    case AST_%s: /* LIT or KW */\n", uline(phrasename[p]));
    }
  }

  fprintf (stdout, "\n");
}

int main (int argc, char **argv) {
  int i;

  fprintf (stdout, "\n");
  fprintf (stdout, "// compile: this is a skeleton that is built once from the final grammar,\n");
  fprintf (stdout, "//          and modified by the programmer to do whatever the program needs to do.\n");
  fprintf (stdout, "//\n");
  fprintf (stdout, "//          The baseline is simply to re-output the initial input, but obviously\n");
  fprintf (stdout, "//          a real implementation would do something more complex, such as indentation\n");
  fprintf (stdout, "//          and formatting (e.g. like SOAP), or conversion into another language\n");
  fprintf (stdout, "//          such as C, or even to create a real compiler.\n");
  fprintf (stdout, "//\n");
  fprintf (stdout, "//          If all you are doing is re-outputing the original source, this code is\n");
  fprintf (stdout, "//          way overkill.  A 20-line version would do the same job.\n");
  fprintf (stdout, "//\n");
  fprintf (stdout, "//          You would typically *not* re-create this file automatically in your Makefile...\n");
  fprintf (stdout, "//          Remember to edit this comment once you get to the stage where you are\n");
  fprintf (stdout, "//          maintaining this procedure manually...\n");
  fprintf (stdout, "//\n\n");
  fprintf (stdout, "void compile(int astp) {\n");
  fprintf (stdout, "  int i;\n");
  fprintf (stdout, "  // These offsets are a poor man's struct:\n");
  fprintf (stdout, "  // Offsets in the A record are different from offsets in the AST.\n");
  fprintf (stdout, "\n");
  fprintf (stdout, "  // A record offsets:\n");
  fprintf (stdout, "#define A_literal_offset 3\n");
  fprintf (stdout, "\n");
  fprintf (stdout, "  // AST offsets:\n");
  fprintf (stdout, "#define AST_op_offset 1\n");
  fprintf (stdout, "#define AST_alt_offset 2\n");
  fprintf (stdout, "#define AST_count_offset 3\n");
  fprintf (stdout, "// Any new fixed fields (such as a pointer to the text) would be inserted here.\n");
  fprintf (stdout, "// Please do not ever write code with absolute offsets!\n");
  fprintf (stdout, "#define AST_child0_offset 4\n"); // NOTE: we number children from 1.  There is actually a child(0) which contains redundant information (T[0])
  fprintf (stdout, "\n");
  fprintf (stdout, "  if (astp < 0) {\n");
  fprintf (stdout, "    return; // -phrase denotes an optional item we don't want to print when reconstituting the source\n");
  fprintf (stdout, "    // Not an ideal mechanism. May change it later to add optional bits to 'op' field.\n");
  fprintf (stdout, "  }\n\n");
  fprintf (stdout, "\n");
  fprintf (stdout, "  int astop = AST[astp+AST_op_offset];\n");
  fprintf (stdout, "  int alt = AST[astp+AST_alt_offset];\n");
  fprintf (stdout, "  int count = AST[astp+AST_count_offset];\n");
  fprintf (stdout, "  int *A_child = &AST[astp+AST_child0_offset]; // An index into a child of the AREC, *not* a child of the AST.\n");
  fprintf (stdout, "\n");
  fprintf (stdout, "// Must use these macros for children of the AST, in case new fields are added.\n");
  fprintf (stdout, "#define leftchild(p) AST[(p)+AST_child0_offset+(1-1)]\n");
  fprintf (stdout, "#define rightchild(p) AST[(p)+AST_child0_offset+(2-1)]\n");
  fprintf (stdout, "#define nthchild(p,i) AST[(p)+AST_child0_offset+((i)-1)]\n");
  fprintf (stdout, "\n");

#if defined(WANT_SEMANTIC_TABLE) && defined(SEMANTIC_NAME)
  fprintf(stdout, "\n//\\\\ C<%s>", SEMANTIC_NAME);
  if (*SEMANTIC_HEADER != '\0') {
    char *p = SEMANTIC_HEADER;
    fprintf(stdout, " = {");
    while (*p != '\0') {
      fprintf(stdout, "%c", *p);
      if (*p == '\n') fprintf(stdout, "//\\\\ ");
      p++;
    }
    fprintf(stdout, "}");
  }
  fprintf(stdout, ";\n\n");
#endif
  
  
  fprintf (stdout, "  switch (astop) {\n");
  for (i = 0; i <= AST__KW; i++) {
    walk (i);
  }
  fprintf (stdout, "    default: \n");
  fprintf (stdout, "      for (i = 1; i <= count; i++) compile(nthchild(astp,i));\n");
  fprintf (stdout, "      break;\n");
  fprintf (stdout, "  }\n");
  fprintf (stdout, "}\n");
  exit (0);
}
@


1.3
log
@removed old code
@
text
@d231 5
a245 5
  fprintf (stdout, "  if (astp < 0) {\n");
  fprintf (stdout, "    return; // -phrase denotes an optional item we don't want to print when reconstituting the source\n");
  fprintf (stdout, "    // Not an ideal mechanism. May change it later to add optional bits to 'op' field.\n");
  fprintf (stdout, "  }\n\n");

@


1.2
log
@cleaned up symbolic offsets in case new fields are added at AST record.
@
text
@a3 2
//#define ORIGINAL_CHILDREN 1

a92 3
#ifdef ORIGINAL_CHILDREN
    fprintf (stdout, "      RECONSTITUTE(A[arg[1]+3], stdout);\n");
#else
a93 1
#endif
a172 3
#ifdef ORIGINAL_CHILDREN
    fprintf (stdout, "      for (i = 1; i <= count; i++) compile(AST[astp+3+i]);\n");
#else
a173 1
#endif
a178 3
#ifdef ORIGINAL_CHILDREN
      fprintf (stdout, "      for (i = arg[1]; i < arg[1]+arg[2]; i++) {\n");
#else
a179 1
#endif
a185 3
#ifdef ORIGINAL_CHILDREN
      fprintf (stdout, "      RECONSTITUTE(A[arg[1]+3], stdout);\n");
#else
a186 1
#endif
a216 6
#ifdef ORIGINAL_CHILDREN
  fprintf (stdout, "  int astop = AST[astp+1];\n");
  fprintf (stdout, "  int alt = AST[astp+2];\n");
  fprintf (stdout, "  int count = AST[astp+3];\n");
  fprintf (stdout, "  int *arg = &AST[astp+4];\n"); // AHA!!! NOT 3
#else
a234 1
#endif
a235 1
#ifndef ORIGINAL_CHILDREN
a240 1
#endif
a267 3
#ifdef ORIGINAL_CHILDREN
  fprintf (stdout, "      for (i = 1; i <= count; i++) compile(AST[astp+3+i]);\n");
#else  
a268 1
#endif
@


1.1
log
@Initial revision
@
text
@d4 2
d12 1
d95 1
d97 3
d154 1
a154 1
#ifdef WANT_SEMANTIC
d179 1
d181 3
d189 1
d191 3
d200 1
d202 3
d235 1
d239 21
a259 1
  fprintf (stdout, "  int *arg = &AST[astp+4];\n");
d261 7
d272 18
d295 1
d297 3
@
