Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

壊れた暗号生成器

JAG (Japanese Alumni Group) は多くのプログラマで構成される謎の組織であり，この組織の本部がある建物に入るためには毎回ある機械によって生成される暗号文を解かなくてはならない．
この暗号文は，'+'，'-'，'['，']' の記号と大文字のアルファベットからなっており，以下の BNF で定義される <Cipher> によって表される．

<Cipher> ::= <String> | <Cipher><String>
<String> ::= <Letter> | '['<Cipher>']'
<Letter> ::= '+'<Letter> | '-'<Letter> |
'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' |
'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z'

ここでそれぞれの記号は以下のような意味を表す．

+(文字) : その文字の次のアルファベットを表す (ただし 'Z' の次のアルファベットは 'A' であるとする)

-(文字) : その文字の前のアルファベットを表す (ただし 'A' の前のアルファベットは 'Z' であるとする)

[(文字列)] : その文字列を左右反転した文字列を表す

しかしこの暗号文を生成する機械には現在故障が発生しており，暗号文のうちアルファベットの箇所が数文字壊れて読めなくなっている場合がある．読めない文字は仮に '?' と表されている．
調査の結果，壊れた文字の埋め方は，復号後の文字列が，復号後の文字列としてありえる文字列の中で辞書順最小になるようなものであることがわかった．
あなたの仕事はこの暗号文を正しく復号することである．

Input

入力は複数のデータセットから構成される．
各データセットは，上記の BNF で定義された暗号文において，一部の大文字のアルファベットが ‘?’ に置き換えられた文字列を含む 1 行からなる．
各文字列の長さは $80$ 以下であると仮定してよい．
また各データセットに含まれる '?' の数は $0$ 以上 $3$ 以下であると仮定してよい．

入力の終了は '.' の1文字だけを含む行で表される．

Output

各データセットに対して，復号後の文字列が辞書順最小になるように暗号文を復号したときの，復号後の文字列を出力せよ．

Sample Input

A+A++A
Z-Z--Z+-Z
[ESREVER]
J---?---J
++++++++A+++Z-----------A+++Z
[[++-+--?[--++-?++-+++L]][-+-----+-O]]++++---+L
.

Output for Sample Input

ABC
ZYXZ
REVERSE
JAG
ICPC
JAPAN

Solution in JAVA (judge verdict: Accepted)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Deque;

public class Main {

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String line;

		while ((line = br.readLine()) != null && !line.isEmpty()) {
			if (line.equals(".")) break;

			Deque<Character> rev = new ArrayDeque<Character>();
			Deque<Character> out = new ArrayDeque<Character>();
			int shift = 0;

			for (char c : line.toCharArray()) {
				switch (c) {
					case '[':
						out.offer(c);
						break;
					case ']':
						char d = out.removeLast();
						while (d != '[') {
							rev.push(d);
							d = out.removeLast();
						}
						// reverse
						while (!rev.isEmpty()) {
							out.offer(rev.removeLast());
						}
						break;
					case '+':
						shift++;
						break;
					case '-':
						shift--;
						break;
					case '?':
						out.offer('A');
						shift = 0;
						break;
					default:
						if (shift != 0) {
							shift %= 26;
							c += shift;
							if (c < 'A') {
								c += 26;
							} else if (c > 'Z') {
								c -= 26;
							}
							out.offer((char) c);
							shift = 0;
						} else {
							out.offer(c);
						}
						break;
				}
			}
			StringBuilder sb = new StringBuilder();
			while (!out.isEmpty()) {
				sb.append(out.poll());
			}
			System.out.println(sb.toString());
		}
	} //end while
} //end main