Implementation

Once you generate your parser you can use it as a part of you project. It can be used with any C/C++ compiler that supports C11 syntax. The code is compatible with both Linux and Windows.

You can generate the parser as single file or multiple files. By default, the parser includes a main function (for demo purposes), machine code (runs the parser) and program code (defines the parser) or JSON file for the program a long with code in the machine to read it. You can exclude the main and the machine code from the generation. Declarations are included inside the source file by default but you can generate a separate header file if you want.

You can generate multiple parsers (as programs) and use a single machine to run all of them.

The generated program is stored as a struct AlgodalParser_Program. It is normally in the name of the parser such as struct AlgodalParser_Program ParserProgram;. To parse the text using your parser program, just simply call AlgodalParser_ParsedData pd = AlgodalParser_ParseText(ParserProgram, text, length);. You can call AlgodalParser_PrintParsedData(ParserProgram); to see the result of the parsing. Then use functions like the AlgodalParser_IsNodeKey to manipulate the AST to get the information you need. Please not the AST doesn’t allocate any string. It refers (points to the text string) you passed to AlgodalParser_ParseText. So do not free that text until you are done with the AST manipulation. Take a look at the API reference to see the various APIs at your disposal.

Here is an example from out int parser. You can see more examples at https://github.com/Algodal/Parser-Generator-Tool-PR/tree/main/examples.

main.c shows how a user of the parser is expected to make use of it.

#include "algodal-parser-header.h"

extern AlgodalParser_Program IntParserProgram; //generated in IntParser.c

static char *ReadFile(const char *name, unsigned int *sizeOfFile)
{
    FILE* fp = fopen(name, "rb");
    if(fp)
    {
        fseek(fp, 0, SEEK_END);
        const size_t length = ftell(fp);
        fseek(fp, 0, SEEK_SET);
        char *text = malloc(length + 1);
        text[length] = 0;
        (void)fread(text, 1, length, fp);
        fclose(fp);
        if(sizeOfFile) *sizeOfFile = length;
        return text;
    }
    cwpc_printf("FAILED TO OPEN FILE %s\n", name);
    return 0;
}

static int NodeToNumber(AlgodalParser_Ast ast, AlgodalParser_Node* node)
{
    char buf[1024] = {0};
    AlgodalParser_GetNodeValue(ast, node, buf);
    return strtol(buf, 0, 10);
}

static int CalculateExprValue(AlgodalParser_Ast ast, AlgodalParser_Node* node)
{
    //Here we will demonstrate AST manipulation
    //At the root, we expect `line `.  The first child will always be integer
    //followed by series of one of `multiply`, `add`, `divide` or `substract`.
    //Each of which follows the same pattern for it's children.
    //Therefore, we can use a simple loop for each.

    int result = NodeToNumber(ast, node->children.addr[0]);
    //based on AST, the first child will always be of type `integer`

    for(uint32_t i = 1; i < node->children.size; i++)
    {
        AlgodalParser_Node* child = node->children.addr[i];

        if(AlgodalParser_IsNodeKey(ast, 0, "multiply", child))
        {
            result *= CalculateExprValue(ast, child);
        }
        else
        if(AlgodalParser_IsNodeKey(ast, 0, "divide", child))
        {
            result /= CalculateExprValue(ast, child);
        }
        else
        if(AlgodalParser_IsNodeKey(ast, 0, "add", child))
        {
            result += CalculateExprValue(ast, child);
        }
        else
        if(AlgodalParser_IsNodeKey(ast, 0, "subtract", child))
        {
            result -= CalculateExprValue(ast, child);
        }
    }
    return result;
}

int main(int argc, char* argv[])
{
    if(argc > 1)
    {
        unsigned int length = 0;
        char* text = ReadFile(argv[1], &length);
        AlgodalParser_ParsedData pd = AlgodalParser_ParseText(IntParserProgram, text, length);
        //AlgodalParser_PrintParsedData(pd); //to view the tokens and AST
        for(uint32_t i = 0; i < pd.ast.nodes.size; i++)
        {
            char buf[1024] = {0}; //for demo purposes just using a big enough size but can allocate exact size
            printf(
                "%s = %d\n",
                AlgodalParser_GetNodeValueSimplified(pd.ast, pd.ast.nodes.addr[i], buf),
                CalculateExprValue(pd.ast, pd.ast.nodes.addr[i])
            );
        }
        AlgodalParser_DestroyParsedData(pd);
        free(text); //only free this after you are done with the parsed data
    }
    else
    {
        printf("Pass file to parse\n");
    }
    return 0;
}