def parse_prototype(sigparser, decl, prototypes):
    """Get the C++ prototype for a given function declaration."""
    # poor man's scanner :-)
    tokens = re.sub(r'[,()]', lambda m: ' ' + m.group(0) + ' ', decl).split()

    tokens, ret_type = sigparser.get_type(tokens)

    name = tokens[0]

    if tokens[1] != '(':
        error("unknown token '" + tokens[1] + "' while processing '" + decl +
              "': '(' expected")
        sys.exit(1)

    tokens = tokens[2:]

    params = []

    if tokens[0] != ')':
        while True:
            tokens, t = sigparser.get_type(tokens)
            paramname = tokens[0]
            tokens = tokens[1:]

            if tokens[0] == '=':
                # default argument
                defarg, tokens = eat_until({',': None, ')': None}, tokens[1:])
            else:
                defarg = []

            params.append((t, paramname, ''.join(defarg)))

            if tokens[0] == ')':
                break
            if tokens[0] != ',':
                error("unknown token '" + tokens[1] + "' while processing '" +
                      decl + "': ',' expected")
                sys.exit(1)
            # skip the comma
            tokens = tokens[1:]

    # For array returns, add one pointer parameter per array element
    if "[" in ret_type:
        match = re.match("([^[]+)\[(\d+)\]", ret_type)
        if match:
            elem_type = match.group(1)
            num_elems = int(match.group(2))
            for i in range(num_elems):
                params.append((elem_type + "*", "res_%d" % i, []))
            ret_type = "void"

    prototype = "%s %s(%s);" % (ret_type, name, ", ".join(
        map(format_param, params)))
    if "[" in ret_type or name == "transpose" or "[<N>]" in prototype:
        prototype = "// %s  (not supported yet)" % prototype
    prototypes.append(prototype)
def main(args):
    """Process one file and generate signatures."""
    if len(args) != 3:
        return usage(args)

    stdlib_dir = args[1]
    out_name = args[2]
    strict = True

    prototypes = []

    # monkey patch SignatureParser to generate signature names suitable for C++ header files
    SignatureParser.get_signature = (
        lambda self, decl: parse_prototype(self, decl, prototypes))

    try:
        parser = SignatureParser(args[0], stdlib_dir, out_name, strict)

        # copy the copyright from first 3 lines of state.cpp
        state_cpp_path = os.path.join(os.path.dirname(out_name), "state.cpp")
        with open(state_cpp_path) as f:
            copyright = "".join([next(f) for x in xrange(3)])

        with open(out_name, "w") as f:
            parser.write(f, copyright)
            parser.write(
                f, "\n#ifndef MDL_USER_MODULES_MDL_RUNTIME_H\n"
                "#define MDL_USER_MODULES_MDL_RUNTIME_H\n")

            for module_name in ["math", "debug"]:
                # clear list before parsing next module
                del prototypes[:]

                parser.parse(module_name)

                parser.write(f, "\nnamespace %s\n" % module_name)
                parser.write(f, "{\n")
                parser.indent += 1
                for prototype in prototypes:
                    print_wrapped(parser, f, prototype)
                parser.indent -= 1
                parser.write(f, "}\n")

            parser.write(f, "\n#endif  // MDL_USER_MODULES_MDL_RUNTIME_H\n")

    except Exception as e:
        error(str(e))
        return 1
    return 0
def parse_prototype(sigparser, decl, prototypes):
    """Get the C++ prototype for a given function declaration."""
    # poor man's scanner :-)
    tokens = re.sub(r'[,()]', lambda m: ' ' + m.group(0) + ' ', decl).split()

    tokens, ret_type = sigparser.get_type(tokens)

    name = tokens[0]

    if tokens[1] != '(':
        error("unknown token '" + tokens[1] + "' while processing '" + decl +
              "': '(' expected")
        sys.exit(1)

    tokens = tokens[2:]

    params = []

    if tokens[0] != ')':
        while True:
            tokens, t = sigparser.get_type(tokens)
            paramname = tokens[0]
            tokens = tokens[1:]

            if tokens[0] == '=':
                # default argument
                defarg, tokens = eat_until({',': None, ')': None}, tokens[1:])
            else:
                defarg = []

            params.append((t, paramname, ''.join(defarg)))

            if tokens[0] == ')':
                break
            if tokens[0] != ',':
                error("unknown token '" + tokens[1] + "' while processing '" +
                      decl + "': ',' expected")
                sys.exit(1)
            # skip the comma
            tokens = tokens[1:]

    ret_type = type_map.get(ret_type, ret_type)

    prototype = "%s %s(%s);" % (ret_type, name, ", ".join(
        map(format_param, params)))
    if "[" in ret_type or name == "transpose" or "[<N>]" in prototype or "color " in prototype:
        prototype = "// %s  (not supported yet)" % prototype
    prototypes.append(prototype)