/**
   * Retorna uma árvore binária que representa a expressão regular informada
   *
   * @param expr
   * @return
   * @throws FormaisException
   */
  public static Nodo<Character> parse(String expr) throws FormaisException {
    if (expr == null || expr.isEmpty()) {
      return new Nodo<Character>(null);
    }

    if (expr.length() == 1) {
      return parseChar(expr.charAt(0));
    }

    // Traduz símbolos especiais (como o '+') para outros mais primitivos
    expr = traduzirSimbolosEspeciais(expr);

    // Se expressão for da forma "(...)", retorna o parse da expressão interna
    // Cuida com expressões do tipo "(...)(...)" !!
    if (expr.startsWith("(") && expr.endsWith(")")) {
      // Verificamos em qual posição termina o parênteses inicial
      // Se terminar na última posição, a expressão tem a forma "(...)"
      // Senão, ela tem a forma "(...)(...)..."
      int depth = 0;
      for (int i = 0; i < expr.length(); i++) {
        Character c = expr.charAt(i);
        if (c.equals(')')) {
          depth++;
        } else if (c.equals('(')) {
          depth--;
        }
        if (depth == 0) {
          if (i == expr.length() - 1) {
            return parse(expr.substring(1, expr.length() - 1));
          }
          break;
        }
      }
    }

    // Procuramos pela operação de mais alto nível, seguindo a precedência dos operadores
    int pos;

    // Se possuir '|'
    pos = posOperador(expr, '|');
    if (pos != -1) {
      Nodo<Character> nodo = new Nodo<Character>('|');
      nodo.setEsq(parse(expr.substring(0, pos)));
      nodo.setDir(parse(expr.substring(pos + 1)));
      return nodo;
    }

    // Se possuir concatenação
    pos = posConcat(expr);
    if (pos != 0) {
      Nodo<Character> nodo = new Nodo<Character>('.');
      nodo.setEsq(parse(expr.substring(0, pos)));
      nodo.setDir(parse(expr.substring(pos)));
      return nodo;
    }

    if (expr.endsWith("*")) {
      Nodo<Character> nodo = new Nodo<Character>('*');
      nodo.setEsq(parse(expr.substring(0, expr.length() - 1)));
      return nodo;
    }

    if (expr.endsWith("?")) {
      Nodo<Character> nodo = new Nodo<Character>('?');
      nodo.setEsq(parse(expr.substring(0, expr.length() - 1)));
      return nodo;
    }

    throw new FormaisException("Expressão regular má formada: '" + expr + "'");
  }