protected ASTNode internalParse(ILexer lexer) throws ParseException
    {
        /*
         * CHARACTERS,
         */

        /*
         *  -- terminals
         *  
         * TRUE := 'true'
         * FALSE := 'false'
         * IDENTIFIER := '_\\-0-9a-zA-Z'
         * EQUALS := '='
         * NOT := 'not'
         * OR := 'or'
         * AND := 'and'
         * 
         * --- 
         * NOT_TERM = NOT TERM
         * OR_TERM = EXPR OR TERM
         * AND_TERM = EXPR AND TERM
         * 
         *  TERM = IDENTIFIER | TRUE | FALSE | NOT_TERM | OR_TERM | AND_TERM | '(' TERM ')'
         *  
         *  EXPRESSION = TERM EQUALS TERM 
         */
        
        final int startOffset = lexer.currentParseOffset();
        ASTNode lastAddedNode = null;
        final Stack<OperatorNode> operatorStack = new Stack<OperatorNode>();
        final Stack<ASTNode> valueStack = new Stack<ASTNode>();   
        
        // System.out.println(" ---------- start: parse term ---------- ");
        do {
            final Token tok = lexer.peek();
            
            if ( tok.hasType( TokenType.IDENTIFIER ) ) 
            {
                lastAddedNode = pushToStack( operatorStack , valueStack , new IdentifierNode().parse(lexer ) , lastAddedNode  );
            } 
            else if ( tok.hasType( TokenType.TRUE ) ) 
            {
                lastAddedNode = pushToStack( operatorStack , valueStack , new TrueNode().parse(lexer ) , lastAddedNode  );
            } 
            else if ( tok.hasType( TokenType.FALSE ) ) 
            {
                lastAddedNode = pushToStack( operatorStack , valueStack , new FalseNode().parse(lexer ) , lastAddedNode );
            } 
            else if ( tok.hasType( TokenType.AND ) || tok.hasType( TokenType.NOT ) || tok.hasType( TokenType.OR)) 
            {
                lastAddedNode = pushToStack( operatorStack ,valueStack ,  new OperatorNode().parse(lexer ) , lastAddedNode );
            } 
            else if ( tok.hasType( TokenType.PARENS_OPEN ) ) 
            {
                lexer.read( TokenType.PARENS_OPEN );
                ASTNode parsed = new TermNode().internalParse(lexer);
                lastAddedNode = pushToStack( operatorStack ,valueStack , parsed , lastAddedNode  );
                lexer.read( TokenType.PARENS_CLOSE);                
            }
            else {
                break;
            }
            
        } while ( ! lexer.eof() );

        clearStacks( operatorStack , valueStack , lastAddedNode );

        if ( ! operatorStack.isEmpty() ) {
            throw new ParseException("Term stack not empty: "+operatorStack, startOffset );
        }
        // System.out.println(" ---------- finish: parse term : "+this+" ---------- ");
        
        assertNoEmptyTerms( startOffset );
        return this;
    }