parse(FILE * fp, struct node *root)
{
#ifdef TEST
    extern void     xmalloc_stats(FILE *);
#endif
    char            token[MAXTOKEN];
    char            name[MAXTOKEN+1];
    int             type = LABEL;
    int             lasttype = LABEL;

#define BETWEEN_MIBS          1
#define IN_MIB                2
    int             state = BETWEEN_MIBS;
    struct node    *np, *nnp;
    struct objgroup *oldgroups = NULL, *oldobjects = NULL, *oldnotifs =
        NULL;

    DEBUGMSGTL(("parse-file", "Parsing file:  %s...\n", File));

    if (last_err_module)
        free(last_err_module);
    last_err_module = NULL;

    np = root;
    if (np != NULL) {
        /*
         * now find end of chain 
         */
        while (np->next)
            np = np->next;
    }

    while (type != ENDOFFILE) {
        if (lasttype == CONTINUE)
            lasttype = type;
        else
            type = lasttype = get_token(fp, token, MAXTOKEN);

        switch (type) {
        case END:
            if (state != IN_MIB) {
                print_error("Error, END before start of MIB", NULL, type);
                gMibError = MODULE_SYNTAX_ERROR;
                return NULL;
            } else {
                struct module  *mp;
#ifdef TEST
                printf("\nNodes for Module %s:\n", name);
                print_nodes(stdout, root);
#endif
                for (mp = module_head; mp; mp = mp->next)
                    if (mp->modid == current_module)
                        break;
                scan_objlist(root, mp, objgroups, "Undefined OBJECT-GROUP");
                scan_objlist(root, mp, objects, "Undefined OBJECT");
                scan_objlist(root, mp, notifs, "Undefined NOTIFICATION");
                objgroups = oldgroups;
                objects = oldobjects;
                notifs = oldnotifs;
                do_linkup(mp, root);
                np = root = NULL;
            }
            state = BETWEEN_MIBS;
#ifdef TEST
            if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
				   NETSNMP_DS_LIB_MIB_WARNINGS)) {
                /* xmalloc_stats(stderr); */
	    }
#endif
            continue;
        case IMPORTS:
            parse_imports(fp);
            continue;
        case EXPORTS:
            while (type != SEMI && type != ENDOFFILE)
                type = get_token(fp, token, MAXTOKEN);
            continue;
        case LABEL:
        case INTEGER:
        case INTEGER32:
        case UINTEGER32:
        case UNSIGNED32:
        case COUNTER:
        case COUNTER64:
        case GAUGE:
        case IPADDR:
        case NETADDR:
        case NSAPADDRESS:
        case OBJSYNTAX:
        case APPSYNTAX:
        case SIMPLESYNTAX:
        case OBJNAME:
        case NOTIFNAME:
        case KW_OPAQUE:
        case TIMETICKS:
            break;
        case ENDOFFILE:
            continue;
        default:
            strlcpy(name, token, sizeof(name));
            type = get_token(fp, token, MAXTOKEN);
            nnp = NULL;
            if (type == MACRO) {
                nnp = parse_macro(fp, name);
                if (nnp == NULL) {
                    print_error("Bad parse of MACRO", NULL, type);
                    gMibError = MODULE_SYNTAX_ERROR;
                    /*
                     * return NULL;
                     */
                }
                free_node(nnp); /* IGNORE */
                nnp = NULL;
            } else
                print_error(name, "is a reserved word", lasttype);
            continue;           /* see if we can parse the rest of the file */
        }
        strlcpy(name, token, sizeof(name));
        type = get_token(fp, token, MAXTOKEN);
        nnp = NULL;

        /*
         * Handle obsolete method to assign an object identifier to a
         * module
         */
        if (lasttype == LABEL && type == LEFTBRACKET) {
            while (type != RIGHTBRACKET && type != ENDOFFILE)
                type = get_token(fp, token, MAXTOKEN);
            if (type == ENDOFFILE) {
                print_error("Expected \"}\"", token, type);
                gMibError = MODULE_SYNTAX_ERROR;
                return NULL;
            }
            type = get_token(fp, token, MAXTOKEN);
        }

        switch (type) {
        case DEFINITIONS:
            if (state != BETWEEN_MIBS) {
                print_error("Error, nested MIBS", NULL, type);
                gMibError = MODULE_SYNTAX_ERROR;
                return NULL;
            }
            state = IN_MIB;
            current_module = which_module(name);
            oldgroups = objgroups;
            objgroups = NULL;
            oldobjects = objects;
            objects = NULL;
            oldnotifs = notifs;
            notifs = NULL;
            if (current_module == -1) {
                new_module(name, File);
                current_module = which_module(name);
            }
            DEBUGMSGTL(("parse-mibs", "Parsing MIB: %d %s\n",
                        current_module, name));
            while ((type = get_token(fp, token, MAXTOKEN)) != ENDOFFILE)
                if (type == BEGIN)
                    break;
            break;
        case OBJTYPE:
            nnp = parse_objecttype(fp, name);
            if (nnp == NULL) {
                print_error("Bad parse of OBJECT-TYPE", NULL, type);
                gMibError = MODULE_SYNTAX_ERROR;
                return NULL;
            }
            break;
        case OBJGROUP:
            nnp = parse_objectgroup(fp, name, OBJECTS, &objects);
            if (nnp == NULL) {
                print_error("Bad parse of OBJECT-GROUP", NULL, type);
                gMibError = MODULE_SYNTAX_ERROR;
                return NULL;
            }
            break;
        case NOTIFGROUP:
            nnp = parse_objectgroup(fp, name, NOTIFICATIONS, &notifs);
            if (nnp == NULL) {
                print_error("Bad parse of NOTIFICATION-GROUP", NULL, type);
                gMibError = MODULE_SYNTAX_ERROR;
                return NULL;
            }
            break;
        case TRAPTYPE:
            nnp = parse_trapDefinition(fp, name);
            if (nnp == NULL) {
                print_error("Bad parse of TRAP-TYPE", NULL, type);
                gMibError = MODULE_SYNTAX_ERROR;
                return NULL;
            }
            break;
        case NOTIFTYPE:
            nnp = parse_notificationDefinition(fp, name);
            if (nnp == NULL) {
                print_error("Bad parse of NOTIFICATION-TYPE", NULL, type);
                gMibError = MODULE_SYNTAX_ERROR;
                return NULL;
            }
            break;
        case COMPLIANCE:
            nnp = parse_compliance(fp, name);
            if (nnp == NULL) {
                print_error("Bad parse of MODULE-COMPLIANCE", NULL, type);
                gMibError = MODULE_SYNTAX_ERROR;
                return NULL;
            }
            break;
        case AGENTCAP:
            nnp = parse_capabilities(fp, name);
            if (nnp == NULL) {
                print_error("Bad parse of AGENT-CAPABILITIES", NULL, type);
                gMibError = MODULE_SYNTAX_ERROR;
                return NULL;
            }
            break;
        case MACRO:
            nnp = parse_macro(fp, name);
            if (nnp == NULL) {
                print_error("Bad parse of MACRO", NULL, type);
                gMibError = MODULE_SYNTAX_ERROR;
                /*
                 * return NULL;
                 */
            }
            free_node(nnp);     /* IGNORE */
            nnp = NULL;
            break;
        case MODULEIDENTITY:
            nnp = parse_moduleIdentity(fp, name);
            if (nnp == NULL) {
                print_error("Bad parse of MODULE-IDENTITY", NULL, type);
                gMibError = MODULE_SYNTAX_ERROR;
                return NULL;
            }
            break;
        case OBJIDENTITY:
            nnp = parse_objectgroup(fp, name, OBJECTS, &objects);
            if (nnp == NULL) {
                print_error("Bad parse of OBJECT-IDENTITY", NULL, type);
                gMibError = MODULE_SYNTAX_ERROR;
                return NULL;
            }
            break;
        case OBJECT:
            type = get_token(fp, token, MAXTOKEN);
            if (type != IDENTIFIER) {
                print_error("Expected IDENTIFIER", token, type);
                gMibError = MODULE_SYNTAX_ERROR;
                return NULL;
            }
            type = get_token(fp, token, MAXTOKEN);
            if (type != EQUALS) {
                print_error("Expected \"::=\"", token, type);
                gMibError = MODULE_SYNTAX_ERROR;
                return NULL;
            }
            nnp = parse_objectid(fp, name);
            if (nnp == NULL) {
                print_error("Bad parse of OBJECT IDENTIFIER", NULL, type);
                gMibError = MODULE_SYNTAX_ERROR;
                return NULL;
            }
            break;
        case EQUALS:
            nnp = parse_asntype(fp, name, &type, token);
            lasttype = CONTINUE;
            break;
        case ENDOFFILE:
            break;
        default:
            print_error("Bad operator", token, type);
            gMibError = MODULE_SYNTAX_ERROR;
            return NULL;
        }
        if (nnp) {
            if (np)
                np->next = nnp;
            else
                np = root = nnp;
            while (np->next)
                np = np->next;
            if (np->type == TYPE_OTHER)
                np->type = type;
        }
    }
    DEBUGMSGTL(("parse-file", "End of file (%s)\n", File));
    return root;
}