/*
 * Title: Lexer
 * Author: Matthew Boyette
 * Date: 9/25/2016
 * 
 * This class functions as a generic extendible lexical analyzer.
 * It's default settings are for the for the C language.
 */

package api.util;

import java.util.ArrayList;
import api.util.datastructures.Token;
import edu.princeton.cs.algs4.In;

public abstract class Lexer<T>
{
    /*
     * This helper enumerator class represents each of the various special types of depth we are tracking for each token.
     */
    protected static enum DepthType
    {
        //@formatter:off
        BRACE, BRACKET, COMMENT, PARENTH
        //@formatter:on
    }

    // RegExr patterns describing the various components of the C language grammar.
    public static final String C_ASSIGNMENT_OPS = "(\\+\\=)|(\\-\\=)|(\\*\\=)|(\\/\\=)|(%\\=)|(&\\=)|(\\^\\=)|(\\|\\=)|(\\=)|(\\=)|(\\=)";
    public static final String C_BIT_SHIFT_OPS  = "(\\<\\<)|(\\>\\>)";
    public static final String C_COMMENTS       = "(\\/\\/)|(\\/\\*)|(\\*\\/)";
    public static final String C_COMPARISON_OPS = "(&&)|(\\|\\|)|(&)|(\\^)|(\\|)";
    public static final String C_CONDITION_OPS  = "(:)|(\\?)";
    public static final String C_ERRORS         = "([^\\(\\)\\{\\}\\[\\]\\.\\?:;,&%\\+\\-\\*\\/\\<\\>\\=\\!\\^\\|\\s]+)";
    public static final String C_GROUPINGS      = "([\\(\\)\\{\\}\\[\\]])|(\")|(\')|(,)|(;)|(\\.)|(\\-\\>)";
    public static final String C_IDENTIFIERS    = "([A-Za-z_]\\w*)";
    public static final String C_INCR_DECR_OPS  = "(\\+\\+)|(\\-\\-)";
    public static final String C_KEYWORDS       = "(\\b((auto)|(break)|(case)|(char)|(const)|(continue)|(default)|(do)|(double)|(else)|(enum)|(extern)|(float)|(for)|(goto)|(if)|(int)|(long)|(register)|(return)|(short)|(signed)|(sizeof)|(static)|(struct)|(switch)|(typedef)|(union)|(unsigned)|(void)|(volatile)|(while))\\b)";
    public static final String C_MATHEMATIC_OPS = "(\\+)|(\\-)|(\\*)|(\\/)|(%)";
    public static final String C_NUMBERS        = "((\\-)?\\d+(\\.\\d+)?((E|e)(\\+|\\-)?\\d+)?)|((\\-)?\\.\\d+((E|e)(\\+|\\-)?\\d+)?)";
    public static final String C_OPERATORS      = C_INCR_DECR_OPS + "|" + C_BIT_SHIFT_OPS + "|" + C_CONDITION_OPS + "|" + C_ASSIGNMENT_OPS + "|" + C_COMPARISON_OPS + "|" + C_MATHEMATIC_OPS;
    public static final String C_WHITESPACES    = "(\\s+)";

    // Internal Depth Tracking Array
    protected int[] Depth = { 0, 0, 0, 0 };

    public ArrayList<Token<T>> lex(final String s)
    {
        return this.lex(s, false, false);
    }

    public ArrayList<Token<T>> lex(final String s, final boolean silent)
    {
        return this.lex(s, silent, false);
    }

    public abstract ArrayList<Token<T>> lex(final String s, final boolean silent, final boolean ignoreWhiteSpace);

    public ArrayList<Token<T>> lexFile(final String fileName)
    {
        return this.lexFile(fileName, false);
    }

    public ArrayList<Token<T>> lexFile(final String fileName, final boolean silent)
    {
        return this.lexFile(fileName, silent, false);
    }

    public ArrayList<Token<T>> lexFile(final String fileName, final boolean silent, final boolean ignoreWhiteSpace)
    {
        // A buffer for the tokens we want to return.
        ArrayList<Token<T>> tokens = new ArrayList<Token<T>>();

        In inputStream = null;
        
        try
        {
            // Try to open the given input file for a read operation.
            inputStream = new In(fileName);
            
            // Pass each line of text from the input file to lex(), and add all the returned tokens to our output token buffer.
            while ( inputStream.hasNextLine() )
            {
                tokens.addAll(this.lex(inputStream.readLine(), silent, ignoreWhiteSpace));
            }
        }
        catch ( final IllegalArgumentException iae )
        {
            iae.printStackTrace();
        }
        catch ( final NullPointerException npe )
        {
            npe.printStackTrace();
        }
        finally
        {
            if ( inputStream != null )
            {
                inputStream.close();
                inputStream = null;
            }
        }

        return tokens;
    }
}

@@ -971,16 +971,19 @@
 %22(%5C%5C/%5C%5C/
+.*$
 )%7C(%5C%5C/%5C%5C
@@ -2615,32 +2615,210 @@
  false);%0A    %7D%0A%0A
+    public ArrayList%3CToken%3CT%3E%3E lex(final String s, final boolean silent, final boolean ignoreWhiteSpace)%0A    %7B%0A        return this.lex(s, silent, ignoreWhiteSpace, true);%0A    %7D%0A%0A
     public abstr
@@ -2850,33 +2850,40 @@
 ex(final String 
-s
+fileName
 , final boolean 
@@ -2920,16 +2920,46 @@
 iteSpace
+, final boolean ignoreComments
 );%0A%0A    
@@ -3340,32 +3340,262 @@
 iteSpace)%0A    %7B%0A
+        return this.lexFile(fileName, silent, ignoreWhiteSpace, true);%0A    %7D%0A%0A    public ArrayList%3CToken%3CT%3E%3E lexFile(final String fileName, final boolean silent, final boolean ignoreWhiteSpace, final boolean ignoreComments)%0A    %7B%0A
         // A buf
@@ -4068,32 +4068,32 @@
 )%0A            %7B%0A
-
                 
@@ -4163,16 +4163,32 @@
 iteSpace
+, ignoreComments
 ));%0A    

Update Lexer.java