'The grammar here is based on the description in the `Standards
for Astronomical Catalogues 2.0
<http://cds.u-strasbg.fr/doc/catstd-3.2.htx>`_, which is not
terribly precise.  The exact grammar is here is based on the
YACC grammar in the `unity library
<https://bitbucket.org/nxg/unity/>`_.'

@classmethod
def _make_parser(cls):

    from ...extern.ply import yacc
    tokens = cls._tokens
    def p_main(p):
        u'\n                                                main    :    factor    combined_units\n                                                                    |    combined_units\n                                                                    |    factor\n                                                '
        from ..core import Unit
        if (len(p) == 3):
            p[0] = Unit((p[1] * p[2]))
        else:
            p[0] = Unit(p[1])
    def p_combined_units(p):
        u'\n                                                combined_units    :    product_of_units\n                                                                                                            |    division_of_units\n                                                '
        p[0] = p[1]
    def p_product_of_units(p):
        u'\n                                                product_of_units    :    unit_expression    PRODUCT    combined_units\n                                                                                                                    |    unit_expression\n                                                '
        if (len(p) == 4):
            p[0] = (p[1] * p[3])
        else:
            p[0] = p[1]
    def p_division_of_units(p):
        u'\n                                                division_of_units    :    DIVISION    unit_expression\n                                                                                                                        |    unit_expression    DIVISION    combined_units\n                                                '
        if (len(p) == 3):
            p[0] = (p[2] ** (-1))
        else:
            p[0] = (p[1] / p[3])
    def p_unit_expression(p):
        u'\n                                                unit_expression    :    unit_with_power\n                                                                                                                |    OPEN_PAREN    combined_units    CLOSE_PAREN\n                                                '
        if (len(p) == 2):
            p[0] = p[1]
        else:
            p[0] = p[2]
    def p_factor(p):
        u'\n                                                factor    :    signed_float    X    UINT    signed_int\n                                                                            |    UINT    X    UINT    signed_int\n                                                                            |    UINT    signed_int\n                                                                            |    UINT\n                                                                            |    signed_float\n                                                '
        if (len(p) == 5):
            if (p[3] != 10):
                raise ValueError(u'Only    base    ten    exponents    are    allowed    in    CDS')
            p[0] = (p[1] * (10.0 ** p[4]))
        elif (len(p) == 3):
            if (p[1] != 10):
                raise ValueError(u'Only    base    ten    exponents    are    allowed    in    CDS')
            p[0] = (10.0 ** p[2])
        elif (len(p) == 2):
            p[0] = p[1]
    def p_unit_with_power(p):
        u'\n                                                unit_with_power    :    UNIT    numeric_power\n                                                                                                                |    UNIT\n                                                '
        if (len(p) == 2):
            p[0] = p[1]
        else:
            p[0] = (p[1] ** p[2])
    def p_numeric_power(p):
        u'\n                                                numeric_power    :    sign    UINT\n                                                '
        p[0] = (p[1] * p[2])
    def p_sign(p):
        u'\n                                                sign    :    SIGN\n                                                                    |\n                                                '
        if (len(p) == 2):
            p[0] = p[1]
        else:
            p[0] = 1.0
    def p_signed_int(p):
        u'\n                                                signed_int    :    SIGN    UINT\n                                                '
        p[0] = (p[1] * p[2])
    def p_signed_float(p):
        u'\n                                                signed_float    :    sign    UINT\n                                                                                                    |    sign    UFLOAT\n                                                '
        p[0] = (p[1] * p[2])
    def p_error(p):
        raise ValueError()
    parser = yacc.yacc(debug=False, tabmodule=str(u'cds_parsetab'), outputdir=os.path.dirname(__file__), write_tables=True)
    return parser
