Tuesday 17 January 2017

Chapter 21 Exercise 3, Introduction to Java Programming, Tenth Edition Y. Daniel LiangY.

21.3 (Count the keywords in Java source code)
Revise the program in Listing 21.7. If a keyword is in a comment or in a
string, don’t count it. Pass the Java file name from the command line.
Assume that the Java source code is correct and line comments and paragraph
comments do not overlap.


import java.io.File;
import java.util.*;

public class Exercise_03 {

    public static void main(String[] args) throws Exception {
        Scanner input = new Scanner(System.in);
        System.out.print("Enter a Java source file: ");
        String filename = input.nextLine();
        // test file
        // String filename = "/Users/Kernel/GitHub/intro-to-java-10th-edition/src/Chapter_21/Exercise_03.java";

        File file = new File(filename);
        if (file.exists()) {
            System.out.println("The number of keywords in " + file.getName()
                    + " is " + countKeywords(file));
        }
        else {
            System.out.println("File " + filename + " does not exist");
        }
    }

    private static boolean[] states = new boolean[4];
    private static int BLOCK = 0;
    private static int LINE = 1;
    private static int STRING = 2;
    private static int CHAR = 3;

    public static int countKeywords(File file) throws Exception {
        // Array of all Java keywords + true, false and null
        String[] keywordString = {"abstract", "assert", "boolean",
                "break", "byte", "case", "catch", "char", "class", "const",
                "continue", "default", "do", "double", "else", "enum",
                "extends", "for", "final", "finally", "float", "goto",
                "if", "implements", "import", "instanceof", "int",
                "interface", "long", "native", "new", "package", "private",
                "protected", "public", "return", "short", "static",
                "strictfp", "super", "switch", "synchronized", "this",
                "throw", "throws", "transient", "try", "void", "volatile",
                "while", "true", "false", "null"};

        Scanner input = new Scanner(file);
        int count = 0;
        HashSet<String> keywords = new HashSet<>(Arrays.asList(keywordString));
        String word = "";
        while (input.hasNext()) {
            word += input.nextLine() + "\n";
        }

        int index;
        while ((index = getNextState(word)) != -1) {
            if (states[BLOCK])
                word = removeBlock(word, index);
            else if (states[LINE])
                word = removeLine(word, index);
            else if (states[STRING])
                word = removeString(word, index);
            else if (states[CHAR])
                word = removeChar(word, index);
        }

        String[] filter = word.split("\\W");

        for (String s : filter) {
            if (s.length() > 0 && keywords.contains(s))
                count++;

        }
        return count;
    }

    private static String removeString(String word, int index) {

        states[STRING] = false;
        String clean = word.substring(0, index);
        String dirty = word.substring(index + 1);
        int escape = dirty.indexOf("\\");
        int dQuote = dirty.indexOf("\"");
        if (escape == -1 || escape > dQuote) // its clean to merge string
            return clean + dirty.substring(dQuote + 1);

        // else get the next double quote that doesn't have an escape character
        Stack<Character> tokens = new Stack<>();

        char[] charArray = dirty.toCharArray();
        for (int i = 0; i < charArray.length; i++) {
            char ch = charArray[i];
            if (ch == '\"' && tokens.isEmpty())
                return clean + dirty.substring(i + 1);

            if (!tokens.isEmpty())
                tokens.pop();
            else if (ch == '\\') {
                tokens.push(ch);
            }
        }
        return "ERROR FINDING END OF STRING";
    }

    private static String removeLine(String word, int index) {
        states[LINE] = false;
        String clean = word.substring(0, index);
        String end = word.substring(index);
        end = end.substring(end.indexOf("\n"));

        return clean + end;
    }

    private static String removeChar(String word, int index) {
        states[CHAR] = false;
        String clean = word.substring(0, index);
        String dirty = word.substring(index + 1);

        if (dirty.charAt(0) == '\\')
            dirty = dirty.substring(3);
        else
            dirty = dirty.substring(2);

        return clean + dirty;
    }

    private static String removeBlock(String s, int index) {
        states[BLOCK] = false;
        int end = s.indexOf("*/");
        String clean = s.substring(0, index);
        String endString = s.substring(end + 2);

        return clean + endString;
    }

    public static int getNextState(String s) {
        // block, line, string, char
        int[] indices = new int[4];
        String[] startStateTokens = {"/*", "//", "\"", "\'"};

        int lowest = -1;
        int key = 0;
        for (int i = 0; i < indices.length; i++) {
            indices[i] = s.indexOf(startStateTokens[i]);
            if (lowest == -1) {
                lowest = indices[i];
                key = i;
            } else if (lowest > indices[i] && indices[i] >= 0) {
                lowest = indices[i];
                key = i;
            }
        }

        if (key != -1) {
            states[key] = true;
        }

        return indices[key];
    }

}

No comments :

Post a Comment