home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 39 / IOPROG_39.ISO / SOFT / sdkjava40.exe / data1.cab / fg_Samples / Samples / JDirect / CToJParser / defscan.java < prev    next >
Encoding:
Java Source  |  2000-05-04  |  42.9 KB  |  1,283 lines

  1. /**
  2.  * (C) Copyright 1995 - 1999 Microsoft Corporation.  All rights reserved.
  3.  *
  4.  * Simple #define scanner.  Reads files of #defines and converts them into Java.
  5.  * Handles most of them, although it can't process macros.  Output files are Java
  6.  * interfaces broken down alphabetically.
  7.  *
  8.  * Currently Strings are left out - they require constructors to run.  That might
  9.  * slow down our code.
  10.  *
  11.  * Note: You must look for unterminated C-style comments in #define files.  Run this
  12.  * command over your def files and fix up any lines in the output:
  13.  * grep \/\* *.def | grep -v \*\/
  14.  *
  15.  */
  16.  
  17. import java.io.*;
  18. import java.util.*;
  19.  
  20. class symbol {
  21.     public String name;
  22.     public int type;
  23.     public boolean isBool;
  24.     public boolean isChar;
  25.     public boolean isString;
  26.     public boolean isInt;
  27.     public boolean isLong;
  28.     public boolean isDouble;
  29.     public boolean isComplex;  // True if its something non-trivial, like (0x1|CONSTANT)
  30.     public String text;
  31.     public String undefined_tokens;
  32.  
  33.     public symbol()
  34.     {
  35.         name = null;
  36.         text = null;
  37.         undefined_tokens = null;
  38.         isBool = false;
  39.         isChar = false;
  40.         isString = false;
  41.         isInt = false;
  42.         isLong = false;
  43.         isDouble = false;
  44.         isComplex = false;
  45.     }
  46.  
  47.     public void setTypes(boolean isBool, boolean isInt, boolean isLong, boolean isDouble, boolean isChar, boolean isString, boolean isComplex)
  48.     {
  49.         this.isBool = isBool;
  50.         this.isChar = isChar;
  51.         this.isString = isString;
  52.         this.isInt = isInt;
  53.         this.isLong = isLong;
  54.         this.isDouble = isDouble;
  55.         this.isComplex = isComplex;
  56.     }
  57.  
  58.     public void addTypes(boolean isBool, boolean isInt, boolean isLong, boolean isDouble, boolean isChar, boolean isString, boolean isComplex)
  59.     {
  60.         this.isBool = this.isBool | isBool;
  61.         this.isChar = this.isChar | isChar;
  62.         this.isString = this.isString | isString;
  63.         this.isInt = this.isInt | isInt;
  64.         this.isLong = this.isLong | isLong;
  65.         this.isDouble = this.isDouble | isDouble;
  66.         this.isComplex = this.isComplex | isComplex;
  67.     }
  68.  
  69.     public void addUndefToken(String token)
  70.     {
  71.         if(undefined_tokens == null)
  72.             undefined_tokens = token;
  73.         else
  74.             undefined_tokens = undefined_tokens + " " + token;
  75.     }
  76.  
  77.     public boolean hasUndefinedTokens()
  78.     {
  79.         return undefined_tokens != null;
  80.     }
  81. }
  82.  
  83.  
  84. class FileWrapper 
  85. {
  86.     public PrintWriter stream;
  87.     public String name;
  88.     public int numEntries;
  89.     public boolean lastWasBool;
  90.     public boolean lastWasInt;
  91.     public boolean lastWasLong;
  92.     public boolean lastWasDouble;
  93.     public boolean lastWasString;
  94.     public boolean lastWasChar;
  95.     public boolean veryFirstLine;
  96.  
  97.     /**
  98.      * Pass in the relative path, using \\ to separate directories.
  99.      * @param path relative path of file
  100.      * @param name name of the file.
  101.      */
  102.     public FileWrapper(String path, String name) throws IOException
  103.     {
  104.         this.name = name;
  105.         if(path!=null && !path.endsWith("\\"))
  106.             path = path+"\\";
  107.         OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(path+name));
  108.         stream = new PrintWriter(osw, true);
  109.         lastWasBool = false;
  110.         lastWasInt = false;
  111.         lastWasLong = false;
  112.         lastWasDouble = false;
  113.         lastWasString = false;
  114.         lastWasChar = false;
  115.         veryFirstLine = true;
  116.         numEntries = 0;
  117.     }
  118.  
  119.     public void finalizer()
  120.     {
  121.         stream.close();
  122.         stream = null;
  123.     }
  124. }
  125.  
  126.  
  127. public class defscan
  128. {
  129.     // Strings can be put in a separate interface.  May help performance a little, since 
  130.     // you'd have to run constructors for all strings when you used the interfaces otherwise.
  131.     private static final boolean SeparateStrings = true;
  132.  
  133.     // Change this location.  Sample value: "com\\ms\\win32"
  134.     private static final String outputdir = "com\\ms\\win32";
  135.  
  136.     // Change this too, or set to null if you don't want this in a package
  137.     // Sample value: "com.ms.win32"
  138.     private static final String PackageName = "com.ms.win32";
  139.  
  140.     private PrintWriter out;
  141.     private Hashtable Symbols;
  142.     public int skippedMacros;
  143.     public int skippedAliases;
  144.     public int skippedSymbols;
  145.     public int skippedNoValue;
  146.     public int skippedRedefined;
  147.     public int skippedStrings;
  148.     public int skippedUnterminatedExpressions;
  149.     public int skippedUnparsible;
  150.     public int resolvedLater;
  151.     public int unifiedSymbols;
  152.     public int outputted;
  153.     public int total;
  154.     protected Vector Files;
  155.     protected Vector UnrecognizedSymbols;
  156.  
  157.     // Magic numbers detailing place in Files vector for a global output and miscellaneous
  158.     // output files.  DO NOT EDIT WITHOUT GOOD REASON UNLESS YOU KNOW WHAT YOU'RE DOING.
  159.     // (such as you're adding numbers or upper&lower case interface files).
  160.     // global_output is supposed to be the highest number and they should all be consecutive and start at 26.
  161.     private static final int misc_output = 26;
  162.     private static final int string_output = 27;
  163.     private static final int global_output = 28;
  164.  
  165.     public defscan()
  166.     {
  167.         Symbols = new Hashtable();
  168.         UnrecognizedSymbols = new Vector();
  169.         skippedMacros = 0;
  170.         skippedAliases = 0;
  171.         skippedSymbols = 0;
  172.         skippedNoValue = 0;
  173.         skippedRedefined = 0;
  174.         skippedStrings = 0;
  175.         skippedUnterminatedExpressions = 0;
  176.         skippedUnparsible = 0;
  177.         resolvedLater = 0;
  178.         unifiedSymbols = 0;
  179.         outputted = 0;
  180.         total = 0;
  181.         SetupInterfaceFiles();
  182.     }
  183.  
  184.     public void finalizer() {
  185.         Symbols = null;
  186.         CloseInterfaceFiles();
  187.     }
  188.  
  189.     /**
  190.      * Create FileWrappers for all of the interface files.  Depends heavily on the magic
  191.      * numbers for global, misc, and string output from above.
  192.      * @return No return value.
  193.      */
  194.     protected void SetupInterfaceFiles() {
  195.         Files = new Vector(global_output+1);  // Use the magic number from above.
  196.         // Files should hold files for A-Z, a miscellaneous file, and a global output.
  197.         String path = outputdir;
  198.         String packageString = null;
  199.         if(PackageName!=null)
  200.             packageString = "\r\npackage "+PackageName+";\r\n";
  201.         try {
  202.             for(char c = 'a'; c <= 'z'; c++) {
  203.                 FileWrapper f = new FileWrapper(path, "win"+c+".java");
  204.                 Files.addElement(f);
  205.                 if(packageString != null)
  206.                     f.stream.print(packageString);
  207.                 f.stream.print("\r\npublic interface win"+c+" {\r\n");
  208.             }
  209.             
  210.             // Make a file for miscellaneous constants...
  211.             FileWrapper f = new FileWrapper(path, "winmisc.java");
  212.             Files.addElement(f);
  213.             if(packageString != null)
  214.                 f.stream.print(packageString);
  215.             f.stream.print("\r\npublic interface winmisc {\r\n");
  216.  
  217.             // Make a file for string constants...
  218.             f = new FileWrapper(path, "winstrings.java");
  219.             Files.addElement(f);
  220.             if(packageString != null)
  221.                 f.stream.print(packageString);
  222.             f.stream.print("\r\npublic interface winstrings {\r\n");
  223.  
  224.             // Add global file.  It should be the last one.
  225.             f = new FileWrapper(path, "win.java");
  226.             Files.addElement(f);
  227.             if(packageString != null)
  228.                 f.stream.print(packageString);
  229.             f.stream.print("\r\npublic interface win {\r\n");
  230.         }
  231.         catch (IOException e) {
  232.             System.out.println(e);
  233.             e.printStackTrace();
  234.             Files = null;
  235.         }
  236.     }
  237.  
  238.     /**
  239.      * Close win*.java after writing out all terminating info necessary.
  240.      * @return No return value.
  241.      */
  242.     protected void CloseInterfaceFiles() {
  243.         if(Files == null)
  244.             return;
  245.         System.out.println("Closing files...");
  246.         for(int i=0; i<Files.size(); i++) {
  247.             //PrintStream s = (PrintStream) Files.elementAt(i);
  248.             FileWrapper f = (FileWrapper) Files.elementAt(i);
  249.             if(!f.veryFirstLine)
  250.                 f.stream.print(";\r\n");
  251.             f.stream.print("\r\n}\r\n");
  252.             //System.out.println(f.name+" contained "+f.numEntries+" constants.");
  253.             f.finalizer();
  254.             f = null;
  255.         }
  256.         Files = null;
  257.     }
  258.  
  259.     /**
  260.      * Mainly useful if you scan the header files in the wrong order or if you have circular
  261.      * dependencies in your headers.  Resolves all unresolved symbols, or at least as much as
  262.      * it can.
  263.      */
  264.     protected void HandleUnrecognizedSymbols() throws IOException {
  265.         boolean converged = false;
  266.         Vector removeList = new Vector();  // Remove from UnrecognizedSymbols at end of pass.
  267.         int passes = 1;
  268.         System.out.print("\n\nLooking up "+UnrecognizedSymbols.size()+" unrecognized symbols... ");
  269.         do {
  270.             removeList = new Vector();
  271.             System.out.print("pass "+(passes++)+"... ");
  272.             for(int i=0; i<UnrecognizedSymbols.size(); i++) {
  273.                 symbol unrec = (symbol) UnrecognizedSymbols.elementAt(i);
  274.                 symbol sym = (symbol) Symbols.get(unrec.text);
  275.                 if(Symbols.containsKey(unrec.name)) {
  276.                     System.out.println("HandleUnrecognizedSymbols won't deal with unparsed redefinition of "+unrec.name);
  277.                     removeList.addElement(unrec);
  278.                     skippedRedefined++;
  279.                     skippedSymbols--;
  280.                     continue;
  281.                 }
  282.                 
  283.                 //System.out.println("Symbol "+unrec.name+" has unrecognized text "+unrec.text+"... ");
  284.                 
  285.                 boolean cont = false;
  286.                 if(sym==null)  // Try to save something... (Parse complex strings)
  287.                     cont = jitParse(unrec);
  288.                 if(sym != null || cont) {
  289.                     resolvedLater++;
  290.                     if(sym!=null) {
  291. //                        System.out.println("late lookup succeeded for "+unrec.name+": "+unrec.text+" -> "+sym.text);
  292.                         unrec.text = sym.text;
  293.                         unrec.setTypes(sym.isBool, sym.isInt, sym.isLong, sym.isDouble, sym.isChar, sym.isString, sym.isComplex|unrec.isComplex);
  294.                     }
  295.                     Symbols.put(unrec.name, unrec);
  296.                     OutputToFile(unrec, false, false);
  297.                     OutputToFile(unrec, false, true);
  298.                     outputted++;
  299.                     removeList.addElement(unrec);
  300.                 }
  301.             }
  302.  
  303.             // Must remove after finishing for loop, or add some slightly complex logic
  304.             // to for loop for incrementing i.  But this gives us our convergence test, so...
  305.             if(removeList.size() == 0)
  306.                 converged = true;
  307.             else {
  308.                 System.out.println("removed "+removeList.size());
  309.                 for(int j=0; j<removeList.size(); j++) {
  310.                     symbol sym = (symbol) removeList.elementAt(j);
  311.                     UnrecognizedSymbols.removeElement(sym);
  312.                 }
  313.             }
  314.             removeList = null;
  315.         } while(!converged);
  316.  
  317.         System.out.println("\nDone resolving unresolved symbols.");
  318.         System.out.println("Resolved "+resolvedLater+" symbols, converging after "+(passes-2)+" passes.");
  319.     }
  320.  
  321.     /**
  322.      * jitParse is a magic last-minute attempt at parsing complex symbol 
  323.      * expressions, looking for undefined symbols that might be defined now.  Employ
  324.      * whatever algorithms you want here, this is your last chance.  Changes sym.
  325.      * @param symbol to fix up.
  326.      * @return true if it fixed the problem, else false
  327.      */
  328.     public boolean jitParse(symbol sym)
  329.     {
  330.         if(!sym.hasUndefinedTokens())
  331.             return false;
  332.         if(sym.text == null) {
  333.             System.out.println("Ack! Won't JIT parse a symbol with null text! "+sym.name);
  334.             return false;
  335.         }
  336. //        System.out.print("JIT parsing "+sym.name+"... ");
  337. //        System.out.print("undef_tokens: "+sym.undefined_tokens+"  text: "+sym.text);
  338.         StringTokenizer unrec_strings = new StringTokenizer(sym.undefined_tokens);
  339.         do {
  340.             String replace = unrec_strings.nextToken();
  341.             symbol repsym = (symbol) Symbols.get(replace);
  342.             if(repsym == null) {
  343.                 //System.out.println("failed.");
  344.                 return false;
  345.             }
  346.             //System.out.println(replace +" -> "+repsym.text);
  347.             sym.addTypes(repsym.isBool, repsym.isInt, repsym.isLong, repsym.isDouble, repsym.isChar, repsym.isString, repsym.isComplex);
  348.  
  349.             StringTokenizer st = new StringTokenizer(sym.text, "() \t\r\n+-*\\/#&|~^", true);
  350.             String token;
  351.             String text = "";
  352.             do {
  353.                 token = st.nextToken();
  354.                 String append;
  355.                 if(token.equals(replace)) {
  356.                     append = repsym.text;
  357.                     //System.out.print("replaced "+replace+" with "+repsym.text+"  ");
  358.                 }
  359.                 else
  360.                     append = token;
  361.                 text = text + append;
  362.             } while(st.hasMoreTokens());
  363.             sym.text = text;
  364.         } while(unrec_strings.hasMoreTokens());
  365.         sym.undefined_tokens = null;
  366. //        System.out.println("JIT parsing succeeded for "+sym.name);
  367.         return true;
  368.     }
  369.  
  370.     /**
  371.      * Parses a C number and returns a symbol containing it.  Don't try editing
  372.      * without a spatula.
  373.      * @param st StreamTokenizer positioned on a number or a '-'.
  374.      * @return symbol holding the int, long, or double.
  375.      */
  376.     protected symbol parseNum(StreamTokenizer st) throws IOException
  377.     {
  378.         if(st.ttype != st.TT_NUMBER && st.ttype != '-') {
  379.             System.out.println("Invalid StreamTokenizer in parseNum!");
  380.             System.exit(6);
  381.         }
  382.         symbol sym = new symbol();
  383.         String text = "";
  384.         boolean negative = false;
  385.         boolean doULcheck = true;
  386.         if(st.ttype=='-') {
  387.             st.nextToken();
  388.             negative = true;
  389.         }
  390.         sym.isInt = true;
  391.         Double d = new Double(st.nval);  // we never have float values in #defines.
  392.         text = text+d.intValue();
  393.         if(st.nval==0.0) { // check for hex.
  394.             st.nextToken();
  395.             if(st.ttype == st.TT_WORD && st.sval.toLowerCase().startsWith("x")) {
  396.                 String append = "";
  397.                 if(st.sval.toUpperCase().endsWith("UL"))
  398.                     append="0"+st.sval.substring(0, st.sval.length()-2);
  399.                 else if(st.sval.toUpperCase().endsWith("L") || st.sval.toUpperCase().endsWith("U"))
  400.                     append="0"+st.sval.substring(0, st.sval.length()-1);
  401.                 else
  402.                     append = "0"+st.sval;
  403.                 if(append.length()>10) {
  404.                     sym.isLong = true;
  405.                     append = append+"L";
  406.                 }
  407.                 text = append;
  408.                 doULcheck = false;
  409.             }
  410.             else {
  411.                 st.pushBack();
  412.                 doULcheck = true;
  413.             }
  414.         }
  415.  
  416.         if(doULcheck) { // Do U & L check, plus E
  417.             // U - unsigned   L - long   E - 10^x
  418.             st.nextToken();
  419.             if(st.ttype == st.TT_WORD) {
  420.                 if(st.sval.toUpperCase().equals("L") || st.sval.toUpperCase().equals("U")
  421.                     || st.sval.toUpperCase().equals("UL")) {
  422.                     //System.out.println("Found a long...");
  423.                     //sym.isLong = true;
  424.                     //text = text+"L";
  425.                 }
  426.                 else if(st.sval.toUpperCase().startsWith("E")) {
  427.                     sym.isDouble = true;
  428.                     sym.isInt = false;
  429.                     text = text+st.sval.toUpperCase();
  430.                 }
  431.                 else  // Should never be called?
  432.                     st.pushBack();
  433.             }
  434.             else
  435.                 st.pushBack();
  436.         }
  437.  
  438.         if(negative)
  439.             text = "-"+text;
  440.         sym.name = "Integer";
  441.         sym.text = text;
  442.         return sym;
  443.     }  // end parseNum
  444.  
  445.  
  446.     /**
  447.      * Parse a string of words, trying to unroll known symbols if possible.
  448.      * terminator should usually be StreamTokenizer.TT_EOL or ')'.
  449.      * <p>Ideally, parseWords will leave st on the terminator, but occasionally it will be
  450.      * on the EOL character.  It will add the symbol to UnrecognizedSymbols if appropriate,
  451.      * but not Symbols table.</p>
  452.      * <p>Currently it puts undefined symbols into the symbol once per occurrence!
  453.      * So something like: #define foo (x+x)  contains x twice.  JIT test takes slightly longer.
  454.      * Not very serious.</p>
  455.      * <p>BUGBUG: Casting doesn't work.</p>
  456.      * @param st StreamTokenizer positioned at the start of a word or expression [like a '('].
  457.      * @param terminator char to use as a token to end this expression (often ';' or ')')
  458.      * @param moreThanOneWord whether this expression can be longer than one word
  459.      * @param nested true if this is a recursive call to parseWords, else false.
  460.      * @param name Name of the symbol to return (ie, #define FOO 1  would have FOO as the name)
  461.      * @param pretext String to append before symbol text (used for casting)
  462.      * @param posttext String to append after symbol text (used for casting)
  463.      * @return symbol containing the parsed expression
  464.      * @exception IOException if st hits a problem
  465.      */
  466.     protected symbol parseWords(StreamTokenizer st, char terminator, boolean moreThanOneWord, boolean nested, String name, String pretext, String posttext) throws IOException {
  467.         // Booleans will be set here, but should also be set externally too.
  468.         boolean isBool = false;
  469.         boolean isChar = false;
  470.         boolean isString = false;
  471.         boolean isInt = false;
  472.         boolean isLong = false;
  473.         boolean isDouble = false;
  474.         boolean isComplex = false;  // True if its something non-trivial, like (0x1|CONSTANT)
  475.         boolean unknown = false;
  476.         boolean firstTime = true;
  477.         symbol retsym = new symbol();
  478.         retsym.name = name;
  479.         String text = pretext;
  480.         if(st.ttype == terminator || st.ttype==st.TT_EOL || st.ttype==st.TT_EOF)
  481.             return null;
  482.         do {
  483.             if(!firstTime)
  484.                 isComplex = true;
  485.             String append = "";
  486.             // Must eventually add in handling for ' and ".
  487.             // Handle Unicode strings and characters.
  488.             if(st.ttype==st.TT_WORD && st.sval.toUpperCase().equals("L")) {
  489.                 st.nextToken();
  490.                 // Normal characters are ' and ", but , and ) are common wrong cases...
  491.                 if(st.ttype == ',' || st.ttype==')')
  492.                     st.pushBack();
  493.                 else if(st.ttype != '\'' && st.ttype != '\"')
  494.                     System.out.println("Odd syntax: in "+name+", found L then not a string or char literal!");
  495.             }
  496.             if(st.ttype == '\'') {
  497.                 // When hitting a \', StreamTokenizer puts the character into sval.
  498.                 isChar = true;
  499.                 append = "\'"+st.sval+"\'";
  500.                 //System.out.println("Char "+name+" defined as "+text);
  501.             }
  502.             else if(st.ttype == '\"') {
  503.                 isString = true;
  504.                 append = '\"' + st.sval + '\"';
  505.             }
  506.             else if(st.ttype == st.TT_WORD && (st.sval.equals("MAKEINTRESOURCE") ||
  507.                 st.sval.equals("_HRESULT_TYPEDEF_") || st.sval.equals("TEXT"))) {
  508.                 // MAKEINTRESOURCE is used frequently in winuser.h.  It does some odd casting.
  509.                 // _HRESULT_TYPEDEF_ just returns the symbol.  Does nothing basically.
  510.                 String macroname = st.sval;
  511.                 st.nextToken();  // Read in '('
  512.                 st.nextToken();  // position right after '('
  513.                 if(st.ttype == '(') {
  514.                     System.out.println("Found a cast inside a "+macroname+" call.");
  515.                     st.nextToken();  // st = cast_type
  516.                     st.nextToken();  // st = ')'
  517.                     st.nextToken();  // position after trailing ')'
  518.                 }
  519.                 isInt = true;
  520.                 retsym = parseWords(st, ')', true, true, name, "", "");
  521.                 if(retsym.hasUndefinedTokens()) {
  522.                     System.out.println(macroname+" handler: "+name+" has unrecognized tokens!");
  523.                     System.out.println(retsym.undefined_tokens);
  524.                 }
  525.                 return retsym;
  526.             }
  527.             else if(st.ttype==st.TT_WORD && (st.sval.toUpperCase().equals("TRUE") || st.sval.toUpperCase().equals("FALSE"))) {
  528.                 // Boolean handler.
  529.                 isBool = true;
  530.                 System.out.println("Handling boolean "+name);
  531.                 if(st.sval.toUpperCase().equals("TRUE"))
  532.                     append = "true";
  533.                 else
  534.                     append = "false";
  535.             }
  536.             else if(st.ttype == st.TT_WORD) {
  537.                 //System.out.println("in parsewords on "+name+", found a string "+st.sval);
  538.                 // Necessary Function Alias check.
  539.                 if(firstTime && st.sval.startsWith(name) && st.sval.length() == name.length()+1) {
  540.                     //System.out.println("Skipping definition of function alias for "+name);
  541.                     skippedAliases++;
  542.                     retsym = null;
  543.                     return retsym;
  544.                 }
  545.  
  546.                 // If possible, substitute the value for this symbol
  547.                 symbol value = (symbol) Symbols.get(st.sval);
  548.                 if(value==null) {
  549.                     //System.out.println("in parseWords, expression has unknown symbol in it! "+name+" text: "+text+" symbol: "+st.sval);
  550.                     unknown = true;
  551.                     append = st.sval;
  552.                     retsym.addUndefToken(st.sval);
  553.                 }
  554.                 else {
  555.                     //System.out.println(st.sval+" -> "+value.text);
  556.                     append = value.text;
  557.                     if(value.isInt)
  558.                         isInt = true;
  559.                 }
  560.             }
  561.             else if(st.ttype == st.TT_NUMBER) { // Don't put '-' here.  More flexible this way.
  562.                 symbol sym = parseNum(st);
  563.                 if(sym == null) {
  564.                     System.out.println("Ack! Unparsible int-like number.  name: "+name);
  565.                     retsym = null;
  566.                     skippedUnparsible++;
  567.                     return retsym;
  568.                 }
  569.                 append = sym.text;
  570.                 isInt = sym.isInt;
  571.                 isLong = sym.isLong;
  572.                 //System.out.println("Read an integer. "+append+" isInt: "+isInt+" isLong: "+isLong);
  573.             }                            
  574.             else if(st.ttype == '(') {
  575.                 // This section is mostly for ignoring parenthesized casts, like:
  576.                 // #define x ((int) y)
  577.                 st.nextToken();
  578.                 if(st.ttype == st.TT_WORD && (st.sval.equals("int") || st.sval.equals("DWORD")
  579.                       || st.sval.equals("WORD") || st.sval.equals("HTREEITEM"))) {
  580.                     st.nextToken();
  581.                     //System.out.println("Found something like a int cast in "+name);
  582.                     if(st.ttype == ')') {
  583.                         //System.out.println("For "+name+", found an int cast.");
  584.                         isInt = true;
  585.                         // Let loop test handle positioning issues.
  586.                         continue;
  587.                     }
  588.                     else
  589.                         st.pushBack();
  590.                 }
  591.                 else if(st.ttype == st.TT_WORD && st.sval.toUpperCase().equals("BYTE")) {
  592.                     st.nextToken();
  593.                     if(st.ttype == ')') {
  594.                         //System.out.println("For "+name+", found a BYTE cast.");
  595.                         isInt = true;
  596.                         // Let loop test handle positioning issues.
  597.                         continue;
  598.                     }
  599.                     else
  600.                         st.pushBack();
  601.                 }
  602.                 else {  // Normal parenthesized expression case.
  603.                     symbol trash = parseWords(st, ')', true, true, "embedded from "+name, "", "");
  604.                     if(trash == null) { // the normal case
  605.                         System.out.println(name+" had an unrecognized parenthesized expression! Guessing it was a parenthesized cast.");
  606.                         skippedUnparsible++;
  607.                         if(st.ttype != st.TT_EOL)
  608.                             while(st.nextToken() != st.TT_EOL && st.ttype != st.TT_EOF);
  609.                         unknown = true;
  610.                         retsym = null;
  611.                         return retsym;
  612.                     }
  613.                     else {
  614.                         //System.out.println("Wow.  Got embedded expression from "+name+".  text was "+trash.text);
  615.                         append = '('+trash.text+')';
  616.                         isBool = isBool | trash.isBool;
  617.                         isInt = isInt | trash.isInt;
  618.                         isLong = isLong | trash.isLong;
  619.                         isDouble = isDouble | trash.isDouble;
  620.                         isChar = isChar | trash.isChar;
  621.                         isString = isString | trash.isString;
  622.                         isComplex = true;
  623.                     }
  624.                 }
  625.             }
  626.             else if(st.ttype == '+' || st.ttype == '-' || st.ttype == '/' || st.ttype == '&' ||
  627.                       st.ttype == '|' || st.ttype == '~' || st.ttype == '<' || st.ttype == '>' ||
  628.                       st.ttype == '#')
  629.             {
  630.                 //System.out.println("Appending operator "+(char)st.ttype);
  631.                 append = ""+(char)st.ttype;
  632.                 if(st.ttype=='#') {
  633.                     System.out.println("General interest note: Added operator \'#\' to "+name+", thinking I\'ve found string##string");
  634.                 }
  635.             }
  636.             else {
  637.                 //System.out.println("Appending unrecognized token "+(char)st.ttype);
  638.                 append = ""+(char)st.ttype;
  639.             }
  640.  
  641.             text = text + append;
  642.             firstTime = false;            
  643.         } while(st.nextToken() != st.TT_EOL && st.ttype != terminator && moreThanOneWord && st.ttype != st.TT_EOF);
  644.  
  645.         if(!moreThanOneWord) {
  646.             if(st.ttype != terminator && st.ttype != st.TT_EOF) {
  647.                 System.out.println("Ack!  Serious error in parseWords.  Expected one word, got multiple. name: "+name+"  text: "+text);
  648.             }
  649.         }
  650.  
  651.         if(st.ttype != terminator || retsym == null) {
  652.             if(!nested) {
  653.                 while(st.ttype != st.TT_EOL && st.ttype != st.TT_EOF)
  654.                     st.nextToken();
  655.                 skippedUnterminatedExpressions++;
  656.                 //System.out.println("parseWords ignoring unterminated expression "+name);
  657.             }
  658.             return null;
  659.         }
  660.         retsym.text = text + posttext;
  661.         retsym.setTypes(isBool, isInt, isLong, isDouble, isChar, isString, isComplex);
  662.  
  663.         if(isBool)
  664.             System.out.println("Found boolean "+name);
  665.  
  666.         if(st.ttype != terminator && st.ttype != st.TT_EOL) {
  667.             System.out.println("Ack!!! st not positioned properly while reading "+name+"! st.ttype: "+(char)st.ttype+" sval: "+st.sval);
  668.             System.exit(12);
  669.         }
  670.  
  671.         // Macro and cast check
  672.         if(!nested && terminator == ')' && st.ttype == terminator) {
  673.             st.nextToken();
  674.             if(st.ttype != st.TT_EOL) {
  675.                 //System.out.println("Found macro or unparenthesized cast "+name);
  676.                 skippedMacros++;
  677.                 while(st.nextToken() != st.TT_EOL && st.ttype != st.TT_EOF);
  678.                 return null;
  679.             }
  680.         }
  681.  
  682.         if(unknown) {
  683.             if(!nested) {
  684.                 //System.out.println("parseWords punted on unknown "+retsym.name+" = "+retsym.text);
  685.                 skippedSymbols++;
  686.                 UnrecognizedSymbols.addElement(retsym);
  687.             }
  688.             return null;
  689.         }
  690.         else {
  691.             //System.out.println("parseWords returning "+retsym.name+" = "+retsym.text);
  692.             return retsym;
  693.         }
  694.     }
  695.     
  696.  
  697.     public void scan(String infile) throws IOException
  698.     {
  699.         InputStreamReader isr = new InputStreamReader(new FileInputStream(infile));
  700.         StreamTokenizer st = new StreamTokenizer(isr);
  701.         st.eolIsSignificant(true);
  702.         st.wordChars('_', '_');
  703.         st.wordChars(':', ':');
  704.         st.ordinaryChar('/');
  705.         st.ordinaryChar('-');
  706.         st.ordinaryChar('+');
  707.         st.ordinaryChar('*');
  708.         st.slashSlashComments(true);
  709.         st.slashStarComments(true);
  710.     //    st.wordChars('0', '9');
  711.         boolean lastWasInt = false;
  712.         boolean lastWasString = false;
  713.  
  714.         st.nextToken();
  715.  
  716.         // Must use labelled while loop here to more easily exit out of function.
  717.         // Loop invariant - if this is a valid line, then st is positioned on the # at
  718.         // the beginning of this loop.  And the second token after # is name.
  719.         // However, we do have lines like:  * some comment text mentioning #define foo
  720. lineproc: while(st.ttype != st.TT_EOF) {
  721.             total++;
  722.             st.nextToken(); // read define
  723.             st.nextToken(); // read name
  724.             if(st.ttype != st.TT_WORD) {
  725.                 System.out.println("Ack!  not good!");
  726.                 System.out.println("Instead of a name, we found "+(char)st.ttype+" sval: "+st.sval);
  727.                 System.out.println("Loop invariant broken in file "+infile+", or data file in unrecognized format.");
  728.                 System.exit(8);
  729.             }
  730.             String name = st.sval;
  731.             //System.out.println("name: "+name);
  732.             if(name.equals("define")) {
  733.                 System.out.println("Critical error: name was define.  Loop invariant broken.");
  734.                 System.exit(13);
  735.             }
  736.             st.nextToken();
  737.             String text = "";
  738.             boolean isBool = false;
  739.             boolean isChar = false;
  740.             boolean isString = false;
  741.             boolean isInt = false;
  742.             boolean isLong = false;
  743.             boolean isDouble = false;
  744.             boolean isComplex = false;  // True if its something non-trivial, like (0x1|CONSTANT)
  745.             boolean CommentOut = false;
  746.  
  747.             if(st.ttype == st.TT_WORD && st.sval.toUpperCase().equals("L")) {
  748.                 // What we have next is a Unicode character or string, I think...
  749.                 st.nextToken();
  750.                 if(st.ttype != '\'' && st.ttype != '\"') {
  751.                     System.out.println("Error: Found L followed by something other than a \' or \"! token: "+(char)st.ttype);
  752.                     System.exit(14);
  753.                 }
  754.             }
  755.  
  756.             if(st.ttype == '\\' || st.ttype == '{' || st.ttype == '&') {
  757.                 total--;
  758.                 while(st.nextToken() != st.TT_EOL && st.ttype!=st.TT_EOF);
  759.                 st.nextToken();
  760.                 continue;
  761.             }
  762.             else if(st.ttype == '\'') {
  763.                 // When hitting a \', StreamTokenizer puts the character into sval.
  764.                 isChar = true;
  765.                 //st.nextToken();
  766.                 text = "\'"+st.sval+"\'";
  767.                 //System.out.println("Char "+name+" defined as "+text);
  768.                 st.nextToken();
  769.             }
  770.             else if(st.ttype == '(') {
  771.                 // Skip macros.  But check for something like #define FLAG (-1)
  772.                 // And try to parse complex expressions like #define z (y+1)
  773.                 st.nextToken();
  774.                 text = "(";
  775.  
  776.                 if(st.ttype != ')') {
  777.                     symbol blah = parseWords(st, ')', true, false, name, text, ")");
  778.                     if(st.ttype == ')')
  779.                         st.nextToken();
  780.                     if(blah == null) {
  781.                         // Macros will go through this part of the code.  So will 
  782.                         // unparenthesized casts, like #define x (int)y
  783.                         if(st.ttype != st.TT_EOL) {
  784.                             // Found a macro.
  785.                             //skippedMacros++;
  786.                             //skippedSymbols--;
  787.                             System.out.println("Skipping macro "+name+"... ");
  788.                             removeSymbol(name, UnrecognizedSymbols);
  789.                             while(st.nextToken() != st.TT_EOL && st.ttype != st.TT_EOF);
  790.                             st.nextToken();
  791.                             continue lineproc;
  792.                         }
  793.                         System.out.println("parsewords gave up on expression starting with '(' "+name);
  794.                         if(st.ttype != st.TT_EOL)
  795.                             while(st.nextToken() != st.TT_EOL && st.ttype != st.TT_EOF);
  796.                         st.nextToken();
  797.                         continue lineproc;
  798.                     }
  799.                     else {
  800.                         //blah.text = blah.text + ')';
  801.                         isComplex = blah.isComplex;
  802.                         isBool = blah.isBool;
  803.                         isInt = blah.isInt;
  804.                         isLong = blah.isLong;
  805.                         isDouble = blah.isDouble;
  806.                         isChar = blah.isChar;
  807.                         isString = blah.isString;
  808.                         text = blah.text;
  809. //                        Symbols.put(blah.name, blah);
  810.                         // If we get here and st isn't at EOL, freak below in loop invariant check.
  811.                     }
  812.                 }
  813.                 else {
  814.                     System.out.println("Weird case: found "+name+" ( ) and I don't know what to do with it.");
  815.                     System.out.println("Punting "+name+" as a macro...");
  816.                     skippedMacros++;
  817.                     while(st.nextToken() != st.TT_EOL && st.ttype != st.TT_EOF);
  818.                     st.nextToken();
  819.                     continue lineproc;
  820.                 }
  821.             } // End '(' handler
  822.             else if(st.ttype == '\"') {
  823.                 // When finding a quoteChar, StreamTokenizer puts the string in the sval field
  824.                 // But that's the wrong approach because that way strings could span lines,
  825.                 // or at least that's what I think...  Not sure.  Very odd results.
  826.  
  827.                 // For now ignore strings.
  828.                 //System.out.println("Skipping string "+name);
  829.                 //skippedStrings++;
  830.                 /*
  831.                 while(st.nextToken() != st.TT_EOL && st.ttype != st.TT_EOF);
  832.                 st.nextToken();
  833.                 continue;
  834. */
  835.  
  836.                 isString = true;
  837.                 text = "\""+st.sval+"\"";
  838.                 st.nextToken();
  839.                 if(st.ttype != st.TT_EOL) {
  840.                     System.out.println("Ack!  Found non-EOL token "+(char)st.ttype+" after string!");
  841.                     System.exit(9);
  842.                 }
  843.  
  844.                 if(st.ttype != st.TT_EOL)
  845.                     st.nextToken();
  846.                 //System.out.println("String "+name+" defined as "+text);
  847.  
  848.             }
  849.             else if(st.ttype == st.TT_NUMBER || st.ttype=='-') {
  850.                 // Normal number handler.
  851.                 symbol sym = parseNum(st);
  852.                 if(sym == null)
  853.                     continue;
  854.                 text = sym.text;
  855.                 isInt = sym.isInt;
  856.                 isLong = sym.isLong;
  857.                 isDouble = sym.isDouble;
  858.                 //System.out.println("Read an integer. "+text+" isInt: "+isInt+" isLong: "+isLong);
  859.  
  860.                 st.nextToken(); // read in TT_EOL.  If not here, we should freak in loop invariant.
  861.             }
  862.             else if(st.ttype == st.TT_WORD) {
  863.                 // Something like:  #define SOMEINT 1     #define FOO SOMEINT
  864.                 // or could be #define CreateWindow CreateWindowW
  865.  
  866.                 // More special parseWords code
  867.                 symbol value = parseWords(st, (char)st.TT_EOL, false, false, name, "", "");
  868.                 if(value == null) {
  869.                     //System.out.println("while reading a word, parseWords gave up on "+name);
  870.                     if(st.ttype != st.TT_EOL)
  871.                         while(st.nextToken() != st.TT_EOL && st.ttype != st.TT_EOF);
  872.                     st.nextToken();
  873.                     continue lineproc;
  874.                 }
  875.                 else {
  876.                     isBool = value.isBool;
  877.                     isChar = value.isChar;
  878.                     isString = value.isString;
  879.                     isLong = value.isLong;
  880.                     isDouble = value.isDouble;
  881.                     isInt = value.isInt;
  882.                     isComplex = value.isComplex;
  883.                     text = value.text;
  884.                     if(st.ttype != st.TT_EOL)
  885.                         st.nextToken();
  886.                     if(st.ttype != st.TT_EOL) {
  887.                         System.out.println("Not at end of line.  macro? "+name);
  888.                         while(st.nextToken() != st.TT_EOL && st.ttype != st.TT_EOF);
  889.                     }
  890.                 }
  891.  
  892.                 /*
  893.                 // Necessary Function Alias check.
  894.                 if(text.startsWith(name) && text.length() == name.length()+1) {
  895.                     System.out.println("Skipping definition of function alias for "+text);
  896.                     skippedAliases++;
  897.                     if(st.ttype != st.TT_EOL)  // This will almost never be true.
  898.                         while(st.nextToken() != st.TT_EOL && st.ttype != st.TT_EOF);
  899.                     if(st.ttype !=st.TT_EOF)
  900.                         st.nextToken();
  901.                     continue;
  902.                 }
  903.                 */
  904.             }  // end Word handler. (plus function alias handler)
  905.             else if(st.ttype == st.TT_EOL) {
  906.                 // Found a defined symbol, but with no value assigned to it.
  907.                 //isInt = true;
  908.                 //text = "1";
  909.                 st.nextToken();
  910.                 skippedNoValue++;
  911.                 continue lineproc;
  912.             }
  913.  
  914.  
  915.             // Now handle symbol lookup rules.
  916.  
  917.             // If this is a redefinition, comment this out.
  918.             if(Symbols.containsKey(name)) {
  919.                 //System.out.println("Not redefining "+name);
  920.                 CommentOut = true;
  921.                 skippedRedefined++;
  922.                 symbol s = (symbol) Symbols.get(name);
  923.                 if(s.text.equals(text)) {
  924.                     if(st.ttype!=st.TT_EOF)
  925.                         st.nextToken();
  926.                     continue;
  927.                 }
  928.             }
  929.  
  930.             // If it's a String or a Character or a complex blob of tokens, don't expect
  931.             // it to appear in the symbol table.  If it's an int, its shaky.  That's because
  932.             // while an int could be something like (-1), an int could also be something 
  933.             // like #define FOO 1   then #define THIS_IS_AN_INT FOO
  934.             if(!isBool && !isString && !isChar && !isLong && !isComplex) {
  935.                 //StringTokenizer str = new StringTokenizer(text);
  936.                 if(text.length()==0)
  937.                     System.out.println("Ack!  for "+name+", text was length 0!");
  938.                 char c = text.charAt(0);
  939.                 if(!Character.isDigit(c) && c != '-'  & c!='(') {
  940.                     symbol s = (symbol) Symbols.get(text);
  941.                     // Extremely simple and underpowered parse attempt. look at jitParse...
  942.                     if(s == null) {
  943.                         //System.out.println("Symbol "+text+" not found.  Will try "+name+" later.");
  944.                         symbol unrec_sym = new symbol();
  945.                         unrec_sym.name = name;
  946.                         unrec_sym.text = text;
  947.                         unrec_sym.setTypes(isBool, isInt, isLong, isDouble, isChar, isString, isComplex);
  948.                         UnrecognizedSymbols.addElement(unrec_sym);
  949.                         st.nextToken();
  950.                         skippedSymbols++;
  951.                         continue lineproc;
  952.                     }
  953.                     else
  954.                         text = s.text;
  955.                 }
  956.             }
  957.  
  958.             // Create a symbol and insert into Symbol table.
  959.             symbol sym = null;
  960.             sym = new symbol();
  961.             sym.name = name;
  962.             sym.text = text;
  963.             sym.setTypes(isBool, isInt, isLong, isDouble, isChar, isString, isComplex);
  964.             if(!CommentOut) {
  965.                 Symbols.put(name, sym);
  966.  
  967. // This is a deprecated check.
  968. //                if(sym.isString && !SuppressStrings) // Skip strings for now.
  969. //                    skippedStrings++;
  970. //                else
  971.                     outputted++;
  972.             }
  973.  
  974.             // Call first to output to alphabetical file
  975.             OutputToFile(sym, CommentOut, false);
  976.             // Call a second time to output to global output file.
  977.             OutputToFile(sym, CommentOut, true);
  978.             
  979.             if(!isBool && !isString && !isInt && !isChar && !isDouble) {
  980.                 System.out.println("Neither isBool nor isString nor isInt nor isChar nor isDouble were true! name: "+name+" text: "+text);
  981.             }
  982.  
  983.             // Loop invariant check and preservation code.  This is probably the
  984.             // only safe place for this test, sadly.  Plus it can't get much fancier.
  985.             if(st.ttype != st.TT_EOL) {
  986.                 System.out.println("loop invariant broken file: "+infile+".  name&text: "+name+"\t"+text+". st.ttype="+(char)st.ttype+"  Quitting.");
  987.                 System.exit(1);
  988.             }
  989.             st.nextToken();  // Must move past EOL to # or possibly EOF
  990.         }
  991.         isr.close();
  992.         isr = null;
  993.         st = null;
  994.     }
  995.  
  996.     public void scanfromFile(String filename) throws IOException
  997.     {
  998.         try {
  999.         InputStreamReader isr = new InputStreamReader(new FileInputStream(filename));
  1000.         StreamTokenizer st = new StreamTokenizer(isr);
  1001.         st.eolIsSignificant(false);
  1002.         while(st.nextToken() != st.TT_EOF) {
  1003.             scan("defs/"+st.sval);
  1004.         }
  1005.         isr.close();
  1006.         isr = null;
  1007.         st = null;
  1008.         }
  1009.         catch (IOException e) {
  1010.             System.out.println("Problem: "+e+" while opening "+filename);
  1011.             throw e;
  1012.         }
  1013.     }
  1014.  
  1015.     /**
  1016.      * Generates output from symbol, writing output to either the proper alphabetical
  1017.      * file or to the global output file.  Handles cases such as first line in file and
  1018.      * the type being the same as the last type in the file, removing type declarations.
  1019.      * This is pretty slick.
  1020.      * @param sym #symbol to output
  1021.      * @param CommentOut whether this line should be commented out or not
  1022.      * @param globalOutput should we send this to the global output file OR the proper alphabetical file
  1023.      * @return No return value.
  1024.      */
  1025.     public void OutputToFile(symbol sym, boolean CommentOut, boolean globalOutput) throws IOException
  1026.     {
  1027.         if(sym == null) {
  1028.             System.err.println("Not going to deal with null symbols in OutputToFile!");
  1029.             System.exit(7);
  1030.         }
  1031.  
  1032.         // Select the correct file to output in.
  1033.         FileWrapper f=null;
  1034.         if(globalOutput)
  1035.             f = (FileWrapper) Files.elementAt(global_output);
  1036.         else if(sym.isString && SeparateStrings)
  1037.             f = (FileWrapper) Files.elementAt(string_output);
  1038.         else {
  1039.             // Name tells us which file to put output in.
  1040.             char first = Character.toLowerCase(sym.name.charAt(0));
  1041.             if(first >= 'a' && first <= 'z')
  1042.                 f = (FileWrapper) Files.elementAt(first - 'a');
  1043.             else
  1044.                 f = (FileWrapper) Files.elementAt(misc_output);
  1045.         }
  1046.  
  1047.         // Now set all the necessary output strings which depend on this symbol and this file.
  1048.         String header = ";\r\n\t";  // normal case
  1049.         if(f.veryFirstLine) {
  1050.             header = "\t";
  1051.             f.veryFirstLine = false;
  1052.         }
  1053.         boolean isSameType = false;
  1054.         // Check to see whether this type is the same as the last type.
  1055.         if((sym.isString && f.lastWasString) || (sym.isInt && f.lastWasInt && !sym.isLong) ||
  1056.             (f.lastWasLong && sym.isLong) || (sym.isChar && f.lastWasChar) ||
  1057.             (sym.isDouble && f.lastWasDouble) || (sym.isBool && f.lastWasBool)) 
  1058.         {
  1059.             header = ",\r\n\t\t";
  1060.             isSameType = true;
  1061.         }
  1062.  
  1063.         if(CommentOut)
  1064.             header = ";\r\n\t// ";
  1065.  
  1066.         String output = header;
  1067.         if(!isSameType) {
  1068.             if(sym.isInt) {
  1069.                 if((f.lastWasInt && !sym.isLong) || (f.lastWasLong && sym.isLong))
  1070.                     output = header;
  1071.                 else {
  1072.                     if(sym.isLong)
  1073.                         output = header+"long ";
  1074.                     else
  1075.                         output = header+"int ";
  1076.                 }
  1077.             }
  1078.             else if(sym.isDouble) {
  1079.                 output = header+"double ";
  1080.             }
  1081.             else if(sym.isString) {
  1082.                 output = header+"String ";
  1083.             }
  1084.             else if(sym.isChar) {
  1085.                 output = header+"char ";
  1086.             }
  1087.             else if(sym.isBool) {
  1088.                 output = header+"boolean ";
  1089.             }
  1090.             else if(sym.isComplex) {
  1091.                 output = header+"int ";
  1092.             }
  1093.             else
  1094.                 output = "\r\n\r\nAck!  Unknown type!";
  1095.         }
  1096.  
  1097.         output = output + sym.name + " = " + sym.text;
  1098.  
  1099.         if(CommentOut) { // set everything to false
  1100.             f.lastWasBool = false;
  1101.             f.lastWasInt = false;
  1102.             f.lastWasLong = false;
  1103.             f.lastWasChar = false;
  1104.             f.lastWasString = false;
  1105.         }
  1106.         else {
  1107.             f.lastWasBool = sym.isBool;
  1108.             f.lastWasInt = sym.isInt && !sym.isLong;
  1109.             f.lastWasLong = sym.isLong;
  1110.             f.lastWasChar = sym.isChar;
  1111.             f.lastWasString = sym.isString;
  1112.         }
  1113.         
  1114.         if(!sym.isBool && !sym.isString && !sym.isInt && !sym.isChar && !sym.isDouble) {
  1115.             System.out.println("Neither isBool nor isString nor isInt nor isChar nor isDouble were true! name: "+sym.name+" text: "+sym.text);
  1116.         }
  1117.  
  1118.         if(!CommentOut)
  1119.             f.numEntries++;
  1120.         f.stream.print(output);
  1121.     }
  1122.  
  1123.     protected void removeSymbol(String name, Vector search)
  1124.     {
  1125.         for(int i=0; i<search.size(); i++) {
  1126.             symbol s = (symbol) search.elementAt(i);
  1127.             if(s.name.equals(name)) {
  1128.                 search.removeElementAt(i);
  1129.                 System.out.println("Removed "+name);
  1130.             }
  1131.         }
  1132.     }
  1133.  
  1134.     /**
  1135.      * Scans through all symbols, looking for pairs that end in A and W 
  1136.      * (ASCII and Unicode versions) and creates a new one using the ASCII
  1137.      * value without the A or W.
  1138.      * @return No return value.
  1139.      */
  1140.     protected void UnifyAWSymbols()
  1141.     {
  1142.         // Make enumeration from hashtable Symbols.  Don't forget to check in UndefinedSymbols too...?
  1143.         symbol sym;
  1144.         System.out.print("Unifying symbols... ");
  1145.         Enumeration e = Symbols.elements();
  1146.         unifySymbolsHelper(e, true);
  1147.         e = UnrecognizedSymbols.elements();
  1148.         unifySymbolsHelper(e, false);
  1149.         System.out.println("Done unifying symbols.");
  1150.     }
  1151.  
  1152.     /**
  1153.      * Scans an enumeration for symbols to be unified, unifys them, then puts them
  1154.      * in either the Symbols or UnrecognizedSymbols table.
  1155.      * @param e Enumeration to scan.
  1156.      * @param recognized true if this e contains recognized symbols, false if it has unrecognized ones.
  1157.      */
  1158.     protected void unifySymbolsHelper(Enumeration e, boolean recognized)
  1159.     {
  1160.         symbol sym;
  1161.         while(e.hasMoreElements()) {
  1162.             String rootname = null;
  1163.             symbol ASCIIsym = null;
  1164.             symbol Unicodesym = null;
  1165.             sym = (symbol) e.nextElement();
  1166.             if(sym.name.endsWith("A")) {
  1167.                 ASCIIsym = sym;
  1168.                 rootname = sym.name.substring(0, sym.name.length()-1);
  1169.                 if(!Symbols.containsKey(rootname))
  1170.                     Unicodesym = (symbol) Symbols.get(rootname+"W");
  1171.             }
  1172.             else if(sym.name.endsWith("W")) {
  1173.                 Unicodesym = sym;
  1174.                 rootname = sym.name.substring(0, sym.name.length()-1);
  1175.                 if(!Symbols.containsKey(rootname))
  1176.                     ASCIIsym = (symbol) Symbols.get(rootname+"A");
  1177.             }
  1178.             if(Unicodesym != null && ASCIIsym != null) {
  1179.                 if(Unicodesym == ASCIIsym) {
  1180.                     System.out.println("For "+sym.name+", two symbol structures were exactly equal!");
  1181.                     continue;
  1182.                 }
  1183.                 System.out.println("Unifying symbols to "+rootname+"... ");
  1184.                 // For now, we always use the ASCII value, which is depressing.
  1185.                 // But its the only thing that will work on both 95 & NT.
  1186.                 symbol ins = new symbol();
  1187.                 ins.name = rootname;
  1188.                 ins.type = ASCIIsym.type;
  1189.                 ins.isBool = ASCIIsym.isBool;
  1190.                 ins.isChar = ASCIIsym.isChar;
  1191.                 ins.isString = ASCIIsym.isString;
  1192.                 ins.isInt = ASCIIsym.isInt;
  1193.                 ins.isLong = ASCIIsym.isLong;
  1194.                 ins.isDouble = ASCIIsym.isDouble;
  1195.                 ins.isComplex = ASCIIsym.isComplex;
  1196.                 ins.text = new String(ASCIIsym.text);
  1197.                 if(ASCIIsym.undefined_tokens != null)
  1198.                     ins.undefined_tokens = new String(ASCIIsym.undefined_tokens);
  1199.  
  1200.                 // Add to appropriate symbol storage and output to files.
  1201.                 if(recognized)
  1202.                     Symbols.put(rootname, ins);
  1203.                 else
  1204.                     UnrecognizedSymbols.addElement(ins);
  1205.                 try {
  1206.                     OutputToFile(ins, false, false);
  1207.                     OutputToFile(ins, false, true);
  1208.                     unifiedSymbols++;
  1209.                     total++;
  1210.                 }
  1211.                 catch(IOException ioe) {
  1212.                     System.out.println("Ack! Caught "+ioe+" while trying to output unified file name!");
  1213.                 }
  1214.             }
  1215.         }
  1216.     }
  1217.  
  1218.     public static void main(String args[])
  1219.     {
  1220.         try {
  1221.             defscan read = new defscan();
  1222.             read.out = new PrintWriter(new FileOutputStream("win.java"));
  1223.             read.out.print("\r\ninterface Constants\r\n{\r\n");
  1224.  
  1225.             if(args.length == 0) {
  1226.                 /*
  1227.                 System.out.println("Usage: defscan <file of #defines> [<more files>]");
  1228.                 System.exit(5);
  1229.                 */
  1230.                 System.out.println("Using file list \"files.txt\" as input files to search through.");
  1231.                 read.scanfromFile("files.txt");
  1232.             }
  1233.             else {
  1234.                 for(int i=0; i<args.length; i++) {
  1235.                     System.out.println("Processing "+args[i]+"... ");
  1236.                     read.scan(args[i]);
  1237.                 }
  1238.             }
  1239.  
  1240.             read.UnifyAWSymbols();
  1241.  
  1242.             read.HandleUnrecognizedSymbols();
  1243.  
  1244.             read.out.print(";\r\n\r\n}\r\n");
  1245.             read.out.close();
  1246.             read.CloseInterfaceFiles();
  1247.             float precentUnparsed = (float) (read.skippedUnterminatedExpressions + 
  1248.                 (read.skippedSymbols-read.resolvedLater) + read.skippedUnparsible) 
  1249.                 / (read.total - read.unifiedSymbols);
  1250.             System.out.println("Skipped "+read.skippedMacros+" macros and unparenthesized casts [example: #define x (int)y ]");
  1251.             System.out.println("Skipped "+read.skippedAliases+" function and structure aliases.");
  1252.             System.out.println("Skipped "+read.skippedSymbols+" unrecognized symbols, but "+read.resolvedLater+" were resolved later, leaving "+(read.skippedSymbols-read.resolvedLater)+".");
  1253.             System.out.println("Skipped "+read.skippedNoValue+" symbols defined without a value.");
  1254.             System.out.println("Skipped "+read.skippedRedefined+" redefined symbols.");
  1255. //            System.out.println("Read "+read.skippedStrings+" strings.");
  1256.             System.out.println("Skipped "+read.skippedUnterminatedExpressions+" unterminated expressions.");
  1257.             System.out.println("Skipped "+read.skippedUnparsible+" unparsible expressions (including parenthesized casts & pointers)");
  1258.             System.out.println("Read through "+read.total+" symbols.");
  1259.             System.out.println("Unified "+read.unifiedSymbols+" ASCII & Unicode redefined symbols.");
  1260.             System.out.println("Outputted "+read.outputted+" symbols.");
  1261.             System.out.println("Percentage unparsible: "+precentUnparsed*100.0);
  1262.  
  1263.             int diff = read.total - read.outputted - read.skippedAliases 
  1264.                 - read.skippedSymbols - read.skippedNoValue - read.skippedRedefined 
  1265.                 - read.skippedStrings
  1266.                 - read.skippedMacros - read.skippedUnterminatedExpressions - read.skippedUnparsible
  1267.                 + read.resolvedLater - read.unifiedSymbols;
  1268.             if(diff != 0)
  1269.                 System.out.println("I lost "+diff+" symbols!");
  1270.         }
  1271.         catch (IOException e)
  1272.         {
  1273.             System.out.println("IOException caught: "+e);
  1274.             for(int i=0; i<1000000; i++);
  1275.         }
  1276.         catch (Exception e)
  1277.         {
  1278.             System.out.println(e);
  1279.             e.printStackTrace();
  1280.         }
  1281.     }
  1282. }
  1283.