#!/usr/bin/icmake -qt/tmp/grambuild

string
    target;
list
    startrulegr,
    rules,
    components;
int
    addLineDirectives;

int openblock(string line)
{
    int idx;
    string ch;

    for (idx = strlen(line); idx--; )       // from the last to the first
    {
        ch = element(idx, line);
        if (strfind(" \t\n{", ch) == -1)    // not a ws or open curly
            return 0;                       // not a C++ compound stmnt
        if (ch == "{")                      // open curly
            return 1;                       // then C++ compound stmnt starts
    }
    return 0;
}

void catlines(int offset, string file)
{
    list result;

    while (sizeof(result = fgets(file, offset)))
    {
        offset = (int)element(1, result);
        fprintf(target, element(0, result));
    }    
}


void catfile(string file)
{
    int linenr;
    int offset;
    list result;
    string line;

    printf(file + " >> " + target + "\n");

    linenr = 1;
    offset = 0;

    if (!addLineDirectives)
        catlines(0, file);
    else
    {
        while (sizeof(result = fgets(file, offset)))
        {
            linenr++;
            line = element(0, result);
            offset = (int)element(1, result);
    
            fprintf(target, line);
            if (openblock(line))
            {
                fprintf(target, "#line ", linenr, "  \"", file, "\"\n");
                catlines(offset, file);
                break;
            }    
        }
    }
    fprintf(target, "\n\n");
}

void cat(list parts)
{
    int
        idx,
        n;

    n = sizeof(parts);

    for (idx = 0; idx < n; ++idx)
        catfile(element(idx, parts));
}

int update()
{
    system("echo > " + target);     // refresh the target

    cat(components);

    system("echo '%%' >> " + target);

    cat(startrulegr);
    cat(rules);
    return 0;
}

int inspect(list parts)
{
    int
        idx,    
        n;

    n = sizeof(parts);

    for (idx = 0; idx < n; ++idx)
    {
        if (element(idx, parts) younger target)
        {
            update();
            return 1;
        }
    }
    return 0;
}

int main(int argc, list argv)
{
//    system("ln -sf gramspec/grammar ..");

    addLineDirectives = argc > 1;

    startrulegr = (list)"startrule.gr0";
    rules = makelist("*.gr");

    components = makelist("*.gr0") - startrulegr - (list)"header.gr0";
    components = (list)"header.gr0" + components;

    target = "../grammar";

    if (!exists(target))
        return update();

    if (!inspect(components) && !inspect(startrulegr))
        inspect(rules);

    return 0;
}
