options {
    STATIC=false;
    OPTIMIZE_TOKEN_MANAGER=true;
    FORCE_LA_CHECK=true;
}

PARSER_BEGIN(ChemNumber)

import java.io.StringReader;

/**
 * A class partly generated by JavaCC (http://javacc.dev.java.net) which translates
 * ancient greek style "prefixs" to an integer.
 *
 * Released under the LGPL by the University of Manchester 2003
 *
 * @author Stephen Tomkinson
 */
public class ChemNumber {
    private static int currentNumber;

    /**
     * Converts the ancient greek style "prefix" string into an int.
     *
     * @throws ParseException Any error which occur in the parsing get wrapped
     * up in a ParseException and thrown.
     */
    public static int fromString (String stringToParse) throws ParseException
    {
        currentNumber = 0;

        StringReader stringReader = new StringReader (stringToParse.toLowerCase(Locale.ENGLISH) + "\n");
        ChemNumber parser = new ChemNumber (stringReader);               
        parser.wholeNumber();

        return currentNumber;
    }

    /**
     * A very basic usage of the program in which the first argument from the command line gets
     * translated and printed out.
     */
    public static void main (String args[])
    {
        try
        {
            System.out.println ("Returned: " + fromString(args[0]));
        }
        catch (Throwable t)
        {
            System.out.println (t);
        }
    }
}

PARSER_END(ChemNumber)

/**
 * The obligatory EOL character.
 */
TOKEN :
{
    < EOL: "\n" >
}

/**
 * Initial small numbers.
 */
TOKEN :
{
    < METH: "meth" >
|   < ETH: "eth" >
|   < PROP: "prop" >
|   < BUT: "but" >
}

/**
 * Other special cases.
 */
TOKEN :
{
    < UNDEC: "undec" >
|   < EICOS: "eicos" | "icos" >
|   < HENICOS: "henicos" >
}

/**
 * Usual numbers for base 10 numbering.
 */
TOKEN :
{
    < HEN: "hen" >
|   < DO: "do" >
|   < TRI: "tri" >
|   < TETR: "tetra" >
|   < PENT: "pent" >
|   < HEX: "hex" >
|   < HEPT: "hept" >
|   < OCT: "oct" >
|   < NON: "non" >
}

/**
 * Positional aides which give the magnitude of the the base numbers.
 * Equivalent to "...ty" and "...hundred" in English.
 */
TOKEN :
{
    < DEC: "dec" >
|   < COS: "cos" >
|   < CONT: "cont" >
}

/** Skip the "a" letter for greek numbers since the rules for when to use an "a" are very complicated. */
SKIP :
{
    < A : "a" >
}

/** The build up of a complete number from 1 - 99 */
void wholeNumber() :
{}
{
    ( specialCase() | allBaseNumbers() [tensWithUnits() | tensNoUnits()] ) 
    <EOL>
}

/** Deal with special cases where the rules don't apply. */
void specialCase() :
{}
{
    < METH > {currentNumber = 1;}
|   < ETH > {currentNumber = 2;}
|   < PROP > {currentNumber = 3;}
|   < BUT > {currentNumber = 4;}
|   < UNDEC > {currentNumber = 11;}
|   < EICOS > {currentNumber = 20;}
|   < HENICOS > {currentNumber = 21;}
}

/** The usual numbers .*/
void allBaseNumbers() :
{}
{
    < HEN > {currentNumber = 1;}
|   < DO > {currentNumber = 2;}
|   < TRI > {currentNumber = 3;}
|   < TETR > {currentNumber = 4;}
|   < PENT > {currentNumber = 5;}
|   < HEX > {currentNumber = 6;}
|   < HEPT > {currentNumber = 7;}
|   < OCT > {currentNumber = 8;}
|   < NON > {currentNumber = 9;}
}

/** Deal with fragments referring to the positioning of the base numbers (denoting their magnitude) */
void tensNoUnits() :
{}
{
    <DEC> { currentNumber += 10; }
|   <COS> { currentNumber += 20; }
|   <CONT> { currentNumber *= 10; }
}

/** Deals with numbers above 30 where the base numbers set appear twice, i.e. in the tens and the units. */
void tensWithUnits() :
{
    int tempBackup;
}
{
    { tempBackup = currentNumber; }
    allBaseNumbers() <CONT>
    { currentNumber *= 10; currentNumber += tempBackup; }
}
