Login

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download | RSS feed

/* parser.c - source file parser library.

   This is free and unencumbered software released into the public domain.
   For more information, please refer to <http://unlicense.org>. */


#include "defs.h"

#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "debug.h"
#include "l_ifile.h"
#include "parser.h"

const struct
{
    char *name;
    unsigned syntax;
}
syntaxes[] =
{
    { "tasm", SYNTAX_TASM },
    { "sjasm", SYNTAX_SJASM },
    { NULL, 0 }
};

bool _str_to_syntax (const char *name, unsigned *syntax)
{
    unsigned i;
    for (i = 0; syntaxes[i].name; i++)
    {
        if (!strcmp (syntaxes[i].name, name))
        {
            *syntax = syntaxes[i].syntax;
            return true;
        }
    }
    return false;
}

bool _syntax_to_str (unsigned syntax, const char **name)
{
    unsigned i;
    for (i = 0; syntaxes[i].name; i++)
    {
        if (syntaxes[i].syntax == syntax)
        {
            *name = syntaxes[i].name;
            return true;
        }
    }
    return false;
}

const char *_skip_blanks (const char *s)
{
    if (s) while (*s != '\0' && isblank(*s)) s++;
    return s;
}

const char *_skip_word (const char *s)
{
    if (s)
    {
        if (*s == '_' || isalpha(*s))
        {
            s++;
            while (*s != '\0' && isalnum(*s)) s++;
        }
    }
    return s;
}

const char *_skip_string (const char *s)
{
    const char *p;
    p = s;
    if (p)
    {
        if (*p == '"')
        {
            p++;        // Skip opening double quote character
            while (*p != '\0' && *p != '"') p++;
            if (*p == '"')
                p++;    // Skip closing double quote character
            else
                p = s;  // Fail
        }
    }
    return p;
}

#define TEXT_BUF_SIZE 15
char get_include_tasm (const char *s, unsigned *flags, char **name)
{
    char st;
    char buf[TEXT_BUF_SIZE+1];
    const char *endp, *np;
    unsigned sl, nl;
    unsigned inc_flags;
    char *inc_name;

    st = PARST_SKIP;
    inc_name = (char *) NULL;

    if (!flags || !name)
        goto _error_exit;

    // RegEx pattern: [[:space:]]*include[[:space:]]+"[^[:space:]]+"
    // The rest of a line is not analized.

    // blanks
    endp = _skip_blanks (s);
    if (*endp == '\0')
        goto _skip_line;
    // assembler directive
    s = endp;
    endp = _skip_word (s);
    if (s == endp || *endp == '\0')
        goto _skip_line;
    // (save it)
    sl = endp - s;
    if (sl > TEXT_BUF_SIZE)
        sl = TEXT_BUF_SIZE;
    memcpy (buf, s, sl);
    buf[sl] = '\0';
    // (check it)
    if (!strcasecmp (buf, "include"))
        inc_flags = SRCFL_PARSE;
    else
        goto _skip_line;
    // blanks
    s = endp;
    endp = _skip_blanks (s);
    if (s == endp || *endp == '\0')
        goto _skip_line;
    // string
    s = endp;
    endp = _skip_string (s);
    if (s == endp)
        goto _skip_line;
    // (save it)
    np = s + 1;         // skip opening double quotes character
    nl = endp - s - 2;  // excluding double quotes characters
    inc_name = malloc (nl + 1); // including terminating zero
    if (!inc_name)
    {
        // Fail
        _perror ("malloc");
        goto _error_exit;
    }
    memcpy (inc_name, np, nl);
    inc_name[nl] = '\0';
    // (done)
    st = PARST_OK;
    *flags = inc_flags;
    *name = inc_name;
    goto _local_exit;

_skip_line:
    st = PARST_SKIP;
    goto _local_exit;

_error_exit:
    st = PARST_ERR;

_local_exit:
    if (st != PARST_OK)
    {
        if (inc_name)
            free (inc_name);
    }
    return st;
}
#undef TEXT_BUF_SIZE

#define TEXT_BUF_SIZE 15
char get_include_sjasm (const char *s, unsigned *flags, char **name)
{
    char st;
    char buf[TEXT_BUF_SIZE+1];
    const char *endp, *np;
    unsigned sl, nl;
    unsigned inc_flags;
    char *inc_name;

    st = PARST_SKIP;
    inc_name = (char *) NULL;

    if (!flags || !name)
        goto _error_exit;

    // RegEx pattern: [[:space:]]+(include|incbin)[[:space:]]+"[^[:space:]]+"
    // The rest of a line is not analized.

    // blanks
    endp = _skip_blanks (s);
    if (s == endp || *endp == '\0')
        goto _skip_line;
    // assembler directive
    s = endp;
    endp = _skip_word (s);
    if (s == endp || *endp == '\0')
        goto _skip_line;
    // (save it)
    sl = endp - s;
    if (sl > TEXT_BUF_SIZE)
        sl = TEXT_BUF_SIZE;
    memcpy (buf, s, sl);
    buf[sl] = '\0';
    // (check it)
    if (!strcasecmp (buf, "incbin"))
        inc_flags = 0;
    else if (!strcasecmp (buf, "include"))
        inc_flags = SRCFL_PARSE;
    else
        goto _skip_line;
    // blanks
    s = endp;
    endp = _skip_blanks (s);
    if (s == endp || *endp == '\0')
        goto _skip_line;
    // string
    s = endp;
    endp = _skip_string (s);
    if (s == endp)
        goto _skip_line;
    // (save it)
    np = s + 1;         // skip opening double quotes character
    nl = endp - s - 2;  // excluding double quotes characters
    inc_name = malloc (nl + 1); // including terminating zero
    if (!inc_name)
    {
        // Fail
        _perror ("malloc");
        goto _error_exit;
    }
    memcpy (inc_name, np, nl);
    inc_name[nl] = '\0';
    // (done)
    st = PARST_OK;
    *flags = inc_flags;
    *name = inc_name;
    goto _local_exit;

_skip_line:
    st = PARST_SKIP;
    goto _local_exit;

_error_exit:
    st = PARST_ERR;

_local_exit:
    if (st != PARST_OK)
    {
        if (inc_name)
            free (inc_name);
    }
    return st;
}
#undef TEXT_BUF_SIZE

const struct
{
    get_include_proc_t *proc;
    unsigned syntax;
}
include_procs[] =
{
    { get_include_tasm, SYNTAX_TASM },
    { get_include_sjasm, SYNTAX_SJASM },
    { NULL, 0 }
};

bool _find_get_include_proc (unsigned syntax, get_include_proc_t **proc)
{
    unsigned i;
    for (i = 0; include_procs[i].proc; i++)
    {
        if (include_procs[i].syntax == syntax)
        {
            *proc = include_procs[i].proc;
            return true;
        }
    }
    return false;
}