view src/buildkeywordtab.c @ 123:5681cdada362

Redo keyword table handling to handle keywords differing in length Some keywords differ only due to length. That is, the shorter keyword matches the leading characters of the longer one. Make the keyword table builder and processor handle these cases. Also re-implement the handler based on evolved understanding of its requirements.
author William Astle <lost@l-w.ca>
date Mon, 01 Jan 2024 15:15:45 -0700
parents 5d5472b11ccd
children 8770e6f977c3
line wrap: on
line source

/*
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;
};

/*
lookaheaddepth will start at 255 and count down which gives an appropriate
two's complement negative number.
*/

int treedepth = 0;
void print_tree(FILE *fp, struct treenode *tn, char *lookahead, int lookaheaddepth)
{
    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)
    {
        // if there are child nodes, insert the sub tree
        if (tn1 -> firstchild)
        {
            fprintf(fp, " fcb 0x%02x,token_eot\n", tn1 -> ccode);
            if (tn1 -> toksym)
            {
                print_tree(fp, tn1, tn1 -> toksym, 255);
            }
            else
            {
                if (lookahead)
                {
                    print_tree(fp, tn1, lookahead, lookaheaddepth - 1);
                }
                else
                {
                    print_tree(fp, tn1, NULL, 0);
                }
            }
        }
        // if there is also a terminal symbol here
        if (tn1 -> toksym)
        {
            fprintf(fp, " fcb 0x%02x,%s\n", tn1 -> ccode, tn1 -> toksym);
        }
    }
    // handle lookahead failure
    if (lookahead)
    {
        fprintf(fp, " fcb 0x%02x,%s\n", lookaheaddepth, lookahead);
    }
    
    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, " *pragmapush list\n *pragma list\n");
    fprintf(outfile, "parse_wordtab\n");    
    print_tree(outfile, treeroot, NULL, 0);
    fprintf(outfile, " *pragmapop list\n");
    fclose(outfile);
    exit(0);
}