diff src/buildkeywordtab.c @ 121:5d5472b11ccd

Initital skeleton of separation of separate parsing scheme This is the first commit in a long series related to separating the parsing of the input code from the execution of the code. It should allow for more efficient, and probably simpler, execution while giving quicker feedback when someone types in syntactically invalid code.
author William Astle <lost@l-w.ca>
date Sun, 31 Dec 2023 17:44:39 -0700
parents
children 5681cdada362
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/buildkeywordtab.c	Sun Dec 31 17:44:39 2023 -0700
@@ -0,0 +1,122 @@
+/*
+Build the keyword parse table for lwbasic
+*/
+
+#define _POSIX_C_SOURCE 200809L // for getline()
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct treenode
+{
+    int ccode;
+    char *toksym;
+    struct treenode *nextsibling;
+    struct treenode *firstchild;
+};
+
+int treedepth = 0;
+void print_tree(FILE *fp, struct treenode *tn)
+{
+    struct treenode *tn1;
+    int depth = ++treedepth;
+    
+    fprintf(fp, "parse_wt%d fdb parse_wt%de-parse_wt%d-2\n", depth, depth, depth);
+
+    for (tn1 = tn -> firstchild; tn1; tn1 = tn1 -> nextsibling)
+    {
+        fprintf(fp, " fcb 0x%02x,%s\n", tn1 -> ccode, tn1 -> toksym ? tn1 -> toksym : "token_eot");
+        if (tn1 -> firstchild)
+            print_tree(fp, tn1);
+    }
+    
+    fprintf(fp, "parse_wt%de\n", depth);
+}
+
+int main(int argc, char **argv)
+{
+    FILE *infile, *outfile;
+    struct treenode *treeroot;
+    struct treenode *tnp, *tn, *tnprev;
+    char *linebuf = NULL;
+    size_t bufsize = 0;
+    ssize_t rval;
+    char *ptr, *ptr2;
+
+    if (argc != 3)
+    {
+        fprintf(stderr, "Usage: %s <source> <output>\n", argv[0]);
+        exit(1);
+    }
+
+    infile = fopen(argv[1], "rb");
+    if (!infile)
+    {
+        perror("Opening input file");
+        exit(1);
+    }
+    
+    treeroot = calloc(1, sizeof(struct treenode));
+    while (1)
+    {
+        rval = getline(&linebuf, &bufsize, infile);
+        if (rval == -1)
+        {
+            if (feof(infile))
+                break;
+            perror("Reading keyword list line");
+            fclose(infile);
+            if (linebuf) free(linebuf);
+            exit(1);
+        }
+        ptr = linebuf + rval - 1;
+        // lose any line terminators
+        while (*ptr == '\r' || *ptr == '\n')
+            *ptr-- = '\0';
+        ptr = strchr(linebuf, ',');
+        if (!ptr)
+        {
+            fprintf(stderr, "WARNING: malformed input line\n");
+            continue;
+        }
+        *ptr++ = '\0'; // put a NUL break in
+        tnp = treeroot;
+        for (ptr2 = linebuf; *ptr2; ptr2++)
+        {
+            for (tn = tnp -> firstchild, tnprev = NULL; tn; tn = tn -> nextsibling)
+            {
+                if (tn -> ccode == *ptr2)
+                    break;
+                tnprev = tn;
+            }
+            if (!tn)
+            {
+                tn = calloc(1, sizeof(struct treenode));
+                tn -> ccode = *ptr2;
+                if (!*(ptr2 + 1))
+                    tn -> toksym = strdup(ptr);
+                if (tnprev)
+                    tnprev -> nextsibling = tn;
+                else
+                    tnp -> firstchild = tn;
+                fprintf(stderr, "Create entry: %c, %s\n", tn -> ccode, tn -> toksym);
+            }
+            tnp = tn;
+        }
+    }
+    fclose(infile);
+
+    outfile = fopen(argv[2], "wb");
+    if (!outfile)
+    {
+        perror("Opening output file");
+        exit(1);
+    }
+    fprintf(outfile, "; This file is automatically generated. Edit %s and rebuild to make changes.\n", argv[1]);
+    fprintf(outfile, "parse_wordtab\n");    
+    print_tree(outfile, treeroot);
+
+    fclose(outfile);
+    exit(0);
+}