view src/buildkeywordtab.c @ 124:8770e6f977c3

Rework parser to use parse_wordtab for symbols too There's no reason not to use the parse_wordtab table thing to match the symbols with their token codes. It takes less space than the combined code and tables to do it separately.
author William Astle <lost@l-w.ca>
date Mon, 01 Jan 2024 15:57:59 -0700
parents 5681cdada362
children ac183a519439
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, '\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);
}