view src/buildkeywordtab.c @ 126:ac183a519439

Update parsing scheme with a keyword lookup by token value and other framework Add ability to turn a token code into a keyword string. Also correct some details related to token table generation with some additiona adjustments for token symbols. Also rework token symbol definitions and creation of some parsing tables as well as the main statement parsing loop.
author William Astle <lost@l-w.ca>
date Mon, 08 Jan 2024 22:58:08 -0700
parents 8770e6f977c3
children 5d4801c0566d
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\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, '\t');
        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;
            }
            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_wt\n");    
    print_tree(outfile, treeroot, NULL, 0);
    fprintf(outfile, " *pragmapop list\n");
    fclose(outfile);
    exit(0);
}