The Laws of Cryptography:
Java Coloring Program

Copyright © 2001 by Neal R. Wagner. All rights reserved.

The following Java program will color comments dark red, keywords blue (including "true", "false", and "null", which are technically constants, but are reserved like keywords), Strings dark green, and character constants dark yellow.

It also translates the '<' character into "&lt;" so that the program will handle HTML commands correctly. (The '<' character is the only one that causes trouble. When one wants '<' to appear inside HTML, one actually has to write '&lt;'.) So this part of the program has a flaw. If the program encounters "&lt;", it should translate this into "&amp;lt;", but I did that by hand in the program below. (Thus this program does not quite correctly translate itself.)

Another odd point: when I wrote "&amp;lt;" above, I wanted it to appear correctly in an HTML document, so I actually had to write "&amp;amp;lt;". In order to write the quoted string I just wrote, I actually had to write "&amp;amp;amp;lt;" for it, and in order to write this string . . . .    In spite of all this, if you just select and copy from your browser, it will copy a correct Java program.


// Keywords.java: format a Java program for html
import java.io.*;
class Keywords {
   private String[] keywords = {"abstract", "boolean", "byte", "case",
      "catch", "char", "class", "continue", "default", "do", "double",
      "else", "extends", "final", "finally", "float", "for", "if", 
      "implements", "import", "instanceof", "int", "interface", "long",
      "native", "new", "package", "private", "protected", "public",
      "return", "short", "static", "super", "switch", "synchronized",
      "this", "throw", "throws", "transient", "try", "void", "volatile",
      "while",
      "false", "true", "null" // technically, constants, not keywords
   };
   
   private Reader in; // internal file name for input stream
   private boolean fileOpen = false; // is the file open yet?
   private String fileName; // name of input file, if present

   // Keywords: constructor, input parameter: input file name or null
   public Keywords(String f) {
      fileName = f;
   } 

   // getNextChar: fetches next char.  Also opens input file
   private char getNextChar() {
      char ch = ' '; // = ' ' to keep compiler happy
      if (!fileOpen) {
         fileOpen = true;
         if (fileName == null)
            in = new InputStreamReader(System.in);
         else {
            try {
               in = new FileReader(fileName);
            } catch (IOException e) {
               System.out.println("Exception opening " + fileName);
            }
         }
      }
      try {
         ch = (char)in.read();
      } catch (IOException e) {
         System.out.println("Exception reading character");
      }
      return ch;
   }

   // buildDisplay: fetch each character and do the translation
   public void buildDisplay() {
      String word;
      System.out.println("<html><pre>");
      char ch = getNextChar();
      char ch2 = ' '; // = ' ' to keep compiler happy
      while (ch != 65535) { // EOF
         // check for comment
         if (ch == '/') {
            ch = getNextChar();
            if (ch == '/') { // first process one-line comments 
               System.out.print("<font color=\"#BB0000\">//"); // dark red
               while ((ch = getNextChar()) != '\n') {
                  if (ch == '<') System.out.print("&lt;");
                  else System.out.print(ch);
               }
               System.out.print("</font>");
            }
            else if (ch == '*') { // next process multi-line comment
               System.out.print("<font color=\"#BB0000\">/*"); // dark red
               ch = getNextChar();
               ch2 = getNextChar();
               while (true) {
                  if (ch == '*' && ch2 == '/') { // end of multi-line comm
                     System.out.print("*/</font>");
                     ch = getNextChar();
                     break;
                  }
                  else {
                     if (ch == '<') System.out.print("&lt;");
                     else System.out.print(ch);
                     ch = ch2;
                     ch2 = getNextChar();
                  }
               } // while
            }
            else { // not a comment, just a /
               System.out.print("/");
               if (ch == '<') System.out.print("&lt;");
               else System.out.print(ch);
               ch = getNextChar();
            }
         } // end of comment handler
         // check for quoted string (between "")
         else if (ch == '"') {
            System.out.print("<font color=\"#006600\">\""); // dark green
            while (true) {
               ch = getNextChar();
               // need the following to handle \" in a String
               if (ch == '\\') {
                  ch = getNextChar();
                  System.out.print("\\");
                  if (ch == '<') System.out.print("&lt;");
                  else System.out.print(ch);
               }
               else if (ch == '"') {
                  System.out.print("\"</font>");
                  ch = getNextChar();
                  break;
               }
               else {
                  if (ch == '<') System.out.print("&lt;");
                  else System.out.print(ch);
               }
            } // while
         } // end of quoted String handler
         // check for character constant (between '')
         else if (ch == '\'') {
            System.out.print("<font color=\"#B0B000\">\'"); // dark yellow
            while (true) {
               ch = getNextChar();
               // need the following to handle \' in a char constant
               if (ch == '\\') {
                  ch = getNextChar();
                  System.out.print("\\");
                  if (ch == '<') System.out.print("&lt;");
                  else System.out.print(ch);
               }
               else if (ch == '\'') { // end of character constant
                  System.out.print("\'</font>");
                  ch = getNextChar();
                  break;
               }
               else {
                  if (ch == '<') System.out.print("&lt;");
                  else System.out.print(ch);
               }
            } // while
         } // end of character constant handler
         // check for keyword
         else if (Character.isLetter(ch)) {
            word = "" + ch;
            while (Character.isLetter(ch = getNextChar()))
               word += ch;
            if (Character.isDigit(ch) || ch == '_') {
               System.out.print(word); // just bail out
               while (Character.isLetterOrDigit(ch) || ch == '_') {
                  System.out.print(ch);
                  ch = getNextChar();
               }
            }
            else { // check word if keyword
               if (lookUp(word) != -1) {
                  System.out.print("<font color=\"#0000BB\">" // blue
                     + word + "</font>");
               }
               else 
                  System.out.print(word);
            }
         } // end of keyword handler
         if (ch == '<') System.out.print("&lt;");
         else System.out.print(ch);
         ch = getNextChar();
      }
      System.out.println("</pre></html>");
   }
   
   // lookUp: loop up the next word in the array keywords
   public int lookUp(String s) {
      for (int j = 0; j < keywords.length; j++)
         if (s.equals(keywords[j])) return j;
      return -1;
   }
   
   // main: doesn't do much; just feeds in input file name
   public static void main(String[] args) {
      Keywords key;
      // pass an input file name if present on command line
      if (args.length > 0)
         key = new Keywords(args[0]);
      else
         key = new Keywords(null);
      key.buildDisplay();
   }
}