private void manMung() { // 手动混淆,即由用户输入混淆变量
   JTable table = AnalyseWarnPanel.table;
   Set<ScriptOrFnScope> scopes = scopeSymbolMaping.keySet();
   Iterator<ScriptOrFnScope> scopesSetIt = scopes.iterator();
   int i = 0;
   while (scopesSetIt.hasNext()) {
     ScriptOrFnScope tmpScope = scopesSetIt.next();
     List<String> symbolList = scopeSymbolMaping.get(tmpScope);
     Iterator<String> symbolListIt = symbolList.iterator();
     while (symbolListIt.hasNext()) {
       String symbol = symbolListIt.next();
       JavaScriptIdentifier identifier = tmpScope.getIdentifier(symbol);
       String mungedValue = table.getValueAt(i, 1).toString().trim();
       if (identifier.isMarkedForMunging() && !mungedValue.equals("null")) {
         identifier.setMungedValue(mungedValue);
       }
       i++;
     }
   }
 }
  private void parseScope(ScriptOrFnScope scope) {

    String symbol;
    JavaScriptToken token;
    JavaScriptIdentifier identifier;

    int length = tokens.size();

    enterScope(scope); // 进入范围(将scope压入栈scopes中)

    while (offset < length) { // 在此函数调用前已设置为0

      token = consumeToken(); // 消费tokens,offset自增

      switch (token.getType()) {
        case Token.VAR: // 注意后面没有break;
          if (mode == BUILDING_SYMBOL_TREE) {
            scope.incrementVarCount(); // 当前范围内的var数量加1
          }

          /* FALLSTHROUGH(falls through) 失败 */

        case Token.CONST:

          // The var keyword is followed by at least one symbol name.
          // If several symbols follow, they are comma(逗号) separated.
          for (; ; ) {
            token = consumeToken();

            assert token.getType() == Token.NAME;
            // 判断关键字var、const后的变量是否已经定义,未定义则定义,已定义则输出警告
            if (mode == BUILDING_SYMBOL_TREE) {
              symbol = token.getValue();
              if (scope.getIdentifier(symbol) == null) {
                scope.declareIdentifier(symbol, true); // 声明标识符
              } else {
                warn("变量" + symbol + "已经在相同的作用域中声明", true);
              }
            }

            token = getToken(0); // offset不自增,token.getValue()的值一般为'='或';'

            assert token.getType() == Token.SEMI
                || token.getType() == Token.ASSIGN
                || token.getType() == Token.COMMA
                || token.getType() == Token.IN;

            if (token.getType() == Token.IN) {
              break;
            } else {
              parseExpression(); // 解释表达式(例如解释var a = 'u';或var a;)
              token = getToken(-1); // 得到的是';'
              if (token.getType() == Token.SEMI) { // 变量声明完成
                break;
              }
            }
          }
          break;

        case Token.FUNCTION:
          parseFunctionDeclaration();
          break;

        case Token.LC:
          braceNesting++;
          break;

        case Token.RC:
          braceNesting--;
          assert braceNesting >= scope.getBraceNesting();
          if (braceNesting == scope.getBraceNesting()) { // 说明要离开当前作用域了
            leaveCurrentScope(); // 离开当前作用域
            return;
          }
          break;

        case Token.WITH:
          if (mode == BUILDING_SYMBOL_TREE) {
            // Inside a 'with' block, it is impossible to figure out
            // statically whether a symbol is a local variable or an
            // object member. As a consequence, the only thing we can
            // do is turn the obfuscation off for the highest scope
            // containing the 'with' block.
            protectScopeFromObfuscation(scope);
            warn("不推荐使用with关键字。" + (munge ? " 使用with会降低压缩水平" : ""), true);
          }
          break;

        case Token.CATCH:
          parseCatch();
          break;

        case Token.CONDCOMMENT:
          if (mode == BUILDING_SYMBOL_TREE) {
            protectScopeFromObfuscation(scope);
            warn("不推荐使用JScript条件注释。" + (munge ? "使用JScript条件解释会降低压缩水平。" : ""), true);
          }
          break;

        case Token.NAME:
          symbol = token.getValue();

          if (mode == BUILDING_SYMBOL_TREE) {

            if (symbol.equals("eval")) {

              protectScopeFromObfuscation(scope);
              warn("不推荐使用'eval'关键字。" + (munge ? "使用'eval'会降低压缩水平!" : ""), true);
            }

          } else if (mode == CHECKING_SYMBOL_TREE) {

            if ((offset < 2 || getToken(-2).getType() != Token.DOT)
                && getToken(0).getType() != Token.OBJECTLIT) {

              identifier = getIdentifier(symbol, scope);

              if (identifier == null) {

                if (symbol.length() <= 3 && !builtin.contains(symbol)) {
                  // Here, we found an undeclared and
                  // un-namespaced symbol that is
                  // 3 characters or less in length. Declare it in
                  // the global scope.
                  // We don't need to declare longer symbols since
                  // they won't cause
                  // any conflict with other munged symbols.
                  globalScope.declareIdentifier(symbol, false);
                  // warn("Found an undeclared symbol: " + symbol,
                  // true);
                }

              } else {

                identifier.incrementRefcount();
              }
            }
          }
          break;
      }
    }
  }
  private void parseExpression() {

    // Parse the expression until we encounter a comma or a semi-colon
    // in the same brace nesting, bracket nesting(方括号嵌套) and paren nesting.
    // Parse functions if any...

    String symbol;
    JavaScriptToken token;
    ScriptOrFnScope currentScope;
    JavaScriptIdentifier identifier;

    int expressionBraceNesting = braceNesting; // 花括号嵌套
    int bracketNesting = 0; // 方括号嵌套
    int parensNesting = 0; //

    int length = tokens.size();

    while (offset < length) {

      token = consumeToken();

      currentScope = getCurrentScope(); // return scopes.peek();

      switch (token.getType()) {
        case Token.SEMI:
        case Token.COMMA:
          if (braceNesting == expressionBraceNesting && bracketNesting == 0 && parensNesting == 0) {
            return;
          }
          break;

        case Token.FUNCTION:
          parseFunctionDeclaration();
          break;

        case Token.LC:
          braceNesting++;
          break;

        case Token.RC:
          braceNesting--;
          assert braceNesting >= expressionBraceNesting;
          break;

        case Token.LB:
          bracketNesting++;
          break;

        case Token.RB:
          bracketNesting--;
          break;

        case Token.LP:
          parensNesting++;
          break;

        case Token.RP:
          parensNesting--;
          break;

        case Token.CONDCOMMENT:
          if (mode == BUILDING_SYMBOL_TREE) {
            protectScopeFromObfuscation(currentScope);
            warn("不推荐使用JScript条件注释。" + (munge ? "使用JScript条件注释会降低压缩水平!" : ""), true);
          }
          break;

        case Token.NAME:
          symbol = token.getValue();

          if (mode == BUILDING_SYMBOL_TREE) {

            if (symbol.equals("eval")) {

              protectScopeFromObfuscation(currentScope);
              warn("不推荐使用'eval'关键字。" + (munge ? "使用'eval'会降低压缩水平!" : ""), true);
            }

          } else if (mode == CHECKING_SYMBOL_TREE) {

            if ((offset < 2
                    || (getToken(-2).getType() != Token.DOT
                        && getToken(-2).getType() != Token.GET
                        && getToken(-2).getType() != Token.SET))
                && getToken(0).getType() != Token.OBJECTLIT) {

              identifier = getIdentifier(symbol, currentScope);

              if (identifier == null) {

                if (symbol.length() <= 3 && !builtin.contains(symbol)) {
                  // Here, we found an undeclared and
                  // un-namespaced symbol that is
                  // 3 characters or less in length. Declare it in
                  // the global scope.
                  // We don't need to declare longer symbols since
                  // they won't cause
                  // any conflict with other munged symbols.
                  globalScope.declareIdentifier(symbol, false);

                  // I removed the warning since was only being
                  // done when
                  // for identifiers 3 chars or less, and was just
                  // causing
                  // noise for people who happen to rely on an
                  // externally
                  // declared variable that happen to be that
                  // short. We either
                  // should always warn or never warn -- the fact
                  // that we
                  // declare the short symbols in the global space
                  // doesn't
                  // change anything.
                  // warn("Found an undeclared symbol: " + symbol,
                  // true);
                }

              } else {

                identifier.incrementRefcount();
              }
            }
          }
          break;
      }
    }
  }
 private static boolean isValidIdentifier(String s) {
   Matcher m = SIMPLE_IDENTIFIER_NAME_PATTERN.matcher(s);
   return (m.matches() && !reserved.contains(s));
 }
  static {

    // This list contains all the 3 characters or less built-in global
    // symbols available in a browser. Please add to this list if you
    // see anything missing.
    builtin.add("NaN");
    builtin.add("top");

    ones = new ArrayList<String>();
    for (char c = 'a'; c <= 'z'; c++) ones.add(Character.toString(c));
    for (char c = 'A'; c <= 'Z'; c++) ones.add(Character.toString(c));

    twos = new ArrayList<String>();
    for (int i = 0; i < ones.size(); i++) {
      String one = ones.get(i);
      for (char c = 'a'; c <= 'z'; c++) twos.add(one + Character.toString(c));
      for (char c = 'A'; c <= 'Z'; c++) twos.add(one + Character.toString(c));
      for (char c = '0'; c <= '9'; c++) twos.add(one + Character.toString(c));
    }

    // Remove two-letter JavaScript reserved words and built-in globals...
    twos.remove("as");
    twos.remove("is");
    twos.remove("do");
    twos.remove("if");
    twos.remove("in");
    twos.removeAll(builtin);

    threes = new ArrayList<String>();
    for (int i = 0; i < twos.size(); i++) {
      String two = twos.get(i);
      for (char c = 'a'; c <= 'z'; c++) threes.add(two + Character.toString(c));
      for (char c = 'A'; c <= 'Z'; c++) threes.add(two + Character.toString(c));
      for (char c = '0'; c <= '9'; c++) threes.add(two + Character.toString(c));
    }

    // Remove three-letter JavaScript reserved words and built-in globals...
    threes.remove("for");
    threes.remove("int");
    threes.remove("new");
    threes.remove("try");
    threes.remove("use");
    threes.remove("var");
    threes.removeAll(builtin);

    // That's up to ((26+26)*(1+(26+26+10)))*(1+(26+26+10))-8
    // (206,380 symbols per scope)

    // The following list comes from
    // org/mozilla/javascript/Decompiler.java...
    // 注意:此处并为认为地设定键与值的acsii码相等,比如Token.ASSIGN是89,而'='为61
    literals.put(new Integer(Token.GET), "get ");
    literals.put(new Integer(Token.SET), "set ");
    literals.put(new Integer(Token.TRUE), "true");
    literals.put(new Integer(Token.FALSE), "false");
    literals.put(new Integer(Token.NULL), "null");
    literals.put(new Integer(Token.THIS), "this");
    literals.put(new Integer(Token.FUNCTION), "function");
    literals.put(new Integer(Token.COMMA), ",");
    literals.put(new Integer(Token.LC), "{");
    literals.put(new Integer(Token.RC), "}");
    literals.put(new Integer(Token.LP), "(");
    literals.put(new Integer(Token.RP), ")");
    literals.put(new Integer(Token.LB), "[");
    literals.put(new Integer(Token.RB), "]");
    literals.put(new Integer(Token.DOT), ".");
    literals.put(new Integer(Token.NEW), "new ");
    literals.put(new Integer(Token.DELPROP), "delete ");
    literals.put(new Integer(Token.IF), "if");
    literals.put(new Integer(Token.ELSE), "else");
    literals.put(new Integer(Token.FOR), "for");
    literals.put(new Integer(Token.IN), " in ");
    literals.put(new Integer(Token.WITH), "with");
    literals.put(new Integer(Token.WHILE), "while");
    literals.put(new Integer(Token.DO), "do");
    literals.put(new Integer(Token.TRY), "try");
    literals.put(new Integer(Token.CATCH), "catch");
    literals.put(new Integer(Token.FINALLY), "finally");
    literals.put(new Integer(Token.THROW), "throw");
    literals.put(new Integer(Token.SWITCH), "switch");
    literals.put(new Integer(Token.BREAK), "break");
    literals.put(new Integer(Token.CONTINUE), "continue");
    literals.put(new Integer(Token.CASE), "case");
    literals.put(new Integer(Token.DEFAULT), "default");
    literals.put(new Integer(Token.RETURN), "return");
    literals.put(new Integer(Token.VAR), "var ");
    literals.put(new Integer(Token.SEMI), ";");
    literals.put(new Integer(Token.ASSIGN), "=");
    literals.put(new Integer(Token.ASSIGN_ADD), "+=");
    literals.put(new Integer(Token.ASSIGN_SUB), "-=");
    literals.put(new Integer(Token.ASSIGN_MUL), "*=");
    literals.put(new Integer(Token.ASSIGN_DIV), "/=");
    literals.put(new Integer(Token.ASSIGN_MOD), "%=");
    literals.put(new Integer(Token.ASSIGN_BITOR), "|=");
    literals.put(new Integer(Token.ASSIGN_BITXOR), "^=");
    literals.put(new Integer(Token.ASSIGN_BITAND), "&=");
    literals.put(new Integer(Token.ASSIGN_LSH), "<<=");
    literals.put(new Integer(Token.ASSIGN_RSH), ">>=");
    literals.put(new Integer(Token.ASSIGN_URSH), ">>>=");
    literals.put(new Integer(Token.HOOK), "?");
    literals.put(new Integer(Token.OBJECTLIT), ":");
    literals.put(new Integer(Token.COLON), ":");
    literals.put(new Integer(Token.OR), "||");
    literals.put(new Integer(Token.AND), "&&");
    literals.put(new Integer(Token.BITOR), "|");
    literals.put(new Integer(Token.BITXOR), "^");
    literals.put(new Integer(Token.BITAND), "&");
    literals.put(new Integer(Token.SHEQ), "===");
    literals.put(new Integer(Token.SHNE), "!==");
    literals.put(new Integer(Token.EQ), "==");
    literals.put(new Integer(Token.NE), "!=");
    literals.put(new Integer(Token.LE), "<=");
    literals.put(new Integer(Token.LT), "<");
    literals.put(new Integer(Token.GE), ">=");
    literals.put(new Integer(Token.GT), ">");
    literals.put(new Integer(Token.INSTANCEOF), " instanceof ");
    literals.put(new Integer(Token.LSH), "<<");
    literals.put(new Integer(Token.RSH), ">>");
    literals.put(new Integer(Token.URSH), ">>>");
    literals.put(new Integer(Token.TYPEOF), "typeof");
    literals.put(new Integer(Token.VOID), "void ");
    literals.put(new Integer(Token.CONST), "const ");
    literals.put(new Integer(Token.NOT), "!");
    literals.put(new Integer(Token.BITNOT), "~");
    literals.put(new Integer(Token.POS), "+");
    literals.put(new Integer(Token.NEG), "-");
    literals.put(new Integer(Token.INC), "++");
    literals.put(new Integer(Token.DEC), "--");
    literals.put(new Integer(Token.ADD), "+");
    literals.put(new Integer(Token.SUB), "-");
    literals.put(new Integer(Token.MUL), "*");
    literals.put(new Integer(Token.DIV), "/");
    literals.put(new Integer(Token.MOD), "%");
    literals.put(new Integer(Token.COLONCOLON), "::");
    literals.put(new Integer(Token.DOTDOT), "..");
    literals.put(new Integer(Token.DOTQUERY), ".(");
    literals.put(new Integer(Token.XMLATTR), "@");
    literals.put(new Integer(Token.LET), "let ");
    literals.put(new Integer(Token.YIELD), "yield ");

    // See
    // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Reserved_Words

    // JavaScript 1.5 reserved words
    reserved.add("break");
    reserved.add("case");
    reserved.add("catch");
    reserved.add("continue");
    reserved.add("default");
    reserved.add("delete");
    reserved.add("do");
    reserved.add("else");
    reserved.add("finally");
    reserved.add("for");
    reserved.add("function");
    reserved.add("if");
    reserved.add("in");
    reserved.add("instanceof");
    reserved.add("new");
    reserved.add("return");
    reserved.add("switch");
    reserved.add("this");
    reserved.add("throw");
    reserved.add("try");
    reserved.add("typeof");
    reserved.add("var");
    reserved.add("void");
    reserved.add("while");
    reserved.add("with");
    // Words reserved for future use
    reserved.add("abstract");
    reserved.add("boolean");
    reserved.add("byte");
    reserved.add("char");
    reserved.add("class");
    reserved.add("const");
    reserved.add("debugger");
    reserved.add("double");
    reserved.add("enum");
    reserved.add("export");
    reserved.add("extends");
    reserved.add("final");
    reserved.add("float");
    reserved.add("goto");
    reserved.add("implements");
    reserved.add("import");
    reserved.add("int");
    reserved.add("interface");
    reserved.add("long");
    reserved.add("native");
    reserved.add("package");
    reserved.add("private");
    reserved.add("protected");
    reserved.add("public");
    reserved.add("short");
    reserved.add("static");
    reserved.add("super");
    reserved.add("synchronized");
    reserved.add("throws");
    reserved.add("transient");
    reserved.add("volatile");
    // These are not reserved, but should be taken into account
    // in isValidIdentifier (See jslint source code)
    reserved.add("arguments");
    reserved.add("eval");
    reserved.add("true");
    reserved.add("false");
    reserved.add("Infinity");
    reserved.add("NaN");
    reserved.add("null");
    reserved.add("undefined");
  }