lib/grammar.js
function checkStructMember(structname, obj, callback, root) {
    var membername = obj.name.name;

    if (!isVarString(membername)) {
        callback(false, structname + '.' + membername + ': The first letter should be lowercase.');

        return false;
    }

    if (!base.isType(obj.type, root)) {
        callback(false, structname + '.' + membername + ': ' + obj.type + ' not defined.');

        return false;
    }

    if (obj.type == 'time') {
        if (obj.hasOwnProperty('val')) {
            if (typeof(obj.val) == 'object') {
                if (obj.val.type == 'NULL') {
                    return true;
                }
                else if (obj.val.type == 'time' && obj.val.val == 'NOW') {
                    return true;
                }
            }

            callback(false, structname + '.' + membername + ': default is not NULL or NOW.');

            return false;
        }
    }
    else if (obj.type == 'int') {
        if (obj.hasOwnProperty('val')) {
            if (typeof(obj.val) == 'object') {
                if (obj.val.type == 'int' && obj.val.val == 'AUTOINC') {
                    if (obj.type2 != 'primary') {
                        callback(false, structname + '.' + membername + ': AUTOINC is primary.');

                        return false;
                    }
                }
            }
        }
    }

    if (obj.type2 == 'expand') {
        if (obj.hasOwnProperty('expand')) {
            if (!base.isEnum(obj.expand, root)) {
                callback(false, structname + '.' + membername + ': expand need enum!.');

                return false;
            }
        }
        else {
            var cobj = base.getGlobalObj(obj.type, root);
            if (cobj == undefined) {
                callback(false, structname + '.' + membername + ': expand fail!.');

                return false;
            }

            var structobj = base.getGlobalObj(structname, root);
            for (var i = 0; i < cobj.val.length; ++i) {
                if (base.hasMemberEx(cobj.val[i].name.name, obj.type, structobj, root)) {
                    callback(false, structname + '.' + membername + '.' + cobj.val[i].name.name + ': expand err(duplication of name).');

                    return false;
                }
            }
        }
    }

    if (obj.type2 == 'repeated') {
        if (obj.hasOwnProperty('memberkey')) {
            if (!(base.isStruct(obj.type, root) || base.isStatic(obj.type, root))) {
                callback(false, structname + '.' + membername + ': repeated object must be struct.');

                return false;
            }

            if (!base.hasMember2(obj.memberkey, base.getGlobalObj(obj.type, root), root)) {
                callback(false, structname + '.' + membername + ': repeated key(' + obj.memberkey + ') not defined in ' + obj.type + '.');

                return false;
            }
        }
    }

    return true;
}
function checkStructMember(structname, obj, callback, root) {
    var membername = obj.name.name;

    if (!isVarString(membername)) {
        callback(false, structname + '.' + membername + ': The first letter should be lowercase.');

        return false;
    }

    if (!base.isType(obj.type, root)) {
        callback(false, structname + '.' + membername + ': ' + obj.type + ' not defined.');

        return false;
    }

    if (obj.type == 'time') {
        if (obj.hasOwnProperty('val')) {
            if (typeof(obj.val) == 'object') {
                if (obj.val.type == 'NULL') {
                    return true;
                }
                else if (obj.val.type == 'time' && obj.val.val == 'NOW') {
                    return true;
                }
            }

            callback(false, structname + '.' + membername + ': default is not NULL or NOW.');

            return false;
        }
    }
    else if (obj.type == 'int') {
        if (obj.hasOwnProperty('val')) {
            if (typeof(obj.val) == 'object') {
                if (obj.val.type == 'int' && obj.val.val == 'AUTOINC') {
                    if (obj.type2 != 'primary') {
                        callback(false, structname + '.' + membername + ': AUTOINC is primary.');

                        return false;
                    }
                }
            }
        }
    }

    if (obj.type2 == 'expand') {
        if (obj.hasOwnProperty('expand')) {
            if (!base.isEnum(obj.expand, root)) {
                callback(false, structname + '.' + membername + ': expand need enum!.');

                return false;
            }
        }
        else {
            var cobj = base.getGlobalObj(obj.type, root);
            if (cobj == undefined) {
                callback(false, structname + '.' + membername + ': expand fail!.');

                return false;
            }

            var structobj = base.getGlobalObj(structname, root);
            for (var i = 0; i < cobj.val.length; ++i) {
                if (base.hasMemberEx(cobj.val[i].name.name, obj.type, structobj, root)) {
                    callback(false, structname + '.' + membername + '.' + cobj.val[i].name.name + ': expand err(duplication of name).');

                    return false;
                }
            }
        }
    }

    if (obj.type2 == 'repeated') {
        if (obj.hasOwnProperty('memberkey')) {
            if (!(base.isStruct(obj.type, root) || base.isStatic(obj.type, root))) {
                callback(false, structname + '.' + membername + ': repeated object must be struct.');

                return false;
            }

            if (!base.hasMember2(obj.memberkey, base.getGlobalObj(obj.type, root), root)) {
                callback(false, structname + '.' + membername + ': repeated key(' + obj.memberkey + ') not defined in ' + obj.type + '.');

                return false;
            }
        }
    }

    return true;
}
callback(isok, err)