#!/usr/bin/awk -f

# Generic preprocessor inspired by the GNU Assembler preprocessor.
#
# Written by Stone Horse. Public domain.

function dirname(path) {
    if (path ~ /\//)
        sub(/\/[^\/]*$/, "", path)
    else
        path = "."
    return path
}

function evaluate(wd, file_name,   array, cmd) {
    gsub(/__FILE__/, sprintf("\"%s\"", file_name))
    if ($0 !~ /^#[a-z]/) {
        if (include == 1) {
            for (name in symtab)
                gsub(name, symtab[name], $0)
            if ($0 ~ /\\$/) {
                sub(/\\$/, "", $0)
                printf($0)
            } else {
                print($0)
            }
        }
        return
    }
    split(substr($0, 2), array)
    if (array[1] == "include") {
        if (include == 0)
            return
        if (array[2] == "") {
            print("Error: missing string") > "/dev/stderr"
            exit(1)
        }
        gsub(/\"/, "", array[2])
        cmd = sprintf("stat %s/%s/%s > /dev/null 2>&1", include_path, wd, array[2])
        status = system(cmd)
        if (status != 0) {
            printf("Error: can't open %s for reading: No such file or directory\n", array[2]) > "/dev/stderr"
            exit(1)
        }
	cmd = sprintf("cat %s/%s/%s", include_path, wd, array[2])
        parent_directory = dirname(array[2])
        file_name = array[2]
        sub(/\.nqh$/, "\.h", array[2])
        # Recurse
        while (cmd | getline)
            evaluate(parent_directory, array[2])
        close(cmd)
    } else if (array[1] == "set") {
        if (include == 0)
            return
        if (array[2] == "") {
            print("Error: expected symbol name") > "/dev/stderr"
            exit(1)
        }
        if (array[3] == "") {
            print("Error: missing expression") > "/dev/stderr"
            exit(1)
        }
	sub(array[1], "")
        sub(array[2], "")
        sub(/^#[[:space:]]*/, "")
	symtab[array[2]] = $0
    } else if (array[1] == "ifdef") {
        compare = 1
        if (!(array[2] in symtab))
            include = 0
    } else if (array[1] == "ifndef") {
        compare = 1
        if (array[2] in symtab)
            include = 0
    } else if (array[1] == "else") {
        if (compare != 1) {
            printf("Error: \"#else\" without matching \"#if\"\n") > "/dev/stderr"
            exit(1)
        }
        if (include == 1)
            include = 0
        else
            include = 1
    } else if (array[1] == "endif") {
        compare = 0
        include = 1
    } else {
        printf("Error: unknown directive: `#%s'\n", array[1]) > "/dev/stderr"
        exit(1)
    }
}

BEGIN {
    compare = 0
    include = 1
    include_path = "."
    if (ENVIRON["INCLUDE_PATH"])
        include_path = ENVIRON["INCLUDE_PATH"]
}

{
    evaluate(".", in_file)
}
