alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
 * Microsystems, Inc. All Rights Reserved.
 */
package org.netbeans.mdrshell;

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

/** Implements the #define and #include commands well known from C/C++
 *
 * @author  Petr Hrebejk        
 * @version 
 */

public class Preprocessor extends Object {

    /** #deinfe / #include command delimiters */
    private static final String DELIMITERS = " ";
    
    private static final char HASH ='#';
    private static final char BACK_QUOTE = '`';
    private static final String DEFINE = "#define";
    private static final String INCLUDE = "#include";
    private static final String UNDEFINE = "#undef";
    private static final String PARAMS = "[$]";
    
    
    /** Variables defined in this shell */
    Hashtable definedVariables;
    
    /** Parametrized variables (commands) in this shell */
    Hashtable definedParamVariables;

    /** The shell this preprocessor works for */
    private Shell shell;
    
    /** Creates new CommandPerformer 
    */
    Preprocessor( Shell shell ) {
        definedVariables = new Hashtable( 11 );
        definedParamVariables = new Hashtable( 11 );
        this.shell = shell;
    }
    
    /** Recognizes the commands and replaces predefined variables
    */
    String processLine( String line ) throws PreprocessorException {
        
        if ( processCommand( line ) ) {
            return null;
        }
        
        String processedLine = replaceVariables( line );
        
        return processedLine;
    }
    
    // Private methods ---------------------------------------------------------
    
    boolean processCommand( String line ) throws PreprocessorException {
        
        if ( line.charAt( 0 ) != HASH ) {
            return false;
        }
        
        StringTokenizer st = new StringTokenizer( line, DELIMITERS );

        int tokenCount = st.countTokens();

        if ( tokenCount == 0 ) {
            return false;
        }
        
        String command = st.nextToken();
            
        if ( command.equals( DEFINE ) ) {  // Handle the #define command
            
            if ( tokenCount < 2 ) {
                throw new PreprocessorException( "Variable not specified: " + line );
            }
      
            String variable = st.nextToken();
            
            String value = tokenCount == 2 ? "" : st.nextToken( "" ).trim();
            VariableDescriptor vd = new VariableDescriptor( variable, value );
            definedVariables.put( vd.getName(), vd );
            return true;  
        }
        else if ( command.equals( UNDEFINE ) ) {  // Handle the #undef command
           
            if ( tokenCount != 2 ) {
                throw new PreprocessorException( "Variable not specified: " + line );
            }
            
            String variable = st.nextToken();
            
            if ( definedVariables.get( variable ) == null ) {
                throw new PreprocessorException( "Variable " + variable + " not defined: " + line );
            }
                
            definedVariables.remove( variable );
            return true;                
        }   
        else if ( command.equals( INCLUDE ) ) { // Handle #include command
            if ( tokenCount == 1 ) {
                throw new PreprocessorException( "File not specified: " + line );
            }
            
            String fileName = st.nextToken( );
            
            File file = new File( fileName );
            try { 
                InputStream is = new FileInputStream( fileName );
                shell.pushInput( is );
            }
            catch ( java.io.FileNotFoundException e ) {
                throw new PreprocessorException( "File " + fileName + " not found: " + line );
            }
            return true;
        }
        else {
            return false;
        }
      
    }
    
    
    
    /** Replaces the variables in given string. 
    */
    private String replaceVariables( String line ) throws PreprocessorException {
        
        ArrayList tokens = tokenize( line );  // Get tokenized form of the line
        
        //printTokens( tokens );
    
        while( replaceVariables( tokens) );  // Replace variables until no is found
       
        // Now we need to find and remove all tokens which are just BACK_QUOTES 
        for( Iterator it = tokens.iterator(); it.hasNext(); ) {
            Token t = (Token)it.next();
            
            if ( t.ttype == BACK_QUOTE ) {
                it.remove();
            }
        }
       
        return restoreString(  tokens ); 
    }
       
     /** Replaces variables in tokenized string. Starts at startIndex 
     */    
     private boolean replaceVariables( ArrayList tokens ) {   
        
        for ( int i = tokens.size() - 1; i >= 0; i-- ) { // For all tokens from right to left
            
            Token t = (Token)tokens.get(i);
            
            if ( t.ttype != StreamTokenizer.TT_WORD )  // Skip whitespaces and separators
                continue; 
            
            // Test wether token equals to some variable
            Collection vars = definedVariables.keySet();
            for( Iterator it = vars.iterator(); it.hasNext(); ) {  // For all variables
                String variableName = (String)it.next();
                if ( t.sval.equals( variableName ) ) {
                    // Variable found replace it
                    replaceVariable( tokens, variableName, i );
                    return true;
                }
            }      
        }
        
        return false;
   
   
    }
        
    /** Replaces the variable in the tokeized string 
    */
    private void replaceVariable( ArrayList tokens, String variable, int index ) {
        
        VariableDescriptor vd = (VariableDescriptor)definedVariables.get( variable );
        
        tokens.remove( index ); // Removes the token with the variable
        
        ArrayList params = vd.extractParameters( tokens, index );  // Extract params and remove the tokens
       
        String variableValue = vd.getValue();
         
        if ( vd.isParam() ) { // We have replace the $n with param values in the variable value
            for( int i = vd.getParamCount(); i > 0 ; i-- ) { // For all params
                String paramName = "$" + i;
                while( variableValue.indexOf( paramName ) != -1 ) {  // For all occurences of the param
                    variableValue = replaceString( variableValue, paramName, (String)params.get( i - 1 ) );
                }
            }
        }
        
        ArrayList tv = tokenize( variableValue );
        
        if ( index >= tokens.size() ) {
            tokens.addAll( tv );
        }
        else {
            tokens.addAll( index, tv );
        }
                
    }    
        
        
    /** Parses a string to collection of tokens
    */
    private ArrayList tokenize( String line ) {
        
        ArrayList tokens = new ArrayList( 100 );
        
        StreamTokenizer stok = new StreamTokenizer( new StringReader( line ) );
   
        stok.resetSyntax();
        
        // Initialize the Stream tokenizer to standard Java except of parsing numbers
        stok.wordChars('a', 'z');
	stok.wordChars('A', 'Z');
	stok.wordChars(128 + 32, 255);
	//stok.whitespaceChars(0, ' ');
	stok.commentChar('/');
        stok.quoteChar('"');
	stok.quoteChar('\'');
        
        // Changes to standard Java
        
        
        // if ( quotas ) {
        //    stok.quoteChar('`');           // This quote means that the wohle token should be taken as 
                                                        // command parameter.
        //}
        //stok.quoteChar('~');                  // Tilda means execute command and put result as string into command
        stok.wordChars('$', '$');               // Command parameters
        stok.wordChars('_', '_');               // Underlines are part of identifiers
        stok.wordChars('0', '9');               // Take numbers as part of words
        stok.ordinaryChars(0, ' ');             // We want to know about spaces 
        stok.ordinaryChar(BACK_QUOTE); // We want to know about spaces 
        try {
            while ( stok.nextToken() != StreamTokenizer.TT_EOF ) {          
                tokens.add( new Token( stok.sval, stok.ttype ) );
            }
        }
        catch ( java.io.IOException e ) {
        }
        
        return tokens;
        
    }
    
    
    /** ReCreates a string from collection of tokens
    */
    private String restoreString( ArrayList tokens ) {
        
        StringBuffer sb = new StringBuffer( 200 );
        
        for ( Iterator it = tokens.iterator(); it.hasNext(); ) {
            Token token = (Token)it.next();
            
            if ( token.sval == null ) {
                sb.append( (char)token.ttype );
            }
            else if ( token.ttype < 0 ) {
                sb.append( token.sval );
            }
            else {
                sb.append( (char)token.ttype );
                sb.append( token.sval );
                sb.append( (char)token.ttype );
            }
        }
        
        return sb.toString();
    }
    
    private String replaceString( String in, String what, String by ) {
        
        StringBuffer sb = new StringBuffer( in );
        
        int index = in.indexOf( what );
        
        sb.delete( index, index + what.length() );
        sb.insert( index, by );
        
        return sb.toString();
    }
    
    // Innerclasses ------------------------------------------------------------
    
    /** Description of a defined variable 
    */
    private class VariableDescriptor extends Object {
        
        private String name;
        private String value;
        private boolean  isParam;
        private int paramCount; 
        
        VariableDescriptor( String var, String value ) {
            
            if ( var.endsWith( PARAMS ) ) {
                name = var.substring(0, var.length() - PARAMS.length() );
                isParam = true;
               
                for ( int i = 1; true; i++ ) {
                    String pname = "$" + i;
                    if ( value.indexOf( pname ) == -1 ) {
                        paramCount = i - 1;
                        break;
                    }
                }
            }
            else {
                name = var;
                isParam = false;
            }
            
            this.value = value;
        }
        
        String getName() {
            return name;
        }
        
        String getValue() {
            return value;
        }
        
        boolean isParam() {
            return isParam;
        }
        
        int getParamCount() {
            return paramCount;
        }
        
        /** Returns collection of strings representing the command parameters. The original
        * tokens are removed from the tokens list.
        */
        ArrayList extractParameters( ArrayList tokens, int index ) {
            
            if ( !isParam() ) {
                return null;
            }
            
            ArrayList parameters = new ArrayList( getParamCount() );
            
            Token t = (Token)tokens.get( index );
            
            for ( int i = 0; i < getParamCount(); i++ ) { // For all parameters
                
                try {
                    
                    while( t.ttype >= 0 && t.ttype <= 32 ) {  // Remove trailing spaces
                        tokens.remove( index );
                        t = (Token)tokens.get( index );
                    }
                    
                    StringBuffer sb = new StringBuffer( "" );
                    boolean isQuoted = false;
                    
                    if ( t.ttype == BACK_QUOTE ) {
                        isQuoted = true;
                        tokens.remove( index );
                        t = (Token)tokens.get( index );
                    }
                    
                    while( true ) {
                       
                        if ( (t.ttype >= 0 && t.ttype <= 32) || t.ttype == BACK_QUOTE ) {
                            if ( isQuoted && t.ttype == BACK_QUOTE ) {
                                tokens.remove( index );
                                break;
                            }
                            else if ( !isQuoted ) {
                                break;
                            }
                        }
                        
                        if ( t.sval == null ) {
                            sb.append( (char)t.ttype );
                        }
                        else if ( t.ttype < 0 ) {
                            sb.append( t.sval );
                        }
                        else {
                            sb.append( (char)t.ttype );
                            sb.append( t.sval );
                            sb.append( (char)t.ttype );
                        }
                        
                        tokens.remove( index ); 
                        
                        if ( index >= tokens.size()  ) {
                            break;
                        }
                        
                        t = (Token)tokens.get( index );
                    }
                    
                    parameters.add( sb.toString() );
                }
                catch( IndexOutOfBoundsException e ) {
                    parameters.add( "null" );
                }
                
            }
            
            return parameters;
        }
        
    }
    
    /** Token in a parsed string
    */
    private static class Token {
        
        String sval;
        int ttype;

        Token( String value, int type ) {
            sval = value;
            ttype = type;
        }
        
        public String toString() {
            return "[ " + sval + ", " + ttype + " ]";
        }

    }
    
    
    void printTokens( ArrayList tokens ) {
        
        System.out.print( "{ ");
        
        for( Iterator it = tokens.iterator(); it.hasNext(); ) {
            System.out.print( it.next() + ", ");
        }
        
        System.out.println(" }");
    }
    
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.